From 866f8763175ff60e4fa455b92b5eb660a12fe6c7 Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 26 Sep 2017 16:34:46 +0000 Subject: [PATCH] Security-58286.1.32.tar.gz --- Analytics/SFAnalyticsLogger.h | 72 + Analytics/SFAnalyticsLogger.m | 878 ++ Analytics/SFAnalyticsLogging.plist | 16 + Analytics/SQLite/SFObjCType.h | 88 + Analytics/SQLite/SFObjCType.m | 169 + Analytics/SQLite/SFSQLite.h | 152 + Analytics/SQLite/SFSQLite.m | 1067 ++ Analytics/SQLite/SFSQLiteStatement.h | 72 + Analytics/SQLite/SFSQLiteStatement.m | 319 + CircleJoinRequested/CircleJoinRequested.m | 198 +- ...m.apple.security.CircleJoinRequested.plist | 5 + Forwarding Headers/SOSCloudCircle.h | 11 - Forwarding Headers/SOSPeerInfo.h | 11 - KVSKeychainSyncingProxy/CKDAKSLockMonitor.m | 39 +- KVSKeychainSyncingProxy/CKDKVSProxy.h | 4 +- KVSKeychainSyncingProxy/CKDKVSProxy.m | 465 +- KVSKeychainSyncingProxy/CKDKVSStore.h | 1 + KVSKeychainSyncingProxy/CKDKVSStore.m | 128 +- KVSKeychainSyncingProxy/CKDStore.h | 3 + .../CloudKeychainProxy-Info.plist | 2 + .../XPCNotificationDispatcher.m | 3 +- KVSKeychainSyncingProxy/cloudkeychainproxy.m | 51 +- ...ple.security.cloudkeychainproxy3.osx.plist | 10 + KeychainCircle/KCAESGCMDuplexSession.m | 2 +- KeychainCircle/KCAccountKCCircleDelegate.h | 8 +- KeychainCircle/KCAccountKCCircleDelegate.m | 13 +- KeychainCircle/KCDer.m | 15 +- KeychainCircle/KCError.h | 7 +- KeychainCircle/KCJoiningAcceptSession.m | 28 +- KeychainCircle/KCJoiningMessages.h | 14 +- KeychainCircle/KCJoiningMessages.m | 85 +- KeychainCircle/KCJoiningRequestSession.m | 32 +- KeychainCircle/KCJoiningSession.h | 17 +- KeychainCircle/KCSRPContext.m | 2 +- KeychainCircle/KeychainCircle.h | 1 + KeychainCircle/NSError+KCCreationHelpers.h | 8 +- KeychainCircle/NSError+KCCreationHelpers.m | 3 + KeychainCircle/PairingChannel.h | 39 + KeychainCircle/PairingChannel.m | 503 + KeychainCircle/Tests/KCAESGCMTest.m | 1 + KeychainCircle/Tests/KCJoiningSessionTest.m | 25 +- KeychainCircle/Tests/KCPairingTest-Info.plist | 24 + KeychainCircle/Tests/KCPairingTest.m | 427 + KeychainCircle/Tests/KCParing.plist | 32 + KeychainEntitledTestApp_ios/AppDelegate.h | 17 + KeychainEntitledTestApp_ios/AppDelegate.m | 51 + .../AppIcon.appiconset/Contents.json | 93 + .../Base.lproj/LaunchScreen.storyboard | 27 + .../Base.lproj/Main.storyboard | 26 + KeychainEntitledTestApp_ios/Info.plist | 45 + KeychainEntitledTestApp_ios/ViewController.h | 15 + KeychainEntitledTestApp_ios/ViewController.m | 29 + KeychainEntitledTestApp_ios/main.m | 16 + KeychainEntitledTestApp_mac/AppDelegate.h | 15 + KeychainEntitledTestApp_mac/AppDelegate.m | 27 + .../AppIcon.appiconset/Contents.json | 58 + .../Base.lproj/Main.storyboard | 693 + KeychainEntitledTestApp_mac/Info.plist | 30 + KeychainEntitledTestApp_mac/ViewController.h | 15 + KeychainEntitledTestApp_mac/ViewController.m | 27 + KeychainEntitledTestApp_mac/main.m | 13 + ...KeychainSyncAccountNotification-Info.plist | 4 + .../KeychainSyncAccountNotification.m | 37 +- KeychainSyncAccountUpdater/Info.plist | 24 + .../KeychainSyncAccountUpdater.h | 5 + .../KeychainSyncAccountUpdater.m | 20 + KeychainSyncingOverIDSProxy/IDSProxy.h | 66 +- KeychainSyncingOverIDSProxy/IDSProxy.m | 206 +- ...ychainSyncingOverIDSProxy+ReceiveMessage.m | 131 +- .../KeychainSyncingOverIDSProxy+SendMessage.m | 175 +- .../KeychainSyncingOverIDSProxy+Throttle.m | 11 +- .../KeychainSyncingOverIDSProxy-Info.plist | 2 + .../KeychainSyncingOverIDSProxy.8 | 9 + ...rity.keychainsyncingoveridsproxy.ios.plist | 2 - ...rity.keychainsyncingoveridsproxy.osx.plist | 4 - .../keychainsyncingoveridsproxy.m | 66 +- Modules/KeychainCircle.modulemap | 6 + OSX/Breadcrumb/SecBreadcrumb.c | 1 + OSX/Breadcrumb/breadcrumb_regressions.h | 2 +- .../KNAppDelegate.m | 395 +- .../Keychain Circle Notification.8 | 9 + ...ecurity.keychain-circle-notification.plist | 9 +- .../SecurityTests-Entitlements.plist | 5 + OSX/SecurityTestsOSX/main.m | 6 +- OSX/SecurityTestsOSX/testlist.h | 1 + OSX/authd/agent.c | 31 +- OSX/authd/authd-Entitlements.plist | 8 + OSX/authd/authd_private.h | 3 +- OSX/authd/authdb.c | 118 +- OSX/authd/authitems.c | 134 +- OSX/authd/authitems.h | 12 + OSX/authd/authorization.plist | 65 +- OSX/authd/authtoken.c | 54 +- OSX/authd/authtoken.h | 3 + OSX/authd/authutilities.c | 1 - OSX/authd/ccaudit.c | 16 +- OSX/authd/com.apple.authd.sb | 2 + OSX/authd/connection.c | 2 +- OSX/authd/credential.c | 6 +- OSX/authd/debugging.c | 75 - OSX/authd/debugging.h | 28 +- OSX/authd/engine.c | 731 +- OSX/authd/engine.h | 9 + OSX/authd/main.c | 29 +- OSX/authd/mechanism.c | 2 +- OSX/authd/process.c | 31 +- OSX/authd/rule.c | 51 +- OSX/authd/rule.h | 3 + OSX/authd/server.c | 155 +- OSX/authd/server.h | 3 + OSX/authd/session.c | 14 +- OSX/authd/tests/authdtestlist.h | 5 + OSX/authd/tests/authdtests.m | 155 + OSX/authd/tests/main.m | 45 + OSX/authorizationdump/main.m | 290 + OSX/config/base.xcconfig | 3 +- OSX/config/debug.xcconfig | 2 - OSX/config/lib.xcconfig | 4 +- OSX/config/release.xcconfig | 2 - OSX/config/security_framework_macos.xcconfig | 2 +- OSX/config/security_macos.xcconfig | 2 +- ....dfr.prompts-BBBAA77A32-C4EBFEA440.strings | 4 +- .../en.lproj/authorization.prompts.strings | 3 +- OSX/lib/generateErrStrings.pl | 5 +- OSX/libsecurity_apple_csp/lib/opensshWrap.cpp | 9 +- .../open_ssl/opensslUtils/opensslUtils.h | 2 +- .../lib/SSCSPDLSession.cpp | 5 + .../lib/SSCSPDLSession.h | 2 + .../lib/SSCSPSession.cpp | 1 + .../lib/SSDatabase.cpp | 16 +- OSX/libsecurity_apple_cspdl/lib/SSKey.cpp | 8 +- .../lib/DecodedExtensions.cpp | 2 +- .../lib/clNssUtils.cpp | 2 +- .../lib/TPCrlInfo.cpp | 11 +- .../lib/TPDatabase.cpp | 3 +- .../lib/certGroupUtils.cpp | 4 + OSX/libsecurity_apple_x509_tp/lib/cuEnc64.c | 12 + .../lib/tpPolicies.cpp | 2 +- OSX/libsecurity_asn1/Security | 1 - OSX/libsecurity_asn1/lib/X509Templates.c | 4 +- OSX/libsecurity_asn1/lib/pkcs12Templates.h | 2 +- .../lib/Authorization.c | 59 + .../lib/Authorization.h | 5 +- .../lib/AuthorizationPlugin.h | 25 +- .../lib/AuthorizationPriv.h | 65 +- .../lib/AuthorizationTagsPriv.h | 7 +- .../lib/trampolineClient.cpp | 5 +- OSX/libsecurity_cdsa_client/lib/clclient.cpp | 4 + .../lib/cryptoclient.h | 3 + .../lib/cssmclient.cpp | 4 + OSX/libsecurity_cdsa_client/lib/cssmclient.h | 2 +- .../lib/cssmerrors.cpp | 48 +- .../lib/cssmerrors.h | 3 +- .../lib/handletemplates.h | 12 + OSX/libsecurity_cdsa_utils/lib/cuEnc64.c | 4 + OSX/libsecurity_cdsa_utils/lib/cuFileIo.c | 8 +- .../lib/cuOidParser.cpp | 8 +- OSX/libsecurity_cms/lib/CMSDecoder.cpp | 28 +- OSX/libsecurity_cms/lib/CMSDecoder.h | 11 +- OSX/libsecurity_cms/lib/CMSEncoder.cpp | 4 +- .../libsecurity_cms.xcodeproj/project.pbxproj | 4 +- .../regressions/cms-hashagility-test.c | 2 +- .../regressions/cms-trust-settings-test.c | 2 +- .../regressions/cms_regressions.h | 2 +- OSX/libsecurity_codesigning/lib/CSCommon.h | 7 +- .../lib/CSCommonPriv.h | 16 +- .../lib/SecAssessment.cpp | 7 +- OSX/libsecurity_codesigning/lib/SecCode.cpp | 3 +- OSX/libsecurity_codesigning/lib/SecCode.h | 7 +- OSX/libsecurity_codesigning/lib/SecCodePriv.h | 2 +- .../lib/SecRequirement.cpp | 4 + .../lib/SecRequirementPriv.h | 2 + .../lib/SecStaticCode.cpp | 17 +- .../lib/SecStaticCode.h | 7 +- .../lib/SecStaticCodePriv.h | 2 +- OSX/libsecurity_codesigning/lib/SecTask.c | 387 - .../lib/StaticCode.cpp | 306 +- OSX/libsecurity_codesigning/lib/StaticCode.h | 17 +- .../lib/bundlediskrep.cpp | 10 + .../lib/bundlediskrep.h | 2 + OSX/libsecurity_codesigning/lib/cdbuilder.cpp | 15 +- OSX/libsecurity_codesigning/lib/cdbuilder.h | 12 +- .../lib/codedirectory.cpp | 14 +- .../lib/codedirectory.h | 16 +- OSX/libsecurity_codesigning/lib/cs.h | 5 + OSX/libsecurity_codesigning/lib/cskernel.cpp | 4 + OSX/libsecurity_codesigning/lib/csprocess.h | 2 +- .../lib/csutilities.cpp | 10 +- OSX/libsecurity_codesigning/lib/csutilities.h | 52 +- .../lib/dirscanner.cpp | 2 +- OSX/libsecurity_codesigning/lib/diskrep.cpp | 10 +- OSX/libsecurity_codesigning/lib/diskrep.h | 8 + .../lib/kerneldiskrep.cpp | 5 + .../lib/kerneldiskrep.h | 1 + OSX/libsecurity_codesigning/lib/machorep.cpp | 77 + OSX/libsecurity_codesigning/lib/machorep.h | 4 + .../lib/opaquewhitelist.cpp | 2 +- .../lib/piddiskrep.cpp | 5 + OSX/libsecurity_codesigning/lib/piddiskrep.h | 1 + .../lib/policyengine.cpp | 41 +- OSX/libsecurity_codesigning/lib/reqdumper.cpp | 8 +- OSX/libsecurity_codesigning/lib/reqdumper.h | 2 +- OSX/libsecurity_codesigning/lib/reqinterp.cpp | 20 +- OSX/libsecurity_codesigning/lib/reqinterp.h | 7 +- OSX/libsecurity_codesigning/lib/reqmaker.h | 2 +- OSX/libsecurity_codesigning/lib/reqreader.cpp | 4 + OSX/libsecurity_codesigning/lib/reqreader.h | 2 +- .../lib/requirement.cpp | 5 +- OSX/libsecurity_codesigning/lib/requirement.h | 3 +- OSX/libsecurity_codesigning/lib/resources.cpp | 7 + OSX/libsecurity_codesigning/lib/signer.cpp | 66 +- OSX/libsecurity_codesigning/lib/signer.h | 8 +- .../lib/singlediskrep.cpp | 8 + .../lib/singlediskrep.h | 1 + OSX/libsecurity_codesigning/lib/slcrep.cpp | 13 +- OSX/libsecurity_cryptkit/lib/giantIntegers.c | 1 - OSX/libsecurity_cryptkit/lib/platform.h | 8 +- OSX/libsecurity_cssm/lib/cssmkrspi.h | 1 + OSX/libsecurity_cssm/lib/cssmspi.h | 1 + OSX/libsecurity_cssm/lib/eisl.h | 2 +- OSX/libsecurity_cssm/lib/emmspi.h | 2 + OSX/libsecurity_filedb/lib/AppleDatabase.cpp | 36 +- OSX/libsecurity_filedb/lib/AtomicFile.cpp | 16 +- .../lib/CertificateRequest.cpp | 858 -- .../lib/CertificateRequest.h | 154 - .../lib/DLDBListCFPref.cpp | 27 +- OSX/libsecurity_keychain/lib/Item.cpp | 108 +- OSX/libsecurity_keychain/lib/KCCursor.cpp | 3 - OSX/libsecurity_keychain/lib/KeyItem.cpp | 32 +- OSX/libsecurity_keychain/lib/Keychains.cpp | 32 +- OSX/libsecurity_keychain/lib/Keychains.h | 6 - .../lib/MacOSErrorStrings.h | 2 +- OSX/libsecurity_keychain/lib/SecACL.cpp | 17 + OSX/libsecurity_keychain/lib/SecACL.h | 4 + OSX/libsecurity_keychain/lib/SecAccess.cpp | 10 +- OSX/libsecurity_keychain/lib/SecAccessPriv.h | 15 +- OSX/libsecurity_keychain/lib/SecCFTypes.cpp | 1 - OSX/libsecurity_keychain/lib/SecCFTypes.h | 1 - .../lib/SecCertificate.cpp | 12 - .../lib/SecCertificateP.c | 143 +- .../lib/SecCertificateRequest.cpp | 190 - .../lib/SecFDERecoveryAsymmetricCrypto.cpp | 2 +- OSX/libsecurity_keychain/lib/SecFrameworkP.h | 2 +- OSX/libsecurity_keychain/lib/SecIdentity.cpp | 55 +- .../lib/SecIdentitySearch.cpp | 16 + .../lib/SecImportExportAgg.cpp | 5 + OSX/libsecurity_keychain/lib/SecItem.cpp | 179 +- .../lib/SecItemConstants.c | 13 +- OSX/libsecurity_keychain/lib/SecKey.cpp | 91 +- OSX/libsecurity_keychain/lib/SecKeychain.cpp | 162 +- OSX/libsecurity_keychain/lib/SecKeychain.h | 6 +- .../lib/SecKeychainAddIToolsPassword.cpp | 73 +- .../lib/SecKeychainItem.cpp | 89 + .../lib/SecKeychainItemExtendedAttributes.cpp | 10 + .../lib/SecKeychainSearch.cpp | 10 + OSX/libsecurity_keychain/lib/SecPassword.cpp | 17 +- OSX/libsecurity_keychain/lib/SecPolicy.cpp | 35 +- OSX/libsecurity_keychain/lib/SecRandom.c | 2 +- .../lib/SecRecoveryPassword.c | 101 +- .../lib/SecRecoveryPassword.h | 4 +- OSX/libsecurity_keychain/lib/SecTrust.cpp | 407 +- .../lib/SecTrustOSXEntryPoints.cpp | 45 +- .../lib/SecTrustSettings.cpp | 279 +- OSX/libsecurity_keychain/lib/TokenLogin.cpp | 2 +- .../lib/TrustAdditions.cpp | 35 +- OSX/libsecurity_keychain/lib/TrustAdditions.h | 9 +- .../lib/TrustRevocation.cpp | 90 +- OSX/libsecurity_keychain/lib/defaultcreds.cpp | 20 +- OSX/libsecurity_keychain/lib/defaultcreds.h | 2 + .../lib/tsaDERUtilities.c | 4 +- .../libDER/libDER/asn1Types.h | 2 + .../libDER/libDER/module.modulemap | 3 + .../libDER/libDERUtils/fileIo.c | 4 +- .../plist/iToolsTrustedApps.plist | 28 - .../regressions/kc-03-status.c | 6 +- .../regressions/kc-06-cert-search-email.m | 12 +- .../regressions/kc-10-item-add-generic.c | 5 +- .../regressions/kc-18-find-combined.c | 24 +- .../regressions/kc-20-identity-find-stress.c | 37 +- .../regressions/kc-20-item-find-stress.c | 34 +- .../regressions/kc-20-key-find-stress.c | 35 +- .../regressions/kc-21-item-xattrs.c | 2 +- .../regressions/kc-23-key-export-symmetric.m | 4 + .../regressions/kc-28-cert-sign.c | 2 +- .../regressions/kc-30-xara.c | 39 +- .../regressions/kc-40-seckey.m | 16 +- .../regressions/kc-41-sececkey.m | 104 +- .../regressions/kc-helpers.h | 8 +- .../regressions/kc-item-helpers.h | 6 +- .../regressions/kc-keychain-file-helpers.h | 1 + .../regressions/keychain_regressions.h | 2 +- OSX/libsecurity_keychain/xpc-tsa/main-tsa.m | 15 +- .../xpc-tsa/timestampclient.h | 2 +- .../xpc-tsa/timestampclient.m | 4 +- OSX/libsecurity_keychain/xpc/main.c | 5 +- OSX/libsecurity_manifest/lib/Download.cpp | 3 +- OSX/libsecurity_manifest/lib/SecManifest.cpp | 6 +- OSX/libsecurity_manifest/lib/SecureDownload.h | 2 +- .../lib/SecureDownloadInternal.c | 11 +- OSX/libsecurity_mds/lib/MDSAttrUtils.cpp | 2 +- OSX/libsecurity_mds/lib/MDSSession.cpp | 81 +- OSX/libsecurity_mds/lib/mdsapi.cpp | 3 + OSX/libsecurity_ocspd/client/ocspdClient.cpp | 28 +- OSX/libsecurity_pkcs12/lib/pkcs12BagAttrs.cpp | 1 + OSX/libsecurity_pkcs12/lib/pkcs12Keychain.cpp | 8 + OSX/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp | 4 +- OSX/libsecurity_pkcs12/lib/pkcs12Utils.h | 2 +- OSX/libsecurity_smime/lib/SecCMS.c | 27 +- OSX/libsecurity_smime/lib/SecCMS.h | 30 + OSX/libsecurity_smime/lib/SecCmsSignerInfo.h | 10 + OSX/libsecurity_smime/lib/SecSMIMEPriv.h | 3 +- OSX/libsecurity_smime/lib/cert.c | 148 +- OSX/libsecurity_smime/lib/cert.h | 5 +- OSX/libsecurity_smime/lib/cmsdigest.c | 2 - OSX/libsecurity_smime/lib/cmsencode.c | 9 +- OSX/libsecurity_smime/lib/cmslocal.h | 2 + OSX/libsecurity_smime/lib/cmssiginfo.c | 59 +- OSX/libsecurity_smime/lib/cryptohi.c | 3 + OSX/libsecurity_smime/lib/smimeutil.c | 6 +- OSX/libsecurity_smime/lib/tsaSupport.c | 11 +- OSX/libsecurity_smime/lib/tsaTemplates.c | 2 + .../regressions/cms-01-basic.c | 2 + .../regressions/smime-cms-test.c | 2 +- .../regressions/smime_regressions.h | 2 +- OSX/libsecurity_ssl/lib/CipherSuite.h | 38 +- OSX/libsecurity_ssl/lib/SecureTransport.h | 141 +- OSX/libsecurity_ssl/lib/SecureTransportPriv.h | 7 + OSX/libsecurity_ssl/lib/sslBuildFlags.h | 28 +- OSX/libsecurity_ssl/lib/sslCipherSpecs.c | 68 +- OSX/libsecurity_ssl/lib/sslContext.c | 267 +- OSX/libsecurity_ssl/lib/sslContext.h | 20 +- OSX/libsecurity_ssl/lib/sslCrypto.c | 27 +- OSX/libsecurity_ssl/lib/sslTransport.c | 75 +- OSX/libsecurity_ssl/lib/tlsCallbacks.c | 65 +- OSX/libsecurity_ssl/regressions/ssl-39-echo.c | 2 +- .../regressions/ssl-42-ciphers.c | 49 +- .../regressions/ssl-44-crashes.c | 6 +- .../ssl-46-SSLGetSupportedCiphers.c | 4 +- .../regressions/ssl-48-split.c | 6 +- OSX/libsecurity_ssl/regressions/ssl-49-sni.c | 2 +- OSX/libsecurity_ssl/regressions/ssl-utils.c | 3 +- .../regressions/ssl_regressions.h | 2 +- OSX/libsecurity_transform/custom.mm | 5 +- .../lib/CEncryptDecrypt.c | 9 +- .../lib/CoreFoundationBasics.cpp | 6 +- OSX/libsecurity_transform/lib/Digest.cpp | 17 +- OSX/libsecurity_transform/lib/Digest.h | 2 +- .../lib/EncodeDecodeTransforms.c | 48 +- .../lib/EncryptTransform.cpp | 32 +- .../lib/GroupTransform.cpp | 27 +- OSX/libsecurity_transform/lib/Monitor.cpp | 11 +- .../lib/NullTransform.cpp | 2 +- OSX/libsecurity_transform/lib/NullTransform.h | 2 +- .../lib/SecCollectTransform.cpp | 14 +- .../lib/SecCustomTransform.cpp | 53 +- .../lib/SecDigestTransform.cpp | 4 +- .../lib/SecEncodeTransform.h | 2 +- .../lib/SecEncryptTransform.cpp | 5 +- .../lib/SecMaskGenerationFunctionTransform.c | 31 +- .../lib/SecMaskGenerationFunctionTransform.h | 1 - .../lib/SecSignVerifyTransform.c | 56 +- .../lib/SecTransform.cpp | 38 +- .../lib/SecTransformInternal.h | 2 +- .../lib/SecTransformReadTransform.cpp | 4 +- .../lib/SingleShotSource.cpp | 5 +- OSX/libsecurity_transform/lib/Source.cpp | 21 +- .../lib/StreamSource.cpp | 15 +- OSX/libsecurity_transform/lib/Transform.cpp | 142 +- .../lib/TransformFactory.cpp | 2 +- .../lib/TransformFactory.h | 2 +- OSX/libsecurity_transform/lib/Utilities.cpp | 8 +- OSX/libsecurity_transform/lib/Utilities.h | 2 +- OSX/libsecurity_transform/lib/c++utils.cpp | 5 +- OSX/libsecurity_transform/lib/c++utils.h | 2 +- OSX/libsecurity_transform/lib/misc.c | 11 +- .../regressions/transform-01-sigverify.m | 219 + .../regressions/transform_regressions.h | 3 + .../lib/SecTranslocateDANotification.cpp | 40 +- .../lib/SecTranslocateShared.cpp | 80 +- .../lib/SecTranslocateShared.hpp | 4 +- .../lib/CSPDLTransaction.cpp | 3 + .../lib/CSPDLTransaction.h | 6 + .../lib/FileLockTransaction.cpp | 4 + .../lib/FileLockTransaction.h | 4 + OSX/libsecurity_utilities/lib/alloc.cpp | 5 +- OSX/libsecurity_utilities/lib/bufferfifo.cpp | 94 - OSX/libsecurity_utilities/lib/bufferfifo.h | 76 - OSX/libsecurity_utilities/lib/buffers.cpp | 106 - OSX/libsecurity_utilities/lib/buffers.h | 162 - OSX/libsecurity_utilities/lib/cfmunge.cpp | 62 +- OSX/libsecurity_utilities/lib/cfmunge.h | 23 +- OSX/libsecurity_utilities/lib/cfutilities.cpp | 133 +- OSX/libsecurity_utilities/lib/cfutilities.h | 16 + .../lib/debugging_internal.cpp | 9 +- OSX/libsecurity_utilities/lib/debugsupport.h | 6 +- OSX/libsecurity_utilities/lib/devrandom.cpp | 18 +- OSX/libsecurity_utilities/lib/devrandom.h | 11 +- OSX/libsecurity_utilities/lib/dispatch.h | 2 +- OSX/libsecurity_utilities/lib/endian.h | 2 +- OSX/libsecurity_utilities/lib/errors.cpp | 18 +- OSX/libsecurity_utilities/lib/errors.h | 3 +- OSX/libsecurity_utilities/lib/fdmover.cpp | 109 - OSX/libsecurity_utilities/lib/fdmover.h | 94 - OSX/libsecurity_utilities/lib/fdsel.cpp | 96 - OSX/libsecurity_utilities/lib/fdsel.h | 80 - OSX/libsecurity_utilities/lib/globalizer.h | 7 +- OSX/libsecurity_utilities/lib/headermap.cpp | 150 - OSX/libsecurity_utilities/lib/headermap.h | 93 - OSX/libsecurity_utilities/lib/hosts.cpp | 151 - OSX/libsecurity_utilities/lib/hosts.h | 82 - OSX/libsecurity_utilities/lib/inetreply.cpp | 91 - OSX/libsecurity_utilities/lib/inetreply.h | 100 - OSX/libsecurity_utilities/lib/iodevices.cpp | 271 - OSX/libsecurity_utilities/lib/iodevices.h | 166 - OSX/libsecurity_utilities/lib/ip++.cpp | 381 - OSX/libsecurity_utilities/lib/ip++.h | 278 - OSX/libsecurity_utilities/lib/ktracecodes.h | 144 - OSX/libsecurity_utilities/lib/logging.cpp | 4 + OSX/libsecurity_utilities/lib/mach++.cpp | 3 +- OSX/libsecurity_utilities/lib/mach++.h | 4 +- OSX/libsecurity_utilities/lib/muscle++.cpp | 3 + OSX/libsecurity_utilities/lib/muscle++.h | 6 +- OSX/libsecurity_utilities/lib/osxcode.h | 2 + OSX/libsecurity_utilities/lib/pcsc++.cpp | 6 +- OSX/libsecurity_utilities/lib/pcsc++.h | 5 + OSX/libsecurity_utilities/lib/powerwatch.cpp | 3 + OSX/libsecurity_utilities/lib/powerwatch.h | 6 + OSX/libsecurity_utilities/lib/seccfobject.cpp | 7 +- OSX/libsecurity_utilities/lib/seccfobject.h | 3 +- .../lib/security_utilities.h | 14 - OSX/libsecurity_utilities/lib/selector.cpp | 204 - OSX/libsecurity_utilities/lib/selector.h | 125 - OSX/libsecurity_utilities/lib/socks++.cpp | 162 - OSX/libsecurity_utilities/lib/socks++.h | 222 - OSX/libsecurity_utilities/lib/socks++4.cpp | 134 - OSX/libsecurity_utilities/lib/socks++4.h | 86 - OSX/libsecurity_utilities/lib/socks++5.cpp | 208 - OSX/libsecurity_utilities/lib/socks++5.h | 125 - OSX/libsecurity_utilities/lib/sqlite++.cpp | 1 + .../lib/transactions.cpp | 6 +- OSX/libsecurity_utilities/lib/transactions.h | 6 +- OSX/libsecurity_utilities/lib/typedvalue.h | 86 - OSX/libsecurity_utilities/lib/unix++.cpp | 33 +- OSX/libsecurity_utilities/lib/unix++.h | 11 +- OSX/libsecurity_utilities/lib/url.cpp | 152 - OSX/libsecurity_utilities/lib/url.h | 82 - OSX/libsecurity_utilities/lib/vproc++.cpp | 8 +- OSX/libsecurityd/lib/dictionary.cpp | 2 +- OSX/libsecurityd/lib/eventlistener.cpp | 35 +- OSX/libsecurityd/lib/ssclient.cpp | 5 +- OSX/libsecurityd/lib/sstransit.h | 36 +- OSX/regressions/test/testcert.c | 6 +- OSX/regressions/test/testenv.m | 5 +- OSX/regressions/test/testmore.c | 12 +- OSX/regressions/test/testmore.h | 8 +- .../CloudKeychainProxy/CloudKeychainProxy.1 | 79 - .../CloudKeychainProxy/CloudKeychainProxy.8 | 9 + .../CKBridge/SOSCloudKeychainClient.c | 157 +- .../CKBridge/SOSCloudKeychainClient.h | 7 + .../CKBridge/SOSCloudKeychainConstants.c | 5 + .../CKBridge/SOSCloudKeychainConstants.h | 5 + .../Regressions/SOSCircle_regressions.h | 3 +- .../Regressions/SOSRegressionUtilities.h | 4 +- ...onUtilities.c => SOSRegressionUtilities.m} | 24 +- OSX/sec/SOSCircle/Regressions/SOSTestDevice.c | 8 +- .../Regressions/sc-130-resignationticket.c | 4 +- .../{sc-150-ring.c => sc-150-ring.m} | 16 +- .../Regressions/sc-153-backupslicekeybag.c | 8 +- .../{sc-20-keynames.c => sc-20-keynames.m} | 4 +- .../SOSCircle/Regressions/sc-30-peerinfo.c | 4 +- .../Regressions/sc-31-peerinfo-simplefuzz.c | 4 +- OSX/sec/SOSCircle/Regressions/sc-40-circle.c | 16 +- OSX/sec/SOSCircle/SOSPeerInfoDER.c | 154 - .../SecureObjectSync/CKDSimulatedStore.h | 1 + .../SecureObjectSync/CKDSimulatedStore.m | 12 +- .../SOSCircle/SecureObjectSync/SOSAccount.c | 2192 ---- .../SOSCircle/SecureObjectSync/SOSAccount.h | 315 +- .../SOSCircle/SecureObjectSync/SOSAccount.m | 2771 ++++ ...{SOSAccountBackup.c => SOSAccountBackup.m} | 194 +- .../SecureObjectSync/SOSAccountCircles.c | 158 - .../SecureObjectSync/SOSAccountCircles.m | 43 + ...rameters.c => SOSAccountCloudParameters.m} | 19 +- .../SecureObjectSync/SOSAccountCredentials.c | 351 - .../SecureObjectSync/SOSAccountCredentials.m | 471 + .../{SOSAccountDer.c => SOSAccountDer.m} | 38 +- ...ullPeerInfo.c => SOSAccountFullPeerInfo.m} | 153 +- .../SecureObjectSync/SOSAccountGetSet.c | 105 - .../SecureObjectSync/SOSAccountGetSet.m | 72 + .../SecureObjectSync/SOSAccountGhost.h | 6 +- .../{SOSAccountGhost.c => SOSAccountGhost.m} | 29 +- .../SecureObjectSync/SOSAccountHSAJoin.c | 99 - .../SecureObjectSync/SOSAccountHSAJoin.h | 19 - .../SecureObjectSync/SOSAccountLog.h | 10 +- .../{SOSAccountLog.c => SOSAccountLog.m} | 31 +- .../{SOSAccountPeers.c => SOSAccountPeers.m} | 101 +- .../SecureObjectSync/SOSAccountPersistence.c | 426 - .../SecureObjectSync/SOSAccountPersistence.m | 530 + .../SecureObjectSync/SOSAccountPriv.h | 433 +- ...AccountRecovery.c => SOSAccountRecovery.m} | 78 +- .../SecureObjectSync/SOSAccountRingUpdate.c | 374 - .../SecureObjectSync/SOSAccountRingUpdate.m | 55 + .../SecureObjectSync/SOSAccountRings.c | 331 - .../SecureObjectSync/SOSAccountRings.m | 228 + .../{SOSAccountSync.c => SOSAccountSync.m} | 267 +- .../SecureObjectSync/SOSAccountTransaction.c | 226 - .../SecureObjectSync/SOSAccountTransaction.h | 46 +- .../SecureObjectSync/SOSAccountTransaction.m | 298 + .../SecureObjectSync/SOSAccountTrust.h | 54 + .../SecureObjectSync/SOSAccountTrust.m | 87 + .../SOSAccountTrustClassic+Circle.h | 36 + .../SOSAccountTrustClassic+Circle.m | 686 + .../SOSAccountTrustClassic+Expansion.h | 44 + .../SOSAccountTrustClassic+Expansion.m | 635 + .../SOSAccountTrustClassic+Identity.h | 26 + .../SOSAccountTrustClassic+Identity.m | 131 + .../SOSAccountTrustClassic+Retirement.h | 17 + .../SOSAccountTrustClassic+Retirement.m | 106 + .../SecureObjectSync/SOSAccountTrustClassic.h | 68 + .../SecureObjectSync/SOSAccountTrustClassic.m | 820 ++ .../SecureObjectSync/SOSAccountTrustOctagon.h | 11 + .../SecureObjectSync/SOSAccountTrustOctagon.m | 6 + .../SecureObjectSync/SOSAccountUpdate.c | 734 -- .../SecureObjectSync/SOSAccountUpdate.m | 415 + ...AccountViewSync.c => SOSAccountViewSync.m} | 143 +- .../SecureObjectSync/SOSBackupEvent.c | 4 +- .../SecureObjectSync/SOSBackupInformation.h | 2 +- ...upInformation.c => SOSBackupInformation.m} | 12 +- .../SecureObjectSync/SOSBackupSliceKeyBag.h | 2 +- ...upSliceKeyBag.c => SOSBackupSliceKeyBag.m} | 36 +- .../SecureObjectSync/SOSChangeTracker.c | 7 +- .../SOSCircle/SecureObjectSync/SOSCircle.c | 32 +- .../SOSCircle/SecureObjectSync/SOSCircle.h | 2 + .../SOSCircle/SecureObjectSync/SOSCircleDer.c | 38 + .../SOSCircle/SecureObjectSync/SOSCircleDer.h | 8 + .../SecureObjectSync/SOSCloudCircle.h | 47 +- .../{SOSCloudCircle.c => SOSCloudCircle.m} | 310 +- .../SecureObjectSync/SOSCloudCircleInternal.h | 7 +- OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.c | 21 +- OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.h | 5 +- .../SecureObjectSync/SOSControlHelper.h} | 15 +- .../SecureObjectSync/SOSControlHelper.m | 66 + .../SecureObjectSync/SOSDataSource.h | 6 +- .../SecureObjectSync/SOSECWrapUnwrap.c | 2 +- .../SOSCircle/SecureObjectSync/SOSEngine.c | 120 +- .../SOSCircle/SecureObjectSync/SOSEngine.h | 15 +- .../SecureObjectSync/SOSEnginePriv.h | 6 +- .../SecureObjectSync/SOSExports.exp-in | 55 +- .../SecureObjectSync/SOSFullPeerInfo.h | 10 +- .../{SOSFullPeerInfo.c => SOSFullPeerInfo.m} | 91 +- .../SOSCircle/SecureObjectSync/SOSInternal.h | 20 +- .../{SOSInternal.c => SOSInternal.m} | 9 +- .../SOSCircle/SecureObjectSync/SOSKVSKeys.h | 22 +- .../{SOSKVSKeys.c => SOSKVSKeys.m} | 73 +- OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.h | 13 +- .../SecureObjectSync/{SOSPeer.c => SOSPeer.m} | 47 +- .../SOSCircle/SecureObjectSync/SOSPeerCoder.h | 4 +- .../{SOSPeerCoder.c => SOSPeerCoder.m} | 49 +- .../SOSCircle/SecureObjectSync/SOSPeerInfo.h | 12 +- .../{SOSPeerInfo.c => SOSPeerInfo.m} | 58 +- .../{SOSPeerInfoDER.c => SOSPeerInfoDER.m} | 0 .../SecureObjectSync/SOSPeerInfoRingState.h | 2 - ...InfoRingState.c => SOSPeerInfoRingState.m} | 0 ...ties.c => SOSPeerInfoSecurityProperties.m} | 18 +- .../SecureObjectSync/SOSPeerInfoV2.h | 3 - .../{SOSPeerInfoV2.c => SOSPeerInfoV2.m} | 8 +- .../SecureObjectSync/SOSPeerOTRTimer.h | 24 + .../SecureObjectSync/SOSPeerOTRTimer.m | 393 + .../SecureObjectSync/SOSPeerRateLimiter.h | 36 + .../SecureObjectSync/SOSPeerRateLimiter.m | 112 + .../SOSCircle/SecureObjectSync/SOSPiggyback.h | 45 + .../SOSCircle/SecureObjectSync/SOSPiggyback.m | 414 + .../SecureObjectSync/SOSRecoveryKeyBag.h | 8 +- ...OSRecoveryKeyBag.c => SOSRecoveryKeyBag.m} | 44 +- .../{SOSRingBackup.c => SOSRingBackup.m} | 0 .../{SOSRingBasic.c => SOSRingBasic.m} | 0 .../{SOSRingRecovery.c => SOSRingRecovery.m} | 2 - .../SOSCircle/SecureObjectSync/SOSRingTypes.h | 17 - .../{SOSRingTypes.c => SOSRingTypes.m} | 229 +- .../{SOSRingV0.c => SOSRingV0.m} | 0 .../{SOSSysdiagnose.c => SOSSysdiagnose.m} | 0 .../SOSCircle/SecureObjectSync/SOSTransport.h | 32 +- .../{SOSTransport.c => SOSTransport.m} | 201 +- ...tBackupPeer.c => SOSTransportBackupPeer.m} | 6 +- .../SecureObjectSync/SOSTransportCircle.c | 112 - .../SecureObjectSync/SOSTransportCircle.h | 74 +- .../SecureObjectSync/SOSTransportCircle.m | 65 + .../SecureObjectSync/SOSTransportCircleCK.h | 23 + .../SecureObjectSync/SOSTransportCircleCK.m | 71 + .../SecureObjectSync/SOSTransportCircleKVS.c | 435 - .../SecureObjectSync/SOSTransportCircleKVS.h | 37 +- .../SecureObjectSync/SOSTransportCircleKVS.m | 313 + .../SOSTransportKeyParameter.c | 67 - .../SOSTransportKeyParameter.h | 54 +- .../SOSTransportKeyParameter.m | 119 + .../SOSTransportKeyParameterKVS.c | 137 - .../SOSTransportKeyParameterKVS.h | 16 - .../SecureObjectSync/SOSTransportMessage.c | 172 - .../SecureObjectSync/SOSTransportMessage.h | 76 +- .../SecureObjectSync/SOSTransportMessage.m | 408 + .../SecureObjectSync/SOSTransportMessageIDS.h | 41 +- ...tMessageIDS.c => SOSTransportMessageIDS.m} | 192 +- .../SecureObjectSync/SOSTransportMessageKVS.c | 277 - .../SecureObjectSync/SOSTransportMessageKVS.h | 37 +- .../SecureObjectSync/SOSTransportMessageKVS.m | 258 + OSX/sec/SOSCircle/SecureObjectSync/SOSTypes.h | 55 + .../{SOSUserKeygen.c => SOSUserKeygen.m} | 7 +- .../SecureObjectSync/SOSViews.exp-in | 4 +- OSX/sec/SOSCircle/SecureObjectSync/SOSViews.h | 13 +- .../{SOSViews.c => SOSViews.m} | 193 +- .../SOSCircle/SecureObjectSync/ViewList.list | 56 +- .../SOSCircle/Tool/NSFileHandle+Formatting.m | 4 + ...iewsPrint.c => accountCirclesViewsPrint.m} | 9 +- .../Tool/{keychain_log.c => keychain_log.m} | 9 +- OSX/sec/SOSCircle/Tool/keychain_sync.h | 3 +- .../Tool/{keychain_sync.c => keychain_sync.m} | 37 +- OSX/sec/SOSCircle/Tool/keychain_sync_test.m | 49 +- OSX/sec/SOSCircle/Tool/recovery_key.h | 3 +- OSX/sec/SOSCircle/Tool/recovery_key.m | 41 +- OSX/sec/SOSCircle/Tool/secToolFileIO.c | 4 +- OSX/sec/SOSCircle/Tool/secViewDisplay.c | 3 +- .../Tool/{syncbackup.c => syncbackup.m} | 2 + .../AppleiPhoneDeviceCACertificates.h | 239 + .../Regressions/Security_regressions.h | 7 +- .../Regressions/crypto/padding-00-mmcs.c | 91 + .../Security/Regressions/rk_01_recoverykey.m | 25 +- .../Regressions/secitem/si-10-find-internet.c | 2 + .../Regressions/secitem/si-15-certificate.c | 91 +- .../secitem/si-15-delete-access-group.m | 2 +- .../secitem/si-17-item-system-bluetooth.m | 4 +- .../secitem/si-18-certificate-parse.m | 195 + .../Regressions/secitem/si-20-sectrust.c | 79 +- .../Regressions/secitem/si-20-sectrust.h | 291 + .../Regressions/secitem/si-23-sectrust-ocsp.c | 29 +- .../secitem/si-28-sectrustsettings.m | 44 +- .../secitem/si-29-sectrust-sha1-deprecation.m | 2 +- .../secitem/si-32-sectrust-pinning-required.h | 261 + .../secitem/si-32-sectrust-pinning-required.m | 120 + .../secitem/si-33-keychain-backup.c | 126 +- .../Regressions/secitem/si-40-seckey.c | 51 +- .../Security/Regressions/secitem/si-60-cms.c | 45 +- .../Regressions/secitem/si-61-pkcs12.c | 719 +- .../Regressions/secitem/si-61-pkcs12.h | 867 ++ .../Regressions/secitem/si-64-ossl-cms.c | 50 +- .../secitem/si-65-cms-cert-policy.c | 2 +- .../Regressions/secitem/si-66-smime.c | 195 +- .../secitem/si-66-smime/smime_attr_emails.h | 1322 ++ ...blacklist.c => si-67-sectrust-blocklist.c} | 24 +- .../Global Trustee.cer.h | 0 .../UTN-USERFirst-Hardware.cer.h | 0 .../addons.mozilla.org.cer.h | 0 .../login.live.com.cer.h | 0 .../login.skype.com.cer.h | 0 .../login.yahoo.com.1.cer.h | 0 .../login.yahoo.com.2.cer.h | 0 .../login.yahoo.com.cer.h | 0 .../mail.google.com.cer.h | 0 .../www.google.com.cer.h | 0 .../secitem/si-68-secmatchissuer.c | 28 +- .../Regressions/secitem/si-82-token-ag.c | 4 +- .../secitem/si-84-sectrust-allowlist.m | 102 +- .../secitem/si-87-sectrust-name-constraints.c | 322 - .../secitem/si-87-sectrust-name-constraints.h | 2526 +--- .../secitem/si-87-sectrust-name-constraints.m | 80 + .../secitem/si-89-cms-hash-agility.c | 201 +- .../secitem/si-89-cms-hash-agility.h | 233 + .../Regressions/vmdh/vmdh-41-example.c | 14 +- .../Regressions/vmdh/vmdh-42-example2.c | 15 +- OSX/sec/Security/SecAccessControl.c | 8 +- .../Security/SecAccessControlExports.exp-in | 1 + OSX/sec/Security/SecBackupKeybagEntry.h | 53 + OSX/sec/Security/SecBackupKeybagEntry.m | 112 + OSX/sec/Security/SecCMS.c | 8 + OSX/sec/Security/SecCMS.h | 1 + OSX/sec/Security/SecCTKKey.c | 325 +- OSX/sec/Security/SecCTKKeyPriv.h | 1 - OSX/sec/Security/SecCertificate.c | 500 +- OSX/sec/Security/SecCertificateInternal.h | 1 + OSX/sec/Security/SecCertificatePath.c | 472 +- OSX/sec/Security/SecCertificatePath.h | 70 +- OSX/sec/Security/SecCertificateRequest.c | 44 +- OSX/sec/Security/SecDH.c | 56 +- OSX/sec/Security/SecECKey.c | 108 +- OSX/sec/Security/SecEMCS.m | 18 +- OSX/sec/Security/SecExports.exp-in | 267 +- OSX/sec/Security/SecFramework.c | 2 +- OSX/sec/Security/SecFrameworkStrings.h | 24 +- OSX/sec/Security/SecImportExport.c | 44 +- OSX/sec/Security/SecItem.c | 576 +- OSX/sec/Security/SecItem.m | 151 + OSX/sec/Security/SecItemBackup.c | 59 +- OSX/sec/Security/SecItemBackup.h | 21 + OSX/sec/Security/SecItemConstants.c | 23 +- OSX/sec/Security/SecItemInternal.h | 24 +- OSX/sec/Security/SecKey.c | 185 +- OSX/sec/Security/SecKeyAdaptors.c | 355 +- OSX/sec/Security/SecOTRDHKey.c | 25 +- OSX/sec/Security/SecOTRMath.c | 11 - OSX/sec/Security/SecOTRSession.c | 34 +- OSX/sec/Security/SecOTRSession.h | 1 + OSX/sec/Security/SecOTRSessionAKE.c | 21 +- OSX/sec/Security/SecOTRUtils.c | 15 +- OSX/sec/Security/SecPasswordGenerate.c | 54 +- OSX/sec/Security/SecPolicy.c | 815 +- OSX/sec/Security/SecPolicyInternal.h | 8 +- OSX/sec/Security/SecPolicyLeafCallbacks.c | 14 +- OSX/sec/Security/SecRSAKey.c | 73 +- OSX/sec/Security/SecRecoveryKey.h | 18 + OSX/sec/Security/SecRecoveryKey.m | 154 +- OSX/sec/Security/SecServerEncryptionSupport.c | 8 +- OSX/sec/Security/SecServerEncryptionSupport.h | 13 +- OSX/sec/Security/SecSharedCredential.c | 4 +- OSX/sec/Security/SecTrust.c | 614 +- OSX/sec/Security/SecTrustInternal.h | 2 + OSX/sec/Security/SecTrustStatusCodes.c | 145 + OSX/sec/Security/SecTrustStatusCodes.h | 53 + OSX/sec/Security/SecTrustStore.c | 16 +- OSX/sec/Security/SecTrustStore.h | 12 +- OSX/sec/Security/SecuritydXPC.c | 94 +- OSX/sec/Security/SecuritydXPC.h | 7 + OSX/sec/Security/Tool/SecurityCommands.h | 32 +- .../Tool/{keychain_find.c => keychain_find.m} | 34 +- OSX/sec/Security/Tool/scep.c | 7 +- OSX/sec/Security/Tool/spc.c | 32 +- OSX/sec/Security/Tool/verify_cert.c | 324 +- OSX/sec/Security/so_01_serverencryption.c | 6 +- OSX/sec/SecurityTool/SecurityTool.c | 26 +- OSX/sec/SecurityTool/SecurityTool.h | 2 - OSX/sec/SecurityTool/builtin_commands.h | 17 + OSX/sec/SecurityTool/security.1 | 16 +- OSX/sec/SecurityTool/sos.m | 347 + OSX/sec/SecurityTool/syncbubble.m | 2 +- OSX/sec/SecurityTool/tool_errors.h | 9 +- OSX/sec/SecurityTool/whoami.m | 2 +- .../swcagent-entitlements.plist | 18 +- OSX/sec/SharedWebCredential/swcagent.m | 241 +- OSX/sec/SharedWebCredential/swcagent_client.h | 2 + OSX/sec/ipc/SecdWatchdog.h | 42 + OSX/sec/ipc/SecdWatchdog.m | 191 + OSX/sec/ipc/client.c | 116 +- OSX/sec/ipc/client_endpoint.m | 187 + OSX/sec/ipc/com.apple.secd.plist | 15 + OSX/sec/ipc/com.apple.securityd.plist | 12 + OSX/sec/ipc/secd.8 | 10 + OSX/sec/ipc/securityd_client.h | 151 +- OSX/sec/ipc/server.c | 882 +- OSX/sec/ipc/server_endpoint.h | 42 + OSX/sec/ipc/server_endpoint.m | 194 + OSX/sec/ipc/server_entitlement_helpers.c | 205 + OSX/sec/ipc/server_entitlement_helpers.h | 48 + OSX/sec/ipc/server_security_helpers.c | 124 + OSX/sec/ipc/server_security_helpers.h | 38 + OSX/sec/ipc/server_xpc.m | 359 + OSX/sec/securityd/AsymKeybagBackup.h | 45 + OSX/sec/securityd/AsymKeybagBackup.m | 147 + OSX/sec/securityd/Info-macOS.plist | 26 + OSX/sec/securityd/OTATrustUtilities.c | 270 +- OSX/sec/securityd/OTATrustUtilities.h | 44 +- .../securityd/Regressions/SOSAccountTesting.h | 323 +- .../Regressions/SOSTransportTestTransports.c | 949 -- .../Regressions/SOSTransportTestTransports.h | 133 +- .../Regressions/SOSTransportTestTransports.m | 918 ++ .../Regressions/SecdTestKeychainUtilities.c | 2 +- ...{sd-10-policytree.c => sd-10-policytree.m} | 0 .../{secd-01-items.c => secd-01-items.m} | 0 ...ocked.c => secd-02-upgrade-while-locked.m} | 0 ...pted-items.c => secd-03-corrupted-items.m} | 0 ...pted-items.c => secd-04-corrupted-items.m} | 0 ...0-initialsync.c => secd-100-initialsync.m} | 17 +- ...er-views.c => secd-130-other-peer-views.m} | 23 +- ...ne-backoff.c => secd-154-engine-backoff.m} | 0 .../secd-155-otr-negotiation-monitor.m | 390 + .../securityd/Regressions/secd-156-timers.m | 100 + .../Regressions/secd-20-keychain_upgrade.m | 34 +- ...ecd-200-logstate.c => secd-200-logstate.m} | 65 +- .../{secd-201-coders.c => secd-201-coders.m} | 168 +- .../Regressions/secd-202-recoverykey.m | 2 +- .../Regressions/secd-210-keyinterest.m | 11 +- .../Regressions/secd-230-keybagtable.m | 253 + ...n-upgrade.c => secd-30-keychain-upgrade.m} | 0 ...-keychain-bad.c => secd-31-keychain-bad.m} | 10 +- ...adable.c => secd-31-keychain-unreadable.m} | 8 +- ...-backup.c => secd-32-restore-bad-backup.m} | 0 .../Regressions/secd-33-keychain-ctk.m | 238 +- ...der-parse.c => secd-34-backup-der-parse.m} | 0 ...inet.c => secd-35-keychain-migrate-inet.m} | 0 .../secd-37-pairing-initial-sync.m | 157 + ...d-40-cc-gestalt.c => secd-40-cc-gestalt.m} | 2 +- ...ecd-49-manifests.c => secd-49-manifests.m} | 0 .../{secd-50-account.c => secd-50-account.m} | 59 +- .../{secd-50-message.c => secd-50-message.m} | 11 +- ...nt-inflate.c => secd-51-account-inflate.m} | 8 +- ...nt-changed.c => secd-52-account-changed.m} | 62 +- ...et.c => secd-52-offering-gencount-reset.m} | 45 +- ...ount-circle.c => secd-55-account-circle.m} | 42 +- .../secd-55-account-incompatibility.c | 235 - .../secd-55-account-incompatibility.m | 113 + ...ccount-apply.c => secd-56-account-apply.m} | 19 +- ...ng.c => secd-57-1-account-last-standing.m} | 26 +- ...ccount-leave.c => secd-57-account-leave.m} | 32 +- ...ord-change.c => secd-58-password-change.m} | 26 +- ...nt-cleanup.c => secd-59-account-cleanup.m} | 47 +- ...ity.c => secd-60-account-cloud-identity.m} | 99 +- ...-61-account-leave-not-in-kansas-anymore.m} | 33 +- ...ount-backup.c => secd-62-account-backup.m} | 62 +- .../Regressions/secd-62-account-hsa-join.c | 157 - ...ction.c => secd-63-account-resurrection.m} | 31 +- ...64-circlereset.c => secd-64-circlereset.m} | 41 +- ...t.c => secd-65-account-retirement-reset.m} | 34 +- ...-recovery.c => secd-66-account-recovery.m} | 123 +- .../{secd-668-ghosts.c => secd-668-ghosts.m} | 51 +- ...fixedKeyIDs.c => secd-67-prefixedKeyIDs.m} | 4 +- ...ine-corrupt.c => secd-70-engine-corrupt.m} | 0 ...-engine-smash.c => secd-70-engine-smash.m} | 0 .../{secd-70-engine.c => secd-70-engine.m} | 2 +- ...d-70-otr-remote.c => secd-70-otr-remote.m} | 15 +- ...71-engine-save.c => secd-71-engine-save.m} | 2 +- ...ervers.c => secd-74-engine-beer-servers.m} | 0 ...-engine-views.c => secd-75-engine-views.m} | 0 ...-idstransport.c => secd-76-idstransport.m} | 118 +- ...ws-alwayson.c => secd-80-views-alwayson.m} | 21 +- ...80-views-basic.c => secd-80-views-basic.m} | 30 +- ...acl-stress.c => secd-81-item-acl-stress.m} | 2 +- ...{secd-81-item-acl.c => secd-81-item-acl.m} | 4 +- ...sistent-ref.c => secd-82-persistent-ref.m} | 36 +- ...-basic.c => secd-82-secproperties-basic.m} | 11 +- .../Regressions/secd-83-item-match-policy.m | 5 + OSX/sec/securityd/Regressions/secd-90-hsa2.c | 159 - ...istence.c => secd-95-escrow-persistence.m} | 27 +- ...sure.c => secd60-account-cloud-exposure.m} | 66 +- ...ds_messaging.c => secd_77_ids_messaging.m} | 105 +- .../securityd/Regressions/secd_regressions.h | 12 +- .../Regressions/securityd_regressions.h | 2 +- OSX/sec/securityd/SOSCloudCircleServer.h | 34 +- ...dCircleServer.c => SOSCloudCircleServer.m} | 815 +- OSX/sec/securityd/SecCAIssuerCache.c | 7 + OSX/sec/securityd/SecCAIssuerRequest.c | 2 + OSX/sec/securityd/SecCertificateServer.c | 1318 ++ OSX/sec/securityd/SecCertificateServer.h | 154 + OSX/sec/securityd/SecCertificateSource.c | 112 +- OSX/sec/securityd/SecDbItem.c | 62 +- OSX/sec/securityd/SecDbItem.h | 10 +- OSX/sec/securityd/SecDbKeychainItem.c | 24 +- OSX/sec/securityd/SecDbKeychainItem.h | 1 + OSX/sec/securityd/SecDbQuery.c | 59 +- OSX/sec/securityd/SecDbQuery.h | 8 + OSX/sec/securityd/SecItemDataSource.c | 177 +- OSX/sec/securityd/SecItemDb.c | 281 +- OSX/sec/securityd/SecItemDb.h | 61 +- OSX/sec/securityd/SecItemSchema.c | 1284 +- OSX/sec/securityd/SecItemSchema.h | 24 +- OSX/sec/securityd/SecItemServer.c | 1100 +- OSX/sec/securityd/SecItemServer.h | 26 +- OSX/sec/securityd/SecKeybagSupport.c | 23 +- ...ettingsServer.c => SecLogSettingsServer.m} | 5 +- OSX/sec/securityd/SecOCSPCache.c | 16 +- OSX/sec/securityd/SecOCSPRequest.c | 1 + OSX/sec/securityd/SecOCSPResponse.c | 36 +- .../{SecOTRRemote.c => SecOTRRemote.m} | 58 +- .../securityd/SecPinningDb.h} | 43 +- OSX/sec/securityd/SecPinningDb.m | 943 ++ OSX/sec/securityd/SecPolicyServer.c | 2452 +--- OSX/sec/securityd/SecPolicyServer.h | 86 +- OSX/sec/securityd/SecRevocationDb.c | 2203 ++-- OSX/sec/securityd/SecRevocationDb.h | 46 +- .../SecRevocationNetworking.h} | 18 +- OSX/sec/securityd/SecRevocationNetworking.m | 408 + OSX/sec/securityd/SecRevocationServer.c | 1096 ++ OSX/sec/securityd/SecRevocationServer.h | 70 + OSX/sec/securityd/SecTrustServer.c | 732 +- OSX/sec/securityd/SecTrustServer.h | 67 +- OSX/sec/securityd/asynchttp.c | 18 +- OSX/sec/securityd/com.apple.secd.sb | 47 + OSX/sec/securityd/entitlements.plist | 32 + OSX/sec/securityd/personalization.c | 3 +- OSX/sec/securityd/policytree.c | 4 +- OSX/sec/securityd/policytree.h | 1 - OSX/sec/securityd/spi.c | 93 +- OSX/sec/securityd/spi.h | 7 +- OSX/sectests/main.c | 6 +- OSX/shared_regressions/shared_regressions.h | 19 +- .../parse_fail_spki_unused_bits.cer | Bin 0 -> 584 bytes ..._fail_basic_constraints_too_many_bytes.cer | Bin 0 -> 586 bytes ...ail_basic_constraints_wrong_true_value.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/parse_fail_length_1.cer | Bin 0 -> 649 bytes .../parse_fail_length_10.cer | Bin 0 -> 649 bytes .../parse_fail_length_11.cer | Bin 0 -> 649 bytes .../parse_fail_length_12.cer | Bin 0 -> 649 bytes .../parse_fail_length_13.cer | Bin 0 -> 649 bytes .../parse_fail_length_14.cer | Bin 0 -> 649 bytes .../parse_fail_length_15.cer | Bin 0 -> 649 bytes .../parse_fail_length_16.cer | Bin 0 -> 649 bytes .../parse_fail_length_17.cer | Bin 0 -> 649 bytes .../parse_fail_length_18.cer | Bin 0 -> 649 bytes .../parse_fail_length_19.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_length_2.cer | Bin 0 -> 649 bytes .../parse_fail_length_20.cer | Bin 0 -> 649 bytes .../parse_fail_length_21.cer | Bin 0 -> 649 bytes .../parse_fail_length_22.cer | Bin 0 -> 649 bytes .../parse_fail_length_23.cer | Bin 0 -> 649 bytes .../parse_fail_length_24.cer | Bin 0 -> 649 bytes .../parse_fail_length_25.cer | Bin 0 -> 649 bytes .../parse_fail_length_26.cer | Bin 0 -> 649 bytes .../parse_fail_length_27.cer | Bin 0 -> 649 bytes .../parse_fail_length_28.cer | Bin 0 -> 649 bytes .../parse_fail_length_29.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_length_3.cer | Bin 0 -> 649 bytes .../parse_fail_length_30.cer | Bin 0 -> 649 bytes .../parse_fail_length_31.cer | Bin 0 -> 649 bytes .../parse_fail_length_32.cer | Bin 0 -> 649 bytes .../parse_fail_length_33.cer | Bin 0 -> 649 bytes .../parse_fail_length_34.cer | Bin 0 -> 649 bytes .../parse_fail_length_35.cer | Bin 0 -> 649 bytes .../parse_fail_length_36.cer | Bin 0 -> 649 bytes .../parse_fail_length_37.cer | Bin 0 -> 649 bytes .../parse_fail_length_38.cer | Bin 0 -> 649 bytes .../parse_fail_length_39.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_length_4.cer | Bin 0 -> 649 bytes .../parse_fail_length_40.cer | Bin 0 -> 649 bytes .../parse_fail_length_41.cer | Bin 0 -> 649 bytes .../parse_fail_length_42.cer | Bin 0 -> 649 bytes .../parse_fail_length_43.cer | Bin 0 -> 649 bytes .../parse_fail_length_44.cer | Bin 0 -> 649 bytes .../parse_fail_length_45.cer | Bin 0 -> 649 bytes .../parse_fail_length_46.cer | Bin 0 -> 649 bytes .../parse_fail_length_47.cer | Bin 0 -> 649 bytes .../parse_fail_length_48.cer | Bin 0 -> 649 bytes .../parse_fail_length_49.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_length_5.cer | Bin 0 -> 649 bytes .../parse_fail_length_50.cer | Bin 0 -> 649 bytes .../parse_fail_length_51.cer | Bin 0 -> 649 bytes .../parse_fail_length_52.cer | Bin 0 -> 649 bytes .../parse_fail_length_53.cer | Bin 0 -> 649 bytes .../parse_fail_length_54.cer | Bin 0 -> 649 bytes .../parse_fail_length_55.cer | Bin 0 -> 649 bytes .../parse_fail_length_56.cer | Bin 0 -> 649 bytes .../parse_fail_length_57.cer | Bin 0 -> 649 bytes .../parse_fail_length_58.cer | Bin 0 -> 649 bytes .../parse_fail_length_59.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_length_6.cer | Bin 0 -> 649 bytes .../parse_fail_length_60.cer | Bin 0 -> 649 bytes .../parse_fail_length_61.cer | Bin 0 -> 649 bytes .../parse_fail_length_62.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_length_7.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_length_8.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_length_9.cer | Bin 0 -> 649 bytes .../parse_fail_rsa_encryption_non_null.cer | Bin 0 -> 994 bytes .../parse_fail_rsa_sig_nonnull.cer | Bin 0 -> 847 bytes .../parse_fail_spki_negative_rsa.cer | Bin 0 -> 993 bytes .../ParseFailureCerts/parse_fail_tag_1.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_10.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_11.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_12.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_13.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_14.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_15.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_16.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_17.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_18.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_19.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_2.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_20.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_21.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_22.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_23.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_24.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_25.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_26.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_29.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_3.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_30.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_31.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_33.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_34.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_35.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_37.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_38.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_39.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_4.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_5.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_6.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_7.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_8.cer | Bin 0 -> 649 bytes .../ParseFailureCerts/parse_fail_tag_9.cer | Bin 0 -> 649 bytes .../parse_fail_too_small.cer | Bin 0 -> 640 bytes .../ParseFailureCerts/parse_fail_v4.cer | Bin 0 -> 649 bytes .../signature_fail_length_1.cer | Bin 0 -> 585 bytes .../signature_fail_length_2.cer | Bin 0 -> 585 bytes .../signature_fail_length_3.cer | Bin 0 -> 585 bytes .../signature_fail_length_4.cer | Bin 0 -> 585 bytes .../signature_fail_length_5.cer | Bin 0 -> 585 bytes .../signature_fail_length_6.cer | Bin 0 -> 585 bytes .../signature_fail_tag_1.cer | Bin 0 -> 585 bytes .../signature_fail_tag_2.cer | Bin 0 -> 585 bytes .../signature_fail_tag_3.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_1.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_10.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_2.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_3.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_4.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_5.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_6.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_7.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_8.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_length_9.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_tag_1.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_tag_2.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_tag_3.cer | Bin 0 -> 585 bytes .../ParseFailureCerts/spki_fail_tag_5.cer | Bin 0 -> 585 bytes ...e_success_basic_constraints_no_pathlen.cer | Bin 0 -> 582 bytes .../parse_success_issuerUID.cer | Bin 0 -> 1296 bytes .../parse_success_keyusage_mask.cer | Bin 0 -> 649 bytes .../parse_success_multiple_ekus.cer | Bin 0 -> 694 bytes .../parse_success_unknown_apple_extension.cer | Bin 0 -> 466 bytes .../parse_success_unknown_extension.cer | Bin 0 -> 649 bytes .../parse_fail_nonnull_sig_alg_params.cer | Bin 0 -> 654 bytes .../parse_fail_signature_negative.cer | Bin 0 -> 584 bytes .../path_fail_mismatch_algorithm.cer | Bin 0 -> 655 bytes .../signature_fail_length_7.cer | Bin 0 -> 585 bytes .../signature_fail_length_8.cer | Bin 0 -> 585 bytes .../PathFailureCerts/signature_fail_tag_4.cer | Bin 0 -> 585 bytes .../TODOFailureCerts/TODODescriptions.txt | 29 + ...e_fail_basic_constraints_notCA_pathlen.cer | Bin 0 -> 582 bytes .../parse_fail_ec_not_on_curve.cer | Bin 0 -> 585 bytes .../parse_fail_keyusage_extra_bit.cer | Bin 0 -> 650 bytes .../TODOFailureCerts/parse_fail_length_63.cer | Bin 0 -> 649 bytes .../TODOFailureCerts/parse_fail_tag_27.cer | Bin 0 -> 649 bytes .../TODOFailureCerts/parse_fail_tag_28.cer | Bin 0 -> 649 bytes .../TODOFailureCerts/parse_fail_tag_32.cer | Bin 0 -> 649 bytes .../TODOFailureCerts/parse_fail_tag_36.cer | Bin 0 -> 649 bytes .../TODOFailureCerts/parse_fail_too_big.cer | Bin 0 -> 672 bytes .../TODOFailureCerts/spki_fail_tag_4.cer | Bin 0 -> 585 bytes .../si-18-certificate-parse/root.cer | Bin 0 -> 585 bytes .../AppleiPh0neCA.cer | Bin 0 -> 1015 bytes .../AppleiPh0neDeviceCA.cer | Bin 0 -> 877 bytes .../EntrustCAL1C.cer | Bin 0 -> 1270 bytes .../EntrustRootCA.cer | Bin 0 -> 1070 bytes .../EscrowServiceRootCA0.cer | Bin 0 -> 976 bytes .../EscrowServiceRootCA100.cer | Bin 0 -> 980 bytes .../EscrowServiceRootCA101.cer | Bin 0 -> 980 bytes .../PinningPolicyTrustTest.plist | 669 +- .../SymantecClass3SSCAG4.cer | Bin 0 -> 1340 bytes .../TestAppleiPh0neDeviceCA.cer | Bin 0 -> 892 bytes ...3PublicPrimaryCertificationAuthorityG5.cer | Bin 0 -> 1239 bytes .../apn_legacy.cer | Bin 0 -> 1319 bytes .../escrow_service_key_049F9D11.cer | Bin 0 -> 1034 bytes .../escrow_service_key_9B6EEF8D.cer | Bin 0 -> 1035 bytes .../escrow_service_key_B157A8D4.cer | Bin 0 -> 1033 bytes .../iPh0ne_developer.cer | Bin 0 -> 1448 bytes .../si-20-sectrust-policies-data/ids_prod.cer | Bin 0 -> 1241 bytes .../{ids.cer => ids_qa.cer} | Bin .../ids_symantec.cer | Bin 0 -> 1651 bytes .../ppq_signing.cer | Bin 0 -> 1036 bytes .../wildcard_icloud.cer | Bin 0 -> 1406 bytes .../si-20-sectrust-policies.m | 77 +- OSX/shared_regressions/si-44-seckey-aks.m | 131 + OSX/shared_regressions/si-44-seckey-ec.m | 88 +- OSX/shared_regressions/si-44-seckey-fv.m | 68 + OSX/shared_regressions/si-44-seckey-gen.m | 119 +- OSX/shared_regressions/si-44-seckey-ies.m | 217 +- OSX/shared_regressions/si-44-seckey-rsa.m | 103 + OSX/shared_regressions/si-82-sectrust-ct.m | 17 +- OSX/trustd/com.apple.trustd.sb | 30 - OSX/trustd/iOS/com.apple.trustd.plist | 38 + OSX/trustd/iOS/entitlements.plist | 28 + .../{ => macOS}/SecTrustOSXEntryPoints.h | 2 +- .../{ => macOS}/com.apple.trustd.agent.plist | 2 +- OSX/trustd/{ => macOS}/com.apple.trustd.plist | 2 +- OSX/trustd/macOS/com.apple.trustd.sb | 70 + OSX/trustd/{ => macOS}/entitlements.plist | 8 + OSX/trustd/macOS/trustd.8 | 14 + OSX/trustd/trustd-Info.plist | 2 +- OSX/trustd/trustd.c | 655 + .../Regressions/su-41-secdb-stress.c | 2 +- .../Regressions/utilities_regressions.h | 2 +- OSX/utilities/SecurityTool/readline.c | 4 + OSX/utilities/src/SecADWrapper.c | 11 +- OSX/utilities/src/SecADWrapper.h | 2 - OSX/utilities/src/SecAKSWrappers.h | 24 +- OSX/utilities/src/SecCFCCWrappers.c | 11 + OSX/utilities/src/SecCFCCWrappers.h | 3 + OSX/utilities/src/SecCFError.c | 10 - OSX/utilities/src/SecCFError.h | 30 +- OSX/utilities/src/SecCFWrappers.h | 13 +- OSX/utilities/src/SecCertificateTrace.c | 549 - OSX/utilities/src/SecDb.c | 311 +- OSX/utilities/src/SecDb.h | 26 +- OSX/utilities/src/SecFileLocations.c | 15 +- OSX/utilities/src/SecFileLocations.h | 3 + OSX/utilities/src/SecInternalRelease.c | 12 +- OSX/utilities/src/SecMeta.h | 203 - OSX/utilities/src/SecNSAdditions.h | 73 + OSX/utilities/src/SecNSAdditions.m | 132 + OSX/utilities/src/SecPLWrappers.h | 48 + OSX/utilities/src/SecPLWrappers.m | 99 + OSX/utilities/src/SecPaddingConfigurations.c | 94 + .../src/SecPaddingConfigurationsPriv.h | 45 + OSX/utilities/src/debugging.c | 48 +- OSX/utilities/src/debugging.h | 20 +- OSX/utilities/src/der_plist_internal.c | 4 - OSX/utilities/src/der_plist_internal.h | 4 +- OSX/utilities/src/fileIo.c | 4 +- OSX/utilities/src/iCloudKeychainTrace.c | 106 +- OSX/utilities/src/iOSforOSX-SecAttr.c | 1 - OSX/utilities/src/sec_action.c | 116 + OSX/utilities/src/sec_action.h | 80 + OTAPKIAssetTool/OTAPKIAssetTool.xcconfig | 2 +- README | 4 + .../SecAtomicFile/SecAtomicFile.cpp | 62 + RegressionTests/Security.plist | 52 + RegressionTests/manifeststresstest/Config.h | 43 + RegressionTests/manifeststresstest/Config.m | 13 + RegressionTests/manifeststresstest/Keychain.h | 31 + RegressionTests/manifeststresstest/Keychain.m | 181 + RegressionTests/manifeststresstest/Monkey.h | 52 + RegressionTests/manifeststresstest/Monkey.m | 288 + .../manifeststresstest.entitlements | 10 + .../manifeststresstest/manifeststresstest.m | 225 + RegressionTests/manifeststresstest/mark.h | 25 + RegressionTests/manifeststresstest/mark.m | 134 + .../secitemfunctionality.m | 71 +- .../seckeychainnetworkextensionstest/main.m | 77 + ...keychainnetworkextensionstest.entitlements | 11 + .../main.m | 50 + ...workextensionsystemdaemontest.entitlements | 12 + .../main.m | 49 + ...tensionunauthorizedaccesstest.entitlements | 10 + SOSCCAuthPlugin/SOSCCAuthPlugin.m | 9 +- Security.exp-in | 47 +- Security.xcodeproj/project.pbxproj | 10608 +++++++++++++--- .../xcshareddata/xcschemes/CKKSTests.xcscheme | 70 + .../xcschemes/TrustedPeers.xcscheme | 100 + .../xcschemes/ios - Debug.xcscheme | 39 +- .../xcschemes/ios - Release.xcscheme | 10 +- .../xcschemes/ios - secdtests.xcscheme | 70 +- .../xcschemes/osx - World.xcscheme | 93 +- .../xcschemes/osx - secdtests.xcscheme | 20 +- .../xcschemes/osx - sectests.xcscheme | 2 +- .../SecurityTests-Entitlements.plist | 5 + SecurityTests/nist-certs/Expectations.plist | 52 +- SecurityTests/testlist.h | 2 +- SecurityTests/testmain.c | 6 +- SecurityTool/authz.c | 6 +- SecurityTool/cmsutil.c | 40 +- SecurityTool/createFVMaster.c | 17 +- SecurityTool/identity_find.h | 2 +- .../{identity_find.c => identity_find.m} | 179 +- SecurityTool/identity_prefs.c | 24 +- SecurityTool/keychain_add.c | 2 +- .../{keychain_export.c => keychain_export.m} | 89 +- SecurityTool/keychain_find.c | 85 +- SecurityTool/keychain_utilities.c | 73 +- SecurityTool/keychain_utilities.h | 2 +- SecurityTool/security.1 | 27 +- SecurityTool/security.c | 41 +- SecurityTool/security_tool.h | 6 +- SecurityTool/smartcards.m | 8 +- SecurityTool/trusted_cert_add.c | 3 +- SecurityTool/trusted_cert_utils.c | 33 +- SecurityTool/trusted_cert_utils.h | 13 +- SecurityTool/verify_cert.c | 141 +- SecurityUnitTests/Info.plist | 22 + SecurityUnitTests/SecurityUnitTests.m | 43 + .../SWCViewController.m | 18 +- base/SecBase.h | 20 +- base/SecBasePriv.h | 1 - base/SecRandom.h | 7 +- base/Security.h | 4 +- cssm/certextensions.h | 1 + cssm/cssmapple.h | 7 +- header_symlinks/iOS/Security/CSCommon.h | 1 + header_symlinks/iOS/Security/CSCommonPriv.h | 1 + header_symlinks/iOS/Security/CodeSigning.h | 1 + header_symlinks/iOS/Security/SecCode.h | 1 + header_symlinks/iOS/Security/SecCodeHost.h | 1 + header_symlinks/iOS/Security/SecCodePriv.h | 1 + header_symlinks/iOS/Security/SecCodeSigner.h | 1 + header_symlinks/iOS/Security/SecRequirement.h | 1 + .../iOS/Security/SecRequirementPriv.h | 1 + header_symlinks/iOS/Security/SecStaticCode.h | 1 + .../iOS/Security/SecStaticCodePriv.h | 1 + header_symlinks/iOS/Security/X509Templates.h | 1 + header_symlinks/iOS/Security/keyTemplates.h | 1 + header_symlinks/iOS/Security/nameTemplates.h | 1 + header_symlinks/iOS/Security/oidsattr.h | 1 + header_symlinks/iOS/Security/osxcode.h | 1 + .../macOS/Security/SecSharedCredential.h | 1 + .../Security => keychain}/SecAccessControl.h | 0 keychain/SecImportExport.h | 8 +- keychain/SecItem.h | 16 +- keychain/SecItemPriv.h | 131 +- keychain/SecKey.h | 177 +- keychain/SecKeyPriv.h | 15 +- .../SecSharedCredential.h | 0 keychain/analytics/CKKSPowerCollection.h | 40 + keychain/analytics/CKKSPowerCollection.m | 83 + ...DKeychainCKKSRateLimiterAggregatedScores.h | 50 + ...DKeychainCKKSRateLimiterAggregatedScores.m | 264 + .../awd/AWDKeychainCKKSRateLimiterOverload.h | 47 + .../awd/AWDKeychainCKKSRateLimiterOverload.m | 227 + .../AWDKeychainCKKSRateLimiterTopWriters.h | 50 + .../AWDKeychainCKKSRateLimiterTopWriters.m | 244 + .../awd/AWDKeychainSecDbMarkedCorrupt.h | 48 + .../awd/AWDKeychainSecDbMarkedCorrupt.m | 242 + .../analytics/awd/AWDMetricIds_Keychain.h | 35 + .../awd/AwdMetadata-0x60-Keychain.bin | Bin 0 -> 924 bytes keychain/analytics/awd/awdgen.yaml | 2 + keychain/ckks/CKKS.h | 274 + keychain/ckks/CKKS.m | 402 + keychain/ckks/CKKSAPSReceiver.h | 59 + keychain/ckks/CKKSAPSReceiver.m | 164 + keychain/ckks/CKKSAnalyticsLogger.h | 62 + keychain/ckks/CKKSAnalyticsLogger.m | 144 + keychain/ckks/CKKSCKAccountStateTracker.h | 89 + keychain/ckks/CKKSCKAccountStateTracker.m | 396 + keychain/ckks/CKKSCondition.h | 44 + keychain/ckks/CKKSCondition.m | 56 + keychain/ckks/CKKSControlProtocol.h | 40 + keychain/ckks/CKKSControlProtocol.m | 108 + keychain/ckks/CKKSCurrentItemPointer.h | 52 + keychain/ckks/CKKSCurrentItemPointer.m | 158 + keychain/ckks/CKKSCurrentKeyPointer.h | 65 + keychain/ckks/CKKSCurrentKeyPointer.m | 219 + keychain/ckks/CKKSDeviceStateEntry.h | 76 + keychain/ckks/CKKSDeviceStateEntry.m | 301 + .../CKKSFetchAllRecordZoneChangesOperation.h | 51 + .../CKKSFetchAllRecordZoneChangesOperation.m | 363 + keychain/ckks/CKKSGroupOperation.h | 95 + keychain/ckks/CKKSGroupOperation.m | 469 + keychain/ckks/CKKSHealKeyHierarchyOperation.h | 40 + keychain/ckks/CKKSHealKeyHierarchyOperation.m | 406 + keychain/ckks/CKKSIncomingQueueEntry.h | 62 + keychain/ckks/CKKSIncomingQueueEntry.m | 146 + keychain/ckks/CKKSIncomingQueueOperation.h | 43 + keychain/ckks/CKKSIncomingQueueOperation.m | 669 + keychain/ckks/CKKSItem.h | 119 + keychain/ckks/CKKSItem.m | 514 + keychain/ckks/CKKSItemEncrypter.h | 62 + keychain/ckks/CKKSItemEncrypter.m | 225 + keychain/ckks/CKKSKey.h | 140 + keychain/ckks/CKKSKey.m | 833 ++ keychain/ckks/CKKSKeychainView.h | 251 + keychain/ckks/CKKSKeychainView.m | 2436 ++++ keychain/ckks/CKKSLockStateTracker.h | 43 + keychain/ckks/CKKSLockStateTracker.m | 122 + keychain/ckks/CKKSLogger.h | 64 + keychain/ckks/CKKSLogger.m | 706 + keychain/ckks/CKKSLogging.plist | 16 + keychain/ckks/CKKSManifest.h | 115 + keychain/ckks/CKKSManifest.m | 1450 +++ keychain/ckks/CKKSManifestLeafRecord.h | 65 + keychain/ckks/CKKSManifestLeafRecord.m | 317 + keychain/ckks/CKKSMirrorEntry.h | 58 + keychain/ckks/CKKSMirrorEntry.m | 154 + keychain/ckks/CKKSNearFutureScheduler.h | 59 + keychain/ckks/CKKSNearFutureScheduler.m | 183 + keychain/ckks/CKKSNewTLKOperation.h | 40 + keychain/ckks/CKKSNewTLKOperation.m | 336 + keychain/ckks/CKKSNotifier.h | 35 + keychain/ckks/CKKSNotifier.m | 37 + keychain/ckks/CKKSOutgoingQueueEntry.h | 67 + keychain/ckks/CKKSOutgoingQueueEntry.m | 300 + .../ckks/CKKSOutgoingQueueOperation.h | 41 +- keychain/ckks/CKKSOutgoingQueueOperation.m | 533 + .../ckks/CKKSProcessReceivedKeysOperation.h | 34 + .../ckks/CKKSProcessReceivedKeysOperation.m | 212 + keychain/ckks/CKKSRateLimiter.h | 62 + keychain/ckks/CKKSRateLimiter.m | 305 + keychain/ckks/CKKSRecordHolder.h | 60 + keychain/ckks/CKKSRecordHolder.m | 135 + .../CKKSReencryptOutgoingItemsOperation.h | 41 + .../CKKSReencryptOutgoingItemsOperation.m | 188 + keychain/ckks/CKKSSIV.h | 62 + keychain/ckks/CKKSSIV.m | 391 + keychain/ckks/CKKSSQLDatabaseObject.h | 110 + keychain/ckks/CKKSSQLDatabaseObject.m | 455 + keychain/ckks/CKKSScanLocalItemsOperation.h | 44 + keychain/ckks/CKKSScanLocalItemsOperation.m | 274 + keychain/ckks/CKKSSynchronizeOperation.h | 40 + keychain/ckks/CKKSSynchronizeOperation.m | 164 + .../CKKSUpdateCurrentItemPointerOperation.h | 41 + .../CKKSUpdateCurrentItemPointerOperation.m | 259 + .../ckks/CKKSUpdateDeviceStateOperation.h | 37 + .../ckks/CKKSUpdateDeviceStateOperation.m | 184 + keychain/ckks/CKKSViewManager.h | 129 + keychain/ckks/CKKSViewManager.m | 832 ++ keychain/ckks/CKKSZone.h | 126 + keychain/ckks/CKKSZone.m | 519 + keychain/ckks/CKKSZoneChangeFetcher.h | 72 + keychain/ckks/CKKSZoneChangeFetcher.m | 256 + keychain/ckks/CKKSZoneStateEntry.h | 76 + keychain/ckks/CKKSZoneStateEntry.m | 170 + keychain/ckks/CloudKitCategories.h | 41 + keychain/ckks/CloudKitCategories.m | 59 + keychain/ckks/CloudKitDependencies.h | 125 + keychain/ckks/RateLimiter.h | 132 + keychain/ckks/RateLimiter.m | 364 + keychain/ckks/tests/CKKSAPSReceiverTests.m | 194 + keychain/ckks/tests/CKKSCloudKitTests.m | 593 + .../ckks/tests/CKKSCloudKitTestsInfo.plist | 22 + keychain/ckks/tests/CKKSConditionTests.m | 83 + keychain/ckks/tests/CKKSDispatchTests.m | 249 + keychain/ckks/tests/CKKSEncryptionTests.m | 653 + keychain/ckks/tests/CKKSLoggerTests.m | 230 + keychain/ckks/tests/CKKSManifestTests.m | 329 + .../ckks/tests/CKKSNearFutureSchedulerTests.m | 249 + keychain/ckks/tests/CKKSOperationTests.m | 414 + keychain/ckks/tests/CKKSRateLimiterTests.m | 292 + keychain/ckks/tests/CKKSSOSTests.m | 531 + keychain/ckks/tests/CKKSSQLTests.m | 582 + keychain/ckks/tests/CKKSTests+API.h | 49 + keychain/ckks/tests/CKKSTests+API.m | 778 ++ keychain/ckks/tests/CKKSTests+Coalesce.m | 120 + .../ckks/tests/CKKSTests+CurrentPointerAPI.m | 751 ++ keychain/ckks/tests/CKKSTests.h | 53 + keychain/ckks/tests/CKKSTests.m | 2790 ++++ .../tests/CloudKitKeychainSyncingMockXCTest.h | 102 + .../tests/CloudKitKeychainSyncingMockXCTest.m | 718 ++ keychain/ckks/tests/CloudKitMockXCTest.h | 139 + keychain/ckks/tests/CloudKitMockXCTest.m | 793 ++ keychain/ckks/tests/Info.plist | 22 + keychain/ckks/tests/MockCloudKit.h | 111 + keychain/ckks/tests/MockCloudKit.m | 435 + keychain/ckks/tests/RateLimiterTests.m | 292 + .../ckks/tests/testrunner/KeychainCKKS.plist | 33 + ...chainEntitledTestRunner-Entitlements.plist | 32 + .../testrunner/KeychainEntitledTestRunner.m | 221 + keychain/ckksctl/ckksctl-Entitlements.plist | 8 + keychain/ckksctl/ckksctl.h | 18 + keychain/ckksctl/ckksctl.m | 599 + keychain/trust/.open_source_exclude | 0 keychain/trust/TrustedPeers/Info.plist | 26 + keychain/trust/TrustedPeers/TPCategoryRule.h | 47 + keychain/trust/TrustedPeers/TPCategoryRule.m | 72 + keychain/trust/TrustedPeers/TPCircle.h | 66 + keychain/trust/TrustedPeers/TPCircle.m | 123 + keychain/trust/TrustedPeers/TPDecrypter.h | 36 + keychain/trust/TrustedPeers/TPEncrypter.h | 36 + keychain/trust/TrustedPeers/TPHash.h | 60 + keychain/trust/TrustedPeers/TPHash.m | 175 + keychain/trust/TrustedPeers/TPModel.h | 253 + keychain/trust/TrustedPeers/TPModel.m | 730 ++ keychain/trust/TrustedPeers/TPPeer.h | 68 + keychain/trust/TrustedPeers/TPPeer.m | 108 + .../trust/TrustedPeers/TPPeerDynamicInfo.h | 67 + .../trust/TrustedPeers/TPPeerDynamicInfo.m | 131 + .../trust/TrustedPeers/TPPeerPermanentInfo.h | 68 + .../trust/TrustedPeers/TPPeerPermanentInfo.m | 151 + .../trust/TrustedPeers/TPPeerStableInfo.h | 68 + .../trust/TrustedPeers/TPPeerStableInfo.m | 144 + keychain/trust/TrustedPeers/TPPolicy.h | 55 + keychain/trust/TrustedPeers/TPPolicy.m | 70 + .../trust/TrustedPeers/TPPolicyDocument.h | 68 + .../trust/TrustedPeers/TPPolicyDocument.m | 335 + keychain/trust/TrustedPeers/TPSigningKey.h | 52 + .../trust/TrustedPeers/TPTypes.h | 19 +- keychain/trust/TrustedPeers/TPUtils.h | 34 + keychain/trust/TrustedPeers/TPUtils.m | 43 + keychain/trust/TrustedPeers/TPVoucher.h | 72 + keychain/trust/TrustedPeers/TPVoucher.m | 129 + .../trust/TrustedPeers/TrustedPeers.h | 58 +- keychain/trust/TrustedPeersTests/Info.plist | 22 + .../trust/TrustedPeersTests/TPCircleTests.m | 52 + .../TrustedPeersTests/TPDummyDecrypter.h | 26 +- .../TrustedPeersTests/TPDummyDecrypter.m | 49 + .../TrustedPeersTests/TPDummyEncrypter.h | 39 + .../TrustedPeersTests/TPDummyEncrypter.m | 48 + .../TrustedPeersTests/TPDummySigningKey.h | 54 + .../TrustedPeersTests/TPDummySigningKey.m | 85 + .../TPDummySigningKeyTests.m | 43 + .../trust/TrustedPeersTests/TPHashTests.m | 92 + .../trust/TrustedPeersTests/TPModelTests.m | 831 ++ .../TPPeerPermanentInfoTests.m | 209 + .../TrustedPeersTests/TPPeerStableInfoTests.m | 131 + .../trust/TrustedPeersTests/TPPeerTests.m | 119 + .../TrustedPeersTests/TPPolicyDocumentTests.m | 68 + .../trust/TrustedPeersTests/TPUtilsTests.m | 39 + .../trust/TrustedPeersTests/TPVoucherTests.m | 103 + lib/SecArgParse.c | 362 + lib/SecArgParse.h | 85 + libsecurity_smime/lib/CMSDecoder.c | 997 ++ libsecurity_smime/lib/CMSDecoder.h | 418 + libsecurity_smime/lib/CMSEncoder.c | 1493 +++ libsecurity_smime/lib/CMSEncoder.h | 424 + libsecurity_smime/lib/CMSUtils.c | 146 + libsecurity_smime/lib/CMSUtils.h | 79 + libsecurity_smime/lib/SecCmsBase.h | 2 + libsecurity_smime/lib/SecCmsContentInfo.h | 3 + libsecurity_smime/lib/SecCmsSignerInfo.h | 9 + libsecurity_smime/lib/SecSMIMEPriv.h | 2 +- libsecurity_smime/lib/cert.h | 8 + libsecurity_smime/lib/cmscinfo.c | 39 +- libsecurity_smime/lib/cmscipher.c | 832 +- libsecurity_smime/lib/cmsdigest.c | 66 +- libsecurity_smime/lib/cmsencode.c | 9 +- libsecurity_smime/lib/cmsenvdata.c | 22 + libsecurity_smime/lib/cmslocal.h | 2 + libsecurity_smime/lib/cmspriv.h | 7 +- libsecurity_smime/lib/cmspubkey.c | 4 + libsecurity_smime/lib/cmsrecinfo.c | 96 +- libsecurity_smime/lib/cmssigdata.c | 68 +- libsecurity_smime/lib/cmssiginfo.c | 174 +- libsecurity_smime/lib/cmsutil.c | 25 + libsecurity_smime/lib/crypto-embedded.c | 105 +- libsecurity_smime/lib/cryptohi.h | 26 + libsecurity_smime/lib/secoid.c | 37 +- libsecurity_smime/lib/secoidt.h | 3 + libsecurity_smime/lib/smimeutil.c | 45 +- .../libCMS.xcodeproj/project.pbxproj | 74 +- resources/English.lproj/Certificate.strings | Bin 24718 -> 25744 bytes resources/English.lproj/CloudKeychain.strings | Bin 10030 -> 11502 bytes resources/English.lproj/OID.strings | Bin 212512 -> 212512 bytes .../SharedWebCredentials.strings | Bin 4910 -> 5020 bytes secacltests/main.c | 6 +- secacltests/testlist.h | 2 +- secdtests/main.m | 11 +- secdtests/secdtests-entitlements.plist | 12 + sectask/SecEntitlements.h | 43 +- sectask/SecTask.c | 112 +- .../lib => sectask}/SecTaskPriv.h | 30 +- sectask/regressions/sectask-10-sectask.c | 4 +- sectask/regressions/sectask_regressions.h | 6 +- .../security-sysdiagnose.entitlements.plist | 8 + security-sysdiagnose/security-sysdiagnose.m | 159 +- securityd/etc/com.apple.securityd.plist | 7 + .../KeyStore/KeyStoreEvents.c | 5 +- .../project.pbxproj | 47 +- .../com.apple.securitydservice.sb | 3 +- .../securityd_service/main.c | 307 +- .../securityd_service/securityd_service.8 | 10 + .../securityd_service/securityd_service.h | 4 + .../securityd_service_client.c | 83 + .../securityd_service_client.h | 3 + .../securityd_service/service.entitlements | 6 +- securityd/src/SharedMemoryServer.cpp | 54 +- securityd/src/acls.cpp | 6 +- securityd/src/agentquery.cpp | 35 +- securityd/src/agentquery.h | 2 +- securityd/src/csproxy.cpp | 38 +- securityd/src/dbcrypto.cpp | 3 +- securityd/src/kcdatabase.cpp | 84 +- securityd/src/kcdatabase.h | 2 + securityd/src/main.cpp | 21 +- securityd/src/notifications.cpp | 5 - securityd/src/structure.cpp | 4 +- securityd/src/tokend.cpp | 2 + securityd/src/tokendatabase.cpp | 1 - securityd/src/transition.cpp | 11 + sslViewer/SSLViewer.c | 68 +- sslViewer/sslAppUtils.cpp | 2 +- sslViewer/sslServer.cpp | 3 +- tests/secfuzzer/SecCertificateFuzzer.c | 22 + tests/secfuzzer/secfuzzer.m | 48 + trust/SecCertificate.h | 27 +- trust/SecCertificatePriv.h | 16 +- trust/SecCertificateRequest.h | 155 - trust/SecPolicyPriv.h | 221 +- trust/SecTrust.h | 15 +- trust/SecTrustPriv.h | 65 +- trust/SecTrustSettingsPriv.h | 21 +- xcconfig/PlatformFeatures.xcconfig | 26 + xcconfig/PlatformLibraries.xcconfig | 55 + xcconfig/Security.xcconfig | 26 +- ...ork_requiring_modern_objc_runtime.xcconfig | 7 + xcconfig/ios_on_macos.xcconfig | 2 + xcconfig/lib_ios.xcconfig | 12 +- xcconfig/lib_ios_debug.xcconfig | 5 - xcconfig/lib_ios_debug_all_archs.xcconfig | 7 - xcconfig/lib_ios_release.xcconfig | 1 - ...ug_shim.xcconfig => lib_ios_shim.xcconfig} | 2 +- xcconfig/lib_ios_x64_debug.xcconfig | 5 - xcconfig/lib_ios_x64_debug_shim.xcconfig | 3 - xcconfig/lib_ios_x64_release.xcconfig | 1 - xcconfig/lib_ios_x64_release_shim.xcconfig | 3 - ...him.xcconfig => lib_ios_x64_shim.xcconfig} | 2 +- xcconfig/macos_legacy_lib.xcconfig | 2 +- 1475 files changed, 111213 insertions(+), 35966 deletions(-) create mode 100644 Analytics/SFAnalyticsLogger.h create mode 100644 Analytics/SFAnalyticsLogger.m create mode 100644 Analytics/SFAnalyticsLogging.plist create mode 100644 Analytics/SQLite/SFObjCType.h create mode 100644 Analytics/SQLite/SFObjCType.m create mode 100644 Analytics/SQLite/SFSQLite.h create mode 100644 Analytics/SQLite/SFSQLite.m create mode 100644 Analytics/SQLite/SFSQLiteStatement.h create mode 100644 Analytics/SQLite/SFSQLiteStatement.m delete mode 100644 Forwarding Headers/SOSCloudCircle.h delete mode 100644 Forwarding Headers/SOSPeerInfo.h create mode 100644 KeychainCircle/PairingChannel.h create mode 100644 KeychainCircle/PairingChannel.m create mode 100644 KeychainCircle/Tests/KCPairingTest-Info.plist create mode 100644 KeychainCircle/Tests/KCPairingTest.m create mode 100644 KeychainCircle/Tests/KCParing.plist create mode 100644 KeychainEntitledTestApp_ios/AppDelegate.h create mode 100644 KeychainEntitledTestApp_ios/AppDelegate.m create mode 100644 KeychainEntitledTestApp_ios/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 KeychainEntitledTestApp_ios/Base.lproj/LaunchScreen.storyboard create mode 100644 KeychainEntitledTestApp_ios/Base.lproj/Main.storyboard create mode 100644 KeychainEntitledTestApp_ios/Info.plist create mode 100644 KeychainEntitledTestApp_ios/ViewController.h create mode 100644 KeychainEntitledTestApp_ios/ViewController.m create mode 100644 KeychainEntitledTestApp_ios/main.m create mode 100644 KeychainEntitledTestApp_mac/AppDelegate.h create mode 100644 KeychainEntitledTestApp_mac/AppDelegate.m create mode 100644 KeychainEntitledTestApp_mac/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 KeychainEntitledTestApp_mac/Base.lproj/Main.storyboard create mode 100644 KeychainEntitledTestApp_mac/Info.plist create mode 100644 KeychainEntitledTestApp_mac/ViewController.h create mode 100644 KeychainEntitledTestApp_mac/ViewController.m create mode 100644 KeychainEntitledTestApp_mac/main.m create mode 100644 KeychainSyncAccountUpdater/Info.plist create mode 100644 KeychainSyncAccountUpdater/KeychainSyncAccountUpdater.h create mode 100644 KeychainSyncAccountUpdater/KeychainSyncAccountUpdater.m create mode 100644 KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy.8 create mode 100644 Modules/KeychainCircle.modulemap create mode 100644 OSX/Keychain Circle Notification/Keychain Circle Notification.8 create mode 100644 OSX/authd/authd-Entitlements.plist delete mode 100644 OSX/authd/debugging.c create mode 100644 OSX/authd/tests/authdtestlist.h create mode 100644 OSX/authd/tests/authdtests.m create mode 100644 OSX/authd/tests/main.m create mode 100644 OSX/authorizationdump/main.m delete mode 120000 OSX/libsecurity_asn1/Security delete mode 100644 OSX/libsecurity_codesigning/lib/SecTask.c delete mode 100644 OSX/libsecurity_keychain/lib/CertificateRequest.cpp delete mode 100644 OSX/libsecurity_keychain/lib/CertificateRequest.h delete mode 100644 OSX/libsecurity_keychain/lib/SecCertificateRequest.cpp create mode 100644 OSX/libsecurity_keychain/libDER/libDER/module.modulemap delete mode 100644 OSX/libsecurity_keychain/plist/iToolsTrustedApps.plist create mode 100644 OSX/libsecurity_transform/regressions/transform-01-sigverify.m create mode 100644 OSX/libsecurity_transform/regressions/transform_regressions.h delete mode 100644 OSX/libsecurity_utilities/lib/bufferfifo.cpp delete mode 100644 OSX/libsecurity_utilities/lib/bufferfifo.h delete mode 100644 OSX/libsecurity_utilities/lib/buffers.cpp delete mode 100644 OSX/libsecurity_utilities/lib/buffers.h delete mode 100644 OSX/libsecurity_utilities/lib/fdmover.cpp delete mode 100644 OSX/libsecurity_utilities/lib/fdmover.h delete mode 100644 OSX/libsecurity_utilities/lib/fdsel.cpp delete mode 100644 OSX/libsecurity_utilities/lib/fdsel.h delete mode 100644 OSX/libsecurity_utilities/lib/headermap.cpp delete mode 100644 OSX/libsecurity_utilities/lib/headermap.h delete mode 100644 OSX/libsecurity_utilities/lib/hosts.cpp delete mode 100644 OSX/libsecurity_utilities/lib/hosts.h delete mode 100644 OSX/libsecurity_utilities/lib/inetreply.cpp delete mode 100644 OSX/libsecurity_utilities/lib/inetreply.h delete mode 100644 OSX/libsecurity_utilities/lib/iodevices.cpp delete mode 100644 OSX/libsecurity_utilities/lib/iodevices.h delete mode 100644 OSX/libsecurity_utilities/lib/ip++.cpp delete mode 100644 OSX/libsecurity_utilities/lib/ip++.h delete mode 100644 OSX/libsecurity_utilities/lib/ktracecodes.h delete mode 100644 OSX/libsecurity_utilities/lib/selector.cpp delete mode 100644 OSX/libsecurity_utilities/lib/selector.h delete mode 100644 OSX/libsecurity_utilities/lib/socks++.cpp delete mode 100644 OSX/libsecurity_utilities/lib/socks++.h delete mode 100644 OSX/libsecurity_utilities/lib/socks++4.cpp delete mode 100644 OSX/libsecurity_utilities/lib/socks++4.h delete mode 100644 OSX/libsecurity_utilities/lib/socks++5.cpp delete mode 100644 OSX/libsecurity_utilities/lib/socks++5.h delete mode 100644 OSX/libsecurity_utilities/lib/typedvalue.h delete mode 100644 OSX/libsecurity_utilities/lib/url.cpp delete mode 100644 OSX/libsecurity_utilities/lib/url.h delete mode 100644 OSX/sec/CloudKeychainProxy/CloudKeychainProxy.1 create mode 100644 OSX/sec/CloudKeychainProxy/CloudKeychainProxy.8 rename OSX/sec/SOSCircle/Regressions/{SOSRegressionUtilities.c => SOSRegressionUtilities.m} (95%) rename OSX/sec/SOSCircle/Regressions/{sc-150-ring.c => sc-150-ring.m} (90%) rename OSX/sec/SOSCircle/Regressions/{sc-20-keynames.c => sc-20-keynames.m} (97%) delete mode 100644 OSX/sec/SOSCircle/SOSPeerInfoDER.c delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountBackup.c => SOSAccountBackup.m} (72%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountCloudParameters.c => SOSAccountCloudParameters.m} (79%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCredentials.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCredentials.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountDer.c => SOSAccountDer.m} (80%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountFullPeerInfo.c => SOSAccountFullPeerInfo.m} (52%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGetSet.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGetSet.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountGhost.c => SOSAccountGhost.m} (80%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountHSAJoin.c delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountHSAJoin.h rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountLog.c => SOSAccountLog.m} (51%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountPeers.c => SOSAccountPeers.m} (76%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountRecovery.c => SOSAccountRecovery.m} (74%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.m delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountSync.c => SOSAccountSync.m} (54%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrust.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrust.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Circle.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Circle.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Expansion.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Expansion.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Identity.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Identity.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Retirement.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Retirement.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustOctagon.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustOctagon.m delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSAccountViewSync.c => SOSAccountViewSync.m} (71%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSBackupInformation.c => SOSBackupInformation.m} (86%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSBackupSliceKeyBag.c => SOSBackupSliceKeyBag.m} (95%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSCloudCircle.c => SOSCloudCircle.m} (89%) rename OSX/{libsecurity_codesigning/lib/SecIntegrity.cpp => sec/SOSCircle/SecureObjectSync/SOSControlHelper.h} (85%) create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSControlHelper.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSFullPeerInfo.c => SOSFullPeerInfo.m} (87%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSInternal.c => SOSInternal.m} (96%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSKVSKeys.c => SOSKVSKeys.m} (83%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSPeer.c => SOSPeer.m} (96%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSPeerCoder.c => SOSPeerCoder.m} (74%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSPeerInfo.c => SOSPeerInfo.m} (95%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSPeerInfoDER.c => SOSPeerInfoDER.m} (100%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSPeerInfoRingState.c => SOSPeerInfoRingState.m} (100%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSPeerInfoSecurityProperties.c => SOSPeerInfoSecurityProperties.m} (82%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSPeerInfoV2.c => SOSPeerInfoV2.m} (98%) create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSPeerOTRTimer.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSPeerOTRTimer.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSPeerRateLimiter.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSPeerRateLimiter.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSPiggyback.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSPiggyback.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSRecoveryKeyBag.c => SOSRecoveryKeyBag.m} (86%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSRingBackup.c => SOSRingBackup.m} (100%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSRingBasic.c => SOSRingBasic.m} (100%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSRingRecovery.c => SOSRingRecovery.m} (99%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSRingTypes.c => SOSRingTypes.m} (62%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSRingV0.c => SOSRingV0.m} (100%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSSysdiagnose.c => SOSSysdiagnose.m} (100%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSTransport.c => SOSTransport.m} (73%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSTransportBackupPeer.c => SOSTransportBackupPeer.m} (88%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.m create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleCK.h create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleCK.m delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.m delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.m delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameterKVS.c delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameterKVS.h delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSTransportMessageIDS.c => SOSTransportMessageIDS.m} (59%) delete mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.c create mode 100644 OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.m rename OSX/sec/SOSCircle/SecureObjectSync/{SOSUserKeygen.c => SOSUserKeygen.m} (99%) rename OSX/sec/SOSCircle/SecureObjectSync/{SOSViews.c => SOSViews.m} (71%) rename OSX/sec/SOSCircle/Tool/{accountCirclesViewsPrint.c => accountCirclesViewsPrint.m} (98%) rename OSX/sec/SOSCircle/Tool/{keychain_log.c => keychain_log.m} (99%) rename OSX/sec/SOSCircle/Tool/{keychain_sync.c => keychain_sync.m} (97%) rename OSX/sec/SOSCircle/Tool/{syncbackup.c => syncbackup.m} (97%) create mode 100644 OSX/sec/Security/AppleiPhoneDeviceCACertificates.h create mode 100644 OSX/sec/Security/Regressions/crypto/padding-00-mmcs.c create mode 100644 OSX/sec/Security/Regressions/secitem/si-18-certificate-parse.m create mode 100644 OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.h create mode 100644 OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.m create mode 100644 OSX/sec/Security/Regressions/secitem/si-61-pkcs12.h create mode 100644 OSX/sec/Security/Regressions/secitem/si-66-smime/smime_attr_emails.h rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist.c => si-67-sectrust-blocklist.c} (87%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/Global Trustee.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/UTN-USERFirst-Hardware.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/addons.mozilla.org.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/login.live.com.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/login.skype.com.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/login.yahoo.com.1.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/login.yahoo.com.2.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/login.yahoo.com.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/mail.google.com.cer.h (100%) rename OSX/sec/Security/Regressions/secitem/{si-67-sectrust-blacklist => si-67-sectrust-blocklist}/www.google.com.cer.h (100%) delete mode 100644 OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.c create mode 100644 OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.m create mode 100644 OSX/sec/Security/SecBackupKeybagEntry.h create mode 100644 OSX/sec/Security/SecBackupKeybagEntry.m create mode 100644 OSX/sec/Security/SecItem.m create mode 100644 OSX/sec/Security/SecTrustStatusCodes.c create mode 100644 OSX/sec/Security/SecTrustStatusCodes.h rename OSX/sec/Security/Tool/{keychain_find.c => keychain_find.m} (94%) create mode 100644 OSX/sec/SecurityTool/sos.m create mode 100644 OSX/sec/ipc/SecdWatchdog.h create mode 100644 OSX/sec/ipc/SecdWatchdog.m create mode 100644 OSX/sec/ipc/client_endpoint.m create mode 100644 OSX/sec/ipc/secd.8 create mode 100644 OSX/sec/ipc/server_endpoint.h create mode 100644 OSX/sec/ipc/server_endpoint.m create mode 100644 OSX/sec/ipc/server_entitlement_helpers.c create mode 100644 OSX/sec/ipc/server_entitlement_helpers.h create mode 100644 OSX/sec/ipc/server_security_helpers.c create mode 100644 OSX/sec/ipc/server_security_helpers.h create mode 100644 OSX/sec/ipc/server_xpc.m create mode 100644 OSX/sec/securityd/AsymKeybagBackup.h create mode 100644 OSX/sec/securityd/AsymKeybagBackup.m create mode 100644 OSX/sec/securityd/Info-macOS.plist delete mode 100644 OSX/sec/securityd/Regressions/SOSTransportTestTransports.c create mode 100644 OSX/sec/securityd/Regressions/SOSTransportTestTransports.m rename OSX/sec/securityd/Regressions/{sd-10-policytree.c => sd-10-policytree.m} (100%) rename OSX/sec/securityd/Regressions/{secd-01-items.c => secd-01-items.m} (100%) rename OSX/sec/securityd/Regressions/{secd-02-upgrade-while-locked.c => secd-02-upgrade-while-locked.m} (100%) rename OSX/sec/securityd/Regressions/{secd-03-corrupted-items.c => secd-03-corrupted-items.m} (100%) rename OSX/sec/securityd/Regressions/{secd-04-corrupted-items.c => secd-04-corrupted-items.m} (100%) rename OSX/sec/securityd/Regressions/{secd-100-initialsync.c => secd-100-initialsync.m} (87%) rename OSX/sec/securityd/Regressions/{secd-130-other-peer-views.c => secd-130-other-peer-views.m} (88%) rename OSX/sec/securityd/Regressions/{secd-154-engine-backoff.c => secd-154-engine-backoff.m} (100%) create mode 100644 OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m create mode 100644 OSX/sec/securityd/Regressions/secd-156-timers.m rename OSX/sec/securityd/Regressions/{secd-200-logstate.c => secd-200-logstate.m} (73%) rename OSX/sec/securityd/Regressions/{secd-201-coders.c => secd-201-coders.m} (64%) rename OSX/sec/{SOSCircle => securityd}/Regressions/secd-210-keyinterest.m (95%) create mode 100644 OSX/sec/securityd/Regressions/secd-230-keybagtable.m rename OSX/sec/securityd/Regressions/{secd-30-keychain-upgrade.c => secd-30-keychain-upgrade.m} (100%) rename OSX/sec/securityd/Regressions/{secd-31-keychain-bad.c => secd-31-keychain-bad.m} (93%) rename OSX/sec/securityd/Regressions/{secd-31-keychain-unreadable.c => secd-31-keychain-unreadable.m} (94%) rename OSX/sec/securityd/Regressions/{secd-32-restore-bad-backup.c => secd-32-restore-bad-backup.m} (100%) rename OSX/sec/securityd/Regressions/{secd-34-backup-der-parse.c => secd-34-backup-der-parse.m} (100%) rename OSX/sec/securityd/Regressions/{secd-35-keychain-migrate-inet.c => secd-35-keychain-migrate-inet.m} (100%) create mode 100644 OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m rename OSX/sec/securityd/Regressions/{secd-40-cc-gestalt.c => secd-40-cc-gestalt.m} (97%) rename OSX/sec/securityd/Regressions/{secd-49-manifests.c => secd-49-manifests.m} (100%) rename OSX/sec/securityd/Regressions/{secd-50-account.c => secd-50-account.m} (66%) rename OSX/sec/securityd/Regressions/{secd-50-message.c => secd-50-message.m} (96%) rename OSX/sec/securityd/Regressions/{secd-51-account-inflate.c => secd-51-account-inflate.m} (97%) rename OSX/sec/securityd/Regressions/{secd-52-account-changed.c => secd-52-account-changed.m} (78%) rename OSX/sec/securityd/Regressions/{secd-52-offering-gencount-reset.c => secd-52-offering-gencount-reset.m} (76%) rename OSX/sec/securityd/Regressions/{secd-55-account-circle.c => secd-55-account-circle.m} (89%) delete mode 100644 OSX/sec/securityd/Regressions/secd-55-account-incompatibility.c create mode 100644 OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m rename OSX/sec/securityd/Regressions/{secd-56-account-apply.c => secd-56-account-apply.m} (92%) rename OSX/sec/securityd/Regressions/{secd-57-1-account-last-standing.c => secd-57-1-account-last-standing.m} (85%) rename OSX/sec/securityd/Regressions/{secd-57-account-leave.c => secd-57-account-leave.m} (90%) rename OSX/sec/securityd/Regressions/{secd-58-password-change.c => secd-58-password-change.m} (93%) rename OSX/sec/securityd/Regressions/{secd-59-account-cleanup.c => secd-59-account-cleanup.m} (75%) rename OSX/sec/securityd/Regressions/{secd-60-account-cloud-identity.c => secd-60-account-cloud-identity.m} (62%) rename OSX/sec/securityd/Regressions/{secd-61-account-leave-not-in-kansas-anymore.c => secd-61-account-leave-not-in-kansas-anymore.m} (84%) rename OSX/sec/securityd/Regressions/{secd-62-account-backup.c => secd-62-account-backup.m} (80%) delete mode 100644 OSX/sec/securityd/Regressions/secd-62-account-hsa-join.c rename OSX/sec/securityd/Regressions/{secd-63-account-resurrection.c => secd-63-account-resurrection.m} (86%) rename OSX/sec/securityd/Regressions/{secd-64-circlereset.c => secd-64-circlereset.m} (79%) rename OSX/sec/securityd/Regressions/{secd-65-account-retirement-reset.c => secd-65-account-retirement-reset.m} (84%) rename OSX/sec/securityd/Regressions/{secd-66-account-recovery.c => secd-66-account-recovery.m} (71%) rename OSX/sec/securityd/Regressions/{secd-668-ghosts.c => secd-668-ghosts.m} (83%) rename OSX/sec/securityd/Regressions/{secd-67-prefixedKeyIDs.c => secd-67-prefixedKeyIDs.m} (98%) rename OSX/sec/securityd/Regressions/{secd-70-engine-corrupt.c => secd-70-engine-corrupt.m} (100%) rename OSX/sec/securityd/Regressions/{secd-70-engine-smash.c => secd-70-engine-smash.m} (100%) rename OSX/sec/securityd/Regressions/{secd-70-engine.c => secd-70-engine.m} (99%) rename OSX/sec/securityd/Regressions/{secd-70-otr-remote.c => secd-70-otr-remote.m} (91%) rename OSX/sec/securityd/Regressions/{secd-71-engine-save.c => secd-71-engine-save.m} (99%) rename OSX/sec/securityd/Regressions/{secd-74-engine-beer-servers.c => secd-74-engine-beer-servers.m} (100%) rename OSX/sec/securityd/Regressions/{secd-75-engine-views.c => secd-75-engine-views.m} (100%) rename OSX/sec/securityd/Regressions/{secd-76-idstransport.c => secd-76-idstransport.m} (66%) rename OSX/sec/securityd/Regressions/{secd-80-views-alwayson.c => secd-80-views-alwayson.m} (85%) rename OSX/sec/securityd/Regressions/{secd-80-views-basic.c => secd-80-views-basic.m} (86%) rename OSX/sec/securityd/Regressions/{secd-81-item-acl-stress.c => secd-81-item-acl-stress.m} (99%) rename OSX/sec/securityd/Regressions/{secd-81-item-acl.c => secd-81-item-acl.m} (99%) rename OSX/sec/securityd/Regressions/{secd-82-persistent-ref.c => secd-82-persistent-ref.m} (71%) rename OSX/sec/securityd/Regressions/{secd-82-secproperties-basic.c => secd-82-secproperties-basic.m} (90%) delete mode 100644 OSX/sec/securityd/Regressions/secd-90-hsa2.c rename OSX/sec/securityd/Regressions/{secd-95-escrow-persistence.c => secd-95-escrow-persistence.m} (87%) rename OSX/sec/securityd/Regressions/{secd60-account-cloud-exposure.c => secd60-account-cloud-exposure.m} (78%) rename OSX/sec/securityd/Regressions/{secd_77_ids_messaging.c => secd_77_ids_messaging.m} (66%) rename OSX/sec/securityd/{SOSCloudCircleServer.c => SOSCloudCircleServer.m} (73%) create mode 100644 OSX/sec/securityd/SecCertificateServer.c create mode 100644 OSX/sec/securityd/SecCertificateServer.h rename OSX/sec/securityd/{SecLogSettingsServer.c => SecLogSettingsServer.m} (88%) rename OSX/sec/securityd/{SecOTRRemote.c => SecOTRRemote.m} (72%) rename OSX/{utilities/src/SecCertificateTrace.h => sec/securityd/SecPinningDb.h} (55%) create mode 100644 OSX/sec/securityd/SecPinningDb.m rename OSX/sec/{SOSCircle/Regressions/sc-140-hsa2.c => securityd/SecRevocationNetworking.h} (81%) create mode 100644 OSX/sec/securityd/SecRevocationNetworking.m create mode 100644 OSX/sec/securityd/SecRevocationServer.c create mode 100644 OSX/sec/securityd/SecRevocationServer.h create mode 100644 OSX/sec/securityd/com.apple.secd.sb create mode 100644 OSX/shared_regressions/si-18-certificate-parse/KeyFailureCerts/parse_fail_spki_unused_bits.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_basic_constraints_too_many_bytes.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_basic_constraints_wrong_true_value.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_1.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_10.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_11.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_12.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_13.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_14.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_15.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_16.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_17.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_18.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_19.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_2.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_20.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_21.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_22.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_23.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_24.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_25.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_26.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_27.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_28.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_29.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_3.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_30.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_31.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_32.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_33.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_34.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_35.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_36.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_37.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_38.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_39.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_4.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_40.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_41.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_42.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_43.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_44.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_45.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_46.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_47.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_48.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_49.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_5.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_50.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_51.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_52.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_53.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_54.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_55.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_56.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_57.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_58.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_59.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_6.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_60.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_61.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_62.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_7.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_8.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_9.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_rsa_encryption_non_null.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_rsa_sig_nonnull.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_spki_negative_rsa.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_1.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_10.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_11.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_12.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_13.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_14.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_15.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_16.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_17.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_18.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_19.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_2.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_20.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_21.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_22.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_23.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_24.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_25.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_26.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_29.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_3.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_30.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_31.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_33.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_34.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_35.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_37.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_38.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_39.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_4.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_5.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_6.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_7.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_8.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_9.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_too_small.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_v4.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_1.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_2.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_3.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_4.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_5.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_6.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_tag_1.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_tag_2.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_tag_3.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_1.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_10.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_2.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_3.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_4.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_5.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_6.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_7.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_8.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_9.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_tag_1.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_tag_2.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_tag_3.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_tag_5.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_basic_constraints_no_pathlen.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_issuerUID.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_keyusage_mask.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_multiple_ekus.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_unknown_apple_extension.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_unknown_extension.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/parse_fail_nonnull_sig_alg_params.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/parse_fail_signature_negative.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/path_fail_mismatch_algorithm.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_length_7.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_length_8.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_tag_4.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/TODODescriptions.txt create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_basic_constraints_notCA_pathlen.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_ec_not_on_curve.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_keyusage_extra_bit.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_length_63.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_tag_27.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_tag_28.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_tag_32.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_tag_36.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_too_big.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/spki_fail_tag_4.cer create mode 100644 OSX/shared_regressions/si-18-certificate-parse/root.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/AppleiPh0neCA.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/AppleiPh0neDeviceCA.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/EntrustCAL1C.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/EntrustRootCA.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/EscrowServiceRootCA0.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/EscrowServiceRootCA100.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/EscrowServiceRootCA101.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/SymantecClass3SSCAG4.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/TestAppleiPh0neDeviceCA.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/VeriSignClass3PublicPrimaryCertificationAuthorityG5.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/apn_legacy.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_049F9D11.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_9B6EEF8D.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_B157A8D4.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/iPh0ne_developer.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/ids_prod.cer rename OSX/shared_regressions/si-20-sectrust-policies-data/{ids.cer => ids_qa.cer} (100%) create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/ids_symantec.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/ppq_signing.cer create mode 100644 OSX/shared_regressions/si-20-sectrust-policies-data/wildcard_icloud.cer create mode 100644 OSX/shared_regressions/si-44-seckey-aks.m create mode 100644 OSX/shared_regressions/si-44-seckey-fv.m delete mode 100644 OSX/trustd/com.apple.trustd.sb create mode 100644 OSX/trustd/iOS/com.apple.trustd.plist create mode 100644 OSX/trustd/iOS/entitlements.plist rename OSX/trustd/{ => macOS}/SecTrustOSXEntryPoints.h (96%) rename OSX/trustd/{ => macOS}/com.apple.trustd.agent.plist (97%) rename OSX/trustd/{ => macOS}/com.apple.trustd.plist (96%) create mode 100644 OSX/trustd/macOS/com.apple.trustd.sb rename OSX/trustd/{ => macOS}/entitlements.plist (58%) create mode 100644 OSX/trustd/macOS/trustd.8 create mode 100644 OSX/trustd/trustd.c delete mode 100644 OSX/utilities/src/SecCertificateTrace.c delete mode 100644 OSX/utilities/src/SecMeta.h create mode 100644 OSX/utilities/src/SecNSAdditions.h create mode 100644 OSX/utilities/src/SecNSAdditions.m create mode 100644 OSX/utilities/src/SecPLWrappers.h create mode 100644 OSX/utilities/src/SecPLWrappers.m create mode 100644 OSX/utilities/src/SecPaddingConfigurations.c create mode 100644 OSX/utilities/src/SecPaddingConfigurationsPriv.h create mode 100644 OSX/utilities/src/sec_action.c create mode 100644 OSX/utilities/src/sec_action.h create mode 100644 RegressionTests/SecAtomicFile/SecAtomicFile.cpp create mode 100644 RegressionTests/manifeststresstest/Config.h create mode 100644 RegressionTests/manifeststresstest/Config.m create mode 100644 RegressionTests/manifeststresstest/Keychain.h create mode 100644 RegressionTests/manifeststresstest/Keychain.m create mode 100644 RegressionTests/manifeststresstest/Monkey.h create mode 100644 RegressionTests/manifeststresstest/Monkey.m create mode 100644 RegressionTests/manifeststresstest/manifeststresstest.entitlements create mode 100644 RegressionTests/manifeststresstest/manifeststresstest.m create mode 100644 RegressionTests/manifeststresstest/mark.h create mode 100644 RegressionTests/manifeststresstest/mark.m create mode 100644 RegressionTests/seckeychainnetworkextensionstest/main.m create mode 100644 RegressionTests/seckeychainnetworkextensionstest/seckeychainnetworkextensionstest.entitlements create mode 100644 RegressionTests/seckeychainnetworkextensionsystemdaemontest/main.m create mode 100644 RegressionTests/seckeychainnetworkextensionsystemdaemontest/seckeychainnetworkextensionsystemdaemontest.entitlements create mode 100644 RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/main.m create mode 100644 RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/seckeychainnetworkextensionunauthorizedaccesstest.entitlements create mode 100644 Security.xcodeproj/xcshareddata/xcschemes/CKKSTests.xcscheme create mode 100644 Security.xcodeproj/xcshareddata/xcschemes/TrustedPeers.xcscheme rename SecurityTool/{identity_find.c => identity_find.m} (76%) rename SecurityTool/{keychain_export.c => keychain_export.m} (90%) create mode 100644 SecurityUnitTests/Info.plist create mode 100644 SecurityUnitTests/SecurityUnitTests.m create mode 120000 header_symlinks/iOS/Security/CSCommon.h create mode 120000 header_symlinks/iOS/Security/CSCommonPriv.h create mode 120000 header_symlinks/iOS/Security/CodeSigning.h create mode 120000 header_symlinks/iOS/Security/SecCode.h create mode 120000 header_symlinks/iOS/Security/SecCodeHost.h create mode 120000 header_symlinks/iOS/Security/SecCodePriv.h create mode 120000 header_symlinks/iOS/Security/SecCodeSigner.h create mode 120000 header_symlinks/iOS/Security/SecRequirement.h create mode 120000 header_symlinks/iOS/Security/SecRequirementPriv.h create mode 120000 header_symlinks/iOS/Security/SecStaticCode.h create mode 120000 header_symlinks/iOS/Security/SecStaticCodePriv.h create mode 120000 header_symlinks/iOS/Security/X509Templates.h create mode 120000 header_symlinks/iOS/Security/keyTemplates.h create mode 120000 header_symlinks/iOS/Security/nameTemplates.h create mode 120000 header_symlinks/iOS/Security/oidsattr.h create mode 120000 header_symlinks/iOS/Security/osxcode.h create mode 120000 header_symlinks/macOS/Security/SecSharedCredential.h rename {OSX/sec/Security => keychain}/SecAccessControl.h (100%) rename {OSX/sec/Security => keychain}/SecSharedCredential.h (100%) create mode 100644 keychain/analytics/CKKSPowerCollection.h create mode 100644 keychain/analytics/CKKSPowerCollection.m create mode 100644 keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.h create mode 100644 keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.m create mode 100644 keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.h create mode 100644 keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.m create mode 100644 keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.h create mode 100644 keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.m create mode 100644 keychain/analytics/awd/AWDKeychainSecDbMarkedCorrupt.h create mode 100644 keychain/analytics/awd/AWDKeychainSecDbMarkedCorrupt.m create mode 100644 keychain/analytics/awd/AWDMetricIds_Keychain.h create mode 100644 keychain/analytics/awd/AwdMetadata-0x60-Keychain.bin create mode 100644 keychain/analytics/awd/awdgen.yaml create mode 100644 keychain/ckks/CKKS.h create mode 100644 keychain/ckks/CKKS.m create mode 100644 keychain/ckks/CKKSAPSReceiver.h create mode 100644 keychain/ckks/CKKSAPSReceiver.m create mode 100644 keychain/ckks/CKKSAnalyticsLogger.h create mode 100644 keychain/ckks/CKKSAnalyticsLogger.m create mode 100644 keychain/ckks/CKKSCKAccountStateTracker.h create mode 100644 keychain/ckks/CKKSCKAccountStateTracker.m create mode 100644 keychain/ckks/CKKSCondition.h create mode 100644 keychain/ckks/CKKSCondition.m create mode 100644 keychain/ckks/CKKSControlProtocol.h create mode 100644 keychain/ckks/CKKSControlProtocol.m create mode 100644 keychain/ckks/CKKSCurrentItemPointer.h create mode 100644 keychain/ckks/CKKSCurrentItemPointer.m create mode 100644 keychain/ckks/CKKSCurrentKeyPointer.h create mode 100644 keychain/ckks/CKKSCurrentKeyPointer.m create mode 100644 keychain/ckks/CKKSDeviceStateEntry.h create mode 100644 keychain/ckks/CKKSDeviceStateEntry.m create mode 100644 keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h create mode 100644 keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m create mode 100644 keychain/ckks/CKKSGroupOperation.h create mode 100644 keychain/ckks/CKKSGroupOperation.m create mode 100644 keychain/ckks/CKKSHealKeyHierarchyOperation.h create mode 100644 keychain/ckks/CKKSHealKeyHierarchyOperation.m create mode 100644 keychain/ckks/CKKSIncomingQueueEntry.h create mode 100644 keychain/ckks/CKKSIncomingQueueEntry.m create mode 100644 keychain/ckks/CKKSIncomingQueueOperation.h create mode 100644 keychain/ckks/CKKSIncomingQueueOperation.m create mode 100644 keychain/ckks/CKKSItem.h create mode 100644 keychain/ckks/CKKSItem.m create mode 100644 keychain/ckks/CKKSItemEncrypter.h create mode 100644 keychain/ckks/CKKSItemEncrypter.m create mode 100644 keychain/ckks/CKKSKey.h create mode 100644 keychain/ckks/CKKSKey.m create mode 100644 keychain/ckks/CKKSKeychainView.h create mode 100644 keychain/ckks/CKKSKeychainView.m create mode 100644 keychain/ckks/CKKSLockStateTracker.h create mode 100644 keychain/ckks/CKKSLockStateTracker.m create mode 100644 keychain/ckks/CKKSLogger.h create mode 100644 keychain/ckks/CKKSLogger.m create mode 100644 keychain/ckks/CKKSLogging.plist create mode 100644 keychain/ckks/CKKSManifest.h create mode 100644 keychain/ckks/CKKSManifest.m create mode 100644 keychain/ckks/CKKSManifestLeafRecord.h create mode 100644 keychain/ckks/CKKSManifestLeafRecord.m create mode 100644 keychain/ckks/CKKSMirrorEntry.h create mode 100644 keychain/ckks/CKKSMirrorEntry.m create mode 100644 keychain/ckks/CKKSNearFutureScheduler.h create mode 100644 keychain/ckks/CKKSNearFutureScheduler.m create mode 100644 keychain/ckks/CKKSNewTLKOperation.h create mode 100644 keychain/ckks/CKKSNewTLKOperation.m create mode 100644 keychain/ckks/CKKSNotifier.h create mode 100644 keychain/ckks/CKKSNotifier.m create mode 100644 keychain/ckks/CKKSOutgoingQueueEntry.h create mode 100644 keychain/ckks/CKKSOutgoingQueueEntry.m rename OSX/libsecurity_codesigning/lib/SecIntegrity.h => keychain/ckks/CKKSOutgoingQueueOperation.h (61%) create mode 100644 keychain/ckks/CKKSOutgoingQueueOperation.m create mode 100644 keychain/ckks/CKKSProcessReceivedKeysOperation.h create mode 100644 keychain/ckks/CKKSProcessReceivedKeysOperation.m create mode 100644 keychain/ckks/CKKSRateLimiter.h create mode 100644 keychain/ckks/CKKSRateLimiter.m create mode 100644 keychain/ckks/CKKSRecordHolder.h create mode 100644 keychain/ckks/CKKSRecordHolder.m create mode 100644 keychain/ckks/CKKSReencryptOutgoingItemsOperation.h create mode 100644 keychain/ckks/CKKSReencryptOutgoingItemsOperation.m create mode 100644 keychain/ckks/CKKSSIV.h create mode 100644 keychain/ckks/CKKSSIV.m create mode 100644 keychain/ckks/CKKSSQLDatabaseObject.h create mode 100644 keychain/ckks/CKKSSQLDatabaseObject.m create mode 100644 keychain/ckks/CKKSScanLocalItemsOperation.h create mode 100644 keychain/ckks/CKKSScanLocalItemsOperation.m create mode 100644 keychain/ckks/CKKSSynchronizeOperation.h create mode 100644 keychain/ckks/CKKSSynchronizeOperation.m create mode 100644 keychain/ckks/CKKSUpdateCurrentItemPointerOperation.h create mode 100644 keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m create mode 100644 keychain/ckks/CKKSUpdateDeviceStateOperation.h create mode 100644 keychain/ckks/CKKSUpdateDeviceStateOperation.m create mode 100644 keychain/ckks/CKKSViewManager.h create mode 100644 keychain/ckks/CKKSViewManager.m create mode 100644 keychain/ckks/CKKSZone.h create mode 100644 keychain/ckks/CKKSZone.m create mode 100644 keychain/ckks/CKKSZoneChangeFetcher.h create mode 100644 keychain/ckks/CKKSZoneChangeFetcher.m create mode 100644 keychain/ckks/CKKSZoneStateEntry.h create mode 100644 keychain/ckks/CKKSZoneStateEntry.m create mode 100644 keychain/ckks/CloudKitCategories.h create mode 100644 keychain/ckks/CloudKitCategories.m create mode 100644 keychain/ckks/CloudKitDependencies.h create mode 100644 keychain/ckks/RateLimiter.h create mode 100644 keychain/ckks/RateLimiter.m create mode 100644 keychain/ckks/tests/CKKSAPSReceiverTests.m create mode 100644 keychain/ckks/tests/CKKSCloudKitTests.m create mode 100644 keychain/ckks/tests/CKKSCloudKitTestsInfo.plist create mode 100644 keychain/ckks/tests/CKKSConditionTests.m create mode 100644 keychain/ckks/tests/CKKSDispatchTests.m create mode 100644 keychain/ckks/tests/CKKSEncryptionTests.m create mode 100644 keychain/ckks/tests/CKKSLoggerTests.m create mode 100644 keychain/ckks/tests/CKKSManifestTests.m create mode 100644 keychain/ckks/tests/CKKSNearFutureSchedulerTests.m create mode 100644 keychain/ckks/tests/CKKSOperationTests.m create mode 100644 keychain/ckks/tests/CKKSRateLimiterTests.m create mode 100644 keychain/ckks/tests/CKKSSOSTests.m create mode 100644 keychain/ckks/tests/CKKSSQLTests.m create mode 100644 keychain/ckks/tests/CKKSTests+API.h create mode 100644 keychain/ckks/tests/CKKSTests+API.m create mode 100644 keychain/ckks/tests/CKKSTests+Coalesce.m create mode 100644 keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m create mode 100644 keychain/ckks/tests/CKKSTests.h create mode 100644 keychain/ckks/tests/CKKSTests.m create mode 100644 keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h create mode 100644 keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m create mode 100644 keychain/ckks/tests/CloudKitMockXCTest.h create mode 100644 keychain/ckks/tests/CloudKitMockXCTest.m create mode 100644 keychain/ckks/tests/Info.plist create mode 100644 keychain/ckks/tests/MockCloudKit.h create mode 100644 keychain/ckks/tests/MockCloudKit.m create mode 100644 keychain/ckks/tests/RateLimiterTests.m create mode 100644 keychain/ckks/tests/testrunner/KeychainCKKS.plist create mode 100644 keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist create mode 100644 keychain/ckks/tests/testrunner/KeychainEntitledTestRunner.m create mode 100644 keychain/ckksctl/ckksctl-Entitlements.plist create mode 100644 keychain/ckksctl/ckksctl.h create mode 100644 keychain/ckksctl/ckksctl.m create mode 100644 keychain/trust/.open_source_exclude create mode 100644 keychain/trust/TrustedPeers/Info.plist create mode 100644 keychain/trust/TrustedPeers/TPCategoryRule.h create mode 100644 keychain/trust/TrustedPeers/TPCategoryRule.m create mode 100644 keychain/trust/TrustedPeers/TPCircle.h create mode 100644 keychain/trust/TrustedPeers/TPCircle.m create mode 100644 keychain/trust/TrustedPeers/TPDecrypter.h create mode 100644 keychain/trust/TrustedPeers/TPEncrypter.h create mode 100644 keychain/trust/TrustedPeers/TPHash.h create mode 100644 keychain/trust/TrustedPeers/TPHash.m create mode 100644 keychain/trust/TrustedPeers/TPModel.h create mode 100644 keychain/trust/TrustedPeers/TPModel.m create mode 100644 keychain/trust/TrustedPeers/TPPeer.h create mode 100644 keychain/trust/TrustedPeers/TPPeer.m create mode 100644 keychain/trust/TrustedPeers/TPPeerDynamicInfo.h create mode 100644 keychain/trust/TrustedPeers/TPPeerDynamicInfo.m create mode 100644 keychain/trust/TrustedPeers/TPPeerPermanentInfo.h create mode 100644 keychain/trust/TrustedPeers/TPPeerPermanentInfo.m create mode 100644 keychain/trust/TrustedPeers/TPPeerStableInfo.h create mode 100644 keychain/trust/TrustedPeers/TPPeerStableInfo.m create mode 100644 keychain/trust/TrustedPeers/TPPolicy.h create mode 100644 keychain/trust/TrustedPeers/TPPolicy.m create mode 100644 keychain/trust/TrustedPeers/TPPolicyDocument.h create mode 100644 keychain/trust/TrustedPeers/TPPolicyDocument.m create mode 100644 keychain/trust/TrustedPeers/TPSigningKey.h rename OSX/libsecurity_codesigning/lib/SecIntegrityLib.c => keychain/trust/TrustedPeers/TPTypes.h (80%) create mode 100644 keychain/trust/TrustedPeers/TPUtils.h create mode 100644 keychain/trust/TrustedPeers/TPUtils.m create mode 100644 keychain/trust/TrustedPeers/TPVoucher.h create mode 100644 keychain/trust/TrustedPeers/TPVoucher.m rename OSX/libsecurity_codesigning/lib/SecIntegrityLib.h => keychain/trust/TrustedPeers/TrustedPeers.h (52%) create mode 100644 keychain/trust/TrustedPeersTests/Info.plist create mode 100644 keychain/trust/TrustedPeersTests/TPCircleTests.m rename OSX/libsecurity_utilities/lib/typedvalue.cpp => keychain/trust/TrustedPeersTests/TPDummyDecrypter.h (76%) create mode 100644 keychain/trust/TrustedPeersTests/TPDummyDecrypter.m create mode 100644 keychain/trust/TrustedPeersTests/TPDummyEncrypter.h create mode 100644 keychain/trust/TrustedPeersTests/TPDummyEncrypter.m create mode 100644 keychain/trust/TrustedPeersTests/TPDummySigningKey.h create mode 100644 keychain/trust/TrustedPeersTests/TPDummySigningKey.m create mode 100644 keychain/trust/TrustedPeersTests/TPDummySigningKeyTests.m create mode 100644 keychain/trust/TrustedPeersTests/TPHashTests.m create mode 100644 keychain/trust/TrustedPeersTests/TPModelTests.m create mode 100644 keychain/trust/TrustedPeersTests/TPPeerPermanentInfoTests.m create mode 100644 keychain/trust/TrustedPeersTests/TPPeerStableInfoTests.m create mode 100644 keychain/trust/TrustedPeersTests/TPPeerTests.m create mode 100644 keychain/trust/TrustedPeersTests/TPPolicyDocumentTests.m create mode 100644 keychain/trust/TrustedPeersTests/TPUtilsTests.m create mode 100644 keychain/trust/TrustedPeersTests/TPVoucherTests.m create mode 100644 lib/SecArgParse.c create mode 100644 lib/SecArgParse.h create mode 100644 libsecurity_smime/lib/CMSDecoder.c create mode 100644 libsecurity_smime/lib/CMSDecoder.h create mode 100644 libsecurity_smime/lib/CMSEncoder.c create mode 100644 libsecurity_smime/lib/CMSEncoder.h create mode 100644 libsecurity_smime/lib/CMSUtils.c create mode 100644 libsecurity_smime/lib/CMSUtils.h rename {OSX/libsecurity_codesigning/lib => sectask}/SecTaskPriv.h (84%) create mode 100644 securityd/securityd_service/securityd_service/securityd_service.8 create mode 100644 tests/secfuzzer/SecCertificateFuzzer.c create mode 100644 tests/secfuzzer/secfuzzer.m create mode 100644 xcconfig/PlatformFeatures.xcconfig create mode 100644 xcconfig/PlatformLibraries.xcconfig create mode 100644 xcconfig/framework_requiring_modern_objc_runtime.xcconfig delete mode 100644 xcconfig/lib_ios_debug.xcconfig delete mode 100644 xcconfig/lib_ios_debug_all_archs.xcconfig delete mode 100644 xcconfig/lib_ios_release.xcconfig rename xcconfig/{lib_ios_debug_shim.xcconfig => lib_ios_shim.xcconfig} (68%) delete mode 100644 xcconfig/lib_ios_x64_debug.xcconfig delete mode 100644 xcconfig/lib_ios_x64_debug_shim.xcconfig delete mode 100644 xcconfig/lib_ios_x64_release.xcconfig delete mode 100644 xcconfig/lib_ios_x64_release_shim.xcconfig rename xcconfig/{lib_ios_release_shim.xcconfig => lib_ios_x64_shim.xcconfig} (67%) diff --git a/Analytics/SFAnalyticsLogger.h b/Analytics/SFAnalyticsLogger.h new file mode 100644 index 00000000..ebdba8b7 --- /dev/null +++ b/Analytics/SFAnalyticsLogger.h @@ -0,0 +1,72 @@ +/* + * 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 + +#if __OBJC2__ + +@interface SFAnalyticsLogger : NSObject + ++ (instancetype)logger; + ++ (NSInteger)fuzzyDaysSinceDate:(NSDate*)date; + +- (void)logSuccessForEventNamed:(NSString*)eventName; +- (void)logHardFailureForEventNamed:(NSString*)eventName withAttributes:(NSDictionary*)attributes; +- (void)logSoftFailureForEventNamed:(NSString*)eventName withAttributes:(NSDictionary*)attributes; + +- (void)noteEventNamed:(NSString*)eventName; + +// -------------------------------- +// Things below are for subclasses + +// Override to create a concrete logger instance +@property (readonly, class) NSString* databasePath; + +// Storing dates +- (void)setDateProperty:(NSDate*)date forKey:(NSString*)key; +- (NSDate*)datePropertyForKey:(NSString*)key; + +- (NSDictionary*)extraValuesToUploadToServer; +- (NSString*)sysdiagnoseStringForEventRecord:(NSDictionary*)eventRecord; + +// -------------------------------- +// Things below are for utilities to drive and/or test the system + +- (NSString*)getSysdiagnoseDumpWithError:(NSError**)error; +- (NSData*)getLoggingJSONWithError:(NSError**)error; +- (BOOL)forceUploadWithError:(NSError**)error; + +// -------------------------------- +// Things below are for unit testing + +@property (readonly) dispatch_queue_t splunkLoggingQueue; +@property (readonly) NSURL* splunkUploadURL; +@property (readonly) NSString* splunkTopicName; +@property (readonly) NSURL* splunkBagURL; +@property (readonly) BOOL allowsInsecureSplunkCert; +@property BOOL ignoreServerDisablingMessages; + +@end + +#endif diff --git a/Analytics/SFAnalyticsLogger.m b/Analytics/SFAnalyticsLogger.m new file mode 100644 index 00000000..2a750ca5 --- /dev/null +++ b/Analytics/SFAnalyticsLogger.m @@ -0,0 +1,878 @@ +/* + * 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 "SFAnalyticsLogger.h" +#import "SFSQLite.h" +#import "CKKSViewManager.h" +#import "debugging.h" +#import + +NSString* const SFAnalyticsLoggerTableSuccessCount = @"success_count"; +NSString* const SFAnalyticsLoggerColumnEventType = @"event_type"; +NSString* const SFAnalyticsLoggerColumnSuccessCount = @"success_count"; +NSString* const SFAnalyticsLoggerColumnHardFailureCount = @"hard_failure_count"; +NSString* const SFAnalyticsLoggerColumnSoftFailureCount = @"soft_failure_count"; + +NSString* const SFAnalyticsLoggerTableHardFailures = @"hard_failures"; +NSString* const SFAnalyticsLoggerTableSoftFailures = @"soft_failures"; +NSString* const SFAnalyticsLoggerTableAllEvents = @"all_events"; +NSString* const SFAnalyticsLoggerColumnDate = @"timestamp"; +NSString* const SFAnalyticsLoggerColumnData = @"data"; + +NSString* const SFAnalyticsLoggerUploadDate = @"upload_date"; + +NSString* const SFAnalyticsLoggerSplunkTopic = @"topic"; +NSString* const SFAnalyticsLoggerSplunkEventTime = @"eventTime"; +NSString* const SFAnalyticsLoggerSplunkPostTime = @"postTime"; +NSString* const SFAnalyticsLoggerSplunkEventType = @"eventType"; +NSString* const SFAnalyticsLoggerMetricsBase = @"metricsBase"; +NSString* const SFAnalyticsLoggerEventClassKey = @"eventClass"; + +NSString* const SFAnalyticsUserDefaultsSuite = @"com.apple.security.analytics"; + +static NSString* const SFAnalyticsLoggerTableSchema = @"CREATE TABLE IF NOT EXISTS hard_failures (\n" + @"id INTEGER PRIMARY KEY AUTOINCREMENT,\n" + @"timestamp REAL," + @"data BLOB\n" + @");\n" + @"CREATE TRIGGER IF NOT EXISTS maintain_ring_buffer_hard_failures AFTER INSERT ON hard_failures\n" + @"BEGIN\n" + @"DELETE FROM hard_failures WHERE id != NEW.id AND id % 999 = NEW.id % 999;\n" + @"END;\n" + @"CREATE TABLE IF NOT EXISTS soft_failures (\n" + @"id INTEGER PRIMARY KEY AUTOINCREMENT,\n" + @"timestamp REAL," + @"data BLOB\n" + @");\n" + @"CREATE TRIGGER IF NOT EXISTS maintain_ring_buffer_soft_failures AFTER INSERT ON soft_failures\n" + @"BEGIN\n" + @"DELETE FROM soft_failures WHERE id != NEW.id AND id % 999 = NEW.id % 999;\n" + @"END;\n" + @"CREATE TABLE IF NOT EXISTS all_events (\n" + @"id INTEGER PRIMARY KEY AUTOINCREMENT,\n" + @"timestamp REAL," + @"data BLOB\n" + @");\n" + @"CREATE TRIGGER IF NOT EXISTS maintain_ring_buffer_all_events AFTER INSERT ON all_events\n" + @"BEGIN\n" + @"DELETE FROM all_events WHERE id != NEW.id AND id % 10000 = NEW.id % 10000;\n" + @"END;\n" + @"CREATE TABLE IF NOT EXISTS success_count (\n" + @"event_type STRING PRIMARY KEY,\n" + @"success_count INTEGER,\n" + @"hard_failure_count INTEGER,\n" + @"soft_failure_count INTEGER\n" + @");\n"; + +#define SFANALYTICS_SPLUNK_DEV 0 +#define SFANALYTICS_MAX_EVENTS_TO_REPORT 999 + +#if SFANALYTICS_SPLUNK_DEV +#define SECONDS_BETWEEN_UPLOADS 10 +#else +// three days = 60 seconds times 60 minutes * 72 hours +#define SECONDS_BETWEEN_UPLOADS (60 * 60 * 72) +#endif + +#define SECONDS_PER_DAY (60 * 60 * 24) + +typedef NS_ENUM(NSInteger, SFAnalyticsEventClass) { + SFAnalyticsEventClassSuccess, + SFAnalyticsEventClassHardFailure, + SFAnalyticsEventClassSoftFailure, + SFAnalyticsEventClassNote +}; + +@interface SFAnalyticsLoggerSQLiteStore : SFSQLite + +@property (readonly, strong) NSArray* failureRecords; +@property (readonly, strong) NSArray* allEvents; +@property (readwrite, strong) NSDate* uploadDate; + ++ (instancetype)storeWithPath:(NSString*)path schema:(NSString*)schema; + +- (void)incrementSuccessCountForEventType:(NSString*)eventType; +- (void)incrementHardFailureCountForEventType:(NSString*)eventType; +- (void)incrementSoftFailureCountForEventType:(NSString*)eventType; +- (NSInteger)successCountForEventType:(NSString*)eventType; +- (NSInteger)hardFailureCountForEventType:(NSString*)eventType; +- (NSInteger)softFailureCountForEventType:(NSString*)eventType; +- (void)addEventDict:(NSDictionary*)eventDict toTable:(NSString*)table; +- (void)clearAllData; + +- (NSDictionary*)summaryCounts; + +@end + +@implementation SFAnalyticsLogger { + SFAnalyticsLoggerSQLiteStore* _database; + NSURL* _splunkUploadURL; + NSString* _splunkTopicName; + NSURL* _splunkBagURL; + dispatch_queue_t _queue; + NSInteger _secondsBetweenUploads; + NSDictionary* _metricsBase; // data the server provides and wants us to send back + NSArray* _blacklistedFields; + NSArray* _blacklistedEvents; + + unsigned int _allowInsecureSplunkCert:1; + unsigned int _disableLogging:1; + unsigned int _disableUploads:1; + unsigned int _ignoreServersMessagesTellingUsToGoAway:1; +} + +@synthesize splunkUploadURL = _splunkUploadURL; +@synthesize splunkBagURL = _splunkBagURL; +@synthesize splunkTopicName = _splunkTopicName; +@synthesize splunkLoggingQueue = _queue; + ++ (instancetype)logger +{ +#if TARGET_OS_SIMULATOR + return nil; +#else + + if (self == [SFAnalyticsLogger class]) { + secerror("attempt to instatiate abstract class SFAnalyticsLogger"); + return nil; + } + + SFAnalyticsLogger* logger = nil; + @synchronized(self) { + logger = objc_getAssociatedObject(self, "SFAnalyticsLoggerInstance"); + if (!logger) { + logger = [[self alloc] init]; + objc_setAssociatedObject(self, "SFAnalyticsLoggerInstance", logger, OBJC_ASSOCIATION_RETAIN); + } + } + return logger; +#endif +} + ++ (NSString*)databasePath +{ + return nil; +} + ++ (NSInteger)fuzzyDaysSinceDate:(NSDate*)date +{ + NSTimeInterval timeIntervalSinceDate = [[NSDate date] timeIntervalSinceDate:date]; + if (timeIntervalSinceDate < SECONDS_PER_DAY) { + return 0; + } + else if (timeIntervalSinceDate < (SECONDS_PER_DAY * 7)) { + return 1; + } + else if (timeIntervalSinceDate < (SECONDS_PER_DAY * 30)) { + return 7; + } + else if (timeIntervalSinceDate < (SECONDS_PER_DAY * 365)) { + return 30; + } + else { + return 365; + } +} + +- (instancetype)init +{ + if (self = [super init]) { + _database = [SFAnalyticsLoggerSQLiteStore storeWithPath:self.class.databasePath schema:SFAnalyticsLoggerTableSchema]; + _queue = dispatch_queue_create("com.apple.security.analytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + _secondsBetweenUploads = SECONDS_BETWEEN_UPLOADS; + + NSDictionary* systemDefaultValues = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle bundleWithPath:@"/System/Library/Frameworks/Security.framework"] pathForResource:@"SFAnalyticsLogging" ofType:@"plist"]]; + _splunkTopicName = systemDefaultValues[@"splunk_topic"]; + _splunkUploadURL = [NSURL URLWithString:systemDefaultValues[@"splunk_uploadURL"]]; + _splunkBagURL = [NSURL URLWithString:systemDefaultValues[@"splunk_bagURL"]]; + _allowInsecureSplunkCert = [[systemDefaultValues valueForKey:@"splunk_allowInsecureCertificate"] boolValue]; + NSString* splunkEndpoint = systemDefaultValues[@"splunk_endpointDomain"]; + + NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:SFAnalyticsUserDefaultsSuite]; + NSString* userDefaultsSplunkTopic = [defaults stringForKey:@"splunk_topic"]; + if (userDefaultsSplunkTopic) { + _splunkTopicName = userDefaultsSplunkTopic; + } + + NSURL* userDefaultsSplunkUploadURL = [NSURL URLWithString:[defaults stringForKey:@"splunk_uploadURL"]]; + if (userDefaultsSplunkUploadURL) { + _splunkUploadURL = userDefaultsSplunkUploadURL; + } + + NSURL* userDefaultsSplunkBagURL = [NSURL URLWithString:[defaults stringForKey:@"splunk_bagURL"]]; + if (userDefaultsSplunkUploadURL) { + _splunkBagURL = userDefaultsSplunkBagURL; + } + + BOOL userDefaultsAllowInsecureSplunkCert = [defaults boolForKey:@"splunk_allowInsecureCertificate"]; + _allowInsecureSplunkCert |= userDefaultsAllowInsecureSplunkCert; + + NSString* userDefaultsSplunkEndpoint = [defaults stringForKey:@"splunk_endpointDomain"]; + if (userDefaultsSplunkEndpoint) { + splunkEndpoint = userDefaultsSplunkEndpoint; + } + +#if SFANALYTICS_SPLUNK_DEV + _ignoreServersMessagesTellingUsToGoAway = YES; + + if (!_splunkUploadURL && splunkEndpoint) { + NSString* urlString = [NSString stringWithFormat:@"https://%@/report/2/%@", splunkEndpoint, _splunkTopicName]; + _splunkUploadURL = [NSURL URLWithString:urlString]; + } +#else + (void)splunkEndpoint; +#endif + } + + return self; +} + +- (void)logSuccessForEventNamed:(NSString*)eventName +{ + [self logEventNamed:eventName class:SFAnalyticsEventClassSuccess attributes:nil]; +} + +- (void)logHardFailureForEventNamed:(NSString*)eventName withAttributes:(NSDictionary*)attributes +{ + [self logEventNamed:eventName class:SFAnalyticsEventClassSoftFailure attributes:attributes]; +} + +- (void)logSoftFailureForEventNamed:(NSString*)eventName withAttributes:(NSDictionary*)attributes +{ + [self logEventNamed:eventName class:SFAnalyticsEventClassHardFailure attributes:attributes]; +} + +- (void)noteEventNamed:(NSString*)eventName +{ + [self logEventNamed:eventName class:SFAnalyticsEventClassNote attributes:nil]; +} + +- (void)logEventNamed:(NSString*)eventName class:(SFAnalyticsEventClass)class attributes:(NSDictionary*)attributes +{ + if (!eventName) { + secinfo("SFAnalytics", "attempt to log an event with no name"); + return; + } + + __block NSDate* uploadDate = nil; + __weak __typeof(self) weakSelf = self; + dispatch_sync(_queue, ^{ + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf || strongSelf->_disableLogging || [strongSelf->_blacklistedEvents containsObject:eventName]) { + return; + } + + NSDictionary* eventDict = [self eventDictForEventName:eventName withAttributes:attributes eventClass:class]; + [strongSelf->_database addEventDict:eventDict toTable:SFAnalyticsLoggerTableAllEvents]; + + if (class == SFAnalyticsEventClassHardFailure) { + NSDictionary* strippedDict = [self eventDictWithBlacklistedFieldsStrippedFrom:eventDict]; + [strongSelf->_database addEventDict:strippedDict toTable:SFAnalyticsLoggerTableHardFailures]; + [strongSelf->_database incrementHardFailureCountForEventType:eventName]; + } + else if (class == SFAnalyticsEventClassSoftFailure) { + NSDictionary* strippedDict = [self eventDictWithBlacklistedFieldsStrippedFrom:eventDict]; + [strongSelf->_database addEventDict:strippedDict toTable:SFAnalyticsLoggerTableSoftFailures]; + [strongSelf->_database incrementSoftFailureCountForEventType:eventName]; + } + else if (class == SFAnalyticsEventClassSuccess || class == SFAnalyticsEventClassNote) { + [strongSelf->_database incrementSuccessCountForEventType:eventName]; + } + + uploadDate = strongSelf->_database.uploadDate; + }); + + NSDate* nowDate = [NSDate date]; + if (uploadDate) { + if ([nowDate compare:uploadDate] == NSOrderedDescending) { + NSError* error = nil; + BOOL uploadSuccess = [self forceUploadWithError:&error]; + if (uploadSuccess) { + secinfo("SFAnalytics", "uploaded sync health data"); + [self resetUploadDate:YES]; + } + + if (error) { + secerror("SFAnalytics: failed to upload json to analytics server with error: %@", error); + } + } + } + else { + [self resetUploadDate:NO]; + } +} + +- (void)resetUploadDate:(BOOL)clearData +{ + __weak __typeof(self) weakSelf = self; + dispatch_sync(_queue, ^{ + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + if (clearData) { + [strongSelf->_database clearAllData]; + } + strongSelf->_database.uploadDate = [NSDate dateWithTimeIntervalSinceNow:strongSelf->_secondsBetweenUploads]; + }); +} + +- (NSDictionary*)eventDictForEventName:(NSString*)eventName withAttributes:(NSDictionary*)attributes eventClass:(SFAnalyticsEventClass)eventClass +{ + NSMutableDictionary* eventDict = attributes ? attributes.mutableCopy : [NSMutableDictionary dictionary]; + eventDict[SFAnalyticsLoggerSplunkTopic] = _splunkTopicName; + eventDict[SFAnalyticsLoggerSplunkEventType] = eventName; + eventDict[SFAnalyticsLoggerSplunkEventTime] = @([[NSDate date] timeIntervalSince1970] * 1000); + eventDict[SFAnalyticsLoggerEventClassKey] = @(eventClass); + + [_metricsBase enumerateKeysAndObjectsUsingBlock:^(NSString* key, id object, BOOL* stop) { + if (!eventDict[key]) { + eventDict[key] = object; + } + }]; + + return eventDict; +} + +- (NSDictionary*)eventDictWithBlacklistedFieldsStrippedFrom:(NSDictionary*)eventDict +{ + NSMutableDictionary* strippedDict = eventDict.mutableCopy; + for (NSString* blacklistedField in _blacklistedFields) { + [strippedDict removeObjectForKey:blacklistedField]; + } + return strippedDict; +} + +- (void)setDateProperty:(NSDate*)date forKey:(NSString*)key +{ + dispatch_sync(_queue, ^{ + [self->_database setDateProperty:date forKey:key]; + }); +} + +- (NSDate*)datePropertyForKey:(NSString*)key +{ + __block NSDate* result = nil; + dispatch_sync(_queue, ^{ + result = [self->_database datePropertyForKey:key]; + }); + return result; +} + +- (NSDictionary*)extraValuesToUploadToServer +{ + return [NSDictionary dictionary]; +} + +// this method is kind of evil for the fact that it has side-effects in pulling other things besides the metricsURL from the server, and as such should NOT be memoized. +// TODO redo this, probably to return a dictionary. +- (NSURL*)splunkUploadURL +{ + dispatch_assert_queue(_queue); + + if (_splunkUploadURL) { + return _splunkUploadURL; + } + + __weak __typeof(self) weakSelf = self; + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + + __block NSError* error = nil; + NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + NSURLSession* storeBagSession = [NSURLSession sessionWithConfiguration:defaultConfiguration + delegate:self + delegateQueue:nil]; + + NSURL* requestEndpoint = _splunkBagURL; + __block NSURL* result = nil; + NSURLSessionDataTask* storeBagTask = [storeBagSession dataTaskWithURL:requestEndpoint completionHandler:^(NSData * _Nullable data, + NSURLResponse * _Nullable __unused response, + NSError * _Nullable responseError) { + + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + if (data && !responseError) { + NSData *responseData = data; // shut up compiler + NSDictionary* responseDict = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error]; + if([responseDict isKindOfClass:NSDictionary.class] && !error) { + if (!self->_ignoreServersMessagesTellingUsToGoAway) { + strongSelf->_disableLogging = [[responseDict valueForKey:@"disabled"] boolValue]; + if (strongSelf->_disableLogging || [[responseDict valueForKey:@"sendDisabled"] boolValue]) { + // then don't upload anything right now + secerror("not returning a splunk URL because uploads are disabled"); + dispatch_semaphore_signal(sem); + return; + } + + NSUInteger millisecondsBetweenUploads = [[responseDict valueForKey:@"postFrequency"] unsignedIntegerValue] / 1000; + if (millisecondsBetweenUploads > 0) { + strongSelf->_secondsBetweenUploads = millisecondsBetweenUploads; + } + + strongSelf->_blacklistedEvents = responseDict[@"blacklistedEvents"]; + strongSelf->_blacklistedFields = responseDict[@"blacklistedFields"]; + } + + strongSelf->_metricsBase = responseDict[@"metricsBase"]; + + NSString* metricsEndpoint = responseDict[@"metricsUrl"]; + if([metricsEndpoint isKindOfClass:NSString.class]) { + /* Lives our URL */ + NSString* endpoint = [metricsEndpoint stringByAppendingFormat:@"/2/%@", strongSelf->_splunkTopicName]; + secnotice("ckks", "got metrics endpoint: %@", endpoint); + NSURL* endpointURL = [NSURL URLWithString:endpoint]; + if([endpointURL.scheme isEqualToString:@"https"]) { + result = endpointURL; + } + } + } + } + else { + error = responseError; + } + if(error) { + secnotice("ckks", "Unable to fetch splunk endpoint at URL: %@ -- error: %@", requestEndpoint, error.description); + } + else if(!result) { + secnotice("ckks", "Malformed iTunes config payload!"); + } + + dispatch_semaphore_signal(sem); + }]; + + [storeBagTask resume]; + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + + return result; +} + +- (BOOL)forceUploadWithError:(NSError**)error +{ + __block BOOL result = NO; + NSData* json = [self getLoggingJSONWithError:error]; + dispatch_sync(_queue, ^{ + if (json && [self _onQueuePostJSON:json error:error]) { + secinfo("ckks", "uploading sync health data: %@", json); + + [self->_database clearAllData]; + self->_database.uploadDate = [NSDate dateWithTimeIntervalSinceNow:self->_secondsBetweenUploads]; + result = YES; + } + else { + result = NO; + } + }); + + return result; +} + +- (BOOL)_onQueuePostJSON:(NSData*)json error:(NSError**)error +{ + dispatch_assert_queue(_queue); + + /* + * Create the NSURLSession + * We use the ephemeral session config because we don't need cookies or cache + */ + NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + NSURLSession* postSession = [NSURLSession sessionWithConfiguration:defaultConfiguration + delegate:self + delegateQueue:nil]; + + /* + * Create the request + */ + NSURL* postEndpoint = self.splunkUploadURL; + if (!postEndpoint) { + secerror("failed to get a splunk upload endpoint - not uploading"); + return NO; + } + + NSMutableURLRequest* postRequest = [[NSMutableURLRequest alloc] init]; + postRequest.URL = postEndpoint; + postRequest.HTTPMethod = @"POST"; + postRequest.HTTPBody = json; + + /* + * Create the upload task. + */ + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + __block BOOL uploadSuccess = NO; + NSURLSessionDataTask* uploadTask = [postSession dataTaskWithRequest:postRequest + completionHandler:^(NSData * _Nullable __unused data, NSURLResponse * _Nullable response, NSError * _Nullable requestError) { + if(requestError) { + secerror("Error in uploading the events to splunk: %@", requestError); + } + else if (![response isKindOfClass:NSHTTPURLResponse.class]){ + Class class = response.class; + secerror("Received the wrong kind of response: %@", NSStringFromClass(class)); + } + else { + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; + if(httpResponse.statusCode >= 200 && httpResponse.statusCode < 300) { + /* Success */ + uploadSuccess = YES; + secnotice("ckks", "Splunk upload success"); + } + else { + secnotice("ckks", "Splunk upload unexpected status to URL: %@ -- status: %d", postEndpoint, (int)(httpResponse.statusCode)); + } + } + dispatch_semaphore_signal(sem); + }]; + + secnotice("ckks", "Splunk upload start"); + [uploadTask resume]; + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + return uploadSuccess; +} + +- (NSString*)stringForEventClass:(SFAnalyticsEventClass)eventClass +{ + if (eventClass == SFAnalyticsEventClassNote) { + return @"EventNote"; + } + else if (eventClass == SFAnalyticsEventClassSuccess) { + return @"EventSuccess"; + } + else if (eventClass == SFAnalyticsEventClassHardFailure) { + return @"EventHardFailure"; + } + else if (eventClass == SFAnalyticsEventClassSoftFailure) { + return @"EventSoftFailure"; + } + else { + return @"EventUnknown"; + } +} + +- (NSString*)sysdiagnoseStringForEventRecord:(NSDictionary*)eventRecord +{ + NSMutableDictionary* mutableEventRecord = eventRecord.mutableCopy; + [mutableEventRecord removeObjectForKey:SFAnalyticsLoggerSplunkTopic]; + + NSDate* eventDate = [NSDate dateWithTimeIntervalSince1970:[[eventRecord valueForKey:SFAnalyticsLoggerSplunkEventTime] doubleValue] / 1000]; + [mutableEventRecord removeObjectForKey:SFAnalyticsLoggerSplunkEventTime]; + + NSString* eventName = eventRecord[SFAnalyticsLoggerSplunkEventType]; + [mutableEventRecord removeObjectForKey:SFAnalyticsLoggerSplunkEventType]; + + SFAnalyticsEventClass eventClass = [[eventRecord valueForKey:SFAnalyticsLoggerEventClassKey] integerValue]; + NSString* eventClassString = [self stringForEventClass:eventClass]; + [mutableEventRecord removeObjectForKey:SFAnalyticsLoggerEventClassKey]; + + NSMutableString* additionalAttributesString = [NSMutableString string]; + if (mutableEventRecord.count > 0) { + [additionalAttributesString appendString:@" - Attributes: {" ]; + __block BOOL firstAttribute = YES; + [mutableEventRecord enumerateKeysAndObjectsUsingBlock:^(NSString* key, id object, BOOL* stop) { + NSString* openingString = firstAttribute ? @"" : @", "; + [additionalAttributesString appendString:[NSString stringWithFormat:@"%@%@ : %@", openingString, key, object]]; + firstAttribute = NO; + }]; + [additionalAttributesString appendString:@" }"]; + } + + return [NSString stringWithFormat:@"%@ %@: %@%@", eventDate, eventClassString, eventName, additionalAttributesString]; +} + +- (NSString*)getSysdiagnoseDumpWithError:(NSError**)error +{ + NSMutableString* sysdiagnose = [[NSMutableString alloc] init]; + + NSDictionary* extraValues = self.extraValuesToUploadToServer; + [extraValues enumerateKeysAndObjectsUsingBlock:^(NSString* key, id object, BOOL* stop) { + [sysdiagnose appendFormat:@"Key: %@, Value: %@\n", key, object]; + }]; + + [sysdiagnose appendString:@"\n"]; + + dispatch_sync(_queue, ^{ + NSArray* allEvents = self->_database.allEvents; + for (NSDictionary* eventRecord in allEvents) { + [sysdiagnose appendFormat:@"%@\n", [self sysdiagnoseStringForEventRecord:eventRecord]]; + } + }); + + return sysdiagnose; +} + +- (NSData*)getLoggingJSONWithError:(NSError**)error +{ + __block NSData* json = nil; + NSDictionary* extraValues = self.extraValuesToUploadToServer; + dispatch_sync(_queue, ^{ + NSArray* failureRecords = self->_database.failureRecords; + + NSDictionary* successCounts = self->_database.summaryCounts; + NSInteger totalSuccessCount = 0; + NSInteger totalHardFailureCount = 0; + NSInteger totalSoftFailureCount = 0; + for (NSDictionary* perEventTypeSuccessCounts in successCounts.objectEnumerator) { + totalSuccessCount += [perEventTypeSuccessCounts[SFAnalyticsLoggerColumnSuccessCount] integerValue]; + totalHardFailureCount += [perEventTypeSuccessCounts[SFAnalyticsLoggerColumnHardFailureCount] integerValue]; + totalSoftFailureCount += [perEventTypeSuccessCounts[SFAnalyticsLoggerColumnSoftFailureCount] integerValue]; + } + + NSDate* now = [NSDate date]; + + NSMutableDictionary* healthSummaryEvent = extraValues ? extraValues.mutableCopy : [[NSMutableDictionary alloc] init]; + healthSummaryEvent[SFAnalyticsLoggerSplunkTopic] = self->_splunkTopicName ?: [NSNull null]; + healthSummaryEvent[SFAnalyticsLoggerSplunkEventTime] = @([now timeIntervalSince1970] * 1000); + healthSummaryEvent[SFAnalyticsLoggerSplunkEventType] = @"ckksHealthSummary"; + healthSummaryEvent[SFAnalyticsLoggerColumnSuccessCount] = @(totalSuccessCount); + healthSummaryEvent[SFAnalyticsLoggerColumnHardFailureCount] = @(totalHardFailureCount); + healthSummaryEvent[SFAnalyticsLoggerColumnSoftFailureCount] = @(totalSoftFailureCount); + + NSMutableArray* splunkRecords = failureRecords.mutableCopy; + [splunkRecords addObject:healthSummaryEvent]; + + NSDictionary* jsonDict = @{SFAnalyticsLoggerSplunkPostTime : @([now timeIntervalSince1970] * 1000), @"events" : splunkRecords}; + + json = [NSJSONSerialization dataWithJSONObject:jsonDict options:NSJSONWritingPrettyPrinted error:error]; + }); + + return json; +} + +- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler { + assert(completionHandler); + (void)session; + secnotice("ckks", "Splunk upload challenge"); + NSURLCredential *cred = nil; + SecTrustResultType result = kSecTrustResultInvalid; + + if ([challenge previousFailureCount] > 0) { + // Previous failures occurred, bail + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + + } else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + /* + * Evaluate trust for the certificate + */ + + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + SecTrustEvaluate(serverTrust, &result); + if (_allowInsecureSplunkCert || (result == kSecTrustResultProceed) || (result == kSecTrustResultUnspecified)) { + /* + * All is well, accept the credentials + */ + if(_allowInsecureSplunkCert) { + secnotice("ckks", "Force Accepting Splunk Credential"); + } + cred = [NSURLCredential credentialForTrust:serverTrust]; + completionHandler(NSURLSessionAuthChallengeUseCredential, cred); + + } else { + /* + * An error occurred in evaluating trust, bail + */ + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + } else { + /* + * Just perform the default handling + */ + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } + +} + +- (BOOL)ignoreServerDisablingMessages +{ + return _ignoreServersMessagesTellingUsToGoAway; +} + +- (void)setIgnoreServerDisablingMessages:(BOOL)ignoreServer +{ + _ignoreServersMessagesTellingUsToGoAway = ignoreServer ? YES : NO; +} + +- (BOOL)allowsInsecureSplunkCert +{ + return _allowInsecureSplunkCert; +} + +- (void)setAllowsInsecureSplunkCert:(BOOL)allowsInsecureSplunkCert +{ + _allowInsecureSplunkCert = allowsInsecureSplunkCert ? YES : NO; +} + +@end + +@implementation SFAnalyticsLoggerSQLiteStore + ++ (instancetype)storeWithPath:(NSString*)path schema:(NSString*)schema +{ + SFAnalyticsLoggerSQLiteStore* store = nil; + @synchronized([SFAnalyticsLoggerSQLiteStore class]) { + static NSMutableDictionary* loggingStores = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + loggingStores = [[NSMutableDictionary alloc] init]; + }); + + NSString* standardizedPath = path.stringByStandardizingPath; + store = loggingStores[standardizedPath]; + if (!store) { + store = [[self alloc] initWithPath:standardizedPath schema:schema]; + loggingStores[standardizedPath] = store; + } + + [store open]; + } + + return store; +} + +- (void)dealloc +{ + [self close]; +} + +- (NSInteger)successCountForEventType:(NSString*)eventType +{ + return [[[[self select:@[SFAnalyticsLoggerColumnSuccessCount] from:SFAnalyticsLoggerTableSuccessCount where:@"event_type = ?" bindings:@[eventType]] firstObject] valueForKey:SFAnalyticsLoggerColumnSuccessCount] integerValue]; +} + +- (void)incrementSuccessCountForEventType:(NSString*)eventType +{ + NSInteger successCount = [self successCountForEventType:eventType]; + NSInteger hardFailureCount = [self hardFailureCountForEventType:eventType]; + NSInteger softFailureCount = [self softFailureCountForEventType:eventType]; + [self insertOrReplaceInto:SFAnalyticsLoggerTableSuccessCount values:@{SFAnalyticsLoggerColumnEventType : eventType, SFAnalyticsLoggerColumnSuccessCount : @(successCount + 1), SFAnalyticsLoggerColumnHardFailureCount : @(hardFailureCount), SFAnalyticsLoggerColumnSoftFailureCount : @(softFailureCount)}]; +} + +- (NSInteger)hardFailureCountForEventType:(NSString*)eventType +{ + return [[[[self select:@[SFAnalyticsLoggerColumnHardFailureCount] from:SFAnalyticsLoggerTableSuccessCount where:@"event_type = ?" bindings:@[eventType]] firstObject] valueForKey:SFAnalyticsLoggerColumnHardFailureCount] integerValue]; +} + +- (NSInteger)softFailureCountForEventType:(NSString*)eventType +{ + return [[[[self select:@[SFAnalyticsLoggerColumnSoftFailureCount] from:SFAnalyticsLoggerTableSuccessCount where:@"event_type = ?" bindings:@[eventType]] firstObject] valueForKey:SFAnalyticsLoggerColumnSoftFailureCount] integerValue]; +} + +- (void)incrementHardFailureCountForEventType:(NSString*)eventType +{ + NSInteger successCount = [self successCountForEventType:eventType]; + NSInteger hardFailureCount = [self hardFailureCountForEventType:eventType]; + NSInteger softFailureCount = [self softFailureCountForEventType:eventType]; + [self insertOrReplaceInto:SFAnalyticsLoggerTableSuccessCount values:@{SFAnalyticsLoggerColumnEventType : eventType, SFAnalyticsLoggerColumnSuccessCount : @(successCount), SFAnalyticsLoggerColumnHardFailureCount : @(hardFailureCount + 1), SFAnalyticsLoggerColumnSoftFailureCount : @(softFailureCount)}]; +} + +- (void)incrementSoftFailureCountForEventType:(NSString*)eventType +{ + NSInteger successCount = [self successCountForEventType:eventType]; + NSInteger hardFailureCount = [self hardFailureCountForEventType:eventType]; + NSInteger softFailureCount = [self softFailureCountForEventType:eventType]; + [self insertOrReplaceInto:SFAnalyticsLoggerTableSuccessCount values:@{SFAnalyticsLoggerColumnEventType : eventType, SFAnalyticsLoggerColumnSuccessCount : @(successCount), SFAnalyticsLoggerColumnHardFailureCount : @(hardFailureCount), SFAnalyticsLoggerColumnSoftFailureCount : @(softFailureCount + 1)}]; +} + +- (NSDictionary*)summaryCounts +{ + NSMutableDictionary* successCountsDict = [NSMutableDictionary dictionary]; + NSArray* rows = [self selectAllFrom:SFAnalyticsLoggerTableSuccessCount where:nil bindings:nil]; + for (NSDictionary* rowDict in rows) { + NSString* eventName = rowDict[SFAnalyticsLoggerColumnEventType]; + if (!eventName) { + secinfo("SFAnalytics", "ignoring entry in success counts table without an event name"); + continue; + } + + successCountsDict[eventName] = @{SFAnalyticsLoggerTableSuccessCount : rowDict[SFAnalyticsLoggerColumnSuccessCount], SFAnalyticsLoggerColumnHardFailureCount : rowDict[SFAnalyticsLoggerColumnHardFailureCount], SFAnalyticsLoggerColumnSoftFailureCount : rowDict[SFAnalyticsLoggerColumnSoftFailureCount]}; + } + + return successCountsDict; +} + +- (NSArray*)failureRecords +{ + NSArray* recordBlobs = [self select:@[SFAnalyticsLoggerColumnData] from:SFAnalyticsLoggerTableHardFailures]; + if (recordBlobs.count < SFANALYTICS_MAX_EVENTS_TO_REPORT) { + NSArray* softFailureBlobs = [self select:@[SFAnalyticsLoggerColumnData] from:SFAnalyticsLoggerTableSoftFailures]; + if (softFailureBlobs.count > 0) { + NSInteger numSoftFailuresToReport = SFANALYTICS_MAX_EVENTS_TO_REPORT - recordBlobs.count; + recordBlobs = [recordBlobs arrayByAddingObjectsFromArray:[softFailureBlobs subarrayWithRange:NSMakeRange(softFailureBlobs.count - numSoftFailuresToReport, numSoftFailuresToReport)]]; + } + } + + NSMutableArray* failureRecords = [[NSMutableArray alloc] init]; + for (NSDictionary* row in recordBlobs) { + NSDictionary* deserializedRecord = [NSPropertyListSerialization propertyListWithData:row[SFAnalyticsLoggerColumnData] options:0 format:nil error:nil]; + [failureRecords addObject:deserializedRecord]; + } + + return failureRecords; +} + +- (NSArray*)allEvents +{ + NSArray* recordBlobs = [self select:@[SFAnalyticsLoggerColumnData] from:SFAnalyticsLoggerTableAllEvents]; + NSMutableArray* records = [[NSMutableArray alloc] init]; + for (NSDictionary* row in recordBlobs) { + NSDictionary* deserializedRecord = [NSPropertyListSerialization propertyListWithData:row[SFAnalyticsLoggerColumnData] options:0 format:nil error:nil]; + [records addObject:deserializedRecord]; + } + return records; +} + +- (void)addEventDict:(NSDictionary*)eventDict toTable:(NSString*)table +{ + NSError* error = nil; + NSData* serializedRecord = [NSPropertyListSerialization dataWithPropertyList:eventDict format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error]; + if(!error && serializedRecord) { + [self insertOrReplaceInto:table values:@{SFAnalyticsLoggerColumnDate : [NSDate date], SFAnalyticsLoggerColumnData : serializedRecord}]; + } + if(error && !serializedRecord) { + secerror("Couldn't serialize failure record: %@", error); + } +} + +- (NSDate*)uploadDate +{ + return [self datePropertyForKey:SFAnalyticsLoggerUploadDate]; +} + +- (void)setUploadDate:(NSDate*)uploadDate +{ + [self setDateProperty:uploadDate forKey:SFAnalyticsLoggerUploadDate]; +} + +- (void)clearAllData +{ + [self deleteFrom:SFAnalyticsLoggerTableSuccessCount where:@"event_type like ?" bindings:@[@"%"]]; + [self deleteFrom:SFAnalyticsLoggerTableHardFailures where:@"id >= 0" bindings:nil]; + [self deleteFrom:SFAnalyticsLoggerTableSoftFailures where:@"id >= 0" bindings:nil]; +} + +@end + +#endif // __OBJC2__ diff --git a/Analytics/SFAnalyticsLogging.plist b/Analytics/SFAnalyticsLogging.plist new file mode 100644 index 00000000..060222c3 --- /dev/null +++ b/Analytics/SFAnalyticsLogging.plist @@ -0,0 +1,16 @@ + + + + + splunk_topic + xp_sear_keysync + splunk_allowInsecureCertificate + + splunk_bagURL + https://xp.apple.com/config/1/report/xp_sear_keysync + SyncManifests + + EnforceManifests + + + diff --git a/Analytics/SQLite/SFObjCType.h b/Analytics/SQLite/SFObjCType.h new file mode 100644 index 00000000..61acd4b6 --- /dev/null +++ b/Analytics/SQLite/SFObjCType.h @@ -0,0 +1,88 @@ +/* + * 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 + +typedef NS_ENUM(NSInteger, SFObjCTypeCode) { + SFObjCTypeChar = 0, // 'c' + SFObjCTypeShort = 1, // 's' + SFObjCTypeInt = 2, // 'i' + SFObjCTypeLong = 3, // 'l' + SFObjCTypeLongLong = 4, // 'q' + SFObjCTypeUnsignedChar = 5, // 'C' + SFObjCTypeUnsignedShort = 6, // 'S' + SFObjCTypeUnsignedInt = 7, // 'I' + SFObjCTypeUnsignedLong = 8, // 'L' + SFObjCTypeUnsignedLongLong = 9, // 'Q' + SFObjCTypeFloat = 10, // 'f' + SFObjCTypeDouble = 11, // 'd' + SFObjCTypeBool = 12, // 'b' + SFObjCTypeVoid = 13, // 'v' + SFObjCTypeCharPointer = 14, // '*' + SFObjCTypeObject = 15, // '@' + SFObjCTypeClass = 16, // '#' + SFObjCTypeSelector = 17, // ':' + SFObjCTypeArray = 18, // '[' type ']' + SFObjCTypeStructure = 19, // '{' name '=' type... '}' + SFObjCTypeUnion = 20, // '(' name '=' type... ')' + SFObjCTypeBitfield = 21, // 'b' number + SFObjCTypePointer = 22, // '^' type + SFObjCTypeUnknown = 23, // '?' +}; + +typedef NS_ENUM(NSInteger, SFObjCTypeFlag) { + SFObjCTypeFlagIntegerNumber = 0x1, + SFObjCTypeFlagFloatingPointNumber = 0x2, + + SFObjCTypeFlagNone = 0x0, + SFObjCTypeFlagNumberMask = 0x3, +}; + +@interface SFObjCType : NSObject { + SFObjCTypeCode _code; + NSString* _encoding; + NSString* _name; + NSString* _className; + NSUInteger _size; + NSUInteger _flags; +} + ++ (SFObjCType *)typeForEncoding:(const char *)encoding; ++ (SFObjCType *)typeForValue:(NSValue *)value; + +@property (nonatomic, readonly, assign) SFObjCTypeCode code; +@property (nonatomic, readonly, strong) NSString *encoding; +@property (nonatomic, readonly, strong) NSString *name; +@property (nonatomic, readonly, strong) NSString *className; +@property (nonatomic, readonly, assign) NSUInteger size; +@property (nonatomic, readonly, assign) NSUInteger flags; + +@property (nonatomic, readonly, assign, getter=isNumber) BOOL number; +@property (nonatomic, readonly, assign, getter=isIntegerNumber) BOOL integerNumber; +@property (nonatomic, readonly, assign, getter=isFloatingPointNumber) BOOL floatingPointNumber; +@property (nonatomic, readonly, assign, getter=isObject) BOOL object; + +- (id)objectWithBytes:(const void *)bytes; +- (void)getBytes:(void *)bytes forObject:(id)object; + +@end diff --git a/Analytics/SQLite/SFObjCType.m b/Analytics/SQLite/SFObjCType.m new file mode 100644 index 00000000..98257f2b --- /dev/null +++ b/Analytics/SQLite/SFObjCType.m @@ -0,0 +1,169 @@ +/* + * 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 "SFObjCType.h" + + +static NSArray *_SFObjCTypesByCode = nil; + + +#define OBJC_TYPE(_code, _encoding, _name, _size, _flags) \ + [[SFObjCType alloc] initWithCode:SFObjCType##_code encoding:_encoding name:_name className:nil size:_size flags:SFObjCTypeFlag##_flags] + +@implementation SFObjCType + +@synthesize code = _code; +@synthesize encoding = _encoding; +@synthesize name = _name; +@synthesize className = _className; +@synthesize size = _size; +@synthesize flags = _flags; + ++ (SFObjCType *)typeForEncoding:(const char *)encodingUTF8 { + NSString *encoding = @(encodingUTF8); + + static dispatch_once_t once; + dispatch_once(&once, ^{ + _SFObjCTypesByCode = @[ + OBJC_TYPE(Char, @"c", @"char", sizeof(char), IntegerNumber), + OBJC_TYPE(Short, @"s", @"short", sizeof(short), IntegerNumber), + OBJC_TYPE(Int, @"i", @"int", sizeof(int), IntegerNumber), + OBJC_TYPE(Long, @"l", @"long", sizeof(long), IntegerNumber), + OBJC_TYPE(LongLong, @"q", @"long long", sizeof(long long), IntegerNumber), + OBJC_TYPE(UnsignedChar, @"C", @"unsigned char", sizeof(unsigned char), IntegerNumber), + OBJC_TYPE(UnsignedShort, @"S", @"unsigned short", sizeof(unsigned short), IntegerNumber), + OBJC_TYPE(UnsignedInt, @"I", @"unsigned int", sizeof(unsigned int), IntegerNumber), + OBJC_TYPE(UnsignedLong, @"L", @"unsigned long", sizeof(unsigned long), IntegerNumber), + OBJC_TYPE(UnsignedLongLong, @"Q", @"unsigned long long", sizeof(unsigned long long), IntegerNumber), + OBJC_TYPE(Float, @"f", @"float", sizeof(float), FloatingPointNumber), + OBJC_TYPE(Double, @"d", @"double", sizeof(double), FloatingPointNumber), + OBJC_TYPE(Bool, @"B", @"bool", sizeof(bool), IntegerNumber), + OBJC_TYPE(Void, @"v", @"void", sizeof(void), None), + OBJC_TYPE(CharPointer, @"*", @"char*", sizeof(char*), None), + OBJC_TYPE(Object, @"@", @"id", sizeof(id), None), + OBJC_TYPE(Class, @"#", @"Class", sizeof(Class), None), + ]; + }); + + switch (encodingUTF8[0]) { + case 'c': return _SFObjCTypesByCode[SFObjCTypeChar]; + case 's': return _SFObjCTypesByCode[SFObjCTypeShort]; + case 'i': return _SFObjCTypesByCode[SFObjCTypeInt]; + case 'l': return _SFObjCTypesByCode[SFObjCTypeLong]; + case 'q': return _SFObjCTypesByCode[SFObjCTypeLongLong]; + case 'C': return _SFObjCTypesByCode[SFObjCTypeUnsignedChar]; + case 'S': return _SFObjCTypesByCode[SFObjCTypeUnsignedShort]; + case 'I': return _SFObjCTypesByCode[SFObjCTypeUnsignedInt]; + case 'L': return _SFObjCTypesByCode[SFObjCTypeUnsignedLong]; + case 'Q': return _SFObjCTypesByCode[SFObjCTypeUnsignedLongLong]; + case 'f': return _SFObjCTypesByCode[SFObjCTypeFloat]; + case 'd': return _SFObjCTypesByCode[SFObjCTypeDouble]; + case 'B': return _SFObjCTypesByCode[SFObjCTypeBool]; + case 'v': return _SFObjCTypesByCode[SFObjCTypeVoid]; + case '*': return _SFObjCTypesByCode[SFObjCTypeCharPointer]; + case '@': { + if (encoding.length > 3 && [encoding characterAtIndex:1] == '"' && [encoding characterAtIndex:encoding.length-1] == '"') { + NSString *className = [encoding substringWithRange:NSMakeRange(2, encoding.length-3)]; + NSString *name = [className stringByAppendingString:@"*"]; + return [[SFObjCType alloc] initWithCode:SFObjCTypeObject encoding:encoding name:name className:className size:sizeof(id) flags:SFObjCTypeFlagNone]; + } else { + return _SFObjCTypesByCode[SFObjCTypeObject]; + } + } + case '#': return _SFObjCTypesByCode[SFObjCTypeClass]; + case ':': return _SFObjCTypesByCode[SFObjCTypeSelector]; + case '[': return OBJC_TYPE(Array, encoding, @"array", 0, None); + case '{': return OBJC_TYPE(Structure, encoding, @"structure", 0, None); + case '(': return OBJC_TYPE(Union, encoding, @"union", 0, None); + case 'b': return OBJC_TYPE(Bitfield, encoding, @"bitfield", 0, None); + case '^': return OBJC_TYPE(Pointer, encoding, @"pointer", sizeof(void*), None); + case '?': + default: + return [[SFObjCType alloc] initWithCode:SFObjCTypeUnknown encoding:encoding name:@"unknown" className:nil size:0 flags:0]; + } +} + ++ (SFObjCType *)typeForValue:(NSValue *)value { + NS_VALID_UNTIL_END_OF_SCOPE NSValue *arcSafeValue = value; + return [SFObjCType typeForEncoding:[arcSafeValue objCType]]; +} + +- (id)initWithCode:(SFObjCTypeCode)code encoding:(NSString *)encoding name:(NSString *)name className:(NSString *)className size:(NSUInteger)size flags:(NSUInteger)flags { + if ((self = [super init])) { + _code = code; + _encoding = encoding; + _name = name; + _className = className; + _size = size; + _flags = flags; + } + return self; +} + +- (BOOL)isNumber { + return (_flags & SFObjCTypeFlagNumberMask) != 0; +} + +- (BOOL)isIntegerNumber { + return (_flags & SFObjCTypeFlagIntegerNumber) != 0; +} + +- (BOOL)isFloatingPointNumber { + return (_flags & SFObjCTypeFlagFloatingPointNumber) != 0; +} + +- (BOOL)isObject { + return _code == SFObjCTypeObject; +} + +- (id)objectWithBytes:(const void *)bytes { + switch (_code) { + case SFObjCTypeChar: return [NSNumber numberWithChar:*((const char *)bytes)]; + case SFObjCTypeShort: return [NSNumber numberWithShort:*((const short *)bytes)]; + case SFObjCTypeInt: return [NSNumber numberWithInt:*((const int *)bytes)]; + case SFObjCTypeLong: return [NSNumber numberWithLong:*((const long *)bytes)]; + case SFObjCTypeLongLong: return [NSNumber numberWithLongLong:*((const long long *)bytes)]; + case SFObjCTypeUnsignedChar: return [NSNumber numberWithUnsignedChar:*((const unsigned char *)bytes)]; + case SFObjCTypeUnsignedShort: return [NSNumber numberWithUnsignedShort:*((const unsigned short *)bytes)]; + case SFObjCTypeUnsignedInt: return [NSNumber numberWithUnsignedInt:*((const unsigned int *)bytes)]; + case SFObjCTypeUnsignedLong: return [NSNumber numberWithUnsignedLong:*((const unsigned long *)bytes)]; + case SFObjCTypeUnsignedLongLong: return [NSNumber numberWithUnsignedLongLong:*((const unsigned long long *)bytes)]; + case SFObjCTypeFloat: return [NSNumber numberWithFloat:*((const float *)bytes)]; + case SFObjCTypeDouble: return [NSNumber numberWithDouble:*((const double *)bytes)]; + case SFObjCTypeBool: return [NSNumber numberWithBool:(BOOL)*((const _Bool *)bytes)]; + case SFObjCTypeObject: return (__bridge id)((const void *)(*((uintptr_t *)bytes))); + default: + [NSException raise:NSInternalInconsistencyException format:@"For class %@, Unsupported boxing type: %@", _className, _name]; + return nil; + } +} + +- (void)getBytes:(void *)bytes forObject:(id)object { + if ([object isKindOfClass:[NSValue class]]) { + [object getValue:bytes]; + } else { + [NSException raise:NSInternalInconsistencyException format:@"Unsupported unboxing type: %@", _name]; + } +} + +@end diff --git a/Analytics/SQLite/SFSQLite.h b/Analytics/SQLite/SFSQLite.h new file mode 100644 index 00000000..9a5a4b20 --- /dev/null +++ b/Analytics/SQLite/SFSQLite.h @@ -0,0 +1,152 @@ +/* + * 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@ + */ + +// Header exposed for unit testing only + +#import +#import + +@class SFSQLiteStatement; + +typedef SInt64 SFSQLiteRowID; +@class SFSQLite; + +NSArray *SFSQLiteJournalSuffixes(void); + +typedef NS_ENUM(NSInteger, SFSQLiteSynchronousMode) { + SFSQLiteSynchronousModeOff = 0, + SFSQLiteSynchronousModeNormal = 1, // default + SFSQLiteSynchronousModeFull = 2 +}; + +@protocol SFSQLiteDelegate +@property (nonatomic, readonly) SInt32 userVersion; + +- (BOOL)migrateDatabase:(SFSQLite *)db fromVersion:(SInt32)version; +@end + +// Wrapper around the SQLite API. Typically subclassed to add table accessor methods. +@interface SFSQLite : NSObject { + id _delegate; + NSString* _path; + NSString* _schema; + NSString* _schemaVersion; + NSMutableDictionary* _statementsBySQL; + NSString* _objectClassPrefix; + SFSQLiteSynchronousMode _synchronousMode; + SInt32 _userVersion; + sqlite3* _db; + NSUInteger _openCount; + NSDateFormatter* _dateFormatter; +#if DEBUG + NSMutableDictionary* _unitTestOverrides; +#endif + BOOL _hasMigrated; + BOOL _shouldVacuum; + BOOL _corrupt; + BOOL _traced; +} + +- (instancetype)initWithPath:(NSString *)path schema:(NSString *)schema; + +@property (nonatomic, readonly, strong) NSString *path; +@property (nonatomic, readonly, strong) NSString *schema; +@property (nonatomic, readonly, strong) NSString *schemaVersion; +@property (nonatomic, strong) NSString *objectClassPrefix; +@property (nonatomic, assign) SInt32 userVersion; +@property (nonatomic, assign) SFSQLiteSynchronousMode synchronousMode; +@property (nonatomic, readonly) BOOL isOpen; +@property (nonatomic, readonly) BOOL hasMigrated; +@property (nonatomic, assign) BOOL shouldVacuum; // vacuum the db on open (default:YES) +@property (nonatomic, assign) BOOL traced; + +@property (nonatomic, strong) id delegate; + +#if DEBUG +@property (nonatomic, strong) NSDictionary* unitTestOverrides; +#endif + +// Open/close the underlying database file read/write. Initially, the database is closed. +- (void)open; +- (BOOL)openWithError:(NSError **)error; +- (void)close; + +// Remove the database file. +- (void)remove; + +// Database exclusive transaction operations. +- (void)begin; +- (void)end; +- (void)rollback; + +// Database maintenance. +- (void)analyze; +- (void)vacuum; + +// Raise an exception. Including any database error in the description and removing the databse if it's corrupt. +- (void)raise:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); + +// The rowID assigned to the last record inserted into the database. +- (SFSQLiteRowID)lastInsertRowID; + +// returns the number of rows modified, inserted or deleted by the most recently completed INSERT, UPDATE or DELETE statement on the database connection +- (int)changes; + +// Execute one-or-more queries. Use prepared statements for anything performance critical. +- (void)executeSQL:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); +- (void)executeSQL:(NSString *)format arguments:(va_list)args NS_FORMAT_FUNCTION(1, 0); + +// Prepared statement pool accessors. Statements must be reset after they're used. +- (SFSQLiteStatement *)statementForSQL:(NSString *)SQL; +- (void)removeAllStatements; + +// Accessors for all the tables created in the database. +- (NSArray *)allTableNames; +- (void)dropAllTables; + +// Generic key/value properties set in the database. +- (NSString *)propertyForKey:(NSString *)key; +- (void)setProperty:(NSString *)value forKey:(NSString *)key; +- (NSDate *)datePropertyForKey:(NSString *)key; +- (void)setDateProperty:(NSDate *)value forKey:(NSString *)key; +- (void)removePropertyForKey:(NSString *)key; + +// Date the cache was created. +- (NSDate *)creationDate; + +// Convience calls that generate and execute statements. +- (NSArray *)selectAllFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings; +- (NSArray *)select:(NSArray *)columns from:(NSString *)tableName; +- (NSArray *)select:(NSArray *)columns from:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings; +- (void)select:(NSArray *)columns from:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings orderBy:(NSArray *)orderBy limit:(NSNumber *)limit block:(void (^)(NSDictionary *resultDictionary, BOOL *stop))block; +- (void)selectFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings orderBy:(NSArray *)orderBy limit:(NSNumber *)limit block:(void (^)(NSDictionary *resultDictionary, BOOL *stop))block; +- (NSUInteger)selectCountFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings; +- (SFSQLiteRowID)insertOrReplaceInto:(NSString *)tableName values:(NSDictionary *)valuesByColumnName; +- (void)deleteFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings; +- (void)update:(NSString *)tableName set:(NSString *)setSQL where:(NSString *)whereSQL bindings:(NSArray *)whereBindings limit:(NSNumber *)limit; +- (void)deleteFrom:(NSString *)tableName matchingValues:(NSDictionary *)valuesByColumnName; +- (NSSet *)columnNamesForTable:(NSString*)tableName; + +- (SInt32)dbUserVersion; + +@end diff --git a/Analytics/SQLite/SFSQLite.m b/Analytics/SQLite/SFSQLite.m new file mode 100644 index 00000000..4590e889 --- /dev/null +++ b/Analytics/SQLite/SFSQLite.m @@ -0,0 +1,1067 @@ +/* + * 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 "SFSQLite.h" +#import "SFSQLiteStatement.h" +#include +#include + + +#define kSFSQLiteBusyTimeout (5*60*1000) + +// Vaccuum our databases approximately once a week +#define kCKSQLVacuumInterval ((60*60*24)*7) +#define kSFSQLiteLastVacuumKey @"LastVacuum" + +#define kSFSQLiteSchemaVersionKey @"SchemaVersion" +#define kSFSQLiteCreatedDateKey @"Created" + +static NSString *const kSFSQLiteCreatePropertiesTableSQL = + @"create table if not exists Properties (\n" + @" key text primary key,\n" + @" value text\n" + @");\n"; + +@interface SFSQLiteError : NSObject ++ (void)raise:(NSString *)reason code:(int)code extended:(int)extended; +@end + + +NSArray *SFSQLiteJournalSuffixes() { + return @[@"-journal", @"-wal", @"-shm"]; +} + +@interface NSObject (SFSQLiteAdditions) ++ (NSString *)SFSQLiteClassName; +@end + +@implementation NSObject (SFSQLiteAdditions) ++ (NSString *)SFSQLiteClassName { + return NSStringFromClass(self); +} +@end + +@interface SFSQLite () + +@property (nonatomic, assign) sqlite3 *db; +@property (nonatomic, assign) NSUInteger openCount; +@property (nonatomic, assign) BOOL corrupt; +@property (nonatomic, readonly, strong) NSMutableDictionary *statementsBySQL; +@property (nonatomic, strong) NSDateFormatter *dateFormatter; + +@end + +static char intToHexChar(uint8_t i) +{ + return i >= 10 ? 'a' + i - 10 : '0' + i; +} + +static char *SecHexCharFromBytes(const uint8_t *bytes, NSUInteger length, NSUInteger *outlen) { + // Fudge the math a bit on the assert because we don't want a 1GB string anyway + if (length > (NSUIntegerMax / 3)) { + return nil; + } + char *hex = calloc(1, length * 2 * 9 / 8); // 9/8 so we can inline ' ' between every 8 character sequence + char *destPtr = hex; + + NSUInteger i; + + for (i = 0; length > 4; i += 4, length -= 4) { + for (NSUInteger offset = 0; offset < 4; offset++) { + *destPtr++ = intToHexChar((bytes[i+offset] & 0xF0) >> 4); + *destPtr++ = intToHexChar(bytes[i+offset] & 0x0F); + } + *destPtr++ = ' '; + } + + /* Using the same i from the above loop */ + for (; length > 0; i++, length--) { + *destPtr++ = intToHexChar((bytes[i] & 0xF0) >> 4); + *destPtr++ = intToHexChar(bytes[i] & 0x0F); + } + + if (outlen) *outlen = destPtr - hex; + + return hex; +} + +static BOOL SecCreateDirectoryAtPath(NSString *path, NSError **error) { + BOOL success = YES; + NSError *localError; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + if (![fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&localError]) { + if (![localError.domain isEqualToString:NSCocoaErrorDomain] || localError.code != NSFileWriteFileExistsError) { + success = NO; + } + } + +#if TARGET_OS_IPHONE + if (success) { + NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:&localError]; + if (![attributes[NSFileProtectionKey] isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]) { + [fileManager setAttributes:@{ NSFileProtectionKey: NSFileProtectionCompleteUntilFirstUserAuthentication } + ofItemAtPath:path error:nil]; + } + } +#endif + if (!success) { + if (error) *error = localError; + } + return success; +} + +@implementation NSData (CKUtilsAdditions) + +- (NSString *)CKHexString { + NSUInteger hexLen = 0; + NS_VALID_UNTIL_END_OF_SCOPE NSData *arcSafeSelf = self; + char *hex = SecHexCharFromBytes([arcSafeSelf bytes], [arcSafeSelf length], &hexLen); + return [[NSString alloc] initWithBytesNoCopy:hex length:hexLen encoding:NSASCIIStringEncoding freeWhenDone:YES]; +} + +- (NSString *)CKLowercaseHexStringWithoutSpaces { + NSMutableString *retVal = [[self CKHexString] mutableCopy]; + [retVal replaceOccurrencesOfString:@" " withString:@"" options:0 range:NSMakeRange(0, [retVal length])]; + return retVal; +} + +- (NSString *)CKUppercaseHexStringWithoutSpaces { + NSMutableString *retVal = [[[self CKHexString] uppercaseString] mutableCopy]; + [retVal replaceOccurrencesOfString:@" " withString:@"" options:0 range:NSMakeRange(0, [retVal length])]; + return retVal; +} + ++ (NSData *)CKDataWithHexString:(NSString *)hexString stringIsUppercase:(BOOL)stringIsUppercase { + NSMutableData *retVal = [[NSMutableData alloc] init]; + NSCharacterSet *hexCharacterSet = nil; + char aChar; + if (stringIsUppercase) { + hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"]; + aChar = 'A'; + } else { + hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdef"]; + aChar = 'a'; + } + + unsigned int i; + for (i = 0; i < [hexString length] ; ) { + BOOL validFirstByte = NO; + BOOL validSecondByte = NO; + unichar firstByte = 0; + unichar secondByte = 0; + + for ( ; i < [hexString length]; i++) { + firstByte = [hexString characterAtIndex:i]; + if ([hexCharacterSet characterIsMember:firstByte]) { + i++; + validFirstByte = YES; + break; + } + } + for ( ; i < [hexString length]; i++) { + secondByte = [hexString characterAtIndex:i]; + if ([hexCharacterSet characterIsMember:secondByte]) { + i++; + validSecondByte = YES; + break; + } + } + if (!validFirstByte || !validSecondByte) { + goto allDone; + } + if ((firstByte >= '0') && (firstByte <= '9')) { + firstByte -= '0'; + } else { + firstByte = firstByte - aChar + 10; + } + if ((secondByte >= '0') && (secondByte <= '9')) { + secondByte -= '0'; + } else { + secondByte = secondByte - aChar + 10; + } + char totalByteValue = (char)((firstByte << 4) + secondByte); + + [retVal appendBytes:&totalByteValue length:1]; + } +allDone: + return retVal; +} + ++ (NSData *)CKDataWithHexString:(NSString *)hexString { + return [self CKDataWithHexString:hexString stringIsUppercase:NO]; +} + +@end + +@implementation SFSQLite + +@synthesize delegate = _delegate; +@synthesize path = _path; +@synthesize schema = _schema; +@synthesize schemaVersion = _schemaVersion; +@synthesize objectClassPrefix = _objectClassPrefix; +@synthesize userVersion = _userVersion; +@synthesize synchronousMode = _synchronousMode; +@synthesize hasMigrated = _hasMigrated; +@synthesize shouldVacuum = _shouldVacuum; +@synthesize traced = _traced; +@synthesize db = _db; +@synthesize openCount = _openCount; +@synthesize corrupt = _corrupt; +@synthesize statementsBySQL = _statementsBySQL; +@synthesize dateFormatter = _dateFormatter; +#if DEBUG +@synthesize unitTestOverrides = _unitTestOverrides; +#endif + +- (instancetype)initWithPath:(NSString *)path schema:(NSString *)schema { + if ((self = [super init])) { + NSAssert([path length], @"Can't init a database with a zero-length path"); + _path = path; + _schema = schema; + _schemaVersion = [self _createSchemaHash]; + _statementsBySQL = [[NSMutableDictionary alloc] init]; + _objectClassPrefix = @"CK"; + _synchronousMode = SFSQLiteSynchronousModeNormal; + _hasMigrated = NO; + _shouldVacuum = YES; + } + return self; +} + +- (void)dealloc { + @autoreleasepool { + [self close]; + } +} + +- (SInt32)userVersion { + if (self.delegate) { + return self.delegate.userVersion; + } + return _userVersion; +} + +- (NSString *)_synchronousModeString { + switch (self.synchronousMode) { + case SFSQLiteSynchronousModeOff: + return @"off"; + case SFSQLiteSynchronousModeFull: + return @"full"; + case SFSQLiteSynchronousModeNormal: + break; + default: + assert(0 && "Unknown synchronous mode"); + } + return @"normal"; +} + +- (NSString *)_createSchemaHash { + unsigned char hashBuffer[CC_SHA256_DIGEST_LENGTH] = {0}; + NSData *hashData = [NSData dataWithBytesNoCopy:hashBuffer length:CC_SHA256_DIGEST_LENGTH freeWhenDone:NO]; + NS_VALID_UNTIL_END_OF_SCOPE NSData *schemaData = [self.schema dataUsingEncoding:NSUTF8StringEncoding]; + CC_SHA256([schemaData bytes], (CC_LONG)[schemaData length], hashBuffer); + return [hashData CKUppercaseHexStringWithoutSpaces]; +} + +- (BOOL)isOpen { + return _db != NULL; +} + +- (void)_periodicVacuum { + // "When the auto-vacuum mode is 1 or "full", the freelist pages are moved to the end of the database file and the database file is truncated to remove the freelist pages at every transaction commit. + // Note, however, that auto-vacuum only truncates the freelist pages from the file. Auto-vacuum does not defragment the database nor repack individual database pages the way that the VACUUM command does. + // In fact, because it moves pages around within the file, auto-vacuum can actually make fragmentation worse." + // https://sqlite.org/pragma.html#pragma_auto_vacuum + NSDate *lastVacuumDate = [NSDate dateWithTimeIntervalSinceReferenceDate:[[self propertyForKey:kSFSQLiteLastVacuumKey] floatValue]]; + if ([lastVacuumDate timeIntervalSinceNow] < -(kCKSQLVacuumInterval)) { + [self executeSQL:@"VACUUM"]; + + NSString *vacuumDateString = [NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSinceReferenceDate]]; + [self setProperty:vacuumDateString forKey:kSFSQLiteLastVacuumKey]; + } +} + +- (BOOL)openWithError:(NSError **)error { + BOOL success = NO; + NSError *localError; + NSString *dbSchemaVersion, *dir; + NSArray *results; + NS_VALID_UNTIL_END_OF_SCOPE NSString *arcSafePath = _path; + + if (_openCount > 0) { + NSAssert(_db != NULL, @"Missing handle for open cache db"); + _openCount += 1; + success = YES; + goto done; + } + + // Create the directory for the cache. + dir = [_path stringByDeletingLastPathComponent]; + if (!SecCreateDirectoryAtPath(dir, &localError)) { + goto done; + } + + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; +#if TARGET_OS_IPHONE + flags |= SQLITE_OPEN_FILEPROTECTION_COMPLETEUNTILFIRSTUSERAUTHENTICATION; +#endif + int rc = sqlite3_open_v2([arcSafePath fileSystemRepresentation], &_db, flags, NULL); + if (rc != SQLITE_OK) { + localError = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Error opening db at %@, rc=%d(0x%x)", _path, rc, rc]}]; + goto done; + } + sqlite3_extended_result_codes(_db, 1); + rc = sqlite3_busy_timeout(_db, kSFSQLiteBusyTimeout); + if (rc != SQLITE_OK) { + goto done; + } + + // You don't argue with the Ben: rdar://12685305 + [self executeSQL:@"pragma journal_mode = WAL"]; + [self executeSQL:@"pragma synchronous = %@", [self _synchronousModeString]]; + [self executeSQL:@"pragma auto_vacuum = FULL"]; + + // rdar://problem/32168789 + // [self executeSQL:@"pragma foreign_keys = 1"]; + + // Initialize the db within a transaction in case there is a crash between creating the schema and setting the + // schema version, and to avoid multiple threads trying to re-create the db at once. + [self begin]; + + // Create the Properties table before trying to read the schema version from it. If the Properties table doesn't + // exist we can't prepare a statement to access it. + results = [self select:@[@"name"] from:@"sqlite_master" where:@"type = ? AND name = ?" bindings:@[@"table", @"Properties"]]; + if (!results.count) { + [self executeSQL:kSFSQLiteCreatePropertiesTableSQL]; + } + + // Check the schema version and create or re-create the db if needed. + BOOL create = NO; + dbSchemaVersion = [self propertyForKey:kSFSQLiteSchemaVersionKey]; + SInt32 dbUserVersion = [self dbUserVersion]; + + if (!dbSchemaVersion) { + // The schema version isn't set so the db was just created or we failed to initialize it previously. + create = YES; + } else if (![dbSchemaVersion isEqualToString:self.schemaVersion] + || (self.userVersion && dbUserVersion != self.userVersion)) { + + if (self.delegate && [self.delegate migrateDatabase:self fromVersion:dbUserVersion]) { + _hasMigrated = YES; + } + + if (!_hasMigrated) { + // The schema version doesn't match and we haven't migrated to the new version. Give up and throw away the db and re-create it instead of trying to migrate. + [self removeAllStatements]; + [self dropAllTables]; + create = YES; + _hasMigrated = YES; + } + } + if (create) { + [self executeSQL:kSFSQLiteCreatePropertiesTableSQL]; + [self executeSQL:@"%@", self.schema]; + NSString *createdDateString = [NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSinceReferenceDate]]; + [self setProperty:createdDateString forKey:kSFSQLiteCreatedDateKey]; + } + + [self end]; + +#if DEBUG + // TODO: Resolve Race Condition When Setting 'userVersion/schemaVersion' in SFSQLite + if ([self.unitTestOverrides[@"RacyUserVersionUpdate"] isEqual:@YES]) { + success = YES; + goto done; + } +#endif + + if (self.shouldVacuum) [self _periodicVacuum]; + + if (create || _hasMigrated) { + [self setProperty:self.schemaVersion forKey:kSFSQLiteSchemaVersionKey]; + if (self.userVersion) { + [self executeSQL:@"pragma user_version = %ld", (long)self.userVersion]; + } + } + + _openCount += 1; + success = YES; + +done: + if (!success && error) { + *error = localError; + } + return success; +} + +- (void)open { + NSError *error; + if (![self openWithError:&error]) { + [self raise:@"Error opening db at %@: %@", self.path, error]; + } +} + + +- (void)close { + if (_openCount > 0) { + if (_openCount == 1) { + NSAssert(_db != NULL, @"Missing handle for open cache db"); + + [self removeAllStatements]; + + if (sqlite3_close(_db)) { + [self raise:@"Error closing database"]; + } + _db = NULL; + } + _openCount -= 1; + } +} + +- (void)remove { + NSAssert(_openCount == 0, @"Trying to remove db at: %@ while it is open", _path); + [[NSFileManager defaultManager] removeItemAtPath:_path error:nil]; + for (NSString *suffix in SFSQLiteJournalSuffixes()) { + [[NSFileManager defaultManager] removeItemAtPath:[_path stringByAppendingString:suffix] error:nil]; + } +} + +- (void)begin { + [self executeSQL:@"begin exclusive"]; +} + +- (void)end { + [self executeSQL:@"end"]; +} + +- (void)rollback { + [self executeSQL:@"rollback"]; +} + +- (void)analyze { + [self executeSQL:@"analyze"]; +} + +- (void)vacuum { + [self executeSQL:@"vacuum"]; +} + +- (void)raise:(NSString *)format, ... { + va_list args; + va_start(args, format); + + NSString *reason = [[NSString alloc] initWithFormat:format arguments:args]; + + int code = 0; + int extendedCode = 0; + if (_db) { + code = sqlite3_errcode(_db) & 0xFF; + extendedCode = sqlite3_extended_errcode(_db); + const char *errmsg = sqlite3_errmsg(_db); + + NSDictionary *dbAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:self.path error:NULL]; + NSDictionary *fsAttrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:self.path error:NULL]; + reason = [reason stringByAppendingFormat:@" - errcode:%04x, msg:\"%s\", size: %@, path:%@, fs:%@/%@", extendedCode, errmsg, dbAttrs[NSFileSize], _path, fsAttrs[NSFileSystemFreeSize], fsAttrs[NSFileSystemSize]]; + + if (!_corrupt && (code == SQLITE_CORRUPT || code == SQLITE_NOTADB)) { + _corrupt = YES; + + @try { + [self close]; + } @catch (NSException *x) { + NSLog(@"Warn: Error closing corrupt db: %@", x); + } + + [self remove]; + } + } + + va_end(args); + + [SFSQLiteError raise:reason code:code extended:extendedCode]; +} + +- (SFSQLiteRowID)lastInsertRowID { + if (!_db) { + [self raise:@"Database is closed"]; + } + + return sqlite3_last_insert_rowid(_db); +} + +- (int)changes +{ + if (!_db) { + [self raise:@"Database is closed"]; + } + + return sqlite3_changes(_db); +} + +- (void)executeSQL:(NSString *)format, ... { + va_list args; + va_start(args, format); + [self executeSQL:format arguments:args]; + va_end(args); +} + +- (void)executeSQL:(NSString *)format arguments:(va_list)args { + NS_VALID_UNTIL_END_OF_SCOPE NSString *SQL = [[NSString alloc] initWithFormat:format arguments:args]; + if (!_db) { + [self raise:@"Database is closed"]; + } + int execRet = sqlite3_exec(_db, [SQL UTF8String], NULL, NULL, NULL); + if (execRet != SQLITE_OK) { + [self raise:@"Error executing SQL: \"%@\" (%d)", SQL, execRet]; + } +} + +- (SFSQLiteStatement *)statementForSQL:(NSString *)SQL { + if (!_db) { + [self raise:@"Database is closed"]; + } + + SFSQLiteStatement *statement = _statementsBySQL[SQL]; + if (statement) { + NSAssert(statement.isReset, @"Statement not reset after last use: \"%@\"", SQL); + } else { + sqlite3_stmt *handle = NULL; + NS_VALID_UNTIL_END_OF_SCOPE NSString *arcSafeSQL = SQL; + if (sqlite3_prepare_v2(_db, [arcSafeSQL UTF8String], -1, &handle, NULL)) { + [self raise:@"Error preparing statement: %@", SQL]; + } + + statement = [[SFSQLiteStatement alloc] initWithSQLite:self SQL:SQL handle:handle]; + _statementsBySQL[SQL] = statement; + } + + return statement; +} + +- (void)removeAllStatements { + [[_statementsBySQL allValues] makeObjectsPerformSelector:@selector(finalizeStatement)]; + [_statementsBySQL removeAllObjects]; +} + +- (NSArray *)allTableNames { + NSMutableArray *tableNames = [[NSMutableArray alloc] init]; + + SFSQLiteStatement *statement = [self statementForSQL:@"select name from sqlite_master where type = 'table'"]; + while ([statement step]) { + NSString *name = [statement textAtIndex:0]; + [tableNames addObject:name]; + } + [statement reset]; + + return tableNames; +} + +- (void)dropAllTables { + for (NSString *tableName in [self allTableNames]) { + [self executeSQL:@"drop table %@", tableName]; + } +} + +- (NSString *)propertyForKey:(NSString *)key { + NSAssert(key, @"Null key"); + + NSString *value = nil; + + SFSQLiteStatement *statement = [self statementForSQL:@"select value from Properties where key = ?"]; + [statement bindText:key atIndex:0]; + if ([statement step]) { + value = [statement textAtIndex:0]; + } + [statement reset]; + + return value; +} + +- (void)setProperty:(NSString *)value forKey:(NSString *)key { + NSAssert(key, @"Null key"); + + if (value) { + SFSQLiteStatement *statement = [self statementForSQL:@"insert or replace into Properties (key, value) values (?,?)"]; + [statement bindText:key atIndex:0]; + [statement bindText:value atIndex:1]; + [statement step]; + [statement reset]; + } else { + [self removePropertyForKey:key]; + } +} + +- (NSDateFormatter *)dateFormatter { + if (!_dateFormatter) { + NSDateFormatter* dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZZZZZ"; + _dateFormatter = dateFormatter; + } + return _dateFormatter; +} + +- (NSDate *)datePropertyForKey:(NSString *)key { + NSString *dateStr = [self propertyForKey:key]; + if (dateStr.length) { + return [self.dateFormatter dateFromString:dateStr]; + } + return nil; +} + +- (void)setDateProperty:(NSDate *)value forKey:(NSString *)key { + NSString *dateStr = nil; + if (value) { + dateStr = [self.dateFormatter stringFromDate:value]; + } + [self setProperty:dateStr forKey:key]; +} + +- (void)removePropertyForKey:(NSString *)key { + NSAssert(key, @"Null key"); + + SFSQLiteStatement *statement = [self statementForSQL:@"delete from Properties where key = ?"]; + [statement bindText:key atIndex:0]; + [statement step]; + [statement reset]; +} + +- (NSDate *)creationDate { + return [NSDate dateWithTimeIntervalSinceReferenceDate:[[self propertyForKey:kSFSQLiteCreatedDateKey] floatValue]]; +} + +// https://sqlite.org/pragma.html#pragma_table_info +- (NSSet *)columnNamesForTable:(NSString*)tableName { + SFSQLiteStatement *statement = [self statementForSQL:[NSString stringWithFormat:@"pragma table_info(%@)", tableName]]; + NSMutableSet* columnNames = [[NSMutableSet alloc] init]; + while ([statement step]) { + [columnNames addObject:[statement textAtIndex:1]]; + } + [statement reset]; + return columnNames; +} + +- (NSArray *)select:(NSArray *)columns from:(NSString *)tableName { + return [self select:columns from:tableName where:nil bindings:nil]; +} + +- (NSArray *)select:(NSArray *)columns from:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings { + NSMutableArray *results = [[NSMutableArray alloc] init]; + + NSMutableString *SQL = [NSMutableString stringWithFormat:@"select %@ from %@", [columns componentsJoinedByString:@", "], tableName]; + if (whereSQL) { + [SQL appendFormat:@" where %@", whereSQL]; + } + + SFSQLiteStatement *statement = [self statementForSQL:SQL]; + [statement bindValues:bindings]; + while ([statement step]) { + [results addObject:[statement allObjectsByColumnName]]; + } + [statement reset]; + + return results; +} + +- (void)select:(NSArray *)columns from:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings orderBy:(NSArray *)orderBy limit:(NSNumber *)limit block:(void (^)(NSDictionary *resultDictionary, BOOL *stop))block { + @autoreleasepool { + NSMutableString *SQL = [[NSMutableString alloc] init]; + NSString *columnsString = @"*"; + if ([columns count]) columnsString = [columns componentsJoinedByString:@", "]; + [SQL appendFormat:@"select %@ from %@", columnsString, tableName]; + + if (whereSQL.length) { + [SQL appendFormat:@" where %@", whereSQL]; + } + if (orderBy) { + NSString *orderByString = [orderBy componentsJoinedByString:@", "]; + [SQL appendFormat:@" order by %@", orderByString]; + } + if (limit) { + [SQL appendFormat:@" limit %ld", (long)limit.integerValue]; + } + + SFSQLiteStatement *statement = [self statementForSQL:SQL]; + [statement bindValues:bindings]; + do { + @autoreleasepool { + if (![statement step]) { + break; + } + NSDictionary *stepResult = [statement allObjectsByColumnName]; + if (block) { + BOOL stop = NO; + block(stepResult, &stop); + if (stop) { + break; + } + } + } + } while (1); + [statement reset]; + } +} + +- (void)selectFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings orderBy:(NSArray *)orderBy limit:(NSNumber *)limit block:(void (^)(NSDictionary *resultDictionary, BOOL *stop))block { + @autoreleasepool { + NSMutableString *SQL = [[NSMutableString alloc] init]; + [SQL appendFormat:@"select * from %@", tableName]; + + if (whereSQL.length) { + [SQL appendFormat:@" where %@", whereSQL]; + } + if (orderBy) { + NSString *orderByString = [orderBy componentsJoinedByString:@", "]; + [SQL appendFormat:@" order by %@", orderByString]; + } + if (limit) { + [SQL appendFormat:@" limit %ld", (long)limit.integerValue]; + } + + SFSQLiteStatement *statement = [self statementForSQL:SQL]; + [statement bindValues:bindings]; + do { + @autoreleasepool { + if (![statement step]) { + break; + } + NSDictionary *stepResult = [statement allObjectsByColumnName]; + if (block) { + BOOL stop = NO; + block(stepResult, &stop); + if (stop) { + break; + } + } + } + } while (1); + [statement reset]; + } +} + +- (NSArray *)selectFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings limit:(NSNumber *)limit { + NSMutableString *SQL = [[NSMutableString alloc] init]; + [SQL appendFormat:@"select * from %@", tableName]; + + if (whereSQL.length) { + [SQL appendFormat:@" where %@", whereSQL]; + } + if (limit) { + [SQL appendFormat:@" limit %ld", (long)limit.integerValue]; + } + + NSMutableArray *results = [[NSMutableArray alloc] init]; + + SFSQLiteStatement *statement = [self statementForSQL:SQL]; + [statement bindValues:bindings]; + while ([statement step]) { + [results addObject:[statement allObjectsByColumnName]]; + } + [statement reset]; + + return results; +} + +- (void)update:(NSString *)tableName set:(NSString *)setSQL where:(NSString *)whereSQL bindings:(NSArray *)whereBindings limit:(NSNumber *)limit { + NSMutableString *SQL = [[NSMutableString alloc] init]; + [SQL appendFormat:@"update %@", tableName]; + + NSAssert(setSQL.length > 0, @"null set expression"); + + [SQL appendFormat:@" set %@", setSQL]; + if (whereSQL.length) { + [SQL appendFormat:@" where %@", whereSQL]; + } + if (limit) { + [SQL appendFormat:@" limit %ld", (long)limit.integerValue]; + } + + SFSQLiteStatement *statement = [self statementForSQL:SQL]; + [statement bindValues:whereBindings]; + while ([statement step]) { + } + [statement reset]; +} + +- (NSArray *)selectAllFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings { + return [self selectFrom:tableName where:whereSQL bindings:bindings limit:nil]; +} + +- (NSUInteger)selectCountFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings { + NSArray *results = [self select:@[@"count(*) as n"] from:tableName where:whereSQL bindings:bindings]; + return [results[0][@"n"] unsignedIntegerValue]; +} + +- (SFSQLiteRowID)insertOrReplaceInto:(NSString *)tableName values:(NSDictionary *)valuesByColumnName { + NSArray *columnNames = [[valuesByColumnName allKeys] sortedArrayUsingSelector:@selector(compare:)]; + NSMutableArray *values = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < columnNames.count; i++) { + values[i] = valuesByColumnName[columnNames[i]]; + } + + NSMutableString *SQL = [[NSMutableString alloc] initWithString:@"insert or replace into "]; + [SQL appendString:tableName]; + [SQL appendString:@" ("]; + for (NSUInteger i = 0; i < columnNames.count; i++) { + [SQL appendString:columnNames[i]]; + if (i != columnNames.count-1) { + [SQL appendString:@","]; + } + } + [SQL appendString:@") values ("]; + for (NSUInteger i = 0; i < columnNames.count; i++) { + if (i != columnNames.count-1) { + [SQL appendString:@"?,"]; + } else { + [SQL appendString:@"?"]; + } + } + [SQL appendString:@")"]; + + SFSQLiteStatement *statement = [self statementForSQL:SQL]; + [statement bindValues:values]; + [statement step]; + [statement reset]; + + return [self lastInsertRowID]; +} + +- (void)deleteFrom:(NSString *)tableName matchingValues:(NSDictionary *)valuesByColumnName { + NSArray *columnNames = [[valuesByColumnName allKeys] sortedArrayUsingSelector:@selector(compare:)]; + NSMutableArray *values = [[NSMutableArray alloc] init]; + NSMutableString *whereSQL = [[NSMutableString alloc] init]; + int bindingCount = 0; + for (NSUInteger i = 0; i < columnNames.count; i++) { + id value = valuesByColumnName[columnNames[i]]; + [whereSQL appendString:columnNames[i]]; + if (!value || [[NSNull null] isEqual:value]) { + [whereSQL appendString:@" is NULL"]; + } else { + values[bindingCount++] = value; + [whereSQL appendString:@"=?"]; + } + if (i != columnNames.count-1) { + [whereSQL appendString:@" AND "]; + } + } + [self deleteFrom:tableName where:whereSQL bindings:values]; +} + +- (void)deleteFrom:(NSString *)tableName where:(NSString *)whereSQL bindings:(NSArray *)bindings { + NSString *SQL = [NSString stringWithFormat:@"delete from %@ where %@", tableName, whereSQL]; + + SFSQLiteStatement *statement = [self statementForSQL:SQL]; + [statement bindValues:bindings]; + [statement step]; + [statement reset]; +} + +- (NSString *)_tableNameForClass:(Class)objectClass { + NSString *className = [objectClass SFSQLiteClassName]; + if (![className hasPrefix:_objectClassPrefix]) { + [NSException raise:NSInvalidArgumentException format:@"Object class \"%@\" does not have prefix \"%@\"", className, _objectClassPrefix]; + } + return [className substringFromIndex:_objectClassPrefix.length]; +} + +- (SInt32)dbUserVersion { + SInt32 userVersion = 0; + SFSQLiteStatement *statement = [self statementForSQL:@"pragma user_version"]; + while ([statement step]) { + userVersion = [statement intAtIndex:0]; + } + [statement reset]; + + return userVersion; +} + +@end + + +#define SFSQLiteErrorRaiseMethod(SQLiteError) + (void)SQLiteError:(NSString *)reason { [NSException raise:NSGenericException format:@"%@", reason]; } +#define SFSQLiteErrorCase(SQLiteError) case SQLITE_ ## SQLiteError: [self SQLiteError:reason]; break + +@implementation SFSQLiteError + +// SQLite error codes +SFSQLiteErrorRaiseMethod(ERROR) +SFSQLiteErrorRaiseMethod(INTERNAL) +SFSQLiteErrorRaiseMethod(PERM) +SFSQLiteErrorRaiseMethod(ABORT) +SFSQLiteErrorRaiseMethod(BUSY) +SFSQLiteErrorRaiseMethod(LOCKED) +SFSQLiteErrorRaiseMethod(NOMEM) +SFSQLiteErrorRaiseMethod(READONLY) +SFSQLiteErrorRaiseMethod(INTERRUPT) +SFSQLiteErrorRaiseMethod(IOERR) +SFSQLiteErrorRaiseMethod(CORRUPT) +SFSQLiteErrorRaiseMethod(NOTFOUND) +SFSQLiteErrorRaiseMethod(FULL) +SFSQLiteErrorRaiseMethod(CANTOPEN) +SFSQLiteErrorRaiseMethod(PROTOCOL) +SFSQLiteErrorRaiseMethod(SCHEMA) +SFSQLiteErrorRaiseMethod(TOOBIG) +SFSQLiteErrorRaiseMethod(CONSTRAINT) +SFSQLiteErrorRaiseMethod(MISMATCH) +SFSQLiteErrorRaiseMethod(MISUSE) +SFSQLiteErrorRaiseMethod(RANGE) +SFSQLiteErrorRaiseMethod(NOTADB) + +// SQLite extended error codes +SFSQLiteErrorRaiseMethod(IOERR_READ) +SFSQLiteErrorRaiseMethod(IOERR_SHORT_READ) +SFSQLiteErrorRaiseMethod(IOERR_WRITE) +SFSQLiteErrorRaiseMethod(IOERR_FSYNC) +SFSQLiteErrorRaiseMethod(IOERR_DIR_FSYNC) +SFSQLiteErrorRaiseMethod(IOERR_TRUNCATE) +SFSQLiteErrorRaiseMethod(IOERR_FSTAT) +SFSQLiteErrorRaiseMethod(IOERR_UNLOCK) +SFSQLiteErrorRaiseMethod(IOERR_RDLOCK) +SFSQLiteErrorRaiseMethod(IOERR_DELETE) +SFSQLiteErrorRaiseMethod(IOERR_BLOCKED) +SFSQLiteErrorRaiseMethod(IOERR_NOMEM) +SFSQLiteErrorRaiseMethod(IOERR_ACCESS) +SFSQLiteErrorRaiseMethod(IOERR_CHECKRESERVEDLOCK) +SFSQLiteErrorRaiseMethod(IOERR_LOCK) +SFSQLiteErrorRaiseMethod(IOERR_CLOSE) +SFSQLiteErrorRaiseMethod(IOERR_DIR_CLOSE) +SFSQLiteErrorRaiseMethod(IOERR_SHMOPEN) +SFSQLiteErrorRaiseMethod(IOERR_SHMSIZE) +SFSQLiteErrorRaiseMethod(IOERR_SHMLOCK) +SFSQLiteErrorRaiseMethod(IOERR_SHMMAP) +SFSQLiteErrorRaiseMethod(IOERR_SEEK) +SFSQLiteErrorRaiseMethod(IOERR_DELETE_NOENT) +SFSQLiteErrorRaiseMethod(IOERR_MMAP) +SFSQLiteErrorRaiseMethod(IOERR_GETTEMPPATH) +SFSQLiteErrorRaiseMethod(IOERR_CONVPATH) +SFSQLiteErrorRaiseMethod(LOCKED_SHAREDCACHE) +SFSQLiteErrorRaiseMethod(BUSY_RECOVERY) +SFSQLiteErrorRaiseMethod(BUSY_SNAPSHOT) +SFSQLiteErrorRaiseMethod(CANTOPEN_NOTEMPDIR) +SFSQLiteErrorRaiseMethod(CANTOPEN_ISDIR) +SFSQLiteErrorRaiseMethod(CANTOPEN_FULLPATH) +SFSQLiteErrorRaiseMethod(CANTOPEN_CONVPATH) +SFSQLiteErrorRaiseMethod(CORRUPT_VTAB) +SFSQLiteErrorRaiseMethod(READONLY_RECOVERY) +SFSQLiteErrorRaiseMethod(READONLY_CANTLOCK) +SFSQLiteErrorRaiseMethod(READONLY_ROLLBACK) +SFSQLiteErrorRaiseMethod(READONLY_DBMOVED) +SFSQLiteErrorRaiseMethod(ABORT_ROLLBACK) +SFSQLiteErrorRaiseMethod(CONSTRAINT_CHECK) +SFSQLiteErrorRaiseMethod(CONSTRAINT_COMMITHOOK) +SFSQLiteErrorRaiseMethod(CONSTRAINT_FOREIGNKEY) +SFSQLiteErrorRaiseMethod(CONSTRAINT_FUNCTION) +SFSQLiteErrorRaiseMethod(CONSTRAINT_NOTNULL) +SFSQLiteErrorRaiseMethod(CONSTRAINT_PRIMARYKEY) +SFSQLiteErrorRaiseMethod(CONSTRAINT_TRIGGER) +SFSQLiteErrorRaiseMethod(CONSTRAINT_UNIQUE) +SFSQLiteErrorRaiseMethod(CONSTRAINT_VTAB) +SFSQLiteErrorRaiseMethod(CONSTRAINT_ROWID) +SFSQLiteErrorRaiseMethod(NOTICE_RECOVER_WAL) +SFSQLiteErrorRaiseMethod(NOTICE_RECOVER_ROLLBACK) + ++ (void)raise:(NSString *)reason code:(int)code extended:(int)extended { + switch(extended) { + SFSQLiteErrorCase(IOERR_READ); + SFSQLiteErrorCase(IOERR_SHORT_READ); + SFSQLiteErrorCase(IOERR_WRITE); + SFSQLiteErrorCase(IOERR_FSYNC); + SFSQLiteErrorCase(IOERR_DIR_FSYNC); + SFSQLiteErrorCase(IOERR_TRUNCATE); + SFSQLiteErrorCase(IOERR_FSTAT); + SFSQLiteErrorCase(IOERR_UNLOCK); + SFSQLiteErrorCase(IOERR_RDLOCK); + SFSQLiteErrorCase(IOERR_DELETE); + SFSQLiteErrorCase(IOERR_BLOCKED); + SFSQLiteErrorCase(IOERR_NOMEM); + SFSQLiteErrorCase(IOERR_ACCESS); + SFSQLiteErrorCase(IOERR_CHECKRESERVEDLOCK); + SFSQLiteErrorCase(IOERR_LOCK); + SFSQLiteErrorCase(IOERR_CLOSE); + SFSQLiteErrorCase(IOERR_DIR_CLOSE); + SFSQLiteErrorCase(IOERR_SHMOPEN); + SFSQLiteErrorCase(IOERR_SHMSIZE); + SFSQLiteErrorCase(IOERR_SHMLOCK); + SFSQLiteErrorCase(IOERR_SHMMAP); + SFSQLiteErrorCase(IOERR_SEEK); + SFSQLiteErrorCase(IOERR_DELETE_NOENT); + SFSQLiteErrorCase(IOERR_MMAP); + SFSQLiteErrorCase(IOERR_GETTEMPPATH); + SFSQLiteErrorCase(IOERR_CONVPATH); + SFSQLiteErrorCase(LOCKED_SHAREDCACHE); + SFSQLiteErrorCase(BUSY_RECOVERY); + SFSQLiteErrorCase(BUSY_SNAPSHOT); + SFSQLiteErrorCase(CANTOPEN_NOTEMPDIR); + SFSQLiteErrorCase(CANTOPEN_ISDIR); + SFSQLiteErrorCase(CANTOPEN_FULLPATH); + SFSQLiteErrorCase(CANTOPEN_CONVPATH); + SFSQLiteErrorCase(CORRUPT_VTAB); + SFSQLiteErrorCase(READONLY_RECOVERY); + SFSQLiteErrorCase(READONLY_CANTLOCK); + SFSQLiteErrorCase(READONLY_ROLLBACK); + SFSQLiteErrorCase(READONLY_DBMOVED); + SFSQLiteErrorCase(ABORT_ROLLBACK); + SFSQLiteErrorCase(CONSTRAINT_CHECK); + SFSQLiteErrorCase(CONSTRAINT_COMMITHOOK); + SFSQLiteErrorCase(CONSTRAINT_FOREIGNKEY); + SFSQLiteErrorCase(CONSTRAINT_FUNCTION); + SFSQLiteErrorCase(CONSTRAINT_NOTNULL); + SFSQLiteErrorCase(CONSTRAINT_PRIMARYKEY); + SFSQLiteErrorCase(CONSTRAINT_TRIGGER); + SFSQLiteErrorCase(CONSTRAINT_UNIQUE); + SFSQLiteErrorCase(CONSTRAINT_VTAB); + SFSQLiteErrorCase(CONSTRAINT_ROWID); + SFSQLiteErrorCase(NOTICE_RECOVER_WAL); + SFSQLiteErrorCase(NOTICE_RECOVER_ROLLBACK); + default: break; + } + switch(code) { + SFSQLiteErrorCase(ERROR); + SFSQLiteErrorCase(INTERNAL); + SFSQLiteErrorCase(PERM); + SFSQLiteErrorCase(ABORT); + SFSQLiteErrorCase(BUSY); + SFSQLiteErrorCase(LOCKED); + SFSQLiteErrorCase(NOMEM); + SFSQLiteErrorCase(READONLY); + SFSQLiteErrorCase(INTERRUPT); + SFSQLiteErrorCase(IOERR); + SFSQLiteErrorCase(CORRUPT); + SFSQLiteErrorCase(NOTFOUND); + SFSQLiteErrorCase(FULL); + SFSQLiteErrorCase(CANTOPEN); + SFSQLiteErrorCase(PROTOCOL); + SFSQLiteErrorCase(SCHEMA); + SFSQLiteErrorCase(TOOBIG); + SFSQLiteErrorCase(CONSTRAINT); + SFSQLiteErrorCase(MISMATCH); + SFSQLiteErrorCase(MISUSE); + SFSQLiteErrorCase(RANGE); + SFSQLiteErrorCase(NOTADB); + default: break; + } + [NSException raise:NSGenericException format:@"%@", reason]; +} + +@end diff --git a/Analytics/SQLite/SFSQLiteStatement.h b/Analytics/SQLite/SFSQLiteStatement.h new file mode 100644 index 00000000..15ddb278 --- /dev/null +++ b/Analytics/SQLite/SFSQLiteStatement.h @@ -0,0 +1,72 @@ +/* + * 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 +#import + +@class SFSQLite; + +@interface SFSQLiteStatement : NSObject { + __weak SFSQLite* _SQLite; + NSString* _SQL; + sqlite3_stmt* _handle; + BOOL _reset; + NSMutableArray* _temporaryBoundObjects; +} + +- (id)initWithSQLite:(SFSQLite *)SQLite SQL:(NSString *)SQL handle:(sqlite3_stmt *)handle; + +@property (nonatomic, readonly, weak) SFSQLite *SQLite; +@property (nonatomic, readonly, strong) NSString *SQL; +@property (nonatomic, readonly, assign) sqlite3_stmt *handle; + +@property (nonatomic, assign, getter=isReset) BOOL reset; + +- (BOOL)step; +- (void)reset; + +- (void)finalizeStatement; + +- (void)bindInt:(SInt32)value atIndex:(NSUInteger)index; +- (void)bindInt64:(SInt64)value atIndex:(NSUInteger)index; +- (void)bindDouble:(double)value atIndex:(NSUInteger)index; +- (void)bindBlob:(NSData *)value atIndex:(NSUInteger)index; +- (void)bindText:(NSString *)value atIndex:(NSUInteger)index; +- (void)bindNullAtIndex:(NSUInteger)index; +- (void)bindValue:(id)value atIndex:(NSUInteger)index; +- (void)bindValues:(NSArray *)values; + +- (NSUInteger)columnCount; +- (int)columnTypeAtIndex:(NSUInteger)index; +- (NSString *)columnNameAtIndex:(NSUInteger)index; + +- (SInt32)intAtIndex:(NSUInteger)index; +- (SInt64)int64AtIndex:(NSUInteger)index; +- (double)doubleAtIndex:(NSUInteger)index; +- (NSData *)blobAtIndex:(NSUInteger)index; +- (NSString *)textAtIndex:(NSUInteger)index; +- (id)objectAtIndex:(NSUInteger)index; +- (NSArray *)allObjects; +- (NSDictionary *)allObjectsByColumnName; + +@end diff --git a/Analytics/SQLite/SFSQLiteStatement.m b/Analytics/SQLite/SFSQLiteStatement.m new file mode 100644 index 00000000..c8de43a8 --- /dev/null +++ b/Analytics/SQLite/SFSQLiteStatement.m @@ -0,0 +1,319 @@ +/* + * 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 "SFSQLite.h" +#import "SFSQLiteStatement.h" +#import "SFObjCType.h" + +@interface SFSQLiteStatement () +@property (nonatomic, strong) NSMutableArray *temporaryBoundObjects; +@end +@implementation SFSQLiteStatement + +@synthesize SQLite = _SQLite; +@synthesize SQL = _SQL; +@synthesize handle = _handle; +@synthesize reset = _reset; +@synthesize temporaryBoundObjects = _temporaryBoundObjects; + +- (id)initWithSQLite:(SFSQLite *)SQLite SQL:(NSString *)SQL handle:(sqlite3_stmt *)handle { + if ((self = [super init])) { + _SQLite = SQLite; + _SQL = SQL; + _handle = handle; + _reset = YES; + } + return self; +} + +- (void)finalizeStatement { + SFSQLite *strongSQLite = _SQLite; + + if (!_reset) { + [strongSQLite raise: @"Statement not reset after last use: \"%@\"", _SQL]; + } + if (sqlite3_finalize(_handle)) { + [strongSQLite raise:@"Error finalizing prepared statement: \"%@\"", _SQL]; + } +} + +- (void)resetAfterStepError +{ + if (!_reset) { + (void)sqlite3_reset(_handle); // we expect this to return an error + (void)sqlite3_clear_bindings(_handle); + [_temporaryBoundObjects removeAllObjects]; + _reset = YES; + } +} + +- (BOOL)step { + if (_reset) { + _reset = NO; + } + + int rc = sqlite3_step(_handle); + if ((rc & 0x00FF) == SQLITE_ROW) { + return YES; + } else if ((rc & 0x00FF) == SQLITE_DONE) { + return NO; + } else { + [self resetAfterStepError]; + [_SQLite raise:@"Failed to step (%d): \"%@\"", rc, _SQL]; + return NO; + } +} + +- (void)reset { + SFSQLite *strongSQLite = _SQLite; + + if (!_reset) { + if (sqlite3_reset(_handle)) { + [strongSQLite raise:@"Error resetting prepared statement: \"%@\"", _SQL]; + } + + if (sqlite3_clear_bindings(_handle)) { + [strongSQLite raise:@"Error clearing prepared statement bindings: \"%@\"", _SQL]; + } + [_temporaryBoundObjects removeAllObjects]; + _reset = YES; + } +} + +- (void)bindInt:(SInt32)value atIndex:(NSUInteger)index { + NSAssert(_reset, @"Statement is not reset: \"%@\"", _SQL); + + if (sqlite3_bind_int(_handle, (int)index+1, value)) { + [_SQLite raise:@"Error binding int at %ld: \"%@\"", (unsigned long)index, _SQL]; + } +} + +- (void)bindInt64:(SInt64)value atIndex:(NSUInteger)index { + NSAssert(_reset, @"Statement is not reset: \"%@\"", _SQL); + + if (sqlite3_bind_int64(_handle, (int)index+1, value)) { + [_SQLite raise:@"Error binding int64 at %ld: \"%@\"", (unsigned long)index, _SQL]; + } +} + +- (void)bindDouble:(double)value atIndex:(NSUInteger)index { + NSAssert(_reset, @"Statement is not reset: \"%@\"", _SQL); + + if (sqlite3_bind_double(_handle, (int)index+1, value)) { + [_SQLite raise:@"Error binding double at %ld: \"%@\"", (unsigned long)index, _SQL]; + } +} + +- (void)bindBlob:(NSData *)value atIndex:(NSUInteger)index { + NSAssert(_reset, @"Statement is not reset: \"%@\"", _SQL); + + if (value) { + NS_VALID_UNTIL_END_OF_SCOPE NSData *arcSafeValue = value; + if (sqlite3_bind_blob(_handle, (int)index+1, [arcSafeValue bytes], (int)[arcSafeValue length], NULL)) { + [_SQLite raise:@"Error binding blob at %ld: \"%@\"", (unsigned long)index, _SQL]; + } + } else { + [self bindNullAtIndex:index]; + } +} + +- (void)bindText:(NSString *)value atIndex:(NSUInteger)index { + NSAssert(_reset, @"Statement is not reset: \"%@\"", _SQL); + + if (value) { + NS_VALID_UNTIL_END_OF_SCOPE NSString *arcSafeValue = value; + if (sqlite3_bind_text(_handle, (int)index+1, [arcSafeValue UTF8String], -1, NULL)) { + [_SQLite raise:@"Error binding text at %ld: \"%@\"", (unsigned long)index, _SQL]; + } + } else { + [self bindNullAtIndex:index]; + } +} + +- (void)bindNullAtIndex:(NSUInteger)index { + int rc = sqlite3_bind_null(_handle, (int)index+1); + if ((rc & 0x00FF) != SQLITE_OK) { + [_SQLite raise:@"sqlite3_bind_null error"]; + } +} + +- (id)retainedTemporaryBoundObject:(id)object +{ + if (!_temporaryBoundObjects) { + _temporaryBoundObjects = [NSMutableArray new]; + } + [_temporaryBoundObjects addObject:object]; + return object; +} + +- (void)bindValue:(id)value atIndex:(NSUInteger)index { + if ([value isKindOfClass:[NSNumber class]]) { + SFObjCType *type = [SFObjCType typeForValue:value]; + if (type.isIntegerNumber) { + if (type.size <= 4) { + [self bindInt:[value intValue] atIndex:index]; + } else { + [self bindInt64:[value longLongValue] atIndex:index]; + } + } else { + NSAssert(type.isFloatingPointNumber, @"Expected number type to be either integer or floating point"); + if (type.code == SFObjCTypeFloat) { + [self bindInt:[value intValue] atIndex:index]; + } else { + NSAssert(type.code == SFObjCTypeDouble, @"Unexpected floating point number type: %@", type); + [self bindInt64:[value longLongValue] atIndex:index]; + } + } + } else if ([value isKindOfClass:[NSData class]]) { + [self bindBlob:value atIndex:index]; + } else if ([value isKindOfClass:[NSUUID class]]) { + uuid_t uuid; + [(NSUUID *)value getUUIDBytes:uuid]; + [self bindBlob:[self retainedTemporaryBoundObject:[NSData dataWithBytes:uuid length:sizeof(uuid_t)]] atIndex:index]; + } else if ([value isKindOfClass:[NSString class]]) { + [self bindText:value atIndex:index]; + } else if ([value isKindOfClass:[NSNull class]]) { + [self bindNullAtIndex:index]; + } else if ([value isKindOfClass:[NSDate class]]) { + [self bindDouble:[(NSDate *)value timeIntervalSinceReferenceDate] atIndex:index]; + } else if ([value isKindOfClass:[NSError class]]) { + [self bindBlob:[self retainedTemporaryBoundObject:[NSKeyedArchiver archivedDataWithRootObject:value]] atIndex:index]; + } else if ([value isKindOfClass:[NSURL class]]) { + [self bindText:[self retainedTemporaryBoundObject:[value absoluteString]] atIndex:index]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Can't bind object of type %@", [value class]]; + } +} + +- (void)bindValues:(NSArray *)values { + for (NSUInteger i = 0; i < values.count; i++) { + [self bindValue:values[i] atIndex:i]; + } +} + +- (NSUInteger)columnCount { + NSAssert(!_reset, @"Statement is reset: \"%@\"", _SQL); + + return sqlite3_column_count(_handle); +} + +- (int)columnTypeAtIndex:(NSUInteger)index { + NSAssert(!_reset, @"Statement is reset: \"%@\"", _SQL); + + return sqlite3_column_type(_handle, (int)index); +} + +- (NSString *)columnNameAtIndex:(NSUInteger)index { + NSAssert(!_reset, @"Statement is reset: \"%@\"", _SQL); + + return @(sqlite3_column_name(_handle, (int)index)); +} + +- (SInt32)intAtIndex:(NSUInteger)index { + NSAssert(!_reset, @"Statement is reset: \"%@\"", _SQL); + + return sqlite3_column_int(_handle, (int)index); +} + +- (SInt64)int64AtIndex:(NSUInteger)index { + NSAssert(!_reset, @"Statement is reset: \"%@\"", _SQL); + + return sqlite3_column_int64(_handle, (int)index); +} + +- (double)doubleAtIndex:(NSUInteger)index { + NSAssert(!_reset, @"Statement is reset: \"%@\"", _SQL); + + return sqlite3_column_double(_handle, (int)index); +} + +- (NSData *)blobAtIndex:(NSUInteger)index { + NSAssert(!_reset, @"Statement is reset: \"%@\"", _SQL); + + const void *bytes = sqlite3_column_blob(_handle, (int)index); + if (bytes) { + int length = sqlite3_column_bytes(_handle, (int)index); + return [NSData dataWithBytes:bytes length:length]; + } else { + return nil; + } +} + +- (NSString *)textAtIndex:(NSUInteger)index { + NSAssert(!_reset, @"Statement is reset: \"%@\"", _SQL); + + const char *text = (const char *)sqlite3_column_text(_handle, (int)index); + if (text) { + return @(text); + } else { + return nil; + } +} + +- (id)objectAtIndex:(NSUInteger)index { + int type = [self columnTypeAtIndex:index]; + switch (type) { + case SQLITE_INTEGER: + return @([self int64AtIndex:index]); + + case SQLITE_FLOAT: + return @([self doubleAtIndex:index]); + + case SQLITE_TEXT: + return [self textAtIndex:index]; + + case SQLITE_BLOB: + return [self blobAtIndex:index]; + + case SQLITE_NULL: + return nil; + + default: + [NSException raise:NSGenericException format:@"Unexpected column type: %d", type]; + return nil; + } +} + +- (NSArray *)allObjects { + NSUInteger columnCount = [self columnCount]; + NSMutableArray *objects = [NSMutableArray arrayWithCapacity:columnCount]; + for (NSUInteger i = 0; i < columnCount; i++) { + objects[i] = [self objectAtIndex:i] ?: [NSNull null]; + } + return objects; +} + +- (NSDictionary *)allObjectsByColumnName { + NSUInteger columnCount = [self columnCount]; + NSMutableDictionary *objectsByColumnName = [NSMutableDictionary dictionaryWithCapacity:columnCount]; + for (NSUInteger i = 0; i < columnCount; i++) { + NSString *columnName = [self columnNameAtIndex:i]; + id object = [self objectAtIndex:i]; + if (object) { + objectsByColumnName[columnName] = object; + } + } + return objectsByColumnName; +} + +@end diff --git a/CircleJoinRequested/CircleJoinRequested.m b/CircleJoinRequested/CircleJoinRequested.m index 2664efd7..d6942e57 100644 --- a/CircleJoinRequested/CircleJoinRequested.m +++ b/CircleJoinRequested/CircleJoinRequested.m @@ -1,10 +1,26 @@ -// -// CircleJoinRequested.m -// CircleJoinRequested -// -// Created by J Osborne on 3/5/13. -// Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. -// +/* + * Copyright (c) 2013-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 #import #import @@ -47,6 +63,7 @@ #import "CoreCDP/CDPFollowUpController.h" #import "CoreCDP/CDPFollowUpContext.h" +#import // As long as we are logging the failure use exit code of zero to make launchd happy #define EXIT_LOGGED_FAILURE(code) xpc_transaction_end(); exit(0) @@ -62,12 +79,31 @@ dispatch_block_t doOnceInMainBlockChain = NULL; bool _isLocked = true; bool processApplicantsAfterUnlock = false; bool _unlockedSinceBoot = false; +bool _hasPostedFollowupAndStillInError = false; +bool _isAccountICDP = false; + -NSString *castleKeychainUrl = @"prefs:root=CASTLE&path=Keychain/ADVANCED"; -NSString *rejoinICDPUrl = @"prefs:root=CASTLE&aaaction=CDP&command=rejoin"; +NSString *castleKeychainUrl = @"prefs:root=APPLE_ACCOUNT&path=ICLOUD_SERVICE/com.apple.Dataclass.KeychainSync/ADVANCED"; +NSString *rejoinICDPUrl = @"prefs:root=APPLE_ACCOUNT&aaaction=CDP&command=rejoin"; BOOL processRequests(CFErrorRef *error); +static void PSKeychainSyncIsUsingICDP(void) +{ + ACAccountStore *accountStore = [[ACAccountStore alloc] init]; + ACAccount *account = [accountStore aa_primaryAppleAccount]; + NSString *dsid = account.accountProperties[@"personID"]; + BOOL isICDPEnabled = NO; + if (dsid) { + isICDPEnabled = [CDPAccount isICDPEnabledForDSID:dsid]; + NSLog(@"iCDP: PSKeychainSyncIsUsingICDP returning %@", isICDPEnabled ? @"TRUE" : @"FALSE"); + } else { + NSLog(@"iCDP: no primary account"); + } + + _isAccountICDP = isICDPEnabled; + secnotice("cjr", "account is icdp: %d", _isAccountICDP); +} static void keybagDidLock() { @@ -84,7 +120,28 @@ static void keybagDidUnlock() processRequests(&error); processApplicantsAfterUnlock = false; } - + + SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(&error); + if(_isAccountICDP && (circleStatus == kSOSCCError || circleStatus == kSOSCCCircleAbsent || circleStatus == kSOSCCNotInCircle) && _hasPostedFollowupAndStillInError == false){ + NSError *localError = nil; + CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair]; + CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; + [cdpd postFollowUpWithContext:context error:&localError ]; + secnotice("cjr", "account is icdp"); + if(localError){ + secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError); + } + else{ + secnotice("cjr", "CoreCDP handling follow up"); + _hasPostedFollowupAndStillInError = true; + } + } + else if(_isAccountICDP && circleStatus == kSOSCCInCircle){ + _hasPostedFollowupAndStillInError = false; + } + else{ + secnotice("cjr", "account not icdp"); + } } static bool updateIsLocked () @@ -305,7 +362,10 @@ static void applicantChoice(CFUserNotificationRef userNotification, CFOptionFlag static void passwordFailurePrompt() { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" NSString *pwIncorrect = [NSString stringWithFormat:(NSString *)CFBridgingRelease(SecCopyCKString(SEC_CK_PASSWORD_INCORRECT)), appleIDAccountName()]; +#pragma clang diagnostic pop NSString *tryAgain = CFBridgingRelease(SecCopyCKString(SEC_CK_TRY_AGAIN)); NSDictionary *noteAttributes = @{ (id) kCFUserNotificationAlertHeaderKey : pwIncorrect, @@ -348,14 +408,17 @@ static NSDictionary *createNote(Applicant *applicantToAskAbout) if(!applicantToAskAbout || !applicantToAskAbout.name || !applicantToAskAbout.deviceType) return NULL; - NSString *header = [NSString stringWithFormat: (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_APPROVAL_TITLE_IOS), applicantToAskAbout.name]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" + NSString *header = [NSString stringWithFormat: (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_APPROVAL_TITLE), applicantToAskAbout.name]; NSString *body = [NSString stringWithFormat: getLocalizedApprovalBody(applicantToAskAbout.deviceType), appleIDAccountName()]; +#pragma clang diagnostic pop return @{ (id) kCFUserNotificationAlertHeaderKey : header, (id) kCFUserNotificationAlertMessageKey : body, - (id) kCFUserNotificationDefaultButtonTitleKey : (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_ALLOW), - (id) kCFUserNotificationAlternateButtonTitleKey: (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_DONT_ALLOW), + (id) kCFUserNotificationDefaultButtonTitleKey : (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_APPROVE), + (id) kCFUserNotificationAlternateButtonTitleKey: (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_DECLINE), (id) kCFUserNotificationTextFieldTitlesKey : (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_ICLOUD_PASSWORD), (id) kCFUserNotificationAlertTopMostKey : @YES, // get us onto the lock screen (__bridge_transfer id) SBUserNotificationDontDismissOnUnlock: @YES, @@ -525,21 +588,9 @@ static void kickOutChoice(CFUserNotificationRef userNotification, CFOptionFlags if (responseFlags == kCFUserNotificationDefaultResponse) { // We need to let things unwind to main for the new state to get saved doOnceInMain(^{ - ACAccountStore *store = [ACAccountStore new]; - ACAccount *primary = [store aa_primaryAppleAccount]; - NSString *dsid = [primary aa_personID]; - bool localICDP = false; - if (dsid) { - NSDictionary *options = @{ (__bridge id) kPCSSetupDSID : dsid, }; - PCSIdentitySetRef identity = PCSIdentitySetCreate((__bridge CFDictionaryRef) options, NULL, NULL); - - if (identity) { - localICDP = PCSIdentitySetIsICDP(identity, NULL); - CFRelease(identity); - } - } - NSURL *url = [NSURL URLWithString: localICDP ? rejoinICDPUrl : castleKeychainUrl]; + NSURL *url = [NSURL URLWithString: _isAccountICDP ? rejoinICDPUrl : castleKeychainUrl]; BOOL ok = [[LSApplicationWorkspace defaultWorkspace] openSensitiveURL:url withOptions:nil]; + secnotice("cjr","kickOutChoice account is iCDP: %d", _isAccountICDP); secnotice("cjr", "ok=%d opening %@", ok, url); }); } @@ -547,29 +598,18 @@ static void kickOutChoice(CFUserNotificationRef userNotification, CFOptionFlags else if (responseFlags == kCFUserNotificationAlternateResponse) { // We need to let things unwind to main for the new state to get saved doOnceInMain(^{ - CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; - ACAccountStore *store = [ACAccountStore new]; - ACAccount *primary = [store aa_primaryAppleAccount]; - NSString *dsid = [primary aa_personID]; - bool localICDP = false; - if (dsid) { - NSDictionary *options = @{ (__bridge id) kPCSSetupDSID : dsid, }; - PCSIdentitySetRef identity = PCSIdentitySetCreate((__bridge CFDictionaryRef) options, NULL, NULL); - - if (identity) { - localICDP = PCSIdentitySetIsICDP(identity, NULL); - CFRelease(identity); - } - } - if(localICDP){ + if(_isAccountICDP){ + CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; NSError *localError = nil; CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair]; [cdpd postFollowUpWithContext:context error:&localError ]; if(localError){ secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError); } - else + else{ secnotice("cjr", "CoreCDP handling follow up"); + _hasPostedFollowupAndStillInError = true; + } } }); @@ -643,8 +683,11 @@ static void postKickedOutAlert(enum DepartureReason reason) "unknown reason" }; int idx = (kSOSDepartureReasonError <= reason && reason <= kSOSLostPrivateKey) ? reason : (kSOSLostPrivateKey + 1); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" NSString *reason_str = [NSString stringWithFormat:(__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CR_REASON_INTERNAL), departureReasonStrings[idx]]; +#pragma clang diagnostic pop message = [message stringByAppendingString: reason_str]; } @@ -722,19 +765,57 @@ static bool processEvents() scheduleActivity(ceil(timeUntilApplicationAlert)); } } - - if(circleStatus == kSOSCCError && state.lastCircleStatus != kSOSCCError && (departureReason == kSOSNeverLeftCircle)) { - secnotice("cjr", "error from SOSCCThisDeviceIsInCircle: %@", error); + + PSKeychainSyncIsUsingICDP(); + + if(_isAccountICDP){ + if((circleStatus == kSOSCCError || circleStatus == kSOSCCCircleAbsent || circleStatus == kSOSCCNotInCircle) && _hasPostedFollowupAndStillInError == false) { + secnotice("cjr", "error from SOSCCThisDeviceIsInCircle: %@", error); + secnotice("cjr", "iCDP: We need to get back into the circle"); + doOnceInMain(^{ + if(_isAccountICDP){ + NSError *localError = nil; + CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; + CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair]; + [cdpd postFollowUpWithContext:context error:&localError ]; + if(localError){ + secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError); + } + else{ + secnotice("cjr", "CoreCDP handling follow up"); + _hasPostedFollowupAndStillInError = true; + } + } + else{ + postKickedOutAlert(kSOSPasswordChanged); + state.lastCircleStatus = kSOSCCError; + [state writeToStorage]; + } + }); + state.lastCircleStatus = circleStatus; + return false; + } + else if(circleStatus == kSOSCCInCircle){ + secnotice("cjr", "follow up should be resolved"); + _hasPostedFollowupAndStillInError = false; + } + else{ + secnotice("cjr", "followup not resolved"); + return false; + } + } + else if(circleStatus == kSOSCCError && state.lastCircleStatus != kSOSCCError && (departureReason == kSOSNeverLeftCircle) + && !_isAccountICDP) { + secnotice("cjr", "SA: error from SOSCCThisDeviceIsInCircle: %@", error); CFIndex errorCode = CFErrorGetCode(error); if(errorCode == kSOSErrorPublicKeyAbsent){ - secnotice("cjr", "We need the password to re-validate ourselves - it's changed on another device"); + secnotice("cjr", "SA: We need the password to re-validate ourselves - it's changed on another device"); postKickedOutAlert(kSOSPasswordChanged); state.lastCircleStatus = kSOSCCError; [state writeToStorage]; return true; } } - // No longer in circle? if ((state.lastCircleStatus == kSOSCCInCircle && (circleStatus == kSOSCCNotInCircle || circleStatus == kSOSCCCircleAbsent)) || (state.lastCircleStatus == kSOSCCCircleAbsent && circleStatus == kSOSCCNotInCircle && state.absentCircleWithNoReason) || @@ -753,7 +834,26 @@ static bool processEvents() if (departureReason != kSOSDepartureReasonError) { state.absentCircleWithNoReason = (circleStatus == kSOSCCCircleAbsent && departureReason == kSOSNeverLeftCircle); secnotice("cjr", "Depature reason %d", departureReason); - postKickedOutAlert(departureReason); + if(!_isAccountICDP){ + secnotice("cjr", "posting revocation notification!"); + postKickedOutAlert(departureReason); + } + else if(_isAccountICDP && _hasPostedFollowupAndStillInError == false){ + NSError *localError = nil; + CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; + CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair]; + [cdpd postFollowUpWithContext:context error:&localError ]; + if(localError){ + secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError); + } + else{ + secnotice("cjr", "CoreCDP handling follow up"); + _hasPostedFollowupAndStillInError = true; + } + } + else{ + secnotice("cjr", "still waiting for followup to resolve"); + } secnotice("cjr", "pKOA returned (cS %d lCS %d)", circleStatus, state.lastCircleStatus); } else { secnotice("cjr", "Couldn't get last departure reason: %@", departError); diff --git a/CircleJoinRequested/com.apple.security.CircleJoinRequested.plist b/CircleJoinRequested/com.apple.security.CircleJoinRequested.plist index 72e08d7f..38d478a8 100644 --- a/CircleJoinRequested/com.apple.security.CircleJoinRequested.plist +++ b/CircleJoinRequested/com.apple.security.CircleJoinRequested.plist @@ -16,6 +16,11 @@ com.apple.notifyd.matching + kPublicKeyAvailable + + Notification + com.apple.security.publickeyavailable + com.apple.mobile.keybagd.lock_status Notification diff --git a/Forwarding Headers/SOSCloudCircle.h b/Forwarding Headers/SOSCloudCircle.h deleted file mode 100644 index 077b1d9e..00000000 --- a/Forwarding Headers/SOSCloudCircle.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// Forward to the proper location -// This header is temporary until deprecation can be accomplished -// -// SOSCloudCircle.h was erroneously put directly in PrivateHeaders. -// This header forwards for clients who adopted that location. -// -// Warning and removing this file left to the future -// - -#include diff --git a/Forwarding Headers/SOSPeerInfo.h b/Forwarding Headers/SOSPeerInfo.h deleted file mode 100644 index 29b81a5a..00000000 --- a/Forwarding Headers/SOSPeerInfo.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// Forward to the proper location -// This header is temporary until deprecation can be accomplished -// -// SOSPeerInfo.h was erroneously put directly in PrivateHeaders. -// This header forwards for clients who adopted that location. -// -// Warning and removing this file left to the future -// - -#include diff --git a/KVSKeychainSyncingProxy/CKDAKSLockMonitor.m b/KVSKeychainSyncingProxy/CKDAKSLockMonitor.m index 328d96a4..8686852b 100644 --- a/KVSKeychainSyncingProxy/CKDAKSLockMonitor.m +++ b/KVSKeychainSyncingProxy/CKDAKSLockMonitor.m @@ -14,11 +14,13 @@ #include #include +#include @interface CKDAKSLockMonitor () @property XPCNotificationDispatcher* dispatcher; @property XPCNotificationBlock notificationBlock; +@property dispatch_queue_t queue; @end @@ -34,39 +36,56 @@ if (self) { XPCNotificationDispatcher* dispatcher = [XPCNotificationDispatcher dispatcher]; - [dispatcher addListener: self]; + _queue = dispatch_queue_create("CKDAKSLockMonitor", NULL); + _locked = true; + _unlockedSinceBoot = false; - self->_locked = true; - self->_unlockedSinceBoot = false; + /* also use dispatch to make sure */ + int token = 0; + __weak typeof(self) weakSelf = self; + notify_register_dispatch(kUserKeybagStateChangeNotification, &token, _queue, ^(int t) { + [weakSelf _onqueueRecheck]; + }); [self recheck]; + + [dispatcher addListener: self]; } return self; } - (void) handleNotification:(const char *)name { - if (strcmp(name, kUserKeybagStateChangeNotification) == 0) { + if (strcmp(name, kUserKeybagStateChangeNotification) == 0 || strcmp(name, "com.apple.mobile.keybagd.lock_status") == 0) { [self recheck]; } } - (void) notifyListener { - if (self.listener) { + // Take a strong reference: + __strong __typeof(self.listener) listener = self.listener; + + if (listener) { if (self.locked) { - [self.listener locked]; + [listener locked]; } else { - [self.listener unlocked]; + [listener unlocked]; } } } - (void)connectTo: (NSObject*) listener { - self->_listener = listener; + _listener = listener; [self notifyListener]; } - (void) recheck { + dispatch_async(_queue, ^{ + [self _onqueueRecheck]; + }); +} + +- (void) _onqueueRecheck { CFErrorRef aksError = NULL; bool locked = true; // Assume locked if we get an error @@ -76,10 +95,10 @@ } BOOL previousLocked = self.locked; - self->_locked = locked; + _locked = locked; if (!self.locked) { - self->_unlockedSinceBoot = true; + _unlockedSinceBoot = true; } if (previousLocked != self.locked) { diff --git a/KVSKeychainSyncingProxy/CKDKVSProxy.h b/KVSKeychainSyncingProxy/CKDKVSProxy.h index f776992b..23dc1994 100644 --- a/KVSKeychainSyncingProxy/CKDKVSProxy.h +++ b/KVSKeychainSyncingProxy/CKDKVSProxy.h @@ -140,6 +140,7 @@ typedef void (^FreshnessResponseBlock)(bool success, NSError *err); - (void)processPendingKeysForCurrentLockState; - (void)registerKeys: (NSDictionary*)keys forAccount: (NSString*) accountUUID; +- (void)removeKeys: (NSArray*)keys forAccount: (NSString*) accountUUID; - (void)processKeyChangedEvent:(NSDictionary *)keysChangedInCloud; - (NSMutableDictionary *)copyValues:(NSSet *)keysOfInterest; @@ -148,7 +149,6 @@ typedef void (^FreshnessResponseBlock)(bool success, NSError *err); - (void) calloutWith: (void(^)(NSSet *pending, NSSet* pendingSyncIDs, NSSet* pendingBackupSyncIDs, bool ensurePeerRegistration, dispatch_queue_t queue, void(^done)(NSSet *handledKeys, NSSet *handledSyncs, bool handledEnsurePeerRegistration, NSError* error))) callout; - (void) sendKeysCallout: (NSSet *(^)(NSSet* pending, NSError **error)) handleKeys; -- (void)recordWriteToKVS:(NSDictionary *)values; -- (NSDictionary*)recordHaltedValuesAndReturnValuesToSafelyWrite:(NSDictionary *)values; +- (void)perfCounters:(void(^)(NSDictionary *counters))callback; @end diff --git a/KVSKeychainSyncingProxy/CKDKVSProxy.m b/KVSKeychainSyncingProxy/CKDKVSProxy.m index 79839ce1..9b74ef60 100644 --- a/KVSKeychainSyncingProxy/CKDKVSProxy.m +++ b/KVSKeychainSyncingProxy/CKDKVSProxy.m @@ -39,14 +39,35 @@ #include #include +#include #include "SOSCloudKeychainConstants.h" #include #include - +#include #import "XPCNotificationDispatcher.h" + +CFStringRef const CKDAggdIncreaseThrottlingKey = CFSTR("com.apple.cloudkeychainproxy.backoff.increase"); +CFStringRef const CKDAggdDecreaseThrottlingKey = CFSTR("com.apple.cloudkeychainproxy.backoff.decrease"); + +@interface NSSet (CKDLogging) +- (NSString*) logKeys; +- (NSString*) logIDs; +@end + +@implementation NSSet (CKDLogging) +- (NSString*) logKeys { + return [self sortedElementsJoinedByString:@" "]; +} + +- (NSString*) logIDs { + return [self sortedElementsTruncated:8 JoinedByString:@" "]; +} +@end + + /* The total space available in your app’s iCloud key-value storage is 1 MB. The maximum number of keys you can specify is 1024, and the size limit for @@ -99,119 +120,6 @@ const CFStringRef kSOSKVSOfficialDSIDKey = CFSTR("^OfficialDSID"); #define kSecServerKeychainChangedNotification "com.apple.security.keychainchanged" -static int max_penalty_timeout = 32; -static int seconds_per_minute = 60; - -static const int64_t kSyncTimerLeeway = (NSEC_PER_MSEC * 250); // 250ms leeway for sync events. - -static NSString* asNSString(NSObject* object) { - return [object isKindOfClass:[NSString class]] ? (NSString*) object : nil; -} - -@interface NSMutableDictionary (FindAndRemove) --(NSObject*)extractObjectForKey:(NSString*)key; -@end - -@implementation NSMutableDictionary (FindAndRemove) --(NSObject*)extractObjectForKey:(NSString*)key -{ - NSObject* result = [self objectForKey:key]; - [self removeObjectForKey: key]; - return result; -} -@end - -@interface NSSet (Emptiness) -- (bool) isEmpty; -@end - -@implementation NSSet (Emptiness) -- (bool) isEmpty -{ - return [self count] == 0; -} -@end - -@interface NSSet (HasElements) -- (bool) containsElementsNotIn: (NSSet*) other; -@end - -@implementation NSSet (HasElements) -- (bool) containsElementsNotIn: (NSSet*) other -{ - __block bool hasElements = false; - [self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { - if (![other containsObject:obj]) { - hasElements = true; - *stop = true; - } - }]; - return hasElements; -} - -@end - -@implementation NSSet (Stringizing) -- (NSString*) sortedElementsJoinedByString: (NSString*) separator { - return [self sortedElementsTruncated: 0 JoinedByString: separator]; -} - -- (NSString*) sortedElementsTruncated: (NSUInteger) length JoinedByString: (NSString*) separator -{ - NSMutableArray* strings = [NSMutableArray array]; - - [self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { - NSString *stringToInsert = nil; - if ([obj isNSString__]) { - stringToInsert = obj; - } else { - stringToInsert = [obj description]; - } - - if (length > 0 && length < stringToInsert.length) { - stringToInsert = [stringToInsert substringToIndex:length]; - } - - [strings insertObject:stringToInsert atIndex:0]; - }]; - - [strings sortUsingSelector: @selector(compare:)]; - - return [strings componentsJoinedByString:separator]; -} -@end - -@implementation NSSet (CKDLogging) -- (NSString*) logKeys { - return [self sortedElementsJoinedByString:@" "]; -} - -- (NSString*) logIDs { - return [self sortedElementsTruncated:8 JoinedByString:@" "]; -} -@end - - -@interface NSDictionary (SOSDictionaryFormat) -- (NSString*) compactDescription; -@end - -@implementation NSDictionary (SOSDictionaryFormat) -- (NSString*) compactDescription -{ - NSMutableArray *elements = [NSMutableArray array]; - [self enumerateKeysAndObjectsUsingBlock: ^(NSString *key, id obj, BOOL *stop) { - [elements addObject: [key stringByAppendingString: @":"]]; - if ([obj isKindOfClass:[NSArray class]]) { - [elements addObject: [(NSArray *)obj componentsJoinedByString: @" "]]; - } else { - [elements addObject: [NSString stringWithFormat:@"%@", obj]]; - } - }]; - return [elements componentsJoinedByString: @" "]; -} -@end - @interface UbiqitousKVSProxy () @property (nonatomic) NSDictionary* persistentData; - (void) doSyncWithAllPeers; @@ -403,310 +311,12 @@ static NSString* asNSString(NSObject* object) { } } - -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR -CFStringRef const CKDAggdIncreaseThrottlingKey = CFSTR("com.apple.cloudkeychainproxy.backoff.increase"); -CFStringRef const CKDAggdDecreaseThrottlingKey = CFSTR("com.apple.cloudkeychainproxy.backoff.decrease"); -#endif - -// MARK: Penalty measurement and handling --(dispatch_source_t)setNewTimer:(int)timeout key:(NSString*)key -{ - __block dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _ckdkvsproxy_queue); - dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC * seconds_per_minute), DISPATCH_TIME_FOREVER, kSyncTimerLeeway); - dispatch_source_set_event_handler(timer, ^{ - [self penaltyTimerFired:key]; - }); - dispatch_resume(timer); - return timer; -} - --(void) increasePenalty:(NSNumber*)currentPenalty key:(NSString*)key keyEntry:(NSMutableDictionary**)keyEntry -{ -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR - SecADAddValueForScalarKey(CKDAggdIncreaseThrottlingKey, 1); -#endif - - secnotice("backoff", "increasing penalty!"); - int newPenalty = 0; - if([currentPenalty intValue] == max_penalty_timeout){ - newPenalty = max_penalty_timeout; - } - else if ([currentPenalty intValue] == 0) - newPenalty = 1; - else - newPenalty = [currentPenalty intValue]*2; - - secnotice("backoff", "key %@, waiting %d minutes long to send next messages", key, newPenalty); - - NSNumber* penalty_timeout = [[NSNumber alloc]initWithInt:newPenalty]; - dispatch_source_t existingTimer = [*keyEntry valueForKey:kMonitorPenaltyTimer]; - - if(existingTimer != nil){ - [*keyEntry removeObjectForKey:kMonitorPenaltyTimer]; - dispatch_suspend(existingTimer); - dispatch_source_set_timer(existingTimer,dispatch_time(DISPATCH_TIME_NOW, newPenalty * NSEC_PER_SEC * seconds_per_minute), DISPATCH_TIME_FOREVER, kSyncTimerLeeway); - dispatch_resume(existingTimer); - [*keyEntry setObject:existingTimer forKey:kMonitorPenaltyTimer]; - } - else{ - dispatch_source_t timer = [self setNewTimer:newPenalty key:key]; - [*keyEntry setObject:timer forKey:kMonitorPenaltyTimer]; - } - - [*keyEntry setObject:penalty_timeout forKey:kMonitorPenaltyBoxKey]; - [_monitor setObject:*keyEntry forKey:key]; -} - --(void) decreasePenalty:(NSNumber*)currentPenalty key:(NSString*)key keyEntry:(NSMutableDictionary**)keyEntry +- (void)perfCounters:(void(^)(NSDictionary *counters))callback { -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR - SecADAddValueForScalarKey(CKDAggdDecreaseThrottlingKey, 1); -#endif - - int newPenalty = 0; - secnotice("backoff","decreasing penalty!"); - if([currentPenalty intValue] == 0 || [currentPenalty intValue] == 1) - newPenalty = 0; - else - newPenalty = [currentPenalty intValue]/2; - - secnotice("backoff","key %@, waiting %d minutes long to send next messages", key, newPenalty); - - NSNumber* penalty_timeout = [[NSNumber alloc]initWithInt:newPenalty]; - - dispatch_source_t existingTimer = [*keyEntry valueForKey:kMonitorPenaltyTimer]; - if(existingTimer != nil){ - [*keyEntry removeObjectForKey:kMonitorPenaltyTimer]; - dispatch_suspend(existingTimer); - if(newPenalty != 0){ - dispatch_source_set_timer(existingTimer,dispatch_time(DISPATCH_TIME_NOW, newPenalty * NSEC_PER_SEC * seconds_per_minute), DISPATCH_TIME_FOREVER, kSyncTimerLeeway); - dispatch_resume(existingTimer); - [*keyEntry setObject:existingTimer forKey:kMonitorPenaltyTimer]; - } - else{ - dispatch_resume(existingTimer); - dispatch_source_cancel(existingTimer); - } - } - else{ - if(newPenalty != 0){ - dispatch_source_t timer = [self setNewTimer:newPenalty key:key]; - [*keyEntry setObject:timer forKey:kMonitorPenaltyTimer]; - } - } - - [*keyEntry setObject:penalty_timeout forKey:kMonitorPenaltyBoxKey]; - [_monitor setObject:*keyEntry forKey:key]; - -} - -- (void)penaltyTimerFired:(NSString*)key -{ - secnotice("backoff", "key: %@, !!!!!!!!!!!!!!!!penalty timeout is up!!!!!!!!!!!!", key); - - NSMutableDictionary *keyEntry = [_monitor objectForKey:key]; - NSMutableDictionary *queuedMessages = [keyEntry objectForKey:kMonitorMessageQueue]; - secnotice("backoff","key: %@, queuedMessages: %@", key, queuedMessages); - if(queuedMessages && [queuedMessages count] != 0){ - secnotice("backoff","key: %@, message queue not empty, writing to KVS!", key); - [self setObjectsFromDictionary:queuedMessages]; - [keyEntry setObject:[NSMutableDictionary dictionary] forKey:kMonitorMessageQueue]; - } - - NSNumber *penalty_timeout = [keyEntry valueForKey:kMonitorPenaltyBoxKey]; - secnotice("backoff", "key: %@, current penalty timeout: %@", key, penalty_timeout); - - NSString* didWriteDuringTimeout = [keyEntry objectForKey:kMonitorDidWriteDuringPenalty]; - if( didWriteDuringTimeout && [didWriteDuringTimeout isEqualToString:@"YES"] ) - { - //increase timeout since we wrote during out penalty timeout - [self increasePenalty:penalty_timeout key:key keyEntry:&keyEntry]; - } - else{ - //decrease timeout since we successfully wrote messages out - [self decreasePenalty:penalty_timeout key:key keyEntry:&keyEntry]; - } - - //resetting the check - [keyEntry setObject: @"NO" forKey:kMonitorDidWriteDuringPenalty]; - - //recompute the timetable and number of consecutive writes to KVS - NSMutableDictionary *timetable = [keyEntry valueForKey:kMonitorTimeTable]; - NSNumber *consecutiveWrites = [keyEntry valueForKey:kMonitorConsecutiveWrites]; - [self recordTimestampForAppropriateInterval:&timetable key:key consecutiveWrites:&consecutiveWrites]; - - [keyEntry setObject:consecutiveWrites forKey:kMonitorConsecutiveWrites]; - [keyEntry setObject:timetable forKey:kMonitorTimeTable]; - [_monitor setObject:keyEntry forKey:key]; + /* Collect and merge perf counters from other layers here too */ + [self.store perfCounters:callback]; } --(NSMutableDictionary*)initializeTimeTable:(NSString*)key -{ - NSDate *currentTime = [NSDate date]; - NSMutableDictionary *firstMinute = [NSMutableDictionary dictionaryWithObjectsAndKeys:[currentTime dateByAddingTimeInterval: seconds_per_minute], kMonitorFirstMinute, @"YES", kMonitorWroteInTimeSlice, nil]; - NSMutableDictionary *secondMinute = [NSMutableDictionary dictionaryWithObjectsAndKeys:[currentTime dateByAddingTimeInterval: seconds_per_minute * 2],kMonitorSecondMinute, @"NO", kMonitorWroteInTimeSlice, nil]; - NSMutableDictionary *thirdMinute = [NSMutableDictionary dictionaryWithObjectsAndKeys:[currentTime dateByAddingTimeInterval: seconds_per_minute * 3], kMonitorThirdMinute, @"NO",kMonitorWroteInTimeSlice, nil]; - NSMutableDictionary *fourthMinute = [NSMutableDictionary dictionaryWithObjectsAndKeys:[currentTime dateByAddingTimeInterval: seconds_per_minute * 4],kMonitorFourthMinute, @"NO", kMonitorWroteInTimeSlice, nil]; - NSMutableDictionary *fifthMinute = [NSMutableDictionary dictionaryWithObjectsAndKeys:[currentTime dateByAddingTimeInterval: seconds_per_minute * 5], kMonitorFifthMinute, @"NO", kMonitorWroteInTimeSlice, nil]; - - NSMutableDictionary *timeTable = [NSMutableDictionary dictionaryWithObjectsAndKeys: firstMinute, kMonitorFirstMinute, - secondMinute, kMonitorSecondMinute, - thirdMinute, kMonitorThirdMinute, - fourthMinute, kMonitorFourthMinute, - fifthMinute, kMonitorFifthMinute, nil]; - return timeTable; -} - -- (void)initializeKeyEntry:(NSString*)key -{ - NSMutableDictionary *timeTable = [self initializeTimeTable:key]; - NSDate *currentTime = [NSDate date]; - - NSMutableDictionary *keyEntry = [NSMutableDictionary dictionaryWithObjectsAndKeys: key, kMonitorMessageKey, @0, kMonitorConsecutiveWrites, currentTime, kMonitorLastWriteTimestamp, @0, kMonitorPenaltyBoxKey, timeTable, kMonitorTimeTable,[NSMutableDictionary dictionary], kMonitorMessageQueue, nil]; - - [_monitor setObject:keyEntry forKey:key]; - -} - -- (void)recordTimestampForAppropriateInterval:(NSMutableDictionary**)timeTable key:(NSString*)key consecutiveWrites:(NSNumber**)consecutiveWrites -{ - NSDate *currentTime = [NSDate date]; - __block int cWrites = [*consecutiveWrites intValue]; - __block BOOL foundTimeSlot = NO; - __block NSMutableDictionary *previousTable = nil; - NSArray *sorted = [[*timeTable allKeys] sortedArrayUsingSelector:@selector(compare:)]; - [sorted enumerateObjectsUsingBlock:^(id sortedKey, NSUInteger idx, BOOL *stop) - { - if(foundTimeSlot == YES) - return; - [*timeTable enumerateKeysAndObjectsUsingBlock: ^(id minute, id obj, BOOL *stop2) - { - if(foundTimeSlot == YES) - return; - if([sortedKey isEqualToString:minute]){ - NSMutableDictionary *minutesTable = (NSMutableDictionary*)obj; - NSString *minuteKey = (NSString*)minute; - NSDate *date = [minutesTable valueForKey:minuteKey]; - if([date compare:currentTime] == NSOrderedDescending){ - foundTimeSlot = YES; - NSString* written = [minutesTable valueForKey:kMonitorWroteInTimeSlice]; - if([written isEqualToString:@"NO"]){ - [minutesTable setObject:@"YES" forKey:kMonitorWroteInTimeSlice]; - if(previousTable != nil){ - written = [previousTable valueForKey:kMonitorWroteInTimeSlice]; - if([written isEqualToString:@"YES"]){ - cWrites++; - } - else if ([written isEqualToString:@"NO"]){ - cWrites = 0; - } - } - } - return; - } - previousTable = minutesTable; - } - }]; - }]; - - if(foundTimeSlot == NO){ - //reset the time table - secnotice("backoff","didn't find a time slot, resetting the table"); - NSMutableDictionary *lastTable = [*timeTable valueForKey:kMonitorFifthMinute]; - NSDate *lastDate = [lastTable valueForKey:kMonitorFifthMinute]; - - if((double)[currentTime timeIntervalSinceDate: lastDate] >= seconds_per_minute){ - *consecutiveWrites = [[NSNumber alloc]initWithInt:0]; - } - else{ - NSString* written = [lastTable valueForKey:kMonitorWroteInTimeSlice]; - if([written isEqualToString:@"YES"]){ - cWrites++; - *consecutiveWrites = [[NSNumber alloc]initWithInt:cWrites]; - } - else{ - *consecutiveWrites = [[NSNumber alloc]initWithInt:0]; - } - } - - *timeTable = [self initializeTimeTable:key]; - return; - } - *consecutiveWrites = [[NSNumber alloc]initWithInt:cWrites]; -} -- (void)recordWriteToKVS:(NSDictionary *)values -{ - if([_monitor count] == 0){ - [values enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) - { - [self initializeKeyEntry: key]; - }]; - } - else{ - [values enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) - { - NSMutableDictionary *keyEntry = [self->_monitor objectForKey:key]; - if(keyEntry == nil){ - [self initializeKeyEntry: key]; - } - else{ - NSNumber *penalty_timeout = [keyEntry objectForKey:kMonitorPenaltyBoxKey]; - NSDate *lastWriteTimestamp = [keyEntry objectForKey:kMonitorLastWriteTimestamp]; - NSMutableDictionary *timeTable = [keyEntry objectForKey: kMonitorTimeTable]; - NSNumber *existingWrites = [keyEntry objectForKey: kMonitorConsecutiveWrites]; - NSDate *currentTime = [NSDate date]; - - [self recordTimestampForAppropriateInterval:&timeTable key:key consecutiveWrites:&existingWrites]; - - int consecutiveWrites = [existingWrites intValue]; - secnotice("backoff","consecutive writes: %d", consecutiveWrites); - [keyEntry setObject:existingWrites forKey:kMonitorConsecutiveWrites]; - [keyEntry setObject:timeTable forKey:kMonitorTimeTable]; - [keyEntry setObject:currentTime forKey:kMonitorLastWriteTimestamp]; - [self->_monitor setObject:keyEntry forKey:key]; - - if([penalty_timeout intValue] != 0 || ((double)[currentTime timeIntervalSinceDate: lastWriteTimestamp] <= 60 && consecutiveWrites >= 5)){ - if([penalty_timeout intValue] != 0 && consecutiveWrites == 5){ - secnotice("backoff","written for 5 consecutive minutes, time to start throttling"); - [self increasePenalty:penalty_timeout key:key keyEntry:&keyEntry]; - } - else - secnotice("backoff","monitor: keys have been written for 5 or more minutes, recording we wrote during timeout"); - - //record we wrote during a timeout - [keyEntry setObject: @"YES" forKey:kMonitorDidWriteDuringPenalty]; - } - //keep writing freely but record it - else if((double)[currentTime timeIntervalSinceDate: lastWriteTimestamp] <= 60 && consecutiveWrites < 5){ - secnotice("backoff","monitor: still writing freely"); - } - } - }]; - } -} - -- (NSDictionary*)recordHaltedValuesAndReturnValuesToSafelyWrite:(NSDictionary *)values -{ - NSMutableDictionary *SafeMessages = [NSMutableDictionary dictionary]; - [values enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) - { - NSMutableDictionary *keyEntry = [self->_monitor objectForKey:key]; - NSNumber *penalty = [keyEntry objectForKey:kMonitorPenaltyBoxKey]; - if([penalty intValue] != 0){ - NSMutableDictionary* existingQueue = [keyEntry valueForKey:kMonitorMessageQueue]; - - [existingQueue setObject:obj forKey:key]; - - [keyEntry setObject:existingQueue forKey:kMonitorMessageQueue]; - [self->_monitor setObject:keyEntry forKey:key]; - } - else{ - [SafeMessages setObject:obj forKey:key]; - } - }]; - return SafeMessages; -} // MARK: Object setting @@ -752,20 +362,17 @@ CFStringRef const CKDAggdDecreaseThrottlingKey = CFSTR("com.apple.cloudkeychainp [self.store removeObjectForKey:key]; } } + [[self store] addOneToOutGoing]; [self.store setObject:obj forKey:key]; } }]; - + [self.store pushWrites]; } - (void)setObjectsFromDictionary:(NSDictionary *)values { - [self recordWriteToKVS: values]; - NSDictionary *safeValues = [self recordHaltedValuesAndReturnValuesToSafelyWrite: values]; - if([safeValues count] !=0){ - [self setStoreObjectsFromDictionary:safeValues]; - } + [self setStoreObjectsFromDictionary:values]; } - (void)waitForSynchronization:(void (^)(NSDictionary *results, NSError *err))handler @@ -836,6 +443,22 @@ CFStringRef const CKDAggdDecreaseThrottlingKey = CFSTR("com.apple.cloudkeychainp [_unlockedKeys unionSet: [NSMutableSet setWithArray: whenUnlockedKeysArray]]; } +- (void)removeKeys: (NSArray*)keys forAccount: (NSString*) accountUUID +{ + secdebug(XPROXYSCOPE, "removeKeys: keys: %@", keys); + + // We only reset when we know the ID and they send the ID and it changes. + bool newAccount = accountUUID != nil && self.accountUUID != nil && ![accountUUID isEqualToString: self.accountUUID]; + + if(newAccount){ + secnotice(XPROXYSCOPE, "not removing keys, account UUID is for a new account"); + return; + } + [keys enumerateObjectsUsingBlock:^(NSString* _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) { + secnotice(XPROXYSCOPE, "removing from KVS store: %@", key); + [self.store removeObjectForKey:key]; + }]; +} - (void)registerKeys: (NSDictionary*)keys forAccount: (NSString*) accountUUID { diff --git a/KVSKeychainSyncingProxy/CKDKVSStore.h b/KVSKeychainSyncingProxy/CKDKVSStore.h index 6dabc84f..4e4b87dd 100644 --- a/KVSKeychainSyncingProxy/CKDKVSStore.h +++ b/KVSKeychainSyncingProxy/CKDKVSStore.h @@ -13,6 +13,7 @@ - (instancetype)init; - (void)connectToProxy: (UbiqitousKVSProxy*) proxy; +- (void)addOneToOutGoing; - (NSObject*)objectForKey:(NSString*)key; diff --git a/KVSKeychainSyncingProxy/CKDKVSStore.m b/KVSKeychainSyncingProxy/CKDKVSStore.m index b455bf1e..89bdd329 100644 --- a/KVSKeychainSyncingProxy/CKDKVSStore.m +++ b/KVSKeychainSyncingProxy/CKDKVSStore.m @@ -17,12 +17,23 @@ #import "SyncedDefaults/SYDConstants.h" #include -//KVS error codes -#define UPDATE_RESUBMIT 4 +struct CKDKVSCounters { + uint64_t synchronize; + uint64_t synchronizeWithCompletionHandler; + uint64_t incomingMessages; + uint64_t outgoingMessages; + uint64_t totalWaittimeSynchronize; + uint64_t longestWaittimeSynchronize; + uint64_t synchronizeFailures; +}; + + @interface CKDKVSStore () @property (readwrite, weak) UbiqitousKVSProxy* proxy; @property (readwrite) NSUbiquitousKeyValueStore* cloudStore; +@property (assign,readwrite) struct CKDKVSCounters *perfCounters; +@property dispatch_queue_t perfQueue; @end @implementation CKDKVSStore @@ -41,10 +52,18 @@ secerror("NO NSUbiquitousKeyValueStore defaultStore!!!"); return nil; } + self.perfQueue = dispatch_queue_create("CKDKVSStorePerfQueue", NULL); + self.perfCounters = calloc(1, sizeof(struct CKDKVSCounters)); + return self; } +- (void)dealloc { + if (_perfCounters) + free(_perfCounters); +} + - (void) connectToProxy: (UbiqitousKVSProxy*) proxy { _proxy = proxy; @@ -86,12 +105,19 @@ - (void)pushWrites { [[self cloudStore] synchronize]; + dispatch_async(self.perfQueue, ^{ + self.perfCounters->synchronize++; + }); } // 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 { + secnotice("CloudKeychainProxy", "%@ KVS Remote changed notification: %@", self, notification); + dispatch_async(self.perfQueue, ^{ + self.perfCounters->incomingMessages++; + }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self kvsStoreChanged:notification]; }); @@ -129,6 +155,12 @@ os_activity_initiate("cloudChanged", OS_ACTIVITY_FLAG_DEFAULT, ^{ secdebug(XPROXYSCOPE, "%@ KVS Remote changed notification: %@", self, notification); + UbiqitousKVSProxy* proxy = self.proxy; + if(!proxy) { + // Weak reference went away. + return; + } + NSDictionary *userInfo = [notification userInfo]; NSNumber *reason = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangeReasonKey]; NSArray *keysChangedArray = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey]; @@ -136,11 +168,11 @@ if (reason) switch ([reason integerValue]) { case NSUbiquitousKeyValueStoreInitialSyncChange: - [self.proxy storeKeysChanged: keysChanged initial: YES]; + [proxy storeKeysChanged: keysChanged initial: YES]; break; case NSUbiquitousKeyValueStoreServerChange: - [self.proxy storeKeysChanged: keysChanged initial: NO]; + [proxy storeKeysChanged: keysChanged initial: NO]; break; case NSUbiquitousKeyValueStoreQuotaViolationChange: @@ -148,7 +180,7 @@ break; case NSUbiquitousKeyValueStoreAccountChange: - [self.proxy storeAccountChanged]; + [proxy storeAccountChanged]; break; default: @@ -158,49 +190,65 @@ }); } -// try to synchronize asap, and invoke the handler on completion to take incoming changes. - -static bool isResubmitError(NSError* error) { - return error && (CFErrorGetCode((__bridge CFErrorRef) error) == UPDATE_RESUBMIT) && - (CFErrorGetDomain((__bridge CFErrorRef)error) == __SYDErrorKVSDomain); -} - - (BOOL) pullUpdates:(NSError **)failure { __block NSError *tempFailure = nil; - const int kMaximumTries = 10; - int tryCount = 0; - // Retry up to 10 times, since we're told this can fail and WE have to deal with it. - + dispatch_semaphore_t freshSemaphore = dispatch_semaphore_create(0); - - do { - ++tryCount; - secnoticeq("fresh", "%s CALLING OUT TO syncdefaultsd SWCH, try %d: %@", kWAIT2MINID, tryCount, self); - - [[self cloudStore] synchronizeWithCompletionHandler:^(NSError *error) { - if (error) { - tempFailure = error; - secnotice("fresh", "%s RETURNING FROM syncdefaultsd SWCH: %@: %@", kWAIT2MINID, self, error); - } else { - secnotice("fresh", "%s RETURNING FROM syncdefaultsd SWCH: %@", kWAIT2MINID, self); - [[self cloudStore] synchronize]; // Per olivier in , sync before getting values - secnotice("fresh", "%s RETURNING FROM syncdefaultsd SYNC: %@", kWAIT2MINID, self); - } - dispatch_semaphore_signal(freshSemaphore); - }]; - dispatch_semaphore_wait(freshSemaphore, DISPATCH_TIME_FOREVER); - } while (tryCount < kMaximumTries && isResubmitError(tempFailure)); - - if (isResubmitError(tempFailure)) { - secerrorq("%s %d retry attempts to request freshness exceeded, failing", kWAIT2MINID, tryCount); - } - + + secnoticeq("fresh", "%s CALLING OUT TO syncdefaultsd SWCH: %@", kWAIT2MINID, self); + + dispatch_async(self.perfQueue, ^{ + self.perfCounters->synchronizeWithCompletionHandler++; + }); + + [[self cloudStore] synchronizeWithCompletionHandler:^(NSError *error) { + if (error) { + dispatch_async(self.perfQueue, ^{ + self.perfCounters->synchronizeFailures++; + }); + tempFailure = error; + secnotice("fresh", "%s RETURNING FROM syncdefaultsd SWCH: %@: %@", kWAIT2MINID, self, error); + } else { + dispatch_async(self.perfQueue, ^{ + self.perfCounters->synchronize++; + }); + secnotice("fresh", "%s RETURNING FROM syncdefaultsd SWCH: %@", kWAIT2MINID, self); + [[self cloudStore] synchronize]; // Per olivier in , sync before getting values + secnotice("fresh", "%s RETURNING FROM syncdefaultsd SYNC: %@", kWAIT2MINID, self); + } + dispatch_semaphore_signal(freshSemaphore); + }]; + dispatch_semaphore_wait(freshSemaphore, DISPATCH_TIME_FOREVER); + if (failure && (*failure == NULL)) { *failure = tempFailure; } - + return tempFailure == nil; } +- (void)perfCounters:(void(^)(NSDictionary *counters))callback +{ + dispatch_async(self.perfQueue, ^{ + callback(@{ + @"CKDKVS-synchronize" : @(self.perfCounters->synchronize), + @"CKDKVS-synchronizeWithCompletionHandler" : @(self.perfCounters->synchronizeWithCompletionHandler), + @"CKDKVS-incomingMessages" : @(self.perfCounters->incomingMessages), + @"CKDKVS-outgoingMessages" : @(self.perfCounters->outgoingMessages), + @"CKDKVS-totalWaittimeSynchronize" : @(self.perfCounters->totalWaittimeSynchronize), + @"CKDKVS-longestWaittimeSynchronize" : @(self.perfCounters->longestWaittimeSynchronize), + @"CKDKVS-synchronizeFailures" : @(self.perfCounters->synchronizeFailures), + }); + }); +} + +- (void)addOneToOutGoing +{ + dispatch_async(self.perfQueue, ^{ + self.perfCounters->outgoingMessages++; + }); +} + + @end diff --git a/KVSKeychainSyncingProxy/CKDStore.h b/KVSKeychainSyncingProxy/CKDStore.h index 53dc2679..46b8a031 100644 --- a/KVSKeychainSyncingProxy/CKDStore.h +++ b/KVSKeychainSyncingProxy/CKDStore.h @@ -25,4 +25,7 @@ - (void)pushWrites; - (BOOL)pullUpdates:(NSError**) failure; +- (void)perfCounters:(void(^)(NSDictionary *counters))callback; +- (void)addOneToOutGoing; + @end diff --git a/KVSKeychainSyncingProxy/CloudKeychainProxy-Info.plist b/KVSKeychainSyncingProxy/CloudKeychainProxy-Info.plist index 5678d775..418c618b 100644 --- a/KVSKeychainSyncingProxy/CloudKeychainProxy-Info.plist +++ b/KVSKeychainSyncingProxy/CloudKeychainProxy-Info.plist @@ -22,5 +22,7 @@ ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} + LSBackgroundOnly + diff --git a/KVSKeychainSyncingProxy/XPCNotificationDispatcher.m b/KVSKeychainSyncingProxy/XPCNotificationDispatcher.m index 1eccd2f6..3b6d7dca 100644 --- a/KVSKeychainSyncingProxy/XPCNotificationDispatcher.m +++ b/KVSKeychainSyncingProxy/XPCNotificationDispatcher.m @@ -66,11 +66,12 @@ static const char *kXPCNotificationNameKey = "Notification"; if (self) { self.queue = dispatch_queue_create("XPC Notification Dispatch", DISPATCH_QUEUE_SERIAL); self.listeners = [NSPointerArray weakObjectsPointerArray]; + __weak typeof(self) weakSelf = self; xpc_set_event_stream_handler(kXPCNotificationStreamName, self.queue, ^(xpc_object_t event){ const char *notificationName = xpc_dictionary_get_string(event, kXPCNotificationNameKey); if (notificationName) { - [self notification:notificationName]; + [weakSelf notification:notificationName]; } }); } diff --git a/KVSKeychainSyncingProxy/cloudkeychainproxy.m b/KVSKeychainSyncingProxy/cloudkeychainproxy.m index a8a8ffc2..29ea3024 100644 --- a/KVSKeychainSyncingProxy/cloudkeychainproxy.m +++ b/KVSKeychainSyncingProxy/cloudkeychainproxy.m @@ -170,27 +170,27 @@ static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t pe secdebug(PROXYXPCSCOPE, "Handling %s operation", operation); - if (operation && !strcmp(operation, kOperationPUTDictionary)) + if (!strcmp(operation, kOperationPUTDictionary)) { operation_put_dictionary(event); sendAckResponse(peer, event); } - else if (operation && !strcmp(operation, kOperationGETv2)) + else if (!strcmp(operation, kOperationGETv2)) { operation_get_v2(peer, event); // operationg_get_v2 sends the response } - else if (operation && !strcmp(operation, kOperationClearStore)) + else if (!strcmp(operation, kOperationClearStore)) { [SharedProxy() clearStore]; sendAckResponse(peer, event); } - else if (operation && !strcmp(operation, kOperationSynchronize)) + else if (!strcmp(operation, kOperationSynchronize)) { [SharedProxy() synchronizeStore]; sendAckResponse(peer, event); } - else if (operation && !strcmp(operation, kOperationSynchronizeAndWait)) + else if (!strcmp(operation, kOperationSynchronizeAndWait)) { xpc_object_t replyMessage = xpc_dictionary_create_reply(event); secnotice(XPROXYSCOPE, "%s XPC request: %s", kWAIT2MINID, kOperationSynchronizeAndWait); @@ -212,7 +212,7 @@ static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t pe } }]; } - else if (operation && !strcmp(operation, kOperationRegisterKeys)) + else if (!strcmp(operation, kOperationRegisterKeys)) { xpc_object_t xkeysToRegisterDict = xpc_dictionary_get_value(event, kMessageKeyValue); @@ -231,7 +231,24 @@ static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t pe secdebug(PROXYXPCSCOPE, "RegisterKeys message sent"); } - else if (operation && !strcmp(operation, kOperationRequestSyncWithPeers)) + 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; + } + + 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)) { NSArray * peerIDs = CreateArrayOfStringsForCFXPCObjectFromKey(event, kMessageKeyPeerIDList); @@ -244,7 +261,7 @@ static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t pe secdebug(PROXYXPCSCOPE, "RequestSyncWithAllPeers reply sent"); } - else if (operation && !strcmp(operation, kOperationHasPendingSyncWithPeer)) { + else if (!strcmp(operation, kOperationHasPendingSyncWithPeer)) { NSString *peerID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyPeerID); BOOL hasPending = [SharedProxy() hasSyncPendingFor: peerID]; @@ -257,7 +274,7 @@ static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t pe secdebug(PROXYXPCSCOPE, "HasPendingSyncWithPeer reply sent"); } } - else if (operation && !strcmp(operation, kOperationHasPendingKey)) { + else if (!strcmp(operation, kOperationHasPendingKey)) { NSString *peerID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyPeerID); BOOL hasPending = [SharedProxy() hasPendingKey: peerID]; @@ -270,19 +287,27 @@ static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t pe secdebug(PROXYXPCSCOPE, "HasIncomingMessageFromPeer reply sent"); } } - else if (operation && !strcmp(operation, kOperationRequestEnsurePeerRegistration)) + else if (!strcmp(operation, kOperationRequestEnsurePeerRegistration)) { [SharedProxy() requestEnsurePeerRegistration]; sendAckResponse(peer, event); secdebug(PROXYXPCSCOPE, "RequestEnsurePeerRegistration reply sent"); } - else if (operation && !strcmp(operation, kOperationFlush)) + 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); @@ -331,14 +356,14 @@ static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event) if (!replyMessage) { secdebug(PROXYXPCSCOPE, "can't create replyMessage"); - assert(true); //must have a reply handler + 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"); - assert(true); // must have a spot for the returned values + assert(false); // must have a spot for the returned values return false; } diff --git a/KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.osx.plist b/KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.osx.plist index b841f7f2..14f56bbf 100644 --- a/KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.osx.plist +++ b/KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.osx.plist @@ -41,6 +41,16 @@ Notification com.apple.keystore.lockstatus + com.apple.mobile.keybagd.lock_status + + Notification + com.apple.mobile.keybagd.lock_status + + com.apple.mobile.keybagd.first_unlock + + Notification + com.apple.mobile.keybagd.first_unlock + com.apple.security.cloudkeychainproxy.kvstorechange3 Notification diff --git a/KeychainCircle/KCAESGCMDuplexSession.m b/KeychainCircle/KCAESGCMDuplexSession.m index 7f80ee0a..b3d5516e 100644 --- a/KeychainCircle/KCAESGCMDuplexSession.m +++ b/KeychainCircle/KCAESGCMDuplexSession.m @@ -278,7 +278,7 @@ static NSString* KCDSContext = @"context"; } if (der - received_tag != kKCAESGCMTagSize) { - KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Unexpected tag size: %d", der - received_tag); + KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Unexpected tag size: %ld", (long)(der - received_tag)); return nil; } diff --git a/KeychainCircle/KCAccountKCCircleDelegate.h b/KeychainCircle/KCAccountKCCircleDelegate.h index dec0a273..62e26e2e 100644 --- a/KeychainCircle/KCAccountKCCircleDelegate.h +++ b/KeychainCircle/KCAccountKCCircleDelegate.h @@ -19,9 +19,10 @@ @parameter circleJoinData Data the acceptor made to allow us to join the circle. - + @parameter version + Piggybacking version, let's secd know it should expect more data */ -- (bool) processCircleJoinData: (NSData*) circleJoinData error: (NSError**)error; +- (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error; + (instancetype) delegate; @@ -39,7 +40,8 @@ */ - (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer error: (NSError**) error; - +-(NSData*) circleGetInitialSyncViews: (NSError**) error; + + (instancetype) delegate; @end diff --git a/KeychainCircle/KCAccountKCCircleDelegate.m b/KeychainCircle/KCAccountKCCircleDelegate.m index 12b64781..71e86c63 100644 --- a/KeychainCircle/KCAccountKCCircleDelegate.m +++ b/KeychainCircle/KCAccountKCCircleDelegate.m @@ -34,9 +34,9 @@ Data the acceptor made to allow us to join the circle. */ -- (bool) processCircleJoinData: (NSData*) circleJoinData error: (NSError**)error { +- (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion) version error: (NSError**)error { CFErrorRef failure = NULL; - bool result = SOSCCJoinWithCircleJoiningBlob((__bridge CFDataRef) circleJoinData, &failure); + bool result = SOSCCJoinWithCircleJoiningBlob((__bridge CFDataRef) circleJoinData, version, &failure); if (failure != NULL && error != nil) { *error = (__bridge_transfer NSError*) failure; } @@ -69,6 +69,15 @@ return (__bridge_transfer NSData*) result; } +-(NSData*) circleGetInitialSyncViews: (NSError**) error{ + CFErrorRef failure = NULL; + CFDataRef result = SOSCCCopyInitialSyncData(&failure); + if (failure != NULL && error != nil) { + *error = (__bridge_transfer NSError*) failure; + } + return (__bridge_transfer NSData*) result; +} + + (instancetype) delegate { return [[KCJoiningAcceptAccountCircleDelegate alloc] init]; } diff --git a/KeychainCircle/KCDer.m b/KeychainCircle/KCDer.m index 38ac5d7f..c4eb34b0 100644 --- a/KeychainCircle/KCDer.m +++ b/KeychainCircle/KCDer.m @@ -8,6 +8,7 @@ #include #import +#import // These should probably be shared with security, but we don't export our der'izing functions yet. @@ -22,7 +23,12 @@ static const uint8_t* kcder_decode_data_internal(NSData** data, bool copy, size_t payload_size = 0; const uint8_t *payload = ccder_decode_tl(CCDER_OCTET_STRING, &payload_size, der, der_end); - if (NULL == payload || payload + payload_size > der_end) { + uintptr_t payload_end_computed = 0; + if(os_add_overflow((uintptr_t)payload, payload_size, &payload_end_computed)) { + KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Bad payload size"); + return NULL; + } + if (NULL == payload || payload_end_computed > (uintptr_t) der_end) { KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Unknown data encoding"); return NULL; } @@ -85,7 +91,12 @@ const uint8_t* kcder_decode_string(NSString** string, NSError**error, size_t payload_size = 0; const uint8_t *payload = ccder_decode_tl(CCDER_UTF8_STRING, &payload_size, der, der_end); - if (NULL == payload || payload + payload_size > der_end) { + uintptr_t payload_end_computed = 0; + if(os_add_overflow((uintptr_t)payload, payload_size, &payload_end_computed)) { + KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Bad payload size"); + return NULL; + } + if (NULL == payload || payload_end_computed > (uintptr_t) der_end) { KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Unknown string encoding"); return NULL; } diff --git a/KeychainCircle/KCError.h b/KeychainCircle/KCError.h index 80868862..1f9d1874 100644 --- a/KeychainCircle/KCError.h +++ b/KeychainCircle/KCError.h @@ -17,18 +17,19 @@ typedef enum { kKCTagMismatch, kUnexpectedMessage, kInternalError, + kDERUnknownVersion, } KCJoiningError; @interface NSError(KCJoiningError) + (instancetype) errorWithJoiningError:(KCJoiningError) code format:(NSString *) format - arguments:(va_list) va; + arguments:(va_list) va NS_FORMAT_FUNCTION(2,0);; + (instancetype) errorWithJoiningError:(KCJoiningError) code - format:(NSString *) format, ...; + format:(NSString *) format, ... NS_FORMAT_FUNCTION(2,3);; - (instancetype) initWithJoiningError:(KCJoiningError) code userInfo:(NSDictionary *)dict; @end -void KCJoiningErrorCreate(KCJoiningError code, NSError* _Nullable * _Nullable error, NSString* _Nonnull format, ...); +void KCJoiningErrorCreate(KCJoiningError code, NSError* _Nullable * _Nullable error, NSString* _Nonnull format, ...) NS_FORMAT_FUNCTION(3,4);; NS_ASSUME_NONNULL_END diff --git a/KeychainCircle/KCJoiningAcceptSession.m b/KeychainCircle/KCJoiningAcceptSession.m index 60b7ada7..ec8b8b90 100644 --- a/KeychainCircle/KCJoiningAcceptSession.m +++ b/KeychainCircle/KCJoiningAcceptSession.m @@ -18,7 +18,7 @@ #include #include #include - +#include #include typedef enum { @@ -36,6 +36,8 @@ typedef enum { @property (readonly) KCAESGCMDuplexSession* session; @property (readonly) KCJoiningAcceptSessionState state; @property (readwrite) NSData* startMessage; +@property (readwrite) NSString *piggy_uuid; +@property (readwrite) PiggyBackProtocolVersion piggy_version; @end @implementation KCJoiningAcceptSession @@ -92,6 +94,8 @@ typedef enum { self->_circleDelegate = circleDelegate; self->_state = kExpectingA; self->_dsid = dsid; + self->_piggy_uuid = nil; + self->_piggy_version = kPiggyV1; return self; } @@ -122,7 +126,13 @@ typedef enum { } - (NSData*) processInitialMessage: (NSData*) initialMessage error: (NSError**) error { - self.startMessage = extractStartFromInitialMessage(initialMessage, error); + uint64_t version = 0; + NSString *uuid = nil; + + self.startMessage = extractStartFromInitialMessage(initialMessage, &version, &uuid, error); + self.piggy_uuid = uuid; + self.piggy_version = (PiggyBackProtocolVersion)version; + if (self.startMessage == nil) return nil; NSData* srpMessage = [self copyChallengeMessage: error]; @@ -182,7 +192,6 @@ typedef enum { error:error] der]; } - - (NSData*) processApplication: (KCJoiningMessage*) message error:(NSError**) error { if ([message type] != kPeerInfo) { KCJoiningErrorCreate(kUnexpectedMessage, error, @"Expected peerInfo!"); @@ -202,10 +211,19 @@ typedef enum { NSData* joinData = [self.circleDelegate circleJoinDataFor:ref error:error]; if (joinData == nil) return nil; - + + if(self->_piggy_version == kPiggyV1){ + //grab iCloud Identity, TLK, BackupV0 thing + secnotice("acceptor", "piggy version is 1"); + NSData* initialSyncData = [self.circleDelegate circleGetInitialSyncViews:error]; + NSMutableData* growPacket = [[NSMutableData alloc] initWithData:joinData]; + [growPacket appendData:initialSyncData]; + joinData = growPacket; + } + NSData* encryptedOutgoing = [self.session encrypt:joinData error:error]; if (encryptedOutgoing == nil) return nil; - + self->_state = kAcceptDone; return [[KCJoiningMessage messageWithType:kCircleBlob diff --git a/KeychainCircle/KCJoiningMessages.h b/KeychainCircle/KCJoiningMessages.h index 18610d41..827e0e41 100644 --- a/KeychainCircle/KCJoiningMessages.h +++ b/KeychainCircle/KCJoiningMessages.h @@ -9,14 +9,24 @@ // Initial messages are versioned and not typed for negotiation. NS_ASSUME_NONNULL_BEGIN -NSData* extractStartFromInitialMessage(NSData* initialMessage, NSError** error); +NSData* extractStartFromInitialMessage(NSData* initialMessage, uint64_t* version, NSString* _Nullable * _Nullable uuidString, NSError** error); size_t sizeof_initialmessage(NSData*data); +size_t sizeof_initialmessage_version1(NSData*data, uint64_t version1, NSData *uuid); + + + uint8_t* _Nullable encode_initialmessage(NSData* data, NSError**error, - const uint8_t *der, uint8_t *der_end); + const uint8_t *der, uint8_t *der_end); +uint8_t* _Nullable encode_initialmessage_version1(NSData* data, NSData* uuidData, uint64_t piggy_version, NSError**error, + const uint8_t *der, uint8_t *der_end); + const uint8_t* _Nullable decode_initialmessage(NSData* _Nonnull * _Nonnull data, NSError** error, const uint8_t* der, const uint8_t *der_end); +const uint8_t* _Nullable decode_version1(NSData* _Nonnull* _Nonnull data, NSData* _Nullable* _Nullable uuid, uint64_t * _Nullable piggy_version, NSError** error, + const uint8_t* der, const uint8_t *der_end); + size_t sizeof_seq_data_data(NSData*data1, NSData*data2, NSError** error); uint8_t* _Nullable encode_seq_data_data(NSData* data, NSData*data2, NSError**error, const uint8_t *der, uint8_t *der_end); diff --git a/KeychainCircle/KCJoiningMessages.m b/KeychainCircle/KCJoiningMessages.m index c2922cdd..7d83db0f 100644 --- a/KeychainCircle/KCJoiningMessages.m +++ b/KeychainCircle/KCJoiningMessages.m @@ -7,10 +7,12 @@ // #import +#import #import #import #import +#import #include @@ -253,7 +255,7 @@ @end -NSData* extractStartFromInitialMessage(NSData* initialMessage, NSError** error) { +NSData* extractStartFromInitialMessage(NSData* initialMessage, uint64_t* version, NSString** uuidString, NSError** error) { NSData* result = nil; const uint8_t *der = [initialMessage bytes]; const uint8_t *der_end = der + [initialMessage length]; @@ -263,10 +265,48 @@ NSData* extractStartFromInitialMessage(NSData* initialMessage, NSError** error) if (parse_end == NULL) { return nil; } + else if (parse_end != der_end) { + NSData *extraStuff = nil; + NSData *uuid = nil; + uint64_t piggy_version = 0; + parse_end = decode_version1(&extraStuff, &uuid, &piggy_version, error, parse_end, der_end); + require_action_quiet(parse_end != NULL, fail, secerror("decoding piggybacking uuid and version failed (v1)")); + *uuidString = [[NSString alloc] initWithData:uuid encoding:NSUTF8StringEncoding]; + *version = piggy_version; + } +fail: return result; } +const uint8_t* decode_version1(NSData** data, NSData** uuid, uint64_t *piggy_version, NSError** error, + const uint8_t* der, const uint8_t *der_end) +{ + if (NULL == der) + return NULL; + + uint64_t versionFromBlob = 0; + der = ccder_decode_uint64(&versionFromBlob, der, der_end); + + if (der == NULL) { + KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Version mising"); + return nil; + } + + if(versionFromBlob == 1){ //decode uuid + size_t payload_size = 0; + const uint8_t *payload = ccder_decode_tl(CCDER_OCTET_STRING, &payload_size, der, der_end); + + *uuid = [NSData dataWithBytes: (void*)payload length: payload_size]; + *piggy_version = versionFromBlob; + } + else{ + KCJoiningErrorCreate(kDERUnknownVersion, error, @"Bad version: %llu", versionFromBlob); + return nil; + } + + return der; +} const uint8_t* decode_initialmessage(NSData** data, NSError** error, const uint8_t* der, const uint8_t *der_end) { @@ -277,10 +317,9 @@ const uint8_t* decode_initialmessage(NSData** data, NSError** error, der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der, der_end); if (der == NULL || sequence_end != der_end) { - KCJoiningErrorCreate(kDERUnknownEncoding, error, @"decode failed"); + KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Decoding failed"); return nil; } - uint64_t version = 0; der = ccder_decode_uint64(&version, der, der_end); @@ -290,10 +329,10 @@ const uint8_t* decode_initialmessage(NSData** data, NSError** error, } if (version != 0) { - KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Bad version: %d", version); + KCJoiningErrorCreate(kDERUnknownEncoding, error, @"Bad version: %llu", version); return nil; } - + return kcder_decode_data(data, error, der, der_end); } @@ -313,11 +352,41 @@ uint8_t* encode_initialmessage(NSData* data, NSError**error, const uint8_t *der, uint8_t *der_end) { return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, - ccder_encode_uint64(0, der, - kcder_encode_data(data, error, der, der_end))); - + ccder_encode_uint64(0, der, + kcder_encode_data(data, error, der, der_end))); } +size_t sizeof_initialmessage_version1(NSData*data, uint64_t version1, NSData *uuid) { + size_t version_size = ccder_sizeof_uint64(0); + if (version_size == 0) { + return 0; + } + size_t message_size = kcder_sizeof_data(data, nil); + if (message_size == 0) { + return 0; + } + size_t version1_size = ccder_sizeof_uint64(version1); + if (version1_size == 0) { + return 0; + } + size_t uuid_size = kcder_sizeof_data(uuid, nil); + if (message_size == 0) { + return 0; + } + return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, version_size + message_size + version1_size + uuid_size); +} + + +uint8_t* encode_initialmessage_version1(NSData* data, NSData* uuidData, uint64_t piggy_version, NSError**error, + const uint8_t *der, uint8_t *der_end) +{ + return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, + ccder_encode_uint64(0, der, + kcder_encode_data(data, error, der, + ccder_encode_uint64(piggy_version, der, + kcder_encode_data(uuidData, error, der, der_end))))); + +} size_t sizeof_seq_data_data(NSData*data1, NSData*data2, NSError**error) { size_t data1_size = kcder_sizeof_data(data1, error); diff --git a/KeychainCircle/KCJoiningRequestSession.m b/KeychainCircle/KCJoiningRequestSession.m index e41c53bb..731a11c8 100644 --- a/KeychainCircle/KCJoiningRequestSession.m +++ b/KeychainCircle/KCJoiningRequestSession.m @@ -35,26 +35,48 @@ typedef enum { kRequestCircleDone } KCJoiningRequestCircleSessionState; + @interface KCJoiningRequestSecretSession () @property (readonly) NSObject* secretDelegate; @property (readonly) KCSRPClientContext* context; @property (readonly) uint64_t dsid; @property (readonly) KCJoiningRequestSecretSessionState state; - +@property (readwrite) NSString* piggy_uuid; +@property (readwrite) uint64_t piggy_version; @property (readwrite) NSData* challenge; @property (readwrite) NSData* salt; @end +static const uint64_t KCProtocolVersion = kPiggyV1; + @implementation KCJoiningRequestSecretSession : NSObject - (nullable NSData*) initialMessage: (NSError**) error { NSData* start = [self->_context copyStart: error]; if (start == nil) return nil; + + NSMutableData* initialMessage = NULL; + + + if(KCProtocolVersion == kPiggyV1) + { + NSUUID *uuid = [NSUUID UUID]; + uuid_t uuidBytes; - NSMutableData* initialMessage = [NSMutableData dataWithLength: sizeof_initialmessage(start)]; + self.piggy_uuid = [uuid UUIDString]; + [uuid getUUIDBytes:uuidBytes]; + NSData *uuidData = [NSData dataWithBytes:uuidBytes length:sizeof(uuid_t)]; - if (NULL == encode_initialmessage(start, error, initialMessage.mutableBytes, initialMessage.mutableBytes + initialMessage.length)) - return nil; + initialMessage = [NSMutableData dataWithLength: sizeof_initialmessage_version1(start, KCProtocolVersion, uuidData)]; + + if (NULL == encode_initialmessage_version1(start, uuidData, KCProtocolVersion, error, initialMessage.mutableBytes, initialMessage.mutableBytes + initialMessage.length)) + return nil; + } + else{ + initialMessage = [NSMutableData dataWithLength: sizeof_initialmessage(start)]; + if (NULL == encode_initialmessage(start, error, initialMessage.mutableBytes, initialMessage.mutableBytes + initialMessage.length)) + return nil; + } return initialMessage; } @@ -318,7 +340,7 @@ typedef enum { NSData* circleBlob = [self.session decryptAndVerify:message.firstData error:error]; if (circleBlob == nil) return nil; - if (![self.circleDelegate processCircleJoinData: circleBlob error:error]) + if (![self.circleDelegate processCircleJoinData: circleBlob version:kPiggyV1 error:error]) return nil; self->_state = kRequestCircleDone; diff --git a/KeychainCircle/KCJoiningSession.h b/KeychainCircle/KCJoiningSession.h index 6e66ea0b..5c251ed5 100644 --- a/KeychainCircle/KCJoiningSession.h +++ b/KeychainCircle/KCJoiningSession.h @@ -7,6 +7,7 @@ #import #import #include +#include NS_ASSUME_NONNULL_BEGIN @@ -24,10 +25,13 @@ NS_ASSUME_NONNULL_BEGIN @parameter circleJoinData Data the acceptor made to allow us to join the circle. + + @parameter version + Piggybacking protocol version, let's secd know to expect more data */ -- (bool) processCircleJoinData: (NSData*) circleJoinData error: (NSError**)error; - +- (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion) version error: (NSError**)error; + @end @protocol KCJoiningRequestSecretDelegate @@ -116,6 +120,15 @@ NS_ASSUME_NONNULL_BEGIN */ - (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer error: (NSError**) error; + +/*! + Retrieves initial sync data from the following initial sync views: backupV0, iCloud identity, and ckks tlk + @param error + Error returns an error if encoding the initial sync data was successful or not + @result + Data blob contains tlks, icloud identities, and backupv0 + */ +-(NSData*) circleGetInitialSyncViews: (NSError**) error; @end typedef enum { diff --git a/KeychainCircle/KCSRPContext.m b/KeychainCircle/KCSRPContext.m index dab973fe..8686fdcd 100644 --- a/KeychainCircle/KCSRPContext.m +++ b/KeychainCircle/KCSRPContext.m @@ -20,7 +20,7 @@ static const NSStringEncoding srpStringEncoding = NSUTF8StringEncoding; @interface KCSRPContext () -@property (readwrite) ccsrp_ctx* context; +@property (readwrite) struct ccsrp_ctx* context; @property (readwrite) struct ccrng_state *rng; @property (readwrite) NSString* user; @end diff --git a/KeychainCircle/KeychainCircle.h b/KeychainCircle/KeychainCircle.h index 8122f4e6..2963e9c1 100644 --- a/KeychainCircle/KeychainCircle.h +++ b/KeychainCircle/KeychainCircle.h @@ -7,3 +7,4 @@ #import #import #import +#import diff --git a/KeychainCircle/NSError+KCCreationHelpers.h b/KeychainCircle/NSError+KCCreationHelpers.h index 4a04a356..b708d437 100644 --- a/KeychainCircle/NSError+KCCreationHelpers.h +++ b/KeychainCircle/NSError+KCCreationHelpers.h @@ -28,11 +28,11 @@ bool OSStatusError(OSStatus status, NSError * _Nullable * _Nullable error, NSStr + (instancetype) errorWithOSStatus:(OSStatus) status description:(NSString*)description - args:(va_list)va; + args:(va_list)va NS_FORMAT_FUNCTION(2, 0); - (instancetype) initWithOSStatus:(OSStatus) status description:(NSString*)description - args:(va_list)va; + args:(va_list)va NS_FORMAT_FUNCTION(2, 0); + (instancetype) errorWithCoreCryptoStatus:(int) status userInfo:(NSDictionary *)dict; @@ -42,11 +42,11 @@ bool OSStatusError(OSStatus status, NSError * _Nullable * _Nullable error, NSStr + (instancetype) errorWithCoreCryptoStatus:(int) status description:(NSString*)description - args:(va_list)va; + args:(va_list)va NS_FORMAT_FUNCTION(2, 0); - (instancetype) initWithCoreCryptoStatus:(int) status description:(NSString*)description - args:(va_list)va; + args:(va_list)va NS_FORMAT_FUNCTION(2, 0); @end diff --git a/KeychainCircle/NSError+KCCreationHelpers.m b/KeychainCircle/NSError+KCCreationHelpers.m index 0d0e6fc8..220d8ff0 100644 --- a/KeychainCircle/NSError+KCCreationHelpers.m +++ b/KeychainCircle/NSError+KCCreationHelpers.m @@ -11,6 +11,9 @@ static NSString* coreCryptoDomain = @"kSecCoreCryptoDomain"; static NSString* srpDomain = @"com.apple.security.srp"; +static NSDictionary* UserInfoFromVA(NSString*description, va_list va) + NS_FORMAT_FUNCTION(1, 0); + static NSDictionary* UserInfoFromVA(NSString*description, va_list va) { return @{NSLocalizedDescriptionKey:[[NSString alloc] initWithFormat:description arguments:va]}; diff --git a/KeychainCircle/PairingChannel.h b/KeychainCircle/PairingChannel.h new file mode 100644 index 00000000..66522092 --- /dev/null +++ b/KeychainCircle/PairingChannel.h @@ -0,0 +1,39 @@ +// +// SecurityPairing.h +// Security +// + +#import +#import + +extern NSString *kKCPairingChannelErrorDomain; + +#define KCPairingErrorNoControlChannel 1 +#define KCPairingErrorTooManySteps 2 +#define KCPairingErrorAccountCredentialMissing 3 + +typedef void(^KCPairingChannelCompletion)(BOOL complete, NSData *packet, NSError *error); + +@interface KCPairingChannelContext : NSObject +@property (strong) NSString *model; +@property (strong) NSString *modelVersion; +@property (strong) NSString *modelClass; +@property (strong) NSString *osVersion; +@end + +@interface KCPairingChannel : NSObject + +@property (assign,readonly) BOOL needInitialSync; + ++ (instancetype)pairingChannelInitiator:(KCPairingChannelContext *)peerVersionContext; ++ (instancetype)pairingChannelAcceptor:(KCPairingChannelContext *)peerVersionContext; + +- (instancetype)initAsInitiator:(bool)initator version:(KCPairingChannelContext *)peerVersionContext; +- (void)validateStart:(void(^)(bool result, NSError *error))complete; + +- (NSData *)exchangePacket:(NSData *)data complete:(bool *)complete error:(NSError **)error; + +/* for tests cases only */ +- (void)setXPCConnectionObject:(NSXPCConnection *)connection; +@end + diff --git a/KeychainCircle/PairingChannel.m b/KeychainCircle/PairingChannel.m new file mode 100644 index 00000000..166ad460 --- /dev/null +++ b/KeychainCircle/PairingChannel.m @@ -0,0 +1,503 @@ +// +// Security +// + +#import "PairingChannel.h" +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#if TARGET_OS_EMBEDDED +#import +#endif + +#import "SecADWrapper.h" + +typedef void(^KCPairingInternalCompletion)(BOOL complete, NSDictionary *outdict, NSError *error); +typedef void(^KCNextState)(NSDictionary *indict, KCPairingInternalCompletion complete); + +NSString *kKCPairingChannelErrorDomain = @"com.apple.security.kcparingchannel"; + +@implementation KCPairingChannelContext +@end + + +@interface KCPairingChannel () +@property (assign) KCPairingChannelContext *peerVersionContext; +@property (assign) bool initator; +@property (assign) unsigned counter; +@property (assign) bool acceptorWillSendInitialSyncCredentials; +@property (strong) NSXPCConnection *connection; + +@property (strong) KCNextState nextState; +@end + + +@implementation KCPairingChannel + ++ (instancetype)pairingChannelInitiator:(KCPairingChannelContext *)peerVersionContext +{ + return [[KCPairingChannel alloc] initAsInitiator:true version:peerVersionContext]; +} + ++ (instancetype)pairingChannelAcceptor:(KCPairingChannelContext *)peerVersionContext +{ + return [[KCPairingChannel alloc] initAsInitiator:false version:peerVersionContext]; +} + +- (instancetype)initAsInitiator:(bool)initator version:(KCPairingChannelContext *)peerVersionContext +{ + if (![KCPairingChannel isSupportedPlatform]) + return NULL; + + if (self = [super init]) { + __weak typeof(self) weakSelf = self; + _initator = initator; + _peerVersionContext = peerVersionContext; + if (_initator) { + _nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf initatorFirstPacket:nsdata complete:kscomplete]; + }; + } else { + _nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf acceptorFirstPacket:nsdata complete:kscomplete]; + }; + } + _needInitialSync = true; + } + return self; +} + ++ (bool)isSupportedPlatform +{ + CFStringRef deviceClass = NULL; +#if TARGET_OS_EMBEDDED && !RC_HIDE_HARDWARE_WINTER_2017_IOS + deviceClass = MGCopyAnswer(kMGQDeviceClass, NULL); + if (deviceClass && CFEqual(deviceClass, kMGDeviceClassAudioAccessory)){ + CFReleaseNull(deviceClass); + return false; + } +#endif + CFReleaseNull(deviceClass); + return true; +} + +- (void)oneStepTooMany:(NSDictionary * __unused)indata complete:(KCPairingInternalCompletion)complete +{ + secerror("pairingchannel: one step too many"); + complete(false, NULL, [NSError errorWithDomain:kKCPairingChannelErrorDomain code:KCPairingErrorTooManySteps userInfo:NULL]); +} + +- (void)setNextStateError:(NSError *)error complete:(KCPairingInternalCompletion)complete +{ + __weak typeof(self) weakSelf = self; + self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf oneStepTooMany:nsdata complete:kscomplete]; + }; + if (complete) { + if (error) + secerror("pairingchannel: failed pairing with: %@", error); + complete(false, NULL, error); + } +} + +//MARK: - Compression + +const compression_algorithm pairingCompression = COMPRESSION_LZFSE; +#define EXTRA_SIZE 100 + +- (NSData *)compressData:(NSData *)data +{ + NSMutableData *scratch = [NSMutableData dataWithLength:compression_encode_scratch_buffer_size(pairingCompression)]; + + NSUInteger outLength = [data length]; + if (outLength > NSUIntegerMax - EXTRA_SIZE) + return nil; + outLength += EXTRA_SIZE; + + NSMutableData *o = [NSMutableData dataWithLength:outLength]; + size_t result = compression_encode_buffer([o mutableBytes], [o length], [data bytes], [data length], [scratch mutableBytes], pairingCompression); + if (result == 0) + return nil; + + [o setLength:result]; + + return o; +} + +- (NSData *)decompressData:(NSData *)data +{ + NSMutableData *scratch = [NSMutableData dataWithLength:compression_decode_scratch_buffer_size(pairingCompression)]; + + size_t outLength = [data length]; + size_t result; + NSMutableData *o = NULL; + + do { + size_t size; + if (__builtin_umull_overflow(outLength, 2, &size)) + return nil; + outLength = size; + o = [NSMutableData dataWithLength:outLength]; + + result = compression_decode_buffer([o mutableBytes], outLength, [data bytes], [data length], [scratch mutableBytes], pairingCompression); + if (result == 0) + return nil; + } while(result == outLength); + + [o setLength:result]; + + return o; +} + + + +//MARK: - Initiator + +- (void)initatorFirstPacket:(NSDictionary * __unused)indata complete:(KCPairingInternalCompletion)complete +{ + secnotice("pairing", "initator packet 1"); + + if (![self ensureControlChannel]) { + [self setNextStateError:[NSError errorWithDomain:kKCPairingChannelErrorDomain code:KCPairingErrorNoControlChannel userInfo:NULL] complete:complete]; + return; + } + + __weak typeof(self) weakSelf = self; + self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf initatorSecondPacket:nsdata complete:kscomplete]; + }; + complete(false, @{ @"d" : @YES }, NULL); +} + +- (void)initatorSecondPacket:(NSDictionary *)indata complete:(KCPairingInternalCompletion)complete +{ + secnotice("pairing", "initator packet 2"); + + NSData *credential = indata[@"c"]; + if (credential == NULL) { + secnotice("pairing", "no credential"); + [self setNextStateError:[NSError errorWithDomain:kKCPairingChannelErrorDomain code:KCPairingErrorAccountCredentialMissing userInfo:NULL] complete:complete]; + return; + } + + if (indata[@"d"]) { + secnotice("pairing", "acceptor will send send initial credentials"); + self.acceptorWillSendInitialSyncCredentials = true; + } + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + complete(true, NULL, error); + }] stashAccountCredential:credential complete:^(bool success, NSError *error) { + [self setNextStateError:NULL complete:NULL]; + if (!success) { + secnotice("pairing", "failed stash credentials: %@", error); + complete(true, NULL, error); + return; + } + [self initatorCompleteSecondPacket:complete]; + }]; +} + +- (void)initatorCompleteSecondPacket:(KCPairingInternalCompletion)complete +{ + __weak typeof(self) weakSelf = self; + secnotice("pairing", "initator complete second packet 2"); + + [self setNextStateError:NULL complete:NULL]; + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + complete(true, NULL, error); + }] myPeerInfo:^(NSData *application, NSError *error) { + if (application) { + complete(false, @{ @"p" : application }, error); + + weakSelf.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf initatorThirdPacket:nsdata complete:kscomplete]; + }; + + } else { + secnotice("pairing", "failed getting application: %@", error); + complete(true, @{}, error); + } + }]; +} + +- (void)initatorThirdPacket:(NSDictionary *)indata complete:(KCPairingInternalCompletion)complete +{ + __weak typeof(self) weakSelf = self; + secnotice("pairing", "initator packet 3"); + + [self setNextStateError:NULL complete:NULL]; + + NSData *circleBlob = indata[@"b"]; + + if (circleBlob == NULL) { + complete(true, NULL, NULL); + return; + } + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + complete(true, NULL, error); + }] joinCircleWithBlob:circleBlob version:kPiggyV1 complete:^(bool success, NSError *error){ + typeof(self) strongSelf = weakSelf; + secnotice("pairing", "initator cirle join complete, more data: %s: %@", + strongSelf->_acceptorWillSendInitialSyncCredentials ? "yes" : "no", error); + + if (strongSelf->_acceptorWillSendInitialSyncCredentials) { + strongSelf.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf initatorFourthPacket:nsdata complete:kscomplete]; + }; + + complete(false, @{}, NULL); + } else { + complete(true, NULL, NULL); + } + }]; +} + +- (void)initatorFourthPacket:(NSDictionary *)indata complete:(KCPairingInternalCompletion)complete +{ + secnotice("pairing", "initator packet 4"); + + [self setNextStateError:NULL complete:NULL]; + + NSArray *items = indata[@"d"]; + if (![items isKindOfClass:[NSArray class]]) { + secnotice("pairing", "initator no items to import"); + complete(true, NULL, NULL); + return; + } + + secnotice("pairing", "importing %lu items", (unsigned long)[items count]); + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + complete(true, NULL, error); + }] importInitialSyncCredentials:items complete:^(bool success, NSError *error) { + secnotice("pairing", "initator importInitialSyncCredentials: %s: %@", success ? "yes" : "no", error); + if (success) + self->_needInitialSync = false; + complete(true, NULL, NULL); + }]; +} + + + +//MARK: - Acceptor + +- (void)acceptorFirstPacket:(NSDictionary *)indata complete:(KCPairingInternalCompletion)complete +{ + __weak typeof(self) weakSelf = self; + + secnotice("pairing", "acceptor packet 1"); + + [self setNextStateError:NULL complete:NULL]; + + if (![self ensureControlChannel]) { + [self setNextStateError:[NSError errorWithDomain:kKCPairingChannelErrorDomain code:KCPairingErrorNoControlChannel userInfo:NULL] complete:complete]; + return; + } + + if (indata[@"d"]) { + secnotice("pairing", "acceptor initialSyncCredentials requested"); + self.acceptorWillSendInitialSyncCredentials = true; + } + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + complete(true, NULL, error); + }] validatedStashedAccountCredential:^(NSData *credential, NSError *error) { + if (!credential) { + secnotice("pairing", "acceptor doesn't have a stashed credential: %@", error); + [self setNextStateError:error complete:complete]; + return; + } + + self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf acceptorSecondPacket:nsdata complete:kscomplete]; + }; + + NSMutableDictionary *reply = [@{ + @"c" : credential, + } mutableCopy]; + + if (self.acceptorWillSendInitialSyncCredentials) { + reply[@"d"] = @YES; + }; + + secnotice("pairing", "acceptor reply to packet 1"); + complete(false, reply, NULL); + }]; +} + +- (void)acceptorSecondPacket:(NSDictionary *)indata complete:(KCPairingInternalCompletion)complete +{ + __weak typeof(self) weakSelf = self; + + [self setNextStateError:NULL complete:NULL]; + + secnotice("pairing", "acceptor packet 2"); + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + complete(true, NULL, error); + }] circleJoiningBlob:indata[@"p"] complete:^(NSData *blob, NSError *error){ + NSMutableDictionary *reply = [NSMutableDictionary dictionary]; + + if (blob) { + secnotice("pairing", "acceptor pairing complete (will send: %s): %@", + self.acceptorWillSendInitialSyncCredentials ? "YES" : "NO", + error); + + reply[@"b"] = blob; + + if (self.acceptorWillSendInitialSyncCredentials) { + self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf acceptorThirdPacket:nsdata complete:kscomplete]; + }; + + complete(false, reply, NULL); + } else { + complete(true, reply, NULL); + } + } else { + complete(true, reply, error); + } + secnotice("pairing", "acceptor reply to packet 2"); + }]; +} + +- (void)acceptorThirdPacket:(NSDictionary *)indata complete:(KCPairingInternalCompletion)complete +{ + secnotice("pairing", "acceptor packet 3"); + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + complete(true, NULL, error); + }] initialSyncCredentials:(SOSControlInitialSyncFlagTLK|SOSControlInitialSyncFlagPCS) complete:^(NSArray *items, NSError *error2) { + NSMutableDictionary *reply = [NSMutableDictionary dictionary]; + + secnotice("pairing", "acceptor initialSyncCredentials complete: items %u: %@", (unsigned)[items count], error2); + if (items) { + reply[@"d"] = items; + } + secnotice("pairing", "acceptor reply to packet 3"); + complete(true, reply, NULL); + }]; +} + + +//MARK: - Helper + +- (bool)ensureControlChannel +{ + if (self.connection) + return true; + + xpc_endpoint_t endpoint = _SecSecuritydCopySOSStatusEndpoint(NULL); + if (endpoint == NULL) + return false; + + NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SOSControlProtocol)]; + NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; + + [listenerEndpoint _setEndpoint:endpoint]; + + self.connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; + if (self.connection == NULL) + return false; + + self.connection.remoteObjectInterface = interface; + + [self.connection resume]; + + return true; +} + +- (void)validateStart:(void(^)(bool result, NSError *error))complete +{ + if (!self.initator) { + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + complete(false, error); + }] stashedCredentialPublicKey:^(NSData *publicKey, NSError *error) { + complete(publicKey != NULL, error); + }]; + } else { + dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ + complete(true, NULL); + }); + } +} + +- (void)exchangePacket:(NSData *)inputCompressedData complete:(KCPairingChannelCompletion)complete +{ + NSDictionary *indict = NULL; + + if (inputCompressedData) { + + NSData *data = [self decompressData:inputCompressedData]; + if (data == NULL) { + secnotice("pairing", "failed to decompress"); + complete(true, NULL, NULL); + } + + NSError *error = NULL; + indict = [NSPropertyListSerialization propertyListWithData:data + options:(NSPropertyListReadOptions)kCFPropertyListSupportedFormatBinary_v1_0 + format:NULL + error:&error]; + if (indict == NULL) { + secnotice("pairing", "failed to deserialize"); + complete(true, NULL, error); + return; + } + } + self.nextState(indict, ^(BOOL completed, NSDictionary *outdict, NSError *error) { + NSData *outdata = NULL, *compressedData = NULL; + if (outdict) { + NSError *error2 = NULL; + outdata = [NSPropertyListSerialization dataWithPropertyList:outdict format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error2]; + if (outdata == NULL && error) + error = error2; + if (outdata) + compressedData = [self compressData:outdata]; + + if (compressedData) { + NSString *key = [NSString stringWithFormat:@"com.apple.ckks.pairing.packet-size.%s.%u", + self->_initator ? "initator" : "acceptor", self->_counter]; + SecADClientPushValueForDistributionKey((__bridge CFStringRef)key, [compressedData length]); + secnotice("pairing", "pairing packet size %lu", (unsigned long)[compressedData length]); + } + } + complete(completed, compressedData, error); + }); +} + +- (NSData *)exchangePacket:(NSData *)data complete:(bool *)complete error:(NSError * __autoreleasing *)error +{ + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + __block NSData *rData = NULL; + __block NSError* processingError; + [self exchangePacket:data complete:^(BOOL cComplete, NSData *cData, NSError *cError) { + self.counter++; + *complete = cComplete; + rData = cData; + processingError = cError; + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + if (error) + *error = processingError; + return rData; +} + +- (void)setXPCConnectionObject:(NSXPCConnection *)connection +{ + self.connection = connection; +} + + +@end diff --git a/KeychainCircle/Tests/KCAESGCMTest.m b/KeychainCircle/Tests/KCAESGCMTest.m index 25e02df7..708a53a7 100644 --- a/KeychainCircle/Tests/KCAESGCMTest.m +++ b/KeychainCircle/Tests/KCAESGCMTest.m @@ -72,6 +72,7 @@ [archiver finishEncoding]; NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + unarchiver.requiresSecureCoding = YES; // Customize the unarchiver. KCAESGCMDuplexSession *result = [unarchiver decodeObjectForKey:@"Top"]; diff --git a/KeychainCircle/Tests/KCJoiningSessionTest.m b/KeychainCircle/Tests/KCJoiningSessionTest.m index d44a297f..4f95e3c5 100644 --- a/KeychainCircle/Tests/KCJoiningSessionTest.m +++ b/KeychainCircle/Tests/KCJoiningSessionTest.m @@ -21,12 +21,12 @@ __unused static SOSFullPeerInfoRef SOSNSFullPeerInfoCreate(NSDictionary* gestalt, - NSData* backupKey, SecKeyRef signingKey, + NSData* backupKey, SecKeyRef signingKey, SecKeyRef octagonSigningKey, NSError**error) { CFErrorRef errorRef = NULL; - SOSFullPeerInfoRef result = SOSFullPeerInfoCreate(NULL, (__bridge CFDictionaryRef) gestalt, (__bridge CFDataRef) backupKey, signingKey, &errorRef); + SOSFullPeerInfoRef result = SOSFullPeerInfoCreate(NULL, (__bridge CFDictionaryRef) gestalt, (__bridge CFDataRef) backupKey, signingKey, octagonSigningKey, &errorRef); if (errorRef && error) { *error = (__bridge_transfer NSError*) errorRef; @@ -54,16 +54,21 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) { } -__unused static SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(NSString* name, SecKeyRef* outSigningKey, NSError** error) +__unused static SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(NSString* name, SecKeyRef* outSigningKey, SecKeyRef* outOctagonSigningKey, NSError** error) { - if (outSigningKey == NULL) + if (outSigningKey == NULL || outOctagonSigningKey == NULL) return NULL; *outSigningKey = GenerateFullECKey(256, error); if (*outSigningKey == NULL) return NULL; + + *outOctagonSigningKey = GenerateFullECKey(384, error); + if (*outOctagonSigningKey == NULL) { + return NULL; + } - return SOSNSFullPeerInfoCreate(@{(__bridge NSString*)kPIUserDefinedDeviceNameKey:name}, nil, *outSigningKey, error); + return SOSNSFullPeerInfoCreate(@{(__bridge NSString*)kPIUserDefinedDeviceNameKey:name}, nil, *outSigningKey, *outOctagonSigningKey, error); } @@ -86,7 +91,7 @@ __unused static SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(NSString* name, - (NSString*) secret; - (NSString*) verificationFailed: (bool) codeChanged; - (SOSPeerInfoRef) copyPeerInfoError: (NSError**) error; -- (bool) processCircleJoinData: (NSData*) circleJoinData error: (NSError**)error ; +- (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error ; - (bool) processAccountCode: (NSString*) accountCode error: (NSError**)error; @end @@ -114,8 +119,9 @@ __unused static SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(NSString* name, self = [super init]; SecKeyRef signingKey = GenerateFullECKey(256, NULL); + SecKeyRef octagonSigningKey = GenerateFullECKey(384, NULL); - self.peerInfo = SOSPeerInfoCreate(NULL, (__bridge CFDictionaryRef) @{(__bridge NSString*)kPIUserDefinedDeviceNameKey:@"Fakey"}, NULL, signingKey, NULL); + self.peerInfo = SOSPeerInfoCreate(NULL, (__bridge CFDictionaryRef) @{(__bridge NSString*)kPIUserDefinedDeviceNameKey:@"Fakey"}, NULL, signingKey, octagonSigningKey, NULL); if (self.peerInfo == NULL) return nil; @@ -147,7 +153,7 @@ __unused static SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(NSString* name, return self.peerInfo; } -- (bool) processCircleJoinData: (NSData*) circleJoinData error: (NSError**)error { +- (bool) processCircleJoinData: (NSData*) circleJoinData version:(PiggyBackProtocolVersion)version error: (NSError**)error { self->_circleJoinData = circleJoinData; return true; } @@ -249,6 +255,9 @@ __unused static SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(NSString* name, return [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ]; } +-(NSData*) circleGetInitialSyncViews: (NSError**) error{ + return [NSData data]; +} @end diff --git a/KeychainCircle/Tests/KCPairingTest-Info.plist b/KeychainCircle/Tests/KCPairingTest-Info.plist new file mode 100644 index 00000000..ba72822e --- /dev/null +++ b/KeychainCircle/Tests/KCPairingTest-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/KeychainCircle/Tests/KCPairingTest.m b/KeychainCircle/Tests/KCPairingTest.m new file mode 100644 index 00000000..eb77f2dd --- /dev/null +++ b/KeychainCircle/Tests/KCPairingTest.m @@ -0,0 +1,427 @@ +// +// SecurityPairing.m +// Security_ios +// +// Created by Love Hörnquist Åstrand on 2017-02-28. +// + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import "SecCFWrappers.h" +#import "SOSRegressionUtilities.h" + +@interface FakeNSXPCConnection : NSObject +- (instancetype) initWithControl:(id)control; +- (id)remoteObjectProxyWithErrorHandler:(void(^)(NSError * _Nonnull error))failureHandler; +@end +@interface FakeNSXPCConnection () +@property id control; +@end +@implementation FakeNSXPCConnection +- (instancetype) initWithControl:(id)control +{ + self = [super init]; + if (self) { + _control = control; + } + return self; +} +- (id)remoteObjectProxyWithErrorHandler:(void(^)(NSError * _Nonnull error))failureHandler +{ + (void)failureHandler; + return _control; +} +@end + + +@interface KCPairingTest : XCTestCase + +@end + +@interface FCPairingFakeSOSControl : NSObject +@property (assign) SecKeyRef accountPrivateKey; +@property (assign) SecKeyRef accountPublicKey; +@property (assign) SecKeyRef deviceKey; +@property (assign) SecKeyRef octagonSigningKey; +@property (assign) SOSCircleRef circle; +@property (assign) SOSFullPeerInfoRef fullPeerInfo; +@property (assign) bool application; +@end + +@implementation FCPairingFakeSOSControl + +- (instancetype)initWithRandomAccountKey:(bool)randomAccountKey circle:(SOSCircleRef)circle +{ + if ((self = [super init])) { + SecKeyRef publicKey = NULL; + NSDictionary* parameters = @{ + (__bridge NSString*)kSecAttrKeyType:(__bridge NSString*) kSecAttrKeyTypeEC, + (__bridge NSString*)kSecAttrKeySizeInBits: @(256), + (__bridge NSString*)kSecAttrNoLegacy : @YES, + (__bridge NSString*)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock, + (__bridge id)kSecPrivateKeyAttrs : @{ + (__bridge NSString*)kSecAttrLabel : @"delete me test case - private", + (__bridge NSString*)kSecAttrIsPermanent : @YES, + (__bridge NSString*)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock, + }, + (__bridge id)kSecPublicKeyAttrs : @{ + (__bridge NSString*)kSecAttrLabel : @"delete me test case - public", + (__bridge NSString*)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock, + } + }; + if(SecKeyGeneratePair((__bridge CFDictionaryRef)parameters, &publicKey, &_deviceKey) != 0) { + NSLog(@"failed to create device key"); + return nil; + } + CFReleaseNull(publicKey); + + NSMutableDictionary* octagonParameters = [parameters mutableCopy]; + octagonParameters[(__bridge NSString*)kSecAttrKeySizeInBits] = @(384); + if(SecKeyGeneratePair((__bridge CFDictionaryRef)octagonParameters, &publicKey, &_octagonSigningKey) != 0) { + NSLog(@"failed to create octagon signing key"); + return nil; + } + CFReleaseNull(publicKey); + + _circle = (SOSCircleRef)CFRetain(circle); + + CFErrorRef error = NULL; + + CFDictionaryRef gestalt = (__bridge CFDictionaryRef)@{ + @"ComputerName" : @"name", + }; + + _fullPeerInfo = SOSFullPeerInfoCreate(NULL, gestalt, NULL, _deviceKey, _octagonSigningKey, &error); + CFReleaseNull(error); + + if (randomAccountKey) { + + NSDictionary* accountParams = @{ + (__bridge NSString*)kSecAttrKeyType:(__bridge NSString*) kSecAttrKeyTypeEC, + (__bridge NSString*)kSecAttrKeySizeInBits: @(256), + (__bridge NSString*)kSecAttrNoLegacy : @YES, + (__bridge NSString*)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock, + }; + + if(SecKeyGeneratePair((__bridge CFDictionaryRef)accountParams, &publicKey, &_accountPrivateKey) != 0) { + NSLog(@"failed to create account signing key"); + return nil; + } + CFReleaseNull(publicKey); + + _accountPublicKey = SecKeyCopyPublicKey(_accountPrivateKey); + + [self signApplicationIfNeeded]; + } + } + return self; +} + +- (void)dealloc +{ + if (_accountPrivateKey) { + SecItemDelete((__bridge CFTypeRef)@{ (__bridge id)kSecValueRef : (__bridge id)_accountPrivateKey }); + CFReleaseNull(_accountPrivateKey); + } + if (_deviceKey) { + SecItemDelete((__bridge CFTypeRef)@{ (__bridge id)kSecValueRef : (__bridge id)_deviceKey }); + CFReleaseNull(_deviceKey); + } + if (_octagonSigningKey) { + SecItemDelete((__bridge CFTypeRef)@{ (__bridge id)kSecValueRef : (__bridge id)_octagonSigningKey }); + CFReleaseNull(_octagonSigningKey); + } + CFReleaseNull(_circle); + CFReleaseNull(_fullPeerInfo); +} + +- (SOSPeerInfoRef)peerInfo +{ + return SOSFullPeerInfoGetPeerInfo(_fullPeerInfo); +} + +- (void)signApplicationIfNeeded +{ + CFErrorRef error = NULL; + + _application = SOSFullPeerInfoPromoteToApplication(_fullPeerInfo, _accountPrivateKey, &error); + if (!_application) + abort(); +} + +- (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete +{ + complete(@[], NULL); +} + +- (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete +{ + complete(true, NULL); +} + +- (void)triggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete +{ + complete(true, NULL); +} + +//MARK - FCPairingFakeSOSControl SOSControlProtocol + +- (void)userPublicKey:(void ((^))(BOOL trusted, NSData *spki, NSError *error))complete +{ + complete(false, NULL, NULL); +} + +- (void)performanceCounters:(void(^)(NSDictionary *))complete +{ + complete(@{}); +} +- (void)kvsPerformanceCounters:(void(^)(NSDictionary *))complete +{ + complete(@{}); +} +- (void)idsPerformanceCounters:(void(^)(NSDictionary *))complete +{ + complete(@{}); +} +- (void)rateLimitingPerformanceCounters:(void(^)(NSDictionary *))complete +{ + complete(@{}); +} +- (void)stashedCredentialPublicKey:(void(^)(NSData *, NSError *error))complete +{ + NSData *publicKey = NULL; + NSError *error = NULL; + if (self.accountPrivateKey) { + publicKey = CFBridgingRelease(SecKeyCopySubjectPublicKeyInfo(self.accountPrivateKey)); + } else { + error = [NSError errorWithDomain:@"FCPairingFakeSOSControl" code:2 userInfo:NULL]; + } + complete(publicKey, error); +} + +- (void)assertStashedAccountCredential:(void(^)(BOOL result, NSError *error))complete +{ + complete(self.accountPrivateKey != NULL, NULL); +} + +- (void)validatedStashedAccountCredential:(void(^)(NSData *credential, NSError *error))complete +{ + NSData *key = NULL; + CFErrorRef error = NULL; + if (self.accountPrivateKey) { + key = CFBridgingRelease(SecKeyCopyExternalRepresentation(self.accountPrivateKey, &error)); + } else { + error = (CFErrorRef)CFBridgingRetain([NSError errorWithDomain:@"FCPairingFakeSOSControl" code:1 userInfo:NULL]); + } + complete(key, (__bridge NSError *)error); + CFReleaseNull(error); +} + +- (void)stashAccountCredential:(NSData *)credential complete:(void(^)(bool success, NSError *error))complete +{ + 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); + CFReleaseNull(error); + return; + } + + _accountPrivateKey = accountPrivateKey; + _accountPublicKey = SecKeyCopyPublicKey(_accountPrivateKey); + + [self signApplicationIfNeeded]; + + complete(true, NULL); +} + +- (void)myPeerInfo:(void(^)(NSData *application, NSError *error))complete +{ + CFErrorRef error = NULL; + + [self signApplicationIfNeeded]; + + NSData *application = CFBridgingRelease(SOSPeerInfoCopyEncodedData([self peerInfo], NULL, &error)); + complete(application, (__bridge NSError *)error); + + CFReleaseNull(error); +} + +- (void)circleJoiningBlob:(NSData *)applicantData complete:(void (^)(NSData *blob, NSError *))complete +{ + CFErrorRef error = NULL; + CFDataRef signature = NULL; + SOSCircleRef prunedCircle = SOSCircleCopyCircle(NULL, _circle, &error); + (void)SOSCirclePreGenerationSign(prunedCircle, _accountPublicKey, &error); + + SOSGenCountRef gencount = SOSGenerationIncrementAndCreate(SOSCircleGetGeneration(prunedCircle)); + if (gencount == NULL) + abort(); + + + SOSPeerInfoRef applicant = SOSPeerInfoCreateFromData(NULL, &error, (__bridge CFDataRef)applicantData); + if (applicant == NULL) + abort(); + + signature = SOSCircleCopyNextGenSignatureWithPeerAdded(prunedCircle, applicant, _deviceKey, &error); + + NSData *pbblob = CFBridgingRelease(SOSPiggyBackBlobCopyEncodedData(gencount, _deviceKey, signature, &error)); + + CFReleaseNull(signature); + CFReleaseNull(gencount); + CFReleaseNull(prunedCircle); + + complete(pbblob, NULL); +} + +- (void)joinCircleWithBlob:(NSData *)blob version:(PiggyBackProtocolVersion)version complete:(void (^)(bool success, NSError *))complete +{ + SOSGenCountRef gencount = NULL; + SecKeyRef pubKey = NULL; + CFDataRef signature = NULL; + CFErrorRef error = NULL; + bool setInitialSyncTimeoutToV0 = false; + + if (!SOSPiggyBackBlobCreateFromData(&gencount, &pubKey, &signature, (__bridge CFDataRef)blob, kPiggyV1, &setInitialSyncTimeoutToV0, &error)) { + complete(true, (__bridge NSError *)error); + CFReleaseNull(error); + return; + } + + (void)SOSCircleAcceptPeerFromHSA2(_circle, + _accountPrivateKey, + gencount, + pubKey, + signature, + _fullPeerInfo, + &error); + + CFReleaseNull(gencount); + CFReleaseNull(pubKey); + CFReleaseNull(signature); + + complete(true, (__bridge NSError *)error); + + CFReleaseNull(error); + +} + +- (void)getWatchdogParameters:(void (^)(NSDictionary*, NSError*))complete +{ + // intentionally left blank + // these are used by the security/2 tool and are only declared here to make the compiler happy about conforming the protocol we shoved the methods into +} + + +- (void)setWatchdogParmeters:(NSDictionary*)parameters complete:(void (^)(NSError*))complete +{ + // intentionally left blank + // these are used by the security/2 tool and are only declared here to make the compiler happy about conforming the protocol we shoved the methods into +} + + +@end + +@implementation KCPairingTest + +- (void)testSecPairBasicTest +{ + bool sp1compete = false, sp2compete = false; + NSData *sp1data = NULL; + NSData *sp2data = NULL; + SOSCircleRef circle = NULL; + unsigned count = 0; + CFErrorRef cferror = NULL; + KCPairingChannel *sp1, *sp2; + + circle = SOSCircleCreate(NULL, CFSTR("TEST DOMAIN"), NULL); + XCTAssert(circle, "circle"); + + FCPairingFakeSOSControl *fc1 = [[FCPairingFakeSOSControl alloc] initWithRandomAccountKey:false circle:circle]; + XCTAssert(fc1, "create fake soscontrol 1"); + + FCPairingFakeSOSControl *fc2 = [[FCPairingFakeSOSControl alloc] initWithRandomAccountKey:true circle:circle]; + XCTAssert(fc2, "create fake soscontrol 2"); + + + XCTAssert(SOSCircleRequestAdmission(circle, fc2.accountPrivateKey, fc2.fullPeerInfo, &cferror), "SOSCircleRequestAdmission: %@", cferror); + CFReleaseNull(cferror); + + XCTAssert(SOSCircleAcceptRequest(circle, fc2.accountPrivateKey, fc2.fullPeerInfo, [fc2 peerInfo], &cferror), "SOSCircleAcceptRequest device 1: %@", cferror); + CFReleaseNull(cferror); + + XCTAssert(SOSCircleHasPeer(circle, [fc2 peerInfo], &cferror), "HasPeer 2: %@", cferror); + CFReleaseNull(cferror); + + + sp1 = [KCPairingChannel pairingChannelInitiator:NULL]; + [sp1 setXPCConnectionObject:(NSXPCConnection *)[[FakeNSXPCConnection alloc] initWithControl:fc1]]; + + sp2 = [KCPairingChannel pairingChannelAcceptor:NULL]; + [sp2 setXPCConnectionObject:(NSXPCConnection *)[[FakeNSXPCConnection alloc] initWithControl:fc2]] ; + + while(1) { + NSError *error = NULL; + + sp1data = [sp1 exchangePacket:sp2data complete:&sp1compete error:&error]; + + if (sp1compete && sp2compete) { + XCTAssert(sp1data == NULL, "sp1 done, yet there is data"); + break; + } + XCTAssert(!sp2compete, "sp2 completed w/o sp1"); + + XCTAssert(sp1data != NULL, "sp1 not done, yet there is no data: %@", error); + if (sp1data == NULL) + break; + + /* send sp1data to peer : BOB CHANNEL HERE */ + + sp2data = [sp2 exchangePacket:sp1data complete:&sp2compete error:&error]; + XCTAssert(sp2data != NULL, "sp2 didn't return data: %@", error); + if (sp2data == NULL) + break; + + if (sp1compete && sp2compete) + break; + + XCTAssert(!sp1compete, "sp2 completed w/o sp1"); + + count++; + if (count > 10) + abort(); + }; + + XCTAssert(sp1compete && sp2compete, "both parties not completed"); + + XCTAssert(fc1.accountPrivateKey, "no accountPrivateKey in fc1"); + XCTAssert(fc2.accountPrivateKey, "no accountPrivateKey in fc2"); + XCTAssert(CFEqualSafe(fc1.accountPrivateKey, fc2.accountPrivateKey), "no accountPrivateKey not same in both"); + + if (sp1compete && sp2compete) + NSLog(@"pairing complete"); + + XCTAssert(SOSCircleHasPeer(circle, [fc1 peerInfo], &cferror), "HasPeer 1: %@", cferror); + CFReleaseNull(cferror); + XCTAssert(SOSCircleHasPeer(circle, [fc2 peerInfo], &cferror), "HasPeer 2: %@", cferror); + CFReleaseNull(cferror); + + XCTAssert(sp1.needInitialSync == false, "no longer need initial sync"); + + +} + +@end diff --git a/KeychainCircle/Tests/KCParing.plist b/KeychainCircle/Tests/KCParing.plist new file mode 100644 index 00000000..137bf077 --- /dev/null +++ b/KeychainCircle/Tests/KCParing.plist @@ -0,0 +1,32 @@ + + + + + BATSConfigVersion + 0.1.0 + Project + Security + TestSpecificLogs + + /var/log/module/com.apple.securityd/security.log.* + /var/mobile/Library/Logs/CrashReporter/DiagnosticLogs/security.log.* + + Tests + + + TestName + testSecPairBasicTest + WorkingDirectory + /AppleInternal/Tests/Security + Arch + platform-native + AsRoot + + Command + + BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testSecPairBasicTest KCPairing.xctest + + + + + diff --git a/KeychainEntitledTestApp_ios/AppDelegate.h b/KeychainEntitledTestApp_ios/AppDelegate.h new file mode 100644 index 00000000..998155c0 --- /dev/null +++ b/KeychainEntitledTestApp_ios/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// KeychainEntitledTestApp_ios +// +// Copyright (c) 2017 Apple Inc. All rights reserved. +// +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/KeychainEntitledTestApp_ios/AppDelegate.m b/KeychainEntitledTestApp_ios/AppDelegate.m new file mode 100644 index 00000000..7905ddac --- /dev/null +++ b/KeychainEntitledTestApp_ios/AppDelegate.m @@ -0,0 +1,51 @@ +// +// 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 new file mode 100644 index 00000000..1d060ed2 --- /dev/null +++ b/KeychainEntitledTestApp_ios/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "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" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/KeychainEntitledTestApp_ios/Base.lproj/LaunchScreen.storyboard b/KeychainEntitledTestApp_ios/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..fdf3f97d --- /dev/null +++ b/KeychainEntitledTestApp_ios/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/KeychainEntitledTestApp_ios/Base.lproj/Main.storyboard b/KeychainEntitledTestApp_ios/Base.lproj/Main.storyboard new file mode 100644 index 00000000..4529698c --- /dev/null +++ b/KeychainEntitledTestApp_ios/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/KeychainEntitledTestApp_ios/Info.plist b/KeychainEntitledTestApp_ios/Info.plist new file mode 100644 index 00000000..d0524738 --- /dev/null +++ b/KeychainEntitledTestApp_ios/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/KeychainEntitledTestApp_ios/ViewController.h b/KeychainEntitledTestApp_ios/ViewController.h new file mode 100644 index 00000000..2300ca20 --- /dev/null +++ b/KeychainEntitledTestApp_ios/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// KeychainEntitledTestApp_ios +// +// Copyright (c) 2017 Apple Inc. All rights reserved. +// +// + +#import + +@interface ViewController : UIViewController + + +@end + diff --git a/KeychainEntitledTestApp_ios/ViewController.m b/KeychainEntitledTestApp_ios/ViewController.m new file mode 100644 index 00000000..30c0bb6d --- /dev/null +++ b/KeychainEntitledTestApp_ios/ViewController.m @@ -0,0 +1,29 @@ +// +// 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 new file mode 100644 index 00000000..d553ece5 --- /dev/null +++ b/KeychainEntitledTestApp_ios/main.m @@ -0,0 +1,16 @@ +// +// main.m +// KeychainEntitledTestApp_ios +// +// Copyright (c) 2017 Apple Inc. All rights reserved. +// +// + +#import +#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 new file mode 100644 index 00000000..5452eb93 --- /dev/null +++ b/KeychainEntitledTestApp_mac/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// KeychainEntitledTestApp_mac +// +// Copyright (c) 2017 Apple Inc. All rights reserved. +// +// + +#import + +@interface AppDelegate : NSObject + + +@end + diff --git a/KeychainEntitledTestApp_mac/AppDelegate.m b/KeychainEntitledTestApp_mac/AppDelegate.m new file mode 100644 index 00000000..e1e6dc39 --- /dev/null +++ b/KeychainEntitledTestApp_mac/AppDelegate.m @@ -0,0 +1,27 @@ +// +// 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 new file mode 100644 index 00000000..2db2b1c7 --- /dev/null +++ b/KeychainEntitledTestApp_mac/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -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/KeychainEntitledTestApp_mac/Base.lproj/Main.storyboard b/KeychainEntitledTestApp_mac/Base.lproj/Main.storyboard new file mode 100644 index 00000000..6f7fdad6 --- /dev/null +++ b/KeychainEntitledTestApp_mac/Base.lproj/Main.storyboard @@ -0,0 +1,693 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/KeychainEntitledTestApp_mac/Info.plist b/KeychainEntitledTestApp_mac/Info.plist new file mode 100644 index 00000000..f16cc068 --- /dev/null +++ b/KeychainEntitledTestApp_mac/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + + diff --git a/KeychainEntitledTestApp_mac/ViewController.h b/KeychainEntitledTestApp_mac/ViewController.h new file mode 100644 index 00000000..3a40d4b2 --- /dev/null +++ b/KeychainEntitledTestApp_mac/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// KeychainEntitledTestApp_mac +// +// Copyright (c) 2017 Apple Inc. All rights reserved. +// +// + +#import + +@interface ViewController : NSViewController + + +@end + diff --git a/KeychainEntitledTestApp_mac/ViewController.m b/KeychainEntitledTestApp_mac/ViewController.m new file mode 100644 index 00000000..452e7570 --- /dev/null +++ b/KeychainEntitledTestApp_mac/ViewController.m @@ -0,0 +1,27 @@ +// +// 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 new file mode 100644 index 00000000..bc0cd59e --- /dev/null +++ b/KeychainEntitledTestApp_mac/main.m @@ -0,0 +1,13 @@ +// +// main.m +// KeychainEntitledTestApp_mac +// +// Copyright (c) 2017 Apple Inc. All rights reserved. +// +// + +#import + +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); +} diff --git a/KeychainSyncAccountNotification/KeychainSyncAccountNotification-Info.plist b/KeychainSyncAccountNotification/KeychainSyncAccountNotification-Info.plist index d11ac900..40f3f2ea 100644 --- a/KeychainSyncAccountNotification/KeychainSyncAccountNotification-Info.plist +++ b/KeychainSyncAccountNotification/KeychainSyncAccountNotification-Info.plist @@ -24,5 +24,9 @@ ${CURRENT_PROJECT_VERSION} NSPrincipalClass KeychainSyncAccountNotification + ACSupportedAccountTypes + + com.apple.account.AppleAccount + diff --git a/KeychainSyncAccountNotification/KeychainSyncAccountNotification.m b/KeychainSyncAccountNotification/KeychainSyncAccountNotification.m index be7452c4..2aeb9955 100644 --- a/KeychainSyncAccountNotification/KeychainSyncAccountNotification.m +++ b/KeychainSyncAccountNotification/KeychainSyncAccountNotification.m @@ -12,15 +12,12 @@ #import #endif #import -#import -#import #import #import "utilities/debugging.h" @implementation KeychainSyncAccountNotification - - (bool)accountIsPrimary:(ACAccount *)account { #if TARGET_OS_IPHONE @@ -31,48 +28,28 @@ } - (BOOL)account:(ACAccount *)account willChangeWithType:(ACAccountChangeType)changeType inStore:(ACDAccountStore *)store oldAccount:(ACAccount *)oldAccount { + NSString* oldAccountIdentifier = oldAccount.identifier; + NSString* accountIdentifier = account.identifier; if ((changeType == kACAccountChangeTypeDeleted) && [oldAccount.accountType.identifier isEqualToString:ACAccountTypeIdentifierAppleAccount]) { - if(oldAccount.identifier != NULL && oldAccount.username !=NULL){ - + if(oldAccountIdentifier != NULL && oldAccount.username !=NULL) { if ([self accountIsPrimary:oldAccount]) { - CFErrorRef removalError = NULL; - secinfo("accounts", "Performing SOS circle credential removal for account %@: %@", oldAccount.identifier, oldAccount.username); + secinfo("accounts", "Performing SOS circle credential removal for account %@: %@", oldAccountIdentifier, oldAccount.username); if (!SOSCCLoggedOutOfAccount(&removalError)) { - secerror("Account %@ could not leave the SOS circle: %@", oldAccount.identifier, removalError); + secerror("Account %@ could not leave the SOS circle: %@", oldAccountIdentifier, removalError); } } else { - secinfo("accounts", "NOT performing SOS circle credential removal for secondary account %@: %@", account.identifier, account.username); + secinfo("accounts", "NOT performing SOS circle credential removal for secondary account %@: %@", accountIdentifier, account.username); } - } - else{ + } else{ secinfo("accounts", "Already logged out of account"); - } } return YES; } -- (void)account:(ACAccount *)account didChangeWithType:(ACAccountChangeType)changeType inStore:(ACDAccountStore *)store oldAccount:(ACAccount *)oldAccount { - if (changeType == kACAccountChangeTypeDeleted) { - if (oldAccount.identifier != NULL && oldAccount.username != NULL){ - - if ([self accountIsPrimary:oldAccount]) { - CFErrorRef removalError = NULL; - secinfo("accounts", "Performing SOS circle credential removal for account %@: %@", oldAccount.identifier, oldAccount.username); - if (!SOSCCLoggedOutOfAccount(&removalError)) { - secerror("Account %@ could not leave the SOS circle: %@", oldAccount.identifier, removalError); - } - } else { - secinfo("accounts", "NOT performing SOS circle credential removal for secondary account %@: %@", account.identifier, account.username); - } - } - secinfo("accounts", "Already logged out of account"); - } -} - @end diff --git a/KeychainSyncAccountUpdater/Info.plist b/KeychainSyncAccountUpdater/Info.plist new file mode 100644 index 00000000..822558c5 --- /dev/null +++ b/KeychainSyncAccountUpdater/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSPrincipalClass + KeychainSyncAccountUpdater + + diff --git a/KeychainSyncAccountUpdater/KeychainSyncAccountUpdater.h b/KeychainSyncAccountUpdater/KeychainSyncAccountUpdater.h new file mode 100644 index 00000000..5c10c1f3 --- /dev/null +++ b/KeychainSyncAccountUpdater/KeychainSyncAccountUpdater.h @@ -0,0 +1,5 @@ +#import + +@interface KeychainSyncAccountUpdater : NSObject + +@end diff --git a/KeychainSyncAccountUpdater/KeychainSyncAccountUpdater.m b/KeychainSyncAccountUpdater/KeychainSyncAccountUpdater.m new file mode 100644 index 00000000..694979f4 --- /dev/null +++ b/KeychainSyncAccountUpdater/KeychainSyncAccountUpdater.m @@ -0,0 +1,20 @@ +#include +#include + +#import "KeychainSyncAccountUpdater.h" + +@implementation KeychainSyncAccountUpdater + +- (BOOL)includePluginInUpdateSession:(nonnull UpdaterSessionParameters *)parameters +{ + return YES; +} + +- (void)updateAccountWithPrivilege +{ + CFPreferencesSetValue(CFSTR("SecItemSynchronizable"), kCFBooleanTrue, CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + Boolean okay = CFPreferencesAppSynchronize(CFSTR("com.apple.security")); + os_log(OS_LOG_DEFAULT, "EnableKeychainSync %d", okay); +} + +@end diff --git a/KeychainSyncingOverIDSProxy/IDSProxy.h b/KeychainSyncingOverIDSProxy/IDSProxy.h index 9bd680b0..9985fe04 100644 --- a/KeychainSyncingOverIDSProxy/IDSProxy.h +++ b/KeychainSyncingOverIDSProxy/IDSProxy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,16 +21,13 @@ * @APPLE_LICENSE_HEADER_END@ */ -// -// IDSProxy.h -// ids-xpc - #import #import #import #import #import "SOSCloudKeychainClient.h" #import +#import typedef enum { kIDSStartPingTestMessage = 1, @@ -42,17 +39,6 @@ typedef enum { kIDSKeychainSyncIDSFragmentation = 8, } idsOperation; -typedef enum { - kSecIDSErrorNoDeviceID = -1, //default case - kSecIDSErrorNotRegistered = -2, - kSecIDSErrorFailedToSend=-3, - kSecIDSErrorCouldNotFindMatchingAuthToken = -4, - kSecIDSErrorDeviceIsLocked = -5, - kSecIDSErrorNoPeersAvailable = -6 - -} idsError; - - @interface KeychainSyncingOverIDSProxy : NSObject { IDSService *_service; @@ -61,26 +47,36 @@ typedef enum { } @property (retain, nonatomic) NSMutableDictionary *deviceIDFromAuthToken; -@property (retain, nonatomic) NSString *deviceID; -@property (retain, nonatomic) NSMutableDictionary *unhandledMessageBuffer; +@property (retain, nonatomic) NSString *deviceID; @property (retain, nonatomic) NSMutableDictionary *shadowPendingMessages; @property (retain, nonatomic) NSMutableDictionary *allFragmentedMessages; -@property (retain, nonatomic) NSMutableDictionary *pingTimers; +@property (retain, atomic) NSMutableDictionary *pingTimers; +@property (retain, nonatomic) NSMutableDictionary *peerNextSendCache; //dictionary of device ID -> time stamp of when to send next + +// Only touch these three dictionaries from the dataQueue or you will crash, eventually. @property (retain, nonatomic) NSMutableDictionary *messagesInFlight; -@property (retain, nonatomic) NSMutableDictionary *peerNextSendCache; //dictioanry of device ID -> time stamp of when to send next +@property (retain, nonatomic) NSMutableDictionary *unhandledMessageBuffer; +@property (retain, nonatomic) NSMutableDictionary *monitor; + +@property (retain, nonatomic) NSArray* listOfDevices; -@property (retain, nonatomic) NSArray* listOfDevices; +@property (atomic) dispatch_source_t penaltyTimer; +@property (atomic) bool penaltyTimerScheduled; +@property (retain, atomic) NSDictionary *queuedMessages; -@property (atomic) dispatch_source_t penaltyTimer; -@property (atomic) bool penaltyTimerScheduled; -@property (retain, atomic) NSMutableDictionary *monitor; -@property (retain, atomic) NSDictionary *queuedMessages; +@property (retain, atomic) NSMutableDictionary *counterValues; +@property (atomic) NSInteger outgoingMessages; +@property (atomic) NSInteger incomingMessages; @property (atomic) bool isIDSInitDone; @property (atomic) bool shadowDoInitializeIDSService; @property (atomic) bool isSecDRunningAsRoot; @property (atomic) bool doesSecDHavePeer; + @property (atomic) dispatch_queue_t calloutQueue; +@property (atomic) dispatch_queue_t pingQueue; +@property dispatch_queue_t dataQueue; + @property (atomic) bool isLocked; @property (atomic) bool unlockedSinceBoot; @property (atomic) dispatch_source_t retryTimer; @@ -97,17 +93,23 @@ typedef enum { - (id)init; -- (void) importIDSState: (NSMutableDictionary*) state; - - (void) doSetIDSDeviceID; - (void) doIDSInitialization; -- (void) calloutWith: (void(^)(NSMutableDictionary *pending, bool handlePendingMesssages, bool doSetDeviceID, dispatch_queue_t queue, void(^done)(NSMutableDictionary *handledMessages, bool handledPendingMessage, bool handledSettingDeviceID))) callout; +- (void) calloutWith: (void(^)(NSMutableDictionary *pending, + bool handlePendingMesssages, + bool doSetDeviceID, + dispatch_queue_t queue, + void(^done)(NSMutableDictionary *handledMessages, + bool handledPendingMessage, + bool handledSettingDeviceID))) callout; - (void) sendKeysCallout: (NSMutableDictionary *(^)(NSMutableDictionary* pending, NSError** error)) handleMessages; -- (void)persistState; +- (void) persistState; - (void) sendPersistedMessagesAgain; - (NSDictionary*) retrievePendingMessages; - -- (void)scheduleRetryRequestTimer; +- (NSDictionary*) collectStats; +- (void) scheduleRetryRequestTimer; +- (BOOL) haveMessagesInFlight; @end -NSString* createErrorString(NSString* format, ...); +NSString* createErrorString(NSString* format, ...) + NS_FORMAT_FUNCTION(1, 2); diff --git a/KeychainSyncingOverIDSProxy/IDSProxy.m b/KeychainSyncingOverIDSProxy/IDSProxy.m index 29f8e1ae..c6cbe5bb 100644 --- a/KeychainSyncingOverIDSProxy/IDSProxy.m +++ b/KeychainSyncingOverIDSProxy/IDSProxy.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,12 +21,6 @@ * @APPLE_LICENSE_HEADER_END@ */ -// -// IDSProxy.m -// ids-xpc -// - - #import #import @@ -51,7 +45,6 @@ #import "IDSProxy.h" #import "KeychainSyncingOverIDSProxy+ReceiveMessage.h" #import "KeychainSyncingOverIDSProxy+SendMessage.h" -#import "KeychainSyncingOverIDSProxy+Throttle.h" #import "IDSPersistentState.h" #define kSecServerKeychainChangedNotification "com.apple.security.keychainchanged" @@ -62,16 +55,15 @@ static NSString *kMonitorState = @"MonitorState"; static NSString *kExportUnhandledMessages = @"UnhandledMessages"; static NSString *kMessagesInFlight = @"MessagesInFlight"; static const char *kStreamName = "com.apple.notifyd.matching"; -static NSString *const kIDSMessageRecipientPeerID = @"RecipientPeerID"; -static NSString *const kIDSMessageRecipientDeviceID = @"RecipientDeviceID"; static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; +static NSString *const kOutgoingMessages = @"IDS Outgoing Messages"; +static NSString *const kIncomingMessages = @"IDS Incoming Messages"; + NSString *const IDSSendMessageOptionForceEncryptionOffKey = @"IDSSendMessageOptionForceEncryptionOff"; static const int64_t kRetryTimerLeeway = (NSEC_PER_MSEC * 250); // 250ms leeway for handling unhandled messages. static const int64_t kMinMessageRetryDelay = (NSEC_PER_SEC * 8); - -CFIndex kSOSErrorPeerNotFound = 1032; CFIndex SECD_RUN_AS_ROOT_ERROR = 1041; #define IDSPROXYSCOPE "IDSProxy" @@ -95,44 +87,96 @@ CFIndex SECD_RUN_AS_ROOT_ERROR = 1041; -(NSDictionary*) exportState { - return @{ kMonitorState:_monitor, - kExportUnhandledMessages:_unhandledMessageBuffer, - kMessagesInFlight:_messagesInFlight + return @{ kMonitorState:self.monitor, + kExportUnhandledMessages:self.unhandledMessageBuffer, + kMessagesInFlight:self.messagesInFlight }; } -(NSDictionary*) retrievePendingMessages { - return [KeychainSyncingOverIDSProxy idsProxy].messagesInFlight; + NSDictionary * __block messages; + dispatch_sync(self.dataQueue, ^{ + messages = [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight copy]; + }); + return messages; +} + +@synthesize unhandledMessageBuffer = _unhandledMessageBuffer; + +- (NSMutableDictionary *) unhandledMessageBuffer { + dispatch_assert_queue(self.dataQueue); + return _unhandledMessageBuffer; +} + +- (void) setUnhandledMessageBuffer:(NSMutableDictionary *)unhandledMessageBuffer { + dispatch_assert_queue(self.dataQueue); + _unhandledMessageBuffer = unhandledMessageBuffer; } -- (void)persistState +@ synthesize messagesInFlight = _messagesInFlight; + +- (NSMutableDictionary *) messagesInFlight { + dispatch_assert_queue(self.dataQueue); + return _messagesInFlight; +} + +- (void) setMessagesInFlight:(NSMutableDictionary *)messagesInFlight { + dispatch_assert_queue(self.dataQueue); + _messagesInFlight = messagesInFlight; +} + +@synthesize monitor = _monitor; + +- (NSMutableDictionary *) monitor { + dispatch_assert_queue(self.dataQueue); + return _monitor; +} + +- (void) setMonitor:(NSMutableDictionary *)monitor { + dispatch_assert_queue(self.dataQueue); + _monitor = monitor; +} + +- (void) persistState { - [KeychainSyncingOverIDSProxyPersistentState setUnhandledMessages:[self exportState]]; + dispatch_sync(self.dataQueue, ^{ + [KeychainSyncingOverIDSProxyPersistentState setUnhandledMessages:[self exportState]]; + }); +} + +- (BOOL) haveMessagesInFlight { + BOOL __block inFlight = NO; + dispatch_sync(self.dataQueue, ^{ + inFlight = [self.messagesInFlight count] > 0; + }); + return inFlight; } - (void) sendPersistedMessagesAgain { - NSMutableDictionary *copy = [NSMutableDictionary dictionaryWithDictionary:_messagesInFlight]; + NSMutableDictionary * __block copy; + + dispatch_sync(self.dataQueue, ^{ + copy = [NSMutableDictionary dictionaryWithDictionary:self.messagesInFlight]; + }); if(copy && [copy count] > 0){ [copy enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { NSDictionary* idsMessage = (NSDictionary*)obj; NSString *uniqueMessageID = (NSString*)key; - NSString *peerID = (NSString*)[idsMessage objectForKey:kIDSMessageRecipientPeerID]; - if(!peerID){ - [self->_messagesInFlight removeObjectForKey:key]; - return; - } - NSString *ID = (NSString*)[idsMessage objectForKey:kIDSMessageRecipientDeviceID]; - if(!ID){ - [self->_messagesInFlight removeObjectForKey:key]; + NSString *peerID = (NSString*)[idsMessage objectForKey:(__bridge NSString*)kIDSMessageRecipientPeerID]; + NSString *ID = (NSString*)[idsMessage objectForKey:(__bridge NSString*)kIDSMessageRecipientDeviceID]; + + dispatch_sync(self.dataQueue, ^{ + [self.messagesInFlight removeObjectForKey:key]; + }); + + if (!peerID || !ID) { return; } - - [self->_messagesInFlight removeObjectForKey:key]; secnotice("IDS Transport", "sending this message: %@", idsMessage); if([self sendIDSMessage:idsMessage name:ID peer:peerID]){ NSString *useAckModel = [idsMessage objectForKey:kIDSMessageUseACKModel]; @@ -145,21 +189,6 @@ CFIndex SECD_RUN_AS_ROOT_ERROR = 1041; } } -- (void) importIDSState: (NSMutableDictionary*) state -{ - _unhandledMessageBuffer = state[kExportUnhandledMessages]; - if(!_unhandledMessageBuffer) - _unhandledMessageBuffer = [NSMutableDictionary dictionary]; - - _monitor = state[kMonitorState]; - if(_monitor == nil) - _monitor = [NSMutableDictionary dictionary]; - - _messagesInFlight = state[kMessagesInFlight]; - if(_messagesInFlight == nil) - _messagesInFlight = [NSMutableDictionary dictionary]; -} - - (id)init { if (self = [super init]) @@ -169,13 +198,15 @@ CFIndex SECD_RUN_AS_ROOT_ERROR = 1041; _isIDSInitDone = false; _service = nil; _calloutQueue = dispatch_queue_create("IDSCallout", DISPATCH_QUEUE_SERIAL); - _unhandledMessageBuffer = [ [NSMutableDictionary alloc] initWithCapacity: 0]; - _pingTimers = [ [NSMutableDictionary alloc] initWithCapacity: 0]; - _messagesInFlight = [ [NSMutableDictionary alloc] initWithCapacity: 0]; - deviceIDFromAuthToken = [ [NSMutableDictionary alloc] initWithCapacity: 0]; - _peerNextSendCache = [ [NSMutableDictionary alloc] initWithCapacity: 0]; - - _listOfDevices = [[NSMutableArray alloc] initWithCapacity:0]; + _pingQueue = dispatch_queue_create("PingQueue", DISPATCH_QUEUE_SERIAL); + _dataQueue = dispatch_queue_create("DataQueue", DISPATCH_QUEUE_SERIAL); + _pingTimers = [[NSMutableDictionary alloc] init]; + deviceIDFromAuthToken = [[NSMutableDictionary alloc] init]; + _peerNextSendCache = [[NSMutableDictionary alloc] init]; + _counterValues = [[NSMutableDictionary alloc] init]; + _listOfDevices = [[NSMutableArray alloc] init]; + _outgoingMessages = 0; + _incomingMessages = 0; _isSecDRunningAsRoot = false; _doesSecDHavePeer = true; secdebug(IDSPROXYSCOPE, "%@ done", self); @@ -183,8 +214,7 @@ CFIndex SECD_RUN_AS_ROOT_ERROR = 1041; [self doIDSInitialization]; if(_isIDSInitDone) [self doSetIDSDeviceID]; - - + // Register for lock state changes xpc_set_event_stream_handler(kStreamName, dispatch_get_main_queue(), ^(xpc_object_t notification){ @@ -197,24 +227,37 @@ CFIndex SECD_RUN_AS_ROOT_ERROR = 1041; [self timerFired]; }); dispatch_resume(_retryTimer); - [self importIDSState: [KeychainSyncingOverIDSProxyPersistentState idsState]]; + NSMutableDictionary *state = [KeychainSyncingOverIDSProxyPersistentState idsState]; + _unhandledMessageBuffer = state[kExportUnhandledMessages]; + if (!_unhandledMessageBuffer) { + _unhandledMessageBuffer = [NSMutableDictionary dictionary]; + } + _messagesInFlight = state[kMessagesInFlight]; + if(_messagesInFlight == nil) { + _messagesInFlight = [NSMutableDictionary dictionary]; + } + _monitor = state[kMonitorState]; + if(_monitor == nil) { + _monitor = [NSMutableDictionary dictionary]; + } + if([_messagesInFlight count ] > 0) _sendRestoredMessages = true; int notificationToken; - notify_register_dispatch(kSecServerKeychainChangedNotification, ¬ificationToken, dispatch_get_main_queue(), + notify_register_dispatch(kSecServerKeychainChangedNotification, ¬ificationToken, self.dataQueue, ^ (int token __unused) { secinfo("backoff", "keychain changed, wiping backoff monitor state"); - self->_monitor = [NSMutableDictionary dictionary]; + self.monitor = [NSMutableDictionary dictionary]; }); int peerInfo; notify_register_dispatch(kSecServerPeerInfoAvailable, &peerInfo, dispatch_get_main_queue(), ^ (int token __unused) { secinfo("IDS Transport", "secd has a peer info"); - if(self->_doesSecDHavePeer == false){ - self->_doesSecDHavePeer = true; + if(self.doesSecDHavePeer == false){ + self.doesSecDHavePeer = true; [self doSetIDSDeviceID]; } }); @@ -300,18 +343,23 @@ CFIndex SECD_RUN_AS_ROOT_ERROR = 1041; - (void)timerFired { - if(_unhandledMessageBuffer) - secnotice("IDS Transport", "%@ attempting to hand unhandled messages to securityd, here is our message queue: %@", self, _unhandledMessageBuffer); - - if(_isLocked) - _retryTimerScheduled = NO; - else if([_unhandledMessageBuffer count] == 0) - _retryTimerScheduled = NO; - else if (_retryTimerScheduled && !_isLocked) + NSUInteger __block messagecount = 0; + dispatch_sync(self.dataQueue, ^{ + if(self.unhandledMessageBuffer) { + secnotice("IDS Transport", "%@ attempting to hand unhandled messages to securityd, here is our message queue: %@", self, self.unhandledMessageBuffer); + messagecount = [self.unhandledMessageBuffer count]; + } + }); + + if(self.isLocked) { + self.retryTimerScheduled = NO; + } else if(messagecount == 0) { + self.retryTimerScheduled = NO; + } else if (self.retryTimerScheduled && !self.isLocked) { [self handleAllPendingMessage]; - else + } else { [[KeychainSyncingOverIDSProxy idsProxy] scheduleRetryRequestTimer]; - + } } - (void)scheduleRetryRequestTimer @@ -445,14 +493,16 @@ CFIndex SECD_RUN_AS_ROOT_ERROR = 1041; __block bool myDoSetDeviceID; __block bool wasLocked; dispatch_sync(idsproxy_queue, ^{ - myPending = [self->_unhandledMessageBuffer copy]; - myHandlePendingMessage = self->_handleAllPendingMessages; - myDoSetDeviceID = self->_setIDSDeviceID; - wasLocked = self->_isLocked; + dispatch_sync(self.dataQueue, ^{ + myPending = [self.unhandledMessageBuffer copy]; + }); + myHandlePendingMessage = self.handleAllPendingMessages; + myDoSetDeviceID = self.setIDSDeviceID; + wasLocked = self.isLocked; - self->_inCallout = YES; + self.inCallout = YES; - self->_shadowHandleAllPendingMessages = NO; + self.shadowHandleAllPendingMessages = NO; }); callout(myPending, myHandlePendingMessage, myDoSetDeviceID, idsproxy_queue, ^(NSMutableDictionary *handledMessages, bool handledPendingMessage, bool handledSetDeviceID) { @@ -497,4 +547,12 @@ NSString* createErrorString(NSString* format, ...) } +- (NSDictionary*) collectStats{ + [_counterValues setObject:[NSNumber numberWithInteger:[KeychainSyncingOverIDSProxy idsProxy].outgoingMessages] forKey:kOutgoingMessages]; + [_counterValues setObject:[NSNumber numberWithInteger:[KeychainSyncingOverIDSProxy idsProxy].incomingMessages] forKey:kIncomingMessages]; + + return _counterValues; +} + + @end diff --git a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+ReceiveMessage.m b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+ReceiveMessage.m index d4e8cb00..05d2f626 100644 --- a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+ReceiveMessage.m +++ b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+ReceiveMessage.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -51,10 +51,7 @@ static NSString *const kIDSNumberOfFragments = @"NumberOfIDSMessageFragments"; static NSString *const kIDSFragmentIndex = @"kFragmentIndex"; -static NSString *const kIDSOperationType = @"IDSMessageOperation"; -static NSString *const kIDSMessageToSendKey = @"MessageToSendKey"; -static NSString *const kIDSMessageUniqueID = @"MessageID"; -static NSString *const kIDSMessageRecipientPeerID = @"RecipientPeerID"; +static NSString *const kIDSMessageRecipientID = @"RecipientPeerID"; static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; @implementation KeychainSyncingOverIDSProxy (ReceiveMessage) @@ -78,7 +75,7 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; if([message valueForKey:kIDSNumberOfFragments] != nil){ NSNumber *idsNumberOfFragments = [message objectForKey:kIDSNumberOfFragments]; NSNumber *index = [message objectForKey:kIDSFragmentIndex]; - NSString *uuidString = [message objectForKey:kIDSMessageUniqueID]; + NSString *uuidString = [message objectForKey:(__bridge NSString*)kIDSMessageUniqueID]; if([KeychainSyncingOverIDSProxy idsProxy].allFragmentedMessages == nil) [KeychainSyncingOverIDSProxy idsProxy].allFragmentedMessages = [NSMutableDictionary dictionary]; @@ -168,11 +165,11 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; NSString *operationString = [[NSString alloc] initWithUTF8String:messageCharS]; NSString* messageString = @"peer availability check finished"; - NSDictionary* messsageDictionary = @{kIDSOperationType:operationString, kIDSMessageToSendKey:messageString}; - + NSDictionary* messsageDictionary = @{(__bridge NSString*)kIDSOperationType:operationString, (__bridge NSString*)kIDSMessageToSendKey:messageString}; + // We can always hold on to a message and our remote peers would bother everyone [self sendIDSMessage:messsageDictionary name:ID peer:@"me"]; - + free(messageCharS); break; @@ -184,13 +181,18 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; //cancel timer! secnotice("IDS Transport", "received ack for: %@", uniqueID); - dispatch_source_t timer = [[KeychainSyncingOverIDSProxy idsProxy].pingTimers objectForKey:uniqueID]; - if(timer != nil){ - dispatch_cancel(timer); - [[KeychainSyncingOverIDSProxy idsProxy].pingTimers removeObjectForKey:uniqueID]; - [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight removeObjectForKey:uniqueID]; - [[KeychainSyncingOverIDSProxy idsProxy] persistState]; - } + dispatch_async(self.pingQueue, ^{ + //remove timer for message id + dispatch_source_t timer = [[KeychainSyncingOverIDSProxy idsProxy].pingTimers objectForKey:uniqueID]; + if(timer != nil){ + dispatch_cancel(timer); + [[KeychainSyncingOverIDSProxy idsProxy].pingTimers removeObjectForKey:uniqueID]; + dispatch_sync(self.dataQueue, ^{ + [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight removeObjectForKey:uniqueID]; + }); + [[KeychainSyncingOverIDSProxy idsProxy] persistState]; + } + }); //call out to securityd to set a NULL [self sendKeysCallout:^NSMutableDictionary *(NSMutableDictionary *pending, NSError** error) { @@ -213,23 +215,32 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; asprintf(&messageCharS, "%d",kIDSPeerReceivedACK); NSString *operationString = [[NSString alloc] initWithUTF8String:messageCharS]; - NSDictionary* messageDictionary = @{kIDSOperationType:operationString, kIDSMessageToSendKey:messageString, kIDSMessageUniqueID:uniqueID}; + NSDictionary* messageDictionary = @{(__bridge NSString*)kIDSOperationType:operationString, (__bridge NSString*)kIDSMessageToSendKey:messageString, (__bridge NSString*)kIDSMessageUniqueID:uniqueID}; [self sendIDSMessage:messageDictionary name:ID peer:sendersPeerID]; + free(messageCharS); } +- (void)updateDeviceList +{ + self.deviceIDFromAuthToken = nil; + self.deviceIDFromAuthToken = [NSMutableDictionary dictionary]; + [self calloutWith:^(NSMutableDictionary *pending, bool handlePendingMesssages, bool doSetDeviceID, dispatch_queue_t queue, void(^done)(NSMutableDictionary *, bool, bool)) { + }]; +} - (void)service:(IDSService *)service account:(IDSAccount *)account incomingMessage:(NSDictionary *)message fromID:(NSString *)fromID context:(IDSMessageContext *)context { NSString *dataKey = [ NSString stringWithUTF8String: kMessageKeyIDSDataMessage ]; NSString *deviceIDKey = [ NSString stringWithUTF8String: kMessageKeyDeviceID ]; NSString *peerIDKey = [ NSString stringWithUTF8String: kMessageKeyPeerID ]; NSString *sendersPeerIDKey = [NSString stringWithUTF8String: kMessageKeySendersPeerID]; + + [KeychainSyncingOverIDSProxy idsProxy].incomingMessages++; dispatch_async(self.calloutQueue, ^{ NSString* messageID = nil; - NSString *ID = nil; uint32_t operationType; bool hadError = false; CFStringRef errorMessage = NULL; @@ -238,8 +249,7 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; NSString* operationTypeAsString = nil; NSMutableDictionary *messageDictionary = nil; NSString *useAck = nil; - - + NSString *ID = nil; NSArray *devices = [self->_service devices]; for(NSUInteger i = 0; i < [ devices count ]; i++){ IDSDevice *device = devices[i]; @@ -257,10 +267,10 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; require_action_quiet(ID, fail, hadError = true; errorMessage = CFSTR("require the sender's device ID")); - operationTypeAsString = [message objectForKey: kIDSOperationType]; - messageDictionary = [message objectForKey: kIDSMessageToSendKey]; + operationTypeAsString = [message objectForKey: (__bridge NSString*)kIDSOperationType]; + messageDictionary = [message objectForKey: (__bridge NSString*)kIDSMessageToSendKey]; - messageID = [message objectForKey:kIDSMessageUniqueID]; + messageID = [message objectForKey:(__bridge NSString*)kIDSMessageUniqueID]; useAck = [message objectForKey:kIDSMessageUseACKModel]; if(useAck != nil && [useAck compare:@"YES"] == NSOrderedSame) @@ -288,7 +298,7 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; NSMutableDictionary *messageAndFromID = nil; if(readyToHandOffToSecD && ([message objectForKey:kIDSFragmentIndex])!= nil){ - NSString* uuid = [message objectForKey:kIDSMessageUniqueID]; + NSString* uuid = [message objectForKey:(__bridge NSString*)kIDSMessageUniqueID]; messageAndFromID = [self combineMessage:ID peerID:myPeerID uuid:uuid]; } else if(readyToHandOffToSecD){ @@ -302,7 +312,9 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; if([KeychainSyncingOverIDSProxy idsProxy].isLocked){ //hang on to the message and set the retry deadline - [self.unhandledMessageBuffer setObject: messageAndFromID forKey: fromID]; + dispatch_sync(self.dataQueue, ^{ + [self.unhandledMessageBuffer setObject: messageAndFromID forKey: fromID]; + }); } else [self sendMessageToSecurity:messageAndFromID fromID:fromID]; @@ -311,7 +323,6 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; fail: if(hadError) secerror("error:%@", errorMessage); - }); } @@ -319,24 +330,34 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; - (void) handleAllPendingMessage { secnotice("IDS Transport", "Attempting to handle pending messsages"); - if([self.unhandledMessageBuffer count] > 0){ - secnotice("IDS Transport", "handling Message: %@", self.unhandledMessageBuffer); - NSMutableDictionary *copyOfUnhanlded = [NSMutableDictionary dictionaryWithDictionary:self.unhandledMessageBuffer]; - [copyOfUnhanlded enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) - { - NSMutableDictionary *messageAndFromID = (NSMutableDictionary*)obj; - NSString *fromID = (NSString*)key; - //remove the message from the official message buffer (if it fails to get handled it'll be reset again in sendMessageToSecurity) + + NSMutableDictionary * __block copyOfUnhandled = nil; + dispatch_sync(self.dataQueue, ^{ + if ([self.unhandledMessageBuffer count] > 0) { + secnotice("IDS Transport", "handling messages: %@", self.unhandledMessageBuffer); + copyOfUnhandled = [NSMutableDictionary dictionaryWithDictionary:self.unhandledMessageBuffer]; + } + }); + + [copyOfUnhandled enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) + { + NSMutableDictionary *messageAndFromID = (NSMutableDictionary*)obj; + NSString *fromID = (NSString*)key; + //remove the message from the official message buffer (if it fails to get handled it'll be reset again in sendMessageToSecurity) + dispatch_sync(self.dataQueue, ^{ [self.unhandledMessageBuffer removeObjectForKey: fromID]; - [self sendMessageToSecurity:messageAndFromID fromID:fromID]; - }]; - } + }); + [self sendMessageToSecurity:messageAndFromID fromID:fromID]; + }]; } - (bool) shouldPersistMessage:(NSDictionary*) newMessageAndFromID id:(NSString*)fromID { //get the dictionary of messages for a particular device id - NSDictionary* messagesFromBuffer = [self.unhandledMessageBuffer valueForKey:fromID]; + NSDictionary* __block messagesFromBuffer; + dispatch_sync(self.dataQueue, ^{ + messagesFromBuffer = [self.unhandledMessageBuffer valueForKey:fromID]; + }); if([messagesFromBuffer isEqual:newMessageAndFromID]) return false; @@ -362,31 +383,39 @@ static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; if(success == kHandleIDSMessageLocked){ secnotice("IDS Transport","cannot handle messages from: %@ when locked, error:%@", fromID, cf_error); - if(!self.unhandledMessageBuffer) - self.unhandledMessageBuffer = [NSMutableDictionary dictionary]; + // I don't think this is ever nil but it was like this when I got here + dispatch_sync(self.dataQueue, ^{ + if(!self.unhandledMessageBuffer) { + self.unhandledMessageBuffer = [NSMutableDictionary dictionary]; + } + }); //write message to disk if message is new to the unhandled queue - if([self shouldPersistMessage:messageAndFromID id:fromID]) + if([self shouldPersistMessage:messageAndFromID id:fromID]) { [self persistState]; + } - [self.unhandledMessageBuffer setObject: messageAndFromID forKey: fromID]; - secnotice("IDS Transport", "unhandledMessageBuffer: %@", self.unhandledMessageBuffer); + dispatch_sync(self.dataQueue, ^{ + [self.unhandledMessageBuffer setObject: messageAndFromID forKey: fromID]; + secnotice("IDS Transport", "unhandledMessageBuffer: %@", self.unhandledMessageBuffer); + }); return NULL; } else if(success == kHandleIDSMessageNotReady){ secnotice("IDS Transport","not ready to handle message from: %@, error:%@", fromID, cf_error); - if(!self.unhandledMessageBuffer) - self.unhandledMessageBuffer = [NSMutableDictionary dictionary]; - [self.unhandledMessageBuffer setObject: messageAndFromID forKey: fromID]; - secnotice("IDS Transport","unhandledMessageBuffer: %@", self.unhandledMessageBuffer); - //set timer - [[KeychainSyncingOverIDSProxy idsProxy] scheduleRetryRequestTimer]; - + dispatch_sync(self.dataQueue, ^{ + if(!self.unhandledMessageBuffer) { + self.unhandledMessageBuffer = [NSMutableDictionary dictionary]; + } + [self.unhandledMessageBuffer setObject: messageAndFromID forKey: fromID]; + secnotice("IDS Transport","unhandledMessageBuffer: %@", self.unhandledMessageBuffer); + }); //write message to disk if message is new to the unhandled queue if([self shouldPersistMessage:messageAndFromID id:fromID]) [self persistState]; - + + [[KeychainSyncingOverIDSProxy idsProxy] scheduleRetryRequestTimer]; return NULL; } else if(success == kHandleIDSmessageDeviceIDMismatch){ diff --git a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+SendMessage.m b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+SendMessage.m index 7d93be01..3136a7e7 100644 --- a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+SendMessage.m +++ b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+SendMessage.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -45,8 +45,6 @@ #import "IDSProxy.h" #import "IDSPersistentState.h" #import "KeychainSyncingOverIDSProxy+SendMessage.h" -#import "KeychainSyncingOverIDSProxy+Throttle.h" - #include @@ -54,11 +52,6 @@ static NSString *const IDSSendMessageOptionForceEncryptionOffKey = @"IDSSendMess static NSString *const kIDSNumberOfFragments = @"NumberOfIDSMessageFragments"; static NSString *const kIDSFragmentIndex = @"kFragmentIndex"; -static NSString *const kIDSOperationType = @"IDSMessageOperation"; -static NSString *const kIDSMessageToSendKey = @"MessageToSendKey"; -static NSString *const kIDSMessageUniqueID = @"MessageID"; -static NSString *const kIDSMessageRecipientPeerID = @"RecipientPeerID"; -static NSString *const kIDSMessageRecipientDeviceID = @"RecipientDeviceID"; static NSString *const kIDSMessageUseACKModel = @"UsesAckModel"; static NSString *const kIDSDeviceID = @"deviceID"; @@ -81,7 +74,7 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; int startingPosition = 0; NSUInteger totalNumberOfFragments = (keychainDataLength + kMaxIDSMessagePayloadSize - 1)/kMaxIDSMessagePayloadSize; - + secnotice("IDS Transport", "sending %lu number of fragments to: %@", (unsigned long)totalNumberOfFragments, deviceName); NSMutableDictionary* fragmentDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys: deviceName, kIDSDeviceID, [NSNumber numberWithUnsignedInteger:totalNumberOfFragments], kIDSNumberOfFragments, @@ -98,7 +91,7 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; // Insert the current fragment data in dictionary with key peerID and message key. [fragmentDictionary setObject:@{theirPeerID:fragment} - forKey:kIDSMessageToSendKey]; + forKey:(__bridge NSString*)kIDSMessageToSendKey]; // Insert the fragment number in the dictionary [fragmentDictionary setObject:[NSNumber numberWithInt:fragmentIndex] forKey:kIDSFragmentIndex]; @@ -155,12 +148,14 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; //call securityd to sync with device over KVS __block CFErrorRef cf_error = NULL; __block bool success = kHandleIDSMessageSuccess; - - dispatch_source_t timer = [[KeychainSyncingOverIDSProxy idsProxy].pingTimers objectForKey:IDSid]; //remove timer - dispatch_cancel(timer); //cancel timer - - [[KeychainSyncingOverIDSProxy idsProxy].pingTimers removeObjectForKey:IDSid]; - + + //cleanup timers + dispatch_async(self.pingQueue, ^{ + dispatch_source_t timer = [[KeychainSyncingOverIDSProxy idsProxy].pingTimers objectForKey:IDSid]; //remove timer + dispatch_cancel(timer); //cancel timer + [[KeychainSyncingOverIDSProxy idsProxy].pingTimers removeObjectForKey:IDSid]; + }); + [self sendKeysCallout:^NSMutableDictionary *(NSMutableDictionary *pending, NSError** error) { success = SOSCCRequestSyncWithPeerOverKVSUsingIDOnly(((__bridge CFStringRef)IDSid), &cf_error); @@ -179,41 +174,37 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; -(void) pingDevices:(NSArray*)list peerID:(NSString*)peerID { - NSDictionary *messageDictionary = @{kIDSOperationType : [NSString stringWithFormat:@"%d", kIDSPeerAvailability], kIDSMessageToSendKey : @"checking peers"}; + NSDictionary *messageDictionary = @{(__bridge NSString*)kIDSOperationType : [NSString stringWithFormat:@"%d", kIDSPeerAvailability], (__bridge NSString*)kIDSMessageToSendKey : @"checking peers"}; [list enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * top) { NSString* IDSid = (NSString*)obj; NSString* identifier = [NSString string]; bool result = false; secnotice("IDS Transport", "sending to id: %@", IDSid); - - [self recordTimestampOfWriteToIDS: messageDictionary deviceName:IDSid peerID:peerID]; //add pings to throttling - NSDictionary *safeValues = [self filterForWritableValues:messageDictionary]; - if(safeValues != nil && [safeValues count] > 0){ - result = [self sendIDSMessage:safeValues name:IDSid peer:peerID]; - - if(!result){ - secerror("Could not send message over IDS"); - [self sendKeysCallout:^NSMutableDictionary *(NSMutableDictionary *pending, NSError** error) { - CFErrorRef kvsError = nil; - bool success = SOSCCRequestSyncWithPeerOverKVSUsingIDOnly(((__bridge CFStringRef)IDSid), &kvsError); - - if(success){ - secnotice("IDSPing", "sent peerID: %@ to securityd to sync over KVS", IDSid); - } - else{ - secerror("Could not hand peerID: %@ to securityd, error: %@", IDSid, kvsError); - } - CFReleaseNull(kvsError); - return NULL; - }]; - } - else{ - dispatch_source_t timer = nil; + result = [self sendIDSMessage:messageDictionary name:IDSid peer:peerID]; + + if(!result){ + secerror("Could not send message over IDS"); + [self sendKeysCallout:^NSMutableDictionary *(NSMutableDictionary *pending, NSError** error) { + CFErrorRef kvsError = nil; + bool success = SOSCCRequestSyncWithPeerOverKVSUsingIDOnly(((__bridge CFStringRef)IDSid), &kvsError); + + if(success){ + secnotice("IDSPing", "sent peerID: %@ to securityd to sync over KVS", IDSid); + } + else{ + secerror("Could not hand peerID: %@ to securityd, error: %@", IDSid, kvsError); + } + CFReleaseNull(kvsError); + return NULL; + }]; + } + else{ + dispatch_async(self.pingQueue, ^{ + //create a timer! if( [self.pingTimers objectForKey:IDSid] == nil){ - timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); - + dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, kRetryTimerLeeway); dispatch_source_set_event_handler(timer, ^{ [self pingTimerFired:IDSid peerID:peerID identifier:identifier]; @@ -222,10 +213,9 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; [self.pingTimers setObject:timer forKey:IDSid]; } - } + }); } }]; - } -(BOOL) shouldProxySendMessage:(NSString*)deviceName @@ -255,12 +245,12 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; -(BOOL) isMessageAPing:(NSDictionary*)data { - NSDictionary *messageDictionary = [data objectForKey: kIDSMessageToSendKey]; + NSDictionary *messageDictionary = [data objectForKey: (__bridge NSString*)kIDSMessageToSendKey]; BOOL isPingMessage = false; if(messageDictionary && ![messageDictionary isKindOfClass:[NSDictionary class]]) { - NSString* messageString = [data objectForKey: kIDSMessageToSendKey]; + NSString* messageString = [data objectForKey: (__bridge NSString*)kIDSMessageToSendKey]; if(messageString && [messageString isKindOfClass:[NSString class]]) isPingMessage = true; } @@ -278,11 +268,11 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; NSError* localError = nil; - NSString* operationTypeAsString = [data objectForKey: kIDSOperationType]; - NSMutableDictionary *messageDictionary = [data objectForKey: kIDSMessageToSendKey]; + NSString* operationTypeAsString = [data objectForKey: (__bridge NSString*)kIDSOperationType]; + NSMutableDictionary *messageDictionary = [data objectForKey: (__bridge NSString*)kIDSMessageToSendKey]; isPingMessage = [self isMessageAPing:data]; - + //check the peer cache for the next time to send timestamp //if the timestamp is set in the future, reroute the message to KVS //otherwise send the message over IDS @@ -298,7 +288,7 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; return true; } } - + if(isPingMessage){ //foward the ping message, no processing result = [self sendIDSMessage:data name:deviceName @@ -326,6 +316,7 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; }]; if(fragment && keychainData && [keychainData length] >= kMaxIDSMessagePayloadSize){ + secnotice("IDS Transport","sending chunked keychain messages"); result = [self chunkAndSendKeychainPayload:keychainData deviceID:deviceName ourPeerID:ourPeerID @@ -336,7 +327,7 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; } else{ NSMutableDictionary* dataCopy = [NSMutableDictionary dictionaryWithDictionary:data]; - [dataCopy setObject:localMessageIdentifier forKey:kIDSMessageUniqueID]; + [dataCopy setObject:localMessageIdentifier forKey:(__bridge NSString*)kIDSMessageUniqueID]; result = [self sendIDSMessage:dataCopy name:deviceName peer:ourPeerID]; @@ -366,19 +357,24 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; secnotice("IDS Transport", "IDS device id: %@, Ping timeout is up for message identifier: %@", ID, identifier); //call securityd to sync with device over KVS - NSMutableDictionary *message = [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight objectForKey:identifier]; + NSMutableDictionary * __block message; + dispatch_sync(self.dataQueue, ^{ + message = [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight objectForKey:identifier]; + [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight removeObjectForKey:identifier]; + }); if(!message){ return; } - NSDictionary *encapsulatedKeychainMessage = [message objectForKey:kIDSMessageToSendKey]; - - [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight removeObjectForKey:identifier]; + NSDictionary *encapsulatedKeychainMessage = [message objectForKey:(__bridge NSString*)kIDSMessageToSendKey]; secnotice("IDS Transport", "Encapsulated message: %@", encapsulatedKeychainMessage); - dispatch_source_t timer = [[KeychainSyncingOverIDSProxy idsProxy].pingTimers objectForKey:identifier]; //remove timer - dispatch_cancel(timer); //cancel timer - - [[KeychainSyncingOverIDSProxy idsProxy].pingTimers removeObjectForKey:identifier]; + //cleanup timers + dispatch_async(self.pingQueue, ^{ + dispatch_source_t timer = [[KeychainSyncingOverIDSProxy idsProxy].pingTimers objectForKey:identifier]; //remove timer + if(timer != nil) + dispatch_cancel(timer); //cancel timer + [[KeychainSyncingOverIDSProxy idsProxy].pingTimers removeObjectForKey:identifier]; + }); [self sendMessageToKVS:encapsulatedKeychainMessage]; @@ -399,11 +395,55 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; dispatch_resume(timer); //restructure message in flight - [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight setObject:message forKey:identifier]; - [self.pingTimers setObject:timer forKey:identifier]; + + + //set the timer for message id + dispatch_async(self.pingQueue, ^{ + [self.pingTimers setObject:timer forKey:identifier]; + }); + + dispatch_sync(self.dataQueue, ^{ + [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight setObject:message forKey:identifier]; + }); [[KeychainSyncingOverIDSProxy idsProxy] persistState]; } +//had an immediate error, remove it from messages in flight, and immediately send it over KVS +-(void) cleanupAfterHardIDSError:(NSDictionary*)data +{ + NSString *messageIdentifier = [data objectForKey:(__bridge NSString*)kIDSMessageUniqueID]; + NSMutableDictionary * __block messageToSendToKVS = nil; + + if(messageIdentifier != nil){ + secerror("removing message id: %@ from message timers", messageIdentifier); + dispatch_sync(self.dataQueue, ^{ + messageToSendToKVS = [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight objectForKey:messageIdentifier]; + [[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight removeObjectForKey:messageIdentifier]; + }); + if(!messageToSendToKVS){ + secnotice("IDS Transport", "no message for identifier: %@", messageIdentifier); + return; + } + secnotice("IDS Transport", "sending over KVS: %@", messageToSendToKVS); + + + + //cleanup timer for message + dispatch_async(self.pingQueue, ^{ + dispatch_source_t timer = [[KeychainSyncingOverIDSProxy idsProxy].pingTimers objectForKey:messageIdentifier]; //remove timer + if(timer) + dispatch_cancel(timer); //cancel timer + [[KeychainSyncingOverIDSProxy idsProxy].pingTimers removeObjectForKey:messageIdentifier]; + }); + } + + NSDictionary *encapsulatedKeychainMessage = [messageToSendToKVS objectForKey:(__bridge NSString*)kIDSMessageToSendKey]; + + if([encapsulatedKeychainMessage isKindOfClass:[NSDictionary class]]){ + secnotice("IDS Transport", "Encapsulated message: %@", encapsulatedKeychainMessage); + [self sendMessageToKVS:encapsulatedKeychainMessage]; + } +} -(BOOL) sendIDSMessage:(NSDictionary*)data name:(NSString*) deviceName peer:(NSString*) peerID { @@ -453,19 +493,18 @@ static const NSUInteger kMaxIDSMessagePayloadSize = 64000; bool result = [self->_service sendMessage:dataCopy toDestinations:destinations priority:priority options:options identifier:&identifier error:&localError ] ; + [KeychainSyncingOverIDSProxy idsProxy].outgoingMessages++; require_action_quiet(localError == nil && result, fail, errorCode = kSecIDSErrorFailedToSend; errMessage = createErrorString(@"Had an error sending IDS message to peer: %@", deviceName)); secnotice("IDS Transport","successfully sent to peer:%@, message: %@", deviceName, dataCopy); fail: - - info = [ NSDictionary dictionaryWithObjectsAndKeys:errMessage, NSLocalizedDescriptionKey, nil ]; - if(localError != nil){ + + if(errMessage != nil){ + info = [ NSDictionary dictionaryWithObjectsAndKeys:errMessage, NSLocalizedDescriptionKey, nil ]; localError = [[NSError alloc] initWithDomain:@"com.apple.security.ids.error" code:errorCode userInfo:info ]; secerror("%@", localError); + [self cleanupAfterHardIDSError: data]; } - if(localError != nil) - secerror("%@", localError); - }); return YES; diff --git a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+Throttle.m b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+Throttle.m index efacc327..769adc8e 100644 --- a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+Throttle.m +++ b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+Throttle.m @@ -71,10 +71,8 @@ static int max_penalty_timeout = 32; static int seconds_per_minute = 60; static int queue_depth = 1; -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR CFStringRef const IDSPAggdIncreaseThrottlingKey = CFSTR("com.apple.security.idsproxy.increasethrottle"); CFStringRef const IDSPAggdDecreaseThrottlingKey = CFSTR("com.apple.security.idsproxy.decreasethrottle"); -#endif static const int64_t kRetryTimerLeeway = (NSEC_PER_MSEC * 250); // 250ms leeway for handling unhandled messages. @@ -94,9 +92,7 @@ static const int64_t kRetryTimerLeeway = (NSEC_PER_MSEC * 250); // 250ms le -(void) increasePenalty:(NSNumber*)currentPenalty key:(NSString*)key keyEntry:(NSMutableDictionary**)keyEntry deviceName:(NSString*)deviceName peerID:(NSString*)peerID { -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR SecADAddValueForScalarKey((IDSPAggdIncreaseThrottlingKey), 1); -#endif secnotice("backoff", "increasing penalty!"); int newPenalty = 0; @@ -129,9 +125,8 @@ static const int64_t kRetryTimerLeeway = (NSEC_PER_MSEC * 250); // 250ms le -(void) decreasePenalty:(NSNumber*)currentPenalty key:(NSString*)key keyEntry:(NSMutableDictionary**)keyEntry deviceName:(NSString*)deviceName peerID:(NSString*)peerID { -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR SecADAddValueForScalarKey((IDSPAggdDecreaseThrottlingKey), 1); -#endif + int newPenalty = 0; secnotice("backoff","decreasing penalty!"); if([currentPenalty intValue] == 0 || [currentPenalty intValue] == 1) @@ -260,6 +255,8 @@ static const int64_t kRetryTimerLeeway = (NSEC_PER_MSEC * 250); // 250ms le __block NSMutableDictionary *previousTable = nil; NSArray *sortedTimestampKeys = [[*timeTable allKeys] sortedArrayUsingSelector:@selector(compare:)]; + NSMutableDictionary* timeTableStrong = *timeTable; + [sortedTimestampKeys enumerateObjectsUsingBlock:^(id arrayObject, NSUInteger idx, BOOL *stop) { if(foundTimeSlot == YES) @@ -269,7 +266,7 @@ static const int64_t kRetryTimerLeeway = (NSEC_PER_MSEC * 250); // 250ms le //grab the dictionary containing write information //(date, boolean to check if a write occured in the timeslice, - NSMutableDictionary *minutesTable = [*timeTable objectForKey: sortedKey]; + NSMutableDictionary *minutesTable = [timeTableStrong objectForKey: sortedKey]; if(minutesTable == nil) minutesTable = [[KeychainSyncingOverIDSProxy idsProxy] initializeTimeTable:key]; diff --git a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy-Info.plist b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy-Info.plist index 97c09063..325edc2d 100644 --- a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy-Info.plist +++ b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy-Info.plist @@ -26,6 +26,8 @@ ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} + LSBackgroundOnly + NSHumanReadableCopyright Copyright © 2013 Apple, Inc. All rights reserved. diff --git a/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy.8 b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy.8 new file mode 100644 index 00000000..1dec9683 --- /dev/null +++ b/KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy.8 @@ -0,0 +1,9 @@ +.Dd November 02, 2016 +.Dt KeychainSyncingOverIDSProxy 8 +.Os +.Sh NAME +.Nm KeychainSyncingOverIDSProxy +.Nd part of iCloud Keychain syncing. +.Sh DESCRIPTION +.Nm +part of iCloud Keychain syncing. diff --git a/KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.ios.plist b/KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.ios.plist index 3b5306f1..a3acb004 100644 --- a/KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.ios.plist +++ b/KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.ios.plist @@ -47,8 +47,6 @@ /System/Library/Frameworks/Security.framework/KeychainSyncingOverIDSProxy.bundle/KeychainSyncingOverIDSProxy - RunAtLoad - enabletransactions diff --git a/KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.osx.plist b/KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.osx.plist index b24e84ee..dbdcaca5 100644 --- a/KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.osx.plist +++ b/KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.osx.plist @@ -37,11 +37,7 @@ /System/Library/Frameworks/Security.framework/Versions/A/Resources/KeychainSyncingOverIDSProxy.bundle/Contents/MacOS/KeychainSyncingOverIDSProxy - RunAtLoad - EnablePressuredExit - KeepAlive - diff --git a/KeychainSyncingOverIDSProxy/keychainsyncingoveridsproxy.m b/KeychainSyncingOverIDSProxy/keychainsyncingoveridsproxy.m index 1d8b03e2..810d4b8f 100644 --- a/KeychainSyncingOverIDSProxy/keychainsyncingoveridsproxy.m +++ b/KeychainSyncingOverIDSProxy/keychainsyncingoveridsproxy.m @@ -36,8 +36,6 @@ #include #include "SOSCloudKeychainConstants.h" #import - -#import "KeychainSyncingOverIDSProxy+Throttle.h" #import "KeychainSyncingOverIDSProxy+SendMessage.h" int idsproxymain(int argc, const char *argv[]); @@ -85,6 +83,15 @@ static void idskeychainsyncingproxy_peer_dictionary_handler(const xpc_connection secdebug(PROXYXPCSCOPE, "Set our IDS Device ID message sent"); } + else if(operation && !strcmp(operation, kOperationGetIDSPerfCounters)){ + NSDictionary *counters = [[KeychainSyncingOverIDSProxy idsProxy] collectStats]; + xpc_object_t xMessages = _CFXPCCreateXPCObjectFromCFObject((__bridge CFDictionaryRef)(counters)); + + xpc_object_t replyMessage = xpc_dictionary_create_reply(event); + xpc_dictionary_set_value(replyMessage, kMessageKeyValue, xMessages); + xpc_connection_send_message(peer, replyMessage); + secdebug(PROXYXPCSCOPE, "Retrieved counters"); + } else if (operation && !strcmp(operation, kOperationGetPendingMesages)) { NSDictionary* messages = [[KeychainSyncingOverIDSProxy idsProxy] retrievePendingMessages]; @@ -138,12 +145,7 @@ static void idskeychainsyncingproxy_peer_dictionary_handler(const xpc_connection require_quiet(isPeerIDString, xit); require_quiet(isMessageDictionary, xit); - [[KeychainSyncingOverIDSProxy idsProxy] recordTimestampOfWriteToIDS: messageDictionary deviceName:deviceName peerID:peerID]; - NSDictionary *safeValues = [[KeychainSyncingOverIDSProxy idsProxy] filterForWritableValues:messageDictionary]; - - if(safeValues != nil && [safeValues count] > 0){ - object = [[KeychainSyncingOverIDSProxy idsProxy] sendFragmentedIDSMessages:safeValues name:deviceName peer:peerID error:&error]; - } + object = [[KeychainSyncingOverIDSProxy idsProxy] sendFragmentedIDSMessages:messageDictionary name:deviceName peer:peerID error:&error]; xpc_object_t replyMessage = xpc_dictionary_create_reply(event); xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, object); @@ -165,7 +167,7 @@ static void idskeychainsyncingproxy_peer_dictionary_handler(const xpc_connection NSString *deviceName = (__bridge_transfer NSString*)(_CFXPCCreateCFObjectFromXPCObject(xDeviceName)); NSString *peerID = (__bridge_transfer NSString*)(_CFXPCCreateCFObjectFromXPCObject(xPeerID)); NSDictionary *messageDictionary = (__bridge_transfer NSDictionary*)(_CFXPCCreateCFObjectFromXPCObject(xidsMessageData)); - NSError *error = NULL; + CFErrorRef error = NULL; bool isNameString = (CFGetTypeID((__bridge CFTypeRef)(deviceName)) == CFStringGetTypeID()); bool isPeerIDString = (CFGetTypeID((__bridge CFTypeRef)(peerID)) == CFStringGetTypeID()); bool isMessageDictionary = (CFGetTypeID((__bridge CFTypeRef)(messageDictionary)) == CFDictionaryGetTypeID()); @@ -174,37 +176,33 @@ static void idskeychainsyncingproxy_peer_dictionary_handler(const xpc_connection require_quiet(isPeerIDString, xit); require_quiet(isMessageDictionary, xit); - [[KeychainSyncingOverIDSProxy idsProxy] recordTimestampOfWriteToIDS: messageDictionary deviceName:deviceName peerID:peerID]; - NSDictionary *safeValues = [[KeychainSyncingOverIDSProxy idsProxy] filterForWritableValues:messageDictionary]; - - if(safeValues != nil && [safeValues count] > 0){ - NSString *localMessageIdentifier = [[NSUUID UUID] UUIDString]; - NSMutableDictionary* safeValuesCopy = [NSMutableDictionary dictionaryWithDictionary:safeValues]; - - [safeValuesCopy setObject:localMessageIdentifier forKey:(__bridge NSString*)(kIDSMessageUniqueID)]; - - if([[KeychainSyncingOverIDSProxy idsProxy] sendIDSMessage:safeValuesCopy name:deviceName peer:peerID]) - { - object = true; - NSString *useAckModel = [safeValuesCopy objectForKey:(__bridge NSString*)(kIDSMessageUsesAckModel)]; - if(object && [useAckModel compare:@"YES"] == NSOrderedSame){ - secnotice("IDS Transport", "setting timer!"); - [[KeychainSyncingOverIDSProxy idsProxy] setMessageTimer:localMessageIdentifier deviceID:deviceName message:safeValuesCopy]; - } - } - else{ - secerror("Could not send message"); + NSString *localMessageIdentifier = [[NSUUID UUID] UUIDString]; + NSMutableDictionary* messageDictionaryCopy = [NSMutableDictionary dictionaryWithDictionary:messageDictionary]; + + [messageDictionaryCopy setObject:localMessageIdentifier forKey:(__bridge NSString*)(kIDSMessageUniqueID)]; + + if([[KeychainSyncingOverIDSProxy idsProxy] sendIDSMessage:messageDictionaryCopy name:deviceName peer:peerID]) + { + object = true; + NSString *useAckModel = [messageDictionaryCopy objectForKey:(__bridge NSString*)(kIDSMessageUsesAckModel)]; + if(object && [useAckModel compare:@"YES"] == NSOrderedSame){ + secnotice("IDS Transport", "setting timer!"); + [[KeychainSyncingOverIDSProxy idsProxy] setMessageTimer:localMessageIdentifier deviceID:deviceName message:messageDictionaryCopy]; } - + } + else{ + SOSErrorCreate(kSecIDSErrorFailedToSend, &error, NULL, CFSTR("Failed to send keychain data message over IDS")); + secerror("Could not send message"); } xpc_object_t replyMessage = xpc_dictionary_create_reply(event); xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, object); if(error){ - xpc_object_t xerrobj = SecCreateXPCObjectWithCFError((__bridge CFErrorRef)(error)); + xpc_object_t xerrobj = SecCreateXPCObjectWithCFError(error); xpc_dictionary_set_value(replyMessage, kMessageKeyError, xerrobj); } + CFReleaseNull(error); xpc_connection_send_message(peer, replyMessage); secdebug(PROXYXPCSCOPE, "IDS message sent"); } @@ -228,7 +226,7 @@ static void idskeychainsyncingproxy_peer_event_handler(xpc_connection_t peer, xp if (type == XPC_TYPE_ERROR) { if (event == XPC_ERROR_CONNECTION_INVALID) { // The client process on the other end of the connection has either - // crashed or cancelled the connection. After receiving this error, + // crashed or canceled the connection. After receiving this error, // the connection is in an invalid state, and you do not need to // call xpc_connection_cancel(). Just tear down any associated state // here. @@ -284,9 +282,9 @@ int idsproxymain(int argc, const char *argv[]) [KeychainSyncingOverIDSProxy idsProxy]; - if([[KeychainSyncingOverIDSProxy idsProxy].messagesInFlight count] > 0 && + if([[KeychainSyncingOverIDSProxy idsProxy] haveMessagesInFlight] && [KeychainSyncingOverIDSProxy idsProxy].isIDSInitDone && - [KeychainSyncingOverIDSProxy idsProxy].sendRestoredMessages){ + [KeychainSyncingOverIDSProxy idsProxy].sendRestoredMessages) { [[KeychainSyncingOverIDSProxy idsProxy] sendPersistedMessagesAgain]; [KeychainSyncingOverIDSProxy idsProxy].sendRestoredMessages = false; } diff --git a/Modules/KeychainCircle.modulemap b/Modules/KeychainCircle.modulemap new file mode 100644 index 00000000..65f5d200 --- /dev/null +++ b/Modules/KeychainCircle.modulemap @@ -0,0 +1,6 @@ +framework module KeychainCircle [system] { + umbrella header "KeychainCircle.h" + + export * + module * { export * } +} diff --git a/OSX/Breadcrumb/SecBreadcrumb.c b/OSX/Breadcrumb/SecBreadcrumb.c index 5a8aee38..13caa20f 100644 --- a/OSX/Breadcrumb/SecBreadcrumb.c +++ b/OSX/Breadcrumb/SecBreadcrumb.c @@ -285,6 +285,7 @@ SecBreadcrumbCopyPassword(CFStringRef inPassword, outLength, CFDataGetBytePtr(inBreadcrumb) + 1 + ivLen, CFDataGetMutableBytePtr(oldpw), tagLen, tag); if (res) { + CFReleaseNull(gcmkey); CFReleaseNull(oldpw); CFReleaseNull(gcmkey); return false; diff --git a/OSX/Breadcrumb/breadcrumb_regressions.h b/OSX/Breadcrumb/breadcrumb_regressions.h index 2b4b5b2a..29894bf2 100644 --- a/OSX/Breadcrumb/breadcrumb_regressions.h +++ b/OSX/Breadcrumb/breadcrumb_regressions.h @@ -2,6 +2,6 @@ 1) add it here 2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes */ -#include +#include ONE_TEST(bc_10_password) diff --git a/OSX/Keychain Circle Notification/KNAppDelegate.m b/OSX/Keychain Circle Notification/KNAppDelegate.m index 0eb509b3..c8995b94 100644 --- a/OSX/Keychain Circle Notification/KNAppDelegate.m +++ b/OSX/Keychain Circle Notification/KNAppDelegate.m @@ -31,6 +31,7 @@ #import #import "notify.h" #import +#import #import #import @@ -44,6 +45,7 @@ #import #import "CoreCDP/CDPFollowUpController.h" #import "CoreCDP/CDPFollowUpContext.h" +#import static const char * const kLaunchLaterXPCName = "com.apple.security.Keychain-Circle-Notification-TICK"; static const NSString * const kKickedOutKey = @"KickedOut"; @@ -51,7 +53,11 @@ static const NSString * const kValidOnlyOutOfCircleKey = @"ValidOnlyOutOfCircle" static const NSString * const kPasswordChangedOrTrustedDeviceChanged = @"TDorPasswordChanged"; static NSString *prefpane = @"/System/Library/PreferencePanes/iCloudPref.prefPane"; #define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable" +#define kPublicKeyAvailable "com.apple.security.publickeyavailable" static NSString *KeychainPCDetailsAEAction = @"AKPCDetailsAEAction"; +bool _hasPostedAndStillInError = false; +bool _haveCheckedForICDPStatusOnceInCircle = false; +bool _isAccountICDP = false; @implementation KNAppDelegate @@ -61,6 +67,26 @@ static NSUserNotificationCenter *appropriateNotificationCenter() type: _NSUserNotificationCenterTypeSystem]; } +static void PSKeychainSyncIsUsingICDP(void) +{ + ACAccountStore *accountStore = [[ACAccountStore alloc] init]; + ACAccount *primaryiCloudAccount = nil; + + if ([accountStore respondsToSelector:@selector(icaPrimaryAppleAccount)]){ + primaryiCloudAccount = [accountStore icaPrimaryAppleAccount]; + } + + NSString *dsid = primaryiCloudAccount.icaPersonID; + BOOL isICDPEnabled = NO; + if (dsid) { + isICDPEnabled = [CDPAccount isICDPEnabledForDSID:dsid]; + NSLog(@"iCDP: PSKeychainSyncIsUsingICDP returning %@", isICDPEnabled ? @"TRUE" : @"FALSE"); + } else { + NSLog(@"iCDP: no primary account"); + } + + _isAccountICDP = isICDPEnabled; +} -(void) startFollowupKitRepair { @@ -71,46 +97,27 @@ static NSUserNotificationCenter *appropriateNotificationCenter() if(localError){ secnotice("kcn", "request to CoreCDP to follow up failed: %@", localError); } - else + else{ secnotice("kcn", "CoreCDP handling follow up"); + _hasPostedAndStillInError = false; + } } - (void) handleDismissedNotification { - ACAccountStore *accountStore = [[ACAccountStore alloc] init]; - ACAccount *primaryiCloudAccount = nil; - - if ([accountStore respondsToSelector:@selector(icaPrimaryAppleAccount)]){ - primaryiCloudAccount = [accountStore icaPrimaryAppleAccount]; - } - - if(primaryiCloudAccount){ - bool localICDP = false; - NSString *dsid = primaryiCloudAccount.icaPersonID; - if (dsid) { - NSDictionary *options = @{ (__bridge id) kPCSSetupDSID : dsid, }; - PCSIdentitySetRef identity = PCSIdentitySetCreate((__bridge CFDictionaryRef) options, NULL, NULL); - - if (identity) { - localICDP = PCSIdentitySetIsICDP(identity, NULL); - CFRelease(identity); - } - } - if(localICDP){ - secnotice("kcn", "handling dismissed notification, would start a follow up"); - [self startFollowupKitRepair]; - } + if(_isAccountICDP){ + secnotice("kcn", "handling dismissed notification, would start a follow up"); + [self startFollowupKitRepair]; } else secerror("unable to find primary account"); - } - (void) notifyiCloudPreferencesAbout: (NSString *) eventName { if (eventName == nil) return; - + secnotice("kcn", "notifyiCloudPreferencesAbout %@", eventName); NSString *accountID = (__bridge_transfer NSString*)(MMCopyLoggedInAccountFromAccounts()); @@ -125,7 +132,6 @@ static NSUserNotificationCenter *appropriateNotificationCenter() AEDesc aeDesc; BOOL createdAEDesc = createAEDescWithAEActionAndAccountID((__bridge NSString *) kMMServiceIDKeychainSync, eventName, accountID, &aeDesc); if (createdAEDesc) { - NSArray *prefPaneURL = [NSArray arrayWithObject: [NSURL fileURLWithPath: prefpane ]]; LSLaunchURLSpec lsSpec = { @@ -145,8 +151,7 @@ static NSUserNotificationCenter *appropriateNotificationCenter() secerror("unable to create and send aedesc for account: '%@' and action: '%@'\n", primaryiCloudAccount, eventName); } } - else - secerror("unable to find primary account"); + secerror("unable to find primary account"); } - (void) timerCheck @@ -211,22 +216,6 @@ static NSUserNotificationCenter *appropriateNotificationCenter() } -// Copied from sysdiagnose/src/utils.m -static bool isAppleInternal(void) -{ - static bool ret = false; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ -#if TARGET_OS_IPHONE - ret = CRIsAppleInternal(); -#else - ret = CRHasBeenAppleInternalRecently(); -#endif - }); - return ret; -} - - #define ICKC_EVENT_DISABLED "com.apple.security.secureobjectsync.disabled" #define ICKC_EVENT_DEPARTURE_REASON "com.apple.security.secureobjectsync.departurereason" #define ICKC_EVENT_NUM_PEERS "com.apple.security.secureobjectsync.numcircledevices" @@ -235,8 +224,22 @@ static bool isAppleInternal(void) { appropriateNotificationCenter().delegate = self; int out_taken; + int available; secnotice("kcn", "Posted at launch: %@", appropriateNotificationCenter().deliveredNotifications); + notify_register_dispatch(kPublicKeyAvailable, &available, dispatch_get_main_queue(), ^(int token) { + CFErrorRef err = NULL; + KNAppDelegate *me = self; + SOSCCStatus currentCircleStatus = SOSCCThisDeviceIsInCircle(&err); + me.state = [KNPersistentState loadFromStorage]; + + secnotice("kcn", "got public key available notification"); + + me.state.lastCircleStatus = currentCircleStatus; + + [me.state writeToStorage]; + }); + //register for public key not available notification, if occurs KCN can react notify_register_dispatch(kPublicKeyNotAvailable, &out_taken, dispatch_get_main_queue(), ^(int token) { CFErrorRef err = NULL; @@ -244,11 +247,24 @@ static bool isAppleInternal(void) enum DepartureReason departureReason = SOSCCGetLastDepartureReason(&err); SOSCCStatus currentCircleStatus = SOSCCThisDeviceIsInCircle(&err); me.state = [KNPersistentState loadFromStorage]; - + secnotice("kcn", "got public key not available notification, but won't send notification unless circle transition matches"); secnotice("kcn", "current circle status: %d, current departure reason: %d, last circle status: %d", currentCircleStatus, departureReason, me.state.lastCircleStatus); - - if(currentCircleStatus == kSOSCCError && me.state.lastCircleStatus == kSOSCCInCircle && (departureReason == kSOSNeverLeftCircle)) { + + PSKeychainSyncIsUsingICDP(); + + if(_isAccountICDP){ + if((currentCircleStatus == kSOSCCError || currentCircleStatus == kSOSCCCircleAbsent || currentCircleStatus == kSOSCCNotInCircle) && _hasPostedAndStillInError == false) { + secnotice("kcn", "iCDP: device not in circle, posting follow up"); + [self postRequirePassword]; + _hasPostedAndStillInError = true; + } + else if(currentCircleStatus == kSOSCCInCircle){ + secnotice("kcn", "iCDP: device is in circle!"); + _hasPostedAndStillInError = false; + } + } + else if(!_isAccountICDP && currentCircleStatus == kSOSCCError && me.state.lastCircleStatus == kSOSCCInCircle && (departureReason == kSOSNeverLeftCircle)) { secnotice("kcn", "circle status went from in circle to not in circle"); [self postRequirePassword]; } @@ -266,26 +282,32 @@ static bool isAppleInternal(void) CFErrorRef err = NULL; - enum DepartureReason departureReason = SOSCCGetLastDepartureReason(&err); - NSDate *nowish = [NSDate date]; + enum DepartureReason departureReason = SOSCCGetLastDepartureReason(&err); SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(&err); me.state = [KNPersistentState loadFromStorage]; secnotice("kcn", "applicationDidFinishLaunching"); + + PSKeychainSyncIsUsingICDP(); + + if(_isAccountICDP){ + if((circleStatus == kSOSCCError || circleStatus == kSOSCCCircleAbsent || circleStatus == kSOSCCNotInCircle) && _hasPostedAndStillInError == false) { - if(circleStatus == kSOSCCError && me.state.lastCircleStatus == kSOSCCInCircle && (departureReason == kSOSNeverLeftCircle)) { - CFErrorRef error = NULL; - SOSCCStatus currentCircleStatus = SOSCCThisDeviceIsInCircle(&error); - CFIndex errorCode = CFErrorGetCode(error); - - if(errorCode == kSOSErrorPublicKeyAbsent){ - secnotice("kcn", "We need the password to re-validate ourselves - it's changed on another device"); - me.state.lastCircleStatus = currentCircleStatus; + secnotice("kcn", "ICDP: We need the password to re-validate ourselves - it's changed on another device"); + me.state.lastCircleStatus = circleStatus; [me.state writeToStorage]; [me postRequirePassword]; + _hasPostedAndStillInError = true; + } + else if(circleStatus == kSOSCCInCircle){ + secnotice("kcn", "iCDP: device is in circle!"); + _hasPostedAndStillInError = false; } } - + else if(!_isAccountICDP && circleStatus == kSOSCCError && me.state.lastCircleStatus == kSOSCCInCircle && (departureReason == kSOSNeverLeftCircle)) { + secnotice("kcn", "SA: circle status went from in circle to not in circle"); + [me postRequirePassword]; + } // Pending application reminder secnotice("kcn", "{ChangeCallback} scheduleActivity %@", me.state.pendingApplicationReminder); if (circleStatus == kSOSCCRequestPending) @@ -511,19 +533,14 @@ static bool isAppleInternal(void) } } - // Improve wording of the iCloud keychain drop/reset error messages - // Contrary to HI spec (and I think it makes more sense) - // 1. otherButton == top : Not Now - // 2. actionButton == bottom: Continue - // 3. If we followed HI spec, replace "Activate" => "Dismiss" in note.userInfo below NSUserNotification *note = [NSUserNotification new]; - note.title = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_APPROVAL_TITLE_OSX); - note.informativeText = [NSString stringWithFormat: (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_APPROVAL_BODY_OSX), applicant.name]; + note.title = [NSString stringWithFormat: (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_APPROVAL_TITLE), applicant.name]; + note.informativeText = [KNAppDelegate localisedApprovalBodyWithDeviceTypeFromPeerInfo:applicant.peerObject]; note._displayStyle = _NSUserNotificationDisplayStyleAlert; note._identityImage = [NSImage bundleImage]; note._identityImageStyle = _NSUserNotificationIdentityImageStyleRectangleNoBorder; - note.otherButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_NOT_NOW); - note.actionButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CONTINUE); + note.otherButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_DECLINE); + note.actionButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_APPROVE); note.identifier = [[NSUUID new] UUIDString]; note.userInfo = @{ @"applicantName": applicant.name, @@ -536,154 +553,130 @@ static bool isAppleInternal(void) postCount++; } ++ (NSString *)localisedApprovalBodyWithDeviceTypeFromPeerInfo:(id)peerInfo { + NSString *type = (__bridge NSString *)SOSPeerInfoGetPeerDeviceType((__bridge SOSPeerInfoRef)(peerInfo)); + CFStringRef localisedType = NULL; + if ([type isEqualToString:@"iPad"]) { + localisedType = SecCopyCKString(SEC_CK_APPROVAL_BODY_OSX_IPAD); + } else if ([type isEqualToString:@"iPhone"]) { + localisedType = SecCopyCKString(SEC_CK_APPROVAL_BODY_OSX_IPHONE); + } else if ([type isEqualToString:@"iPod"]) { + localisedType = SecCopyCKString(SEC_CK_APPROVAL_BODY_OSX_IPOD); + } else if ([type isEqualToString:@"Mac"]) { + localisedType = SecCopyCKString(SEC_CK_APPROVAL_BODY_OSX_MAC); + } else { + localisedType = SecCopyCKString(SEC_CK_APPROVAL_BODY_OSX_GENERIC); + } + return (__bridge_transfer NSString *)localisedType; +} + - (void) postRequirePassword { - ACAccountStore *accountStore = [[ACAccountStore alloc] init]; - ACAccount *primaryiCloudAccount = nil; - bool localICDP = false; - - if ([accountStore respondsToSelector:@selector(icaPrimaryAppleAccount)]){ - primaryiCloudAccount = [accountStore icaPrimaryAppleAccount]; - } - - if(primaryiCloudAccount){ - NSString *dsid = primaryiCloudAccount.icaPersonID; - - if (dsid) { - NSDictionary *options = @{ (__bridge id) kPCSSetupDSID : dsid, }; - PCSIdentitySetRef identity = PCSIdentitySetCreate((__bridge CFDictionaryRef) options, NULL, NULL); - - if (identity) { - localICDP = PCSIdentitySetIsICDP(identity, NULL); - CFRelease(identity); - } - } - if(!localICDP){ - NSUserNotificationCenter *noteCenter = appropriateNotificationCenter(); - for (NSUserNotification *note in noteCenter.deliveredNotifications) { - if (note.userInfo[(NSString*) kPasswordChangedOrTrustedDeviceChanged]) { - if (note.isPresented) { - secnotice("kcn", "Already posted & presented: %@", note); - [appropriateNotificationCenter() removeDeliveredNotification: note]; - } else { - secnotice("kcn", "Already posted, but not presented: %@", note); - } + if(!_isAccountICDP){ + NSUserNotificationCenter *noteCenter = appropriateNotificationCenter(); + for (NSUserNotification *note in noteCenter.deliveredNotifications) { + if (note.userInfo[(NSString*) kPasswordChangedOrTrustedDeviceChanged]) { + if (note.isPresented) { + secnotice("kcn", "Already posted & presented: %@", note); + [appropriateNotificationCenter() removeDeliveredNotification: note]; + } else { + secnotice("kcn", "Already posted, but not presented: %@", note); } } - - NSString *message = CFBridgingRelease(SecCopyCKString(SEC_CK_PWD_REQUIRED_BODY_OSX)); - if (isAppleInternal()) { - NSString *reason_str = [NSString stringWithFormat:(__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CR_REASON_INTERNAL), @"Device became untrusted or password changed"]; - message = [message stringByAppendingString: reason_str]; - } - - NSUserNotification *note = [NSUserNotification new]; - note.title = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_PWD_REQUIRED_TITLE); - note.informativeText = message; - note._identityImage = [NSImage bundleImage]; - note._identityImageStyle = _NSUserNotificationIdentityImageStyleRectangleNoBorder; - note.otherButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_NOT_NOW); - note.actionButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CONTINUE); - note.identifier = [[NSUUID new] UUIDString]; - - note.userInfo = @{ - kPasswordChangedOrTrustedDeviceChanged : @1, - @"Activate" : (__bridge NSString *) kMMPropertyKeychainPCDetailsAEAction, - }; - - secnotice("kcn", "body=%@", note.informativeText); - secnotice("kcn", "About to post #-/%lu (PASSWORD/TRUSTED DEVICE): %@", noteCenter.deliveredNotifications.count, note); - [appropriateNotificationCenter() deliverNotification:note]; } - else{ - secnotice("kcn","would have posted needs password and then followed up"); - [self startFollowupKitRepair]; + + NSString *message = CFBridgingRelease(SecCopyCKString(SEC_CK_PWD_REQUIRED_BODY_OSX)); + if (os_variant_has_internal_ui("iCloudKeychain")) { + NSString *reason_str = [NSString stringWithFormat:(__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CR_REASON_INTERNAL), @"Device became untrusted or password changed"]; + message = [message stringByAppendingString: reason_str]; } + + NSUserNotification *note = [NSUserNotification new]; + note.title = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_PWD_REQUIRED_TITLE); + note.informativeText = message; + note._identityImage = [NSImage bundleImage]; + note._identityImageStyle = _NSUserNotificationIdentityImageStyleRectangleNoBorder; + note.otherButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_NOT_NOW); + note.actionButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CONTINUE); + note.identifier = [[NSUUID new] UUIDString]; + + note.userInfo = @{ + kPasswordChangedOrTrustedDeviceChanged : @1, + @"Activate" : (__bridge NSString *) kMMPropertyKeychainPCDetailsAEAction, + }; + + secnotice("kcn", "body=%@", note.informativeText); + secnotice("kcn", "About to post #-/%lu (PASSWORD/TRUSTED DEVICE): %@", noteCenter.deliveredNotifications.count, note); + [appropriateNotificationCenter() deliverNotification:note]; + } + else{ + secnotice("kcn","would have posted needs password and then followed up"); + [self startFollowupKitRepair]; } } - (void) postKickedOutAlert: (int) reason { - ACAccountStore *accountStore = [[ACAccountStore alloc] init]; - ACAccount *primaryiCloudAccount = nil; - bool localICDP = false; - - if ([accountStore respondsToSelector:@selector(icaPrimaryAppleAccount)]){ - primaryiCloudAccount = [accountStore icaPrimaryAppleAccount]; - } - - if(primaryiCloudAccount){ - NSString *dsid = primaryiCloudAccount.icaPersonID; - - if (dsid) { - NSDictionary *options = @{ (__bridge id) kPCSSetupDSID : dsid, }; - PCSIdentitySetRef identity = PCSIdentitySetCreate((__bridge CFDictionaryRef) options, NULL, NULL); - - if (identity) { - localICDP = PCSIdentitySetIsICDP(identity, NULL); - CFRelease(identity); - } - } - if(!localICDP){ - NSUserNotificationCenter *noteCenter = appropriateNotificationCenter(); - for (NSUserNotification *note in noteCenter.deliveredNotifications) { - if (note.userInfo[(NSString*) kKickedOutKey]) { - if (note.isPresented) { - secnotice("kcn", "Already posted&presented (removing): %@", note); - [appropriateNotificationCenter() removeDeliveredNotification: note]; - } else { - secnotice("kcn", "Already posted, but not presented: %@", note); - } + + if(!_isAccountICDP){ + NSUserNotificationCenter *noteCenter = appropriateNotificationCenter(); + for (NSUserNotification *note in noteCenter.deliveredNotifications) { + if (note.userInfo[(NSString*) kKickedOutKey]) { + if (note.isPresented) { + secnotice("kcn", "Already posted&presented (removing): %@", note); + [appropriateNotificationCenter() removeDeliveredNotification: note]; + } else { + secnotice("kcn", "Already posted, but not presented: %@", note); } } - - NSString *message = CFBridgingRelease(SecCopyCKString(SEC_CK_PWD_REQUIRED_BODY_OSX)); - if (isAppleInternal()) { - static const char *departureReasonStrings[] = { - "kSOSDepartureReasonError", - "kSOSNeverLeftCircle", - "kSOSWithdrewMembership", - "kSOSMembershipRevoked", - "kSOSLeftUntrustedCircle", - "kSOSNeverAppliedToCircle", - "kSOSDiscoveredRetirement", - "kSOSLostPrivateKey", - "unknown reason" - }; - int idx = (kSOSDepartureReasonError <= reason && reason <= kSOSLostPrivateKey) ? reason : (kSOSLostPrivateKey + 1); - NSString *reason_str = [NSString stringWithFormat:(__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CR_REASON_INTERNAL), departureReasonStrings[idx]]; - message = [message stringByAppendingString: reason_str]; - } - - // Improve wording of the iCloud keychain drop/reset error messages - // Contrary to HI spec (and I think it makes more sense) - // 1. otherButton == top : Not Now - // 2. actionButton == bottom: Continue - // 3. If we followed HI spec, replace "Activate" => "Dismiss" in note.userInfo below - NSUserNotification *note = [NSUserNotification new]; - note.title = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_PWD_REQUIRED_TITLE); - note.informativeText = message; - note._identityImage = [NSImage bundleImage]; - note._identityImageStyle = _NSUserNotificationIdentityImageStyleRectangleNoBorder; - note.otherButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_NOT_NOW); - note.actionButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CONTINUE); - note.identifier = [[NSUUID new] UUIDString]; - - note.userInfo = @{ - kKickedOutKey : @1, - kValidOnlyOutOfCircleKey: @1, - @"Activate" : (__bridge NSString *) kMMPropertyKeychainMRDetailsAEAction, - }; - - secnotice("kcn", "body=%@", note.informativeText); - secnotice("kcn", "About to post #-/%lu (KICKOUT): %@", noteCenter.deliveredNotifications.count, note); - [appropriateNotificationCenter() deliverNotification:note]; } - - else{ - secnotice("kcn","postKickedOutAlert starting followup repair"); - [self startFollowupKitRepair]; + + NSString *message = CFBridgingRelease(SecCopyCKString(SEC_CK_PWD_REQUIRED_BODY_OSX)); + if (os_variant_has_internal_ui("iCloudKeychain")) { + static const char *departureReasonStrings[] = { + "kSOSDepartureReasonError", + "kSOSNeverLeftCircle", + "kSOSWithdrewMembership", + "kSOSMembershipRevoked", + "kSOSLeftUntrustedCircle", + "kSOSNeverAppliedToCircle", + "kSOSDiscoveredRetirement", + "kSOSLostPrivateKey", + "unknown reason" + }; + int idx = (kSOSDepartureReasonError <= reason && reason <= kSOSLostPrivateKey) ? reason : (kSOSLostPrivateKey + 1); + NSString *reason_str = [NSString stringWithFormat:(__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CR_REASON_INTERNAL), departureReasonStrings[idx]]; + message = [message stringByAppendingString: reason_str]; } + + // Improve wording of the iCloud keychain drop/reset error messages + // Contrary to HI spec (and I think it makes more sense) + // 1. otherButton == top : Not Now + // 2. actionButton == bottom: Continue + // 3. If we followed HI spec, replace "Activate" => "Dismiss" in note.userInfo below + NSUserNotification *note = [NSUserNotification new]; + note.title = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_PWD_REQUIRED_TITLE); + note.informativeText = message; + note._identityImage = [NSImage bundleImage]; + note._identityImageStyle = _NSUserNotificationIdentityImageStyleRectangleNoBorder; + note.otherButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_NOT_NOW); + note.actionButtonTitle = (__bridge_transfer NSString *) SecCopyCKString(SEC_CK_CONTINUE); + note.identifier = [[NSUUID new] UUIDString]; + + note.userInfo = @{ + kKickedOutKey : @1, + kValidOnlyOutOfCircleKey: @1, + @"Activate" : (__bridge NSString *) kMMPropertyKeychainMRDetailsAEAction, + }; + + secnotice("kcn", "body=%@", note.informativeText); + secnotice("kcn", "About to post #-/%lu (KICKOUT): %@", noteCenter.deliveredNotifications.count, note); + [appropriateNotificationCenter() deliverNotification:note]; + } + + else{ + secnotice("kcn","postKickedOutAlert starting followup repair"); + [self startFollowupKitRepair]; } } diff --git a/OSX/Keychain Circle Notification/Keychain Circle Notification.8 b/OSX/Keychain Circle Notification/Keychain Circle Notification.8 new file mode 100644 index 00000000..d4bdc363 --- /dev/null +++ b/OSX/Keychain Circle Notification/Keychain Circle Notification.8 @@ -0,0 +1,9 @@ +.Dd November 02, 2016 +.Dt Keychain Circle Notification 8 +.Os +.Sh NAME +.Nm Keychain Circle Notification +.Nd part of iCloud Keychain syncing. +.Sh DESCRIPTION +.Nm +part of iCloud Keychain syncing. diff --git a/OSX/Keychain Circle Notification/com.apple.security.keychain-circle-notification.plist b/OSX/Keychain Circle Notification/com.apple.security.keychain-circle-notification.plist index 75952fd6..72154fca 100644 --- a/OSX/Keychain Circle Notification/com.apple.security.keychain-circle-notification.plist +++ b/OSX/Keychain Circle Notification/com.apple.security.keychain-circle-notification.plist @@ -4,10 +4,6 @@ Label com.apple.security.keychain-circle-notification - RunAtLoad - - KeepAlive - EnablePressuredExit LimitLoadToSessionType @@ -16,6 +12,11 @@ com.apple.notifyd.matching + kPublicKeyAvailable + + Notification + com.apple.security.publickeyavailable + kPublicKeyNotAvailable Notification diff --git a/OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist b/OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist index f1509978..44259696 100644 --- a/OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist +++ b/OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist @@ -2,6 +2,10 @@ + com.apple.private.keychain.sysbound + + com.apple.security.attestation.access + keychain-cloud-circle com.apple.keystore.access-keychain-keys @@ -30,6 +34,7 @@ com.apple.security.sos 123456.test.group 123456.test.group2 + com.apple.bluetooth com.apple.private.ubiquity-kvstore-access diff --git a/OSX/SecurityTestsOSX/main.m b/OSX/SecurityTestsOSX/main.m index 223fb6c9..607ee3b5 100644 --- a/OSX/SecurityTestsOSX/main.m +++ b/OSX/SecurityTestsOSX/main.m @@ -25,12 +25,12 @@ #include #include -#include "test/testenv.h" +#include "regressions/test/testenv.h" #include "testlist.h" -#include +#include #include "testlist.h" -#include +#include int main(int argc, char *argv[]) { diff --git a/OSX/SecurityTestsOSX/testlist.h b/OSX/SecurityTestsOSX/testlist.h index 5e7364ea..ea6b6579 100644 --- a/OSX/SecurityTestsOSX/testlist.h +++ b/OSX/SecurityTestsOSX/testlist.h @@ -4,4 +4,5 @@ #include #include #include +#include #include diff --git a/OSX/authd/agent.c b/OSX/authd/agent.c index 3ca68d34..73083533 100644 --- a/OSX/authd/agent.c +++ b/OSX/authd/agent.c @@ -11,7 +11,7 @@ #include "debugging.h" #include "engine.h" -#import +#include #include #include @@ -22,6 +22,8 @@ #define SECURITYAGENT_LOGINWINDOW_BOOTSTRAP_NAME_BASE "com.apple.security.agent.login" #define AUTHORIZATIONHOST_BOOTSTRAP_NAME_BASE "com.apple.security.authhost" +AUTHD_DEFINE_LOG + #define UUID_INITIALIZER_FROM_SESSIONID(sessionid) \ { 0,0,0,0, 0,0,0,0, 0,0,0,0, (unsigned char)((0xff000000 & (sessionid))>>24), (unsigned char)((0x00ff0000 & (sessionid))>>16), (unsigned char)((0x0000ff00 & (sessionid))>>8), (unsigned char)((0x000000ff & (sessionid))) } @@ -66,16 +68,16 @@ _agent_finalize(CFTypeRef value) // If this ever becomes a concurrent queue, then this would need to be a barrier sync dispatch_sync(agent->eventQueue, ^{ - CFReleaseSafe(agent->hints); - CFReleaseSafe(agent->context); - CFReleaseSafe(agent->mech); - CFReleaseSafe(agent->engine); + CFReleaseNull(agent->hints); + CFReleaseNull(agent->context); + CFReleaseNull(agent->mech); + CFReleaseNull(agent->engine); dispatch_release(agent->actionQueue); }); dispatch_release(agent->eventQueue); - LOGD("agent[%i]: _agent_finalize called", agent->agentPid); + os_log_debug(AUTHD_LOG, "agent: finalizing"); } AUTH_TYPE_INSTANCE(agent, @@ -122,7 +124,7 @@ agent_create(engine_t engine, mechanism_t mech, auth_token_t auth, process_t pro tempAddr.ai_asid = audit_info->asid; auditon(A_GETSINFO_ADDR, &tempAddr, sizeof(tempAddr)); - LOGV("agent[%i]: Stored auid %d fetched auid %d", agent->agentPid, audit_info->auid, tempAddr.ai_auid); + os_log_debug(AUTHD_LOG, "agent: stored auid %d fetched auid %d", audit_info->auid, tempAddr.ai_auid); uid_t auid = tempAddr.ai_auid; uuid_t sessionUUID = UUID_INITIALIZER_FROM_SESSIONID((uint32_t)audit_info->asid); @@ -134,19 +136,19 @@ agent_create(engine_t engine, mechanism_t mech, auth_token_t auth, process_t pro // User => regular user-level SecurityAgent agent->agentConnection = xpc_connection_create_mach_service(SECURITYAGENT_BOOTSTRAP_NAME_BASE, NULL, 0); xpc_connection_set_target_uid(agent->agentConnection, auid); - LOGV("agent[%i]: Creating a standard security agent", agent->agentPid); + os_log_debug(AUTHD_LOG, "agent: creating a standard security agent"); } else { // Root session => loginwindow SecurityAgent agent->agentConnection = xpc_connection_create_mach_service(SECURITYAGENT_LOGINWINDOW_BOOTSTRAP_NAME_BASE, NULL, 0); xpc_connection_set_instance(agent->agentConnection, sessionUUID); - LOGV("agent[%i]: Creating a loginwindow security agent", agent->agentPid); + os_log_debug(AUTHD_LOG, "agent: creating a loginwindow security agent"); doSwitchAudit = true; doSwitchBootstrap = true; } } else { agent->agentConnection = xpc_connection_create_mach_service(AUTHORIZATIONHOST_BOOTSTRAP_NAME_BASE, NULL, 0); xpc_connection_set_instance(agent->agentConnection, sessionUUID); - LOGV("agent[%i]: Creating a standard authhost", agent->agentPid); + os_log_debug(AUTHD_LOG, "agent: creating a standard authhost"); doSwitchAudit = true; doSwitchBootstrap = true; } @@ -155,7 +157,6 @@ agent_create(engine_t engine, mechanism_t mech, auth_token_t auth, process_t pro xpc_connection_set_target_queue(agent->agentConnection, agent->eventQueue); xpc_connection_set_event_handler(agent->agentConnection, ^(xpc_object_t object) { char* objectDesc = xpc_copy_description(object); - LOGV("agent[%i]: global xpc message received %s", agent->agentPid, objectDesc); free(objectDesc); if (agent->pluginState == dead) { @@ -182,18 +183,18 @@ agent_create(engine_t engine, mechanism_t mech, auth_token_t auth, process_t pro mach_port_name_t jobPort; if (audit_info != NULL) { if (0 == audit_session_port(audit_info->asid, &jobPort)) { - LOGV("agent[%i]: attaching an audit session port", agent->agentPid); + os_log_debug(AUTHD_LOG, "agent: attaching an audit session port"); xpc_dictionary_set_mach_send(requestObject, AUTH_XPC_AUDIT_SESSION_PORT, jobPort); if (mach_port_mod_refs(mach_task_self(), jobPort, MACH_PORT_RIGHT_SEND, -1) != KERN_SUCCESS) { - LOGE("unable to release send right for audit session, leaking"); + os_log_error(AUTHD_LOG, "agent: unable to release send right for audit session, leaking"); } } } } if (doSwitchBootstrap) { - LOGV("agent[%i]: attaching a bootstrap port", agent->agentPid); + os_log_debug(AUTHD_LOG, "agent: attaching a bootstrap port"); xpc_dictionary_set_mach_send(requestObject, AUTH_XPC_BOOTSTRAP_PORT, process_get_bootstrap(proc)); } @@ -283,7 +284,7 @@ agent_run(agent_t agent, auth_items_t hints, auth_items_t context, auth_items_t } dispatch_release(replyWaiter); - LOGV("agent[%i]: Finished call to SecurityAgent", agent->agentPid); + os_log_debug(AUTHD_LOG, "agent: Finished call to SecurityAgent"); xpc_release(hintsArray); xpc_release(contextArray); diff --git a/OSX/authd/authd-Entitlements.plist b/OSX/authd/authd-Entitlements.plist new file mode 100644 index 00000000..126b1f63 --- /dev/null +++ b/OSX/authd/authd-Entitlements.plist @@ -0,0 +1,8 @@ + + + + + com.apple.private.LocalAuthentication.ExtractCredential + + + diff --git a/OSX/authd/authd_private.h b/OSX/authd/authd_private.h index 78bf06d2..4fc95b64 100644 --- a/OSX/authd/authd_private.h +++ b/OSX/authd/authd_private.h @@ -105,7 +105,8 @@ enum { AUTHORIZATION_CREATE_WITH_AUDIT_TOKEN, AUTHORIZATION_DISMISS, AUTHORIZATION_SETUP, - AUTHORIZATION_ENABLE_SMARTCARD + AUTHORIZATION_ENABLE_SMARTCARD, + AUTHORIZATION_PREAUTHORIZE_CREDENTIALS }; #if defined(__cplusplus) diff --git a/OSX/authd/authdb.c b/OSX/authd/authdb.c index fcf6160d..df25c569 100644 --- a/OSX/authd/authdb.c +++ b/OSX/authd/authdb.c @@ -15,6 +15,8 @@ #include #include +AUTHD_DEFINE_LOG + #define AUTHDB "/var/db/auth.db" #define AUTHDB_DATA "/System/Library/Security/authorization.plist" @@ -117,7 +119,7 @@ _sqlite3_exec(sqlite3 * handle, const char * query) char * errmsg = NULL; rc = sqlite3_exec(handle, query, NULL, NULL, &errmsg); if (errmsg) { - LOGE("authdb: exec, (%i) %s", rc, errmsg); + os_log_error(AUTHD_LOG, "authdb: exec, (%i) %{public}s", rc, errmsg); sqlite3_free(errmsg); } @@ -172,20 +174,6 @@ static int32_t _db_upgrade_from_version(authdb_connection_t dbconn, int32_t vers return s3e; } -static void _printCFError(const char * errmsg, CFErrorRef err) -{ - if (err) { - CFStringRef errString = NULL; - errString = CFErrorCopyDescription(err); - char *tmp = _copy_cf_string(errString, NULL); - LOGV("%s, %s", errmsg, tmp); - free_safe(tmp); - CFReleaseSafe(errString); - } else { - LOGV("%s", errmsg); - } -} - static void _db_load_data(authdb_connection_t dbconn, auth_items_t config) { CFURLRef authURL = NULL; @@ -199,10 +187,10 @@ static void _db_load_data(authdb_connection_t dbconn, auth_items_t config) Boolean ok; authURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR(AUTHDB_DATA), kCFURLPOSIXPathStyle, false); - require_action(authURL != NULL, done, LOGE("authdb: file not found %s", AUTHDB_DATA)); + require_action(authURL != NULL, done, os_log_error(AUTHD_LOG, "authdb: file not found %{public}s", AUTHDB_DATA)); ok = CFURLCopyResourcePropertyForKey(authURL, kCFURLContentModificationDateKey, &value, &err); - require_action(ok && value != NULL, done, _printCFError("authdb: failed to get modification date", err)); + require_action(ok && value != NULL, done, os_log_error(AUTHD_LOG, "authdb: failed to get modification date: %{public}@", err)); if (CFGetTypeID(value) == CFDateGetTypeID()) { ts = CFDateGetAbsoluteTime(value); @@ -216,15 +204,15 @@ static void _db_load_data(authdb_connection_t dbconn, auth_items_t config) // Solution: always import plist and update db when time stamps don't match. // After a successful import, old_ts = ts below. if (ts != old_ts) { - LOGV("authdb: %s modified old=%f, new=%f", AUTHDB_DATA, old_ts, ts); + os_log_debug(AUTHD_LOG, "authdb: %{public}s modified old=%f, new=%f", AUTHDB_DATA, old_ts, ts); CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, authURL, &data, NULL, NULL, (SInt32*)&rc); - require_noerr_action(rc, done, LOGE("authdb: failed to load %s", AUTHDB_DATA)); + require_noerr_action(rc, done, os_log_error(AUTHD_LOG, "authdb: failed to load %{public}s", AUTHDB_DATA)); plist = CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, &err); - require_action(err == NULL, done, _printCFError("authdb: failed to read plist", err)); + require_action(err == NULL, done, os_log_error(AUTHD_LOG, "authdb: failed to read plist: %{public}@", err)); if (authdb_import_plist(dbconn, plist, true)) { - LOGD("authdb: updating data_ts"); + os_log_debug(AUTHD_LOG, "authdb: updating data_ts"); auth_items_t update = auth_items_create(); auth_items_set_double(update, "data_ts", ts); authdb_set_key_value(dbconn, "config", update); @@ -246,7 +234,7 @@ static bool _truncate_db(authdb_connection_t dbconn) int32_t flags = SQLITE_TRUNCATE_JOURNALMODE_WAL | SQLITE_TRUNCATE_AUTOVACUUM_FULL; rc = sqlite3_file_control(dbconn->handle, NULL, SQLITE_TRUNCATE_DATABASE, &flags); if (rc != SQLITE_OK) { - LOGV("Failed to delete db handle! SQLite error %i.\n", rc); + os_log_debug(AUTHD_LOG, "Failed to delete db handle! SQLite error %i.", rc); if (rc == SQLITE_IOERR) { // Unable to recover successfully if we can't truncate abort(); @@ -270,9 +258,9 @@ static void _handle_corrupt_db(authdb_connection_t dbconn) rc = sqlite3_file_control(corrupt_db, NULL, SQLITE_REPLACE_DATABASE, (void *)dbconn->handle); if (SQLITE_OK == rc) { - LOGE("Database at path %s is corrupt. Copying it to %s for further investigation.", dbconn->db->db_path, buf); + os_log_error(AUTHD_LOG, "Database at path %{public}s is corrupt. Copying it to %{public}s for further investigation.", dbconn->db->db_path, buf); } else { - LOGE("Tried to copy corrupt database at path %s, but we failed with SQLite error %i.", dbconn->db->db_path, rc); + os_log_error(AUTHD_LOG, "Tried to copy corrupt database at path %{public}s, but we failed with SQLite error %i.", dbconn->db->db_path, rc); } } @@ -295,18 +283,18 @@ static int32_t _db_maintenance(authdb_connection_t dbconn) // We don't have a config table if (NULL == config) { - LOGV("authdb: initializing database"); + os_log_debug(AUTHD_LOG, "authdb: initializing database"); s3e = _db_upgrade_from_version(dbconn, 0); - require_noerr_action(s3e, done, LOGE("authdb: failed to initialize database %i", s3e)); + require_noerr_action(s3e, done, os_log_error(AUTHD_LOG, "authdb: failed to initialize database %i", s3e)); s3e = authdb_get_key_value(dbconn, "config", true, &config); - require_noerr_action(s3e, done, LOGE("authdb: failed to get config %i", s3e)); + require_noerr_action(s3e, done, os_log_error(AUTHD_LOG, "authdb: failed to get config %i", s3e)); } int64_t currentVersion = auth_items_get_int64(config, "version"); - LOGV("authdb: current db ver=%lli", currentVersion); + os_log_debug(AUTHD_LOG, "authdb: current db ver=%lli", currentVersion); if (currentVersion < AUTHDB_VERSION) { - LOGV("authdb: upgrading schema"); + os_log_debug(AUTHD_LOG, "authdb: upgrading schema"); s3e = _db_upgrade_from_version(dbconn, (int32_t)currentVersion); auth_items_set_int64(config, "version", AUTHDB_VERSION); @@ -335,7 +323,7 @@ static int32_t _db_maintenance(authdb_connection_t dbconn) // require(!rc, done); // // if (dispatch_semaphore_wait(semaphore, 5*NSEC_PER_SEC) != 0) { -// LOGV("authdb: timeout occurred!"); +// os_log_debug(AUTHD_LOG, "authdb: timeout occurred!"); // sqlite3_unlock_notify(dbconn->handle, NULL, NULL); // rc = SQLITE_LOCKED; // } else if (stmt){ @@ -358,16 +346,16 @@ static void _checkResult(authdb_connection_t dbconn, int32_t rc, const char * fn if (isCorrupt) { if (skip_maintenance) { - LOGV("authdb: corrupted db, skipping maintenance %s %s", fn_name, sqlite3_errmsg(dbconn->handle)); + os_log_debug(AUTHD_LOG, "authdb: corrupted db, skipping maintenance %{public}s %{public}s", fn_name, sqlite3_errmsg(dbconn->handle)); } else { _handle_corrupt_db(dbconn); authdb_maintenance(dbconn); } } else if (SQLITE_CONSTRAINT == rc || SQLITE_READONLY == rc) { if (stmt) { - LOGV("authdb: %s %s for %s", fn_name, sqlite3_errmsg(dbconn->handle), sqlite3_sql(stmt)); + os_log_debug(AUTHD_LOG, "authdb: %{public}s %{public}s for %{public}s", fn_name, sqlite3_errmsg(dbconn->handle), sqlite3_sql(stmt)); } else { - LOGV("authdb: %s %s", fn_name, sqlite3_errmsg(dbconn->handle)); + os_log_debug(AUTHD_LOG, "authdb: %{public}s %{public}s", fn_name, sqlite3_errmsg(dbconn->handle)); } } } @@ -394,7 +382,7 @@ _authdb_finalize(CFTypeRef value) { authdb_t db = (authdb_t)value; - CFReleaseSafe(db->connections); + CFReleaseNull(db->connections); dispatch_release(db->queue); free_safe(db->db_path); } @@ -432,7 +420,7 @@ authdb_create() db->connections = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); if (getenv("__OSINSTALL_ENVIRONMENT") != NULL) { - LOGV("authdb: running from installer"); + os_log_debug(AUTHD_LOG, "authdb: running from installer"); db->db_path = _copy_string("file::memory:?cache=shared"); } else { db->db_path = _copy_string(AUTHDB); @@ -457,7 +445,7 @@ authdb_connection_t authdb_connection_acquire(authdb_t db) dbconn = authdb_connection_create(db); #if DEBUG total++; - LOGV("authdb: no handles available total: %i", total); + os_log_debug(AUTHD_LOG, "authdb: no handles available total: %i", total); #endif } }); @@ -478,7 +466,7 @@ void authdb_connection_release(authdb_connection_t * dbconn) if (count <= AUTHDB_MAX_HANDLES) { CFArrayAppendValue(tmp->db->connections, tmp); } else { - LOGD("authdb: freeing extra connection"); + os_log_debug(AUTHD_LOG, "authdb: freeing extra connection"); CFRelease(tmp); } }); @@ -495,14 +483,14 @@ static bool _db_check_corrupted(authdb_connection_t dbconn) rc = sqlite3_prepare_v2(dbconn->handle, "PRAGMA integrity_check;", -1, &stmt, NULL); if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) { - LOGV("authdb: warning error %i when running integrity check", rc); + os_log_debug(AUTHD_LOG, "authdb: warning error %i when running integrity check", rc); isCorrupted = false; } else if (rc == SQLITE_OK) { rc = sqlite3_step(stmt); if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) { - LOGV("authdb: warning error %i when running integrity check", rc); + os_log_debug(AUTHD_LOG, "authdb: warning error %i when running integrity check", rc); isCorrupted = false; } else if (rc == SQLITE_ROW) { const char * result = (const char*)sqlite3_column_text(stmt, 0); @@ -519,12 +507,12 @@ static bool _db_check_corrupted(authdb_connection_t dbconn) bool authdb_maintenance(authdb_connection_t dbconn) { - LOGD("authdb: starting maintenance"); + os_log_debug(AUTHD_LOG, "authdb: starting maintenance"); int32_t rc = SQLITE_ERROR; auth_items_t config = NULL; bool isCorrupted = _db_check_corrupted(dbconn); - LOGD("authdb: integrity check=%s", isCorrupted ? "fail" : "pass"); + os_log_debug(AUTHD_LOG, "authdb: integrity check=%{public}s", isCorrupted ? "fail" : "pass"); if (isCorrupted) { _handle_corrupt_db(dbconn); @@ -534,18 +522,18 @@ bool authdb_maintenance(authdb_connection_t dbconn) dbconn->handle = _create_handle(dbconn->db); } - require_action(dbconn->handle, done, LOGE("authdb: maintenance cannot open database")); + require_action(dbconn->handle, done, os_log_error(AUTHD_LOG, "authdb: maintenance cannot open database")); _db_maintenance(dbconn); rc = authdb_get_key_value(dbconn, "config", true, &config); - require_noerr_action(rc, done, LOGV("authdb: maintenance failed %i", rc)); + require_noerr_action(rc, done, os_log_debug(AUTHD_LOG, "authdb: maintenance failed %i", rc)); _db_load_data(dbconn, config); done: CFReleaseSafe(config); - LOGD("authdb: finished maintenance"); + os_log_debug(AUTHD_LOG, "authdb: finished maintenance"); return rc == SQLITE_OK; } @@ -571,7 +559,7 @@ static int32_t _prepare(authdb_connection_t dbconn, const char * sql, const bool require_action(out_stmt != NULL, done, rc = SQLITE_ERROR); rc = sqlite3_prepare_v2(dbconn->handle, sql, -1, &stmt, NULL); - require_noerr_action(rc, done, LOGV("authdb: prepare (%i) %s", rc, sqlite3_errmsg(dbconn->handle))); + require_noerr_action(rc, done, os_log_debug(AUTHD_LOG, "authdb: prepare (%i) %{public}s", rc, sqlite3_errmsg(dbconn->handle))); *out_stmt = stmt; @@ -643,7 +631,7 @@ static int32_t _bindItemsAtIndex(sqlite3_stmt * stmt, int col, auth_items_t item break; } if (rc != SQLITE_OK) { - LOGV("authdb: auth_items bind failed (%i)", rc); + os_log_debug(AUTHD_LOG, "authdb: auth_items bind failed (%i)", rc); } return rc; } @@ -674,7 +662,7 @@ int32_t authdb_get_key_value(authdb_connection_t dbconn, const char * table, con if (_is_busy(rc)) { sleep(AUTHDB_BUSY_DELAY); } else { - require_noerr_action(rc, done, LOGV("authdb: get_key_value (%i) %s", rc, sqlite3_errmsg(dbconn->handle))); + require_noerr_action(rc, done, os_log_debug(AUTHD_LOG, "authdb: get_key_value (%i) %{public}s", rc, sqlite3_errmsg(dbconn->handle))); } break; } @@ -715,7 +703,7 @@ int32_t authdb_set_key_value(authdb_connection_t dbconn, const char * table, aut rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { _checkResult(dbconn, rc, __FUNCTION__, stmt, false); - LOGV("authdb: set_key_value, step (%i) %s", rc, sqlite3_errmsg(dbconn->handle)); + os_log_debug(AUTHD_LOG, "authdb: set_key_value, step (%i) %{public}s", rc, sqlite3_errmsg(dbconn->handle)); } return true; @@ -734,7 +722,7 @@ static int32_t _begin_transaction_type(authdb_connection_t dbconn, AuthDBTransac const char * query = NULL; switch (type) { case AuthDBTransactionImmediate: - query = "BEGIN IMMEDATE;"; + query = "BEGIN IMMEDIATE;"; break; case AuthDBTransactionExclusive: query = "BEGIN EXCLUSIVE;"; @@ -770,12 +758,12 @@ bool authdb_transaction(authdb_connection_t dbconn, AuthDBTransactionType type, bool commit = false; result = _begin_transaction_type(dbconn, type); - require_action(result == SQLITE_OK, done, LOGV("authdb: transaction begin failed %i", result)); + require_action(result == SQLITE_OK, done, os_log_debug(AUTHD_LOG, "authdb: transaction begin failed %i", result)); commit = t(); result = _end_transaction(dbconn, commit); - require_action(result == SQLITE_OK, done, commit = false; LOGV("authdb: transaction end failed %i", result)); + require_action(result == SQLITE_OK, done, commit = false; os_log_debug(AUTHD_LOG, "authdb: transaction end failed %i", result)); done: return commit; @@ -818,11 +806,11 @@ bool authdb_step(authdb_connection_t dbconn, const char * sql, void (^bind_stmt) break; default: if (_is_busy(rc)) { - LOGV("authdb: %s", sqlite3_errmsg(dbconn->handle)); + os_log_debug(AUTHD_LOG, "authdb: %{public}s", sqlite3_errmsg(dbconn->handle)); sleep(AUTHDB_BUSY_DELAY); sqlite3_reset(stmt); } else { - require_noerr_action(rc, done, LOGV("authdb: step (%i) %s", rc, sqlite3_errmsg(dbconn->handle))); + require_noerr_action(rc, done, os_log_debug(AUTHD_LOG, "authdb: step (%i) %{public}s", rc, sqlite3_errmsg(dbconn->handle))); } break; } @@ -838,7 +826,7 @@ void authdb_checkpoint(authdb_connection_t dbconn) { int32_t rc = sqlite3_wal_checkpoint(dbconn->handle, NULL); if (rc != SQLITE_OK) { - LOGV("authdb: checkpoit failed %i", rc); + os_log_debug(AUTHD_LOG, "authdb: checkpoit failed %i", rc); } } @@ -904,7 +892,7 @@ _import_rules(authdb_connection_t dbconn, CFMutableArrayRef rules, bool version_ rule_sql_fetch(delegate, dbconn); } if (rule_get_id(delegate) == 0) { - LOGD("authdb: delaying %s waiting for delegate %s", rule_get_name(rule), rule_get_name(delegate)); + os_log_debug(AUTHD_LOG, "authdb: delaying %{public}s waiting for delegate %{public}s", rule_get_name(rule), rule_get_name(delegate)); delayCommit = true; return false; } @@ -917,7 +905,7 @@ _import_rules(authdb_connection_t dbconn, CFMutableArrayRef rules, bool version_ if (!delayCommit) { bool success = rule_sql_commit(rule, dbconn, now, NULL); - LOGV("authdb: %s %s %s %s", + os_log_debug(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"); @@ -938,7 +926,7 @@ authdb_import_plist(authdb_connection_t dbconn, CFDictionaryRef plist, bool vers { bool result = false; - LOGV("authdb: starting import"); + os_log_debug(AUTHD_LOG, "authdb: starting import"); CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); CFMutableArrayRef rights = NULL; @@ -955,8 +943,8 @@ authdb_import_plist(authdb_connection_t dbconn, CFDictionaryRef plist, bool vers rules = _copy_rules_dict(RT_RULE, rulesDict, dbconn); } - LOGV("authdb: rights = %li", CFArrayGetCount(rights)); - LOGV("authdb: rules = %li", CFArrayGetCount(rules)); + os_log_debug(AUTHD_LOG, "authdb: rights = %li", CFArrayGetCount(rights)); + os_log_debug(AUTHD_LOG, "authdb: rules = %li", CFArrayGetCount(rules)); CFIndex count; // first pass import base rules without delegations @@ -982,7 +970,7 @@ done: CFReleaseSafe(rights); CFReleaseSafe(rules); - LOGV("authdb: finished import, %s", result ? "succeeded" : "failed"); + os_log_debug(AUTHD_LOG, "authdb: finished import, %{public}s", result ? "succeeded" : "failed"); return result; } @@ -1005,7 +993,7 @@ static bool _sql_profile_enabled(void) profile_enabled = CFBooleanGetValue((CFBooleanRef)profile); } - LOGV("authdb: sql profile: %s", profile_enabled ? "enabled" : "disabled"); + os_log_debug(AUTHD_LOG, "authdb: sql profile: %{public}s", profile_enabled ? "enabled" : "disabled"); CFReleaseSafe(profile); }); @@ -1015,7 +1003,7 @@ static bool _sql_profile_enabled(void) } static void _profile(void *context AUTH_UNUSED, const char *sql, sqlite3_uint64 ns) { - LOGV("==\nauthdb: %s\nTime: %llu ms\n", sql, ns >> 20); + os_log_debug(AUTHD_LOG, "==\nauthdb: %{private}s\nTime: %llu ms\n", sql, ns >> 20); } static sqlite3 * _create_handle(authdb_t db) @@ -1025,7 +1013,7 @@ static sqlite3 * _create_handle(authdb_t db) int32_t rc = sqlite3_open_v2(db->db_path, &handle, SQLITE_OPEN_READWRITE, NULL); if (rc != SQLITE_OK) { - LOGE("authdb: open %s (%i) %s", db->db_path, rc, handle ? sqlite3_errmsg(handle) : "no memory for handle"); + os_log_error(AUTHD_LOG, "authdb: open %{public}s (%i) %{public}s", db->db_path, rc, handle ? sqlite3_errmsg(handle) : "no memory for handle"); if (handle) { sqlite3_close(handle); } @@ -1037,7 +1025,7 @@ static sqlite3 * _create_handle(authdb_t db) dbcreated = true; if (rc != SQLITE_OK) { - LOGE("authdb: create %s (%i) %s", db->db_path, rc, handle ? sqlite3_errmsg(handle) : "no memory for handle"); + os_log_error(AUTHD_LOG, "authdb: create %{public}s (%i) %{public}s", db->db_path, rc, handle ? sqlite3_errmsg(handle) : "no memory for handle"); if (handle) { sqlite3_close(handle); handle = NULL; @@ -1075,7 +1063,7 @@ _authdb_connection_finalize(CFTypeRef value) if (dbconn->handle) { sqlite3_close(dbconn->handle); } - CFReleaseSafe(dbconn->db); + CFReleaseNull(dbconn->db); } AUTH_TYPE_INSTANCE(authdb_connection, diff --git a/OSX/authd/authitems.c b/OSX/authd/authitems.c index abac3452..50dc0a45 100644 --- a/OSX/authd/authitems.c +++ b/OSX/authd/authitems.c @@ -7,8 +7,12 @@ #include "authutilities.h" #include #include +#include + +AUTHD_DEFINE_LOG typedef struct _auth_item_s * auth_item_t; +void auth_items_crypt_worker(auth_items_t items, CFDataRef encryption_key, bool(*function)(auth_item_t, CFDataRef)); #pragma mark - #pragma mark auth_item_t @@ -31,7 +35,7 @@ auth_item_get_string(auth_item_t item) item->data.value = realloc(item->data.value, item->bufLen); if (item->data.value == NULL) { // this is added to prevent running off into random memory if a string buffer doesn't have a null char - LOGE("realloc failed"); + os_log_error(AUTHD_LOG, "items: realloc failed"); abort(); } ((uint8_t*)item->data.value)[item->bufLen-1] = '\0'; @@ -87,15 +91,21 @@ _auth_item_finalize(CFTypeRef value) { auth_item_t item = (auth_item_t)value; - CFReleaseSafe(item->cfKey); + CFReleaseNull(item->cfKey); if (item->data.name) { free((void*)item->data.name); + /* cannot set item->data.name to NULL because item->data.name is non-nullable public API (rdar://problem/32235322) + * cannot leave item->data.name pointing to original data (rdar://problem/31006596) + * => suppress the warning */ + #ifndef __clang_analyzer__ + item->data.name = NULL; + #endif } if (item->data.value) { memset(item->data.value, 0, item->data.valueLength); - free(item->data.value); + free_safe(item->data.value); } } @@ -281,6 +291,49 @@ done: return item; } +static bool auth_item_crypt_worker(auth_item_t item, CFDataRef key, int operation) +{ + bool result = false; + + if (!key) + return result; + + if (item->data.value && item->data.valueLength) { + size_t required_length = 0; + CCCryptorStatus status = CCCrypt(operation, kCCAlgorithmAES, kCCOptionPKCS7Padding, + CFDataGetBytePtr(key), CFDataGetLength(key), NULL, + item->data.value, item->data.valueLength, NULL, 0, &required_length); + require(status == kCCBufferTooSmall, done); + + void *buffer = calloc(1u, required_length); + status = CCCrypt(operation, kCCAlgorithmAES, kCCOptionPKCS7Padding, + CFDataGetBytePtr(key), CFDataGetLength(key), NULL, + item->data.value, item->data.valueLength, buffer, required_length, &required_length); + if (status == kCCSuccess) { + memset(item->data.value, 0, item->data.valueLength); + free(item->data.value); + item->data.value = buffer; + item->data.valueLength = required_length; + result = true; + } else { + free(buffer); + } + } + +done: + return result; +} + +static bool auth_item_decrypt(auth_item_t item, CFDataRef key) +{ + return auth_item_crypt_worker(item, key, kCCDecrypt); +} + +static bool auth_item_encrypt(auth_item_t item, CFDataRef key) +{ + return auth_item_crypt_worker(item, key, kCCEncrypt); +} + #pragma mark - #pragma mark auth_items_t @@ -568,6 +621,30 @@ auth_items_clear(auth_items_t items) CFDictionaryRemoveAllValues(items->dictionary); } +void +auth_items_crypt_worker(auth_items_t items, CFDataRef encryption_key, bool(*function)(auth_item_t, CFDataRef)) +{ + auth_items_iterate(items, ^bool(const char *key) { + CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); + auth_item_t item = (auth_item_t)CFDictionaryGetValue(items->dictionary, lookup); + function(item, encryption_key); + CFReleaseSafe(lookup); + return true; + }); +} + +void +auth_items_encrypt(auth_items_t items, CFDataRef encryption_key) +{ + auth_items_crypt_worker(items, encryption_key, auth_item_encrypt); +} + +void +auth_items_decrypt(auth_items_t items, CFDataRef encryption_key) +{ + auth_items_crypt_worker(items, encryption_key, auth_item_decrypt); +} + void auth_items_copy(auth_items_t items, auth_items_t src) { @@ -580,6 +657,21 @@ auth_items_copy(auth_items_t items, auth_items_t src) }); } +void +auth_items_content_copy(auth_items_t items, auth_items_t src) +{ + auth_items_iterate(src, ^bool(const char *key) { + CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); + auth_item_t item = (auth_item_t)CFDictionaryGetValue(src->dictionary, lookup); + auth_item_t new_item = auth_item_create(item->type, item->data.name, item->data.value, item->data.valueLength, item->data.flags); + if (new_item) + CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(new_item), new_item); + CFReleaseSafe(lookup); + CFReleaseSafe(new_item); + return true; + }); +} + void auth_items_copy_xpc(auth_items_t items, const xpc_object_t src) { @@ -600,6 +692,24 @@ auth_items_copy_with_flags(auth_items_t items, auth_items_t src, uint32_t flags) }); } +// unlike previous method, this one creates true new copy including their content +void +auth_items_content_copy_with_flags(auth_items_t items, auth_items_t src, uint32_t flags) +{ + auth_items_iterate(src, ^bool(const char *key) { + if (auth_items_check_flags(src, key, flags)) { + CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); + auth_item_t item = (auth_item_t)CFDictionaryGetValue(src->dictionary, lookup); + auth_item_t new_item = auth_item_create(item->type, item->data.name, item->data.value, item->data.valueLength, item->data.flags); + if (new_item) + CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(new_item), new_item); + CFReleaseSafe(lookup); + CFReleaseSafe(new_item); + } + return true; + }); +} + bool auth_items_iterate(auth_items_t items, auth_items_iterator_t iter) { @@ -655,7 +765,7 @@ auth_items_get_string(auth_items_t items, const char *key) if (item) { #if DEBUG if (!(item->type == AI_TYPE_STRING || item->type == AI_TYPE_UNKNOWN)) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i", item->data.name, item->type, AI_TYPE_STRING); } #endif @@ -694,7 +804,7 @@ auth_items_get_data(auth_items_t items, const char *key, size_t *len) if (item) { #if DEBUG if (!(item->type == AI_TYPE_DATA || item->type == AI_TYPE_UNKNOWN)) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i", item->data.name, item->type, AI_TYPE_DATA); } #endif @@ -714,7 +824,7 @@ auth_items_get_data_with_flags(auth_items_t items, const char *key, size_t *len, if (item && (item->data.flags & flags) == flags) { #if DEBUG if (!(item->type == AI_TYPE_DATA || item->type == AI_TYPE_UNKNOWN)) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i", item->data.name, item->type, AI_TYPE_DATA); } #endif @@ -748,7 +858,7 @@ auth_items_get_bool(auth_items_t items, const char *key) if (item) { #if DEBUG if (!(item->type == AI_TYPE_BOOL || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(bool))) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li", item->data.name, item->type, AI_TYPE_BOOL, item->data.valueLength, sizeof(bool)); } #endif @@ -788,7 +898,7 @@ auth_items_get_int(auth_items_t items, const char *key) if (item) { #if DEBUG if (!(item->type ==AI_TYPE_INT || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(int32_t))) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li", item->data.name, item->type, AI_TYPE_INT, item->data.valueLength, sizeof(int32_t)); } #endif @@ -828,7 +938,7 @@ auth_items_get_uint(auth_items_t items, const char *key) if (item) { #if DEBUG if (!(item->type ==AI_TYPE_UINT || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(uint32_t))) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li", item->data.name, item->type, AI_TYPE_UINT, item->data.valueLength, sizeof(uint32_t)); } #endif @@ -868,7 +978,7 @@ auth_items_get_int64(auth_items_t items, const char *key) if (item) { #if DEBUG if (!(item->type ==AI_TYPE_INT64 || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(int64_t))) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li", item->data.name, item->type, AI_TYPE_INT64, item->data.valueLength, sizeof(int64_t)); } #endif @@ -908,7 +1018,7 @@ auth_items_get_uint64(auth_items_t items, const char *key) if (item) { #if DEBUG if (!(item->type ==AI_TYPE_UINT64 || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(uint64_t))) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li", item->data.name, item->type, AI_TYPE_UINT64, item->data.valueLength, sizeof(uint64_t)); } #endif @@ -946,7 +1056,7 @@ double auth_items_get_double(auth_items_t items, const char *key) if (item) { #if DEBUG if (!(item->type ==AI_TYPE_DOUBLE || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(double))) { - LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", + os_log_debug(AUTHD_LOG, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li", item->data.name, item->type, AI_TYPE_DOUBLE, item->data.valueLength, sizeof(double)); } #endif diff --git a/OSX/authd/authitems.h b/OSX/authd/authitems.h index 2fe97095..48bd82df 100644 --- a/OSX/authd/authitems.h +++ b/OSX/authd/authitems.h @@ -82,12 +82,18 @@ void auth_items_clear(auth_items_t); AUTH_NONNULL_ALL void auth_items_copy(auth_items_t, auth_items_t src); +AUTH_NONNULL_ALL +void auth_items_content_copy(auth_items_t items, auth_items_t src); + AUTH_NONNULL_ALL void auth_items_copy_xpc(auth_items_t, const xpc_object_t src); AUTH_NONNULL_ALL void auth_items_copy_with_flags(auth_items_t, auth_items_t src, uint32_t flags); +AUTH_NONNULL_ALL +void auth_items_content_copy_with_flags(auth_items_t items, auth_items_t src, uint32_t flags); + AUTH_NONNULL_ALL bool auth_items_iterate(auth_items_t, auth_items_iterator_t iter); @@ -151,6 +157,12 @@ size_t auth_items_get_length(auth_items_t, const char *key); AUTH_NONNULL_ALL void auth_items_set_value(auth_items_t, const char *key, uint32_t type, uint32_t flags, const void *value, size_t len); +AUTH_NONNULL_ALL +void auth_items_encrypt(auth_items_t items, CFDataRef encryption_key); + +AUTH_NONNULL_ALL +void auth_items_decrypt(auth_items_t items, CFDataRef encryption_key); + #pragma mark - #pragma mark auth_rights_t diff --git a/OSX/authd/authorization.plist b/OSX/authd/authorization.plist index d7cef74f..f4f68f3b 100644 --- a/OSX/authd/authorization.plist +++ b/OSX/authd/authorization.plist @@ -1288,14 +1288,20 @@ See remaining rules for examples. allow-root + authenticate-user + class user comment For making Directory Services changes. group admin + session-owner + shared + version + 2 system.services.networkextension.filtering @@ -1513,26 +1519,26 @@ See remaining rules for examples. authenticate-session-owner - system.localauthentication.ui + system.preferences.continuity class - evaluate-mechanisms + rule comment - Used by LocalAuthentication to display its UI. - mechanisms + Used by Password And Continuity PrefPane to request the user's password. + rule - LocalAuthentication:UI + authenticate-staff-extract-context - system.preferences.continuity + com.apple.configurationprofiles.userprofile.trustcert class rule comment - Used by Password And Continuity PrefPane to request the user's password. + Install user configuration profile with certificate requiring trust change. rule - authenticate-staff-extract-context + authenticate-session-owner-or-admin com.apple.safaridriver.allow @@ -1540,13 +1546,17 @@ See remaining rules for examples. comment This right is used by safaridriver to allow running it. class - user - group - admin - allow-root - - shared - + rule + k-of-n + 1 + rule + + is-admin + is-webdeveloper + authenticate-webdeveloper + + version + 1 rules @@ -2098,6 +2108,31 @@ See remaining rules for examples. LocalAuthentication:context + is-webdeveloper + + authenticate-user + + class + user + comment + Verify that the user asking for authorization is a web developer. + group + _webdeveloper + + authenticate-webdeveloper + + class + user + comment + Authenticate as a web developer. + group + _webdeveloper + shared + + timeout + 36000 + + diff --git a/OSX/authd/authtoken.c b/OSX/authd/authtoken.c index c627cb29..995be9d4 100644 --- a/OSX/authd/authtoken.c +++ b/OSX/authd/authtoken.c @@ -13,6 +13,8 @@ #include #include +AUTHD_DEFINE_LOG + static Boolean AuthTokenEqualCallBack(const void *value1, const void *value2) { return (*(uint64_t*)value1) == (*(uint64_t*)value2); @@ -57,6 +59,8 @@ struct _auth_token_s { CFMutableSetRef credentials; CFMutableSetRef authorized_rights; + + CFMutableDataRef encryption_key; bool least_privileged; bool appleSigned; @@ -72,21 +76,23 @@ static void _auth_token_finalize(CFTypeRef value) { auth_token_t auth = (auth_token_t)value; - LOGV("authtoken: deallocated %p", auth); + os_log_debug(AUTHD_LOG, "authtoken: finalizing"); dispatch_barrier_sync(auth->dispatch_queue, ^{}); dispatch_release(auth->dispatch_queue); - CFReleaseSafe(auth->session); - CFReleaseSafe(auth->processes); - CFReleaseSafe(auth->context); - CFReleaseSafe(auth->credentials); - CFReleaseSafe(auth->authorized_rights); + CFReleaseNull(auth->session); + CFReleaseNull(auth->processes); + CFReleaseNull(auth->context); + CFReleaseNull(auth->credentials); + CFReleaseNull(auth->authorized_rights); free_safe(auth->code_url); - CFReleaseSafe(auth->credential); + CFReleaseNull(auth->credential); + CFReleaseNull(auth->encryption_key); if (auth->creator_bootstrap_port != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), auth->creator_bootstrap_port); + auth->creator_bootstrap_port = MACH_PORT_NULL; } } @@ -103,8 +109,8 @@ static CFStringRef _auth_token_copy_description(CFTypeRef value) { auth_token_t auth = (auth_token_t)value; - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("auth_token: %p, uid=%i, pid=%i, processes=%li least_privileged=%i"), - auth, auth->auditInfo.euid, auth->auditInfo.pid, CFSetGetCount(auth->processes), auth->least_privileged); + return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("auth_token: uid=%i, pid=%i, processes=%li least_privileged=%i"), + auth->auditInfo.euid, auth->auditInfo.pid, CFSetGetCount(auth->processes), auth->least_privileged); } static CFHashCode @@ -146,7 +152,7 @@ _auth_token_create(const audit_info_s * auditInfo, bool operateAsLeastPrivileged require(auth != NULL, done); if (CCRandomCopyBytes(kCCRandomDefault, auth->blob.data, sizeof(auth->blob.data)) != kCCSuccess) { - LOGE("authtoken[%i]: failed to generate blob", auditInfo->pid); + os_log_error(AUTHD_LOG, "authtoken: failed to generate blob (PID %d)", auditInfo->pid); CFReleaseNull(auth); goto done; } @@ -168,11 +174,21 @@ _auth_token_create(const audit_info_s * auditInfo, bool operateAsLeastPrivileged else auth->sandboxed = false; + size_t key_length = kCCKeySizeAES256; + auth->encryption_key = CFDataCreateMutable(kCFAllocatorDefault, key_length); + if (auth->encryption_key) { + int rv = CCRandomCopyBytes(kCCRandomDefault, CFDataGetMutableBytePtr(auth->encryption_key), key_length); + if (rv != kCCSuccess) { + CFReleaseNull(auth->encryption_key) + } + CFDataSetLength(auth->encryption_key, key_length); + } + #if DEBUG CFHashCode code = AuthTokenHashCallBack(&auth->blob); if (memcmp(&code, auth->blob.data, sizeof(auth->blob.data)) != 0) { - LOGD("authtoken[%i]: blob = %x%01x", auth->auditInfo.pid, auth->blob.data[1], auth->blob.data[0]); - LOGD("authtoken[%i]: hash = %lx", auth->auditInfo.pid, code); + os_log_debug(AUTHD_LOG, "authtoken[%i]: blob = %x%01x", auth->auditInfo.pid, auth->blob.data[1], auth->blob.data[0]); + os_log_debug(AUTHD_LOG, "authtoken[%i]: hash = %lx", auth->auditInfo.pid, code); assert(false); } #endif @@ -206,7 +222,7 @@ auth_token_create(process_t proc, bool operateAsLeastPrivileged) } } - LOGV("authtoken[%i]: created %p", auth->auditInfo.pid, auth); + os_log_debug(AUTHD_LOG, "authtoken: created for PID %d", auth->auditInfo.pid); done: return auth; @@ -227,7 +243,7 @@ auth_token_create_with_audit_info(const audit_info_s* info, bool operateAsLeastP auth->session = server_find_copy_session(info->asid, true); if (auth->session == NULL) { - LOGV("authtoken[%i]: failed to create session", auth->auditInfo.pid); + os_log_debug(AUTHD_LOG, "authtoken: failed to create session (PID %d)", auth->auditInfo.pid); CFReleaseNull(auth); goto done; } @@ -240,7 +256,7 @@ auth_token_create_with_audit_info(const audit_info_s* info, bool operateAsLeastP CFReleaseSafe(codePid); if (status) { - LOGV("authtoken[%i]: failed to create code ref (%d)", auth->auditInfo.pid, (int)status); + os_log_debug(AUTHD_LOG, "authtoken: failed to create code ref (%d)", (int)status); CFReleaseNull(auth); goto done; } @@ -252,7 +268,7 @@ auth_token_create_with_audit_info(const audit_info_s* info, bool operateAsLeastP } } - LOGV("authtoken[%i]: created %p for %s", auth->auditInfo.pid, auth, auth->code_url); + os_log_debug(AUTHD_LOG, "authtoken: created for %{public}s", auth->code_url); done: CFReleaseSafe(code_Ref); @@ -515,3 +531,9 @@ bool auth_token_check_state(auth_token_t auth, auth_token_state_t state) return auth->state == 0; } } + +CFDataRef auth_token_get_encryption_key(auth_token_t auth) +{ + return auth->encryption_key; +} + diff --git a/OSX/authd/authtoken.h b/OSX/authd/authtoken.h index c745a82a..d4b9db58 100644 --- a/OSX/authd/authtoken.h +++ b/OSX/authd/authtoken.h @@ -108,6 +108,9 @@ auth_token_state_t auth_token_get_state(auth_token_t); AUTH_NONNULL_ALL bool auth_token_check_state(auth_token_t, auth_token_state_t); +AUTH_NONNULL_ALL +CFDataRef auth_token_get_encryption_key(auth_token_t auth); + #if defined(__cplusplus) } #endif diff --git a/OSX/authd/authutilities.c b/OSX/authd/authutilities.c index c1dac101..d769467b 100644 --- a/OSX/authd/authutilities.c +++ b/OSX/authd/authutilities.c @@ -6,7 +6,6 @@ #include #include -#include xpc_object_t SerializeItemSet(const AuthorizationItemSet * itemSet) diff --git a/OSX/authd/ccaudit.c b/OSX/authd/ccaudit.c index 4a147303..2c696ebb 100644 --- a/OSX/authd/ccaudit.c +++ b/OSX/authd/ccaudit.c @@ -9,6 +9,8 @@ #include #include +AUTHD_DEFINE_LOG + struct _ccaudit_s { __AUTH_BASE_STRUCT_HEADER__; @@ -27,8 +29,8 @@ _ccaudit_finalizer(CFTypeRef value) { ccaudit_t ccaudit = (ccaudit_t)value; - CFReleaseSafe(ccaudit->auth); - CFReleaseSafe(ccaudit->proc); + CFReleaseNull(ccaudit->auth); + CFReleaseNull(ccaudit->proc); } AUTH_TYPE_INSTANCE(ccaudit, @@ -88,7 +90,7 @@ static bool _enabled() enabled = true; break; default: - LOGE("ccaudit: error checking auditing status (%d)", acond); + os_log_error(AUTHD_LOG, "ccaudit: error checking auditing status (%d)", acond); } }); @@ -105,7 +107,7 @@ static bool _open(ccaudit_t ccaudit) return true; if ((ccaudit->fd = au_open()) < 0) { - LOGE("ccaudit: au_open() failed (%s)", strerror(errno)); + os_log_error(AUTHD_LOG, "ccaudit: au_open() failed (%{public}s)", strerror(errno)); return false; } @@ -118,7 +120,7 @@ static void _close(ccaudit_t ccaudit) int err = au_close(ccaudit->fd, AU_TO_WRITE, (short)ccaudit->event); ccaudit->fd = -1; if (err < 0) { - LOGE("ccaudit: au_close() failed; record not committed"); + os_log_error(AUTHD_LOG, "ccaudit: au_close() failed; record not committed"); } } } @@ -128,11 +130,11 @@ static bool _write(ccaudit_t ccaudit, token_t * token, const char * name) const char *tokenName = name ? name : ""; if (NULL == token) { - LOGE("ccaudit: invalid '%s' token", tokenName); + os_log_error(AUTHD_LOG, "ccaudit: invalid '%{public}s' token", tokenName); return false; } if (au_write(ccaudit->fd, token) < 0) { - LOGE("ccaudit: error writing '%s' token (%s)", tokenName, strerror(errno)); + os_log_error(AUTHD_LOG, "ccaudit: error writing '%{public}s' token (%{public}s)", tokenName, strerror(errno)); return false; } return true; diff --git a/OSX/authd/com.apple.authd.sb b/OSX/authd/com.apple.authd.sb index 0c951d01..c4f89fb5 100644 --- a/OSX/authd/com.apple.authd.sb +++ b/OSX/authd/com.apple.authd.sb @@ -15,6 +15,8 @@ (subpath (param "TMP_DIR"))) (allow mach-lookup + (global-name "com.apple.CoreAuthentication.agent.libxpc") + (global-name "com.apple.CoreAuthentication.daemon.libxpc") (global-name "com.apple.CoreServices.coreservicesd") (global-name "com.apple.PowerManagement.control") (global-name "com.apple.security.agent") diff --git a/OSX/authd/connection.c b/OSX/authd/connection.c index c9e54a60..2939dfb8 100644 --- a/OSX/authd/connection.c +++ b/OSX/authd/connection.c @@ -27,7 +27,7 @@ _connection_finalize(CFTypeRef value) dispatch_barrier_sync(conn->dispatch_queue, ^{}); dispatch_barrier_sync(conn->dispatch_queue_internal, ^{}); - CFReleaseSafe(conn->proc); + CFReleaseNull(conn->proc); CFReleaseNull(conn->engine); dispatch_release(conn->dispatch_queue); dispatch_release(conn->dispatch_queue_internal); diff --git a/OSX/authd/credential.c b/OSX/authd/credential.c index 10832909..6fd46fc0 100644 --- a/OSX/authd/credential.c +++ b/OSX/authd/credential.c @@ -32,7 +32,7 @@ _credential_finalize(CFTypeRef value) free_safe(cred->name); free_safe(cred->realName); - CFReleaseSafe(cred->cachedGroups); + CFReleaseNull(cred->cachedGroups); } static CFStringRef @@ -123,7 +123,9 @@ credential_create(uid_t uid) struct passwd *pw = getpwuid(uid); if (pw != NULL) { // avoid hinting a locked account - if ( (pw->pw_passwd == NULL) || strcmp(pw->pw_passwd, "*") ) { + // LibInfo started to return asterisk for system accounts in J93: 17a240: Hang during boot (opendirectoryd/powerd deadlock) + // so do not make this check for those system accounts + if ( (uid < 500) || (pw->pw_passwd == NULL) || strcmp(pw->pw_passwd, "*") ) { cred->uid = pw->pw_uid; cred->name = _copy_string(pw->pw_name); cred->realName = _copy_string(pw->pw_gecos); diff --git a/OSX/authd/debugging.c b/OSX/authd/debugging.c deleted file mode 100644 index a7682194..00000000 --- a/OSX/authd/debugging.c +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (c) 2012 Apple Inc. All Rights Reserved. */ - -#include "debugging.h" -#include "authd_private.h" -#include "authutilities.h" -#include -#include -#include -#include - -// sudo defaults write /Library/Preferences/com.apple.security.coderequirements Entitlements -string always - -static bool -security_auth_verbose(void) -{ - static dispatch_once_t onceToken; - static bool verbose_enabled = false; - - //sudo defaults write /Library/Preferences/com.apple.authd verbose -bool true - dispatch_once(&onceToken, ^{ - CFTypeRef verbose = (CFNumberRef)CFPreferencesCopyValue(CFSTR("verbose"), CFSTR(SECURITY_AUTH_NAME), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - - if (verbose && CFGetTypeID(verbose) == CFBooleanGetTypeID()) { - verbose_enabled = CFBooleanGetValue((CFBooleanRef)verbose); - } -#if DEBUG - syslog(LOG_NOTICE, "verbose: %s", verbose_enabled ? "enabled" : "disabled"); -#endif - CFReleaseSafe(verbose); - }); - - return verbose_enabled; -} - -void -security_auth_log(int type,const char * format,...) -{ - va_list ap; - va_start(ap, format); - switch (type) { - case AUTH_LOG_NORMAL: - vsyslog(LOG_NOTICE, format, ap); - break; - case AUTH_LOG_VERBOSE: - if (security_auth_verbose()) { - vsyslog(LOG_NOTICE, format, ap); - } - break; - case AUTH_LOG_ERROR: - vsyslog(LOG_ERR, format, ap); - break; - default: - break; - } - va_end(ap); -} - -void _show_cf(CFTypeRef value) -{ - CFStringRef string = NULL; - char * tmp = NULL; - require(value != NULL, done); - - if (security_auth_verbose()) { - string = CFCopyDescription(value); - tmp = _copy_cf_string(string, NULL); - - syslog(LOG_NOTICE, "%s", tmp); - } - -done: - CFReleaseSafe(string); - free_safe(tmp); - return; -} diff --git a/OSX/authd/debugging.h b/OSX/authd/debugging.h index f6534197..0e0638b3 100644 --- a/OSX/authd/debugging.h +++ b/OSX/authd/debugging.h @@ -7,22 +7,18 @@ extern "C" { #endif -enum { - AUTH_LOG_NORMAL, - AUTH_LOG_VERBOSE, - AUTH_LOG_ERROR +#include +#include + +#define AUTHD_DEFINE_LOG \ +static os_log_t AUTHD_LOG_DEFAULT() { \ +static dispatch_once_t once; \ +static os_log_t log; \ +dispatch_once(&once, ^{ log = os_log_create("com.apple.Authorization", "authd"); }); \ +return log; \ }; - -#define LOG(...) security_auth_log(AUTH_LOG_NORMAL, ##__VA_ARGS__) -#define LOGV(...) security_auth_log(AUTH_LOG_VERBOSE, ##__VA_ARGS__) -#define LOGE(...) security_auth_log(AUTH_LOG_ERROR, ##__VA_ARGS__) -#if DEBUG -#define LOGD(...) security_auth_log(AUTH_LOG_VERBOSE, ##__VA_ARGS__) -#else -#define LOGD(...) -#endif - -void security_auth_log(int,const char *,...) __printflike(2, 3); + +#define AUTHD_LOG AUTHD_LOG_DEFAULT() #define CFReleaseSafe(CF) { CFTypeRef _cf = (CF); if (_cf) CFRelease(_cf); } #define CFReleaseNull(CF) { CFTypeRef _cf = (CF); \ @@ -31,8 +27,6 @@ void security_auth_log(int,const char *,...) __printflike(2, 3); #define xpc_release_safe(obj) if (obj) { xpc_release(obj); obj = NULL; } #define free_safe(obj) if (obj) { free(obj); obj = NULL; } - -void _show_cf(CFTypeRef); #if defined(__cplusplus) } diff --git a/OSX/authd/engine.c b/OSX/authd/engine.c index faee89e1..61bc15ee 100644 --- a/OSX/authd/engine.c +++ b/OSX/authd/engine.c @@ -22,11 +22,16 @@ int checkpw_internal( const struct passwd *pw, const char* password ); #include #include #include +#include +#include #include +#include + +AUTHD_DEFINE_LOG static void _set_process_hints(auth_items_t, process_t); static void _set_process_immutable_hints(auth_items_t, process_t); -static void _set_auth_token_hints(auth_items_t, auth_token_t); +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 *); @@ -55,6 +60,9 @@ struct _engine_s { auth_rights_t grantedRights; + CFTypeRef la_context; + bool preauthorizing; + enum Reason reason; int32_t tries; @@ -80,18 +88,18 @@ _engine_finalizer(CFTypeRef value) { engine_t engine = (engine_t)value; - CFReleaseSafe(engine->mechanism_agents); - CFReleaseSafe(engine->conn); - CFReleaseSafe(engine->auth); - CFReleaseSafe(engine->hints); - CFReleaseSafe(engine->context); - CFReleaseSafe(engine->immutable_hints); - CFReleaseSafe(engine->sticky_context); - CFReleaseSafe(engine->grantedRights); - CFReleaseSafe(engine->sessionCredential); - CFReleaseSafe(engine->credentials); - CFReleaseSafe(engine->effectiveCredentials); - CFReleaseSafe(engine->authenticateRule); + CFReleaseNull(engine->mechanism_agents); + CFReleaseNull(engine->conn); + CFReleaseNull(engine->auth); + CFReleaseNull(engine->hints); + CFReleaseNull(engine->context); + CFReleaseNull(engine->immutable_hints); + CFReleaseNull(engine->sticky_context); + CFReleaseNull(engine->grantedRights); + CFReleaseNull(engine->sessionCredential); + CFReleaseNull(engine->credentials); + CFReleaseNull(engine->effectiveCredentials); + CFReleaseNull(engine->authenticateRule); } AUTH_TYPE_INSTANCE(engine, @@ -135,11 +143,15 @@ engine_create(connection_t conn, auth_token_t auth) engine->sticky_context = auth_items_create(); _set_process_hints(engine->hints, engine->proc); _set_process_immutable_hints(engine->immutable_hints, engine->proc); - _set_auth_token_hints(engine->hints, auth); + _set_auth_token_hints(engine->hints, engine->immutable_hints, auth); engine->grantedRights = auth_rights_create(); engine->reason = noReason; + + engine->preauthorizing = false; + + engine->la_context = NULL; engine->now = CFAbsoluteTimeGetCurrent(); @@ -184,17 +196,24 @@ void _set_process_immutable_hints(auth_items_t immutable_hints, process_t proc) { // process information - immutable - auth_items_set_bool(immutable_hints, AGENT_HINT_PROCESS_SIGNED, process_apple_signed(proc)); - auth_items_set_bool(immutable_hints, AGENT_HINT_PROCESS_FROM_APPLE, process_firstparty_signed(proc)); + auth_items_set_bool(immutable_hints, AGENT_HINT_CLIENT_SIGNED, process_apple_signed(proc)); + auth_items_set_bool(immutable_hints, AGENT_HINT_CLIENT_FROM_APPLE, process_firstparty_signed(proc)); } void -_set_auth_token_hints(auth_items_t hints, auth_token_t auth) +_set_auth_token_hints(auth_items_t hints, auth_items_t immutable_hints, auth_token_t auth) { auth_items_set_string(hints, AGENT_HINT_CLIENT_PATH, auth_token_get_code_url(auth)); auth_items_set_int(hints, AGENT_HINT_CREATOR_PID, auth_token_get_pid(auth)); const audit_info_s * info = auth_token_get_audit_info(auth); auth_items_set_data(hints, AGENT_HINT_CREATOR_AUDIT_TOKEN, &info->opaqueToken, sizeof(info->opaqueToken)); + + process_t proc = process_create(info, auth_token_get_session(auth)); + if (proc) { + auth_items_set_bool(immutable_hints, AGENT_HINT_CREATOR_SIGNED, process_apple_signed(proc)); + auth_items_set_bool(immutable_hints, AGENT_HINT_CREATOR_FROM_APPLE, process_firstparty_signed(proc)); + } + CFReleaseSafe(proc); } static void @@ -244,7 +263,7 @@ _set_localization_hints(authdb_connection_t dbconn, auth_items_t hints, rule_t r static void _set_session_hints(engine_t engine, rule_t rule) { - LOGV("engine[%i]: ** prepare agent hints for rule %s", connection_get_pid(engine->conn), rule_get_name(rule)); + os_log_debug(AUTHD_LOG, "engine: ** prepare agent hints for rule %{public}s", rule_get_name(rule)); if (_evaluate_user_credential_for_rule(engine, engine->sessionCredential, rule, true, true, NULL) == errAuthorizationSuccess) { const char * tmp = credential_get_name(engine->sessionCredential); if (tmp != NULL) { @@ -270,7 +289,7 @@ _evaluate_credential_for_rule(engine_t engine, credential_t cred, rule_t rule, b if (credential_is_right(cred) && credential_get_valid(cred) && _compare_string(engine->currentRightName, credential_get_name(cred))) { if (!ignoreShared) { if (!rule_get_shared(rule) && credential_get_shared(cred)) { - LOGV("engine[%i]: - shared right %s (does NOT satisfy rule)", connection_get_pid(engine->conn), credential_get_name(cred)); + os_log_error(AUTHD_LOG, "engine: - shared right %{public}s (does NOT satisfy rule)", credential_get_name(cred)); if (reason) { *reason = unknownReason; } return errAuthorizationDenied; } @@ -290,26 +309,25 @@ static OSStatus _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t rule, bool ignoreShared, bool sessionOwner, enum Reason * reason) { const char * cred_label = sessionOwner ? "session owner" : "credential"; - LOGV("engine[%i]: - validating %s%s %s (%i) for %s", connection_get_pid(engine->conn), - credential_get_shared(cred) ? "shared " : "", + os_log(AUTHD_LOG, "engine: - validating %{public}s%{public}s %{public}s (%i) for %{public}s", credential_get_shared(cred) ? "shared " : "", cred_label, credential_get_name(cred), credential_get_uid(cred), rule_get_name(rule)); if (rule_get_class(rule) != RC_USER) { - LOGV("engine[%i]: - invalid rule class %i (denied)", connection_get_pid(engine->conn), rule_get_class(rule)); + os_log(AUTHD_LOG, "engine: - invalid rule class %i (denied)", rule_get_class(rule)); return errAuthorizationDenied; } if (credential_get_valid(cred) != true) { - LOGV("engine[%i]: - %s %i invalid (does NOT satisfy rule)", connection_get_pid(engine->conn), cred_label, credential_get_uid(cred)); + os_log(AUTHD_LOG, "engine: - %{public}s %i invalid (does NOT satisfy rule)", cred_label, credential_get_uid(cred)); if (reason) { *reason = invalidPassphrase; } return errAuthorizationDenied; } if (engine->now - credential_get_creation_time(cred) > rule_get_timeout(rule)) { - LOGV("engine[%i]: - %s %i expired '%f > %lli' (does NOT satisfy rule)", connection_get_pid(engine->conn), cred_label, credential_get_uid(cred), + os_log(AUTHD_LOG, "engine: - %{public}s %i expired '%f > %lli' (does NOT satisfy rule)", cred_label, credential_get_uid(cred), (engine->now - credential_get_creation_time(cred)), rule_get_timeout(rule)); if (reason) { *reason = unknownReason; } return errAuthorizationDenied; @@ -318,20 +336,20 @@ _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t ru if (!ignoreShared) { if (!rule_get_shared(rule) && credential_get_shared(cred)) { - LOGV("engine[%i]: - shared %s %i (does NOT satisfy rule)", connection_get_pid(engine->conn), cred_label, credential_get_uid(cred)); + os_log(AUTHD_LOG, "engine: - shared %{public}s %i (does NOT satisfy rule)", cred_label, credential_get_uid(cred)); if (reason) { *reason = unknownReason; } return errAuthorizationDenied; } } if (credential_get_uid(cred) == 0) { - LOGV("engine[%i]: - %s %i has uid 0 (does satisfy rule)", connection_get_pid(engine->conn), cred_label, credential_get_uid(cred)); + os_log(AUTHD_LOG, "engine: - %{public}s %i has uid 0 (does satisfy rule)", cred_label, credential_get_uid(cred)); return errAuthorizationSuccess; } if (rule_get_session_owner(rule)) { if (credential_get_uid(cred) == session_get_uid(auth_token_get_session(engine->auth))) { - LOGV("engine[%i]: - %s %i is session owner (does satisfy rule)", connection_get_pid(engine->conn), cred_label, credential_get_uid(cred)); + os_log(AUTHD_LOG, "engine: - %{public}s %i is session owner (does satisfy rule)", cred_label, credential_get_uid(cred)); return errAuthorizationSuccess; } } @@ -351,7 +369,7 @@ _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t ru } if (credential_check_membership(cred, rule_get_group(rule))) { - LOGV("engine[%i]: - %s %i is member of group %s (does satisfy rule)", connection_get_pid(engine->conn), cred_label, credential_get_uid(cred), rule_get_group(rule)); + os_log(AUTHD_LOG, "engine: - %{public}s %i is member of group %{public}s (does satisfy rule)", cred_label, credential_get_uid(cred), rule_get_group(rule)); return errAuthorizationSuccess; } else { if (reason) { *reason = userNotInGroup; } @@ -361,7 +379,7 @@ _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t ru if (reason) { *reason = unacceptableUser; } } - LOGV("engine[%i]: - %s %i (does NOT satisfy rule)", connection_get_pid(engine->conn), cred_label, credential_get_uid(cred)); + os_log(AUTHD_LOG, "engine: - %{public}s %i (does NOT satisfy rule), reason %d", cred_label, credential_get_uid(cred), reason ? *reason : -1); return errAuthorizationDenied; } @@ -398,6 +416,24 @@ _evaluate_builtin_mechanism(engine_t engine, mechanism_t mech) } +static bool +_extract_password_from_la(engine_t engine, CFTypeRef la_context) +{ + bool retval = false; + // try to retrieve secret + CFDataRef passdata = LACopyCredential(la_context, kLACredentialTypeExtractablePasscode, NULL); + if (passdata) { + if (CFDataGetBytePtr(passdata)) { + auth_items_set_data(engine->context, kAuthorizationEnvironmentPassword, CFDataGetBytePtr(passdata), CFDataGetLength(passdata)); + } else { + char nulChar = 0; + auth_items_set_data(engine->context, kAuthorizationEnvironmentPassword, &nulChar, 1); + } + CFRelease(passdata); + } + return retval; +} + static OSStatus _evaluate_mechanisms(engine_t engine, CFArrayRef mechanisms) { @@ -410,88 +446,132 @@ _evaluate_mechanisms(engine_t engine, CFArrayRef mechanisms) auth_items_copy(hints, engine->hints); auth_items_copy(context, engine->sticky_context); + CFDictionaryRef la_result = NULL; + CFIndex count = CFArrayGetCount(mechanisms); for (CFIndex i = 0; i < count; i++) { mechanism_t mech = (mechanism_t)CFArrayGetValueAtIndex(mechanisms, i); if (mechanism_get_type(mech)) { - LOGV("engine[%i]: running builtin mechanism %s (%li of %li)", connection_get_pid(engine->conn), mechanism_get_string(mech), i+1, count); + os_log_debug(AUTHD_LOG, "engine: running builtin mechanism %{public}s (%li of %li)", mechanism_get_string(mech), i+1, count); result = _evaluate_builtin_mechanism(engine, mech); } else { - agent_t agent = _get_agent(engine, mech, true, i == 0); - require_action(agent != NULL, done, result = kAuthorizationResultUndefined; LOGE("engine[%i]: error creating mechanism agent", connection_get_pid(engine->conn))); - - // check if any agent has been interrupted (it necessary if interrupt will come during creation) - CFIndex j; - agent_t agent1; - for (j = 0; j < i; j++) { - agent1 = _get_agent(engine, (mechanism_t)CFArrayGetValueAtIndex(mechanisms, j), false, j == 0); - if(agent_get_state(agent1) == interrupting) { - break; - } - } - if (j < i) { - LOGV("engine[%i]: mechanisms interrupted", connection_get_pid(engine->conn)); - char * buf = NULL; - asprintf(&buf, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent1))); - ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(agent_get_mechanism(agent1)), kAuthorizationResultAllow, buf); - free_safe(buf); - ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(mech), kAuthorizationResultAllow, NULL); - const char * token_name = auth_items_get_string(hints, AGENT_HINT_TOKEN_NAME); - if (token_name && strlen(token_name) == 0) { - auth_items_remove(hints, AGENT_HINT_TOKEN_NAME); - } - auth_items_copy(context, agent_get_context(agent1)); - auth_items_copy(hints, agent_get_hints(agent1)); + bool sheet_variant_used = false; + if (engine->la_context) { + + if (!la_result) { + int tmp = kLAOptionNotInteractive; + CFNumberRef key = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &tmp); + tmp = 1; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &tmp); + if (key && value) { + CFMutableDictionaryRef options = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(options, key, value); + la_result = LACopyResultOfPolicyEvaluation(engine->la_context, kLAPolicyDeviceOwnerAuthentication, options, NULL); + CFReleaseSafe(options); + } + CFReleaseSafe(key); + CFReleaseSafe(value); + } - i = j - 1; - - continue; - } - - LOGV("engine[%i]: running mechanism %s (%li of %li)", connection_get_pid(engine->conn), mechanism_get_string(agent_get_mechanism(agent)), i+1, count); - result = agent_run(agent, hints, context, engine->immutable_hints); - - auth_items_copy(context, agent_get_context(agent)); - auth_items_copy(hints, agent_get_hints(agent)); - - bool interrupted = false; - for (CFIndex i2 = 0; i2 != i; i2++) { - agent_t agent2 = _get_agent(engine, (mechanism_t)CFArrayGetValueAtIndex(mechanisms, i2), false, i == 0); - if (agent_get_state(agent2) == interrupting) { - agent_deactivate(agent); - interrupted = true; - i = i2 - 1; - char * buf = NULL; - asprintf(&buf, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent2))); - ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(agent_get_mechanism(agent2)), kAuthorizationResultAllow, buf); - free_safe(buf); - auth_items_copy(context, agent_get_context(agent2)); - auth_items_copy(hints, agent_get_hints(agent2)); - break; - } - } + // sheet variant in progress + if (strcmp(mechanism_get_string(mech), "builtin:authenticate") == 0) { + // instead of running SecurityAgent, get uid from the authorization + os_log(AUTHD_LOG, "engine: running builtin sheet authenticate"); + if (!la_result) { + result = kAuthorizationResultDeny; // no la_result => was evaluate did not pass + } + sheet_variant_used = true; + } else if (strcmp(mechanism_get_string(mech), "builtin:authenticate,privileged") == 0) { + os_log(AUTHD_LOG, "engine: running builtin sheet privileged authenticate"); + if (!la_result) { + result = kAuthorizationResultDeny; // no la_result => was evaluate did not pass + } else { + if (!_extract_password_from_la(engine, engine->la_context)) { + os_log_debug(AUTHD_LOG, "engine: cannot extract cred"); + } + } + sheet_variant_used = true; + } + } - // Empty token name means that token doesn't exist (e.g. SC was removed). - // Remove empty token name from hints for UI drawing logic. - const char * token_name = auth_items_get_string(hints, AGENT_HINT_TOKEN_NAME); - if (token_name && strlen(token_name) == 0) { - auth_items_remove(hints, AGENT_HINT_TOKEN_NAME); - } - - if (interrupted) { - LOGV("engine[%i]: mechanisms interrupted", connection_get_pid(engine->conn)); - enum Reason reason = worldChanged; - auth_items_set_data(hints, AGENT_HINT_RETRY_REASON, &reason, sizeof(reason)); - result = kAuthorizationResultAllow; - _cf_dictionary_iterate(engine->mechanism_agents, ^bool(CFTypeRef key __attribute__((__unused__)), CFTypeRef value) { - agent_t tempagent = (agent_t)value; - agent_clear_interrupt(tempagent); - return true; - }); - } + if (!sheet_variant_used) { + agent_t agent = _get_agent(engine, mech, true, i == 0); + require_action(agent != NULL, done, result = kAuthorizationResultUndefined; os_log_error(AUTHD_LOG, "engine: error creating mechanism agent")); + + // check if any agent has been interrupted (it necessary if interrupt will come during creation) + CFIndex j; + agent_t agent1; + for (j = 0; j < i; j++) { + agent1 = _get_agent(engine, (mechanism_t)CFArrayGetValueAtIndex(mechanisms, j), false, j == 0); + if(agent1 && agent_get_state(agent1) == interrupting) { + break; + } + } + if (j < i) { + os_log(AUTHD_LOG, "engine: mechanisms interrupted"); + char * buf = NULL; + asprintf(&buf, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent1))); + ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(agent_get_mechanism(agent1)), kAuthorizationResultAllow, buf); + free_safe(buf); + ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(mech), kAuthorizationResultAllow, NULL); + const char * token_name = auth_items_get_string(hints, AGENT_HINT_TOKEN_NAME); + if (token_name && strlen(token_name) == 0) { + auth_items_remove(hints, AGENT_HINT_TOKEN_NAME); + } + auth_items_copy(context, agent_get_context(agent1)); + auth_items_copy(hints, agent_get_hints(agent1)); + + i = j - 1; + + continue; + } + + os_log(AUTHD_LOG, "engine: running mechanism %{public}s (%li of %li)", mechanism_get_string(agent_get_mechanism(agent)), i+1, count); + + result = agent_run(agent, hints, context, engine->immutable_hints); + + auth_items_copy(context, agent_get_context(agent)); + auth_items_copy(hints, agent_get_hints(agent)); + + bool interrupted = false; + for (CFIndex i2 = 0; i2 != i; i2++) { + agent_t agent2 = _get_agent(engine, (mechanism_t)CFArrayGetValueAtIndex(mechanisms, i2), false, i == 0); + if (agent2 && agent_get_state(agent2) == interrupting) { + agent_deactivate(agent); + interrupted = true; + i = i2 - 1; + char * buf = NULL; + asprintf(&buf, "evaluation interrupted by %s; restarting evaluation there", mechanism_get_string(agent_get_mechanism(agent2))); + ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(agent_get_mechanism(agent2)), kAuthorizationResultAllow, buf); + free_safe(buf); + auth_items_copy(context, agent_get_context(agent2)); + auth_items_copy(hints, agent_get_hints(agent2)); + break; + } + } + + // Empty token name means that token doesn't exist (e.g. SC was removed). + // Remove empty token name from hints for UI drawing logic. + const char * token_name = auth_items_get_string(hints, AGENT_HINT_TOKEN_NAME); + if (token_name && strlen(token_name) == 0) { + auth_items_remove(hints, AGENT_HINT_TOKEN_NAME); + } + + if (interrupted) { + os_log(AUTHD_LOG, "engine: mechanisms interrupted"); + enum Reason reason = worldChanged; + auth_items_set_data(hints, AGENT_HINT_RETRY_REASON, &reason, sizeof(reason)); + result = kAuthorizationResultAllow; + _cf_dictionary_iterate(engine->mechanism_agents, ^bool(CFTypeRef key __attribute__((__unused__)), CFTypeRef value) { + agent_t tempagent = (agent_t)value; + agent_clear_interrupt(tempagent); + return true; + }); + } + } } - + if (result == kAuthorizationResultAllow) { ccaudit_log_mechanism(ccaudit, engine->currentRightName, mechanism_get_string(mech), kAuthorizationResultAllow, NULL); } else { @@ -516,7 +596,8 @@ done: CFReleaseSafe(ccaudit); CFReleaseSafe(context); CFReleaseSafe(hints); - + CFReleaseSafe(la_result); + switch(result) { case kAuthorizationResultDeny: @@ -529,7 +610,7 @@ done: return errAuthorizationInternal; default: { - LOGV("engine[%i]: unexpected error result", connection_get_pid(engine->conn)); + os_log_error(AUTHD_LOG, "engine: unexpected error result"); return errAuthorizationInternal; } } @@ -540,7 +621,7 @@ _evaluate_authentication(engine_t engine, rule_t rule) { OSStatus status = errAuthorizationDenied; ccaudit_t ccaudit = ccaudit_create(engine->proc, engine->auth, AUE_ssauthint); - LOGV("engine[%i]: evaluate authentication", connection_get_pid(engine->conn)); + os_log_debug(AUTHD_LOG, "engine: evaluate authentication"); _set_rule_hints(engine->hints, rule); _set_session_hints(engine, rule); @@ -548,7 +629,7 @@ _evaluate_authentication(engine_t engine, rule_t rule) if (!(CFArrayGetCount(mechanisms) > 0)) { mechanisms = rule_get_mechanisms(engine->authenticateRule); } - require_action(CFArrayGetCount(mechanisms) > 0, done, LOGV("engine[%i]: error no mechanisms found", connection_get_pid(engine->conn))); + require_action(CFArrayGetCount(mechanisms) > 0, done, os_log_debug(AUTHD_LOG, "engine: error no mechanisms found")); int64_t ruleTries = rule_get_tries(rule); for (engine->tries = 0; engine->tries < ruleTries; engine->tries++) { @@ -557,7 +638,7 @@ _evaluate_authentication(engine_t engine, rule_t rule) auth_items_set_int(engine->hints, AGENT_HINT_TRIES, engine->tries); status = _evaluate_mechanisms(engine, mechanisms); - LOGV("engine[%i]: evaluate mechanisms result %d", connection_get_pid(engine->conn), (int)status); + os_log_debug(AUTHD_LOG, "engine: evaluate mechanisms result %d", (int)status); // successfully ran mechanisms to obtain credential if (status == errAuthorizationSuccess) { @@ -568,15 +649,19 @@ _evaluate_authentication(engine_t engine, rule_t rule) if (auth_items_exist(engine->context, "uid")) { newCred = credential_create(auth_items_get_uint(engine->context, "uid")); } else { - LOGV("engine[%i]: mechanism failed to return a valid uid", connection_get_pid(engine->conn)); + os_log_error(AUTHD_LOG, "engine: mechanism failed to return a valid uid"); + if (engine->la_context) { + // sheet failed so remove sheet reference and next time, standard dialog will be displayed + CFReleaseNull(engine->la_context); + } } if (newCred) { if (credential_get_valid(newCred)) { - LOG("UID %u authenticated as user %s (UID %u) for right '%s'", auth_token_get_uid(engine->auth), credential_get_name(newCred), credential_get_uid(newCred), engine->currentRightName); + 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); ccaudit_log_success(ccaudit, newCred, engine->currentRightName); } else { - LOG("UID %u failed to authenticate as user '%s' for right '%s'", auth_token_get_uid(engine->auth), 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, "username"), engine->currentRightName); ccaudit_log_failure(ccaudit, auth_items_get_string(engine->context, "username"), engine->currentRightName); } @@ -594,20 +679,29 @@ _evaluate_authentication(engine_t engine, rule_t rule) session_t session = auth_token_get_session(engine->auth); if (credential_get_uid(newCred) == session_get_uid(session)) { - LOGV("engine[%i]: authenticated as the session owner", connection_get_pid(engine->conn)); + os_log_debug(AUTHD_LOG, "engine: authenticated as the session owner"); session_set_attributes(auth_token_get_session(engine->auth), AU_SESSION_FLAG_HAS_AUTHENTICATED); } break; - } + } else { + os_log_error(AUTHD_LOG, "engine: user credential for rule failed (%d)", (int)status); + } CFReleaseSafe(newCred); } } else if (status == errAuthorizationCanceled || status == errAuthorizationInternal) { - break; + os_log_error(AUTHD_LOG, "engine: evaluate cancelled or failed %d", (int)status); + break; } else if (status == errAuthorizationDenied) { - engine->reason = invalidPassphrase; + os_log_error(AUTHD_LOG, "engine: evaluate denied"); + engine->reason = invalidPassphrase; + if (engine->la_context) { + // for sheet authorizations do not retry with sheet as there is no new sheet UI + CFReleaseNull(engine->la_context); + auth_items_remove(engine->context, AGENT_CONTEXT_UID); + } } } @@ -615,6 +709,7 @@ _evaluate_authentication(engine_t engine, rule_t rule) engine->reason = tooManyTries; auth_items_set_data(engine->hints, AGENT_HINT_RETRY_REASON, &engine->reason, sizeof(engine->reason)); auth_items_set_int(engine->hints, AGENT_HINT_TRIES, engine->tries); + // TODO: determine why evaluate_mechanism is run once again and possibly remove this call _evaluate_mechanisms(engine, mechanisms); ccaudit_log(ccaudit, engine->currentRightName, NULL, 1113); } @@ -634,7 +729,7 @@ _check_entitlement_for_rule(engine_t engine, rule_t rule) if (rule_check_flags(rule, RuleFlagEntitledAndGroup)) { if (auth_token_has_entitlement_for_right(engine->auth, engine->currentRightName)) { if (credential_check_membership(auth_token_get_credential(engine->auth), rule_get_group(rule))) { - LOGV("engine[%i]: creator of authorization has entitlement for right %s and is member of group '%s'", connection_get_pid(engine->conn), engine->currentRightName, rule_get_group(rule)); + os_log_debug(AUTHD_LOG, "engine: creator of authorization has entitlement for right %{public}s and is member of group '%{public}s'", engine->currentRightName, rule_get_group(rule)); entitled = true; goto done; } @@ -646,7 +741,7 @@ _check_entitlement_for_rule(engine_t engine, rule_t rule) value = auth_token_copy_entitlement_value(engine->auth, "com.apple.networking.vpn.configuration"); if (value) { if (credential_check_membership(auth_token_get_credential(engine->auth), rule_get_group(rule))) { - LOGV("engine[%i]: creator of authorization has VPN entitlement and is member of group '%s'", connection_get_pid(engine->conn), rule_get_group(rule)); + os_log_debug(AUTHD_LOG, "engine: creator of authorization has VPN entitlement and is member of group '%{public}s'", rule_get_group(rule)); entitled = true; goto done; } @@ -668,7 +763,7 @@ _evaluate_class_user(engine_t engine, rule_t rule) } if (rule_get_allow_root(rule) && auth_token_get_uid(engine->auth) == 0) { - LOGV("engine[%i]: creator of authorization has uid == 0 granting right %s", connection_get_pid(engine->conn), engine->currentRightName); + os_log_debug(AUTHD_LOG, "engine: creator of authorization has uid == 0 granting right %{public}s", engine->currentRightName); return errAuthorizationSuccess; } @@ -725,29 +820,31 @@ _evaluate_class_user(engine_t engine, rule_t rule) // Finally - we didn't find a credential. Obtain a new credential if our flags let us do so. if (!(engine->flags & kAuthorizationFlagExtendRights)) { - LOGV("engine[%i]: authorization denied (kAuthorizationFlagExtendRights not set)", connection_get_pid(engine->conn)); + os_log_error(AUTHD_LOG, "engine: authorization denied (kAuthorizationFlagExtendRights not set)"); return errAuthorizationDenied; } // authorization that timeout immediately cannot be preauthorized if (engine->flags & kAuthorizationFlagPreAuthorize && rule_get_timeout(rule) == 0) { return errAuthorizationSuccess; - } - - if (!(engine->flags & kAuthorizationFlagInteractionAllowed)) { - LOGV("engine[%i]: Interaction not allowed (kAuthorizationFlagInteractionAllowed not set)", connection_get_pid(engine->conn)); - return errAuthorizationInteractionNotAllowed; - } - - if (!(session_get_attributes(auth_token_get_session(engine->auth)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)) { - LOGV("engine[%i]: Interaction not allowed (session has no ui access)", connection_get_pid(engine->conn)); - return errAuthorizationInteractionNotAllowed; - } - - if (server_in_dark_wake()) { - LOGV("engine[%i]: authorization denied (in DarkWake)", connection_get_pid(engine->conn)); - return errAuthorizationDenied; - } + } + + if (!engine->preauthorizing) { + if (!(engine->flags & kAuthorizationFlagInteractionAllowed)) { + os_log_error(AUTHD_LOG, "engine: Interaction not allowed (kAuthorizationFlagInteractionAllowed not set)"); + return errAuthorizationInteractionNotAllowed; + } + + if (!(session_get_attributes(auth_token_get_session(engine->auth)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)) { + os_log_error(AUTHD_LOG, "engine: Interaction not allowed (session has no ui access)"); + return errAuthorizationInteractionNotAllowed; + } + + if (server_in_dark_wake()) { + os_log_error(AUTHD_LOG, "engine: authorization denied (DW)"); + return errAuthorizationDenied; + } + } return _evaluate_authentication(engine, rule); } @@ -761,7 +858,7 @@ _evaluate_class_rule(engine_t engine, rule_t rule, bool *save_pwd) uint32_t total = (uint32_t)rule_get_delegates_count(rule); __block uint32_t success_count = 0; __block uint32_t count = 0; - LOGV("engine[%i]: ** rule %s has %zi delegates kofn = %lli", connection_get_pid(engine->conn), rule_get_name(rule), total, kofn); + os_log_debug(AUTHD_LOG, "engine: ** rule %{public}s has %zi delegates kofn = %lli",rule_get_name(rule), total, kofn); rule_delegates_iterator(rule, ^bool(rule_t delegate) { count++; @@ -770,7 +867,7 @@ _evaluate_class_rule(engine_t engine, rule_t rule, bool *save_pwd) return false; } - LOGV("engine[%i]: * evaluate rule %s (%i)", connection_get_pid(engine->conn), rule_get_name(delegate), count); + os_log_debug(AUTHD_LOG, "engine: * evaluate rule %{public}s (%i)", rule_get_name(delegate), count); status = _evaluate_rule(engine, delegate, save_pwd); // if status is cancel/internal error abort @@ -781,7 +878,7 @@ _evaluate_class_rule(engine_t engine, rule_t rule, bool *save_pwd) if (kofn != 0) { // if remaining is less than required abort if ((total - count) < (kofn - success_count)) { - LOGD("engine[%i]: rule evaluation remaining: %i, required: %lli", connection_get_pid(engine->conn), (total - count), (kofn - success_count)); + os_log_debug(AUTHD_LOG, "engine: rule evaluation remaining: %i, required: %lli", (total - count), (kofn - success_count)); return false; } return true; @@ -799,7 +896,7 @@ _evaluate_class_rule(engine_t engine, rule_t rule, bool *save_pwd) static bool _preevaluate_class_rule(engine_t engine, rule_t rule) { - LOGV("engine[%i]: _preevaluate_class_rule %s", connection_get_pid(engine->conn), rule_get_name(rule)); + os_log_debug(AUTHD_LOG, "engine: _preevaluate_class_rule %{public}s", rule_get_name(rule)); __block bool password_only = false; rule_delegates_iterator(rule, ^bool(rule_t delegate) { @@ -819,7 +916,7 @@ _evaluate_class_mechanism(engine_t engine, rule_t rule) OSStatus status = errAuthorizationDenied; CFArrayRef mechanisms = NULL; - require_action(rule_get_mechanisms_count(rule) > 0, done, status = errAuthorizationSuccess; LOGV("engine[%i]: no mechanisms specified", connection_get_pid(engine->conn))); + require_action(rule_get_mechanisms_count(rule) > 0, done, status = errAuthorizationSuccess; os_log_error(AUTHD_LOG, "engine: no mechanisms specified")); mechanisms = rule_get_mechanisms(rule); @@ -827,7 +924,7 @@ _evaluate_class_mechanism(engine_t engine, rule_t rule) CFIndex count = CFArrayGetCount(mechanisms); for (CFIndex i = 0; i < count; i++) { if (!mechanism_is_privileged((mechanism_t)CFArrayGetValueAtIndex(mechanisms, i))) { - LOGE("engine[%i]: authorization denied (in DW)", connection_get_pid(engine->conn)); + os_log_error(AUTHD_LOG, "engine: authorization denied (in DW)"); goto done; } } @@ -840,14 +937,14 @@ _evaluate_class_mechanism(engine_t engine, rule_t rule) auth_items_set_int(engine->hints, AGENT_HINT_TRIES, engine->tries); status = _evaluate_mechanisms(engine, mechanisms); - LOGV("engine[%i]: evaluate mechanisms result %d", connection_get_pid(engine->conn), (int)status); + os_log_debug(AUTHD_LOG, "engine: evaluate mechanisms result %d", (int)status); if (status == errAuthorizationSuccess) { credential_t newCred = NULL; if (auth_items_exist(engine->context, "uid")) { newCred = credential_create(auth_items_get_uint(engine->context, "uid")); } else { - LOGV("engine[%i]: mechanism did not return a uid", connection_get_pid(engine->conn)); + os_log(AUTHD_LOG, "engine: mechanism did not return a uid"); } if (newCred) { @@ -876,31 +973,67 @@ done: return status; } +// TODO: Remove when all clients have adopted entitlement +static bool +enforced_entitlement(void) +{ + bool enforced_enabled = false; + //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true + CFTypeRef enforce = (CFNumberRef)CFPreferencesCopyValue(CFSTR("enforceEntitlement"), CFSTR(SECURITY_AUTH_NAME), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + if (enforce && CFGetTypeID(enforce) == CFBooleanGetTypeID()) { + enforced_enabled = CFBooleanGetValue((CFBooleanRef)enforce); + os_log_debug(AUTHD_LOG, "enforceEntitlement for extract password: %{public}s", enforced_enabled ? "enabled" : "disabled"); + } + CFReleaseSafe(enforce); + + return enforced_enabled; +} + static OSStatus _evaluate_rule(engine_t engine, rule_t rule, bool *save_pwd) { if (rule_check_flags(rule, RuleFlagEntitled)) { if (auth_token_has_entitlement_for_right(engine->auth, engine->currentRightName)) { - LOGV("engine[%i]: rule allow, creator of authorization has entitlement for right %s", connection_get_pid(engine->conn), engine->currentRightName); + os_log_debug(AUTHD_LOG, "engine: rule allow, creator of authorization has entitlement for right %{public}s", engine->currentRightName); return errAuthorizationSuccess; } } - - if (rule_check_flags(rule, RuleFlagRequireAppleSigned)) { + + // check apple signature also for every sheet authorization + disable this check for debug builds + if (engine->la_context || rule_check_flags(rule, RuleFlagRequireAppleSigned)) { if (!auth_token_apple_signed(engine->auth)) { - LOGE("engine[%i]: rule deny, creator of authorization is not signed by apple", connection_get_pid(engine->conn)); +#ifdef NDEBUG + os_log_error(AUTHD_LOG, "engine: rule deny, creator of authorization is not signed by Apple"); return errAuthorizationDenied; +#else + os_log_debug(AUTHD_LOG, "engine: in release mode, this rule would be denied because creator of authorization is not signed by Apple"); +#endif } } - *save_pwd |= rule_get_extract_password(rule); + if (rule_get_extract_password(rule)) { + // check if process is entitled to extract password + CFTypeRef extract_password_entitlement = auth_token_copy_entitlement_value(engine->auth, "com.apple.authorization.extract-password"); + if (extract_password_entitlement && (CFGetTypeID(extract_password_entitlement) == CFBooleanGetTypeID()) && extract_password_entitlement == kCFBooleanTrue) { + *save_pwd = TRUE; + os_log_debug(AUTHD_LOG, "engine: authorization allowed to extract password"); + } else { + os_log_debug(AUTHD_LOG, "engine: authorization NOT allowed to extract password"); + } + CFReleaseSafe(extract_password_entitlement); + } + + // TODO: Remove when all clients have adopted entitlement + if (!enforced_entitlement()) { + *save_pwd |= rule_get_extract_password(rule); + } switch (rule_get_class(rule)) { case RC_ALLOW: - LOGV("engine[%i]: rule set to allow", connection_get_pid(engine->conn)); + os_log(AUTHD_LOG, "engine: rule set to allow"); return errAuthorizationSuccess; case RC_DENY: - LOGV("engine[%i]: rule set to deny", connection_get_pid(engine->conn)); + os_log(AUTHD_LOG, "engine: rule set to deny"); return errAuthorizationDenied; case RC_USER: return _evaluate_class_user(engine, rule); @@ -909,7 +1042,7 @@ _evaluate_rule(engine_t engine, rule_t rule, bool *save_pwd) case RC_MECHANISM: return _evaluate_class_mechanism(engine, rule); default: - LOGE("engine[%i]: invalid class for rule or rule not found: %s", connection_get_pid(engine->conn), rule_get_name(rule)); + os_log_error(AUTHD_LOG, "engine: invalid class for rule or rule not found: %{public}s", rule_get_name(rule)); return errAuthorizationInternal; } } @@ -918,7 +1051,7 @@ _evaluate_rule(engine_t engine, rule_t rule, bool *save_pwd) static bool _preevaluate_rule(engine_t engine, rule_t rule) { - LOGV("engine[%i]: _preevaluate_rule %s", connection_get_pid(engine->conn), rule_get_name(rule)); + os_log_debug(AUTHD_LOG, "engine: _preevaluate_rule %{public}s", rule_get_name(rule)); switch (rule_get_class(rule)) { case RC_ALLOW: @@ -983,7 +1116,7 @@ done: r = rule_create_with_string("", dbconn); if (rule_get_id(r) == 0) { CFReleaseNull(r); - LOGE("engine[%i]: default rule lookup error (missing), using builtin defaults", connection_get_pid(engine->conn)); + os_log_error(AUTHD_LOG, "engine: default rule lookup error (missing), using builtin defaults"); r = rule_create_default(); } } @@ -995,8 +1128,7 @@ static void _parse_environment(engine_t engine, auth_items_t environment) require(environment != NULL, done); #if DEBUG - LOGV("engine[%i]: Dumping Environment", connection_get_pid(engine->conn)); - _show_cf(environment); + os_log_debug(AUTHD_LOG, "engine: Dumping Environment: %@", environment); #endif // Check if a credential was passed into the environment and we were asked to extend the rights @@ -1007,17 +1139,17 @@ static void _parse_environment(engine_t engine, auth_items_t environment) require(password_was_used == true, done); bool shared = auth_items_exist(environment, kAuthorizationEnvironmentShared); - require_action(user != NULL, done, LOGV("engine[%i]: user not used password", connection_get_pid(engine->conn))); + require_action(user != NULL, done, os_log_debug(AUTHD_LOG, "engine: user not used password")); struct passwd *pw = getpwnam(user); - require_action(pw != NULL, done, LOGE("engine[%i]: user not found %s", connection_get_pid(engine->conn), user)); + require_action(pw != NULL, done, os_log_error(AUTHD_LOG, "engine: user not found %{public}s", user)); int checkpw_status = checkpw_internal(pw, pass ? pass : ""); - require_action(checkpw_status == CHECKPW_SUCCESS, done, LOGE("engine[%i]: checkpw() returned %d; failed to authenticate user %s (uid %u).", connection_get_pid(engine->conn), checkpw_status, pw->pw_name, pw->pw_uid)); + require_action(checkpw_status == CHECKPW_SUCCESS, done, os_log_error(AUTHD_LOG, "engine: checkpw() returned %d; failed to authenticate user %{public}s (uid %u).", checkpw_status, pw->pw_name, pw->pw_uid)); credential_t cred = credential_create(pw->pw_uid); if (credential_get_valid(cred)) { - LOG("engine[%i]: checkpw() succeeded, creating credential for user %s", connection_get_pid(engine->conn), user); + os_log(AUTHD_LOG, "engine: checkpw() succeeded, creating credential for user %{public}s", user); _engine_set_credential(engine, cred, shared); auth_items_set_string(engine->context, kAuthorizationEnvironmentUsername, user); @@ -1035,13 +1167,13 @@ static bool _verify_sandbox(engine_t engine, const char * right) { pid_t pid = process_get_pid(engine->proc); if (sandbox_check(pid, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME, right)) { - LOGE("Sandbox denied authorizing right '%s' by client '%s' [%d]", right, process_get_code_url(engine->proc), pid); + os_log_error(AUTHD_LOG, "Sandbox denied authorizing right '%{public}s' by client '%{public}s' [%d]", right, process_get_code_url(engine->proc), pid); return false; } pid = auth_token_get_pid(engine->auth); if (auth_token_get_sandboxed(engine->auth) && sandbox_check_by_audit_token(auth_token_get_audit_info(engine->auth)->opaqueToken, "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME, right)) { - LOGE("Sandbox denied authorizing right '%s' for authorization created by '%s' [%d]", right, auth_token_get_code_url(engine->auth), pid); + os_log_error(AUTHD_LOG, "Sandbox denied authorizing right '%{public}s' for authorization created by '%{public}s' [%d]", right, auth_token_get_code_url(engine->auth), pid); return false; } @@ -1051,10 +1183,151 @@ 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) +{ + os_log(AUTHD_LOG, "engine: preauthorizing"); + + OSStatus status = errAuthorizationDenied; + bool save_password = false; + CFTypeRef extract_password_entitlement = auth_token_copy_entitlement_value(engine->auth, "com.apple.authorization.extract-password"); + if (extract_password_entitlement && (CFGetTypeID(extract_password_entitlement) == CFBooleanGetTypeID()) && extract_password_entitlement == kCFBooleanTrue) { + save_password = true; + os_log_debug(AUTHD_LOG, "engine: authorization allowed to extract password"); + } else { + os_log_debug(AUTHD_LOG, "engine: authorization NOT allowed to extract password"); + } + CFReleaseSafe(extract_password_entitlement); + + // TODO: Remove when all clients have adopted entitlement + if (!enforced_entitlement()) { + save_password = true; + } + + engine->flags = kAuthorizationFlagExtendRights; + engine->preauthorizing = true; + CFTypeRef la_context = engine_copy_context(engine, credentials); + if (la_context) { + _extract_password_from_la(engine, la_context); + CFRelease(la_context); + } + + 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, "engine: unable to create items")); + 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)", + 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)); + 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)", + 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); + break; + default: + os_log_error(AUTHD_LOG, "engine: preauthorize returned %d => returning errAuthorizationInternal", (int)status); + status = errAuthorizationInternal; + break; + } + + CFReleaseSafe(rule); + + if (engine->dismissed) { + os_log_error(AUTHD_LOG, "engine: engine dismissed"); + status = errAuthorizationDenied; + } + + os_log_debug(AUTHD_LOG, "engine: preauthorize result: %d", (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: adding least privileged %{public}scredential %{public}s to authorization", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred)); + } else { + os_log(AUTHD_LOG, "engine: adding %{public}scredential %{public}s (%i) to authorization", 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); + } + + if ((status == errAuthorizationSuccess) || (status == errAuthorizationCanceled)) { + auth_items_t encrypted_items = auth_items_create(); + require_action(encrypted_items != NULL, done, os_log_error(AUTHD_LOG, "engine: unable to create items")); + auth_items_content_copy_with_flags(encrypted_items, engine->context, kAuthorizationContextFlagExtractable); +#if DEBUG + os_log_debug(AUTHD_LOG, "engine: ********** Dumping preauthorized context for encryption **********"); + 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: encrypted preauthorization context data"); + CFReleaseSafe(encrypted_items); + } + +done: + engine->preauthorizing = false; + auth_items_clear(engine->context); + auth_items_clear(engine->sticky_context); + CFDictionaryRemoveAllValues(engine->mechanism_agents); + return status; +} + OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t environment, AuthorizationFlags flags) { __block OSStatus status = errAuthorizationSuccess; - __block bool savePassword = false; + __block bool save_password = false; __block bool password_only = false; ccaudit_t ccaudit = NULL; @@ -1071,9 +1344,15 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en if (environment) { _parse_environment(engine, environment); auth_items_copy(engine->hints, environment); + engine_acquire_sheet_data(engine); } - - auth_items_copy(engine->context, auth_token_get_context(engine->auth)); + + auth_items_t decrypted_items = auth_items_create(); + require_action(decrypted_items != NULL, done, os_log_error(AUTHD_LOG, "engine: enable to create items")); + 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); @@ -1085,7 +1364,7 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en auth_rights_iterate(rights, ^bool(const char *key) { if (!key) return true; - LOGV("engine[%i]: checking if rule %s contains password-only item", connection_get_pid(engine->conn), key); + os_log_debug(AUTHD_LOG, "engine: checking if rule %{public}s contains password-only item", key); rule_t rule = _find_rule(engine, dbconn, key); @@ -1101,7 +1380,7 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en } if (password_only) { - LOGV("engine[%i]: password-only item found, forcing SecurityAgent to use password-only UI", connection_get_pid(engine->conn)); + os_log_debug(AUTHD_LOG, "engine: password-only item found, forcing SecurityAgent to use password-only UI"); auth_items_set_bool(engine->immutable_hints, AGENT_HINT_PASSWORD_ONLY, true); } @@ -1117,13 +1396,13 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en authdb_connection_t dbconn = authdb_connection_acquire(server_get_database()); // get db handle - LOGV("engine[%i]: evaluate right %s", connection_get_pid(engine->conn), key); + os_log_debug(AUTHD_LOG, "engine: evaluate right %{public}s", key); rule_t rule = _find_rule(engine, dbconn, key); const char * rule_name = rule_get_name(rule); if (rule_name && (strcasecmp(rule_name, "") == 0)) { rule_name = "default (not defined)"; } - LOGV("engine[%i]: using rule %s", connection_get_pid(engine->conn), rule_name); + os_log_debug(AUTHD_LOG, "engine: using rule %{public}s", rule_name); // only need the hints & mechanisms if we are going to show ui if (engine->flags & kAuthorizationFlagInteractionAllowed) { @@ -1141,7 +1420,7 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en ccaudit_log(ccaudit, key, rule_name, 0); - status = _evaluate_rule(engine, engine->currentRule, &savePassword); + status = _evaluate_rule(engine, engine->currentRule, &save_password); switch (status) { case errAuthorizationSuccess: auth_rights_add(engine->grantedRights, key); @@ -1154,7 +1433,7 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en auth_rights_set_flags(engine->grantedRights, engine->currentRightName, kAuthorizationFlagPreAuthorize); } - LOG("Succeeded authorizing right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d)", + os_log(AUTHD_LOG, "Succeeded authorizing right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d)", key, 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)); break; @@ -1162,17 +1441,17 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en case errAuthorizationInteractionNotAllowed: case errAuthorizationCanceled: if (engine->flags & kAuthorizationFlagInteractionAllowed) { - LOG("Failed to authorize right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d) (%i)", + os_log(AUTHD_LOG, "Failed to authorize right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i)", key, 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); } else { - LOGV("Failed to authorize right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d) (%d)", + os_log_debug(AUTHD_LOG, "Failed to authorize right '%{public}s' by client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%d)", key, 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); } break; default: - LOGE("engine[%i]: evaluate returned %d returning errAuthorizationInternal", connection_get_pid(engine->conn), (int)status); + os_log_error(AUTHD_LOG, "engine: evaluate returned %d returning errAuthorizationInternal", (int)status); status = errAuthorizationInternal; break; } @@ -1193,7 +1472,7 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en }); if (password_only) { - LOGV("engine[%i]: removing password-only flag", connection_get_pid(engine->conn)); + os_log_debug(AUTHD_LOG, "engine: removing password-only flag"); auth_items_remove(engine->immutable_hints, AGENT_HINT_PASSWORD_ONLY); } @@ -1202,11 +1481,11 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en } if (engine->dismissed) { - LOGE("engine: engine dismissed"); + os_log_error(AUTHD_LOG, "engine: dismissed"); status = errAuthorizationDenied; } - LOGV("engine[%i]: authorize result: %d", connection_get_pid(engine->conn), (int)status); + os_log_debug(AUTHD_LOG, "engine: authorize result: %d", (int)status); if ((engine->flags & kAuthorizationFlagExtendRights) && !(engine->flags & kAuthorizationFlagDestroyRights)) { _cf_set_iterate(engine->credentials, ^bool(CFTypeRef value) { @@ -1221,20 +1500,30 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en session_set_credential(session, cred); } if (credential_is_right(cred)) { - LOGV("engine[%i]: adding least privileged %scredential %s to authorization", connection_get_pid(engine->conn), credential_get_shared(cred) ? "shared " : "", credential_get_name(cred)); + os_log_debug(AUTHD_LOG, "engine: adding least privileged %{public}scredential %{public}s to authorization", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred)); } else { - LOGV("engine[%i]: adding %scredential %s (%i) to authorization", connection_get_pid(engine->conn), credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred)); + os_log_debug(AUTHD_LOG, "engine: adding %{public}scredential %{public}s (%i) to authorization", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred)); } return true; }); } - if (status == errAuthorizationSuccess && savePassword) { + if (status == errAuthorizationSuccess && save_password) { auth_items_set_flags(engine->context, kAuthorizationEnvironmentPassword, kAuthorizationContextFlagExtractable); } if ((status == errAuthorizationSuccess) || (status == errAuthorizationCanceled)) { - auth_items_copy_with_flags(auth_token_get_context(engine->auth), engine->context, kAuthorizationContextFlagExtractable); + auth_items_t encrypted_items = auth_items_create(); + require_action(encrypted_items != NULL, done, os_log_error(AUTHD_LOG, "engine: unable to create items")); + auth_items_content_copy_with_flags(encrypted_items, engine->context, kAuthorizationContextFlagExtractable); +#if DEBUG + os_log_debug(AUTHD_LOG,"engine: ********** Dumping context for encryption **********"); + 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: encrypted authorization context data"); + CFReleaseSafe(encrypted_items); } if (auth_rights_get_count(rights) > 0) { @@ -1242,22 +1531,22 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en } #if DEBUG - LOGV("engine[%i]: ********** Dumping auth->credentials **********", connection_get_pid(engine->conn)); + os_log_debug(AUTHD_LOG, "engine: ********** Dumping auth->credentials **********"); auth_token_credentials_iterate(engine->auth, ^bool(credential_t cred) { - _show_cf(cred); - return true; + os_log_debug(AUTHD_LOG, "%@", cred); + return true; }); - LOGV("engine[%i]: ********** Dumping session->credentials **********", connection_get_pid(engine->conn)); + os_log_debug(AUTHD_LOG, "engine: ********** Dumping session->credentials **********"); session_credentials_iterate(auth_token_get_session(engine->auth), ^bool(credential_t cred) { - _show_cf(cred); + os_log_debug(AUTHD_LOG, "%@", cred); return true; }); - LOGV("engine[%i]: ********** Dumping engine->context **********", connection_get_pid(engine->conn)); - _show_cf(engine->context); - LOGV("engine[%i]: ********** Dumping auth->context **********", connection_get_pid(engine->conn)); - _show_cf(auth_token_get_context(engine->auth)); - LOGV("engine[%i]: ********** Dumping granted rights **********", connection_get_pid(engine->conn)); - _show_cf(engine->grantedRights); + os_log_debug(AUTHD_LOG, "engine: ********** Dumping engine->context **********"); + os_log_debug(AUTHD_LOG, "%@", engine->context); + os_log_debug(AUTHD_LOG, "engine: ********** Dumping auth->context **********"); + os_log_debug(AUTHD_LOG, "%@", engine->auth); + os_log_debug(AUTHD_LOG, "engine: ********** Dumping granted rights **********"); + os_log_debug(AUTHD_LOG, "%@", engine->grantedRights); #endif done: @@ -1324,7 +1613,7 @@ OSStatus engine_verify_modification(engine_t engine, rule_t rule, bool remove, b size_t len = strlen(right); require(len != 0, done); - require_action(right[len-1] != '.', done, LOGE("engine[%i]: not allowed to set wild card rules", connection_get_pid(engine->conn))); + require_action(right[len-1] != '.', done, os_log_error(AUTHD_LOG, "engine: not allowed to set wild card rules")); if (strncasecmp(right, kConfigRight, strlen(kConfigRight)) == 0) { // special handling of meta right change: @@ -1353,10 +1642,10 @@ OSStatus engine_verify_modification(engine_t engine, rule_t rule, bool remove, b checkRight = auth_rights_create(); auth_rights_add(checkRight, buf); - status = engine_authorize(engine, checkRight, NULL, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights); + status = engine_authorize(engine, checkRight, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights); done: - LOGV("engine[%i]: authorizing %s for db modification: %d", connection_get_pid(engine->conn), right, (int)status); + os_log_debug(AUTHD_LOG, "engine: authorizing %{public}s for db modification: %d", right, (int)status); CFReleaseSafe(checkRight); return status; } @@ -1364,7 +1653,7 @@ done: void _engine_set_credential(engine_t engine, credential_t cred, bool shared) { - LOGV("engine[%i]: adding %scredential %s (%i) to engine shared: %i", connection_get_pid(engine->conn), credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred), shared); + os_log_debug(AUTHD_LOG, "engine: adding %{public}scredential %{public}s (%i) to engine shared: %i", credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred), shared); CFSetSetValue(engine->credentials, cred); if (shared) { credential_t sharedCred = credential_create_with_credential(cred, true); @@ -1389,7 +1678,7 @@ void engine_destroy_agents(engine_t engine) engine->dismissed = true; _cf_dictionary_iterate(engine->mechanism_agents, ^bool(CFTypeRef key __attribute__((__unused__)), CFTypeRef value) { - LOGD("engine[%i]: Destroying %s", connection_get_pid(engine->conn), mechanism_get_string((mechanism_t)key)); + os_log_debug(AUTHD_LOG, "engine: Destroying %{public}s", mechanism_get_string((mechanism_t)key)); agent_t agent = (agent_t)value; agent_destroy(agent); @@ -1405,3 +1694,57 @@ void engine_interrupt_agent(engine_t engine) return true; }); } + +CFTypeRef engine_copy_context(engine_t engine, auth_items_t source) +{ + CFTypeRef retval = NULL; + + process_t proc = connection_get_process(engine->conn); + if (!proc) { + os_log_error(AUTHD_LOG, "engine: No client process"); + return retval; + } + + uid_t client_uid = process_get_uid(proc); + if (!client_uid) { + os_log_error(AUTHD_LOG, "engine: No client UID"); + return retval; + } + + size_t dataLen = 0; + const void *data = auth_items_get_data(source, AGENT_HINT_SHEET_CONTEXT, &dataLen); + if (data) { + CFDataRef externalized = CFDataCreate(kCFAllocatorDefault, data, dataLen); + if (externalized) { + os_log_debug(AUTHD_LOG, "engine: Going to get LA context for UID %d", client_uid); + retval = LACreateNewContextWithACMContextInSession(client_uid, externalized, NULL); + CFRelease(externalized); + } + } + + return retval; +} + +bool engine_acquire_sheet_data(engine_t engine) +{ + uid_t uid = auth_items_get_int(engine->hints, AGENT_CONTEXT_UID); + if (!uid) + return false; + + CFReleaseSafe(engine->la_context); + engine->la_context = engine_copy_context(engine, engine->hints); + if (engine->la_context) { + // copy UID to the context of the authorization + os_log_debug(AUTHD_LOG, "engine: Sheet user UID %d", uid); + auth_items_set_int(engine->context, AGENT_CONTEXT_UID, uid); + struct passwd *pwd = getpwuid(uid); + if (pwd) { + auth_items_set_string(engine->context, kAuthorizationEnvironmentUsername, pwd->pw_name); + } + return true; + } else { + // this is not real failure as no LA context in authorization context is very valid scenario + os_log_debug(AUTHD_LOG, "engine: Failed to get LA context"); + } + return false; +} diff --git a/OSX/authd/engine.h b/OSX/authd/engine.h index 45a04204..aec7c296 100644 --- a/OSX/authd/engine.h +++ b/OSX/authd/engine.h @@ -16,6 +16,9 @@ engine_t engine_create(connection_t, auth_token_t); 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); + AUTH_NONNULL_ALL OSStatus engine_verify_modification(engine_t, rule_t, bool remove, bool force_modify); @@ -31,6 +34,12 @@ void engine_destroy_agents(engine_t); AUTH_NONNULL_ALL void engine_interrupt_agent(engine_t engine); +AUTH_NONNULL_ALL +bool engine_acquire_sheet_data(engine_t engine); + +AUTH_NONNULL_ALL AUTH_RETURNS_RETAINED +CFTypeRef engine_copy_context(engine_t engine, auth_items_t source); + #if defined(__cplusplus) } #endif diff --git a/OSX/authd/main.c b/OSX/authd/main.c index 19632fde..dbdcf436 100644 --- a/OSX/authd/main.c +++ b/OSX/authd/main.c @@ -21,13 +21,15 @@ #include #endif +AUTHD_DEFINE_LOG + static void security_auth_peer_event_handler(xpc_connection_t connection, xpc_object_t event) { __block OSStatus status = errAuthorizationDenied; connection_t conn = (connection_t)xpc_connection_get_context(connection); - require_action(conn != NULL, done, LOGE("xpc[%i]: process context not found", xpc_connection_get_pid(connection))); + require_action(conn != NULL, done, os_log_error(AUTHD_LOG, "xpc: process context not found")); CFRetainSafe(conn); @@ -36,15 +38,15 @@ security_auth_peer_event_handler(xpc_connection_t connection, xpc_object_t event if (type == XPC_TYPE_ERROR) { if (event == XPC_ERROR_CONNECTION_INVALID) { // The client process on the other end of the connection has either - // crashed or cancelled the connection. After receiving this error, + // crashed or canceled the connection. After receiving this error, // the connection is in an invalid state, and you do not need to // call xpc_connection_cancel(). Just tear down any associated state // here. - LOGV("xpc[%i]: client disconnected", xpc_connection_get_pid(connection)); + os_log_debug(AUTHD_LOG, "xpc: client disconnected PID %d", xpc_connection_get_pid(connection)); connection_destroy_agents(conn); } else if (event == XPC_ERROR_TERMINATION_IMMINENT) { // Handle per-connection termination cleanup. - LOGD("xpc[%i]: per-connection termination", xpc_connection_get_pid(connection)); + os_log_debug(AUTHD_LOG, "xpc: per-connection termination PID %d", xpc_connection_get_pid(connection)); } } else { assert(type == XPC_TYPE_DICTIONARY); @@ -53,7 +55,7 @@ security_auth_peer_event_handler(xpc_connection_t connection, xpc_object_t event require(reply != NULL, done); uint64_t auth_type = xpc_dictionary_get_uint64(event, AUTH_XPC_TYPE); - LOGV("xpc[%i]: received message type=%llu", connection_get_pid(conn), auth_type); + os_log_debug(AUTHD_LOG, "xpc: received message PID %d, type=%llu", connection_get_pid(conn), auth_type); switch (auth_type) { case AUTHORIZATION_CREATE: @@ -107,6 +109,9 @@ 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); + break; #if DEBUG case AUTHORIZATION_DEV: server_dev(); @@ -128,7 +133,7 @@ done: static void connection_finalizer(void * conn) { - LOGD("xpc[%i]: connection_finalizer", connection_get_pid(conn)); + os_log_debug(AUTHD_LOG, "xpc: connection_finalizer for PID %d", connection_get_pid(conn)); server_unregister_connection(conn); //#if DEBUG @@ -158,7 +163,7 @@ security_auth_event_handler(xpc_connection_t xpc_conn) xpc_connection_resume(xpc_conn); } else { - LOGE("xpc[%i]: failed to register connection", xpc_connection_get_pid(xpc_conn)); + os_log_error(AUTHD_LOG, "xpc: failed to register connection (PID %d)", xpc_connection_get_pid(xpc_conn)); xpc_connection_cancel(xpc_conn); } } @@ -171,7 +176,7 @@ static void sandbox(const char *tmpdir) rc = sandbox_init_with_parameters(SECURITY_AUTH_NAME, SANDBOX_NAMED, sandbox_params, &errorbuf); if (rc) { - LOGE("server: sandbox_init failed %s (%i)", errorbuf, rc); + os_log_error(AUTHD_LOG, "server: sandbox_init failed %{public}s (%i)", errorbuf, rc); sandbox_free_error(errorbuf); #ifndef DEBUG abort(); @@ -186,20 +191,20 @@ int main(int argc AUTH_UNUSED, const char *argv[] AUTH_UNUSED) // malloc_zone_print(malloc_default_zone(), false); //#endif - LOGV("starting"); + os_log_debug(AUTHD_LOG, "starting"); // authd needs to provide a writeable temp dir for SQLite // Insecure temporary directory in authd (/tmp/authd) char darwin_tmp[PATH_MAX]; size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, darwin_tmp, sizeof(darwin_tmp)); if (len == 0 || len >= PATH_MAX) { - LOGE("Invalid _CS_DARWIN_USER_TEMP_DIR"); + os_log_error(AUTHD_LOG, "Invalid _CS_DARWIN_USER_TEMP_DIR"); return errAuthorizationInternal; } char *real_tmp = realpath(darwin_tmp, NULL); if (real_tmp == NULL) { - LOGE("realpath( %s ) FAILED", darwin_tmp); + os_log_error(AUTHD_LOG, "realpath( %{public}s ) FAILED", darwin_tmp); return errAuthorizationInternal; } @@ -208,7 +213,7 @@ int main(int argc AUTH_UNUSED, const char *argv[] AUTH_UNUSED) free(real_tmp); if (server_init() != errAuthorizationSuccess) { - LOGE("auth: server_init() failed"); + os_log_error(AUTHD_LOG, "auth: server_init() failed"); return errAuthorizationInternal; } diff --git a/OSX/authd/mechanism.c b/OSX/authd/mechanism.c index 2c2625a4..c35c3456 100644 --- a/OSX/authd/mechanism.c +++ b/OSX/authd/mechanism.c @@ -44,7 +44,7 @@ _mechanism_finalize(CFTypeRef value) { mechanism_t mech = (mechanism_t)value; - CFReleaseSafe(mech->data); + CFReleaseNull(mech->data); free_safe(mech->string); } diff --git a/OSX/authd/process.c b/OSX/authd/process.c index 2e8eb4da..1cbf78ed 100644 --- a/OSX/authd/process.c +++ b/OSX/authd/process.c @@ -12,6 +12,8 @@ #include #include +AUTHD_DEFINE_LOG + struct _process_s { __AUTH_BASE_STRUCT_HEADER__; @@ -52,10 +54,10 @@ _unregister_auth_tokens(const void *value, void *context) static void _destroy_zombie_tokens(process_t proc) { - LOGD("process[%i] destroy zombies, %ld auth tokens", process_get_pid(proc), CFBagGetCount(proc->authTokens)); + os_log_debug(AUTHD_LOG, "destroy zombies, %ld auth tokens", CFBagGetCount(proc->authTokens)); _cf_bag_iterate(proc->authTokens, ^bool(CFTypeRef value) { auth_token_t auth = (auth_token_t)value; - LOGD("process[%i] %p, creator=%i, zombie=%i, process_cout=%ld", process_get_pid(proc), auth, auth_token_is_creator(auth, proc), auth_token_check_state(auth, auth_token_state_zombie), auth_token_get_process_count(auth)); + os_log_debug(AUTHD_LOG, "process:, creator=%i, zombie=%i, process_cout=%ld", auth_token_is_creator(auth, proc), auth_token_check_state(auth, auth_token_state_zombie), auth_token_get_process_count(auth)); if (auth_token_is_creator(auth, proc) && auth_token_check_state(auth, auth_token_state_zombie) && (auth_token_get_process_count(auth) == 1)) { CFBagRemoveValue(proc->authTokens, auth); } @@ -68,7 +70,7 @@ _process_finalize(CFTypeRef value) { process_t proc = (process_t)value; - LOGV("process[%i]: deallocated %p", proc->auditInfo.pid, proc); + os_log_debug(AUTHD_LOG, "process deallocated"); dispatch_barrier_sync(proc->dispatch_queue, ^{ CFBagApplyFunction(proc->authTokens, _unregister_auth_tokens, proc); @@ -77,16 +79,17 @@ _process_finalize(CFTypeRef value) session_remove_process(proc->session, proc); dispatch_release(proc->dispatch_queue); - CFReleaseSafe(proc->authTokens); - CFReleaseSafe(proc->connections); - CFReleaseSafe(proc->session); - CFReleaseSafe(proc->codeRef); - CFReleaseSafe(proc->code_requirement); - CFReleaseSafe(proc->code_requirement_data); - CFReleaseSafe(proc->code_entitlements); + CFReleaseNull(proc->authTokens); + CFReleaseNull(proc->connections); + CFReleaseNull(proc->session); + CFReleaseNull(proc->codeRef); + CFReleaseNull(proc->code_requirement); + CFReleaseNull(proc->code_requirement_data); + CFReleaseNull(proc->code_entitlements); free_safe(proc->code_identifier); if (proc->bootstrap != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), proc->bootstrap); + proc->bootstrap = MACH_PORT_NULL; } } @@ -145,13 +148,13 @@ process_create(const audit_info_s * auditInfo, session_t session) CFReleaseSafe(codePid); if (status) { - LOGE("process[%i]: failed to create code ref %d", proc->auditInfo.pid, (int)status); + os_log_error(AUTHD_LOG, "process: PID %d failed to create code ref %d", proc->auditInfo.pid, (int)status); CFReleaseNull(proc); goto done; } status = SecCodeCopySigningInformation(proc->codeRef, kSecCSRequirementInformation, &code_info); - require_noerr_action(status, done, LOGV("process[%i]: SecCodeCopySigningInformation failed with %d", proc->auditInfo.pid, (int)status)); + require_noerr_action(status, done, os_log_debug(AUTHD_LOG, "process: PID %d SecCodeCopySigningInformation failed with %d", proc->auditInfo.pid, (int)status)); CFTypeRef value = NULL; if (CFDictionaryGetValueIfPresent(code_info, kSecCodeInfoDesignatedRequirement, (const void**)&value)) { @@ -197,7 +200,7 @@ process_create(const audit_info_s * auditInfo, session_t session) proc->appStoreSigned = process_verify_requirement(proc, secRequirementRef); CFReleaseSafe(secRequirementRef); } - LOGV("process[%i]: created (sid=%i) %s %p", proc->auditInfo.pid, proc->auditInfo.asid, proc->code_url, proc); + os_log_debug(AUTHD_LOG, "process: PID %d created (sid=%i) %{public}s", proc->auditInfo.pid, proc->auditInfo.asid, proc->code_url); done: CFReleaseSafe(code_info); @@ -467,7 +470,7 @@ bool process_verify_requirement(process_t proc, SecRequirementRef requirment) { OSStatus status = SecCodeCheckValidity(proc->codeRef, kSecCSDefaultFlags, requirment); if (status != errSecSuccess) { - LOGV("process[%i]: code requirement check failed (%d)", proc->auditInfo.pid, (int)status); + os_log_debug(AUTHD_LOG, "process: PID %d code requirement check failed (%d)", proc->auditInfo.pid, (int)status); } return (status == errSecSuccess); } diff --git a/OSX/authd/rule.c b/OSX/authd/rule.c index 097e1038..b084b72a 100644 --- a/OSX/authd/rule.c +++ b/OSX/authd/rule.c @@ -12,6 +12,8 @@ #include #include "server.h" +AUTHD_DEFINE_LOG + static void _sql_get_id(rule_t,authdb_connection_t); static RuleClass _get_cf_rule_class(CFTypeRef); static bool _copy_cf_rule_mechanisms(rule_t,CFTypeRef,authdb_connection_t); @@ -54,13 +56,13 @@ static void _rule_finalize(CFTypeRef value) { rule_t rule = (rule_t)value; - CFReleaseSafe(rule->data); - CFReleaseSafe(rule->mechanisms); - CFReleaseSafe(rule->delegations); - CFReleaseSafe(rule->loc_prompts); - CFReleaseSafe(rule->loc_buttons); - CFReleaseSafe(rule->requirement_data); - CFReleaseSafe(rule->requirement); + CFReleaseNull(rule->data); + CFReleaseNull(rule->mechanisms); + CFReleaseNull(rule->delegations); + CFReleaseNull(rule->loc_prompts); + CFReleaseNull(rule->loc_buttons); + CFReleaseNull(rule->requirement_data); + CFReleaseNull(rule->requirement); } static Boolean @@ -181,6 +183,27 @@ 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) { @@ -308,7 +331,7 @@ rule_create_with_plist(RuleType type, CFStringRef name, CFDictionaryRef plist, a case RC_ALLOW: break; default: - LOGD("rule: invalid rule class"); + os_log_error(AUTHD_LOG, "rule: invalid rule class"); break; } @@ -490,7 +513,7 @@ _sql_bind(rule_t rule, sqlite3_stmt * stmt) require_noerr(rc, err); break; default: - LOGD("rule: sql bind, invalid rule class"); + os_log_error(AUTHD_LOG, "rule: sql bind, invalid rule class"); break; } @@ -519,7 +542,7 @@ _sql_bind(rule_t rule, sqlite3_stmt * stmt) return true; err: - LOGD("rule: sql bind, error %i", rc); + os_log_error(AUTHD_LOG, "rule: sql bind, error %i", rc); return false; } @@ -742,9 +765,9 @@ rule_sql_commit(rule_t rule, authdb_connection_t dbconn, CFAbsoluteTime modified } } if (!mechanism_exists(mech)) { - LOGE("Warning mechanism not found on disk %s during import of %s", mechanism_get_string(mech), rule_get_name(rule)); + os_log_error(AUTHD_LOG, "Warning mechanism not found on disk %{public}s during import of %{public}s", mechanism_get_string(mech), rule_get_name(rule)); } - require_action(mechanism_get_id(mech) != 0, done, LOGE("rule: commit, invalid mechanism %s:%s for %s", mechanism_get_plugin(mech), mechanism_get_param(mech), rule_get_name(rule))); + require_action(mechanism_get_id(mech) != 0, done, os_log_error(AUTHD_LOG, "rule: commit, invalid mechanism %{public}s:%{public}s for %{public}s", mechanism_get_plugin(mech), mechanism_get_param(mech), rule_get_name(rule))); } } @@ -757,7 +780,7 @@ rule_sql_commit(rule_t rule, authdb_connection_t dbconn, CFAbsoluteTime modified if (rule_get_id(delegate) == 0) { rule_sql_fetch(delegate, dbconn); } - require_action(rule_get_id(delegate) != 0, done, LOGE("rule: commit, missing delegate %s for %s", rule_get_name(delegate), rule_get_name(rule))); + require_action(rule_get_id(delegate) != 0, done, os_log_error(AUTHD_LOG, "rule: commit, missing delegate %{public}s for %{public}s", rule_get_name(delegate), rule_get_name(rule))); } } @@ -800,7 +823,7 @@ rule_sql_commit(rule_t rule, authdb_connection_t dbconn, CFAbsoluteTime modified done: if (!result) { - LOGV("rule: commit, failed for %s (%llu)", rule_get_name(rule), rule_get_id(rule)); + os_log_debug(AUTHD_LOG, "rule: commit, failed for %{public}s (%llu)", rule_get_name(rule), rule_get_id(rule)); } return result; } diff --git a/OSX/authd/rule.h b/OSX/authd/rule.h index b5499d1d..f5d00723 100644 --- a/OSX/authd/rule.h +++ b/OSX/authd/rule.h @@ -44,6 +44,9 @@ typedef uint32_t RuleFlags; 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); diff --git a/OSX/authd/server.c b/OSX/authd/server.c index 86943950..2d46808f 100644 --- a/OSX/authd/server.c +++ b/OSX/authd/server.c @@ -28,6 +28,8 @@ #include #include +AUTHD_DEFINE_LOG + #define MAX_PROCESS_RIGHTS 100 static CFMutableDictionaryRef gProcessMap = NULL; @@ -122,23 +124,23 @@ void server_cleanup() static void _IOMPCallBack(void * param AUTH_UNUSED, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities capabilities) { - LOGV("server: IOMP powerstates %i", capabilities); + os_log_debug(AUTHD_LOG, "server: IOMP powerstates %i", capabilities); if (capabilities & kIOPMSystemPowerStateCapabilityDisk) - LOGV("server: disk"); + os_log_debug(AUTHD_LOG, "server: disk"); if (capabilities & kIOPMSystemPowerStateCapabilityNetwork) - LOGV("server: net"); + os_log_debug(AUTHD_LOG, "server: net"); if (capabilities & kIOPMSystemPowerStateCapabilityAudio) - LOGV("server: audio"); + os_log_debug(AUTHD_LOG, "server: audio"); if (capabilities & kIOPMSystemPowerStateCapabilityVideo) - LOGV("server: video"); + os_log_debug(AUTHD_LOG, "server: video"); /* if cpu and no display -> in DarkWake */ - LOGD("server: DarkWake check current=%i==%i", (capabilities & (kIOPMSystemPowerStateCapabilityCPU|kIOPMSystemPowerStateCapabilityVideo)), kIOPMSystemPowerStateCapabilityCPU); + os_log_debug(AUTHD_LOG, "server: DarkWake check current=%i==%i", (capabilities & (kIOPMSystemPowerStateCapabilityCPU|kIOPMSystemPowerStateCapabilityVideo)), kIOPMSystemPowerStateCapabilityCPU); if ((capabilities & (kIOPMSystemPowerStateCapabilityCPU|kIOPMSystemPowerStateCapabilityVideo)) == kIOPMSystemPowerStateCapabilityCPU) { - LOGV("server: enter DarkWake"); + os_log_debug(AUTHD_LOG, "server: enter DW"); gInDarkWake = true; } else if (gInDarkWake) { - LOGV("server: exit DarkWake"); + os_log_debug(AUTHD_LOG, "server: exit DW"); gInDarkWake = false; } @@ -190,19 +192,19 @@ static void _setupAuditSessionMonitor() auditinfo_addr_t aia; if (NULL == dev) { - LOGE("server: could not open %s %d", AUDIT_SDEV_PATH, errno); + os_log_error(AUTHD_LOG, "server: could not open %{public}s %d", AUDIT_SDEV_PATH, errno); return; } for (;;) { if (0 != au_sdev_read_aia(dev, &event, &aia)) { - LOGE("server: au_sdev_read_aia failed: %d", errno); + os_log_error(AUTHD_LOG, "server: au_sdev_read_aia failed: %d", errno); continue; } - LOGD("server: au_sdev_handle_t event=%i, session=%i", event, aia.ai_asid); + os_log_debug(AUTHD_LOG, "server: au_sdev_handle_t event=%i, session=%i", event, aia.ai_asid); if (event == AUE_SESSION_END) { dispatch_async(get_server_dispatch_queue(), ^{ - LOGV("server: session %i destroyed", aia.ai_asid); + os_log_debug(AUTHD_LOG, "server: session %i destroyed", aia.ai_asid); CFDictionaryRemoveValue(gSessionMap, &aia.ai_asid); }); } @@ -233,7 +235,7 @@ OSStatus server_init(void) auditinfo_addr_t info; memset(&info, 0, sizeof(info)); getaudit_addr(&info, sizeof(info)); - LOGV("server: uid=%i, sid=%i", info.ai_auid, info.ai_asid); + os_log_debug(AUTHD_LOG, "server: uid=%i, sid=%i", info.ai_auid, info.ai_asid); require_action(get_server_dispatch_queue() != NULL, done, status = errAuthorizationInternal); @@ -328,7 +330,7 @@ server_register_connection(xpc_connection_t connection) } }); - LOGV("server[%i]: registered connection (total=%li)", info.pid, conn_count); + os_log_debug(AUTHD_LOG, "server: registered connection (total=%li)", conn_count); done: CFReleaseSafe(session); @@ -344,7 +346,7 @@ server_unregister_connection(connection_t conn) dispatch_sync(get_server_dispatch_queue(), ^{ CFIndex connectionCount = process_get_connection_count(proc); - LOGV("server[%i]: unregistered connection (total=%li)", process_get_pid(proc), connectionCount); + os_log_debug(AUTHD_LOG, "server: unregistered connection (total=%li)", connectionCount); if (connectionCount == 1) { CFDictionaryRemoveValue(gProcessMap, process_get_key(proc)); @@ -364,7 +366,7 @@ server_register_auth_token(auth_token_t auth) { assert(auth); // marked non-null dispatch_sync(get_server_dispatch_queue(), ^{ - LOGV("server: registering auth %p", auth); + os_log_debug(AUTHD_LOG, "server: registering authorization"); CFDictionarySetValue(gAuthTokenMap, auth_token_get_key(auth), auth); auth_token_set_state(auth, auth_token_state_registered); }); @@ -376,7 +378,7 @@ server_unregister_auth_token(auth_token_t auth) assert(auth); AuthorizationBlob blob = *(AuthorizationBlob*)auth_token_get_key(auth); dispatch_async(get_server_dispatch_queue(), ^{ - LOGV("server: unregistering auth %p", auth); + os_log_debug(AUTHD_LOG, "server: unregistering authorization"); CFDictionaryRemoveValue(gAuthTokenMap, &blob); }); } @@ -433,9 +435,9 @@ _process_find_copy_auth_token_from_xpc(process_t proc, xpc_object_t message, aut require_action(auth != NULL, done, status = errAuthorizationInvalidRef); #if DEBUG - LOGV("server[%i]: authtoken lookup %#x%x %p", process_get_pid(proc), blob->data[1],blob->data[0], auth); + os_log_debug(AUTHD_LOG, "server: authtoken lookup %#x%x %p", blob->data[1],blob->data[0], auth); #else - LOGV("server[%i]: authtoken lookup %p", process_get_pid(proc), auth); + os_log_debug(AUTHD_LOG, "server: authtoken lookup"); #endif *auth_out = auth; @@ -444,6 +446,29 @@ done: return status; } +static OSStatus _server_preauthorize(connection_t conn, auth_token_t auth, auth_items_t context, engine_t * engine_out) +{ + __block OSStatus status = errAuthorizationDenied; + engine_t engine = NULL; + + require_action(conn, done, status = errAuthorizationInternal); + + engine = engine_create(conn, auth); + require_action(engine, done, status = errAuthorizationInternal); + + status = engine_preauthorize(engine, context); + +done: + if (engine) { + if (engine_out) { + *engine_out = engine; + } else { + CFRelease(engine); + } + } + 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) { __block OSStatus status = errAuthorizationDenied; @@ -565,7 +590,7 @@ authorization_free(connection_t conn, xpc_object_t message, xpc_object_t reply A if (flags & kAuthorizationFlagDestroyRights) { auth_token_credentials_iterate(auth, ^bool(credential_t cred) { credential_invalidate(cred); - LOGV("engine[%i]: invalidating %scredential %s (%i) from authorization (%p)", connection_get_pid(conn), credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred), auth); + os_log_debug(AUTHD_LOG, "engine[%i]: invalidating %{public}scredential %{public}s (%i)", connection_get_pid(conn), credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred)); return true; }); @@ -576,10 +601,39 @@ authorization_free(connection_t conn, xpc_object_t message, xpc_object_t reply A done: CFReleaseSafe(auth); - LOGV("server[%i]: AuthorizationFree %d (flags:%x)", connection_get_pid(conn), (int)status, (unsigned int)flags); + os_log_debug(AUTHD_LOG, "server: AuthorizationFree %d (flags:%x)", (int)status, (unsigned int)flags); return status; } +// IN: AUTH_XPC_BLOB, AUTH_XPC_DATA +// OUT: +OSStatus +authorization_preauthorize_credentials(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")); + + status = _server_preauthorize(conn, auth, context, &engine); + require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "preauthorize_credentials: authorization failed")); + +done: + CFReleaseSafe(context); + CFReleaseSafe(auth); + CFReleaseSafe(engine); + + return status; +} + + // IN: AUTH_XPC_BLOB, AUTH_XPC_RIGHTS, AUTH_XPC_ENVIRONMENT, AUTH_XPC_FLAGS // OUT: AUTH_XPC_OUT_ITEMS OSStatus @@ -597,11 +651,10 @@ authorization_copy_rights(connection_t conn, xpc_object_t message, xpc_object_t auth_token_t auth = NULL; status = _process_find_copy_auth_token_from_xpc(proc, message, &auth); - require_noerr(status, done); - require_noerr_action_quiet(status, done, LOGE("copy_rights: no auth token")); + require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "copy_rights: no auth token")); status = _server_authorize(conn, auth, flags, rights, environment, &engine); - require_noerr_action_quiet(status, done, LOGE("copy_rights: _server_authorize failed")); + require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "copy_rights: authorization failed")); //reply xpc_object_t outItems = auth_rights_export_xpc(engine_get_granted_rights(engine)); @@ -625,41 +678,49 @@ authorization_copy_info(connection_t conn, xpc_object_t message, xpc_object_t re OSStatus status = errAuthorizationSuccess; auth_items_t items = NULL; + auth_items_t local_items = NULL; const char * tag = NULL; process_t proc = connection_get_process(conn); auth_token_t auth = NULL; status = _process_find_copy_auth_token_from_xpc(proc, message, &auth); - require_noerr(status, done); - + require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "copy_info: no auth token")); + items = auth_items_create(); tag = xpc_dictionary_get_string(message, AUTH_XPC_TAG); - LOGV("server[%i]: requested tag: %s", connection_get_pid(conn), tag ? tag : "(all)"); + os_log_debug(AUTHD_LOG, "server: requested tag: %{public}s", tag ? tag : "(all)"); if (tag) { size_t len; const void * data = auth_items_get_data_with_flags(auth_token_get_context(auth), tag, &len, kAuthorizationContextFlagExtractable); - if (data) + if (data) { + os_log_debug(AUTHD_LOG, "server: requested tag found"); auth_items_set_data(items, tag, data, len); + } } else { auth_items_copy_with_flags(items, auth_token_get_context(auth), kAuthorizationContextFlagExtractable); } + local_items = auth_items_create(); + auth_items_content_copy(local_items, items); // we do not want decrypt content of the authorizationref memory which is where pointers point to + auth_items_decrypt(local_items, auth_token_get_encryption_key(auth)); + os_log_debug(AUTHD_LOG, "server: decrypted authorization context data"); + #if DEBUG - LOGV("server[%i]: Dumping requested AuthRef items", connection_get_pid(conn)); - _show_cf(items); + os_log_debug(AUTHD_LOG, "server: Dumping requested AuthRef items: %{public}@", items); #endif //reply - xpc_object_t outItems = auth_items_export_xpc(items); + xpc_object_t outItems = auth_items_export_xpc(local_items); xpc_dictionary_set_value(reply, AUTH_XPC_OUT_ITEMS, outItems); xpc_release_safe(outItems); done: - CFReleaseSafe(items); + CFReleaseSafe(local_items); + CFReleaseSafe(items); CFReleaseSafe(auth); - LOGV("server[%i]: AuthorizationCopyInfo %i", connection_get_pid(conn), (int) status); + os_log_debug(AUTHD_LOG, "server: AuthorizationCopyInfo %i", (int) status); return status; } @@ -688,7 +749,7 @@ authorization_make_external_form(connection_t conn, xpc_object_t message, xpc_ob done: CFReleaseSafe(auth); - LOGV("server[%i]: AuthorizationMakeExternalForm %d", connection_get_pid(conn), (int)status); + os_log_debug(AUTHD_LOG, "server: AuthorizationMakeExternalForm %d", (int)status); return status; } @@ -716,7 +777,7 @@ authorization_create_from_external_form(connection_t conn, xpc_object_t message, done: CFReleaseSafe(auth); - LOGV("server[%i]: AuthorizationCreateFromExternalForm %d", connection_get_pid(conn), (int)status); + os_log_debug(AUTHD_LOG, "server: AuthorizationCreateFromExternalForm %d", (int)status); return status; } @@ -751,7 +812,7 @@ done: CFReleaseSafe(cfdict); xpc_release_safe(xpcdict); CFReleaseSafe(rule); - LOGV("server[%i]: AuthorizationRightGet %d", connection_get_pid(conn), (int)status); + os_log_debug(AUTHD_LOG, "server: AuthorizationRightGet %d", (int)status); return status; } @@ -888,11 +949,11 @@ authorization_enable_smartcard(connection_t conn, xpc_object_t message, xpc_obje if (!_update_rule_mechanism(dbconn, SYSTEM_LOGIN_CONSOLE, SMARTCARD_LINE, BUILTIN_LINE, enable_smartcard ? false : true)) { status = errAuthorizationInternal; - LOGE("server[%i]: smartcard: enable(%i) failed to update %s", connection_get_pid(conn), enable_smartcard, SYSTEM_LOGIN_CONSOLE); + os_log_error(AUTHD_LOG, "server: smartcard: enable(%i) failed to update %{public}s", enable_smartcard, SYSTEM_LOGIN_CONSOLE); } if (!_update_rule_mechanism(dbconn, AUTHENTICATE, SMARTCARD_LINE, NULL, enable_smartcard ? false : true)) { status = errAuthorizationInternal; - LOGE("server[%i]: smartcard: enable(%i) failed to update %s", connection_get_pid(conn), enable_smartcard, AUTHENTICATE); + os_log_error(AUTHD_LOG, "server: smartcard: enable(%i) failed to update %{public}s", enable_smartcard, AUTHENTICATE); } authdb_checkpoint(dbconn); @@ -980,19 +1041,19 @@ authorization_right_set(connection_t conn, xpc_object_t message, xpc_object_t re rule = rule_create_with_plist(rule_type, cf_rule_name, cf_rule_dict, dbconn); if (process_get_uid(proc) != 0) { - require_action(rule_get_extract_password(rule) == false, done, status = errAuthorizationDenied; LOGE("server[%i]: AuthorizationRightSet not allowed to set extract-password. (denied)", connection_get_pid(conn))); + require_action(rule_get_extract_password(rule) == false, done, status = errAuthorizationDenied; os_log_error(AUTHD_LOG, "server: AuthorizationRightSet not allowed to set extract-password. (denied)")); } // if rule doesn't currently exist then we have to check to see if they are over the Max. if (rule_get_id(rule) == 0) { if (process_get_identifier(proc) == NULL) { - LOGE("server[%i]: AuthorizationRightSet required for process %s (missing code signature). To add rights to the Authorization database, your process must have a code signature.", connection_get_pid(conn), process_get_code_url(proc)); + os_log_error(AUTHD_LOG, "server: AuthorizationRightSet required for process %{public}s (missing code signature). To add rights to the Authorization database, your process must have a code signature.", process_get_code_url(proc)); force_modify = true; } else { int64_t process_rule_count = _process_get_identifier_count(proc, dbconn); if ((process_rule_count >= _get_max_process_rights())) { if (!connection_get_syslog_warn(conn)) { - LOGE("server[%i]: AuthorizationRightSet Denied API abuse process %s already contains %lli rights.", connection_get_pid(conn), process_get_code_url(proc), _get_max_process_rights()); + os_log_error(AUTHD_LOG, "server: AuthorizationRightSet Denied API abuse process %{public}s already contains %lli rights.", process_get_code_url(proc), _get_max_process_rights()); connection_set_syslog_warn(conn); } status = errAuthorizationDenied; @@ -1002,7 +1063,7 @@ authorization_right_set(connection_t conn, xpc_object_t message, xpc_object_t re } else { if (auth_rule) { if (process_get_uid(proc) != 0) { - LOGE("server[%i]: AuthorizationRightSet denied, root required to update the 'authenticate' rule", connection_get_pid(conn)); + os_log_error(AUTHD_LOG, "server: AuthorizationRightSet denied, root required to update the 'authenticate' rule"); status = errAuthorizationDenied; goto done; } @@ -1010,7 +1071,7 @@ authorization_right_set(connection_t conn, xpc_object_t message, xpc_object_t re // verify they are updating a right and not a rule existingRule = rule_create_with_string(rule_get_name(rule), dbconn); if (rule_get_type(existingRule) == RT_RULE) { - LOGE("server[%i]: AuthorizationRightSet Denied updating '%s' rule is prohibited", connection_get_pid(conn), rule_get_name(existingRule)); + os_log_error(AUTHD_LOG, "server: AuthorizationRightSet Denied updating '%{public}s' rule is prohibited", rule_get_name(existingRule)); status = errAuthorizationDenied; goto done; } @@ -1032,11 +1093,11 @@ authorization_right_set(connection_t conn, xpc_object_t message, xpc_object_t re } if (rule_sql_commit(rule, dbconn, engine ? engine_get_time(engine) : CFAbsoluteTimeGetCurrent(), proc)) { - LOGV("server[%i]: Successfully updated rule %s", connection_get_pid(conn), rule_get_name(rule)); + os_log_debug(AUTHD_LOG, "server: Successfully updated rule %{public}s", rule_get_name(rule)); authdb_checkpoint(dbconn); status = errAuthorizationSuccess; } else { - LOGE("server[%i]: Failed to update rule %s", connection_get_pid(conn), rule_get_name(rule)); + os_log_error(AUTHD_LOG, "server: Failed to update rule %{public}s", rule_get_name(rule)); status = errAuthorizationDenied; } @@ -1095,7 +1156,7 @@ done: CFReleaseSafe(auth); CFReleaseSafe(rule); CFReleaseSafe(engine); - LOGV("server[%i]: AuthorizationRightRemove %d", connection_get_pid(conn), (int)status); + os_log_debug(AUTHD_LOG, "server: AuthorizationRightRemove %d", (int)status); return status; } @@ -1124,7 +1185,7 @@ server_dev() { // authdb_get_key_value(server_get_authdb_reader(), "config", &config); // auth_items_set_double(config, "test", d1); // d2 = auth_items_get_double(config, "test"); -// LOGV("d1=%f d2=%f", d1, d2); +// os_log_debug(AUTHD_LOG, "d1=%f d2=%f", d1, d2); // CFReleaseSafe(config); diff --git a/OSX/authd/server.h b/OSX/authd/server.h index 5ccb765d..7889bb32 100644 --- a/OSX/authd/server.h +++ b/OSX/authd/server.h @@ -46,6 +46,9 @@ OSStatus authorization_create_with_audit_token(connection_t,xpc_object_t,xpc_obj 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); + AUTH_NONNULL_ALL OSStatus authorization_copy_rights(connection_t,xpc_object_t,xpc_object_t); diff --git a/OSX/authd/session.c b/OSX/authd/session.c index e1ed31c7..d631e74a 100644 --- a/OSX/authd/session.c +++ b/OSX/authd/session.c @@ -6,6 +6,8 @@ #include #include +AUTHD_DEFINE_LOG + struct _session_s { __AUTH_BASE_STRUCT_HEADER__; @@ -22,14 +24,14 @@ _session_finalize(CFTypeRef value) { session_t session = (session_t)value; - LOGV("session: %i deallocated %p", session->auditinfo.ai_asid, session); + os_log_debug(AUTHD_LOG, "session: %i deallocated", session->auditinfo.ai_asid); // make sure queue is empty dispatch_barrier_sync(session->dispatch_queue, ^{}); dispatch_release(session->dispatch_queue); - CFReleaseSafe(session->credentials); - CFReleaseSafe(session->processes); + CFReleaseNull(session->credentials); + CFReleaseNull(session->processes); } AUTH_TYPE_INSTANCE(session, @@ -64,7 +66,7 @@ session_create(session_id_t sid) session->auditinfo.ai_asid = sid; if (!session_update(session)) { - LOGE("session: failed to get session info"); + os_log_error(AUTHD_LOG, "session: failed to get session info"); } session->dispatch_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); @@ -73,7 +75,7 @@ session_create(session_id_t sid) session->credentials = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks); session->processes = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL); - LOGV("session: %i created (uid=%i) %p", session->auditinfo.ai_asid, session->auditinfo.ai_auid, session); + os_log_debug(AUTHD_LOG, "session: %i created (uid=%i)", session->auditinfo.ai_asid, session->auditinfo.ai_auid); done: return session; @@ -96,7 +98,7 @@ static void _set_attributes(session_t session, uint64_t flags) session->auditinfo.ai_flags = flags; int32_t rc = setaudit_addr(&session->auditinfo, sizeof(session->auditinfo)); if (rc != 0) { - LOGV("session: failed to update session info (%d)", rc); + os_log_debug(AUTHD_LOG, "session: failed to update session info (%d)", rc); } } diff --git a/OSX/authd/tests/authdtestlist.h b/OSX/authd/tests/authdtestlist.h new file mode 100644 index 00000000..9f43ceef --- /dev/null +++ b/OSX/authd/tests/authdtestlist.h @@ -0,0 +1,5 @@ +/* Don't preent multiple inclusions of this file */ +#include + +ONE_TEST(authd_01_authorizationdb) +ONE_TEST(authd_02_basicauthorization) diff --git a/OSX/authd/tests/authdtests.m b/OSX/authd/tests/authdtests.m new file mode 100644 index 00000000..0e1e034a --- /dev/null +++ b/OSX/authd/tests/authdtests.m @@ -0,0 +1,155 @@ +// +// authdtests.m +// +// + +#import +#import +#import +#import +#import "authd/debugging.h" +#import "authdtestlist.h" + +void runRaft(NSString *arguments); +int authd_03_uiauthorization(int argc, char *const *argv); + +#define AuthorizationFreeItemSetNull(IS) { AuthorizationItemSet *_is = (IS); \ +if (_is) { (IS) = NULL; AuthorizationFreeItemSet(_is); } } + +#define SAMPLE_RIGHT "com.apple.security.syntheticinput" +#define SAMPLE_SHARED_RIGHT "system.preferences" + +#define CORRECT_UNAME "bats" +#define CORRECT_PWD "bats" +#define INCORRECT_UNAME "fs;lgp-984-25opsdakflasdg" +#define INCORRECT_PWD "654sa65gsqihr6hhsfd'lbo[0q2,m23-odasdf" + +#define SA_TIMEOUT (20) + +#define RAFT_FILL @"target.processes()[\"SecurityAgent\"].mainWindow().textFields()[\"User Name:\"].click();keyboard.typeString_withModifiersMask_(\"a\", (kUIACommandKeyMask));keyboard.typeVirtualKey_(117);keyboard.typeString_(\"%s\");target.processes()[\"SecurityAgent\"].mainWindow().textFields()[\"Password:\"].click();keyboard.typeString_withModifiersMask_(\"a\", (kUIACommandKeyMask));keyboard.typeVirtualKey_(117);keyboard.typeString_(\"%s\");target.processes()[\"SecurityAgent\"].mainWindow().buttons()[\"OK\"].click();quit();" + +#define RAFT_CANCEL @"target.processes()[\"SecurityAgent\"].mainWindow().buttons()[\"Cancel\"].click();quit();" + +AuthorizationItem validCredentials[] = { + {AGENT_USERNAME, strlen(CORRECT_UNAME), (void *)CORRECT_UNAME, 0}, + {AGENT_PASSWORD, strlen(CORRECT_PWD), (void *)CORRECT_PWD,0} +}; + +AuthorizationItem invalidCredentials[] = { + {AGENT_USERNAME, strlen(INCORRECT_UNAME), (void *)INCORRECT_UNAME, 0}, + {AGENT_PASSWORD, strlen(INCORRECT_PWD), (void *)INCORRECT_PWD,0} +}; + +void runRaft(NSString *arguments) +{ + NSTask *task = [[NSTask alloc] init]; + [task setLaunchPath:@"/usr/local/bin/raft"]; + [task setArguments:@[ @"-b", @"-o", arguments]]; + [task launch]; + [task waitUntilExit]; +} + +int authd_01_authorizationdb(int argc, char *const *argv) +{ + plan_tests(2); + + CFDictionaryRef outDict = NULL; + OSStatus status = AuthorizationRightGet(SAMPLE_RIGHT, &outDict); + ok(status == errAuthorizationSuccess, "AuthorizationRightGet existing right"); + CFReleaseNull(outDict); + + status = AuthorizationRightGet("non-existing-right", &outDict); + ok(status == errAuthorizationDenied, "AuthorizationRightGet non-existing right"); + + return 0; +} + +int authd_02_basicauthorization(int argc, char *const *argv) +{ + plan_tests(5); + + AuthorizationRef authorizationRef; + + OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef); + ok(status == errAuthorizationSuccess, "AuthorizationRef create"); + + AuthorizationItem myItems = {SAMPLE_RIGHT, 0, NULL, 0}; + AuthorizationRights myRights = {1, &myItems}; + AuthorizationRights *authorizedRights = NULL; + AuthorizationEnvironment environment = {sizeof(validCredentials)/sizeof(AuthorizationItem), validCredentials}; + status = AuthorizationCopyRights(authorizationRef, &myRights, &environment, kAuthorizationFlagDefaults, &authorizedRights); + ok(status == errAuthorizationDenied, "Standard authorization without kAuthorizationFlagExtendRights"); + AuthorizationFreeItemSetNull(authorizedRights); + + status = AuthorizationCopyRights(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights, &authorizedRights); + ok(status == errAuthorizationInteractionNotAllowed, "Authorization fail with UI not allowed"); + AuthorizationFreeItemSetNull(authorizedRights); + + status = AuthorizationCopyRights(authorizationRef, &myRights, &environment, kAuthorizationFlagExtendRights, &authorizedRights); + ok(status == errAuthorizationSuccess, "Standard authorization"); + AuthorizationFreeItemSetNull(authorizedRights); + + AuthorizationItem extendedItems = {SAMPLE_SHARED_RIGHT, 0, NULL, 0}; + AuthorizationRights extendedRights = {1, &extendedItems}; + + status = AuthorizationCopyRights(authorizationRef, &extendedRights, &environment, kAuthorizationFlagExtendRights, &authorizedRights); + ok(status == errAuthorizationSuccess, "Extending authorization rights"); + AuthorizationFreeItemSetNull(authorizedRights); + + AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights); + return 0; +} + +int authd_03_uiauthorization(int argc, char *const *argv) +{ + plan_tests(3); + + AuthorizationRef authorizationRef; + + OSStatus status = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef); + ok(status == errAuthorizationSuccess, "AuthorizationRef create"); + + AuthorizationItem myItems = {SAMPLE_RIGHT, 0, NULL, 0}; + AuthorizationRights myRights = {1, &myItems}; + + NSString *raftFillValid = [NSString stringWithFormat:RAFT_FILL, CORRECT_UNAME, CORRECT_PWD]; + + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + /* + AuthorizationAsyncCallback internalBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) { + AuthorizationFreeItemSetNull(blockAuthorizedRights); + ok(err == errAuthorizationInternal, "Async authorization interal error"); + dispatch_semaphore_signal(sem); + }; + AuthorizationAsyncCallback denyBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) { + AuthorizationFreeItemSetNull(blockAuthorizedRights); + ok(err == errAuthorizationDenied, "Async authorization denial"); + dispatch_semaphore_signal(sem); + };*/ + AuthorizationAsyncCallback allowBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) { + AuthorizationFreeItemSetNull(blockAuthorizedRights); + ok(err == errAuthorizationSuccess, "Async authorization"); + dispatch_semaphore_signal(sem); + }; + AuthorizationAsyncCallback cancelBlock = ^(OSStatus err, AuthorizationRights *blockAuthorizedRights) { + AuthorizationFreeItemSetNull(blockAuthorizedRights); + ok(err == errAuthorizationCanceled, "Async authorization cancel"); + dispatch_semaphore_signal(sem); + }; + AuthorizationCopyRightsAsync(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, cancelBlock); + sleep(3); // give some time to SecurityAgent to appear + runRaft(RAFT_CANCEL); + if (dispatch_semaphore_wait(sem, SA_TIMEOUT * NSEC_PER_SEC) != 0) { + fail("Async authorization cancel"); + } + AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); + + AuthorizationCopyRightsAsync(authorizationRef, &myRights, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, allowBlock); + sleep(3); // give some time to SecurityAgent to appear + runRaft(raftFillValid); + if (dispatch_semaphore_wait(sem, SA_TIMEOUT * NSEC_PER_SEC) != 0) { + fail("Async authorization"); + } AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); + + return 0; +} diff --git a/OSX/authd/tests/main.m b/OSX/authd/tests/main.m new file mode 100644 index 00000000..460db2af --- /dev/null +++ b/OSX/authd/tests/main.m @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012,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 +#include + +#include "regressions/test/testenv.h" + +#include "authdtestlist.h" +#include +#include "authdtestlist.h" +#include + +int main(int argc, char *argv[]) +{ + int result = tests_begin(argc, argv); + + fflush(stdout); + fflush(stderr); + + sleep(1); + + return result; +} diff --git a/OSX/authorizationdump/main.m b/OSX/authorizationdump/main.m new file mode 100644 index 00000000..d1d41206 --- /dev/null +++ b/OSX/authorizationdump/main.m @@ -0,0 +1,290 @@ +// +// main.m +// AuthorizationTestTool +// +// Copyright © 2017 Apple, Inc. All rights reserved. +// + +#import + +#define DEFAULT_DB "/System/Library/Security/authorization.plist" +#define START_TAG @"(" +#define END_TAG @")" +#define START_TAG_PLACEHOLDER @"<" +#define END_TAG_PLACEHOLDER @">" + +typedef NS_ENUM(NSInteger, atOutputType) +{ + otHeader, + otUser, + otTries, + otShared, + otTimeout, + otShowUi, + otRequiredGroup, + otEntitlement, + otAllowRoot, + otSessionOwner, + otAllow, + otDeny, + otExtractPassword, + otEntitledAndGroup, + otVpnEntitledAndGroup, + otAppleSigned, + otKofn, + otRules, + otMechanismsHeader, + otMechanisms, + otFooter, +}; + +NSString *itemDescription(atOutputType type, id arg); +NSString *itemName(atOutputType type); +void addDataOutput(NSMutableDictionary *output, NSDictionary *content, atOutputType type, id defaultValue, Boolean writeIfNotFound); +void processOutput(NSArray *input, NSMutableArray *output, NSUInteger level); +NSArray *parseRight(NSDictionary *db, NSString *name, NSUInteger level); + +NSString *itemDescription(atOutputType type, id arg) +{ + switch (type){ + case otTries: return [NSString stringWithFormat:@"Tries: %@", arg]; + case otShared: return [NSString stringWithFormat:@"Shared: %@", arg]; + case otTimeout: return [NSString stringWithFormat:@"Timeout: %@", arg]; + case otShowUi: return [NSString stringWithFormat:@"Show UI if necessary: %@", arg]; + case otRequiredGroup: return [NSString stringWithFormat:@"Require user from group: %@", arg]; + case otEntitlement: return [NSString stringWithFormat:@"Require entitlement: %@", arg]; + case otAllowRoot: return [NSString stringWithFormat:@"Auto-allow if caller process is root: %@", arg]; + case otSessionOwner: return [NSString stringWithFormat:@"Session owner required: %@", arg]; + case otAllow: return @"Always allowed"; + case otDeny: return @"Always denied"; + case otKofn: + if (arg) + return [NSString stringWithFormat:@"At least %@ from the following:", arg]; + else + return [NSString stringWithFormat:@"All from following:"]; + case otExtractPassword: return [NSString stringWithFormat:@"Extractable password: %@", arg]; + case otEntitledAndGroup: return [NSString stringWithFormat:@"Entitled and group: %@", arg]; + case otVpnEntitledAndGroup: return [NSString stringWithFormat:@"VPN entitled and group: %@", arg]; + case otAppleSigned: return [NSString stringWithFormat:@"Requires Apple signature: %@", arg]; + default: + return [NSString stringWithFormat:@"Unknown item %ld", (long)type]; + } + return nil; +} + +NSString *itemName(atOutputType type) +{ + switch (type){ + case otTries: return @"tries"; + case otShared: return @"shared"; + case otTimeout: return @"timeout"; + case otShowUi: return @"authenticate-user"; + case otRequiredGroup: return @"group"; + case otAllowRoot: return @"allow-root"; + case otSessionOwner: return @"session-owner"; + case otExtractPassword: return @"extract-password"; + case otEntitledAndGroup: return @"entitled-group"; + case otVpnEntitledAndGroup: return @"vpn-entitled-group"; + case otAppleSigned: return @"require-apple-signed"; + case otKofn: return @"k-of-n"; + case otMechanisms: return @"mechanism"; + default: + return [NSString stringWithFormat:@"unknown-item-%ld", (long)type]; + } + return nil; +} + +void addDataOutput(NSMutableDictionary *output, NSDictionary *content, atOutputType type, id defaultValue, Boolean writeIfNotFound) +{ + id data = content[itemName(type)]; + if (data == nil) { + if (!writeIfNotFound) + return; + data = defaultValue; + } + output[[NSNumber numberWithInteger:type]] = itemDescription(type, data); +} + +void processOutput(NSArray *arr, NSMutableArray *output, NSUInteger level) +{ + for (id element in arr) { + if ([element isKindOfClass:[NSArray class]]) { + processOutput(element, output, level + 1); + } else { + if (level == 1) { + [output addObject:element]; + } else { + if ([START_TAG_PLACEHOLDER isEqualToString:element]){ + [output addObject:START_TAG]; + } else if ([END_TAG_PLACEHOLDER isEqualToString:element]){ + [output addObject:END_TAG]; + } else { + [output addObject:[NSString stringWithFormat:@"\t%@", element]]; + } + } + } + } +} + +NSArray *parseRight(NSDictionary *db, NSString *name, NSUInteger level) +{ + NSDictionary *content = db[@"rights"][name]; + if (!content) { + content = db[@"rules"][name]; + } + + if (!content) { + printf("Error: Unable to find section %s\n", name.UTF8String); + return 0; + } + + NSString *class = content[@"class"]; + if (!class) { + printf("Error: Unable to get class from %s\n", name.UTF8String); + return 0; + } + + NSMutableDictionary *output = [NSMutableDictionary new]; + addDataOutput(output, content, otEntitlement, nil, NO); + addDataOutput(output, content, otAppleSigned, nil, NO); + + NSArray *mechanisms = nil; + if ([class isEqualToString:@"rule"]) { + addDataOutput(output, content, otKofn, nil, YES); + + id rule = content[@"rule"]; + NSArray *rules; + if ([rule isKindOfClass:[NSString class]]) { + rules = [NSArray arrayWithObject:rule]; + } else { + rules = rule; + } + + NSMutableArray *ruleDetails = [NSMutableArray new]; + + for(NSUInteger i = 0; i < rules.count; ++i) { + NSArray *result = parseRight(db, rules[i], level + 1); + if (result) { + [ruleDetails addObject:result]; + } + } + output[[NSNumber numberWithInteger:otRules]] = ruleDetails; + } else if ([class isEqualToString:@"user"]) { + output[[NSNumber numberWithInteger:otUser]] = @"* user credentials required *"; + + // group + addDataOutput(output, content, otRequiredGroup, nil, NO); + + // timeout + addDataOutput(output, content, otTimeout, @INT32_MAX, NO); + + // tries + addDataOutput(output, content, otTries, @10000, NO); + + // shared (default false) + addDataOutput(output, content, otShared, @NO, YES); + + // allow-root + addDataOutput(output, content, otAllowRoot, @NO, NO); + + // session owner + addDataOutput(output, content, otSessionOwner, @NO, NO); + + // show ui + addDataOutput(output, content, otShowUi, @YES, YES); + + // extract password + addDataOutput(output, content, otExtractPassword, @NO, NO); + + // entitled and group + addDataOutput(output, content, otEntitledAndGroup, @NO, NO); + + // vpn entitled and group + addDataOutput(output, content, otVpnEntitledAndGroup, @NO, NO); + + // password only + addDataOutput(output, content, otExtractPassword, @NO, NO); + + // mechanisms + mechanisms = content[@"mechanisms"]; + } else if ([class isEqualToString:@"evaluate-mechanisms"]) { + addDataOutput(output, content, otShared, @YES, YES); + addDataOutput(output, content, otExtractPassword, @NO, NO); + + // mechanisms + mechanisms = content[@"mechanisms"]; + } else if ([class isEqualToString:@"allow"]) { + addDataOutput(output, content, otAllow, nil, YES); + } else if ([class isEqualToString:@"deny"]) { + addDataOutput(output, content, otDeny, nil, YES); + } + + if (mechanisms) { + NSMutableArray *mechanismsDetails = [NSMutableArray new]; + if ([mechanisms isKindOfClass:[NSArray class]]) { + if (mechanisms.count > 1) { + [mechanismsDetails addObject:START_TAG_PLACEHOLDER]; + } + for(NSUInteger i = 0; i < mechanisms.count; ++i) { + [mechanismsDetails addObject:mechanisms[i]]; + } + if (mechanisms.count > 1) { + [mechanismsDetails addObject:END_TAG_PLACEHOLDER]; + } + if (mechanismsDetails.count) { + output[[NSNumber numberWithInteger:otMechanismsHeader]] = @"All of the following mechanisms:"; + output[[NSNumber numberWithInteger:otMechanisms]] = mechanismsDetails; + } + } else { + printf("Warning: rule %s - mechanisms is not an array\n", name.UTF8String); + } + } + + if (level > 1) { + output[[NSNumber numberWithInteger:otHeader]] = START_TAG_PLACEHOLDER; + output[[NSNumber numberWithInteger:otFooter]] = END_TAG_PLACEHOLDER; + } + + NSArray *sortedKeys = [[output allKeys] sortedArrayUsingSelector: @selector(compare:)]; + NSMutableArray *result = [NSMutableArray new]; + processOutput([output objectsForKeys:sortedKeys notFoundMarker:@""], result, 1); + return result; +} + +int main(int argc, const char * argv[]) +{ + @autoreleasepool { + + NSString *file; + NSString *right; + if (argc > 2) { + file = [NSString stringWithUTF8String:argv[1]]; + right = [NSString stringWithUTF8String:argv[2]]; + } else if (argc == 2) { + right = [NSString stringWithUTF8String:argv[1]]; + file = @DEFAULT_DB; + } else { + NSString *binaryName = [[NSString stringWithUTF8String:argv[0]] lastPathComponent]; + printf("Usage: %s [right [definitions.plist]]\n", binaryName.UTF8String); + exit(-1); + } + NSDictionary *db = [[NSDictionary alloc] initWithContentsOfFile:file]; + if (!db) { + printf("Error: authorization definition file %s was not found or is invalid.\n", file.UTF8String); + exit(-1); + } + + NSDictionary *rightContent = db[@"rights"][right]; + if (!rightContent) { + printf("Error: right %s was not found in %s\n", right.UTF8String, file.UTF8String); + exit(-1); + } + + NSArray *result = parseRight(db, right, 1); + printf("Authorization right %s\n", right.UTF8String); + for (NSString *line in result) { + printf("%s\n", line.UTF8String); + } + } + return 0; +} diff --git a/OSX/config/base.xcconfig b/OSX/config/base.xcconfig index 075f3373..0e70fa2a 100644 --- a/OSX/config/base.xcconfig +++ b/OSX/config/base.xcconfig @@ -16,6 +16,5 @@ STRIP_STYLE = debugging STRIP_INSTALLED_PRODUCT = NO WARNING_CFLAGS = -Wno-deprecated-declarations $(inherited) -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) OSSPINLOCK_USE_INLINED=0 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) CORECRYPTO_DONOT_USE_TRANSPARENT_UNION=1 -HEADER_SEARCH_PATHS = $(inherited) $(PROJECT_DIR)/../header_symlinks/ diff --git a/OSX/config/debug.xcconfig b/OSX/config/debug.xcconfig index 49c092ea..47555cf5 100644 --- a/OSX/config/debug.xcconfig +++ b/OSX/config/debug.xcconfig @@ -1,4 +1,2 @@ GCC_OPTIMIZATION_LEVEL = 0 GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) - -HEADER_SEARCH_PATHS = $(inherited) $(PROJECT_DIR)/../header_symlinks/ diff --git a/OSX/config/lib.xcconfig b/OSX/config/lib.xcconfig index 116ab911..fdb54902 100644 --- a/OSX/config/lib.xcconfig +++ b/OSX/config/lib.xcconfig @@ -5,9 +5,7 @@ EXECUTABLE_PREFIX = CODE_SIGN_IDENTITY = -HEADER_SEARCH_PATHS = $(PROJECT_DIR)/../regressions $(PROJECT_DIR)/../include $(BUILT_PRODUCTS_DIR)/derived_src $(BUILT_PRODUCTS_DIR) $(PROJECT_DIR)/lib $(PROJECT_DIR)/../utilities $(inherited) - -FRAMEWORK_SEARCH_PATHS = $(inherited) $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks +HEADER_SEARCH_PATHS = $(PROJECT_DIR)/../ $(PROJECT_DIR)/../include $(BUILT_PRODUCTS_DIR)/derived_src $(BUILT_PRODUCTS_DIR) $(PROJECT_DIR)/lib $(PROJECT_DIR)/../utilities $(inherited) SKIP_INSTALL = YES diff --git a/OSX/config/release.xcconfig b/OSX/config/release.xcconfig index 5130441c..088ded92 100644 --- a/OSX/config/release.xcconfig +++ b/OSX/config/release.xcconfig @@ -1,4 +1,2 @@ GCC_OPTIMIZATION_LEVEL = s GCC_PREPROCESSOR_DEFINITIONS = NDEBUG=1 $(inherited) - -HEADER_SEARCH_PATHS = $(inherited) $(PROJECT_DIR)/../header_symlinks/ diff --git a/OSX/config/security_framework_macos.xcconfig b/OSX/config/security_framework_macos.xcconfig index 517b88c2..2e878c70 100644 --- a/OSX/config/security_framework_macos.xcconfig +++ b/OSX/config/security_framework_macos.xcconfig @@ -17,7 +17,7 @@ INFOPLIST_FILE = OSX/lib/Info-Security.plist INSTALL_PATH = $(SYSTEM_LIBRARY_DIR)/Frameworks -OTHER_LDFLAGS = -Wl,-upward-lcoretls -Wl,-upward-lcoretls_cfhelpers -laks -lCrashReporterClient +OTHER_LDFLAGS = -laks -lCrashReporterClient -Wl,-upward_framework,Foundation SECTORDER_FLAGS = -order_file_statistics APPLY_RULES_IN_COPY_FILES = NO diff --git a/OSX/config/security_macos.xcconfig b/OSX/config/security_macos.xcconfig index 4c5fd14b..73f31cac 100644 --- a/OSX/config/security_macos.xcconfig +++ b/OSX/config/security_macos.xcconfig @@ -14,7 +14,7 @@ GCC_C_LANGUAGE_STANDARD = gnu99 SUPPORTED_PLATFORMS = macOS // Don't use the inherited cflags; they set SEC_IOS_ON_OSX -GCC_PREPROCESSOR_DEFINITIONS = OSSPINLOCK_USE_INLINED=0 +GCC_PREPROCESSOR_DEFINITIONS = GCC_TREAT_WARNINGS_AS_ERRORS = YES GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO diff --git a/OSX/lib/en.lproj/authorization.dfr.prompts-BBBAA77A32-C4EBFEA440.strings b/OSX/lib/en.lproj/authorization.dfr.prompts-BBBAA77A32-C4EBFEA440.strings index 677e29c7..3e047aa1 100644 --- a/OSX/lib/en.lproj/authorization.dfr.prompts-BBBAA77A32-C4EBFEA440.strings +++ b/OSX/lib/en.lproj/authorization.dfr.prompts-BBBAA77A32-C4EBFEA440.strings @@ -108,7 +108,7 @@ "system.preferences" = "Touch ID to Modify Your System Settings."; -"com.apple.SoftwareUpdate.modify-settings" = "Touch ID to Unlock the App Store Preferences."; +"com.apple.SoftwareUpdate.modify-settings" = "Touch ID to Unlock the App Store preferences."; "com.apple.uninstalld.uninstall" = "Touch ID to Delete an Application."; @@ -124,7 +124,7 @@ "com.apple.server.admin.streaming" = "Touch ID to Modify the QuickTime Streaming Server Settings."; -"system.preferences.softwareupdate" = "Touch ID to Unlock the App Store Preferences."; +"system.preferences.softwareupdate" = "Touch ID to Unlock the App Store preferences."; "system.keychain.modify" = "Touch ID to Modify the System Keychain."; diff --git a/OSX/lib/en.lproj/authorization.prompts.strings b/OSX/lib/en.lproj/authorization.prompts.strings index c5aeceb6..29b23439 100644 --- a/OSX/lib/en.lproj/authorization.prompts.strings +++ b/OSX/lib/en.lproj/authorization.prompts.strings @@ -144,7 +144,7 @@ "com.apple.AOSNotification.FindMyMac.remove" = "__APPNAME__ is trying to turn off Find My Mac."; -"com.apple.iBooksX.ParentalControl" = "__APPNAME__ is trying to unlock your Parental Controls preferences."; +"com.apple.iBooksX.ParentalControl" = "__APPNAME__ is trying to unlock Parental Controls preferences."; "system.services.networkextension.vpn" = "__APPNAME__ is trying to modify the VPN configuration."; @@ -160,3 +160,4 @@ "com.apple.security.sudo" = "__APPNAME__ is trying to execute a command as administrator."; +"com.apple.configurationprofiles.userprofile.trustcert" = "__APPNAME__ is trying to trust a certificate from a user configuration profile."; diff --git a/OSX/lib/generateErrStrings.pl b/OSX/lib/generateErrStrings.pl index 937320a6..509bb088 100644 --- a/OSX/lib/generateErrStrings.pl +++ b/OSX/lib/generateErrStrings.pl @@ -177,13 +177,12 @@ sub processInput # print "identifier: ", $identifier,"\n" if ($identifier ne ''); - #Drop everything before the comma - $enum =~ s/[^,]*,//; + #Drop everything before the comma, end of line or trailing comment + $enum =~ s/[^,]*(,|\n|(\/\*))//; # Now look for trailing comment. We only consider them # trailing if they come before the end of the line ($trailingcomment) = ($enum =~ /^[ \t]*\/\*((.)*)?\*\//); - # ($trailingcomment) = ($enum =~ m%^(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*)%); $trailingcomment = cleanupComment($trailingcomment); #Drop everything before the end of line diff --git a/OSX/libsecurity_apple_csp/lib/opensshWrap.cpp b/OSX/libsecurity_apple_csp/lib/opensshWrap.cpp index 7378251c..988943b2 100644 --- a/OSX/libsecurity_apple_csp/lib/opensshWrap.cpp +++ b/OSX/libsecurity_apple_csp/lib/opensshWrap.cpp @@ -30,7 +30,7 @@ #include "AppleCSPContext.h" #include "AppleCSPUtils.h" #include "AppleCSPKeys.h" -#include "RSA_DSA_Keys.h" +#include "RSA_DSA_keys.h" #include "opensshCoding.h" #include "cspdebugging.h" #include @@ -38,6 +38,7 @@ #include #include #include +#include static const char *authfile_id_string = "SSH PRIVATE KEY FILE FORMAT 1.1\n"; @@ -414,7 +415,10 @@ CSSM_RETURN encodeOpenSSHv1PrivKey( /* appended encrypted portion */ CFDataAppendBytes(cfOut, ctext, ctextLen); *encodedKey = cfOut; + goto cleanup; errOut: + CFReleaseNull(cfOut); +cleanup: /* it would be proper to zero out ptext here, but we can't do that to a CFData */ CFRelease(ptext); return ourRtn; @@ -482,7 +486,7 @@ void AppleCSPSession::WrapKeyOpenSSH1( CFIndex len = CFDataGetLength(cfOut); setUpData(WrappedKey.KeyData, len, normAllocator); memmove(WrappedKey.KeyData.Data, CFDataGetBytePtr(cfOut), len); - CFRelease(cfOut); + CFReleaseNull(cfOut); /* outgoing header */ WrappedKey.KeyHeader.BlobType = CSSM_KEYBLOB_WRAPPED; @@ -708,6 +712,7 @@ void AppleCSPSession::UnwrapKeyOpenSSH1( if(comment) { setUpCssmData(DescriptiveData, commentLen, normAllocator); memcpy(DescriptiveData.Data, comment, commentLen); + free(comment); } /* diff --git a/OSX/libsecurity_apple_csp/open_ssl/opensslUtils/opensslUtils.h b/OSX/libsecurity_apple_csp/open_ssl/opensslUtils/opensslUtils.h index 0467ba20..46f36d16 100644 --- a/OSX/libsecurity_apple_csp/open_ssl/opensslUtils/opensslUtils.h +++ b/OSX/libsecurity_apple_csp/open_ssl/opensslUtils/opensslUtils.h @@ -50,7 +50,7 @@ void clearOpensslErrors(); unsigned long logSslErrInfo(const char *op); void throwRsaDsa( - const char *op); + const char *op) __attribute__((analyzer_noreturn)); /* * given an openssl-style error, throw appropriate CssmError. diff --git a/OSX/libsecurity_apple_cspdl/lib/SSCSPDLSession.cpp b/OSX/libsecurity_apple_cspdl/lib/SSCSPDLSession.cpp index 25755028..e4cbb899 100644 --- a/OSX/libsecurity_apple_cspdl/lib/SSCSPDLSession.cpp +++ b/OSX/libsecurity_apple_cspdl/lib/SSCSPDLSession.cpp @@ -79,11 +79,14 @@ SSCSPDLSession::makeReferenceKey(SSCSPSession &session, KeyHandle inKeyHandle, CssmKey &outKey, SSDatabase &inSSDatabase, uint32 inKeyAttr, const CssmData *inKeyLabel) { +// The analyzer doesn't know what to do with the naked creation of an item +#ifndef __clang_analyzer__ SSKey* sskey = new SSKey(session, inKeyHandle, outKey, inSSDatabase, inKeyAttr, inKeyLabel); (void) sskey; // Compiler thinks this variable isn't used, but we want the side effects of creation. Tell the compiler it's okay. secinfo("SecAccessReference", "made a new reference sskey with handle %d [%ld]", sskey->keyHandle(), sskey->keyReference()); +#endif } SSKey & @@ -122,6 +125,8 @@ void SSCSPDLSession::didChangeKeyAcl(SecurityServer::ClientSession &clientSession, KeyHandle keyHandle, CSSM_ACL_AUTHORIZATION_TAG tag) { + StLock __(mKeyDeletionMutex); // The key can't be deleted while we're poking at it, on pain of crashing + SSKey *theKey = NULL; { diff --git a/OSX/libsecurity_apple_cspdl/lib/SSCSPDLSession.h b/OSX/libsecurity_apple_cspdl/lib/SSCSPDLSession.h index 637655c8..6718c53d 100644 --- a/OSX/libsecurity_apple_cspdl/lib/SSCSPDLSession.h +++ b/OSX/libsecurity_apple_cspdl/lib/SSCSPDLSession.h @@ -49,6 +49,8 @@ public: static void didChangeKeyAclCallback(void *context, SecurityServer::ClientSession &clientSession, SecurityServer::KeyHandle keyHandle, CSSM_ACL_AUTHORIZATION_TAG tag); + + Mutex mKeyDeletionMutex; // Used to ensure that only one thread is in either SSCSPSession::FreeKey or SSCSPDLSession::didChangeKeyAcl at a time, since SSCSPDLSession::didChangeKeyAcl might be trying to use the free-ing key (from a securityd callback). }; diff --git a/OSX/libsecurity_apple_cspdl/lib/SSCSPSession.cpp b/OSX/libsecurity_apple_cspdl/lib/SSCSPSession.cpp index e1f7b928..d079b3f0 100644 --- a/OSX/libsecurity_apple_cspdl/lib/SSCSPSession.cpp +++ b/OSX/libsecurity_apple_cspdl/lib/SSCSPSession.cpp @@ -346,6 +346,7 @@ SSCSPSession::FreeKey(const AccessCredentials *accessCred, { if (ioKey.blobType() == CSSM_KEYBLOB_REFERENCE) { + StLock _(mSSCSPDLSession.mKeyDeletionMutex); // @@@ Note that this means that detaching a session should free // all keys ascociated with it or else... // -- or else what? diff --git a/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp b/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp index 6e0c93fc..2b748e62 100644 --- a/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp +++ b/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp @@ -261,7 +261,7 @@ SSDatabaseImpl::ssCreate(const DLDbIdentifier &dlDbIdentifier) mSSDbHandle = mClientSession.createDb(dlDbIdentifier, cred, owner, dbParameters); CssmDataContainer dbb(allocator()); mClientSession.encodeDb(mSSDbHandle, dbb, allocator()); - secnotice("integrity", "opening %s", name()); + secinfo("integrity", "opening %s", name()); Db::Impl::insert(DBBlobRelationID, NULL, &dbb); if (autoCommit) { @@ -292,7 +292,7 @@ SSDatabaseImpl::ssCreateWithBlob(const DLDbIdentifier &dlDbIdentifier, const CSS { bool autoCommit; commonCreate(dlDbIdentifier, autoCommit); - secnotice("integrity", "opening %s", name()); + secinfo("integrity", "opening %s", name()); Db::Impl::insert(DBBlobRelationID, NULL, &blob); if (autoCommit) { @@ -384,9 +384,9 @@ SSDatabaseImpl::recodeDbToVersion(uint32 newBlobVersion) { try { if(isLocked()) { - secnotice("integrity", "is currently locked"); + secinfo("integrity", "is currently locked"); } else { - secnotice("integrity", "is already unlocked"); + secinfo("integrity", "is already unlocked"); } CssmDataContainer dbb(allocator()); @@ -398,15 +398,15 @@ SSDatabaseImpl::recodeDbToVersion(uint32 newBlobVersion) { dbb.clear(); // Create a newDbHandle using the master secrets from the dbBlob we are recoding to. - secnotice("integrity", "recoding db with handle %d", mSSDbHandle); + secinfo("integrity", "recoding db with handle %d", mSSDbHandle); SecurityServer::DbHandle clonedDbHandle = mClientSession.recodeDbToVersion(newBlobVersion, mSSDbHandle); - secnotice("integrity", "received db with handle %d", clonedDbHandle); + secinfo("integrity", "received db with handle %d", clonedDbHandle); // @@@ If the dbb changed since we fetched it we should abort or // retry the operation here. uint32 newBlobVersion = recodeHelper(clonedDbHandle, dbBlobId); - secnotice("integrity", "committing transaction %d", clonedDbHandle); + secinfo("integrity", "committing transaction %d", clonedDbHandle); // Commit the transaction to the db transaction.commit(); @@ -519,7 +519,7 @@ uint32 SSDatabaseImpl::recodeHelper(SecurityServer::DbHandle clonedDbHandle, Css // Commit the new blob to securityd, reencode the db blob, release the // cloned db handle and commit the new blob to the db. CssmDataContainer dbb(allocator()); - secnotice("integrity", "committing %d", clonedDbHandle); + secinfo("integrity", "committing %d", clonedDbHandle); mClientSession.commitDbForSync(mSSDbHandle, clonedDbHandle, dbb, allocator()); dbBlobId->modify(DBBlobRelationID, NULL, &dbb, diff --git a/OSX/libsecurity_apple_cspdl/lib/SSKey.cpp b/OSX/libsecurity_apple_cspdl/lib/SSKey.cpp index 3fa1dfec..89fd9145 100644 --- a/OSX/libsecurity_apple_cspdl/lib/SSKey.cpp +++ b/OSX/libsecurity_apple_cspdl/lib/SSKey.cpp @@ -236,12 +236,18 @@ mClientSession(session.clientSession()) } SSKey::~SSKey() -{ +try { StLock _(mMutex); // In the destructor too??? Yes. See SSCSPSession.cpp:354 for an explanation of this code's policy on threads. if (mKeyHandle != noKey) clientSession().releaseKey(mKeyHandle); +} catch (...) { + /* + * If the key handle have been invalidated, releaseKey will throw an exception + */ + return; } + void SSKey::free(const AccessCredentials *accessCred, CssmKey &ioKey, CSSM_BOOL deleteKey) diff --git a/OSX/libsecurity_apple_x509_cl/lib/DecodedExtensions.cpp b/OSX/libsecurity_apple_x509_cl/lib/DecodedExtensions.cpp index ace807be..d407b392 100644 --- a/OSX/libsecurity_apple_x509_cl/lib/DecodedExtensions.cpp +++ b/OSX/libsecurity_apple_x509_cl/lib/DecodedExtensions.cpp @@ -500,7 +500,7 @@ void DecodedExtensions::addExtension( mSizeofExtensions = mNumExtensions ? (2 * mNumExtensions) : MIN_EXTENSIONS; mExtensions = (DecodedExten **)mAlloc.realloc( - mExtensions, mSizeofExtensions * sizeof(DecodedExten)); + mExtensions, mSizeofExtensions * sizeof(DecodedExten*)); } mExtensions[mNumExtensions++] = new DecodedExten(extnId, critical, nssObj, berEncoded, templ, mCoder, rawExtn); diff --git a/OSX/libsecurity_apple_x509_cl/lib/clNssUtils.cpp b/OSX/libsecurity_apple_x509_cl/lib/clNssUtils.cpp index bad0ce39..bee31697 100644 --- a/OSX/libsecurity_apple_x509_cl/lib/clNssUtils.cpp +++ b/OSX/libsecurity_apple_x509_cl/lib/clNssUtils.cpp @@ -827,7 +827,7 @@ void CL_qualCertStatementsToCssm( return; } cdsaObj.qcStatements = (CE_QC_Statement *)alloc.malloc( - numQcs * sizeof(CE_AccessDescription)); + numQcs * sizeof(CE_QC_Statement)); cdsaObj.numQCStatements = numQcs; for(unsigned dex=0; dex #include #include +#include #include /* for memcmp */ #include @@ -693,15 +694,13 @@ CSSM_RETURN TPCrlInfo::isCertRevoked( } subjectCert.freeField(&CSSMOID_X509V1SerialNumber, subjSerial); + + CFReleaseNull(cfRevokedTime); + CFReleaseNull(cfVerifyTime); + if(crtn && !subjectCert.addStatusCode(crtn)) { return CSSM_OK; } - if(cfRevokedTime) { - CFRelease(cfRevokedTime); - } - if(cfVerifyTime) { - CFRelease(cfVerifyTime); - } return crtn; } diff --git a/OSX/libsecurity_apple_x509_tp/lib/TPDatabase.cpp b/OSX/libsecurity_apple_x509_tp/lib/TPDatabase.cpp index 0810f0ba..3870a8c8 100644 --- a/OSX/libsecurity_apple_x509_tp/lib/TPDatabase.cpp +++ b/OSX/libsecurity_apple_x509_tp/lib/TPDatabase.cpp @@ -119,7 +119,7 @@ TPCertInfo *tpDbFindIssuerCert( dlDb = dbList->DLDBHandle[dbDex]; cert.Data = NULL; cert.Length = 0; - resultHand = 0; + resultHand = CSSM_INVALID_HANDLE; record = tpCertLookup(dlDb, subjectItem->issuerName(), &resultHand, @@ -507,6 +507,7 @@ TPCrlInfo *tpDbFindIssuerCrl( dlDb = dbList->DLDBHandle[dbDex]; crl.Data = NULL; crl.Length = 0; + resultHand = CSSM_INVALID_HANDLE; record = tpCrlLookup(dlDb, &issuer, vfyCtx.verifyTime, diff --git a/OSX/libsecurity_apple_x509_tp/lib/certGroupUtils.cpp b/OSX/libsecurity_apple_x509_tp/lib/certGroupUtils.cpp index 614fe81b..dffa3c2a 100644 --- a/OSX/libsecurity_apple_x509_tp/lib/certGroupUtils.cpp +++ b/OSX/libsecurity_apple_x509_tp/lib/certGroupUtils.cpp @@ -300,6 +300,10 @@ static const char *tpSubStr( const char *substr, uint32 substrLen) { + if(!bigstr || !substr || bigstrLen == 0 || substrLen == 0) { + return NULL; + } + /* stop searching substrLen chars before end of bigstr */ const char *endBigStr = bigstr + bigstrLen - substrLen; for( ; bigstr <= endBigStr; ) { diff --git a/OSX/libsecurity_apple_x509_tp/lib/cuEnc64.c b/OSX/libsecurity_apple_x509_tp/lib/cuEnc64.c index 879001cd..9d2bbe2d 100644 --- a/OSX/libsecurity_apple_x509_tp/lib/cuEnc64.c +++ b/OSX/libsecurity_apple_x509_tp/lib/cuEnc64.c @@ -260,6 +260,10 @@ unsigned char *cuDec64(const unsigned char *inbuf, bp = news; obuflen = (inlen / 4) * 3; + if(obuflen == 0) { + free(news); + return NULL; + } outbuf = (unsigned char*)malloc(obuflen); outp = outbuf; @@ -408,6 +412,10 @@ static const char *findStr( const char *cp; size_t srchStrLen = strlen(str); char c = str[0]; + + if(!inText) { + return NULL; + } /* last char * we can search in inText for start of str */ const char *endCp = inText + inTextLen - srchStrLen; @@ -439,6 +447,10 @@ static const char *getLine( *consumed = 0; const char *cp = inText; const char *newline = NULL; // if we found a newline, this points to the first one + + if(!inText) { + return NULL; + } while(inTextLen) { char c = *cp; diff --git a/OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp b/OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp index 32132a5c..cdedecc7 100644 --- a/OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp +++ b/OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp @@ -965,7 +965,7 @@ static CSSM_BOOL tpIsNumeric( * CFStringRef. Caller owns and must release the result. NULL return means * unconvertible input "string". */ -static CFStringRef tpTvpToCfString( +static CFStringRef CF_RETURNS_RETAINED tpTvpToCfString( const CSSM_X509_TYPE_VALUE_PAIR *tvp) { CFStringBuiltInEncodings encoding; diff --git a/OSX/libsecurity_asn1/Security b/OSX/libsecurity_asn1/Security deleted file mode 120000 index 945c9b46..00000000 --- a/OSX/libsecurity_asn1/Security +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file diff --git a/OSX/libsecurity_asn1/lib/X509Templates.c b/OSX/libsecurity_asn1/lib/X509Templates.c index 88d71ea1..93dda3e7 100644 --- a/OSX/libsecurity_asn1/lib/X509Templates.c +++ b/OSX/libsecurity_asn1/lib/X509Templates.c @@ -111,10 +111,10 @@ const SecAsn1Template kSecAsn1TBSCertificateTemplate[] = { { SEC_ASN1_INLINE, offsetof(NSS_TBSCertificate,subjectPublicKeyInfo), kSecAsn1SubjectPublicKeyInfoTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1, offsetof(NSS_TBSCertificate,issuerID), kSecAsn1BitStringTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 2, offsetof(NSS_TBSCertificate,subjectID), kSecAsn1BitStringTemplate }, { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | diff --git a/OSX/libsecurity_asn1/lib/pkcs12Templates.h b/OSX/libsecurity_asn1/lib/pkcs12Templates.h index ea2cc6f9..35650cb2 100644 --- a/OSX/libsecurity_asn1/lib/pkcs12Templates.h +++ b/OSX/libsecurity_asn1/lib/pkcs12Templates.h @@ -70,7 +70,7 @@ #define _PKCS12_TEMPLATES_H_ #include /* for NSS_Attribute */ -#include /* will be lib-specific place */ +#include /* will be lib-specific place */ #ifdef __cplusplus extern "C" { diff --git a/OSX/libsecurity_authorization/lib/Authorization.c b/OSX/libsecurity_authorization/lib/Authorization.c index 533fb326..7b7095a7 100644 --- a/OSX/libsecurity_authorization/lib/Authorization.c +++ b/OSX/libsecurity_authorization/lib/Authorization.c @@ -215,6 +215,65 @@ 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 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); + +done: + xpc_release_safe(message); + return status; +} + static OSStatus _AuthorizationCopyRights_send_message(xpc_object_t message, AuthorizationRights **authorizedRights) { diff --git a/OSX/libsecurity_authorization/lib/Authorization.h b/OSX/libsecurity_authorization/lib/Authorization.h index 1c6e9a3b..41f33df7 100644 --- a/OSX/libsecurity_authorization/lib/Authorization.h +++ b/OSX/libsecurity_authorization/lib/Authorization.h @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -90,7 +91,7 @@ CF_ENUM(OSStatus) { errAuthorizationInvalidTag = -60003, /* The authorization tag is invalid. */ errAuthorizationInvalidPointer = -60004, /* The returned authorization is invalid. */ errAuthorizationDenied = -60005, /* The authorization was denied. */ - errAuthorizationCanceled = -60006, /* The authorization was cancelled by the user. */ + errAuthorizationCanceled = -60006, /* The authorization was canceled by the user. */ errAuthorizationInteractionNotAllowed = -60007, /* The authorization was denied since no user interaction was possible. */ errAuthorizationInternal = -60008, /* Unable to obtain authorization for this operation. */ errAuthorizationExternalizeNotAllowed = -60009, /* The authorization is not allowed to be converted to an external format. */ @@ -236,7 +237,7 @@ typedef AuthorizationItemSet AuthorizationEnvironment; errAuthorizationDenied -60005 The authorization for one or more of the requested rights was denied. - errAuthorizationCanceled -60006 The authorization was cancelled by the user. + errAuthorizationCanceled -60006 The authorization was canceled by the user. errAuthorizationInteractionNotAllowed -60007 The authorization was denied since no interaction with the user was allowed. */ diff --git a/OSX/libsecurity_authorization/lib/AuthorizationPlugin.h b/OSX/libsecurity_authorization/lib/AuthorizationPlugin.h index 66c919df..f34c2366 100644 --- a/OSX/libsecurity_authorization/lib/AuthorizationPlugin.h +++ b/OSX/libsecurity_authorization/lib/AuthorizationPlugin.h @@ -78,7 +78,7 @@ CF_ASSUME_NONNULL_BEGIN typedef struct AuthorizationValue { size_t length; - void *data; + void * __nullable data; } AuthorizationValue; /*! @@ -176,7 +176,7 @@ enum { interface. */ enum { - kAuthorizationCallbacksVersion = 1 + kAuthorizationCallbacksVersion = 2 }; @@ -194,6 +194,8 @@ enum { @field SetHintValue Write value to hints. AuthorizationValue and data are copied. @field GetArguments Read arguments passed. AuthorizationValueVector does not own data. @field GetSessionId Read SessionId. + @field GetLAContext Returns authenticated LAContext which can be used for operations with Tokens which would normally require PIN. Caller owns returned context and is responsible for release. + @field GetTokenIdentities Returns array of identities. Caller owns returned array and is reponsible for release. */ typedef struct AuthorizationCallbacks { @@ -246,6 +248,25 @@ typedef struct AuthorizationCallbacks { AuthorizationString inKey, const AuthorizationValue * __nullable * __nullable outValue); + /* + Available only on systems with callback version 2 or higher + Constructs LAContext object based od actual user credentials, + userful for kSecUseAuthenticationContext for SecItem calls. + Caller is responsible for outValue release */ + OSStatus (*GetLAContext)(AuthorizationEngineRef inEngine, + CFTypeRef __nullable * __nullable outValue) __OSX_AVAILABLE_STARTING(__MAC_10_13, __PHONE_NA); + + /* + Available only on systems with callback version 2 or higher + Returns array of available identities available on tokens. Each array item consists of two + elements. The first one is SecIdentityRef and the second one is textual description of that identity + context parameter may contain CFTypeRef returned by GetLAContext. Returned identities + will contain PIN in such case so crypto operations won't display PIN prompt. + Caller is responsible for outValue release */ + OSStatus (*GetTokenIdentities)(AuthorizationEngineRef inEngine, + CFTypeRef context, + CFArrayRef __nullable * __nullable outValue) __OSX_AVAILABLE_STARTING(__MAC_10_13, __PHONE_NA); + } AuthorizationCallbacks; diff --git a/OSX/libsecurity_authorization/lib/AuthorizationPriv.h b/OSX/libsecurity_authorization/lib/AuthorizationPriv.h index de996040..332740ba 100644 --- a/OSX/libsecurity_authorization/lib/AuthorizationPriv.h +++ b/OSX/libsecurity_authorization/lib/AuthorizationPriv.h @@ -71,9 +71,9 @@ enum { */ OSStatus AuthorizationCreateWithAuditToken(audit_token_t token, - const AuthorizationEnvironment *environment, + const AuthorizationEnvironment * _Nullable environment, AuthorizationFlags flags, - AuthorizationRef *authorization); + AuthorizationRef _Nullable * _Nonnull authorization); /*! @function AuthorizationExecuteWithPrivilegesExternalForm @@ -97,11 +97,60 @@ OSStatus AuthorizationCreateWithAuditToken(audit_token_t token, for this functionality. */ -OSStatus AuthorizationExecuteWithPrivilegesExternalForm(const AuthorizationExternalForm * extForm, - const char *pathToTool, +OSStatus AuthorizationExecuteWithPrivilegesExternalForm(const AuthorizationExternalForm * _Nonnull extForm, + const char * _Nonnull pathToTool, AuthorizationFlags flags, - char *const *arguments, - FILE **communicationsPipe) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_7,__IPHONE_NA,__IPHONE_NA); + char * _Nonnull const * _Nonnull arguments, + FILE * _Nullable * _Nonnull communicationsPipe) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_7,__IPHONE_NA,__IPHONE_NA); + +/*! + @function AuthorizationExecuteWithPrivileges + Run an executable tool with enhanced privileges after passing + suitable authorization procedures. + @param authorization An authorization reference that is used to authorize + access to the enhanced privileges. It is also passed to the tool for + further access control. + @param pathToTool Full pathname to the tool that should be executed + with enhanced privileges. + @param options Option bits (reserved). Must be zero. + @param arguments An argv-style vector of strings to be passed to the tool. + @param communicationsPipe Assigned a UNIX stdio FILE pointer for + a bidirectional pipe to communicate with the tool. The tool will have + this pipe as its standard I/O channels (stdin/stdout). If NULL, do not + establish a communications pipe. + + @discussion This function has been deprecated and should no longer be used. + Use a launchd-launched helper tool and/or the Service Mangement framework + for this functionality. + */ +OSStatus AuthorizationExecuteWithPrivileges(AuthorizationRef _Nonnull authorization, + const char * _Nonnull pathToTool, + AuthorizationFlags options, + char * __nonnull const * __nonnull arguments, + 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. + */ +OSStatus AuthorizationPreauthorizeCredentials(AuthorizationRef _Nonnull authorization, + const AuthorizationItemSet * __nonnull credentials) __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); + +/*! + @function AuthorizationCopyPrivilegedReference + From within a tool launched via the AuthorizationExecuteWithPrivileges function + ONLY, retrieve the AuthorizationRef originally passed to that function. + While AuthorizationExecuteWithPrivileges already verified the authorization to + launch your tool, the tool may want to avail itself of any additional pre-authorizations + the caller may have obtained through that reference. + + @discussion This function has been deprecated and should no longer be used. + Use a launchd-launched helper tool and/or the Service Mangement framework + for this functionality. + */ +OSStatus AuthorizationCopyPrivilegedReference(AuthorizationRef __nullable * __nonnull authorization, + AuthorizationFlags flags) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_7,__IPHONE_NA,__IPHONE_NA); /* @function AuthorizationDismiss @@ -139,7 +188,7 @@ OSStatus SessionSetDistinguishedUser(SecuritySessionId session, uid_t user); special constants defined in AuthSession.h. @param user (output) Will receive the uid. Unchanged on error. */ -OSStatus SessionGetDistinguishedUser(SecuritySessionId session, uid_t *user); +OSStatus SessionGetDistinguishedUser(SecuritySessionId session, uid_t * _Nonnull user); /*! @function SessionSetUserPreferences @@ -157,7 +206,7 @@ OSStatus SessionSetUserPreferences(SecuritySessionId session); @param authRef (input) The authorization object on which this operation is performed. @param enable (input) desired smartcard login support state, TRUE to enable, FALSE to disable */ -OSStatus AuthorizationEnableSmartCard(AuthorizationRef authRef, Boolean enable); +OSStatus AuthorizationEnableSmartCard(AuthorizationRef _Nonnull authRef, Boolean enable); #if defined(__cplusplus) } diff --git a/OSX/libsecurity_authorization/lib/AuthorizationTagsPriv.h b/OSX/libsecurity_authorization/lib/AuthorizationTagsPriv.h index 509e571e..f062a321 100644 --- a/OSX/libsecurity_authorization/lib/AuthorizationTagsPriv.h +++ b/OSX/libsecurity_authorization/lib/AuthorizationTagsPriv.h @@ -258,10 +258,13 @@ #define AGENT_HINT_RETRY_REASON "reason" #define AGENT_HINT_AUTHORIZE_RULE "authorize-rule" #define AGENT_HINT_TOKEN_NAME "token-name" -#define AGENT_HINT_PROCESS_SIGNED "process-apple-signed" -#define AGENT_HINT_PROCESS_FROM_APPLE "process-firstparty-signed" +#define AGENT_HINT_CLIENT_SIGNED "client-apple-signed" +#define AGENT_HINT_CLIENT_FROM_APPLE "client-firstparty-signed" +#define AGENT_HINT_CREATOR_SIGNED "creator-apple-signed" +#define AGENT_HINT_CREATOR_FROM_APPLE "creator-firstparty-signed" #define AGENT_HINT_SHOW_RESET "show-reset" #define AGENT_HINT_PASSWORD_ONLY "password-only" +#define AGENT_HINT_SHEET_CONTEXT "sheet-context" // Public Key Hash from certificate used for login #define AGENT_HINT_TOKEN_HASH "token-hash" diff --git a/OSX/libsecurity_authorization/lib/trampolineClient.cpp b/OSX/libsecurity_authorization/lib/trampolineClient.cpp index dfbc986f..f544bb8c 100644 --- a/OSX/libsecurity_authorization/lib/trampolineClient.cpp +++ b/OSX/libsecurity_authorization/lib/trampolineClient.cpp @@ -131,6 +131,7 @@ OSStatus AuthorizationExecuteWithPrivilegesExternalForm(const AuthorizationExter int notify[2]; if (pipe(notify)) { fclose(mbox); + if(argv) { free(argv); } return errAuthorizationToolExecuteFailure; } @@ -139,6 +140,7 @@ OSStatus AuthorizationExecuteWithPrivilegesExternalForm(const AuthorizationExter if (communicationsPipe && socketpair(AF_UNIX, SOCK_STREAM, 0, comm)) { close(notify[READ]); close(notify[WRITE]); fclose(mbox); + if(argv) { free(argv); } return errAuthorizationToolExecuteFailure; } @@ -159,7 +161,8 @@ OSStatus AuthorizationExecuteWithPrivilegesExternalForm(const AuthorizationExter } secinfo("authexec", "fork failed (errno=%d)", errno); close(notify[READ]); close(notify[WRITE]); - return errAuthorizationToolExecuteFailure; + status = errAuthorizationToolExecuteFailure; + goto exit_point; default: { // parent // close foreign side of pipes diff --git a/OSX/libsecurity_cdsa_client/lib/clclient.cpp b/OSX/libsecurity_cdsa_client/lib/clclient.cpp index c816acd6..50764aa6 100644 --- a/OSX/libsecurity_cdsa_client/lib/clclient.cpp +++ b/OSX/libsecurity_cdsa_client/lib/clclient.cpp @@ -36,8 +36,12 @@ CLImpl::CLImpl(const Module &module) : AttachmentImpl(module, CSSM_SERVICE_CL) } CLImpl::~CLImpl() +try { } +catch(...) { + return; +} // diff --git a/OSX/libsecurity_cdsa_client/lib/cryptoclient.h b/OSX/libsecurity_cdsa_client/lib/cryptoclient.h index d708ca16..c0814431 100644 --- a/OSX/libsecurity_cdsa_client/lib/cryptoclient.h +++ b/OSX/libsecurity_cdsa_client/lib/cryptoclient.h @@ -44,6 +44,9 @@ public: Key key() const { return mKey; } void key(const Key &k); const CssmData &initVector() const { return *mInitVector; } + // The following function is invalid: you cannot save a pointer to an object passed in by reference. + // Fixing this error leads to corrupted mutexes everywhere; I cannot figure out why. + // To use the Crypt class, you must ensure that the CssmData object you pass in here lives for the lifetime of Crypt. void initVector(const CssmData &v) { mInitVector = &v; set(CSSM_ATTRIBUTE_INIT_VECTOR, v); } CSSM_PADDING padding() const { return mPadding; } void padding(CSSM_PADDING p) { mPadding = p; set(CSSM_ATTRIBUTE_PADDING, p); } diff --git a/OSX/libsecurity_cdsa_client/lib/cssmclient.cpp b/OSX/libsecurity_cdsa_client/lib/cssmclient.cpp index 2a483fdc..1fd0e6e8 100644 --- a/OSX/libsecurity_cdsa_client/lib/cssmclient.cpp +++ b/OSX/libsecurity_cdsa_client/lib/cssmclient.cpp @@ -458,9 +458,13 @@ AttachmentImpl::AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subservic } AttachmentImpl::~AttachmentImpl() +try { detach(); } +catch (...) { + return; +} void AttachmentImpl::make(CSSM_SERVICE_TYPE subserviceType) diff --git a/OSX/libsecurity_cdsa_client/lib/cssmclient.h b/OSX/libsecurity_cdsa_client/lib/cssmclient.h index df967d1a..a7bc57ea 100644 --- a/OSX/libsecurity_cdsa_client/lib/cssmclient.h +++ b/OSX/libsecurity_cdsa_client/lib/cssmclient.h @@ -65,7 +65,7 @@ private: // class Error : public CssmError { public: - Error(CSSM_RETURN err) : CssmError(err) { } + Error(CSSM_RETURN err) : CssmError(err, false) { } virtual const char *what () const throw(); enum { diff --git a/OSX/libsecurity_cdsa_utilities/lib/cssmerrors.cpp b/OSX/libsecurity_cdsa_utilities/lib/cssmerrors.cpp index 368699dc..98ec8dd8 100644 --- a/OSX/libsecurity_cdsa_utilities/lib/cssmerrors.cpp +++ b/OSX/libsecurity_cdsa_utilities/lib/cssmerrors.cpp @@ -1,15 +1,15 @@ /* * Copyright (c) 2000-2004,2006,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, @@ -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@ */ @@ -34,22 +34,21 @@ namespace Security { -CssmError::CssmError(CSSM_RETURN err) : error(err) +CssmError::CssmError(CSSM_RETURN err, bool suppresslogging) : error(err) { SECURITY_EXCEPTION_THROW_CSSM(this, err); - snprintf(whatBuffer, whatBufferSize, "CSSM Exception: %d %s", err, cssmErrorString(err)); - switch(err) { - case CSSMERR_CL_UNKNOWN_TAG: -#ifndef NDEBUG - secinfo("security_exception", "%s", what()); - LogBacktrace(); -#endif - break; - default: - secnotice("security_exception", "%s", what()); - LogBacktrace(); - break; + if(!suppresslogging || secinfoenabled("security_exception")) { + snprintf(whatBuffer, whatBufferSize, "CSSM Exception: %d %s", err, cssmErrorString(err)); + switch(err) { + /* reduce log noise by filtering out some non-error exceptions */ + case CSSMERR_CL_UNKNOWN_TAG: + break; + default: + secnotice("security_exception", "%s", what()); + LogBacktrace(); + break; + } } } @@ -66,7 +65,7 @@ OSStatus CssmError::osStatus() const { return errSecParam; } - + return error; } @@ -74,11 +73,11 @@ OSStatus CssmError::osStatus() const int CssmError::unixError() const { OSStatus err = osStatus(); - + // embedded UNIX errno values are returned verbatim if (err >= errSecErrnoBase && err <= errSecErrnoLimit) return err - errSecErrnoBase; - + // re-map certain CSSM errors switch (err) { case CSSM_ERRCODE_MEMORY_ERROR: @@ -98,7 +97,12 @@ int CssmError::unixError() const void CssmError::throwMe(CSSM_RETURN err) { - throw CssmError(err); + throw CssmError(err, false); +} + +void CssmError::throwMeNoLogging(CSSM_RETURN err) +{ + throw CssmError(err, true); } @@ -123,7 +127,7 @@ CSSM_RETURN CssmError::cssmError(const CommonError &error, CSSM_RETURN base) case BOOTSTRAP_UNKNOWN_SERVICE: case MIG_SERVER_DIED: return CSSM_ERRCODE_SERVICE_NOT_AVAILABLE; - default: + default: return CSSM_ERRCODE_INTERNAL_ERROR; } } else { diff --git a/OSX/libsecurity_cdsa_utilities/lib/cssmerrors.h b/OSX/libsecurity_cdsa_utilities/lib/cssmerrors.h index fc83b898..7da29adb 100644 --- a/OSX/libsecurity_cdsa_utilities/lib/cssmerrors.h +++ b/OSX/libsecurity_cdsa_utilities/lib/cssmerrors.h @@ -41,7 +41,7 @@ namespace Security // class CssmError : public CommonError { protected: - CssmError(CSSM_RETURN err); + CssmError(CSSM_RETURN err, bool suppresslogging); public: const CSSM_RETURN error; virtual OSStatus osStatus() const; @@ -52,6 +52,7 @@ public: static void check(CSSM_RETURN error) { if (error != CSSM_OK) throwMe(error); } static void throwMe(CSSM_RETURN error) __attribute__((noreturn)); + static void throwMeNoLogging(CSSM_RETURN err) __attribute__((noreturn)); // // Obtain a CSSM_RETURN from any CommonError diff --git a/OSX/libsecurity_cdsa_utilities/lib/handletemplates.h b/OSX/libsecurity_cdsa_utilities/lib/handletemplates.h index 9791072a..f9a6d504 100644 --- a/OSX/libsecurity_cdsa_utilities/lib/handletemplates.h +++ b/OSX/libsecurity_cdsa_utilities/lib/handletemplates.h @@ -99,7 +99,11 @@ public: typedef typename TypedHandle<_Handle>::Handle Handle; virtual ~MappingHandle() { +// security_filedb build error: instantiation of variable 'Security::MappingHandle::state' required here, but no definition is available +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-var-template" State &st = state(); +#pragma clang diagnostic pop StLock _(st); st.erase(this); } @@ -173,8 +177,12 @@ template inline Subclass &MappingHandle<_Handle>::find(_Handle handle, CSSM_RETURN error) { Subclass *sub; +// security_filedb build error: instantiation of variable 'Security::MappingHandle::state' required here, but no definition is available +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-var-template" if (!(sub = dynamic_cast(state().find(handle, error)))) CssmError::throwMe(error); +#pragma clang diagnostic pop return *sub; } @@ -201,7 +209,11 @@ inline Subclass &MappingHandle<_Handle>::findAndKill(_Handle handle, CSSM_RETURN error) { for (;;) { +// security_filedb build error: instantiation of variable 'Security::MappingHandle::state' required here, but no definition is available +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-var-template" typename HandleMap::iterator it = state().locate(handle, error); +#pragma clang diagnostic pop StLock _(state(), true); // locate() locked it Subclass *sub; if (!(sub = dynamic_cast(it->second))) diff --git a/OSX/libsecurity_cdsa_utils/lib/cuEnc64.c b/OSX/libsecurity_cdsa_utils/lib/cuEnc64.c index 41e0b005..23b033ff 100644 --- a/OSX/libsecurity_cdsa_utils/lib/cuEnc64.c +++ b/OSX/libsecurity_cdsa_utils/lib/cuEnc64.c @@ -258,6 +258,10 @@ unsigned char *cuDec64(const unsigned char *inbuf, bp = news; obuflen = (inlen / 4) * 3; + if(obuflen == 0) { + free(news); + return NULL; + } outbuf = (unsigned char*)malloc(obuflen); outp = outbuf; diff --git a/OSX/libsecurity_cdsa_utils/lib/cuFileIo.c b/OSX/libsecurity_cdsa_utils/lib/cuFileIo.c index 7b14cd29..214dca10 100644 --- a/OSX/libsecurity_cdsa_utils/lib/cuFileIo.c +++ b/OSX/libsecurity_cdsa_utils/lib/cuFileIo.c @@ -49,11 +49,7 @@ int writeFileSizet( int fd; fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600); - if(fd < 0) { - return errno; - } - rtn = (int)lseek(fd, 0, SEEK_SET); - if(rtn < 0) { + if(fd == -1) { return errno; } rtn = (int)write(fd, bytes, (size_t)numBytes); @@ -87,7 +83,7 @@ int readFile( *numBytes = 0; *bytes = NULL; fd = open(fileName, O_RDONLY, 0); - if(fd < 0) { + if(fd == -1) { return errno; } rtn = fstat(fd, &sb); diff --git a/OSX/libsecurity_cdsa_utils/lib/cuOidParser.cpp b/OSX/libsecurity_cdsa_utils/lib/cuOidParser.cpp index e9bc4e3b..d490d0f8 100644 --- a/OSX/libsecurity_cdsa_utils/lib/cuOidParser.cpp +++ b/OSX/libsecurity_cdsa_utils/lib/cuOidParser.cpp @@ -76,12 +76,9 @@ int readFileExtra( rtn = ENOMEM; goto errOut; } - rtn = (int)lseek(fd, 0, SEEK_SET); - if(rtn < 0) { - goto errOut; - } rtn = (int)read(fd, buf, (size_t)size); if(rtn != (int)size) { + free(buf); if(rtn >= 0) { printf("readFile: short read\n"); } @@ -92,10 +89,7 @@ int readFileExtra( *bytes = buf; *numBytes = size; } - goto finish; errOut: - if(buf) { free(buf); buf = NULL; } -finish: close(fd); return rtn; } diff --git a/OSX/libsecurity_cms/lib/CMSDecoder.cpp b/OSX/libsecurity_cms/lib/CMSDecoder.cpp index dcb79035..83775b23 100644 --- a/OSX/libsecurity_cms/lib/CMSDecoder.cpp +++ b/OSX/libsecurity_cms/lib/CMSDecoder.cpp @@ -66,7 +66,7 @@ struct _CMSDecoder { SecArenaPoolRef arena; /* the decoder's arena */ SecCmsDecoderRef decoder; CFDataRef detachedContent; - CFTypeRef keychainOrArray; /* from CMSDecoderSetSearchKeychain() */ + CFTypeRef keychainOrArray; /* unused */ /* * The following are valid (and quiescent) after CMSDecoderFinalizeMessage(). @@ -383,24 +383,14 @@ OSStatus CMSDecoderCopyDetachedContent( } /* - * Optionally specify a SecKeychainRef, or an array of them, containing - * intermediate certs to be used in verifying a signed message's signer - * certs. By default, the default keychain search list is used for this. - * Specify an empty CFArrayRef to search *no* keychains for intermediate - * certs. - * IF this is called, it must be called before CMSDecoderCopySignerStatus(). + * Beginning in 10.12, this function stopped affecting the behavior of the + * CMS Decoder. Its only use was in SecTrustSetKeychains which is a no-op. + * Please discontinue use. */ OSStatus CMSDecoderSetSearchKeychain( CMSDecoderRef cmsDecoder, CFTypeRef keychainOrArray) { - if(cmsDecoder == NULL) { - return errSecParam; - } - cmsDecoder->keychainOrArray = keychainOrArray; - if(keychainOrArray) { - CFRetain(keychainOrArray); - } return errSecSuccess; } @@ -474,11 +464,7 @@ OSStatus CMSDecoderCopySignerStatus( SecTrustRef theTrust = NULL; OSStatus vfyRtn = SecCmsSignedDataVerifySignerInfo(cmsDecoder->signedData, (int)signerIndex, - /* - * FIXME this cast should not be necessary, but libsecurity_smime - * declares this argument as a SecKeychainRef - */ - (SecKeychainRef)cmsDecoder->keychainOrArray, + NULL, policyOrArray, &theTrust); @@ -538,10 +524,6 @@ OSStatus CMSDecoderCopySignerStatus( case kSecTrustResultDeny: tpVfyStatus = CSSMERR_APPLETP_TRUST_SETTING_DENY; break; - case kSecTrustResultConfirm: - dprintf("SecTrustEvaluate reported confirm\n"); - tpVfyStatus = CSSMERR_TP_NOT_TRUSTED; - break; default: { /* get low-level TP error */ diff --git a/OSX/libsecurity_cms/lib/CMSDecoder.h b/OSX/libsecurity_cms/lib/CMSDecoder.h index df1c1872..f0357bd0 100644 --- a/OSX/libsecurity_cms/lib/CMSDecoder.h +++ b/OSX/libsecurity_cms/lib/CMSDecoder.h @@ -121,17 +121,14 @@ OSStatus CMSDecoderCopyDetachedContent( __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); /* - * Optionally specify a SecKeychainRef, or an array of them, containing - * intermediate certs to be used in verifying a signed message's signer - * certs. By default, the default keychain search list is used for this. - * Specify an empty CFArrayRef to search *no* keychains for intermediate - * certs. - * If this is called, it must be called before CMSDecoderCopySignerStatus(). + * This function no longer affects the behavior of the CMS Decoder. Please + * discontinue use. */ OSStatus CMSDecoderSetSearchKeychain( CMSDecoderRef cmsDecoder, CFTypeRef keychainOrArray) - __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA); + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_5, __MAC_10_13, __IPHONE_NA, __IPHONE_NA, + "To change the search keychains call SecKeychainSetSearchList."); /* * Obtain the number of signers of a message. A result of zero indicates that diff --git a/OSX/libsecurity_cms/lib/CMSEncoder.cpp b/OSX/libsecurity_cms/lib/CMSEncoder.cpp index 1d49a5d1..c3f43147 100644 --- a/OSX/libsecurity_cms/lib/CMSEncoder.cpp +++ b/OSX/libsecurity_cms/lib/CMSEncoder.cpp @@ -245,12 +245,12 @@ static int encodeOid( for(digit=0; digit +#include #include #include #include diff --git a/OSX/libsecurity_cms/regressions/cms-trust-settings-test.c b/OSX/libsecurity_cms/regressions/cms-trust-settings-test.c index 84a7dbf9..f15725af 100644 --- a/OSX/libsecurity_cms/regressions/cms-trust-settings-test.c +++ b/OSX/libsecurity_cms/regressions/cms-trust-settings-test.c @@ -37,7 +37,7 @@ #define kSystemLoginKeychainPath "/Library/Keychains/System.keychain" -#include +#include "regressions/test/testmore.h" #include "cms-trust-settings-test.h" // See diff --git a/OSX/libsecurity_cms/regressions/cms_regressions.h b/OSX/libsecurity_cms/regressions/cms_regressions.h index 8d8d5509..4cc5ad52 100644 --- a/OSX/libsecurity_cms/regressions/cms_regressions.h +++ b/OSX/libsecurity_cms/regressions/cms_regressions.h @@ -23,7 +23,7 @@ -#include +#include ONE_TEST(cms_hash_agility_test) ONE_TEST(cms_trust_settings_test) diff --git a/OSX/libsecurity_codesigning/lib/CSCommon.h b/OSX/libsecurity_codesigning/lib/CSCommon.h index 11e2f517..6aeef649 100644 --- a/OSX/libsecurity_codesigning/lib/CSCommon.h +++ b/OSX/libsecurity_codesigning/lib/CSCommon.h @@ -111,16 +111,18 @@ CF_ENUM(OSStatus) { errSecCSBadFrameworkVersion = -67009, /* embedded framework contains modified or invalid version */ errSecCSUnsealedFrameworkRoot = -67008, /* unsealed contents present in the root directory of an embedded framework */ errSecCSWeakResourceEnvelope = -67007, /* resource envelope is obsolete (version 1 signature) */ - errSecCSCancelled = -67006, /* operation was terminated by explicit cancellation */ + errSecCSCancelled = -67006, /* operation was terminated by explicit cancelation */ errSecCSInvalidPlatform = -67005, /* invalid platform identifier or platform mismatch */ errSecCSTooBig = -67004, /* code is too big for current signing format */ errSecCSInvalidSymlink = -67003, /* invalid destination for symbolic link in bundle */ errSecCSNotAppLike = -67002, /* the code is valid but does not seem to be an app */ errSecCSBadDiskImageFormat = -67001, /* disk image format unrecognized, invalid, or unsuitable */ - errSecCSUnsupportedDigestAlgorithm = -67000, /* signature digest algorithm(s) specified are not supported */ + errSecCSUnsupportedDigestAlgorithm = -67000, /* a requested signature digest algorithm is not supported */ errSecCSInvalidAssociatedFileData = -66999, /* resource fork, Finder information, or similar detritus not allowed */ errSecCSInvalidTeamIdentifier = -66998, /* a Team Identifier string is invalid */ errSecCSBadTeamIdentifier = -66997, /* a Team Identifier is wrong or inappropriate */ + errSecCSSignatureUntrusted = -66996, /* signature is valid but signer is not trusted */ + errSecMultipleExecSegments = -66995, /* the image contains multiple executable segments */ }; /* @@ -255,7 +257,6 @@ typedef CF_OPTIONS(uint32_t, SecCodeSignatureFlags) { kSecCodeSignatureLibraryValidation = 0x2000, /* library validation required */ }; - /*! @typedef SecCodeStatus The code signing system attaches a set of status flags to each running code. diff --git a/OSX/libsecurity_codesigning/lib/CSCommonPriv.h b/OSX/libsecurity_codesigning/lib/CSCommonPriv.h index 29299cb8..d527dd37 100644 --- a/OSX/libsecurity_codesigning/lib/CSCommonPriv.h +++ b/OSX/libsecurity_codesigning/lib/CSCommonPriv.h @@ -86,7 +86,21 @@ enum { kSecCodeMagicByte = 0xfa /* shared first byte */ }; - + +/*! + @typedef SecCodeExecSegFlags + */ +typedef CF_OPTIONS(uint32_t, SecCodeExecSegFlags) { + kSecCodeExecSegMainBinary = 0x0001, /* exec seg belongs to main binary */ + + // Entitlements + kSecCodeExecSegAllowUnsigned = 0x0010, /* allow unsigned pages (for debugging) */ + kSecCodeExecSegDebugger = 0x0020, /* main binary is debugger */ + kSecCodeExecSegJit = 0x0040, /* JIT enabled */ + kSecCodeExecSegSkipLibraryVal = 0x0080, /* skip library validation */ + kSecCodeExecSegCanLoadCdHash = 0x0100, /* can bless cdhash for execution */ + kSecCodeExecSegCanExecCdHash = 0x0200, /* can execute blessed cdhash */ +}; /* The current (fixed) size of a cdhash in the system. diff --git a/OSX/libsecurity_codesigning/lib/SecAssessment.cpp b/OSX/libsecurity_codesigning/lib/SecAssessment.cpp index 83566481..f3395e63 100644 --- a/OSX/libsecurity_codesigning/lib/SecAssessment.cpp +++ b/OSX/libsecurity_codesigning/lib/SecAssessment.cpp @@ -427,12 +427,7 @@ CFDictionaryRef SecAssessmentCopyUpdate(CFTypeRef target, CFRef result; // make context exist and writable - CFMutableDictionaryRef mcontext; - if (context == NULL) { - mcontext = makeCFMutableDictionary(); - } else { - mcontext = makeCFMutableDictionary(context); - } + CFRef mcontext = context ? makeCFMutableDictionary(context) : makeCFMutableDictionary(); if (CFDictionaryGetValue(mcontext, kSecAssessmentUpdateKeyAuthorization) == NULL) { // no authorization passed in. Make an empty one in this context diff --git a/OSX/libsecurity_codesigning/lib/SecCode.cpp b/OSX/libsecurity_codesigning/lib/SecCode.cpp index 7f6708bf..7cf85740 100644 --- a/OSX/libsecurity_codesigning/lib/SecCode.cpp +++ b/OSX/libsecurity_codesigning/lib/SecCode.cpp @@ -279,7 +279,8 @@ OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flag | kSecCSSigningInformation | kSecCSRequirementInformation | kSecCSDynamicInformation - | kSecCSContentInformation); + | kSecCSContentInformation + | kSecCSSkipResourceDirectory); SecPointer code = SecStaticCode::requiredStatic(codeRef); CFRef info = code->signingInformation(flags); diff --git a/OSX/libsecurity_codesigning/lib/SecCode.h b/OSX/libsecurity_codesigning/lib/SecCode.h index b636b9d5..1f0f831d 100644 --- a/OSX/libsecurity_codesigning/lib/SecCode.h +++ b/OSX/libsecurity_codesigning/lib/SecCode.h @@ -424,15 +424,16 @@ CF_ENUM(uint32_t) { kSecCSSigningInformation = 1 << 1, kSecCSRequirementInformation = 1 << 2, kSecCSDynamicInformation = 1 << 3, - kSecCSContentInformation = 1 << 4 + kSecCSContentInformation = 1 << 4, + kSecCSSkipResourceDirectory = 1 << 5 }; /* flag required to get this value */ extern const CFStringRef kSecCodeInfoCertificates; /* Signing */ extern const CFStringRef kSecCodeInfoChangedFiles; /* Content */ extern const CFStringRef kSecCodeInfoCMS; /* Signing */ extern const CFStringRef kSecCodeInfoDesignatedRequirement; /* Requirement */ -extern const CFStringRef kSecCodeInfoEntitlements; /* Requirement */ -extern const CFStringRef kSecCodeInfoEntitlementsDict; /* Requirement */ +extern const CFStringRef kSecCodeInfoEntitlements; /* generic */ +extern const CFStringRef kSecCodeInfoEntitlementsDict; /* generic */ extern const CFStringRef kSecCodeInfoFlags; /* generic */ extern const CFStringRef kSecCodeInfoFormat; /* generic */ extern const CFStringRef kSecCodeInfoDigestAlgorithm; /* generic */ diff --git a/OSX/libsecurity_codesigning/lib/SecCodePriv.h b/OSX/libsecurity_codesigning/lib/SecCodePriv.h index 5834012a..81038342 100644 --- a/OSX/libsecurity_codesigning/lib/SecCodePriv.h +++ b/OSX/libsecurity_codesigning/lib/SecCodePriv.h @@ -196,7 +196,7 @@ CFDataRef SecCodeCopyComponent(SecCodeRef code, int slot, CFDataRef hash); /* - @funtion SecCodeValidateFileResource + @function SecCodeValidateFileResource For a SecStaticCodeRef, check that a given CFData object faithfully represents a plain-file resource in its resource seal. This call will fail if the file is missing in the bundle, even if it is optional. diff --git a/OSX/libsecurity_codesigning/lib/SecRequirement.cpp b/OSX/libsecurity_codesigning/lib/SecRequirement.cpp index eab15a41..932096a8 100644 --- a/OSX/libsecurity_codesigning/lib/SecRequirement.cpp +++ b/OSX/libsecurity_codesigning/lib/SecRequirement.cpp @@ -113,9 +113,13 @@ OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anch maker.put(opAnd); // both of... maker.infoKey("Application-Group", cfString(groupName)); if (anchorRef) { +#if TARGET_OS_OSX CSSM_DATA certData; MacOSError::check(SecCertificateGetData(anchorRef, &certData)); maker.anchor(0, certData.Data, certData.Length); +#else + maker.anchor(0, SecCertificateGetBytePtr(anchorRef), SecCertificateGetLength(anchorRef)); +#endif } else { maker.anchor(); // canonical Apple anchor } diff --git a/OSX/libsecurity_codesigning/lib/SecRequirementPriv.h b/OSX/libsecurity_codesigning/lib/SecRequirementPriv.h index 66230b96..d40b1bec 100644 --- a/OSX/libsecurity_codesigning/lib/SecRequirementPriv.h +++ b/OSX/libsecurity_codesigning/lib/SecRequirementPriv.h @@ -30,6 +30,8 @@ #define _H_SECREQUIREMENTPRIV #include +#include + #ifdef __cplusplus extern "C" { diff --git a/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp b/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp index f4889f69..3d96abd0 100644 --- a/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp +++ b/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp @@ -121,6 +121,7 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se | kSecCSCheckGatekeeperArchitectures | kSecCSRestrictSymlinks | kSecCSRestrictToAppLike + | kSecCSUseSoftwareSigningCert ); if (errors) @@ -132,6 +133,20 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se 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 + // provisioning profile so if we prematurely throw an error when validating + // the directory, we potentially skip resource validation even though the + // caller will go on to trust the signature + // Applications that are validated against a provisioning profile do not have their resources checked + if (code->trustedSigningCertChain() == false) { + return CSError::cfError(errors, errSecCSSignatureUntrusted); + } +#endif + + END_CSAPI_ERRORS } @@ -222,7 +237,7 @@ OSStatus SecCodeMapMemory(SecStaticCodeRef codeRef, SecCSFlags flags) checkFlags(flags); SecPointer code = SecStaticCode::requiredStatic(codeRef); if (const CodeDirectory *cd = code->codeDirectory(false)) { - fsignatures args = { code->diskRep()->signingBase(), (void *)cd, cd->length() }; + fsignatures args = { static_cast(code->diskRep()->signingBase()), (void *)cd, cd->length() }; UnixError::check(::fcntl(code->diskRep()->fd(), F_ADDSIGS, &args)); } else MacOSError::throwMe(errSecCSUnsigned); diff --git a/OSX/libsecurity_codesigning/lib/SecStaticCode.h b/OSX/libsecurity_codesigning/lib/SecStaticCode.h index 3e5a292d..5fdb98b7 100644 --- a/OSX/libsecurity_codesigning/lib/SecStaticCode.h +++ b/OSX/libsecurity_codesigning/lib/SecStaticCode.h @@ -117,6 +117,8 @@ extern const CFStringRef kSecCodeAttributeBundleVersion; This key is ignored if no main architecture is specified; if it is specified by name; or if the code is not in Mach-O form. @constant kSecCodeAttributeUniversalFileOffset The offset of a Mach-O specific slice of a universal Mach-O file. + @constant kSecCodeAttributeBundleVersion If the code sought is a deep framework bundle (Something.framework/Versions/...), + then select the specified framework version. This key is otherwise ignored. */ OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, SecStaticCodeRef * __nonnull CF_RETURNS_RETAINED staticCode); @@ -141,9 +143,9 @@ OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flag @constant kSecCSCheckAllArchitectures For multi-architecture (universal) Mach-O programs, validate all architectures included. By default, only the native architecture is validated. - @constant kSecCSNoDnotValidateExecutable + @constant kSecCSDoNotValidateExecutable Do not validate the contents of the main executable. This is normally done. - @constant kSecCSNoNotValidateResources + @constant kSecCSDoNotValidateResources Do not validate the presence and contents of all bundle resources (if any). By default, a mismatch in any bundle resource causes validation to fail. @constant kSecCSCheckNestedCode @@ -176,6 +178,7 @@ CF_ENUM(uint32_t) { kSecCSRestrictSymlinks = 1 << 7, kSecCSRestrictToAppLike = 1 << 8, kSecCSRestrictSidebandData = 1 << 9, + kSecCSUseSoftwareSigningCert = 1 << 10, }; OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, SecCSFlags flags, diff --git a/OSX/libsecurity_codesigning/lib/SecStaticCodePriv.h b/OSX/libsecurity_codesigning/lib/SecStaticCodePriv.h index c534c0e5..a736a9e2 100644 --- a/OSX/libsecurity_codesigning/lib/SecStaticCodePriv.h +++ b/OSX/libsecurity_codesigning/lib/SecStaticCodePriv.h @@ -73,7 +73,7 @@ OSStatus SecStaticCodeSetValidationConditions(SecStaticCodeRef code, CFDictionar /* @function SecStaticCodeCancelValidation - Ask for an ongoing static validation using this (static) code object to be cancelled as soon as feasible. + Ask for an ongoing static validation using this (static) code object to be canceled as soon as feasible. if no validation is pending, this does nothing. Since validation is synchronous, this call must be made from another thread. This call will return immediately. If a validation operation is terminated due to it, diff --git a/OSX/libsecurity_codesigning/lib/SecTask.c b/OSX/libsecurity_codesigning/lib/SecTask.c deleted file mode 100644 index 96140c3e..00000000 --- a/OSX/libsecurity_codesigning/lib/SecTask.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2009-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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "SecCode.h" -#include "SecCodePriv.h" -#include "SecRequirement.h" - -#include "SecTask.h" -#include "SecTaskPriv.h" - - -struct __SecTask { - CFRuntimeBase base; - - pid_t pid_self; - - audit_token_t token; - - /* Track whether we've loaded entitlements independently since after the - * load, entitlements may legitimately be NULL */ - Boolean entitlementsLoaded; - CFDictionaryRef entitlements; - - /* for debugging only, shown by debugDescription */ - int lastFailure; -}; - -enum { - kSecCodeMagicEntitlement = 0xfade7171, /* entitlement blob */ -}; - - -CFTypeID _kSecTaskTypeID = _kCFRuntimeNotATypeID; - -static void SecTaskFinalize(CFTypeRef cfTask) -{ - SecTaskRef task = (SecTaskRef) cfTask; - CFReleaseNull(task->entitlements); -} - - -// Define PRIdPID (proper printf format string for pid_t) -#define PRIdPID PRId32 - -static CFStringRef SecTaskCopyDebugDescription(CFTypeRef cfTask) -{ - SecTaskRef task = (SecTaskRef) cfTask; - pid_t pid; - - if (task->pid_self==-1) { - audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); - } else { - pid = task->pid_self; - } - - const char *task_name; - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - struct kinfo_proc kp; - size_t len = sizeof(kp); - if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1 || len == 0) - task_name = strerror(errno); - else - task_name = kp.kp_proc.p_comm; - - return CFStringCreateWithFormat(CFGetAllocator(task), NULL, CFSTR("%s[%" PRIdPID "]"), task_name, pid); -} - -static void SecTaskRegisterClass(void) -{ - static const CFRuntimeClass SecTaskClass = { - .version = 0, - .className = "SecTask", - .init = NULL, - .copy = NULL, - .finalize = SecTaskFinalize, - .equal = NULL, - .hash = NULL, - .copyFormattingDesc = NULL, - .copyDebugDesc = SecTaskCopyDebugDescription, - }; - - _kSecTaskTypeID = _CFRuntimeRegisterClass(&SecTaskClass); -} - -CFTypeID SecTaskGetTypeID(void) -{ - static pthread_once_t secTaskRegisterClassOnce = PTHREAD_ONCE_INIT; - - /* Register the class with the CF runtime the first time through */ - pthread_once(&secTaskRegisterClassOnce, SecTaskRegisterClass); - - return _kSecTaskTypeID; -} - -static SecTaskRef init_task_ref(CFAllocatorRef allocator) -{ - CFIndex extra = sizeof(struct __SecTask) - sizeof(CFRuntimeBase); - return (SecTaskRef) _CFRuntimeCreateInstance(allocator, SecTaskGetTypeID(), extra, NULL); -} - -SecTaskRef SecTaskCreateWithAuditToken(CFAllocatorRef allocator, audit_token_t token) -{ - SecTaskRef task = init_task_ref(allocator); - if (task != NULL) { - - memcpy(&task->token, &token, sizeof(token)); - task->entitlementsLoaded = false; - task->entitlements = NULL; - task->pid_self = -1; - } - - return task; -} - -SecTaskRef SecTaskCreateFromSelf(CFAllocatorRef allocator) -{ - SecTaskRef task = init_task_ref(allocator); - if (task != NULL) { - - memset(&task->token, 0, sizeof(task->token)); - task->entitlementsLoaded = false; - task->entitlements = NULL; - task->pid_self = getpid(); - } - - return task; -} - -/* - * Determine if the given task meets a specified requirement. - */ -OSStatus -SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement) -{ - OSStatus status; - SecCodeRef code = NULL; - SecRequirementRef req = NULL; - CFDataRef auditData = NULL; - CFNumberRef pidRef = NULL; - - CFMutableDictionaryRef codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if(task->pid_self==-1) { - auditData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)&task->token, sizeof(audit_token_t)); - CFDictionarySetValue(codeDict, kSecGuestAttributeAudit, auditData); - } else { - pidRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &task->pid_self); - CFDictionarySetValue(codeDict, kSecGuestAttributePid, pidRef); - } - - status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &code); - CFReleaseNull(codeDict); - CFReleaseNull(auditData); - CFReleaseNull(pidRef); - - if (!status) { - status = SecRequirementCreateWithString(requirement, - kSecCSDefaultFlags, &req); - } - if (!status) { - status = SecCodeCheckValidity(code, kSecCSDefaultFlags, req); - } - - CFReleaseNull(req); - CFReleaseNull(code); - - return status; -} - -static CFRange myMakeRange(CFIndex loc, CFIndex len) { - CFRange r = {.location = loc, .length = len }; - return r; -} -struct csheader { - uint32_t magic; - uint32_t length; -}; - -static int -csops_task(SecTaskRef task, int ops, void *blob, size_t size) -{ - int rc; - if (task->pid_self==-1) { - pid_t pid; - audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); - rc = csops_audittoken(pid, ops, blob, size, &task->token); - } - else - rc = csops(task->pid_self, ops, blob, size); - task->lastFailure = (rc == -1) ? errno : 0; - return rc; -} - -static int SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) -{ - CFMutableDataRef data = NULL; - struct csheader header; - uint32_t bufferlen; - int ret; - - ret = csops_task(task, CS_OPS_ENTITLEMENTS_BLOB, &header, sizeof(header)); - if (ret == 0) { - // we only gave a header's worth of buffer. If this succeeded, we have no entitlements - task->entitlementsLoaded = true; - return 0; - } - if (errno != ERANGE) { - // ERANGE means "your buffer is too small, it now tells you how much you need - // EINVAL is what the kernel says for unsigned code AND broken code, so we'll have to let that pass - if (errno == EINVAL) { - task->entitlementsLoaded = true; - return 0; - } - ret = errno; - goto out; - } - // kernel told us the needed buffer size in header.length; proceed - - bufferlen = ntohl(header.length); - /* check for insane values */ - if (bufferlen > 1024 * 1024 || bufferlen < 8) { - ret = EINVAL; - goto out; - } - data = CFDataCreateMutable(NULL, bufferlen); - if (data == NULL) { - ret = ENOMEM; - goto out; - } - CFDataSetLength(data, bufferlen); - ret = csops_task(task, CS_OPS_ENTITLEMENTS_BLOB, CFDataGetMutableBytePtr(data), bufferlen); - if (ret) { - ret = errno; - goto out; - } - CFDataDeleteBytes(data, myMakeRange(0, 8)); - task->entitlements = CFPropertyListCreateWithData(NULL, data, 0, NULL, error); - task->entitlementsLoaded = true; - out: - if (data) - CFRelease(data); - if (ret && error) - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ret, NULL); - - return ret; -} - -CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error) -{ - /* Load entitlements if necessary */ - if (task->entitlementsLoaded == false) { - SecTaskLoadEntitlements(task, error); - } - - CFTypeRef value = NULL; - if (task->entitlements != NULL) { - value = CFDictionaryGetValue(task->entitlements, entitlement); - - /* Return something the caller must release */ - if (value != NULL) { - CFRetain(value); - } - } - - return value; -} - -CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef entitlements, CFErrorRef *error) -{ - /* Load entitlements if necessary */ - if (task->entitlementsLoaded == false) { - SecTaskLoadEntitlements(task, error); - } - - /* Iterate over the passed in entitlements, populating the dictionary - * If entitlements were loaded but none were present, return an empty - * dictionary */ - CFMutableDictionaryRef values = NULL; - if (task->entitlementsLoaded == true) { - - CFIndex i, count = CFArrayGetCount(entitlements); - values = CFDictionaryCreateMutable(CFGetAllocator(task), count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (task->entitlements != NULL) { - for (i = 0; i < count; i++) { - CFStringRef entitlement = CFArrayGetValueAtIndex(entitlements, i); - CFTypeRef value = CFDictionaryGetValue(task->entitlements, entitlement); - if (value != NULL) { - CFDictionarySetValue(values, entitlement, value); - } - } - } - } - - return values; -} - -Boolean SecTaskEntitlementsValidated(SecTaskRef task) { - // TODO: Cache the result - uint32_t csflags = 0; - const uint32_t mask = CS_VALID | CS_KILL | CS_ENTITLEMENTS_VALIDATED; - int rc = csops_task(task, CS_OPS_STATUS, &csflags, sizeof(csflags)); - return rc != -1 && ((csflags & mask) == mask); -} - -CFStringRef -SecTaskCopySigningIdentifier(SecTaskRef task, CFErrorRef *error) -{ - CFStringRef signingId = NULL; - char *data = NULL; - struct csheader header; - uint32_t bufferlen; - int ret; - - ret = csops_task(task, CS_OPS_IDENTITY, &header, sizeof(header)); - if (ret != -1 || errno != ERANGE) - return NULL; - - bufferlen = ntohl(header.length); - /* check for insane values */ - if (bufferlen > 1024 * 1024 || bufferlen < 8) { - ret = EINVAL; - goto out; - } - data = malloc(bufferlen + 1); - if (data == NULL) { - ret = ENOMEM; - goto out; - } - ret = csops_task(task, CS_OPS_IDENTITY, data, bufferlen); - if (ret) { - ret = errno; - goto out; - } - data[bufferlen] = '\0'; - - signingId = CFStringCreateWithCString(NULL, data + 8, kCFStringEncodingUTF8); - -out: - if (data) - free(data); - if (ret && error) - *error = CFErrorCreate(NULL, kCFErrorDomainPOSIX, ret, NULL); - - return signingId; -} - -uint32_t -SecTaskGetCodeSignStatus(SecTaskRef task) -{ - uint32_t flags = 0; - if (csops_task(task, CS_OPS_STATUS, &flags, sizeof(flags)) != 0) - return 0; - return flags; -} - diff --git a/OSX/libsecurity_codesigning/lib/StaticCode.cpp b/OSX/libsecurity_codesigning/lib/StaticCode.cpp index b7fb0d77..8ec4a437 100644 --- a/OSX/libsecurity_codesigning/lib/StaticCode.cpp +++ b/OSX/libsecurity_codesigning/lib/StaticCode.cpp @@ -27,25 +27,35 @@ #include "StaticCode.h" #include "Code.h" #include "reqmaker.h" +#if TARGET_OS_OSX #include "drmaker.h" +#endif #include "reqdumper.h" #include "reqparser.h" #include "sigblob.h" #include "resources.h" #include "detachedrep.h" +#if TARGET_OS_OSX #include "csdatabase.h" +#endif #include "dirscanner.h" #include #include #include #include +#if TARGET_OS_OSX #include +#endif +#import #include #include #include +#if TARGET_OS_OSX #include +#endif #include #include +#include #include #include #include @@ -53,6 +63,8 @@ #include #include #include +#include +#include namespace Security { @@ -88,14 +100,23 @@ static inline OSStatus errorForSlot(CodeDirectory::SpecialSlot slot) // Construct a SecStaticCode object given a disk representation object // SecStaticCode::SecStaticCode(DiskRep *rep) - : mRep(rep), + : mCheckfix30814861builder1(NULL), + mRep(rep), mValidated(false), mExecutableValidated(false), mResourcesValidated(false), mResourcesValidContext(NULL), - mProgressQueue("com.apple.security.validation-progress", false, QOS_CLASS_DEFAULT), + mProgressQueue("com.apple.security.validation-progress", false, QOS_CLASS_UNSPECIFIED), mOuterScope(NULL), mResourceScope(NULL), - mDesignatedReq(NULL), mGotResourceBase(false), mMonitor(NULL), mLimitedAsync(NULL), mEvalDetails(NULL) + mDesignatedReq(NULL), mGotResourceBase(false), mMonitor(NULL), mLimitedAsync(NULL) +#if TARGET_OS_OSX + , mEvalDetails(NULL) +#else + , mTrustedSigningCertChain(false) +#endif + { CODESIGN_STATIC_CREATE(this, rep); +#if TARGET_OS_OSX checkForSystemSignature(); +#endif } @@ -107,6 +128,7 @@ try { ::free(const_cast(mDesignatedReq)); delete mResourcesValidContext; delete mLimitedAsync; + delete mCheckfix30814861builder1; } catch (...) { return; } @@ -159,7 +181,7 @@ CFTypeRef SecStaticCode::reportEvent(CFStringRef stage, CFDictionaryRef info) void SecStaticCode::prepareProgress(unsigned int workload) { dispatch_sync(mProgressQueue, ^{ - mCancelPending = false; // not cancelled + mCancelPending = false; // not canceled }); if (mValidationFlags & kSecCSReportProgress) { mCurrentWork = 0; // nothing done yet @@ -246,6 +268,7 @@ void SecStaticCode::detachedSignature(CFDataRef sigData) // void SecStaticCode::checkForSystemSignature() { +#if TARGET_OS_OSX if (!this->isSigned()) { SignatureDatabase db; if (db.isOpen()) @@ -257,6 +280,9 @@ void SecStaticCode::checkForSystemSignature() } catch (...) { } } +#else + MacOSError::throwMe(errSecUnimplemented); +#endif } @@ -328,11 +354,15 @@ void SecStaticCode::resetValidity() mGotResourceBase = false; mTrust = NULL; mCertChain = NULL; +#if TARGET_OS_OSX mEvalDetails = NULL; +#endif mRep->flush(); +#if TARGET_OS_OSX // we may just have updated the system database, so check again checkForSystemSignature(); +#endif } @@ -529,6 +559,10 @@ void SecStaticCode::validateDirectory() throw; } assert(validated()); + // XXX: Embedded doesn't have CSSMERR_TP_CERT_EXPIRED so we can't throw it + // XXX: This should be implemented for embedded once we implement + // XXX: verifySignature and see how we're going to handle expired certs +#if TARGET_OS_OSX if (mValidationResult == errSecSuccess) { if (mValidationExpired) if ((mValidationFlags & kSecCSConsiderExpiration) @@ -536,6 +570,7 @@ void SecStaticCode::validateDirectory() MacOSError::throwMe(CSSMERR_TP_CERT_EXPIRED); } else MacOSError::throwMe(mValidationResult); +#endif } @@ -574,7 +609,7 @@ void SecStaticCode::validateTopDirectory() if (component(slot)) foundVector.push_back(slot); int alternateCount = int(mCodeDirectories.size() - 1); // one will go into cdCodeDirectorySlot - for (unsigned n = 0; n < alternateCount; n++) + for (int n = 0; n < alternateCount; n++) foundVector.push_back(cdAlternateCodeDirectorySlots + n); foundVector.push_back(cdSignatureSlot); // mandatory (may be empty) @@ -622,7 +657,7 @@ 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 cms; MacOSError::check(CMSDecoderCreate(&cms.aref())); // create decoder @@ -632,8 +667,8 @@ bool SecStaticCode::verifySignature() MacOSError::check(CMSDecoderSetDetachedContent(cms, mBaseDir)); MacOSError::check(CMSDecoderFinalizeMessage(cms)); MacOSError::check(CMSDecoderSetSearchKeychain(cms, cfEmptyArray())); - CFRef vf_policies(verificationPolicies()); - CFRef ts_policies(SecPolicyCreateAppleTimeStampingAndRevocationPolicies(vf_policies)); + CFRef vf_policies(createVerificationPolicies()); + CFRef ts_policies(createTimeStampingAndRevocationPolicies()); CMSSignerStatus status; MacOSError::check(CMSDecoderCopySignerStatus(cms, 0, vf_policies, @@ -797,9 +832,64 @@ bool SecStaticCode::verifySignature() 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 attrs; + CFRef 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 hashBag; + hashBag = CFDataRef(CFDictionaryGetValue(attrs, kSecCMSHashAgility)); + if (hashBag) { + CFRef 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 + */ + 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); + return false; // XXX: Not checking for expired certs +#endif +} + +#if TARGET_OS_OSX // // Return the TP policy used for signature verification. // This may be a simple SecPolicyRef or a CFArray of policies. @@ -810,12 +900,18 @@ static SecPolicyRef makeRevocationPolicy(CFOptionFlags flags) CFRef policy(SecPolicyCreateRevocation(flags)); return policy.yield(); } +#endif -CFArrayRef SecStaticCode::verificationPolicies() +CFArrayRef SecStaticCode::createVerificationPolicies() { + if (mValidationFlags & kSecCSUseSoftwareSigningCert) { + CFRef ssRef = SecPolicyCreateAppleSoftwareSigning(); + return makeCFArray(1, ssRef.get()); + } +#if TARGET_OS_OSX CFRef core; MacOSError::check(SecPolicyCopy(CSSM_CERT_X_509v3, - &CSSMOID_APPLE_TP_CODE_SIGNING, &core.aref())); + &CSSMOID_APPLE_TP_CODE_SIGNING, &core.aref())); if (mValidationFlags & kSecCSNoNetworkAccess) { // Skips all revocation since they require network connectivity // therefore annihilates kSecCSEnforceRevocationChecks if present @@ -823,12 +919,44 @@ CFArrayRef SecStaticCode::verificationPolicies() return makeCFArray(2, core.get(), no_revoc.get()); } else if (mValidationFlags & kSecCSEnforceRevocationChecks) { - // Add CRL and OCSP policies + // Add CRL and OCSP policies CFRef revoc = makeRevocationPolicy(kSecRevocationUseAnyAvailableMethod); return makeCFArray(2, core.get(), revoc.get()); } else { return makeCFArray(1, core.get()); } +#elif TARGET_OS_TV + CFRef tvOSRef = SecPolicyCreateAppleTVOSApplicationSigning(); + return makeCFArray(1, tvOSRef.get()); +#else + CFRef iOSRef = SecPolicyCreateiPhoneApplicationSigning(); + return makeCFArray(1, iOSRef.get()); +#endif + +} + +CFArrayRef SecStaticCode::createTimeStampingAndRevocationPolicies() +{ + CFRef tsPolicy = SecPolicyCreateAppleTimeStamping(); +#if TARGET_OS_OSX + if (mValidationFlags & kSecCSNoNetworkAccess) { + // Skips all revocation since they require network connectivity + // therefore annihilates kSecCSEnforceRevocationChecks if present + CFRef no_revoc = makeRevocationPolicy(kSecRevocationNetworkAccessDisabled); + return makeCFArray(2, tsPolicy.get(), no_revoc.get()); + } + else if (mValidationFlags & kSecCSEnforceRevocationChecks) { + // Add CRL and OCSP policies + CFRef revoc = makeRevocationPolicy(kSecRevocationUseAnyAvailableMethod); + return makeCFArray(2, tsPolicy.get(), revoc.get()); + } + else { + return makeCFArray(1, tsPolicy.get()); + } +#else + return makeCFArray(1, tsPolicy.get()); +#endif + } @@ -1220,6 +1348,77 @@ CFDictionaryRef SecStaticCode::diskRepInformation() return mRep->diskRepInformation(); } +bool SecStaticCode::checkfix30814861(string path, bool addition) { + // v2 resource rules don't match v1 resource rules + + //// Condition 1: Is the app an iOS app that was built with an SDK lower than 9.0? + + // We started signing correctly in 2014, 9.0 was first seeded mid-2016. + + CFRef inf = diskRepInformation(); + try { + CFDictionary info(diskRepInformation(), errSecCSNotSupported); + uint32_t platformCmd = + cfNumber(info.get(kSecCodeInfoDiskRepOSPlatform, errSecCSNotSupported), 0); + uint32_t sdkVersion = + cfNumber(info.get(kSecCodeInfoDiskRepOSSDKVersion, errSecCSNotSupported), 0); + + if (platformCmd != LC_VERSION_MIN_IPHONEOS || sdkVersion >= 0x00090000) { + return false; + } + } catch (const MacOSError &error) { + return false; + } + + //// Condition 2: Is it a .sinf/.supf/.supp file at the right location? + + static regex_t pathre_sinf; + static regex_t pathre_supp_supf; + static dispatch_once_t once; + + dispatch_once(&once, ^{ + os_assert_zero(regcomp(&pathre_sinf, + "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|())SC_Info/[^/]+\\.sinf$", + REG_EXTENDED | REG_NOSUB)); + os_assert_zero(regcomp(&pathre_supp_supf, + "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|())SC_Info/[^/]+\\.(supf|supp)$", + REG_EXTENDED | REG_NOSUB)); + }); + + // .sinf is added, .supf/.supp are modified. + const regex_t &pathre = addition ? pathre_sinf : pathre_supp_supf; + + const int result = regexec(&pathre, path.c_str(), 0, NULL, 0); + + if (result == REG_NOMATCH) { + return false; + } else if (result != 0) { + // Huh? + secerror("unexpected regexec result %d for path '%s'", result, path.c_str()); + return false; + } + + //// Condition 3: Do the v1 rules actually exclude the file? + + dispatch_once(&mCheckfix30814861builder1_once, ^{ + // Create the v1 resource builder lazily. + CFDictionaryRef rules1 = cfget(resourceDictionary(), "rules"); + const string base = cfString(resourceBase()); + + mCheckfix30814861builder1 = new ResourceBuilder(base, base, rules1, false, mTolerateErrors); + }); + + ResourceBuilder::Rule const * const matchingRule = mCheckfix30814861builder1->findRule(path); + + if (matchingRule == NULL || !(matchingRule->flags & ResourceBuilder::omitted)) { + return false; + } + + //// All matched, this file is a check-fixed sinf/supf/supp. + + return true; + +} void SecStaticCode::validateResource(CFDictionaryRef files, string path, bool isSymlink, ValidationContext &ctx, SecCSFlags flags, uint32_t version) { @@ -1255,8 +1454,13 @@ void SecStaticCode::validateResource(CFDictionaryRef files, string path, bool is if (!hasher->verify(rseal.hash(type))) good = false; }); - if (!good) - ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAltered, fullpath); // altered + if (!good) { + if (version == 2 && checkfix30814861(path, false)) { + secinfo("validateResource", "%s check-fixed (altered).", path.c_str()); + } else { + ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAltered, fullpath); // altered + } + } } else { if (!seal.optional()) ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceMissing, fullpath); // was sealed but is now missing @@ -1272,7 +1476,11 @@ void SecStaticCode::validateResource(CFDictionaryRef files, string path, bool is if (::readlink(cfString(fullpath).c_str(), target, sizeof(target)) > 0) return; } - ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAdded, CFTempURL(path, false, resourceBase())); + if (version == 2 && checkfix30814861(path, true)) { + secinfo("validateResource", "%s check-fixed (added).", path.c_str()); + } else { + ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAdded, CFTempURL(path, false, resourceBase())); + } } void SecStaticCode::validatePlainMemoryResource(string path, CFDataRef fileData, SecCSFlags flags) @@ -1357,11 +1565,11 @@ void SecStaticCode::validateNestedCode(CFURLRef path, const ResourceSeal &seal, flags |= kSecCSBasicValidateOnly | kSecCSQuickCheck; SecPointer code = new SecStaticCode(DiskRep::bestGuess(cfString(path))); code->initializeFromParent(*this); - code->staticValidate(flags & ~kSecCSRestrictToAppLike, SecRequirement::required(req)); + code->staticValidate(flags & (~kSecCSRestrictToAppLike), SecRequirement::required(req)); if (isFramework && (flags & kSecCSStrictValidate)) try { - validateOtherVersions(path, flags, req, code); + validateOtherVersions(path, flags & (~kSecCSRestrictToAppLike), req, code); } catch (const CSError &err) { MacOSError::throwMe(errSecCSBadFrameworkVersion); } catch (const MacOSError &err) { @@ -1511,6 +1719,7 @@ const Requirement *SecStaticCode::defaultDesignatedRequirement() } return maker.make(); } else { +#if TARGET_OS_OSX // full signature: Gin up full context and let DRMaker do its thing validateDirectory(); // need the cert chain Requirement::Context context(this->certificates(), @@ -1520,6 +1729,9 @@ const Requirement *SecStaticCode::defaultDesignatedRequirement() this->codeDirectory() ); return DRMaker(context).make(); +#else + MacOSError::throwMe(errSecCSUnimplemented); +#endif } } @@ -1656,7 +1868,10 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags) // kSecCSRequirementInformation adds information on requirements // if (flags & kSecCSRequirementInformation) - try { + +//DR not currently supported on iOS +#if TARGET_OS_OSX + try { if (const Requirements *reqs = this->internalRequirements()) { CFDictionaryAddValue(dict, kSecCodeInfoRequirements, CFTempString(Dumper::dump(reqs))); @@ -1673,14 +1888,15 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags) CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, dreqRef); } } catch (...) { } +#endif - try { - if (CFDataRef ent = this->component(cdEntitlementSlot)) { - CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent); - if (CFDictionaryRef entdict = this->entitlements()) - CFDictionaryAddValue(dict, kSecCodeInfoEntitlementsDict, entdict); - } - } catch (...) { } + try { + if (CFDataRef ent = this->component(cdEntitlementSlot)) { + CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent); + if (CFDictionaryRef entdict = this->entitlements()) + CFDictionaryAddValue(dict, kSecCodeInfoEntitlementsDict, entdict); + } + } catch (...) { } // // kSecCSInternalInformation adds internal information meant to be for Apple internal @@ -1693,8 +1909,10 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags) if (mDir) CFDictionaryAddValue(dict, kSecCodeInfoCodeDirectory, mDir); CFDictionaryAddValue(dict, kSecCodeInfoCodeOffset, CFTempNumber(mRep->signingBase())); - if (CFRef rdict = getDictionary(cdResourceDirSlot, false)) // suppress validation - CFDictionaryAddValue(dict, kSecCodeInfoResourceDirectory, rdict); + if (!(flags & kSecCSSkipResourceDirectory)) { + if (CFRef rdict = getDictionary(cdResourceDirSlot, false)) // suppress validation + CFDictionaryAddValue(dict, kSecCodeInfoResourceDirectory, rdict); + } if (CFRef ddict = diskRepInformation()) CFDictionaryAddValue(dict, kSecCodeInfoDiskRepInfo, ddict); } catch (...) { } @@ -1706,7 +1924,7 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags) // of the signed code. This is (only) useful for packaging or patching-oriented // applications. // - if (flags & kSecCSContentInformation) + if (flags & kSecCSContentInformation && !(flags & kSecCSSkipResourceDirectory)) if (CFRef files = mRep->modifiedFiles()) CFDictionaryAddValue(dict, kSecCodeInfoChangedFiles, files); @@ -1773,7 +1991,8 @@ void SecStaticCode::staticValidate(SecCSFlags flags, const SecRequirement *req) if (flags & kSecCSReportProgress) prepareProgress(estimateResourceWorkload() + 2); // +1 head, +1 tail - // core components: once per architecture (if any) + + // core components: once per architecture (if any) this->staticValidateCore(flags, req); if (flags & kSecCSCheckAllArchitectures) handleOtherArchitectures(^(SecStaticCode* subcode) { @@ -1852,21 +2071,24 @@ void SecStaticCode::handleOtherArchitectures(void (^handle)(SecStaticCode* other fat->architectures(architectures); if (architectures.size() > 1) { DiskRep::Context ctx; - size_t activeOffset = fat->archOffset(); + off_t activeOffset = fat->archOffset(); for (Universal::Architectures::const_iterator arch = architectures.begin(); arch != architectures.end(); ++arch) { - ctx.offset = fat->archOffset(*arch); - if (ctx.offset > SIZE_MAX) - MacOSError::throwMe(errSecCSBadObjectFormat); - ctx.size = fat->lengthOfSlice((size_t)ctx.offset); - if (ctx.offset != activeOffset) { // inactive architecture; check it - SecPointer subcode = new SecStaticCode(DiskRep::bestGuess(this->mainExecutablePath(), &ctx)); - subcode->detachedSignature(this->mDetachedSig); // carry over explicit (but not implicit) detached signature - if (this->teamID() == NULL || subcode->teamID() == NULL) { - if (this->teamID() != subcode->teamID()) + try { + ctx.offset = int_cast(fat->archOffset(*arch)); + ctx.size = fat->lengthOfSlice(int_cast(ctx.offset)); + if (ctx.offset != activeOffset) { // inactive architecture; check it + SecPointer subcode = new SecStaticCode(DiskRep::bestGuess(this->mainExecutablePath(), &ctx)); + subcode->detachedSignature(this->mDetachedSig); // carry over explicit (but not implicit) detached signature + if (this->teamID() == NULL || subcode->teamID() == NULL) { + if (this->teamID() != subcode->teamID()) + MacOSError::throwMe(errSecCSSignatureInvalid); + } else if (strcmp(this->teamID(), subcode->teamID()) != 0) MacOSError::throwMe(errSecCSSignatureInvalid); - } else if (strcmp(this->teamID(), subcode->teamID()) != 0) - MacOSError::throwMe(errSecCSSignatureInvalid); - handle(subcode); + handle(subcode); + } + } catch(std::out_of_range e) { + // some of our int_casts fell over. + MacOSError::throwMe(errSecCSBadObjectFormat); } } } diff --git a/OSX/libsecurity_codesigning/lib/StaticCode.h b/OSX/libsecurity_codesigning/lib/StaticCode.h index 5f441e24..46dfbd2e 100644 --- a/OSX/libsecurity_codesigning/lib/StaticCode.h +++ b/OSX/libsecurity_codesigning/lib/StaticCode.h @@ -196,6 +196,9 @@ 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 public: void staticValidate(SecCSFlags flags, const SecRequirement *req); @@ -208,7 +211,8 @@ protected: protected: CFDictionaryRef getDictionary(CodeDirectory::SpecialSlot slot, bool check = true); // component value as a dictionary bool verifySignature(); - CFArrayRef verificationPolicies(); + CFArrayRef createVerificationPolicies(); + CFArrayRef createTimeStampingAndRevocationPolicies(); // load preferred rules/files dictionaries (cached therein) bool loadResources(CFDictionaryRef& rules, CFDictionaryRef& files, uint32_t& version); @@ -220,7 +224,11 @@ protected: private: void validateOtherVersions(CFURLRef path, SecCSFlags flags, SecRequirementRef req, SecStaticCode *code); + bool checkfix30814861(string path, bool addition); + ResourceBuilder *mCheckfix30814861builder1; + dispatch_once_t mCheckfix30814861builder1_once; + private: RefPointer mRep; // on-disk representation mutable CodeDirectoryMap mCodeDirectories; // available CodeDirectory blobs by digest type @@ -284,7 +292,12 @@ private: // signature verification outcome (mTrust == NULL => not done yet) CFRef mTrust; // outcome of crypto validation (valid or not) CFRef mCertChain; - CSSM_TP_APPLE_EVIDENCE_INFO *mEvalDetails; +#if TARGET_OS_OSX + CSSM_TP_APPLE_EVIDENCE_INFO *mEvalDetails; +#else + bool mTrustedSigningCertChain; +#endif + }; diff --git a/OSX/libsecurity_codesigning/lib/bundlediskrep.cpp b/OSX/libsecurity_codesigning/lib/bundlediskrep.cpp index c7bd784b..8ec8852c 100644 --- a/OSX/libsecurity_codesigning/lib/bundlediskrep.cpp +++ b/OSX/libsecurity_codesigning/lib/bundlediskrep.cpp @@ -447,6 +447,16 @@ size_t BundleDiskRep::signingLimit() return mExecRep->signingLimit(); } +size_t BundleDiskRep::execSegBase(const Architecture *arch) +{ + return mExecRep->execSegBase(arch); +} + +size_t BundleDiskRep::execSegLimit(const Architecture *arch) +{ + return mExecRep->execSegLimit(arch); +} + string BundleDiskRep::format() { return mFormat; diff --git a/OSX/libsecurity_codesigning/lib/bundlediskrep.h b/OSX/libsecurity_codesigning/lib/bundlediskrep.h index 92269613..f44a2b1c 100644 --- a/OSX/libsecurity_codesigning/lib/bundlediskrep.h +++ b/OSX/libsecurity_codesigning/lib/bundlediskrep.h @@ -64,6 +64,8 @@ public: void prepareForSigning(SigningContext &context); size_t signingBase(); size_t signingLimit(); + size_t execSegBase(const Architecture *arch); + size_t execSegLimit(const Architecture *arch); std::string format(); CFArrayRef modifiedFiles(); UnixPlusPlus::FileDesc &fd(); diff --git a/OSX/libsecurity_codesigning/lib/cdbuilder.cpp b/OSX/libsecurity_codesigning/lib/cdbuilder.cpp index d78660b1..babfe29c 100644 --- a/OSX/libsecurity_codesigning/lib/cdbuilder.cpp +++ b/OSX/libsecurity_codesigning/lib/cdbuilder.cpp @@ -47,6 +47,9 @@ CodeDirectory::Builder::Builder(HashAlgorithm digestAlgorithm) mCodeSlots(0), mScatter(NULL), mScatterSize(0), + mExecSegOffset(0), + mExecSegLimit(0), + mExecSegFlags(0), mDir(NULL) { mDigestLength = (uint32_t)MakeHash(this)->digestLength(); @@ -118,6 +121,8 @@ CodeDirectory::Scatter *CodeDirectory::Builder::scatter(unsigned count) size_t CodeDirectory::Builder::fixedSize(const uint32_t version) { size_t cdSize = sizeof(CodeDirectory); + if (version < supportsExecSegment) + cdSize -= sizeof(mDir->execSegBase) + sizeof(mDir->execSegLimit) + sizeof(mDir->execSegFlags); if (version < supportsCodeLimit64) cdSize -= sizeof(mDir->spare3) + sizeof(mDir->codeLimit64); if (version < supportsTeamID) @@ -182,8 +187,10 @@ CodeDirectory *CodeDirectory::Builder::build() size_t teamIDLength = mTeamID.size() + 1; // Determine the version - if (mExecLength > UINT32_MAX) { + if (mExecSegLimit > 0) { version = currentVersion; + } else if (mExecLength > UINT32_MAX) { + version = supportsCodeLimit64; } else if (mTeamID.size()) { version = supportsTeamID; } else { @@ -221,6 +228,10 @@ CodeDirectory *CodeDirectory::Builder::build() } else mDir->pageSize = 0; // means infinite page size + mDir->execSegBase = mExecSegOffset; + mDir->execSegLimit = mExecSegLimit; + mDir->execSegFlags = mExecSegFlags; + // locate and fill flex fields size_t offset = fixedSize(mDir->version); @@ -244,6 +255,8 @@ CodeDirectory *CodeDirectory::Builder::build() mDir->hashOffset = (uint32_t)(offset + mSpecialSlots * mDigestLength); offset += (mSpecialSlots + mCodeSlots) * mDigestLength; assert(offset == total); // matches allocated size + + (void)offset; // fill special slots memset((*mDir)[(int)-mSpecialSlots], 0, mDigestLength * mSpecialSlots); diff --git a/OSX/libsecurity_codesigning/lib/cdbuilder.h b/OSX/libsecurity_codesigning/lib/cdbuilder.h index cef350dc..761dcf63 100644 --- a/OSX/libsecurity_codesigning/lib/cdbuilder.h +++ b/OSX/libsecurity_codesigning/lib/cdbuilder.h @@ -59,7 +59,11 @@ public: Scatter *scatter(unsigned count); // allocate that many scatter elements (w/o sentinel) Scatter *scatter() { return mScatter; } // return already allocated scatter vector - + + void execSeg(uint64_t base, uint64_t limit, uint64_t flags) { + mExecSegOffset = base; mExecSegLimit = limit; mExecSegFlags = flags; } + void addExecSegFlags(uint64_t flags) { mExecSegFlags |= flags; } + size_t size(const uint32_t version); // calculate size CodeDirectory *build(); // build CodeDirectory and return it size_t fixedSize(const uint32_t version); // calculate fixed size of the CodeDirectory @@ -93,7 +97,11 @@ private: Scatter *mScatter; // scatter vector size_t mScatterSize; // number of scatter elements allocated (incl. sentinel) - + + uint64_t mExecSegOffset; // starting offset of executable segment + uint64_t mExecSegLimit; // limit of executable segment + uint64_t mExecSegFlags; // executable segment flags + CodeDirectory *mDir; // what we're building }; diff --git a/OSX/libsecurity_codesigning/lib/codedirectory.cpp b/OSX/libsecurity_codesigning/lib/codedirectory.cpp index b14b58ec..1fc4fddd 100644 --- a/OSX/libsecurity_codesigning/lib/codedirectory.cpp +++ b/OSX/libsecurity_codesigning/lib/codedirectory.cpp @@ -292,21 +292,19 @@ CodeDirectory::HashAlgorithm CodeDirectory::bestHashOf(const HashAlgorithms &typ void CodeDirectory::multipleHashFileData(FileDesc fd, size_t limit, CodeDirectory::HashAlgorithms types, void (^action)(HashAlgorithm type, DynamicHash* hasher)) { assert(!types.empty()); - vector > hashers; + map > hashes; for (auto it = types.begin(); it != types.end(); ++it) { if (CodeDirectory::viableHash(*it)) - hashers.push_back(CodeDirectory::hashFor(*it)); + hashes[*it] = CodeDirectory::hashFor(*it); } scanFileData(fd, limit, ^(const void *buffer, size_t size) { - unsigned n = 0; - for (auto it = types.begin(); it != types.end(); ++it, ++n) { - hashers[n]->update(buffer, size); + for (auto it = hashes.begin(); it != hashes.end(); ++it) { + it->second->update(buffer, size); } }); CFRef result = makeCFMutableDictionary(); - unsigned n = 0; - for (auto it = types.begin(); it != types.end(); ++it, ++n) { - action(*it, hashers[n]); + for (auto it = hashes.begin(); it != hashes.end(); ++it) { + action(it->first, it->second); } } diff --git a/OSX/libsecurity_codesigning/lib/codedirectory.h b/OSX/libsecurity_codesigning/lib/codedirectory.h index 381d6660..5fdaa355 100644 --- a/OSX/libsecurity_codesigning/lib/codedirectory.h +++ b/OSX/libsecurity_codesigning/lib/codedirectory.h @@ -198,16 +198,20 @@ public: Endian teamIDOffset; // offset of optional teamID string Endian spare3; // unused (most be zero) Endian codeLimit64; // limit to main image signature range, 64 bits - + Endian execSegBase; // offset of executable segment + Endian execSegLimit; // limit of executable segment + Endian execSegFlags; // exec segment flags + // works with the version field; see comments above - static const uint32_t currentVersion = 0x20300; // "version 2.3" + static const uint32_t currentVersion = 0x20400; // "version 2.4" static const uint32_t compatibilityLimit = 0x2F000; // "version 3 with wiggle room" static const uint32_t earliestVersion = 0x20001; // earliest supported version static const uint32_t supportsScatter = 0x20100; // first version to support scatter option static const uint32_t supportsTeamID = 0x20200; // first version to support team ID option static const uint32_t supportsCodeLimit64 = 0x20300; // first version to support codeLimit64 - + static const uint32_t supportsExecSegment = 0x20400; // first version to support exec base and limit + void checkIntegrity() const; // throws if inconsistent or unsupported version typedef uint32_t HashAlgorithm; // types of internal glue hashes @@ -257,7 +261,11 @@ public: const char *teamID() const { return version >= supportsTeamID && teamIDOffset ? at(teamIDOffset) : NULL; } char *teamID() { return version >= supportsTeamID && teamIDOffset ? at(teamIDOffset) : NULL; } - + + uint64_t execSegmentBase() const { return (version >= supportsExecSegment) ? execSegBase.get() : 0; } + uint64_t execSegmentLimit() const { return (version >= supportsExecSegment) ? execSegLimit.get() : 0; } + uint64_t execSegmentFlags() const { return (version >= supportsExecSegment) ? execSegFlags.get() : 0; } + public: bool validateSlot(const void *data, size_t size, Slot slot) const; // validate memory buffer against page slot bool validateSlot(UnixPlusPlus::FileDesc fd, size_t size, Slot slot) const; // read and validate file diff --git a/OSX/libsecurity_codesigning/lib/cs.h b/OSX/libsecurity_codesigning/lib/cs.h index 32f316f1..4e360e91 100644 --- a/OSX/libsecurity_codesigning/lib/cs.h +++ b/OSX/libsecurity_codesigning/lib/cs.h @@ -75,6 +75,11 @@ extern ModuleNexus gCFObjects; OSStatus dbError(const SQLite3::Error &err); +// Embedded platform does not have this function so skip the conversion +#if TARGET_OS_IPHONE +#define SecKeychainErrFromOSStatus(status) (status) +#endif + // // Code Signing API brackets diff --git a/OSX/libsecurity_codesigning/lib/cskernel.cpp b/OSX/libsecurity_codesigning/lib/cskernel.cpp index c4d579f7..7595bd52 100644 --- a/OSX/libsecurity_codesigning/lib/cskernel.cpp +++ b/OSX/libsecurity_codesigning/lib/cskernel.cpp @@ -76,6 +76,7 @@ KernelStaticCode::KernelStaticCode() // SecCode *KernelCode::locateGuest(CFDictionaryRef attributes) { +#if TARGET_OS_OSX CFNumberRef pidNumber = NULL; CFDataRef auditData = NULL; cfscan(attributes, "{%O=%NO}", kSecGuestAttributePid, &pidNumber); @@ -110,6 +111,9 @@ SecCode *KernelCode::locateGuest(CFDictionaryRef attributes) } return (new ProcessCode(pid, audit, diskRep))->retain(); +#else + MacOSError::throwMe(errSecCSUnimplemented); +#endif } diff --git a/OSX/libsecurity_codesigning/lib/csprocess.h b/OSX/libsecurity_codesigning/lib/csprocess.h index 71ee505b..d41ef23c 100644 --- a/OSX/libsecurity_codesigning/lib/csprocess.h +++ b/OSX/libsecurity_codesigning/lib/csprocess.h @@ -29,7 +29,7 @@ #include "csgeneric.h" #include "StaticCode.h" -#include "PidDiskRep.h" +#include "piddiskrep.h" #include namespace Security { diff --git a/OSX/libsecurity_codesigning/lib/csutilities.cpp b/OSX/libsecurity_codesigning/lib/csutilities.cpp index c6f0231b..e25e7b58 100644 --- a/OSX/libsecurity_codesigning/lib/csutilities.cpp +++ b/OSX/libsecurity_codesigning/lib/csutilities.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include "requirement.h" #include #include #include @@ -67,9 +67,13 @@ 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 } @@ -83,7 +87,7 @@ bool verifyHash(SecCertificateRef cert, const Hashing::Byte *digest) return !memcmp(dig, digest, SHA1::digestLength); } - +#if TARGET_OS_OSX // // Check to see if a certificate contains a particular field, by OID. This works for extensions, // even ones not recognized by the local CL. It does not return any value, only presence. @@ -147,7 +151,7 @@ bool certificateHasPolicy(SecCertificateRef cert, const CSSM_OID &policyOid) SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_PolicyConstraints, data); return matched; } - +#endif // // Copyfile diff --git a/OSX/libsecurity_codesigning/lib/csutilities.h b/OSX/libsecurity_codesigning/lib/csutilities.h index dcb0b130..668ffb86 100644 --- a/OSX/libsecurity_codesigning/lib/csutilities.h +++ b/OSX/libsecurity_codesigning/lib/csutilities.h @@ -34,7 +34,9 @@ #include #include #include +#if TARGET_OS_OSX #include +#endif #include #include #include @@ -60,20 +62,38 @@ bool verifyHash(SecCertificateRef cert, const Hashing::Byte *digest); inline size_t scanFileData(UnixPlusPlus::FileDesc fd, size_t limit, void (^handle)(const void *buffer, size_t size)) { - unsigned char buffer[4096]; + UnixPlusPlus::FileDesc::UnixStat st; size_t total = 0; - for (;;) { - size_t size = sizeof(buffer); - if (limit && limit < size) - size = limit; - size_t got = fd.read(buffer, size); - total += got; - if (fd.atEnd()) - break; - handle(buffer, got); - if (limit && (limit -= got) == 0) - break; + unsigned char *buffer = NULL; + + try { + fd.fstat(st); + size_t bufSize = MAX(64 * 1024, st.st_blksize); + buffer = (unsigned char *)valloc(bufSize); + if (!buffer) + return 0; + + for (;;) { + size_t size = bufSize; + if (limit && limit < size) + size = limit; + size_t got = fd.read(buffer, size); + total += got; + if (fd.atEnd()) + break; + handle(buffer, got); + if (limit && (limit -= got) == 0) + break; + } } + catch(...) { + /* don't leak this on error */ + if (buffer) + free(buffer); + throw; + } + + free(buffer); return total; } @@ -104,9 +124,11 @@ size_t hashFileData(const char *path, _Hash *hasher) // Check to see if a certificate contains a particular field, by OID. This works for extensions, // even ones not recognized by the local CL. It does not return any value, only presence. // + +#if TARGET_OS_OSX bool certificateHasField(SecCertificateRef cert, const CSSM_OID &oid); bool certificateHasPolicy(SecCertificateRef cert, const CSSM_OID &policyOid); - +#endif // // Encapsulation of the copyfile(3) API. @@ -139,8 +161,8 @@ class MessageTrace { public: MessageTrace(const char *domain, const char *signature); ~MessageTrace() { ::asl_free(mAsl); } - void add(const char *key, const char *format, ...); - void send(const char *format, ...); + void add(const char *key, const char *format, ...) __attribute__((format(printf,3,4))); + void send(const char *format, ...) __attribute__((format(printf,2,3))); private: aslmsg mAsl; diff --git a/OSX/libsecurity_codesigning/lib/dirscanner.cpp b/OSX/libsecurity_codesigning/lib/dirscanner.cpp index a0cb6361..15140fac 100644 --- a/OSX/libsecurity_codesigning/lib/dirscanner.cpp +++ b/OSX/libsecurity_codesigning/lib/dirscanner.cpp @@ -156,7 +156,7 @@ void DirValidator::validate(const string &root, OSStatus error) else if (rule->flags & required) reqMatched.insert(rule); } - if (reqMatched.size() != mRequireCount) { + if (reqMatched.size() != (unsigned long) mRequireCount) { secinfo("dirval", "matched %lu of %d required rules", reqMatched.size(), mRequireCount); MacOSError::throwMe(error); // not all required rules were matched } diff --git a/OSX/libsecurity_codesigning/lib/diskrep.cpp b/OSX/libsecurity_codesigning/lib/diskrep.cpp index 7663919e..cc6e389a 100644 --- a/OSX/libsecurity_codesigning/lib/diskrep.cpp +++ b/OSX/libsecurity_codesigning/lib/diskrep.cpp @@ -32,8 +32,9 @@ #include "filediskrep.h" #include "bundlediskrep.h" #include "slcrep.h" +#if TARGET_OS_OSX #include "diskimagerep.h" - +#endif namespace Security { namespace CodeSigning { @@ -110,8 +111,10 @@ DiskRep *DiskRep::bestGuess(const char *path, const Context *ctx) AutoFileDesc fd(path, O_RDONLY); if (MachORep::candidate(fd)) return new MachORep(path, ctx); +#if TARGET_OS_OSX if (DiskImageRep::candidate(fd)) return new DiskImageRep(path); +#endif if (DYLDCacheRep::candidate(fd)) return new DYLDCacheRep(path); @@ -197,6 +200,11 @@ size_t DiskRep::signingBase() return 0; // whole file (start at beginning) } +size_t DiskRep::execSegBase(const Architecture *) +{ + return 0; // whole file (start at beginning) +} + CFArrayRef DiskRep::modifiedFiles() { // by default, claim (just) the main executable modified diff --git a/OSX/libsecurity_codesigning/lib/diskrep.h b/OSX/libsecurity_codesigning/lib/diskrep.h index 78239ae9..131f8f68 100644 --- a/OSX/libsecurity_codesigning/lib/diskrep.h +++ b/OSX/libsecurity_codesigning/lib/diskrep.h @@ -70,6 +70,12 @@ public: virtual Universal *mainExecutableImage(); // Mach-O image if Mach-O based [null] virtual size_t signingBase(); // start offset of signed area in main executable [zero] virtual size_t signingLimit() = 0; // size of signed area in main executable + + // The executable segment, if present, denotes which part of the image can be mapped + // into a virtual address space as executable. Not all platforms check this. + virtual size_t execSegBase(const Architecture *arch); // start offset of executable segment in main executable [zero] + virtual size_t execSegLimit(const Architecture *arch) = 0; // size of executable segment in main executable + virtual std::string format() = 0; // human-readable type string virtual CFArrayRef modifiedFiles(); // list of files modified by signing [main execcutable only] virtual UnixPlusPlus::FileDesc &fd() = 0; // a cached file descriptor for main executable file @@ -219,6 +225,8 @@ public: Universal *mainExecutableImage() { return mOriginal->mainExecutableImage(); } size_t signingBase() { return mOriginal->signingBase(); } size_t signingLimit() { return mOriginal->signingLimit(); } + size_t execSegBase(const Architecture *arch) { return mOriginal->execSegBase(arch); } + size_t execSegLimit(const Architecture *arch) { return mOriginal->execSegLimit(arch); } std::string format() { return mOriginal->format(); } CFArrayRef modifiedFiles() { return mOriginal->modifiedFiles(); } UnixPlusPlus::FileDesc &fd() { return mOriginal->fd(); } diff --git a/OSX/libsecurity_codesigning/lib/kerneldiskrep.cpp b/OSX/libsecurity_codesigning/lib/kerneldiskrep.cpp index 91f62435..51fbccaf 100644 --- a/OSX/libsecurity_codesigning/lib/kerneldiskrep.cpp +++ b/OSX/libsecurity_codesigning/lib/kerneldiskrep.cpp @@ -71,6 +71,11 @@ size_t KernelDiskRep::signingLimit() return 0; // don't bother } +size_t KernelDiskRep::execSegLimit(const Architecture *) +{ + return 0; // don't bother +} + string KernelDiskRep::format() { return "system kernel"; diff --git a/OSX/libsecurity_codesigning/lib/kerneldiskrep.h b/OSX/libsecurity_codesigning/lib/kerneldiskrep.h index deb1facf..0bb0619c 100644 --- a/OSX/libsecurity_codesigning/lib/kerneldiskrep.h +++ b/OSX/libsecurity_codesigning/lib/kerneldiskrep.h @@ -51,6 +51,7 @@ public: std::string mainExecutablePath(); CFURLRef copyCanonicalPath(); size_t signingLimit(); + size_t execSegLimit(const Architecture *arch); std::string format(); UnixPlusPlus::FileDesc &fd(); diff --git a/OSX/libsecurity_codesigning/lib/machorep.cpp b/OSX/libsecurity_codesigning/lib/machorep.cpp index 59a256b3..0959b559 100644 --- a/OSX/libsecurity_codesigning/lib/machorep.cpp +++ b/OSX/libsecurity_codesigning/lib/machorep.cpp @@ -29,6 +29,7 @@ #include "reqmaker.h" #include #include +#include @@ -160,6 +161,82 @@ size_t MachORep::signingLimit() return macho->signingExtent(); } +bool MachORep::needsExecSeg(const MachO& macho) { + if (const version_min_command *version = macho.findMinVersion()) { + uint32_t min = UINT32_MAX; + + switch (macho.flip(version->cmd)) { + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_TVOS: + min = (11 << 16 | 0 << 8); + break; + case LC_VERSION_MIN_WATCHOS: + min = (4 << 16 | 0 << 8); + break; + + default: + /* macOS currently does not get this. */ + return false; + } + + if (macho.flip(version->version) >= min) { + return true; + } + } + + return false; +} + +size_t MachORep::execSegBase(const Architecture *arch) +{ + auto_ptr macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture()); + + if (!needsExecSeg(*macho)) { + return 0; + } + + segment_command const * const text_cmd = macho->findSegment("__TEXT"); + + if (text_cmd == NULL) { + return 0; + } + + size_t off = 0; + + if (macho->is64()) { + off = int_cast(reinterpret_cast(text_cmd)->fileoff); + } else { + off = text_cmd->fileoff; + } + + return off; +} + +size_t MachORep::execSegLimit(const Architecture *arch) +{ + auto_ptr macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture()); + + if (!needsExecSeg(*macho)) { + return 0; + } + + segment_command const * const text_cmd = macho->findSegment("__TEXT"); + + if (text_cmd == NULL) { + return 0; + } + + size_t size = 0; + + if (macho->is64()) { + size = int_cast(reinterpret_cast(text_cmd)->filesize); + } else { + size = text_cmd->filesize; + } + + return size; +} + // // We choose the binary identifier for a Mach-O binary as follows: diff --git a/OSX/libsecurity_codesigning/lib/machorep.h b/OSX/libsecurity_codesigning/lib/machorep.h index 7692fde1..d30ba537 100644 --- a/OSX/libsecurity_codesigning/lib/machorep.h +++ b/OSX/libsecurity_codesigning/lib/machorep.h @@ -56,6 +56,8 @@ public: void prepareForSigning(SigningContext &context); size_t signingBase(); size_t signingLimit(); + size_t execSegBase(const Architecture *arch); + size_t execSegLimit(const Architecture *arch); std::string format(); CFDictionaryRef diskRepInformation(); @@ -83,6 +85,8 @@ protected: Requirement *libraryRequirements(const Architecture *arch, const SigningContext &ctx); private: + static bool needsExecSeg(const MachO& macho); + Universal *mExecutable; // cached Mach-O/Universal reference to mainExecutablePath() EmbeddedSignatureBlob *mSigningData; // cached signing data from current architecture }; diff --git a/OSX/libsecurity_codesigning/lib/opaquewhitelist.cpp b/OSX/libsecurity_codesigning/lib/opaquewhitelist.cpp index 483ca40c..ca9a563b 100644 --- a/OSX/libsecurity_codesigning/lib/opaquewhitelist.cpp +++ b/OSX/libsecurity_codesigning/lib/opaquewhitelist.cpp @@ -129,7 +129,7 @@ bool OpaqueWhitelist::contains(SecStaticCodeRef codeRef, SecAssessmentFeedback f trace.add("signature2", "%s", currentHash.c_str()); trace.add("signature3", "%s", opaqueHash.c_str()); trace.add("result", match ? "pass" : "fail"); - trace.add("reason", "%d", reason); + trace.add("reason", "%d", (int)reason); if (!team.empty()) trace.add("teamid", "%s", team.c_str()); if (cfVersion) diff --git a/OSX/libsecurity_codesigning/lib/piddiskrep.cpp b/OSX/libsecurity_codesigning/lib/piddiskrep.cpp index 3b54434a..176fcfb5 100644 --- a/OSX/libsecurity_codesigning/lib/piddiskrep.cpp +++ b/OSX/libsecurity_codesigning/lib/piddiskrep.cpp @@ -167,6 +167,11 @@ size_t PidDiskRep::signingLimit() return 0; } +size_t PidDiskRep::execSegLimit(const Architecture *) +{ + return 0; +} + string PidDiskRep::format() { return "pid diskrep"; diff --git a/OSX/libsecurity_codesigning/lib/piddiskrep.h b/OSX/libsecurity_codesigning/lib/piddiskrep.h index fddb34cf..766a6bda 100644 --- a/OSX/libsecurity_codesigning/lib/piddiskrep.h +++ b/OSX/libsecurity_codesigning/lib/piddiskrep.h @@ -48,6 +48,7 @@ public: std::string mainExecutablePath(); CFURLRef copyCanonicalPath(); size_t signingLimit(); + size_t execSegLimit(const Architecture *arch); std::string format(); UnixPlusPlus::FileDesc &fd(); diff --git a/OSX/libsecurity_codesigning/lib/policyengine.cpp b/OSX/libsecurity_codesigning/lib/policyengine.cpp index 05c44598..1335f687 100644 --- a/OSX/libsecurity_codesigning/lib/policyengine.cpp +++ b/OSX/libsecurity_codesigning/lib/policyengine.cpp @@ -163,6 +163,7 @@ void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, Author SQLite3::int64 latentID = 0; // first (highest priority) disabled matching ID std::string latentLabel; // ... and associated label, if any + secdebug("gk", "evaluateCodeItem type=%d flags=0x%x nested=%d path=%s", type, int(flags), nested, cfString(path).c_str()); while (query.nextRow()) { bool allow = int(query[0]); const char *reqString = query[1]; @@ -174,6 +175,7 @@ void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, Author // const char *filter = query[7]; // const char *remarks = query[8]; + secdebug("gk", "considering rule %d(%s) requirement %s", int(id), label ? label : "UNLABELED", reqString); CFRef requirement; MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref())); switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSBasicValidateOnly | kSecCSCheckGatekeeperArchitectures, requirement)) { @@ -195,6 +197,7 @@ void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, Author } // current rule is first rule (in priority order) that matched. Apply it + secnotice("gk", "rule %d applies - allow=%d", int(id), allow); if (nested && allow) // success, nothing to record return; @@ -240,6 +243,7 @@ void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, Author } // no applicable authority (but signed, perhaps temporarily). Deny by default + secnotice("gk", "rejecting due to lack of matching active rule"); CFRef info; MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); if (flags & kSecAssessmentFlagRequestOrigin) { @@ -269,21 +273,25 @@ void PolicyEngine::adjustValidation(SecStaticCodeRef code) bool PolicyEngine::temporarySigning(SecStaticCodeRef code, AuthorityType type, CFURLRef path, SecAssessmentFlags matchFlags) { - if (matchFlags == 0) { // playback; consult authority table for matches - std::string screen = createWhitelistScreen(code); - SQLite::Statement query(*this, - "SELECT flags FROM authority " - "WHERE type = :type" - " AND NOT flags & :flag" - " AND CASE WHEN filter_unsigned IS NULL THEN remarks = :remarks ELSE filter_unsigned = :screen END"); - query.bind(":type").integer(type); - query.bind(":flag").integer(kAuthorityFlagDefault); - query.bind(":screen") = screen; - query.bind(":remarks") = cfString(path); - if (!query.nextRow()) // guaranteed no matching rule - return false; - matchFlags = SQLite3::int64(query[0]); - } + secnotice("gk", "temporarySigning type=%d matchFlags=0x%x path=%s", type, int(matchFlags), cfString(path).c_str()); + + // see if we have a screened record to take matchFlags from + std::string screen = createWhitelistScreen(code); + SQLite::Statement query(*this, + "SELECT flags FROM authority " + "WHERE type = :type" + " AND NOT flags & :flag" + " AND CASE WHEN filter_unsigned IS NULL THEN remarks = :remarks ELSE filter_unsigned = :screen END"); + query.bind(":type").integer(type); + query.bind(":flag").integer(kAuthorityFlagDefault); + query.bind(":screen") = screen; + query.bind(":remarks") = cfString(path); + secdebug("gk", "match screen=%s", screen.c_str()); + if (query.nextRow()) // got a matching rule + matchFlags = SQLite3::int64(query[0]); + else if (matchFlags == 0) // lazy and no match + return false; + secdebug("gk", "matchFlags found=0x%x", int(matchFlags)); try { // ad-hoc sign the code and attach the signature @@ -302,7 +310,8 @@ bool PolicyEngine::temporarySigning(SecStaticCodeRef code, AuthorityType type, C SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, &dr); CFStringRef drs = NULL; SecRequirementCopyString(dr, kSecCSDefaultFlags, &drs); - + secnotice("gk", "successfully created temporary signature - requirement=%s", cfString(drs).c_str()); + // if we're in GKE recording mode, save that signature and report its location if (SYSPOLICY_RECORDER_MODE_ENABLED()) { int status = recorder_code_unable; // ephemeral signature (not recorded) diff --git a/OSX/libsecurity_codesigning/lib/reqdumper.cpp b/OSX/libsecurity_codesigning/lib/reqdumper.cpp index d1cb94a9..c971f0ff 100644 --- a/OSX/libsecurity_codesigning/lib/reqdumper.cpp +++ b/OSX/libsecurity_codesigning/lib/reqdumper.cpp @@ -25,7 +25,9 @@ // reqdumper - Requirement un-parsing (disassembly) // #include "reqdumper.h" +#if TARGET_OS_OSX #include // OID encoder +#endif #include namespace Security { @@ -199,20 +201,24 @@ void Dumper::expr(SyntaxLevel level) break; case opCertGeneric: print("certificate"); certSlot(); print("["); +#if TARGET_OS_OSX { const unsigned char *data; size_t length; getData(data, length); print("field.%s", CssmOid((unsigned char *)data, length).toOid().c_str()); } +#endif print("]"); match(); break; case opCertPolicy: print("certificate"); certSlot(); print("["); +#if TARGET_OS_OSX { const unsigned char *data; size_t length; getData(data, length); print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str()); } +#endif print("]"); match(); break; case opTrustedCert: @@ -331,7 +337,7 @@ void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false * switch (bestMode) { case isSimple: - print("%.*s", length, data); + print("%.*s", (int)length, data); break; case isPrintable: print("\""); diff --git a/OSX/libsecurity_codesigning/lib/reqdumper.h b/OSX/libsecurity_codesigning/lib/reqdumper.h index ebd9c25c..30793fdc 100644 --- a/OSX/libsecurity_codesigning/lib/reqdumper.h +++ b/OSX/libsecurity_codesigning/lib/reqdumper.h @@ -83,7 +83,7 @@ protected: void certSlot(); // symbolic certificate slot indicator (explicit) void match(); // a match suffix (op + value) - void print(const char *format, ...); + void print(const char *format, ...) __attribute((format(printf,2,3))); private: void printBytes(const Byte *data, size_t length); // just write hex bytes diff --git a/OSX/libsecurity_codesigning/lib/reqinterp.cpp b/OSX/libsecurity_codesigning/lib/reqinterp.cpp index 3215df48..b685802b 100644 --- a/OSX/libsecurity_codesigning/lib/reqinterp.cpp +++ b/OSX/libsecurity_codesigning/lib/reqinterp.cpp @@ -149,6 +149,7 @@ bool Requirement::Interpreter::eval(int depth) Match match(*this); return certFieldValue(key, match, cert); } +#if TARGET_OS_OSX case opCertGeneric: { SecCertificateRef cert = mContext->cert(get()); @@ -163,6 +164,7 @@ bool Requirement::Interpreter::eval(int depth) Match match(*this); return certFieldPolicy(key, match, cert); } +#endif case opTrustedCert: return trustedCert(get()); case opTrustedCerts: @@ -222,6 +224,8 @@ 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) return false; @@ -273,10 +277,11 @@ bool Requirement::Interpreter::certFieldValue(const string &key, const Match &ma // unrecognized key. Fail but do not abort to promote backward compatibility down the road secinfo("csinterp", "cert field notation \"%s\" not understood", key.c_str()); +#endif return false; } - +#if TARGET_OS_OSX bool Requirement::Interpreter::certFieldGeneric(const string &key, const Match &match, SecCertificateRef cert) { // the key is actually a (binary) OID value @@ -300,7 +305,7 @@ bool Requirement::Interpreter::certFieldPolicy(const CssmOid &oid, const Match & { return cert && certificateHasPolicy(cert, oid) && match(kCFBooleanTrue); } - +#endif // // Check the Apple-signed condition @@ -406,12 +411,16 @@ 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 - SHA1 hasher; hasher(certData.Data, certData.Length); +#else + hasher(SecCertificateGetBytePtr(cert), SecCertificateGetLength(cert)); +#endif return hasher.verify(digest); } return false; @@ -469,6 +478,8 @@ bool Requirement::Interpreter::trustedCert(int slot) // SecTrustSettingsResult Requirement::Interpreter::trustSetting(SecCertificateRef cert, bool isAnchor) { + // XXX: Not supported on embedded yet due to lack of supporting API +#if TARGET_OS_OSX // the SPI input is the uppercase hex form of the SHA-1 of the certificate... assert(cert); SHA1::Digest digest; @@ -506,6 +517,9 @@ SecTrustSettingsResult Requirement::Interpreter::trustSetting(SecCertificateRef ::free(errors); MacOSError::throwMe(rc); } +#else + return kSecTrustSettingsResultUnspecified; +#endif } diff --git a/OSX/libsecurity_codesigning/lib/reqinterp.h b/OSX/libsecurity_codesigning/lib/reqinterp.h index fd0188d3..45270409 100644 --- a/OSX/libsecurity_codesigning/lib/reqinterp.h +++ b/OSX/libsecurity_codesigning/lib/reqinterp.h @@ -27,9 +27,12 @@ #ifndef _H_REQINTERP #define _H_REQINTERP -#include +#include "reqreader.h" #include + +#if TARGET_OS_OSX #include // CssmOid +#endif namespace Security { namespace CodeSigning { @@ -69,10 +72,12 @@ protected: bool infoKeyValue(const std::string &key, const Match &match); bool entitlementValue(const std::string &key, const Match &match); bool certFieldValue(const string &key, const Match &match, SecCertificateRef cert); +#if TARGET_OS_OSX bool certFieldGeneric(const string &key, const Match &match, SecCertificateRef cert); bool certFieldGeneric(const CssmOid &oid, const Match &match, SecCertificateRef cert); bool certFieldPolicy(const string &key, const Match &match, SecCertificateRef cert); bool certFieldPolicy(const CssmOid &oid, const Match &match, SecCertificateRef cert); +#endif bool verifyAnchor(SecCertificateRef cert, const unsigned char *digest); bool appleSigned(); bool appleAnchored(); diff --git a/OSX/libsecurity_codesigning/lib/reqmaker.h b/OSX/libsecurity_codesigning/lib/reqmaker.h index 721fc1f3..a3ac0eed 100644 --- a/OSX/libsecurity_codesigning/lib/reqmaker.h +++ b/OSX/libsecurity_codesigning/lib/reqmaker.h @@ -27,7 +27,7 @@ #ifndef _H_REQMAKER #define _H_REQMAKER -#include +#include "requirement.h" namespace Security { namespace CodeSigning { diff --git a/OSX/libsecurity_codesigning/lib/reqreader.cpp b/OSX/libsecurity_codesigning/lib/reqreader.cpp index 63b1e352..bb3d74dd 100644 --- a/OSX/libsecurity_codesigning/lib/reqreader.cpp +++ b/OSX/libsecurity_codesigning/lib/reqreader.cpp @@ -27,7 +27,11 @@ #include "reqreader.h" #include #include + +#if TARGET_OS_OSX #include // for hex encoding +#endif + #include "csutilities.h" namespace Security { diff --git a/OSX/libsecurity_codesigning/lib/reqreader.h b/OSX/libsecurity_codesigning/lib/reqreader.h index b3f4a781..69dc29d0 100644 --- a/OSX/libsecurity_codesigning/lib/reqreader.h +++ b/OSX/libsecurity_codesigning/lib/reqreader.h @@ -27,7 +27,7 @@ #ifndef _H_REQREADER #define _H_REQREADER -#include +#include "requirement.h" #include namespace Security { diff --git a/OSX/libsecurity_codesigning/lib/requirement.cpp b/OSX/libsecurity_codesigning/lib/requirement.cpp index 418c416b..16f5a645 100644 --- a/OSX/libsecurity_codesigning/lib/requirement.cpp +++ b/OSX/libsecurity_codesigning/lib/requirement.cpp @@ -34,7 +34,7 @@ #include #ifdef DEBUGDUMP -#include +#include "reqdumper.h" #endif namespace Security { @@ -141,10 +141,10 @@ const SHA1::Digest &Requirement::testAppleAnchorHash() #endif //TEST_APPLE_ANCHOR - // // Debug dump support // +#if TARGET_OS_OSX #ifdef DEBUGDUMP void Requirement::dump() const @@ -153,6 +153,7 @@ void Requirement::dump() const } #endif //DEBUGDUMP +#endif } // CodeSigning diff --git a/OSX/libsecurity_codesigning/lib/requirement.h b/OSX/libsecurity_codesigning/lib/requirement.h index eb089475..da9175d4 100644 --- a/OSX/libsecurity_codesigning/lib/requirement.h +++ b/OSX/libsecurity_codesigning/lib/requirement.h @@ -84,8 +84,9 @@ public: // canonical (source) names of Requirement types (matched to SecRequirementType in CSCommon.h) static const char *const typeNames[]; - +#if TARGET_OS_OSX IFDUMP(void dump() const); +#endif private: Endian mKind; // expression kind diff --git a/OSX/libsecurity_codesigning/lib/resources.cpp b/OSX/libsecurity_codesigning/lib/resources.cpp index 4c36a387..25ddade7 100644 --- a/OSX/libsecurity_codesigning/lib/resources.cpp +++ b/OSX/libsecurity_codesigning/lib/resources.cpp @@ -260,6 +260,13 @@ ResourceBuilder::Rule *ResourceBuilder::findRule(string path) const } if (!bestRule || rule->weight > bestRule->weight) bestRule = rule; + + +#if TARGET_OS_WATCH +/* rdar://problem/30517969 */ + if (bestRule && bestRule->weight == rule->weight && !(bestRule->flags & omitted) && (rule->flags & omitted)) + bestRule = rule; +#endif } } secinfo("rscan", "choosing %s (%d,0x%x)", diff --git a/OSX/libsecurity_codesigning/lib/signer.cpp b/OSX/libsecurity_codesigning/lib/signer.cpp index e03321cc..fb9e7567 100644 --- a/OSX/libsecurity_codesigning/lib/signer.cpp +++ b/OSX/libsecurity_codesigning/lib/signer.cpp @@ -459,14 +459,18 @@ void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context MacOSError::throwMe(errSecCSBadLVArch); } } - + + bool mainBinary = arch.source.get()->type() == MH_EXECUTE; + arch.ireqs(requirements, rep->defaultRequirements(&arch.architecture, *this), context); if (editor->attribute(writerNoGlobal)) // can't store globally, add per-arch populate(arch); for (auto type = digestAlgorithms().begin(); type != digestAlgorithms().end(); ++type) { arch.eachDigest(^(CodeDirectory::Builder& builder) { populate(builder, arch, arch.ireqs, - arch.source->offset(), arch.source->signingExtent(), unsigned(digestAlgorithms().size()-1)); + arch.source->offset(), arch.source->signingExtent(), + mainBinary, rep->execSegBase(&(arch.architecture)), rep->execSegLimit(&(arch.architecture)), + unsigned(digestAlgorithms().size()-1)); }); } @@ -531,12 +535,16 @@ void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context (new DetachedBlobWriter(*this)) : rep->writer(); CodeDirectorySet cdSet; + for (auto type = digestAlgorithms().begin(); type != digestAlgorithms().end(); ++type) { CodeDirectory::Builder builder(*type); InternalRequirements ireqs; ireqs(requirements, rep->defaultRequirements(NULL, *this), context); populate(*writer); - populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit(), unsigned(digestAlgorithms().size()-1)); + populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit(), + false, // only machOs can currently be main binaries + rep->execSegBase(NULL), rep->execSegLimit(NULL), + unsigned(digestAlgorithms().size()-1)); CodeDirectory *cd = builder.build(); if (!state.mDryRun) @@ -581,7 +589,9 @@ void SecCodeSigner::Signer::populate(DiskRep::Writer &writer) // for the purposes of this call. // void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::Writer &writer, - InternalRequirements &ireqs, size_t offset, size_t length, unsigned alternateDigestCount) + InternalRequirements &ireqs, size_t offset, size_t length, + bool mainBinary, size_t execSegBase, size_t execSegLimit, + unsigned alternateDigestCount) { // fill the CodeDirectory builder.executable(rep->mainExecutablePath(), pagesize, offset, length); @@ -589,6 +599,7 @@ void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::W builder.identifier(identifier); builder.teamID(teamID); builder.platform(state.mPlatform); + builder.execSeg(execSegBase, execSegLimit, mainBinary ? kSecCodeExecSegMainBinary : 0); if (CFRef data = rep->component(cdInfoSlot)) builder.specialSlot(cdInfoSlot, data); @@ -602,6 +613,10 @@ void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::W if (entitlements) { writer.component(cdEntitlementSlot, entitlements); builder.specialSlot(cdEntitlementSlot, entitlements); + + if (mainBinary) { + builder.addExecSegFlags(entitlementsToExecSegFlags(entitlements)); + } } if (CFRef repSpecific = rep->component(cdRepSpecificSlot)) builder.specialSlot(cdRepSpecificSlot, repSpecific); @@ -762,6 +777,49 @@ std::string SecCodeSigner::Signer::uniqueName() const return result; } +bool SecCodeSigner::Signer::booleanEntitlement(CFDictionaryRef entDict, CFStringRef key) { + CFBooleanRef entValue = (CFBooleanRef)CFDictionaryGetValue(entDict, key); + + if (entValue == NULL || CFGetTypeID(entValue) != CFBooleanGetTypeID()) { + return false; + } + + return CFBooleanGetValue(entValue); +} + +uint64_t SecCodeSigner::Signer::entitlementsToExecSegFlags(CFDataRef entitlements) +{ + if (!entitlements) { + return 0; + } + + const EntitlementBlob *blob = reinterpret_cast(CFDataGetBytePtr(entitlements)); + + if (blob == NULL || !blob->validateBlob(CFDataGetLength(entitlements))) { + return 0; + } + + try { + CFRef entDict = blob->entitlements(); + + uint64_t flags = 0; + + flags |= booleanEntitlement(entDict, CFSTR("get-task-allow")) ? kSecCodeExecSegAllowUnsigned : 0; + flags |= booleanEntitlement(entDict, CFSTR("run-unsigned-code")) ? kSecCodeExecSegAllowUnsigned : 0; + flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.cs.debugger")) ? kSecCodeExecSegDebugger : 0; + flags |= booleanEntitlement(entDict, CFSTR("dynamic-codesigning")) ? kSecCodeExecSegJit : 0; + flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.skip-library-validation")) ? kSecCodeExecSegSkipLibraryVal : 0; + flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.amfi.can-load-cdhash")) ? kSecCodeExecSegCanLoadCdHash : 0; + flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.amfi.can-execute-cdhash")) ? kSecCodeExecSegCanExecCdHash : 0; + + return flags; + + } catch (const CommonError &err) { + // Not fatal. + secwarning("failed to parse entitlements: %s", err.what()); + return 0; + } +} } // end namespace CodeSigning } // end namespace Security diff --git a/OSX/libsecurity_codesigning/lib/signer.h b/OSX/libsecurity_codesigning/lib/signer.h index 1e92a9c7..65ea50a5 100644 --- a/OSX/libsecurity_codesigning/lib/signer.h +++ b/OSX/libsecurity_codesigning/lib/signer.h @@ -69,7 +69,10 @@ protected: void populate(DiskRep::Writer &writer); // global void populate(CodeDirectory::Builder &builder, DiskRep::Writer &writer, - InternalRequirements &ireqs, size_t offset, size_t length, unsigned alternateDigestCount); // per-architecture + InternalRequirements &ireqs, + size_t offset, size_t length, + bool mainBinary, size_t execSegBase, size_t execSegLimit, + unsigned alternateDigestCount); // per-architecture CFDataRef signCodeDirectory(const CodeDirectory *cd, CFDataRef hashBag); uint32_t cdTextFlags(std::string text); // convert text CodeDirectory flags @@ -84,6 +87,9 @@ private: void considerTeamID(const PreSigningContext& context); std::vector > topSlots(CodeDirectory::Builder &builder) const; + static bool booleanEntitlement(CFDictionaryRef entDict, CFStringRef key); + static uint64_t entitlementsToExecSegFlags(CFDataRef entitlements); + protected: void buildResources(std::string root, std::string relBase, CFDictionaryRef rules); CFMutableDictionaryRef signNested(const std::string &path, const std::string &relpath); diff --git a/OSX/libsecurity_codesigning/lib/singlediskrep.cpp b/OSX/libsecurity_codesigning/lib/singlediskrep.cpp index 0e63bde8..2c0cbd27 100644 --- a/OSX/libsecurity_codesigning/lib/singlediskrep.cpp +++ b/OSX/libsecurity_codesigning/lib/singlediskrep.cpp @@ -82,6 +82,14 @@ size_t SingleDiskRep::signingLimit() return fd().fileSize(); } +// +// No executable segment in non-machO files. +// +size_t SingleDiskRep::execSegLimit(const Architecture *) +{ + return 0; +} + // // A lazily opened read-only file descriptor for the path. // diff --git a/OSX/libsecurity_codesigning/lib/singlediskrep.h b/OSX/libsecurity_codesigning/lib/singlediskrep.h index 8e9a8df3..4b9169d0 100644 --- a/OSX/libsecurity_codesigning/lib/singlediskrep.h +++ b/OSX/libsecurity_codesigning/lib/singlediskrep.h @@ -50,6 +50,7 @@ public: std::string mainExecutablePath(); // base path CFURLRef copyCanonicalPath(); // base path size_t signingLimit(); // size of file + size_t execSegLimit(const Architecture *arch); // size of executable segment UnixPlusPlus::FileDesc &fd(); // readable fd for this file void flush(); // close cached fd diff --git a/OSX/libsecurity_codesigning/lib/slcrep.cpp b/OSX/libsecurity_codesigning/lib/slcrep.cpp index 8a0ecbd4..602436e3 100644 --- a/OSX/libsecurity_codesigning/lib/slcrep.cpp +++ b/OSX/libsecurity_codesigning/lib/slcrep.cpp @@ -149,10 +149,13 @@ void DYLDCacheRep::Writer::flush() // -// The discretionary additions insert a Scatter vector describing the file's mapping table. +// The discretionary additions insert a Scatter vector describing the file's mapping table, +// and fills out the executable segment. // void DYLDCacheRep::Writer::addDiscretionary(CodeDirectory::Builder &builder) { + bool execSegmentProcessed = false; + unsigned count = rep->mCache.mappingCount(); builder.scatter(count); for (unsigned n = 0; n < count; n++) { @@ -163,6 +166,14 @@ void DYLDCacheRep::Writer::addDiscretionary(CodeDirectory::Builder &builder) assert(dmap.offset() % segmentedPageSize == 0); scatter->count = (uint32_t)(dmap.size() / segmentedPageSize); assert(dmap.size() % segmentedPageSize == 0); + + if (dmap.maxProt() & VM_PROT_EXECUTE) { + if (execSegmentProcessed) { + CSError::throwMe(errSecMultipleExecSegments); + } + + builder.execSeg(dmap.offset(), dmap.limit()-dmap.address(), 0); + } } } diff --git a/OSX/libsecurity_cryptkit/lib/giantIntegers.c b/OSX/libsecurity_cryptkit/lib/giantIntegers.c index 734ab60e..d5a19537 100644 --- a/OSX/libsecurity_cryptkit/lib/giantIntegers.c +++ b/OSX/libsecurity_cryptkit/lib/giantIntegers.c @@ -1047,7 +1047,6 @@ void gshiftleft(int bits, giant g) { if(!size) return; if((size+digits) > (int)g->capacity) { CKRaise("gshiftleft overflow"); - return; } k = size - 1 + digits; // (MSD of result + 1) carry = 0; diff --git a/OSX/libsecurity_cryptkit/lib/platform.h b/OSX/libsecurity_cryptkit/lib/platform.h index 7a9e9a99..4101e4f6 100644 --- a/OSX/libsecurity_cryptkit/lib/platform.h +++ b/OSX/libsecurity_cryptkit/lib/platform.h @@ -48,17 +48,11 @@ extern "C" { #endif #endif /* endian */ -#ifndef NeXT - #define bcopy(s, d, l) memmove(d, s, l) - #define bzero(s, l) memset(s, 0, l) - #define bcmp(s, d, l) memcmp(s, d, l) -#endif - /* * Other platform-dependent functions in platform.c. */ -extern void CKRaise(const char *reason); +extern void CKRaise(const char *reason) __attribute__((noreturn)); /* * Come up with some kind of "really" random int with which to seed the diff --git a/OSX/libsecurity_cssm/lib/cssmkrspi.h b/OSX/libsecurity_cssm/lib/cssmkrspi.h index 5c2cf0f6..741d5578 100644 --- a/OSX/libsecurity_cssm/lib/cssmkrspi.h +++ b/OSX/libsecurity_cssm/lib/cssmkrspi.h @@ -27,6 +27,7 @@ #define _CSSMKRSPI_H_ 1 #include +#include /* CSSM_KRSP_HANDLE */ #ifdef __cplusplus extern "C" { diff --git a/OSX/libsecurity_cssm/lib/cssmspi.h b/OSX/libsecurity_cssm/lib/cssmspi.h index 69765f8a..e91e553e 100644 --- a/OSX/libsecurity_cssm/lib/cssmspi.h +++ b/OSX/libsecurity_cssm/lib/cssmspi.h @@ -27,6 +27,7 @@ #define _CSSMSPI_H_ 1 #include +#include /* CSSM_UPCALLS_PTR */ #ifdef __cplusplus extern "C" { diff --git a/OSX/libsecurity_cssm/lib/eisl.h b/OSX/libsecurity_cssm/lib/eisl.h index fa044731..7c8fa941 100644 --- a/OSX/libsecurity_cssm/lib/eisl.h +++ b/OSX/libsecurity_cssm/lib/eisl.h @@ -216,7 +216,7 @@ EISL_RecycleVerifiedSignatureRoot (ISL_VERIFIED_SIGNATURE_ROOT_PTR Root); /* Certificate Chain Methods */ -const ISL_VERIFIED_CERTIFICATE_CHAIN_PTR +ISL_VERIFIED_CERTIFICATE_CHAIN_PTR EISL_CreateCertificateChainWithCredentialData (const ISL_CONST_DATA RootIssuer, const ISL_CONST_DATA PublicKey, const ISL_CONST_DATA CredentialsImage, diff --git a/OSX/libsecurity_cssm/lib/emmspi.h b/OSX/libsecurity_cssm/lib/emmspi.h index 0981c581..a618be9e 100644 --- a/OSX/libsecurity_cssm/lib/emmspi.h +++ b/OSX/libsecurity_cssm/lib/emmspi.h @@ -27,6 +27,8 @@ #define _EMMSPI_H_ 1 #include +#include /* CSSM_MANAGER_EVENT_NOTIFICATION */ +#include /* CSSM_UPCALLS_PTR */ #ifdef __cplusplus extern "C" { diff --git a/OSX/libsecurity_filedb/lib/AppleDatabase.cpp b/OSX/libsecurity_filedb/lib/AppleDatabase.cpp index 61fca878..60b47123 100644 --- a/OSX/libsecurity_filedb/lib/AppleDatabase.cpp +++ b/OSX/libsecurity_filedb/lib/AppleDatabase.cpp @@ -1687,7 +1687,7 @@ DbModifier::commit() return; try { - secnotice("integrity", "committing to %s", mAtomicFile.path().c_str()); + secinfo("integrity", "committing to %s", mAtomicFile.path().c_str()); WriteSection aHeaderSection(Allocator::standard(), size_t(HeaderSize)); // Set aHeaderSection to the correct size. @@ -2294,40 +2294,6 @@ AppleDatabase::dataDelete(DbContext &inDbContext, { try { - // syslog if it's the .Mac password - CSSM_DB_RECORD_ATTRIBUTE_DATA attrData; - // we have to do this in two phases -- the first to get the record type, and the second to actually read the attributes. Otherwise, we might get - // an exception. - memset(&attrData, 0, sizeof(attrData)); - dataGetFromUniqueRecordId(inDbContext, inUniqueRecord, &attrData, NULL); - - if (attrData.DataRecordType == CSSM_DL_DB_RECORD_GENERIC_PASSWORD) - { - CSSM_DB_ATTRIBUTE_DATA attributes; - - // setup some attributes and see if we are indeed the .Mac password - attributes.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER; - attributes.Info.Label.AttributeID = 'svce'; - attributes.Info.AttributeFormat = 0; - attributes.NumberOfValues = 1; - attributes.Value = NULL; - - attrData.NumberOfAttributes = 1; - attrData.AttributeData = &attributes; - - dataGetFromUniqueRecordId(inDbContext, inUniqueRecord, &attrData, NULL); - - // now check the results - std::string dataString((const char*) attrData.AttributeData[0].Value[0].Data, attrData.AttributeData[0].Value[0].Length); - if (dataString == "iTools") - { - syslog(LOG_WARNING, "Warning: Removed .Me password"); - } - - free(attrData.AttributeData[0].Value[0].Data); - free(attrData.AttributeData[0].Value); - } - StLock _(mWriteLock); Table::Id aTableId; const RecordId aRecordId(parseUniqueRecord(inUniqueRecord, aTableId)); diff --git a/OSX/libsecurity_filedb/lib/AtomicFile.cpp b/OSX/libsecurity_filedb/lib/AtomicFile.cpp index fbfae750..9dd9bbfd 100644 --- a/OSX/libsecurity_filedb/lib/AtomicFile.cpp +++ b/OSX/libsecurity_filedb/lib/AtomicFile.cpp @@ -98,7 +98,7 @@ AtomicFile::performDelete() if (::unlink(mPath.c_str()) != 0) { int error = errno; - secnotice("atomicfile", "unlink %s: %s", mPath.c_str(), strerror(error)); + secinfo("atomicfile", "unlink %s: %s", mPath.c_str(), strerror(error)); if (error == ENOENT) CssmError::throwMe(CSSMERR_DL_DATASTORE_DOESNOT_EXIST); else @@ -121,7 +121,7 @@ AtomicFile::rename(const std::string &inNewPath) if (::rename(path, newPath) != 0) { int error = errno; - secnotice("atomicfile", "rename(%s, %s): %s", path, newPath, strerror(error)); + secinfo("atomicfile", "rename(%s, %s): %s", path, newPath, strerror(error)); UnixError::throwMe(error); } } @@ -140,7 +140,7 @@ AtomicFile::create(mode_t mode) if (fileRef == -1) { int error = errno; - secnotice("atomicfile", "open %s: %s", path, strerror(error)); + secinfo("atomicfile", "open %s: %s", path, strerror(error)); // Do the obvious error code translations here. // @@@ Consider moving these up a level. @@ -338,6 +338,7 @@ AtomicFile::ropen(const char *const name, int flags, mode_t mode) int result = sandbox_check(getpid(), "file-read-data", (sandbox_filter_type) (SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT), name); if (result != 0) { + secdebug("atomicfile", "sandboxing rejected read access to %s", name); return -1; } } @@ -347,6 +348,7 @@ AtomicFile::ropen(const char *const name, int flags, mode_t mode) int result = sandbox_check(getpid(), "file-write-data", (sandbox_filter_type) (SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT), name); if (result != 0) { + secdebug("atomicfile", "sandboxing rejected write access to %s", name); return -1; } } @@ -411,7 +413,7 @@ AtomicBufferedFile::open() const char *path = mPath.c_str(); if (mFileRef >= 0) { - secnotice("atomicfile", "open %s: already open, closing and reopening", path); + secinfo("atomicfile", "open %s: already open, closing and reopening", path); close(); } @@ -446,7 +448,7 @@ AtomicBufferedFile::open() UnixError::throwMe(error); } - secnotice("atomicfile", "%p opened %s: %qd bytes", this, path, mLength); + secinfo("atomicfile", "%p opened %s: %qd bytes", this, path, mLength); return mLength; } @@ -544,7 +546,7 @@ AtomicBufferedFile::close() { if (mFileRef < 0) { - secnotice("atomicfile", "close %s: already closed", mPath.c_str()); + secinfo("atomicfile", "close %s: already closed", mPath.c_str()); } else { @@ -648,7 +650,7 @@ AtomicTempFile::create(mode_t mode) } } - secnotice("atomicfile", "%p created %s", this, path); + secinfo("atomicfile", "%p created %s", this, path); } void diff --git a/OSX/libsecurity_keychain/lib/CertificateRequest.cpp b/OSX/libsecurity_keychain/lib/CertificateRequest.cpp deleted file mode 100644 index 76c1808c..00000000 --- a/OSX/libsecurity_keychain/lib/CertificateRequest.cpp +++ /dev/null @@ -1,858 +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@ - */ - -// -// CertificateRequest.cpp -// -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* one top-level prefs file for all of .mac cert requests */ -#define DOT_MAC_REQ_PREFS "com.apple.security.certreq" - -/* - * Within that dictionary is a set of per-policy dictionaries; the key in the - * top-level prefs for these dictionaries is the raw policy OID data encoded - * as an ASCII string. - * - * Within one per-policy dictionary exists a number of per-user dictionaries, - * with the username key as a string. Note that this user name, the one passed to the - * .mac server, does NOT have to have any relation to the current Unix user name; one - * Unix user can have multiple .mac accounts. - * - * - * Within the per-policy, per user dictionary are these two values, both stored - * as raw data (CFData) blobs. - */ -#define DOT_MAC_REF_ID_KEY "refId" -#define DOT_MAC_CERT_KEY "certificate" - -/* Domain for .mac cert requests */ -#define DOT_MAC_DOMAIN_KEY "domain" -#define DOT_MAC_DOMAIN "mac.com" - -/* Hosts for .mac cert requests */ -#define DOT_MAC_MGMT_HOST "certmgmt" -#define DOT_MAC_INFO_HOST "certinfo" - -/* - * Compare two CSSM_DATAs (or two CSSM_OIDs), return true if identical. - */ -static -bool nssCompareCssmData( - const CSSM_DATA *data1, - const CSSM_DATA *data2) -{ - if((data1 == NULL) || (data1->Data == NULL) || - (data2 == NULL) || (data2->Data == NULL) || - (data1->Length != data2->Length)) { - return false; - } - if(data1->Length != data2->Length) { - return false; - } - if(memcmp(data1->Data, data2->Data, data1->Length) == 0) { - return true; - } - else { - return false; - } -} - -/* any nonzero value means true */ -static bool attrBoolValue( - const SecCertificateRequestAttribute *attr) -{ - if((attr->value.Data != NULL) && - (attr->value.Length != 0) && - (attr->value.Data[0] != 0)) { - return true; - } - else { - return false; - } -} - -static void tokenizeName( - const CSSM_DATA *inName, /* required */ - CSSM_DATA *outName, /* required */ - CSSM_DATA *outDomain) /* optional */ -{ - if (!inName || !outName) return; - CSSM_SIZE idx = 0; - CSSM_SIZE stopIdx = inName->Length; - uint8 *p = inName->Data; - *outName = *inName; - if (outDomain) { - outDomain->Length = idx; - outDomain->Data = p; - } - if (!p) return; - while (idx < stopIdx) { - if (*p++ == '@') { - outName->Length = idx; - if (outDomain) { - outDomain->Length = inName->Length - (idx + 1); - outDomain->Data = p; - } - break; - } - idx++; - } -} - -using namespace KeychainCore; - -CertificateRequest::CertificateRequest(const CSSM_OID &policy, - CSSM_CERT_TYPE certificateType, - CSSM_TP_AUTHORITY_REQUEST_TYPE requestType, - SecKeyRef privateKeyItemRef, - SecKeyRef publicKeyItemRef, - const SecCertificateRequestAttributeList *attributeList, - bool isNew /* = true */) - : mAlloc(Allocator::standard()), - mTP(gGuidAppleDotMacTP), - mCL(gGuidAppleX509CL), - mPolicy(mAlloc, policy.Data, policy.Length), - mCertType(certificateType), - mReqType(requestType), - mPrivKey(NULL), - mPubKey(NULL), - mEstTime(0), - mRefId(mAlloc), - mCertState(isNew ? CRS_New : CRS_Reconstructed), - mCertData(mAlloc), - mUserName(mAlloc), - mPassword(mAlloc), - mHostName(mAlloc), - mDomain(mAlloc), - mDoRenew(false), - mIsAsync(false), - mMutex(Mutex::recursive) -{ - StLock_(mMutex); - certReqDbg("CertificateRequest construct"); - - /* Validate policy OID. */ - if(!(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_IDENTITY, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_SHARED_SERVICES, &policy))) { - certReqDbg("CertificateRequest(): unknown policy oid"); - MacOSError::throwMe(errSecParam); - } - if(privateKeyItemRef) { - mPrivKey = privateKeyItemRef; - CFRetain(mPrivKey); - } - if(publicKeyItemRef) { - mPubKey = publicKeyItemRef; - CFRetain(mPubKey); - } - - /* parse attr array */ - if(attributeList == NULL) { - return; - } - - bool doPendingRequest = false; - for(unsigned dex=0; dexcount; dex++) { - const SecCertificateRequestAttribute *attr = &attributeList->attr[dex]; - - if((attr->oid.Data == NULL) || (attr->value.Data == NULL)) { - MacOSError::throwMe(errSecParam); - } - if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_USERNAME, &attr->oid)) { - CSSM_DATA userName = { 0, NULL }; - CSSM_DATA domainName = { 0, NULL }; - tokenizeName(&attr->value, &userName, &domainName); - if (!domainName.Length || !domainName.Data) { - domainName.Length = strlen(DOT_MAC_DOMAIN); - domainName.Data = (uint8*) DOT_MAC_DOMAIN; - } - mUserName.copy(userName); - mDomain.copy(domainName); - } - else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_PASSWORD, &attr->oid)) { - mPassword.copy(attr->value); - } - else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_HOSTNAME, &attr->oid)) { - mHostName.copy(attr->value); - } - else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_RENEW, &attr->oid)) { - /* - * any nonzero value means true - * FIXME: this is deprecated, Treadstone doesn't allow this. Reject this - * request? Ignore? - */ - mDoRenew = attrBoolValue(attr); - } - else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_ASYNC, &attr->oid)) { - /* any nonzero value means true */ - mIsAsync = attrBoolValue(attr); - } - else if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_VALUE_IS_PENDING, &attr->oid)) { - /* any nonzero value means true */ - doPendingRequest = attrBoolValue(attr); - } - - else { - certReqDbg("CertificateRequest(): unknown name/value oid"); - MacOSError::throwMe(errSecParam); - } - } - if(mCertState == CRS_Reconstructed) { - /* see if we have a refId or maybe even a cert in prefs */ - retrieveResults(); - if(mCertData.data() != NULL) { - mCertState = CRS_HaveCert; - } - else if(mRefId.data() != NULL) { - mCertState = CRS_HaveRefId; - } - else if(doPendingRequest) { - /* ask the server if there's a request pending */ - postPendingRequest(); - /* NOT REACHED - that always throws */ - } - else { - certReqDbg("CertificateRequest(): nothing in prefs"); - /* Nothing found in prefs; nothing to go by */ - MacOSError::throwMe(errSecItemNotFound); - } - } -} - -CertificateRequest::~CertificateRequest() throw() -{ - StLock_(mMutex); - certReqDbg("CertificateRequest destruct"); - - if(mPrivKey) { - CFRelease(mPrivKey); - } - if(mPubKey) { - CFRelease(mPubKey); - } -} - -#pragma mark ----- cert request submit ----- - -void CertificateRequest::submit( - sint32 *estimatedTime) -{ - StLock_(mMutex); - CSSM_DATA &policy = mPolicy.get(); - if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_IDENTITY, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_SHARED_SERVICES, &policy)) { - return submitDotMac(estimatedTime); - } - else { - /* shouldn't be here, we already validated policy in constructor */ - assert(0); - certReqDbg("CertificateRequest::submit(): bad policy"); - MacOSError::throwMe(errSecParam); - } -} - -void CertificateRequest::submitDotMac( - sint32 *estimatedTime) -{ - StLock_(mMutex); - CSSM_RETURN crtn; - CSSM_TP_AUTHORITY_ID tpAuthority; - CSSM_TP_AUTHORITY_ID *tpAuthPtr = NULL; - CSSM_NET_ADDRESS tpNetAddrs; - CSSM_APPLE_DOTMAC_TP_CERT_REQUEST certReq; - CSSM_TP_REQUEST_SET reqSet; - CSSM_CSP_HANDLE cspHand = 0; - CSSM_X509_TYPE_VALUE_PAIR tvp; - CSSM_TP_CALLERAUTH_CONTEXT callerAuth; - CSSM_FIELD policyField; - CSSM_DATA refId = {0, NULL}; - const CSSM_KEY *privKey; - const CSSM_KEY *pubKey; - OSStatus ortn; - - if(mCertState != CRS_New) { - certReqDbg("CertificateRequest: can only submit a new request"); - MacOSError::throwMe(errSecParam); - } - if((mUserName.data() == NULL) || (mPassword.data() == NULL)) { - certReqDbg("CertificateRequest: user name and password required"); - MacOSError::throwMe(errSecParam); - } - - /* get keys and CSP handle in CSSM terms */ - if((mPrivKey == NULL) || (mPubKey == NULL)) { - certReqDbg("CertificateRequest: pub and priv keys required"); - MacOSError::throwMe(errSecParam); - } - ortn = SecKeyGetCSSMKey(mPrivKey, &privKey); - if(ortn) { - MacOSError::throwMe(ortn); - } - ortn = SecKeyGetCSSMKey(mPubKey, &pubKey); - if(ortn) { - MacOSError::throwMe(ortn); - } - ortn = SecKeyGetCSPHandle(mPrivKey, &cspHand); - if(ortn) { - MacOSError::throwMe(ortn); - } - - /* - * CSSM_X509_TYPE_VALUE_PAIR_PTR - one pair for now. - * Caller passes in user name like "johnsmith"; in the CSR, - * we write "johnsmith@mac.com". - */ - tvp.type = CSSMOID_CommonName; - tvp.valueType = BER_TAG_PKIX_UTF8_STRING; - CssmAutoData fullUserName(mAlloc); - size_t nameLen = mUserName.length(); - size_t domainLen = mDomain.length(); - fullUserName.malloc(nameLen + 1 + domainLen); - tvp.value = fullUserName.get(); - memmove(tvp.value.Data, mUserName.data(), nameLen); - memmove(tvp.value.Data + nameLen, "@", 1); - memmove(tvp.value.Data + nameLen + 1, mDomain.data(), domainLen); - - /* Fill in the CSSM_APPLE_DOTMAC_TP_CERT_REQUEST */ - memset(&certReq, 0, sizeof(certReq)); - certReq.version = CSSM_DOT_MAC_TP_REQ_VERSION; - certReq.cspHand = cspHand; - certReq.clHand = mCL->handle(); - certReq.numTypeValuePairs = 1; - certReq.typeValuePairs = &tvp; - certReq.publicKey = const_cast(pubKey); - certReq.privateKey = const_cast(privKey); - certReq.userName = mUserName.get(); - certReq.password = mPassword.get(); - if(mDoRenew) { - certReq.flags |= CSSM_DOTMAC_TP_SIGN_RENEW; - } - /* we don't deal with CSR here, input or output */ - - /* now the rest of the args for CSSM_TP_SubmitCredRequest() */ - reqSet.Requests = &certReq; - reqSet.NumberOfRequests = 1; - policyField.FieldOid = mPolicy; - policyField.FieldValue.Data = NULL; - policyField.FieldValue.Length = 0; - memset(&callerAuth, 0, sizeof(callerAuth)); - callerAuth.Policy.NumberOfPolicyIds = 1; - callerAuth.Policy.PolicyIds = &policyField; - ortn = SecKeyGetCredentials(mPrivKey, - CSSM_ACL_AUTHORIZATION_SIGN, - kSecCredentialTypeDefault, - const_cast(&callerAuth.CallerCredentials)); - if(ortn) { - certReqDbg("CertificateRequest: SecKeyGetCredentials error"); - MacOSError::throwMe(ortn); - } - - CssmAutoData hostName(mAlloc); - tpAuthority.AuthorityCert = NULL; - tpAuthority.AuthorityLocation = &tpNetAddrs; - tpNetAddrs.AddressType = CSSM_ADDR_NAME; - if(mHostName.data() != NULL) { - tpNetAddrs.Address = mHostName.get(); - } else { - unsigned hostLen = strlen(DOT_MAC_MGMT_HOST); - hostName.malloc(hostLen + 1 + domainLen); - tpNetAddrs.Address = hostName.get(); - memmove(tpNetAddrs.Address.Data, DOT_MAC_MGMT_HOST, hostLen); - memmove(tpNetAddrs.Address.Data + hostLen, ".", 1); - memmove(tpNetAddrs.Address.Data + hostLen + 1, mDomain.data(), domainLen); - } - tpAuthPtr = &tpAuthority; - - /* go */ - crtn = CSSM_TP_SubmitCredRequest(mTP->handle(), - tpAuthPtr, - CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, - &reqSet, - &callerAuth, - &mEstTime, - &refId); // CSSM_DATA_PTR ReferenceIdentifier - - /* handle return, store results */ - switch(crtn) { - case CSSM_OK: - /* refID is a cert, we have to store it in prefs for later retrieval. */ - certReqDbg("submitDotMac: full success, storing cert"); - if(!mIsAsync) { - /* store in prefs if not running in async mode */ - ortn = storeResults(NULL, &refId); - if(ortn) { - crtn = ortn; - } - } - /* but keep a local copy too */ - mCertData.copy(refId); - mCertState = CRS_HaveCert; - if(estimatedTime) { - /* it's ready right now */ - *estimatedTime = 0; - } - break; - - case CSSMERR_APPLE_DOTMAC_REQ_QUEUED: - /* refID is the blob we use in CSSM_TP_RetrieveCredResult() */ - certReqDbg("submitDotMac: queued, storing refId"); - mRefId.copy(refId); - /* return success - this crtn is not visible at API */ - crtn = CSSM_OK; - if(!mIsAsync) { - /* store in prefs if not running in async mode */ - ortn = storeResults(&refId, NULL); - if(ortn) { - crtn = ortn; - } - } - mCertState = CRS_HaveRefId; - if(estimatedTime) { - *estimatedTime = mEstTime; - } - break; - - case CSSMERR_APPLE_DOTMAC_REQ_REDIRECT: - /* refID is a URL, caller obtains via getReturnData() */ - certReqDbg("submitDotMac: redirect"); - mRefId.copy(refId); - mCertState = CRS_HaveOtherData; - break; - - default: - /* all others are fatal errors, thrown below */ - break; - } - if(refId.Data) { - /* mallocd on our behalf by TP */ - free(refId.Data); - } - if(crtn) { - CssmError::throwMe(crtn); - } -} - -#pragma mark ----- cert request get result ----- - -void CertificateRequest::getResult( - sint32 *estimatedTime, // optional - CssmData &certData) -{ - StLock_(mMutex); - CSSM_DATA &policy = mPolicy.get(); - if(nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_IDENTITY, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_SIGN, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_EMAIL_ENCRYPT, &policy) || - nssCompareCssmData(&CSSMOID_DOTMAC_CERT_REQ_SHARED_SERVICES, &policy)) { - return getResultDotMac(estimatedTime, certData); - } - else { - /* shouldn't be here, we already validated policy in constructor */ - assert(0); - certReqDbg("CertificateRequest::getResult(): bad policy"); - MacOSError::throwMe(errSecParam); - } -} - -void CertificateRequest::getResultDotMac( - sint32 *estimatedTime, // optional - CssmData &certData) -{ - StLock_(mMutex); - switch(mCertState) { - case CRS_HaveCert: - /* trivial case, we already have what caller is looking for */ - certReqDbg("getResultDotMac: have the cert right now"); - assert(mCertData.data() != NULL); - certData = mCertData.get(); - if(estimatedTime) { - *estimatedTime = 0; - } - break; - case CRS_HaveRefId: - { - /* ping the server */ - certReqDbg("getResultDotMac: CRS_HaveRefId; polling server"); - assert(mRefId.data() != NULL); - CSSM_BOOL ConfirmationRequired; - CSSM_TP_RESULT_SET_PTR resultSet = NULL; - CSSM_RETURN crtn; - - crtn = CSSM_TP_RetrieveCredResult(mTP->handle(), - &mRefId.get(), - NULL, // CallerAuthCredentials - &mEstTime, - &ConfirmationRequired, - &resultSet); - switch(crtn) { - case CSSM_OK: - break; - case CSSMERR_TP_CERT_NOT_VALID_YET: - /* - * By convention, this means "not ready yet". - * The dot mac server does not have a way of telling us the - * estimated time on a straight lookup like this (we only get - * an estimated completion time on the initial request), so we - * fake it. - */ - certReqDbg("getResultDotMac: polled server, not ready yet"); - if(estimatedTime) { - *estimatedTime = (mEstTime) ? mEstTime : 1; - } - MacOSError::throwMe(CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING); - default: - certReqDbg("CSSM_TP_RetrieveCredResult error"); - CssmError::throwMe(crtn); - } - if(resultSet == NULL) { - certReqDbg("***CSSM_TP_RetrieveCredResult OK, but no result set"); - MacOSError::throwMe(errSecInternalComponent); - } - if(resultSet->NumberOfResults != 1) { - certReqDbg("***CSSM_TP_RetrieveCredResult OK, NumberOfResults (%lu)", - (unsigned long)resultSet->NumberOfResults); - MacOSError::throwMe(errSecInternalComponent); - } - if(resultSet->Results == NULL) { - certReqDbg("***CSSM_TP_RetrieveCredResult OK, but empty result set"); - MacOSError::throwMe(errSecInternalComponent); - } - certReqDbg("getResultDotMac: polled server, SUCCESS"); - CSSM_DATA_PTR result = (CSSM_DATA_PTR)resultSet->Results; - if(result->Data == NULL) { - certReqDbg("***CSSM_TP_RetrieveCredResult OK, but empty result"); - MacOSError::throwMe(errSecInternalComponent); - } - mCertData.copy(*result); - certData = mCertData.get(); - mCertState = CRS_HaveCert; - if(estimatedTime) { - *estimatedTime = 0; - } - - /* - * Free the stuff allocated on our behalf by TP. - * FIXME - are we sure CssmClient is using alloc, free, etc.? - */ - free(result->Data); - free(result); - free(resultSet); - break; - } - default: - /* what do we do with this? */ - certReqDbg("CertificateRequest::getResultDotMac(): bad state"); - MacOSError::throwMe(errSecInternalComponent); - } - - /* - * One more thing: once we pass a cert back to caller, we erase - * the record of this transaction from prefs. - */ - assert(mCertData.data() != NULL); - assert(mCertData.data() == certData.Data); - removeResults(); -} - -/* - * Obtain policy/error specific return data blob. We own the data, it's - * not copied. - */ -void CertificateRequest::getReturnData( - CssmData &rtnData) -{ - StLock_(mMutex); - rtnData = mRefId.get(); -} - -#pragma mark ----- preferences support ----- - -/* Current user as CFString, for use as key in per-policy dictionary */ -CFStringRef CertificateRequest::createUserKey() -{ - StLock_(mMutex); - return CFStringCreateWithBytes(NULL, (UInt8 *)mUserName.data(), mUserName.length(), - kCFStringEncodingUTF8, false); -} - -#define MAX_OID_LEN 2048 // way big... */ - -/* current policy as CFString, for use as key in prefs dictionary */ -CFStringRef CertificateRequest::createPolicyKey() -{ - StLock_(mMutex); - char oidstr[MAX_OID_LEN]; - unsigned char *inp = (unsigned char *)mPolicy.data(); - char *outp = oidstr; - CFIndex len = mPolicy.length(); - for(CFIndex dex=0; dex_(mMutex); - assert(mPolicy.data() != NULL); - assert(mUserName.data() != NULL); - assert(mDomain.data() != NULL); - - bool deleteEntry = ((refId == NULL) && (certData == NULL)); - - /* get a mutable copy of the existing prefs, or a fresh empty one */ - MutableDictionary *prefsDict = MutableDictionary::CreateMutableDictionary(DOT_MAC_REQ_PREFS, Dictionary::US_User); - if (prefsDict == NULL) - { - prefsDict = new MutableDictionary(); - } - - /* get a mutable copy of the dictionary for this policy, or a fresh empty one */ - CFStringRef policyKey = createPolicyKey(); - MutableDictionary *policyDict = prefsDict->copyMutableDictValue(policyKey); - - CFStringRef userKey = createUserKey(); - if(deleteEntry) { - /* remove user dictionary from this policy dictionary */ - policyDict->removeValue(userKey); - } - else { - /* get a mutable copy of the dictionary for this user, or a fresh empty one */ - MutableDictionary *userDict = policyDict->copyMutableDictValue(userKey); - - CFStringRef domainKey = CFStringCreateWithBytes(NULL, (UInt8 *)mDomain.data(), mDomain.length(), kCFStringEncodingUTF8, false); - userDict->setValue(CFSTR(DOT_MAC_DOMAIN_KEY), domainKey); - CFRelease(domainKey); - - /* write refId and/or cert --> user dictionary */ - if(refId) { - userDict->setDataValue(CFSTR(DOT_MAC_REF_ID_KEY), refId->Data, refId->Length); - } - if(certData) { - userDict->setDataValue(CFSTR(DOT_MAC_CERT_KEY), certData->Data, certData->Length); - } - - /* new user dictionary --> policy dictionary */ - policyDict->setValue(userKey, userDict->dict()); - delete userDict; - } - CFRelease(userKey); - - /* new policy dictionary to prefs dictionary, or nuke it */ - if(policyDict->count() == 0) { - prefsDict->removeValue(policyKey); - } - else { - prefsDict->setValue(policyKey, policyDict->dict()); - } - CFRelease(policyKey); - delete policyDict; - - /* prefs --> disk */ - OSStatus ortn = errSecSuccess; - if(!prefsDict->writePlistToPrefs(DOT_MAC_REQ_PREFS, Dictionary::US_User)) { - certReqDbg("storeResults: error writing prefs to disk"); - ortn = errSecIO; - } - delete prefsDict; - return ortn; -} - -/* - * Attempt to fetch mCertData or mRefId from preferences. - */ -void CertificateRequest::retrieveResults() -{ - StLock_(mMutex); - assert(mPolicy.data() != NULL); - assert(mUserName.data() != NULL); - - /* get the .mac cert prefs as a dictionary */ - Dictionary *pd = Dictionary::CreateDictionary(DOT_MAC_REQ_PREFS, Dictionary::US_User); - if (pd == NULL) - { - certReqDbg("retrieveResults: no prefs found"); - return; - } - - auto_ptr prefsDict(pd); - - /* get dictionary for current policy */ - CFStringRef policyKey = createPolicyKey(); - Dictionary *policyDict = prefsDict->copyDictValue(policyKey); - CFRelease(policyKey); - if(policyDict != NULL) { - /* dictionary for user */ - CFStringRef userKey = createUserKey(); - Dictionary *userDict = policyDict->copyDictValue(userKey); - if(userDict != NULL) { - /* is there a cert in there? */ - CFDataRef val = userDict->getDataValue(CFSTR(DOT_MAC_CERT_KEY)); - if(val) { - mCertData.copy(CFDataGetBytePtr(val), CFDataGetLength(val)); - } - - /* how about refId? */ - val = userDict->getDataValue(CFSTR(DOT_MAC_REF_ID_KEY)); - if(val) { - mRefId.copy(CFDataGetBytePtr(val), CFDataGetLength(val)); - } - delete userDict; - } - CFRelease(userKey); - delete policyDict; - } -} - -/* - * Remove all trace of current policy/user. Called when we successfully transferred - * the cert back to caller. - */ -void CertificateRequest::removeResults() -{ - StLock_(mMutex); - assert(mPolicy.data() != NULL); - assert(mUserName.data() != NULL); - storeResults(NULL, NULL); -} - -/* - * Have the TP ping the server to see of there's a request pending for the current - * user. Always throws: either - * CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING -- request pending - * CSSMERR_APPLE_DOTMAC_NO_REQ_PENDING -- no request pending - * errSecParam -- no user, no password - * other gross errors, e.g. errSecIO for server connection failure - * - * The distinguishing features about this TP request are: - * - * policy OID = CSSMOID_DOTMAC_CERT_REQ_{IDENTITY,EMAIL_SIGN,EMAIL_ENCRYPT,SHARED_SERVICES} - * CSSM_TP_AUTHORITY_REQUEST_TYPE = CSSM_TP_AUTHORITY_REQUEST_CERTLOOKUP - * CSSM_APPLE_DOTMAC_TP_CERT_REQUEST.flags = CSSM_DOTMAC_TP_IS_REQ_PENDING - * must have userName and password - * hostname optional as usual - */ -void CertificateRequest::postPendingRequest() -{ - StLock_(mMutex); - CSSM_RETURN crtn; - CSSM_TP_AUTHORITY_ID tpAuthority; - CSSM_TP_AUTHORITY_ID *tpAuthPtr = NULL; - CSSM_NET_ADDRESS tpNetAddrs; - CSSM_APPLE_DOTMAC_TP_CERT_REQUEST certReq; - CSSM_TP_REQUEST_SET reqSet; - CSSM_TP_CALLERAUTH_CONTEXT callerAuth; - CSSM_FIELD policyField; - CSSM_DATA refId = {0, NULL}; - - assert(mCertState == CRS_Reconstructed); - if((mUserName.data() == NULL) || (mPassword.data() == NULL)) { - certReqDbg("postPendingRequest: user name and password required"); - MacOSError::throwMe(errSecParam); - } - - /* Fill in the CSSM_APPLE_DOTMAC_TP_CERT_REQUEST */ - memset(&certReq, 0, sizeof(certReq)); - certReq.version = CSSM_DOT_MAC_TP_REQ_VERSION; - certReq.userName = mUserName.get(); - certReq.password = mPassword.get(); - certReq.flags = CSSM_DOTMAC_TP_IS_REQ_PENDING; - - /* now the rest of the args for CSSM_TP_SubmitCredRequest() */ - reqSet.Requests = &certReq; - reqSet.NumberOfRequests = 1; - /* - * This OID actually doesn't matter - right? This RPC doesn't know about - * which request we seek... - */ - policyField.FieldOid = mPolicy; - policyField.FieldValue.Data = NULL; - policyField.FieldValue.Length = 0; - memset(&callerAuth, 0, sizeof(callerAuth)); - callerAuth.Policy.NumberOfPolicyIds = 1; - callerAuth.Policy.PolicyIds = &policyField; - /* no other creds here */ - - if(mHostName.data() != NULL) { - tpAuthority.AuthorityCert = NULL; - tpAuthority.AuthorityLocation = &tpNetAddrs; - tpNetAddrs.AddressType = CSSM_ADDR_NAME; - tpNetAddrs.Address = mHostName.get(); - tpAuthPtr = &tpAuthority; - } - - /* go */ - crtn = CSSM_TP_SubmitCredRequest(mTP->handle(), - tpAuthPtr, - CSSM_TP_AUTHORITY_REQUEST_CERTLOOKUP, - &reqSet, - &callerAuth, - &mEstTime, - &refId); // CSSM_DATA_PTR ReferenceIdentifier - - if(refId.Data) { - /* shouldn't be any but just in case.... */ - free(refId.Data); - } - switch(crtn) { - case CSSMERR_APPLE_DOTMAC_REQ_IS_PENDING: - certReqDbg("postPendingRequest: REQ_IS_PENDING"); - break; - case CSSMERR_APPLE_DOTMAC_NO_REQ_PENDING: - certReqDbg("postPendingRequest: NO_REQ_PENDING"); - break; - case CSSM_OK: - /* should never happen */ - certReqDbg("postPendingRequest: unexpected success!"); - crtn = errSecInternalComponent; - break; - default: - certReqDbg("postPendingRequest: unexpected rtn %lu", (unsigned long)crtn); - break; - } - CssmError::throwMe(crtn); -} - diff --git a/OSX/libsecurity_keychain/lib/CertificateRequest.h b/OSX/libsecurity_keychain/lib/CertificateRequest.h deleted file mode 100644 index 144aae80..00000000 --- a/OSX/libsecurity_keychain/lib/CertificateRequest.h +++ /dev/null @@ -1,154 +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@ - */ - -// -// CertificateRequest.h -// -#ifndef _SECURITY_CERTIFICATEREQUEST_H_ -#define _SECURITY_CERTIFICATEREQUEST_H_ - -#include -#include -#include "SecCFTypes.h" -#include -#include -#include -#include -#include -#include - -#define certReqDbg(args...) secinfo("certReq", ## args) - -namespace Security -{ - -namespace KeychainCore -{ - -class CertificateRequest : public SecCFObject -{ - NOCOPY(CertificateRequest) -public: - SECCFFUNCTIONS(CertificateRequest, SecCertificateRequestRef, errSecInvalidItemRef, gTypes().CertificateRequest) - - CertificateRequest(const CSSM_OID &policy, - CSSM_CERT_TYPE certificateType, - CSSM_TP_AUTHORITY_REQUEST_TYPE requestType, - SecKeyRef privateKeyItemRef, // optional - SecKeyRef publicKeyItemRef, // optional - const SecCertificateRequestAttributeList *attributeList, - /* - * true when called from SecCertificateRequestCreate, cooking up a new - * request from scratch - * false when called from SecCertificateFindRequest, recomnstructing - * a request in progress - */ - bool isNew = true); - - virtual ~CertificateRequest() throw(); - - void submit( - sint32 *estimatedTime); - void getResult( - sint32 *estimatedTime, // optional - CssmData &certData); - - /* - * Obtain policy/error specific return data blob. We own the data, it's - * not copied. - */ - void getReturnData( - CssmData &rtnData); - - CSSM_CERT_TYPE certType() { return mCertType; } - CSSM_TP_AUTHORITY_REQUEST_TYPE reqType() { return mReqType; } - -private: - void submitDotMac( - sint32 *estimatedTime); - void getResultDotMac( - sint32 *estimatedTime, // optional - CssmData &certData); - void postPendingRequest(); - - /* preferences support */ - CFStringRef createUserKey(); - CFStringRef createPolicyKey(); - CFDictionaryRef getPolicyDictionary( - CFDictionaryRef prefsDict); - CFDictionaryRef getUserDictionary( - CFDictionaryRef policyDict); - - /* - * Preferences storage and retrieval. - * Both assume valid mPolicy and mUserName. storeResults stores the - * specified data; retrieveResults retrieves whatever is found in the - * prefs dictionary and restores to mRefId or mCert as appropriate. - */ - OSStatus storeResults( - const CSSM_DATA *refId, // optional, for queued requests - const CSSM_DATA *certDat); // optional, for immediate completion - void retrieveResults(); - void removeResults(); - - typedef enum { - CRS_New = 0, // created via SecCertificateRequestCreate - CRS_Reconstructed, // created via SecCertificateFindRequest - CRS_HaveCert, // completed request one way or another, have a good cert - CRS_HaveRefId, // submitted request, have RefId for later retrieval - CRS_HaveOtherData // submitted request, have other data in mRefId - } CertReqState; - - Allocator &mAlloc; - CssmClient::TP mTP; - CssmClient::CL mCL; - CssmAutoData mPolicy; /* i.e., "CssmAutoOid" */ - CSSM_CERT_TYPE mCertType; - CSSM_TP_AUTHORITY_REQUEST_TYPE mReqType; - SecKeyRef mPrivKey; - SecKeyRef mPubKey; - sint32 mEstTime; - CssmAutoData mRefId; /* returned from SubmitCredRequest() */ - CertReqState mCertState; - CssmAutoData mCertData; - - /* - * The incoming SecCertificateRequestAttributeList oid/value pairs - * map to these: - */ - CssmAutoData mUserName; - CssmAutoData mPassword; /* optional (lookup doesn't use it) */ - CssmAutoData mHostName; /* optional */ - CssmAutoData mDomain; /* optional */ - bool mDoRenew; - bool mIsAsync; /* true means no persistent state - * stored in user prefs; default - * is false */ - Mutex mMutex; -}; - -} // end namespace KeychainCore - -} // end namespace Security - -#endif // !_SECURITY_CERTIFICATEREQUEST_H_ diff --git a/OSX/libsecurity_keychain/lib/DLDBListCFPref.cpp b/OSX/libsecurity_keychain/lib/DLDBListCFPref.cpp index ecef3fbe..3cd84cc4 100644 --- a/OSX/libsecurity_keychain/lib/DLDBListCFPref.cpp +++ b/OSX/libsecurity_keychain/lib/DLDBListCFPref.cpp @@ -307,7 +307,7 @@ DLDbListCFPref::writePropertyList() // The prefs file should at least be made readable by user/group/other and writable by the owner. // Change from euid to ruid if needed for the duration of the new prefs file creat. - mode_t mode = 0666; + mode_t mode = 0644; changeIdentity(UNPRIV); int fd = open(mPrefsPath.c_str(), O_WRONLY|O_CREAT|O_TRUNC, mode); changeIdentity(PRIV); @@ -342,7 +342,7 @@ DLDbListCFPref::testAndFixPropertyList() { char *prefsPath = (char *)mPrefsPath.c_str(); - int fd1, fd2, retval; + int fd1, retval; struct stat stbuf; if((fd1 = open(prefsPath, O_RDONLY)) < 0) { @@ -355,20 +355,27 @@ DLDbListCFPref::testAndFixPropertyList() if(stbuf.st_uid != getuid()) { char tempfile[MAXPATHLEN+1]; - snprintf(tempfile, MAXPATHLEN, "%s.XXXXX", prefsPath); - mktemp(tempfile); - changeIdentity(UNPRIV); - if((fd2 = open(tempfile, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) { - retval = -1; + changeIdentity(UNPRIV); + + snprintf(tempfile, MAXPATHLEN, "%s.XXXXXX", prefsPath); + int fd2 = mkstemp(tempfile); + if (fd2 < 0 || ::fchmod(fd2, 0644) != 0) { + ::unlink(tempfile); + retval = -1; } else { copyfile_state_t s = copyfile_state_alloc(); retval = fcopyfile(fd1, fd2, s, COPYFILE_DATA); copyfile_state_free(s); - if(!retval) retval = ::unlink(prefsPath); - if(!retval) retval = ::rename(tempfile, prefsPath); + if (retval) { + ::unlink(tempfile); + } else { + retval = ::unlink(prefsPath); + if(!retval) retval = ::rename(tempfile, prefsPath); + } } changeIdentity(PRIV); - close(fd2); + if (fd2 >= 0) + close(fd2); } close(fd1); return retval; diff --git a/OSX/libsecurity_keychain/lib/Item.cpp b/OSX/libsecurity_keychain/lib/Item.cpp index dad801c5..ff064c1a 100644 --- a/OSX/libsecurity_keychain/lib/Item.cpp +++ b/OSX/libsecurity_keychain/lib/Item.cpp @@ -275,7 +275,7 @@ void ItemImpl::fillDbAttributesFromSchema(DbAttributes& dbAttributes, CSSM_DB_RE SecKeychainAttributeInfo* infos; keychain->getAttributeInfoForItemID(recordType, &infos); - secnotice("integrity", "filling %u attributes for type %u", (unsigned int)infos->count, recordType); + secinfo("integrity", "filling %u attributes for type %u", (unsigned int)infos->count, recordType); for (uint32 i = 0; i < infos->count; i++) { CSSM_DB_ATTRIBUTE_INFO info; @@ -293,7 +293,7 @@ void ItemImpl::fillDbAttributesFromSchema(DbAttributes& dbAttributes, CSSM_DB_RE DbAttributes* ItemImpl::getCurrentAttributes() { DbAttributes* dbAttributes; - secnotice("integrity", "getting current attributes..."); + secinfo("integrity", "getting current attributes..."); if(mUniqueId.get()) { // If we have a unique id, there's an item in the database backing us. Ask for its attributes. @@ -303,7 +303,7 @@ DbAttributes* ItemImpl::getCurrentAttributes() { // and fold in any updates. if(mDbAttributes.get()) { - secnotice("integrity", "adding %d attributes from mDbAttributes", mDbAttributes->size()); + secinfo("integrity", "adding %d attributes from mDbAttributes", mDbAttributes->size()); dbAttributes->updateWithDbAttributes(&(*mDbAttributes.get())); } } else if (mDbAttributes.get()) { @@ -335,7 +335,7 @@ void ItemImpl::encodeAttributesFromDictionary(CssmOwnedData &attributeBlob, DbAt CFRef attributes; attributes.take(CFDictionaryCreateMutable(NULL, dbAttributes->size(), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - secnotice("integrity", "looking at %d attributes", dbAttributes->size()); + secinfo("integrity", "looking at %d attributes", dbAttributes->size()); // TODO: include record type and semantic information? for(int i = 0; i < dbAttributes->size(); i++) { @@ -461,7 +461,7 @@ void ItemImpl::computeDigestFromDictionary(CssmOwnedData &sha2, DbAttributes* db sha2.length(CC_SHA256_DIGEST_LENGTH); CC_SHA256(attributeBlob.get().data(), static_cast(attributeBlob.get().length()), sha2); - secnotice("integrity", "finished: %s", sha2.get().toHex().c_str()); + secinfo("integrity", "finished: %s", sha2.get().toHex().c_str()); } catch (MacOSError mose) { secnotice("integrity", "MacOSError: %d", (int)mose.osStatus()); } catch (...) { @@ -471,7 +471,7 @@ void ItemImpl::computeDigestFromDictionary(CssmOwnedData &sha2, DbAttributes* db void ItemImpl::addIntegrity(Access &access, bool force) { if(!force && (!mKeychain || !mKeychain->hasIntegrityProtection())) { - secnotice("integrity", "skipping integrity add due to keychain version\n"); + secinfo("integrity", "skipping integrity add due to keychain version\n"); return; } @@ -486,7 +486,7 @@ void ItemImpl::addIntegrity(Access &access, bool force) { if(acls.size() >= 1) { // Use the existing ACL acl = acls[0]; - secnotice("integrity", "previous integrity acl exists; setting integrity"); + secinfo("integrity", "previous integrity acl exists; setting integrity"); acl->setIntegrity(digest.get()); // Delete all extra ACLs @@ -566,7 +566,7 @@ bool ItemImpl::checkIntegrity() { } if(!mKeychain || !mKeychain->hasIntegrityProtection()) { - secnotice("integrity", "skipping integrity check due to keychain version"); + secinfo("integrity", "skipping integrity check due to keychain version"); return true; } @@ -583,7 +583,7 @@ bool ItemImpl::checkIntegrity() { bool ItemImpl::checkIntegrity(AclBearer& aclBearer) { if(!mKeychain || !mKeychain->hasIntegrityProtection()) { - secnotice("integrity", "skipping integrity check due to keychain version"); + secinfo("integrity", "skipping integrity check due to keychain version"); return true; } @@ -731,6 +731,7 @@ PrimaryKey ItemImpl::addWithCopyInfo (Keychain &keychain, bool isCopy) try { mKeychain = keychain; + StLock_(*(mKeychain->getKeychainMutex())); // must hold this mutex before calling db->insert Db db(keychain->database()); if (mDoNotEncrypt) @@ -818,6 +819,9 @@ ItemImpl::update() if (!isModified()) return; + // Hold this before modifying the db below + StLock__(*(mKeychain->getKeychainMutex())); + CSSM_DB_RECORDTYPE aRecordType = recordType(); KeychainSchema schema = mKeychain->keychainSchema(); @@ -896,7 +900,7 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer // If there aren't any attributes, make up some blank ones. if (!mDbAttributes.get()) { - secnotice("integrity", "making new dbattributes"); + secinfo("integrity", "making new dbattributes"); mDbAttributes.reset(new DbAttributes()); mDbAttributes->recordType(mPrimaryKey->recordType()); } @@ -914,7 +918,7 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer if ((!access) && (haveOldUniqueId)) { // Copy the ACL from the old group. - secnotice("integrity", "copying old ACL"); + secinfo("integrity", "copying old ACL"); access = new Access(*(ssGroup)); // We can't copy these over to the new item; they're going to be reset. @@ -922,27 +926,13 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer access->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID); access->removeAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY); } else if (!access) { - secnotice("integrity", "setting up new ACL"); + secinfo("integrity", "setting up new ACL"); // create default access controls for the new item CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecLabelItemAttr)); string printName = data ? CssmData::overlay(data->Value[0]).toString() : "keychain item"; access = new Access(printName); - - // special case for "iTools" password - allow anyone to decrypt the item - if (recordType == CSSM_DL_DB_RECORD_GENERIC_PASSWORD) - { - CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecServiceItemAttr)); - if (data && data->Value[0].Length == 6 && !memcmp("iTools", data->Value[0].Data, 6)) - { - typedef vector > AclSet; - AclSet acls; - access->findAclsForRight(CSSM_ACL_AUTHORIZATION_DECRYPT, acls); - for (AclSet::const_iterator it = acls.begin(); it != acls.end(); it++) - (*it)->form(ACL::allowAllForm); - } - } } else { - secnotice("integrity", "passed an Access, use it"); + secinfo("integrity", "passed an Access, use it"); // Access is non-null. Do nothing. } @@ -962,17 +952,17 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer maker.initialOwner(prototype, nullCred); if(saveToNewSSGroup) { - secnotice("integrity", "saving to a new SSGroup"); + secinfo("integrity", "saving to a new SSGroup"); // If we're updating an item, it has an old group and possibly an // old mUniqueId. Delete these from the database, so we can insert // new ones. if(haveOldUniqueId) { - secnotice("integrity", "deleting old mUniqueId"); + secinfo("integrity", "deleting old mUniqueId"); mUniqueId->deleteRecord(); mUniqueId.release(); } else { - secnotice("integrity", "no old mUniqueId"); + secinfo("integrity", "no old mUniqueId"); } // Create a new SSGroup with temporary access controls @@ -1016,7 +1006,7 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer } } else { // Modify the old SSGroup - secnotice("integrity", "modifying the existing SSGroup"); + secinfo("integrity", "modifying the existing SSGroup"); try { doChange(keychain, recordType, ^{ @@ -1088,7 +1078,7 @@ ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryC // Only check for corrupt items if the keychain supports them if((!kc) || !kc->hasIntegrityProtection()) { - secnotice("integrity", "skipping integrity check for corrupt items due to keychain support"); + secinfo("integrity", "skipping integrity check for corrupt items due to keychain support"); throw; } else { primaryKeyAttrs.reset(getCurrentAttributes()); @@ -1109,7 +1099,7 @@ ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryC // Our keychain doesn't know about any item with this primary key, so maybe // we have a corrupt item in the database. Let's check. - secnotice("integrity", "making a cursor from primary key"); + secinfo("integrity", "making a cursor from primary key"); CssmClient::DbCursor cursor = pk->createCursor(kc); DbUniqueRecord uniqueId; @@ -1123,7 +1113,7 @@ ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryC // Occasionally this cursor won't return the item attributes (for an unknown reason). // However, we know the attributes any item with this primary key should have, so use those instead. while (cursor->next(dbDupAttributes.get(), NULL, uniqueId)) { - secnotice("integrity", "got an item..."); + secinfo("integrity", "got an item..."); SSGroup group = safer_cast(*uniqueId).group(); if(!ItemImpl::checkIntegrityFromDictionary(*group, dbDupAttributes.get())) { @@ -1227,7 +1217,7 @@ ItemImpl::dbUniqueRecord() // Check that our Db still matches our keychain's db. If not, find this item again in the new Db. // Why silly !(x == y) construction? Compiler calls operator bool() on each pointer otherwise. if(!(mUniqueId->database() == keychain()->database())) { - secnotice("integrity", "updating db of mUniqueRecord"); + secinfo("integrity", "updating db of mUniqueRecord"); DbCursor cursor(mPrimaryKey->createCursor(mKeychain)); if (!cursor->next(NULL, NULL, mUniqueId)) @@ -1314,7 +1304,7 @@ void ItemImpl::modifyContent(const SecKeychainAttributeList *attrList, UInt32 dataLength, const void *inData) { StLock_(mMutex); - unique_ptr __(mKeychain == NULL ? NULL : new StReadWriteLock(*(mKeychain->getKeychainReadWriteLock()), StReadWriteLock::Write)); + StMaybeLock__ (mKeychain == NULL ? NULL : mKeychain->getKeychainMutex()); if (!mDbAttributes.get()) { @@ -1536,29 +1526,35 @@ ItemImpl::getAttributesAndData(SecKeychainAttributeInfo *info, SecItemClass *ite if (info && attrList) { SecKeychainAttributeList *theList=reinterpret_cast(malloc(sizeof(SecKeychainAttributeList))); - SecKeychainAttribute *attr=reinterpret_cast(malloc(sizeof(SecKeychainAttribute)*attrCount)); - theList->count=attrCount; - theList->attr=attr; - for (UInt32 ix = 0; ix < attrCount; ++ix) - { - attr[ix].tag=info->tag[ix]; + if(attrCount == 0) { + theList->count = 0; + theList->attr = NULL; + } else { + SecKeychainAttribute *attr=reinterpret_cast(malloc(sizeof(SecKeychainAttribute)*attrCount)); + theList->count=attrCount; + theList->attr=attr; - if (dbAttributes.at(ix).NumberOfValues > 0) - { - attr[ix].data = dbAttributes.at(ix).Value[0].Data; - attr[ix].length = (UInt32)dbAttributes.at(ix).Value[0].Length; + for (UInt32 ix = 0; ix < attrCount; ++ix) + { + attr[ix].tag=info->tag[ix]; - // We don't want the data released, it is up the client - dbAttributes.at(ix).Value[0].Data = NULL; - dbAttributes.at(ix).Value[0].Length = 0; - } - else - { - attr[ix].data = NULL; - attr[ix].length = 0; - } - } + if (dbAttributes.at(ix).NumberOfValues > 0) + { + attr[ix].data = dbAttributes.at(ix).Value[0].Data; + attr[ix].length = (UInt32)dbAttributes.at(ix).Value[0].Length; + + // We don't want the data released, it is up the client + dbAttributes.at(ix).Value[0].Data = NULL; + dbAttributes.at(ix).Value[0].Length = 0; + } + else + { + attr[ix].data = NULL; + attr[ix].length = 0; + } + } + } *attrList=theList; } diff --git a/OSX/libsecurity_keychain/lib/KCCursor.cpp b/OSX/libsecurity_keychain/lib/KCCursor.cpp index 06ec2493..a5d25d96 100644 --- a/OSX/libsecurity_keychain/lib/KCCursor.cpp +++ b/OSX/libsecurity_keychain/lib/KCCursor.cpp @@ -224,9 +224,6 @@ KCCursorImpl::next(Item &item) Keychain &kc = *mCurrent; - // Grab a read lock on the keychain - StReadWriteLock __(*(kc->getKeychainReadWriteLock()), StReadWriteLock::Read); - Mutex* mutex = kc->getKeychainMutex(); StLock _(*mutex); diff --git a/OSX/libsecurity_keychain/lib/KeyItem.cpp b/OSX/libsecurity_keychain/lib/KeyItem.cpp index c8aa467c..12f7113f 100644 --- a/OSX/libsecurity_keychain/lib/KeyItem.cpp +++ b/OSX/libsecurity_keychain/lib/KeyItem.cpp @@ -351,7 +351,17 @@ KeyItem::importTo(const Keychain &keychain, Access *newAccess, SecKeychainAttrib /* Unwrap the new key into the new Keychain. */ CssmClient::UnwrapKey unwrap(keychain->csp(), CSSM_ALGID_3DES_3KEY_EDE); - unwrap.key(wrappingKey); + if (csp()->guid() != keychain->csp()->guid()) { + // Prepare wrapping key to be usable in target keychain's CSP. + CssmClient::WrapKey exportWrapKey(csp(), CSSM_ALGID_NONE); + CssmClient::Key exportedWrappingKey(exportWrapKey(wrappingKey)); + CssmClient::UnwrapKey importUnwrapKey(keychain->csp(), CSSM_ALGID_NONE); + CssmClient::Key importedWrappingKey(importUnwrapKey(exportedWrappingKey, KeySpec(CSSM_KEYUSE_UNWRAP, 0))); + unwrap.key(importedWrappingKey); + } else { + // Wrapping key can be used directly, because source and target CSPs are the same. + unwrap.key(wrappingKey); + } unwrap.mode(CSSM_ALGMODE_ECBPad); unwrap.padding(CSSM_PADDING_PKCS7); unwrap.initVector(iv); @@ -634,7 +644,7 @@ KeyItem::createPair( CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); ssDb = SSDb(impl); - csp = CssmClient::CSP(keychain->csp()); + csp = keychain->csp(); // Generate a random label to use initially CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW); @@ -698,14 +708,14 @@ KeyItem::createPair( CssmClient::Key publicKey; DbAttributes pubDbAttributes; DbUniqueRecord pubUniqueId; - if (permanentPubKey) { + if (permanentPubKey && ssDb) { SSDbCursor dbPubCursor(ssDb, 1); dbPubCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY); dbPubCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label); if (!dbPubCursor->nextKey(&pubDbAttributes, publicKey, pubUniqueId)) MacOSError::throwMe(errSecItemNotFound); } else { - publicKey = CssmClient::Key(appleCsp, publicCssmKey); + publicKey = CssmClient::Key(csp, publicCssmKey); outPublicKey = new KeyItem(publicKey); freePublicKey = false; } @@ -714,14 +724,14 @@ KeyItem::createPair( CssmClient::Key privateKey; DbAttributes privDbAttributes; DbUniqueRecord privUniqueId; - if (permanentPrivKey) { + if (permanentPrivKey && ssDb) { SSDbCursor dbPrivCursor(ssDb, 1); dbPrivCursor->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY); dbPrivCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label); if (!dbPrivCursor->nextKey(&privDbAttributes, privateKey, privUniqueId)) MacOSError::throwMe(errSecItemNotFound); } else { - privateKey = CssmClient::Key(appleCsp, privateCssmKey); + privateKey = CssmClient::Key(csp, privateCssmKey); outPrivateKey = new KeyItem(privateKey); freePrivateKey = false; } @@ -747,8 +757,8 @@ KeyItem::createPair( pubKeyHash.set(*pubKeyHashData); passThrough.allocator().free(pubKeyHashData); - auto_ptrprivDescription; - auto_ptrpubDescription; + auto_ptr privDescription; + auto_ptr pubDescription; try { privDescription.reset(new string(initialAccess->promptDescription())); pubDescription.reset(new string(initialAccess->promptDescription())); @@ -1121,7 +1131,7 @@ KeyItem::generateWithAttributes(const SecKeychainAttributeList *attrList, if (!initialAccess) { // We don't have an access, but we need to set integrity. Make an Access. - initialAccess = new Access(string(label)); + initialAccess = new Access(label.toString()); } } @@ -1398,9 +1408,9 @@ void KeyItem::modifyUniqueId(Keychain keychain, SSDb ssDb, DbUniqueRecord& uniqu } try { - secnotice("integrity", "modifying unique id"); + secinfo("integrity", "modifying unique id"); uniqueId->modify(recordType, &newDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); - secnotice("integrity", "done modifying unique id"); + secinfo("integrity", "done modifying unique id"); } catch(CssmError e) { // Just in case something went wrong, clean up after this add uniqueId->deleteRecord(); diff --git a/OSX/libsecurity_keychain/lib/Keychains.cpp b/OSX/libsecurity_keychain/lib/Keychains.cpp index 43649d3d..e3ce4cb0 100644 --- a/OSX/libsecurity_keychain/lib/Keychains.cpp +++ b/OSX/libsecurity_keychain/lib/Keychains.cpp @@ -46,7 +46,7 @@ #include #include -#include "DLDbListCFPref.h" +#include "DLDBListCFPref.h" #include #include #include @@ -433,12 +433,6 @@ KeychainImpl::getKeychainMutex() return &mMutex; } -ReadWriteLock* -KeychainImpl::getKeychainReadWriteLock() -{ - return &mRWLock; -} - void KeychainImpl::aboutToDestruct() { // remove me from the global cache, we are done @@ -811,7 +805,7 @@ void KeychainImpl::completeAdd(Item &inItem, PrimaryKey &primaryKey) void KeychainImpl::addCopy(Item &inItem) { - StReadWriteLock _(mRWLock, StReadWriteLock::Write); + StLock_(mMutex); Keychain keychain(this); PrimaryKey primaryKey = inItem->addWithCopyInfo(keychain, true); @@ -822,8 +816,7 @@ KeychainImpl::addCopy(Item &inItem) void KeychainImpl::add(Item &inItem) { - // Make sure we hold a write lock on ourselves when we do this - StReadWriteLock _(mRWLock, StReadWriteLock::Write); + StLock_(mMutex); Keychain keychain(this); PrimaryKey primaryKey = inItem->add(keychain); @@ -882,7 +875,7 @@ KeychainImpl::didUpdate(const Item &inItem, PrimaryKey &oldPK, void KeychainImpl::deleteItem(Item &inoutItem) { - StReadWriteLock _(mRWLock, StReadWriteLock::Write); + StLock_(mMutex); { // item must be persistent @@ -933,7 +926,7 @@ KeychainImpl::csp() { StLock_(mMutex); - if (!mDb->dl()->subserviceMask() & CSSM_SERVICE_CSP) + if (!(mDb->dl()->subserviceMask() & CSSM_SERVICE_CSP)) MacOSError::throwMe(errSecInvalidKeychain); // Try to cast first to a CSPDL to handle case where we don't have an SSDb @@ -1416,8 +1409,7 @@ void KeychainImpl::tickle() { bool KeychainImpl::performKeychainUpgradeIfNeeded() { - // Grab this keychain's mutex. This might not be sufficient, since the - // keychain might have outstanding cursors. We'll grab the RWLock later if needed. + // Grab this keychain's mutex. StLock_(mMutex); if(!globals().integrityProtection()) { @@ -1605,17 +1597,9 @@ bool KeychainImpl::keychainMigration(const string oldPath, const uint32 dbBlobVe // // If the keychain is unlocked, try to upgrade it. // In either case, reload the database from disk. - // We need this keychain's read/write lock. - - // Try to grab the keychain write lock. - StReadWriteLock lock(mRWLock, StReadWriteLock::TryWrite); - // If we didn't manage to grab the lock, there's readers out there - // currently reading this keychain. Abort the upgrade. - if(!lock.isLocked()) { - secnotice("integrity", "couldn't get read-write lock, aborting upgrade"); - return false; - } + // Try to grab the keychain mutex (although we should already have it) + StLock_(mMutex); // Take the file lock on the existing database. We don't need to commit this txion, because we're not planning to // change the original keychain. diff --git a/OSX/libsecurity_keychain/lib/Keychains.h b/OSX/libsecurity_keychain/lib/Keychains.h index 7667b7ae..507b270c 100644 --- a/OSX/libsecurity_keychain/lib/Keychains.h +++ b/OSX/libsecurity_keychain/lib/Keychains.h @@ -138,7 +138,6 @@ public: Mutex* getKeychainMutex(); Mutex* getMutexForObject() const; - ReadWriteLock* getKeychainReadWriteLock(); void aboutToDestruct(); bool operator ==(const KeychainImpl &) const; @@ -323,11 +322,6 @@ private: // creation/returning needs a mutex. You should only hold this if you're // copying or changing the mDb object. Mutex mDbMutex; - - // Used to protect mDb across calls. - // Grab a read lock if you expect to read from this keychain in the future. - // The write lock is taken if we're replacing the database wholesale with something new. - ReadWriteLock mRWLock; }; diff --git a/OSX/libsecurity_keychain/lib/MacOSErrorStrings.h b/OSX/libsecurity_keychain/lib/MacOSErrorStrings.h index bac2d85f..02e6195b 100644 --- a/OSX/libsecurity_keychain/lib/MacOSErrorStrings.h +++ b/OSX/libsecurity_keychain/lib/MacOSErrorStrings.h @@ -48,7 +48,7 @@ enum errSecMisc_memFullErr = -108, errSecMisc_dirNFErr = -120, /* The directory could not be found. */ errSecMisc_volGoneErr = -124, /* The server volume is no longer available. It may have been disconnected. */ - errSecMisc_userCanceledErr = -128, // The operation was cancelled by the user. + errSecMisc_userCanceledErr = -128, // The operation was canceled by the user. errSecMisc_resNotFound = -192, /* A required resource could not be found. */ errSecMisc_resFNotFound = -193, /* A required resource is missing or damaged. */ errSecMisc_icNoURLErr = -673, /* The specified location (URL) is an unknown type, or does not contain enough information. */ diff --git a/OSX/libsecurity_keychain/lib/SecACL.cpp b/OSX/libsecurity_keychain/lib/SecACL.cpp index fabae241..d91458b3 100644 --- a/OSX/libsecurity_keychain/lib/SecACL.cpp +++ b/OSX/libsecurity_keychain/lib/SecACL.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "SecBridge.h" // Forward reference @@ -48,6 +50,9 @@ CFTypeID SecACLGetTypeID(void) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecACLGetTypeID", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); return gTypes().ACL.typeID; @@ -63,6 +68,9 @@ OSStatus SecACLCreateFromSimpleContents(SecAccessRef accessRef, SecACLRef *newAcl) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecACLCreateFromSimpleContents", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); SecPointer access = Access::required(accessRef); SecPointer acl = new ACL(cfString(description), *promptSelector); if (applicationList) { @@ -96,6 +104,9 @@ OSStatus SecACLCreateWithSimpleContents(SecAccessRef access, OSStatus SecACLRemove(SecACLRef aclRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecACLRemove", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); ACL::required(aclRef)->remove(); END_SECAPI } @@ -162,6 +173,9 @@ OSStatus SecACLSetSimpleContents(SecACLRef aclRef, CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecACLSetSimpleContents", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); SecPointer acl = ACL::required(aclRef); if(acl->form() == ACL::integrityForm) { // If this is an integrity ACL, route the (unhexified) promptDescription into the right place @@ -284,6 +298,9 @@ OSStatus SecACLSetAuthorizations(SecACLRef aclRef, CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 tagCount) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecACLSetAuthorizations", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); SecPointer acl = ACL::required(aclRef); if (acl->isOwner()) // can't change rights of the owner ACL MacOSError::throwMe(errSecInvalidOwnerEdit); diff --git a/OSX/libsecurity_keychain/lib/SecACL.h b/OSX/libsecurity_keychain/lib/SecACL.h index a0f4514d..abc9f814 100644 --- a/OSX/libsecurity_keychain/lib/SecACL.h +++ b/OSX/libsecurity_keychain/lib/SecACL.h @@ -43,6 +43,8 @@ extern "C" { CF_ASSUME_NONNULL_BEGIN CF_IMPLICIT_BRIDGING_ENABLED +#if SEC_OS_OSX + typedef CF_OPTIONS(uint16, SecKeychainPromptSelector) { kSecKeychainPromptRequirePassphase = 0x0001, /* require re-entering of passphrase */ @@ -169,6 +171,8 @@ CF_IMPLICIT_BRIDGING_ENABLED CFStringRef description, SecKeychainPromptSelector promptSelector) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + +#endif // SEC_OS_OSX /*! @function SecACLGetAuthorizations diff --git a/OSX/libsecurity_keychain/lib/SecAccess.cpp b/OSX/libsecurity_keychain/lib/SecAccess.cpp index 4dacfa95..bb3adfc6 100644 --- a/OSX/libsecurity_keychain/lib/SecAccess.cpp +++ b/OSX/libsecurity_keychain/lib/SecAccess.cpp @@ -321,7 +321,9 @@ SecAccessRef SecAccessCreateWithOwnerAndACL(uid_t userId, gid_t groupId, SecAcce CFRelease(debugStr); #endif - CSSM_ACL_AUTHORIZATION_TAG rights[numAcls]; + CFIndex rightsSize = numAcls > 0 ? numAcls : 1; + + CSSM_ACL_AUTHORIZATION_TAG rights[rightsSize]; memset(rights, 0, sizeof(rights)); for (CFIndex iCnt = 0; iCnt < numAcls; iCnt++) @@ -382,7 +384,7 @@ SecAccessRef SecAccessCreateWithOwnerAndACL(uid_t userId, gid_t groupId, SecAcce { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, false, // Delegate // rights for this entry - { (uint32)(sizeof(rights) / sizeof(rights[0])), rights }, + { (uint32)numAcls, rights }, // rest is defaulted } } @@ -579,9 +581,6 @@ CFArrayRef copyTrustedAppListFromBundle(CFStringRef bundlePath, CFStringRef trus if (!trustedAppsURL) goto xit; - if ( trustedAppListFileNameWithoutExtension ) - CFRelease(trustedAppListFileNameWithoutExtension); - if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,trustedAppsURL,&xmlDataRef,NULL,NULL,&errorCode)) goto xit; @@ -589,6 +588,7 @@ CFArrayRef copyTrustedAppListFromBundle(CFStringRef bundlePath, CFStringRef trus trustedAppList = (CFArrayRef)trustedAppsPlist; xit: + CFReleaseNull(trustedAppListFileNameWithoutExtension); if (bundleURL) CFRelease(bundleURL); if (secBundle) diff --git a/OSX/libsecurity_keychain/lib/SecAccessPriv.h b/OSX/libsecurity_keychain/lib/SecAccessPriv.h index 6b1e5ce2..4e61067e 100644 --- a/OSX/libsecurity_keychain/lib/SecAccessPriv.h +++ b/OSX/libsecurity_keychain/lib/SecAccessPriv.h @@ -39,21 +39,8 @@ extern "C" { #endif -/*! - @function SecKeychainAddIToolsPassword - @abstract Creates a new iTools password using the access control list from iToolsTrustedApps.plist. - @param keychain A reference to the keychain to which to add the password. Pass NULL to add the password to the default keychain. - @param accountNameLength The length of the buffer pointed to by accountName. - @param accountName A pointer to a string containing the account name associated with this password. - @param passwordLength The length of the buffer pointed to by passwordData. - @param passwordData A pointer to a buffer containing the password data to be stored in the keychain. - @param itemRef On return, a reference to the new keychain item. - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion The SecKeychainAddIToolsPassword function adds a new iTools password to the specified keychain with an ACL composed of a list of trusted applications. A required parameter to identify the password is the accountName, which is an application-defined string. The servicename will always be "iTools". SecKeychainAddIToolsPassword optionally returns a reference to the newly added item. -*/ - OSStatus SecKeychainAddIToolsPassword(SecKeychainRef keychain, UInt32 accountNameLength, const char *accountName, - UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef); + UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) __deprecated_msg("iTools is no longer supported"); /*! @function SecAccessCreateWithTrustedApplications diff --git a/OSX/libsecurity_keychain/lib/SecCFTypes.cpp b/OSX/libsecurity_keychain/lib/SecCFTypes.cpp index cfbf7e8e..d224e287 100644 --- a/OSX/libsecurity_keychain/lib/SecCFTypes.cpp +++ b/OSX/libsecurity_keychain/lib/SecCFTypes.cpp @@ -52,7 +52,6 @@ SecCFTypes::SecCFTypes() : Access("SecAccess"), ACL("SecACL"), Certificate("SecCertificate"), - CertificateRequest("SecCertificateRequest"), Identity("SecIdentity"), IdentityCursor("SecIdentitySearch"), ItemImpl("SecKeychainItem"), diff --git a/OSX/libsecurity_keychain/lib/SecCFTypes.h b/OSX/libsecurity_keychain/lib/SecCFTypes.h index c1a8e1d2..ab046ee5 100644 --- a/OSX/libsecurity_keychain/lib/SecCFTypes.h +++ b/OSX/libsecurity_keychain/lib/SecCFTypes.h @@ -82,7 +82,6 @@ public: CFClass Access; CFClass ACL; CFClass Certificate; - CFClass CertificateRequest; CFClass Identity; CFClass IdentityCursor; CFClass ItemImpl; diff --git a/OSX/libsecurity_keychain/lib/SecCertificate.cpp b/OSX/libsecurity_keychain/lib/SecCertificate.cpp index 8c3454c6..a9b145d4 100644 --- a/OSX/libsecurity_keychain/lib/SecCertificate.cpp +++ b/OSX/libsecurity_keychain/lib/SecCertificate.cpp @@ -352,18 +352,6 @@ SecCertificateGetEmailAddress(SecCertificateRef certificate, CFStringRef *emailA END_SECCERTAPI } -/* OS X only */ -OSStatus -SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArrayRef *emailAddresses) -{ - // This macro creates an ItemImpl certificate if it does not exist - BEGIN_SECCERTAPI - - Required(emailAddresses) = Certificate::required(__itemImplRef)->copyEmailAddresses(); - - END_SECCERTAPI -} - /* Return a zero terminated list of CSSM_DATA_PTR's with the values of the field specified by field. * Caller must call releaseFieldValues to free the storage allocated by this call. * diff --git a/OSX/libsecurity_keychain/lib/SecCertificateP.c b/OSX/libsecurity_keychain/lib/SecCertificateP.c index a273273d..77210b57 100644 --- a/OSX/libsecurity_keychain/lib/SecCertificateP.c +++ b/OSX/libsecurity_keychain/lib/SecCertificateP.c @@ -224,10 +224,18 @@ static bool derDateGetAbsoluteTime(const DERItem *dateChoice, /* Static functions. */ static CFStringRef SecCertificateCopyDescription(CFTypeRef cf) { SecCertificateRefP certificate = (SecCertificateRefP)cf; - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFStringRef ret = NULL; + CFStringRef subjectSummary = SecCertificateCopySubjectSummaryP(certificate); + CFStringRef issuerSummary = SecCertificateCopyIssuerSummaryP(certificate); + + ret = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(""), certificate, - SecCertificateCopySubjectSummaryP(certificate), - SecCertificateCopyIssuerSummaryP(certificate)); + subjectSummary, + issuerSummary); + + CFReleaseNull(subjectSummary); + CFReleaseNull(issuerSummary); + return ret; } static void SecCertificateDestroy(CFTypeRef cf) { @@ -724,8 +732,9 @@ static void SecCEPCertificatePolicies(SecCertificateRefP certificate, policy_count++; } require_quiet(drtn == DR_EndOfSequence, badDER); - policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation) - * policy_count); + DERSize malloc_policies = policy_count > 0 ? policy_count : 1; + require_quiet(policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation) + * malloc_policies), badDER); drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq); require_noerr_quiet(drtn, badDER); DERSize policy_ix = 0; @@ -1489,8 +1498,10 @@ static bool SecCertificateParse(SecCertificateRefP certificate) /* Put some upper limit on the number of extentions allowed. */ require_quiet(extensionCount < 10000, badCert); certificate->_extensionCount = extensionCount; + CFIndex mallocCount = extensionCount > 0 ? extensionCount : 1; certificate->_extensions = - malloc(sizeof(SecCertificateExtension) * extensionCount); + malloc(sizeof(SecCertificateExtension) * mallocCount); + require_quiet(certificate->_extensions, badCert); CFIndex ix = 0; drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag, &derSeq); @@ -1551,7 +1562,9 @@ SecCertificateRefP SecCertificateCreateWithBytesP(CFAllocatorRef allocator, sizeof(*result) - sizeof(result->_base)); result->_der.data = ((DERByte *)result + sizeof(*result)); result->_der.length = der_length; - memcpy(result->_der.data, der_bytes, der_length); + if(der_bytes) { + memcpy(result->_der.data, der_bytes, der_length); + } if (!SecCertificateParse(result)) { CFRelease(result); return NULL; @@ -2534,6 +2547,8 @@ static void appendOtherNameContentProperty(CFMutableArrayRef properties, else appendUnparsedProperty(properties, oid_string, &on.value); + CFReleaseNull(value_string); + CFReleaseNull(oid_string); return; badDER: appendInvalidProperty(properties, CFSTR("Other Name"), otherNameContent); @@ -2782,23 +2797,27 @@ badDER: /* Decode a sequence of integers into a comma separated list of ints. */ static void appendIntegerSequenceContent(CFMutableArrayRef properties, CFStringRef label, const DERItem *intSequenceContent) { + CFMutableStringRef value = NULL; + CFStringRef intDesc = NULL; CFAllocatorRef allocator = CFGetAllocator(properties); DERSequence intSeq; DERReturn drtn = DERDecodeSeqContentInit(intSequenceContent, &intSeq); require_noerr_quiet(drtn, badDER); DERDecodedInfo intContent; - CFMutableStringRef value = NULL; + while ((drtn = DERDecodeSeqNext(&intSeq, &intContent)) == DR_Success) { require_quiet(intContent.tag == ASN1_INTEGER, badDER); - CFStringRef intDesc = copyIntegerContentDescription( + intDesc = copyIntegerContentDescription( allocator, &intContent.content); + require_quiet(intDesc, badDER); if (value) { CFStringAppendFormat(value, NULL, CFSTR(", %@"), intDesc); } else { value = CFStringCreateMutableCopy(allocator, 0, intDesc); + require_quiet(value, badDER); } - CFRelease(intDesc); + CFReleaseNull(intDesc); } require_quiet(drtn == DR_EndOfSequence, badDER); if (value) { @@ -2809,12 +2828,15 @@ static void appendIntegerSequenceContent(CFMutableArrayRef properties, } /* DROPTHOUGH if !value. */ badDER: + CFReleaseNull(value); + CFReleaseNull(intDesc); appendInvalidProperty(properties, label, intSequenceContent); } static void appendCertificatePolicies(CFMutableArrayRef properties, const DERItem *extnValue) { CFAllocatorRef allocator = CFGetAllocator(properties); + CFStringRef piLabel = NULL, pqLabel = NULL; DERTag tag; DERSequence piSeq; DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &piSeq); @@ -2830,10 +2852,10 @@ static void appendCertificatePolicies(CFMutableArrayRef properties, DERPolicyInformationItemSpecs, &pi, sizeof(pi)); require_noerr_quiet(drtn, badDER); - CFStringRef piLabel = CFStringCreateWithFormat(allocator, NULL, - CFSTR("Policy Identifier #%d"), pin++); + require_quiet(piLabel = CFStringCreateWithFormat(allocator, NULL, + CFSTR("Policy Identifier #%d"), pin++), badDER); appendOIDProperty(properties, piLabel, &pi.policyIdentifier); - CFRelease(piLabel); + CFReleaseNull(piLabel); if (pi.policyQualifiers.length == 0) continue; @@ -2852,10 +2874,10 @@ static void appendCertificatePolicies(CFMutableArrayRef properties, DERDecodedInfo qualifierContent; drtn = DERDecodeItem(&pqi.qualifier, &qualifierContent); require_noerr_quiet(drtn, badDER); - CFStringRef pqLabel = CFStringCreateWithFormat(allocator, NULL, - CFSTR("Policy Qualifier #%d"), pqn++); + require_quiet(pqLabel = CFStringCreateWithFormat(allocator, NULL, + CFSTR("Policy Qualifier #%d"), pqn++), badDER); appendOIDProperty(properties, pqLabel, &pqi.policyQualifierID); - CFRelease(pqLabel); + CFReleaseNull(pqLabel); if (DEROidCompare(&oidQtCps, &pqi.policyQualifierID)) { require_quiet(qualifierContent.tag == ASN1_IA5_STRING, badDER); appendURLContentProperty(properties, @@ -2896,6 +2918,8 @@ static void appendCertificatePolicies(CFMutableArrayRef properties, require_quiet(drtn == DR_EndOfSequence, badDER); return; badDER: + CFReleaseNull(piLabel); + CFReleaseNull(pqLabel); appendInvalidProperty(properties, CFSTR("Certificate Policies"), extnValue); } @@ -3134,11 +3158,11 @@ static bool appendPrintableDERSequenceP(CFMutableArrayRef properties, CFStringRef string = copyDERThingContentDescription(CFGetAllocator(properties), currDecoded.tag, &currDecoded.content, false); - //CFStringRef cleanString = copyStringRemovingPercentEscapes(string); + require_quiet(string, badSequence); appendPropertyP(properties, kSecPropertyTypeString, label, string); - CFRelease(string); + CFReleaseNull(string); appendedSomething = true; break; } @@ -3529,53 +3553,34 @@ CFArrayRef SecCertificateCopyPropertiesP(SecCertificateRefP certificate) { CFAllocatorRef allocator = CFGetAllocator(certificate); CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); + require_quiet(properties, out); /* First we put the Subject Name in the property list. */ - CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator, - &certificate->_subject); - appendPropertyP(properties, kSecPropertyTypeSection, - CFSTR("Subject Name"), subject_plist); - CFRelease(subject_plist); - -#if 0 - /* Put Normalized subject in for testing. */ - if (certificate->_normalizedSubject) { - DERItem nsubject = { - (DERByte *)CFDataGetBytePtr(certificate->_normalizedSubject), - CFDataGetLength(certificate->_normalizedSubject) - }; - CFArrayRef nsubject_plist = createPropertiesForX501NameContent(allocator, - &nsubject); - appendPropertyP(properties, kSecPropertyTypeSection, - CFSTR("Normalized Subject Name"), nsubject_plist); - CFRelease(nsubject_plist); - } -#endif - - /* Next we put the Issuer Name in the property list. */ - CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator, - &certificate->_issuer); - appendPropertyP(properties, kSecPropertyTypeSection, - CFSTR("Issuer Name"), issuer_plist); - CFRelease(issuer_plist); - -#if 0 - /* Certificate version/type. */ - bool isRoot = false; - CFStringRef typeString = CFStringCreateWithFormat(allocator, NULL, - CFSTR("X.509 version %d %scertificate"), - certificate->_version + 1, isRoot ? "root " : ""); - appendPropertyP(properties, kSecPropertyTypeString, - CFSTR("Certificate Type"), typeString); - CFRelease(typeString); -#endif + CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator, + &certificate->_subject); + if (subject_plist) { + appendPropertyP(properties, kSecPropertyTypeSection, + CFSTR("Subject Name"), subject_plist); + } + CFReleaseNull(subject_plist); - /* Version */ - CFStringRef versionString = CFStringCreateWithFormat(allocator, - NULL, CFSTR("%d"), certificate->_version + 1); - appendPropertyP(properties, kSecPropertyTypeString, - CFSTR("Version"), versionString); - CFRelease(versionString); + /* Next we put the Issuer Name in the property list. */ + CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator, + &certificate->_issuer); + if (issuer_plist) { + appendPropertyP(properties, kSecPropertyTypeSection, + CFSTR("Issuer Name"), issuer_plist); + } + CFReleaseNull(issuer_plist); + + /* Version */ + CFStringRef versionString = CFStringCreateWithFormat(allocator, NULL, CFSTR("%d"), + certificate->_version + 1); + if (versionString) { + appendPropertyP(properties, kSecPropertyTypeString, + CFSTR("Version"), versionString); + } + CFReleaseNull(versionString); /* Serial Number */ if (certificate->_serialNum.length) { @@ -3584,10 +3589,6 @@ CFArrayRef SecCertificateCopyPropertiesP(SecCertificateRefP certificate) { } /* Signature algorithm. */ -#if 0 - appendAlgorithmProperty(properties, CFSTR("Signature Algorithm"), - &certificate->_sigAlg); -#endif appendAlgorithmProperty(properties, CFSTR("Signature Algorithm"), &certificate->_tbsSigAlg); @@ -3631,7 +3632,8 @@ CFArrayRef SecCertificateCopyPropertiesP(SecCertificateRefP certificate) { certificate->_properties = properties; } - CFRetain(certificate->_properties); +out: + CFRetainSafe(certificate->_properties); return certificate->_properties; } @@ -4677,10 +4679,9 @@ CFArrayRef SecCertificateCopyExtendedKeyUsageP(SecCertificateRefP certificate) require_quiet(currDecoded.tag == ASN1_OBJECT_ID, out); CFDataRef oid = CFDataCreate(kCFAllocatorDefault, currDecoded.content.data, currDecoded.content.length); - if (oid) { - CFArrayAppendValue(extended_key_usage_oids, oid); - CFRelease(oid); - } + require_quiet(oid, out); + CFArrayAppendValue(extended_key_usage_oids, oid); + CFReleaseNull(oid); } require_quiet(drtn == DR_EndOfSequence, out); return extended_key_usage_oids; diff --git a/OSX/libsecurity_keychain/lib/SecCertificateRequest.cpp b/OSX/libsecurity_keychain/lib/SecCertificateRequest.cpp deleted file mode 100644 index 9cd90525..00000000 --- a/OSX/libsecurity_keychain/lib/SecCertificateRequest.cpp +++ /dev/null @@ -1,190 +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 - -#include "SecBridge.h" -#include "CertificateRequest.h" -#include "SecImportExport.h" -#include "SecCertificate.h" - -CFTypeID -SecCertificateRequestGetTypeID(void) -{ - BEGIN_SECAPI - - return gTypes().CertificateRequest.typeID; - - END_SECAPI1(_kCFRuntimeNotATypeID) -} - - -OSStatus SecCertificateRequestCreate( - const CSSM_OID *policy, - CSSM_CERT_TYPE certificateType, - CSSM_TP_AUTHORITY_REQUEST_TYPE requestType, - SecKeyRef privateKeyItemRef, - SecKeyRef publicKeyItemRef, - const SecCertificateRequestAttributeList* attributeList, - SecCertificateRequestRef* certRequest) -{ - BEGIN_SECAPI - Required(certRequest); - Required(policy); - *certRequest = (new CertificateRequest(*policy, certificateType, requestType, - privateKeyItemRef, publicKeyItemRef, attributeList))->handle(); - END_SECAPI -} - - -OSStatus SecCertificateRequestSubmit( - SecCertificateRequestRef certRequest, - sint32* estimatedTime) -{ - BEGIN_SECAPI - - CertificateRequest::required(certRequest)->submit(estimatedTime); - - END_SECAPI -} - - -OSStatus SecCertificateRequestGetType( - SecCertificateRequestRef certRequestRef, - CSSM_TP_AUTHORITY_REQUEST_TYPE *requestType) -{ - BEGIN_SECAPI - - Required(requestType); - *requestType = CertificateRequest::required(certRequestRef)->reqType(); - - END_SECAPI -} - -OSStatus SecCertificateRequestGetResult( - SecCertificateRequestRef certRequestRef, - SecKeychainRef keychain, - sint32 *estimatedTime, - SecCertificateRef *certificateRef) -{ - BEGIN_SECAPI - - CssmData certData; - *certificateRef = NULL; - CertificateRequest::required(certRequestRef)->getResult(estimatedTime, certData); - if(certData.data() != NULL) { - /* - * Convert to SecCertifcateRef, optionally import. - */ - CFDataRef cfCert = CFDataCreate(NULL, (UInt8 *)certData.data(), certData.Length); - SecExternalItemType itemType = kSecItemTypeCertificate; - CFArrayRef outItems = NULL; - bool freeKcRef = false; - OSStatus ortn; - - if(keychain == NULL) { - /* - * Unlike most Sec* calls, if the keychain argument to SecKeychainItemImport() - * is NULL, the item is not imported to the default keychain. At our - * interface, however, a NULL keychain means "import to the default - * keychain". - */ - ortn = SecKeychainCopyDefault(&keychain); - if(ortn) { - certReqDbg("GetResult: SecKeychainCopyDefault failure"); - /* oh well, there's nothing we can do about this */ - } - else { - freeKcRef = true; - } - } - ortn = SecKeychainItemImport(cfCert, NULL, - NULL, // format, don't care - &itemType, - 0, // flags - NULL, // keyParams - keychain, // optional, like ours - &outItems); - CFRelease(cfCert); - if(freeKcRef) { - CFRelease(keychain); - } - if(ortn) { - certReqDbg("SecCertificateRequestGetResult: SecKeychainItemImport failure"); - MacOSError::throwMe(ortn); - } - CFIndex numItems = CFArrayGetCount(outItems); - switch(numItems) { - case 0: - certReqDbg("SecCertificateRequestGetResult: import zero items"); - MacOSError::throwMe(errSecInternalComponent); - default: - certReqDbg("SecCertificateRequestGetResult: import %d items", - (int)numItems); - /* but drop thru anyway, take the first one */ - case 1: - SecCertificateRef certRef = - (SecCertificateRef)(CFArrayGetValueAtIndex(outItems, 0)); - if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) { - certReqDbg("SecCertificateRequestGetResult: bad type"); - } - else { - CFRetain(certRef); - *certificateRef = certRef; - } - } - CFRelease(outItems); - } - END_SECAPI -} - -OSStatus SecCertificateFindRequest( - const CSSM_OID *policy, - CSSM_CERT_TYPE certificateType, - CSSM_TP_AUTHORITY_REQUEST_TYPE requestType, - SecKeyRef publicKeyItemRef, - SecKeyRef privateKeyItemRef, - const SecCertificateRequestAttributeList* attributeList, - SecCertificateRequestRef* certRequest) -{ - BEGIN_SECAPI - - Required(certRequest); - Required(policy); - *certRequest = (new CertificateRequest(*policy, certificateType, requestType, - privateKeyItemRef, publicKeyItemRef, attributeList, false))->handle(); - END_SECAPI -} - - -OSStatus SecCertificateRequestGetData( - SecCertificateRequestRef certRequestRef, - CSSM_DATA *data) -{ - BEGIN_SECAPI - - Required(data); - CertificateRequest::required(certRequestRef)->getReturnData(CssmData::overlay(*data)); - - END_SECAPI -} diff --git a/OSX/libsecurity_keychain/lib/SecFDERecoveryAsymmetricCrypto.cpp b/OSX/libsecurity_keychain/lib/SecFDERecoveryAsymmetricCrypto.cpp index 844a1e1a..8d341bf2 100644 --- a/OSX/libsecurity_keychain/lib/SecFDERecoveryAsymmetricCrypto.cpp +++ b/OSX/libsecurity_keychain/lib/SecFDERecoveryAsymmetricCrypto.cpp @@ -34,7 +34,7 @@ #include static void encodePrivateKeyHeader(const CssmData &inBlob, CFDataRef certificate, FVPrivateKeyHeader &outHeader); -static CFDataRef decodePrivateKeyHeader(SecKeychainRef keychainName, const FVPrivateKeyHeader &inHeader); +static CFDataRef CF_RETURNS_RETAINED decodePrivateKeyHeader(SecKeychainRef keychainName, const FVPrivateKeyHeader &inHeader); static void throwIfError(CSSM_RETURN rv); #pragma mark ----- Public SPI ----- diff --git a/OSX/libsecurity_keychain/lib/SecFrameworkP.h b/OSX/libsecurity_keychain/lib/SecFrameworkP.h index 3a7135a8..da08583a 100644 --- a/OSX/libsecurity_keychain/lib/SecFrameworkP.h +++ b/OSX/libsecurity_keychain/lib/SecFrameworkP.h @@ -39,7 +39,7 @@ extern "C" { #endif CFStringRef SecFrameworkCopyLocalizedString(CFStringRef key, - CFStringRef tableName); + CFStringRef tableName) CF_FORMAT_ARGUMENT(1); CFURLRef SecFrameworkCopyResourceURL(CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName); diff --git a/OSX/libsecurity_keychain/lib/SecIdentity.cpp b/OSX/libsecurity_keychain/lib/SecIdentity.cpp index c870ec73..1cb7b595 100644 --- a/OSX/libsecurity_keychain/lib/SecIdentity.cpp +++ b/OSX/libsecurity_keychain/lib/SecIdentity.cpp @@ -38,6 +38,7 @@ #include #include #include +#include /* private function declarations */ OSStatus @@ -108,6 +109,9 @@ CFTypeID SecIdentityGetTypeID(void) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentityGetTypeID", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); return gTypes().Identity.typeID; @@ -121,6 +125,9 @@ SecIdentityCopyCertificate( SecCertificateRef *certificateRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentityCopyCertificate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); if (!identityRef || !certificateRef) { return errSecParam; @@ -179,6 +186,9 @@ SecIdentityCopyPrivateKey( SecKeyRef *privateKeyRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentityCopyPrivateKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Required(privateKeyRef) = (SecKeyRef)CFRetain(Identity::required(identityRef)->privateKeyRef()); @@ -461,14 +471,19 @@ OSStatus SecIdentityCopyPreference( // (Note that behavior is unchanged if the specified name is not a URL.) BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentityCopyPreference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); CFTypeRef val = (CFTypeRef)CFPreferencesCopyValue(CFSTR("LogIdentityPreferenceLookup"), CFSTR("com.apple.security"), kCFPreferencesCurrentUser, kCFPreferencesAnyHost); Boolean logging = false; - if (val && CFGetTypeID(val) == CFBooleanGetTypeID()) { - logging = CFBooleanGetValue((CFBooleanRef)val); + if (val) { + if (CFGetTypeID(val) == CFBooleanGetTypeID()) { + logging = CFBooleanGetValue((CFBooleanRef)val); + } } CFReleaseNull(val); @@ -556,8 +571,15 @@ OSStatus SecIdentitySetPreference( } BEGIN_SECAPI - - SecPointer certificate(Identity::required(identity)->certificate()); + os_activity_t activity = os_activity_create("SecIdentitySetPreference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); + + CFRef certRef; + OSStatus status = SecIdentityCopyCertificate(identity, certRef.take()); + if(status != errSecSuccess) { + MacOSError::throwMe(status); + } // determine the account attribute // @@ -569,7 +591,7 @@ OSStatus SecIdentitySetPreference( // 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); + SecCertificateInferLabel(certRef.get(), &labelStr); if (!labelStr) { MacOSError::throwMe(errSecDataTooLarge); // data is "in a format which cannot be displayed" } @@ -617,7 +639,7 @@ OSStatus SecIdentitySetPreference( // generic attribute (store persistent certificate reference) CFDataRef pItemRef = nil; - certificate->copyPersistentReference(pItemRef); + SecKeychainItemCreatePersistentReference((SecKeychainItemRef)certRef.get(), &pItemRef); if (!pItemRef) { MacOSError::throwMe(errSecInvalidItemRef); } @@ -665,6 +687,9 @@ SecIdentityFindPreferenceItem( 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); @@ -703,6 +728,9 @@ SecIdentityFindPreferenceItemWithNameAndKeyUsage( SecKeychainItemRef *itemRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentityFindPreferenceItemWithNameAndKeyUsage", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); StorageManager::KeychainList keychains; globals().storageManager.optionalSearchList(keychainOrArray, keychains); @@ -870,6 +898,9 @@ OSStatus SecIdentityAddPreferenceItem( // (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); @@ -926,6 +957,9 @@ OSStatus SecIdentityUpdatePreferenceItem( 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); @@ -994,6 +1028,9 @@ OSStatus SecIdentityCopyFromPreferenceItem( 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); @@ -1055,6 +1092,9 @@ OSStatus SecIdentityCopySystemIdentity( CFStringRef *actualDomain) /* optional */ { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentityCopySystemIdentity", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); StLock _(systemIdentityLock()); auto_ptr identDict; @@ -1123,6 +1163,9 @@ OSStatus SecIdentitySetSystemIdentity( SecIdentityRef idRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentitySetSystemIdentity", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); StLock _(systemIdentityLock()); if(geteuid() != 0) { diff --git a/OSX/libsecurity_keychain/lib/SecIdentitySearch.cpp b/OSX/libsecurity_keychain/lib/SecIdentitySearch.cpp index e46cdfad..589fa93e 100644 --- a/OSX/libsecurity_keychain/lib/SecIdentitySearch.cpp +++ b/OSX/libsecurity_keychain/lib/SecIdentitySearch.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "SecBridge.h" @@ -34,6 +35,9 @@ CFTypeID SecIdentitySearchGetTypeID(void) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentitySearchGetTypeID", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); return gTypes().IdentityCursor.typeID; @@ -48,6 +52,9 @@ SecIdentitySearchCreate( SecIdentitySearchRef *searchRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentitySearchCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Required(searchRef); @@ -64,6 +71,9 @@ OSStatus SecIdentitySearchCreateWithAttributes( SecIdentitySearchRef* searchRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentitySearchCreateWithAttributes", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); // // %%%TBI This function needs a new form of IdentityCursor that takes @@ -87,6 +97,9 @@ OSStatus SecIdentitySearchCreateWithPolicy( SecIdentitySearchRef* searchRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentitySearchCreateWithPolicy", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Required(searchRef); @@ -106,6 +119,9 @@ SecIdentitySearchCopyNext( SecIdentityRef *identityRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecIdentitySearchCopyNext", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); RequiredParam(identityRef); SecPointer identityPtr; diff --git a/OSX/libsecurity_keychain/lib/SecImportExportAgg.cpp b/OSX/libsecurity_keychain/lib/SecImportExportAgg.cpp index 96b00341..f21e719f 100644 --- a/OSX/libsecurity_keychain/lib/SecImportExportAgg.cpp +++ b/OSX/libsecurity_keychain/lib/SecImportExportAgg.cpp @@ -547,6 +547,11 @@ OSStatus impExpPkcs12Import( } } + if(!importedCertRef) { + SecImpExpDbg("SecCertificateGetData error (couldn't find cert)"); + goto loopEnd; + } + /* Get digest of this cert's public key */ ortn = SecCertificateGetData(importedCertRef, &certData); if(ortn) { diff --git a/OSX/libsecurity_keychain/lib/SecItem.cpp b/OSX/libsecurity_keychain/lib/SecItem.cpp index c25efd5c..49a0a4d8 100644 --- a/OSX/libsecurity_keychain/lib/SecItem.cpp +++ b/OSX/libsecurity_keychain/lib/SecItem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "cssmdatetime.h" #include "SecItem.h" @@ -53,6 +54,7 @@ #include #include +#include const uint8_t kUUIDStringLength = 36; @@ -73,6 +75,9 @@ OSStatus SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAtt OSStatus SecItemValidateAppleApplicationGroupAccess(CFStringRef group); CFDictionaryRef SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict, CFTypeRef itemClass, bool iOSOut, bool pruneMatch, bool pruneSync, bool pruneReturn, bool pruneData, bool pruneAccess); + +bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, + long long int *return_rowid, CFDictionaryRef *return_token_attrs); } static Boolean SecItemSynchronizable(CFDictionaryRef query); @@ -584,7 +589,7 @@ _ConvertNewFormatToOldFormat( // now we can make the result array attrList->count = (UInt32)count; - attrList->attr = (SecKeychainAttribute*) malloc(sizeof(SecKeychainAttribute) * count); + attrList->attr = (count > 0) ? (SecKeychainAttribute*) malloc(sizeof(SecKeychainAttribute) * count) : NULL; // fill out the array int resultPointer = 0; @@ -663,6 +668,7 @@ _ConvertOldFormatToNewFormat( break; default: stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%d"), keyRecordValue); + retainString = false; break; } if (stringRef) { @@ -949,6 +955,7 @@ _CreateAttributesDictionaryFromKeyItem( break; default: stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%u"), (unsigned int)keyRecordValue); + retainString = false; break; } if (stringRef) { @@ -2233,7 +2240,7 @@ _SafeSecKeychainItemDelete( } // create SecTrustedApplicationRef for current application/tool - CFReleaseSafe(currentAppRef); + CFReleaseNull(currentAppRef); status = SecTrustedApplicationCreateFromPath(NULL, ¤tAppRef); require_noerr(status, finish); require_quiet(currentAppRef != NULL, finish); @@ -2509,7 +2516,7 @@ _UpdateKeychainItem(CFTypeRef item, CFDictionaryRef changedAttributes) } // update item status = SecKeychainItemModifyContent(itemToUpdate, - (changeAttrList->count == 0) ? NULL : changeAttrList, + (!changeAttrList || changeAttrList->count == 0) ? NULL : changeAttrList, (theData != NULL) ? (UInt32)CFDataGetLength(theData) : 0, (theData != NULL) ? CFDataGetBytePtrVoid(theData) : NULL); require_noerr(status, update_failed); @@ -2524,7 +2531,7 @@ update_failed: (itemClass == kSecInternetPasswordItemClass || itemClass == kSecGenericPasswordItemClass)) { // if we got a cryptographic failure updating a password item, it needs to be replaced status = _ReplaceKeychainItem(itemToUpdate, - (changeAttrList->count == 0) ? NULL : changeAttrList, + (!changeAttrList || changeAttrList->count == 0) ? NULL : changeAttrList, theData); } if (itemToUpdate) @@ -2828,6 +2835,7 @@ struct SecItemParams { CFTypeRef keyClass; // value for kSecAttrKeyClass (may be NULL) CFTypeRef service; // value for kSecAttrService (may be NULL) CFTypeRef issuer; // value for kSecAttrIssuer (may be NULL) + CFTypeRef matchIssuers; // value for kSecMatchIssuers (may be NULL) CFTypeRef serialNumber; // value for kSecAttrSerialNumber (may be NULL) CFTypeRef search; // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef) CFTypeRef assumedKeyClass; // if no kSecAttrKeyClass provided, holds the current class we're searching for @@ -2939,6 +2947,7 @@ _FreeSecItemParams(SecItemParams *itemParams) if (itemParams->keyClass) CFRelease(itemParams->keyClass); if (itemParams->service) CFRelease(itemParams->service); if (itemParams->issuer) CFRelease(itemParams->issuer); + if (itemParams->matchIssuers) CFRelease(itemParams->matchIssuers); if (itemParams->serialNumber) CFRelease(itemParams->serialNumber); if (itemParams->search) CFRelease(itemParams->search); if (itemParams->access) CFRelease(itemParams->access); @@ -2957,6 +2966,7 @@ _CreateSecItemParamsFromDictionary(CFDictionaryRef dict, OSStatus *error) { OSStatus status; CFTypeRef value = NULL; + CFDictionaryRef policyDict = NULL; SecItemParams *itemParams = (SecItemParams *)calloc(1, sizeof(struct SecItemParams)); require_action(itemParams != NULL, error_exit, status = errSecAllocate); @@ -3065,6 +3075,32 @@ _CreateSecItemParamsFromDictionary(CFDictionaryRef dict, OSStatus *error) require_action(!(itemParams->itemClass == 0 && !itemParams->useItems), error_exit, status = errSecItemClassMissing); } + // kSecMatchIssuers is only permitted with identities. + // Convert the input issuers to normalized form. + require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchIssuers, (const void **)&itemParams->matchIssuers, CFArrayGetTypeID(), NULL), error_exit); + if (itemParams->matchIssuers) { + require_action(itemParams->returnIdentity, error_exit, status = errSecParam); + CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayRef issuers = (CFArrayRef)itemParams->matchIssuers; + if (canonical_issuers) { + CFIndex i, count = CFArrayGetCount(issuers); + for (i = 0; i < count; i++) { + CFTypeRef issuer_data = CFArrayGetValueAtIndex(issuers, i); + CFDataRef issuer_canonical = NULL; + if (CFDataGetTypeID() == CFGetTypeID(issuer_data)) + issuer_canonical = SecDistinguishedNameCopyNormalizedSequence((CFDataRef)issuer_data); + if (issuer_canonical) { + CFArrayAppendValue(canonical_issuers, issuer_canonical); + CFRelease(issuer_canonical); + } + } + if (CFArrayGetCount(canonical_issuers) > 0) { + CFAssignRetained(itemParams->matchIssuers, canonical_issuers); + } else + CFRelease(canonical_issuers); + } + } + itemParams->keyUsage = _CssmKeyUsageFromQuery(dict); itemParams->trustedOnly = CFDictionaryGetValueIfPresent(dict, kSecMatchTrustedOnly, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value); itemParams->issuerAndSNToMatch = (itemParams->issuer != NULL && itemParams->serialNumber != NULL); @@ -3113,12 +3149,18 @@ _CreateSecItemParamsFromDictionary(CFDictionaryRef dict, OSStatus *error) require_noerr(status, error_exit); } - // if we already have an item list (to add or find items in), we don't need an item class, attribute list or a search reference + // if we already have an item list (to add or find items in), we don't need a search reference if (itemParams->useItems) { if (itemParams->itemClass == 0) { itemParams->itemClass = _ItemClassFromItemList(itemParams->useItems); } - status = errSecSuccess; + + // build a SecKeychainAttributeList from the query dictionary for the specified item class + if (itemParams->itemClass != 0) { + status = _CreateSecKeychainAttributeListFromDictionary(dict, itemParams->itemClass, &itemParams->attrList); + } else { + status = errSecSuccess; + } goto error_exit; // all done here } @@ -3127,12 +3169,12 @@ _CreateSecItemParamsFromDictionary(CFDictionaryRef dict, OSStatus *error) // if policy is a SMIME policy, copy email address in policy into emailAddrToMatch parameter if(itemParams->policy) { - CFDictionaryRef policyDict = SecPolicyCopyProperties(itemParams->policy); + policyDict = SecPolicyCopyProperties(itemParams->policy); CFStringRef oidStr = (CFStringRef) CFDictionaryGetValue(policyDict, kSecPolicyOid); if(oidStr && CFStringCompare(kSecPolicyAppleSMIME,oidStr,0) == 0) { require_noerr(status = _ValidateDictionaryEntry(policyDict, kSecPolicyName, (const void **)&itemParams->emailAddrToMatch, CFStringGetTypeID(), NULL), error_exit); } - CFRelease(policyDict); + CFReleaseNull(policyDict); } // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef) @@ -3181,6 +3223,7 @@ _CreateSecItemParamsFromDictionary(CFDictionaryRef dict, OSStatus *error) } error_exit: + CFReleaseNull(policyDict); if (status) { _FreeSecItemParams(itemParams); itemParams = NULL; @@ -3357,6 +3400,77 @@ _FilterWithTrust(Boolean trustedOnly, SecCertificateRef cert) return status; } +static bool items_matching_issuer_parent(CFDataRef issuer, CFArrayRef issuers, int recurse) { + if (!issuers || CFArrayGetCount(issuers) == 0) { return false; } + + /* We found a match, we're done. */ + if (CFArrayContainsValue(issuers, CFRangeMake(0, CFArrayGetCount(issuers)), issuer)) { return true; } + + /* Prevent infinite recursion */ + if (recurse <= 0) { return false; } + recurse--; + + /* Query for parents */ + CFMutableDictionaryRef query = NULL; + CFTypeRef parents = NULL; + bool found = false; + + require_quiet(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), out); + CFDictionaryAddValue(query, kSecClass, kSecClassCertificate); + CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); + CFDictionaryAddValue(query, kSecAttrSubject, issuer); + CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll); + require_noerr_quiet(SecItemCopyMatching(query, &parents), out); + + if (parents && CFArrayGetTypeID() == CFGetTypeID(parents)) { + CFIndex i, count = CFArrayGetCount((CFArrayRef)parents); + for (i = 0; i < count; i++) { + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)parents, i); + CFDataRef cert_issuer = SecCertificateCopyNormalizedIssuerSequence(cert); + if (CFEqual(cert_issuer, issuer)) { + // Self-issued cert, don't look for parents. + CFReleaseNull(cert_issuer); + continue; + } + found = items_matching_issuer_parent(cert_issuer, issuers, recurse); + CFReleaseNull(cert_issuer); + if (found) { break; } + } + } else if (parents && SecCertificateGetTypeID() == CFGetTypeID(parents)) { + SecCertificateRef cert = (SecCertificateRef)parents; + CFDataRef cert_issuer = SecCertificateCopyNormalizedIssuerSequence(cert); + require_action_quiet(!CFEqual(cert_issuer, issuer), out, CFReleaseNull(cert_issuer)); + found = items_matching_issuer_parent(cert_issuer, issuers, recurse); + CFReleaseNull(cert_issuer); + } + +out: + CFReleaseNull(query); + CFReleaseNull(parents); + return found; +} + +static OSStatus +_FilterWithIssuers(CFArrayRef issuers, SecCertificateRef cert) +{ + if (!issuers || CFArrayGetCount(issuers) == 0) return errSecParam; + if (!cert) return errSecParam; + + OSStatus status = errSecInternalError; + + /* kSecMatchIssuers matches certificates where ANY certificate in the chain has this issuer. + * So we now need to recursively query the keychain for this cert's parents to determine if + * they match. (This is why we limited the use of this key in _CreateSecItemParamsFromDictionary.) */ + CFDataRef issuer = SecCertificateCopyNormalizedIssuerSequence(cert); + if (items_matching_issuer_parent(issuer, issuers, 10)) { + status = errSecSuccess; + } + + CFReleaseNull(issuer); + return status; +} + static SecKeychainItemRef CopyResolvedKeychainItem(CFTypeRef item) { @@ -3465,16 +3579,17 @@ SecItemSearchCopyNext(SecItemParams *params, CFTypeRef *item) OSStatus status; CFTypeRef search = (params) ? params->search : NULL; CFTypeID typeID = (search) ? CFGetTypeID(search) : 0; - if (typeID == SecIdentitySearchGetTypeID()) { + + if (search && typeID == SecIdentitySearchGetTypeID()) { status = SecIdentitySearchCopyNext((SecIdentitySearchRef)search, (SecIdentityRef*)item); } - else if (typeID == SecKeychainSearchGetTypeID()) { + else if (search && typeID == SecKeychainSearchGetTypeID()) { status = SecKeychainSearchCopyNext((SecKeychainSearchRef)search, (SecKeychainItemRef*)item); // Check if we need to refresh the search for the next key class while (status == errSecItemNotFound && params->assumedKeyClass != NULL) status = UpdateKeychainSearchAndCopyNext(params, item); } - else if (typeID == 0 && (params->useItems || params->itemList)) { + else if (typeID == 0 && params && (params->useItems || params->itemList)) { // No search available, but there is an item list available. // Return the next candidate item from the caller's item list CFArrayRef itemList = (params->useItems) ? params->useItems : params->itemList; @@ -3599,6 +3714,11 @@ FilterCandidateItem(CFTypeRef *item, SecItemParams *itemParams, SecIdentityRef * } // certificate item is trusted on this system } + if (itemParams->matchIssuers) { + status = _FilterWithIssuers((CFArrayRef)itemParams->matchIssuers, (SecCertificateRef) *item); + if (status) goto filterOut; + // certificate item has one of the issuers + } } if (itemParams->itemList) { Boolean foundMatch = FALSE; @@ -3895,10 +4015,7 @@ static Boolean SecItemSynchronizable(CFDictionaryRef query) static Boolean SecItemIsIOSPersistentReference(CFTypeRef value) { if (value) { - /* Synchronizable persistent ref consists of the sqlite rowid and 4-byte class value */ - const CFIndex kSynchronizablePersistentRefLength = sizeof(int64_t) + 4; - return (CFGetTypeID(value) == CFDataGetTypeID() && - CFDataGetLength((CFDataRef)value) == kSynchronizablePersistentRefLength); + return ::_SecItemParsePersistentRef((CFDataRef)value, NULL, NULL, NULL); } return false; } @@ -4212,7 +4329,7 @@ void SecItemParentCachePurge() { CFReleaseNull(gParentCertCacheList); } -static CFArrayRef parentCacheRead(SecCertificateRef certificate) { +static CFArrayRef CF_RETURNS_RETAINED parentCacheRead(SecCertificateRef certificate) { CFArrayRef parents = NULL; CFIndex ix; CFDataRef digest = SecCertificateGetSHA1Digest(certificate); @@ -4261,13 +4378,13 @@ static void parentCacheWrite(SecCertificateRef certificate, CFArrayRef parents) } /* - * SecItemCopyParentCertificates returns an array of zero of more possible + * SecItemCopyParentCertificates_osx returns an array of zero of more possible * issuer certificates for the provided certificate. No cryptographic validation * of the signature is performed in this function; its purpose is only to * provide a list of candidate certificates. */ CFArrayRef -SecItemCopyParentCertificates(SecCertificateRef certificate, void *context) +SecItemCopyParentCertificates_osx(SecCertificateRef certificate, void *context) { #pragma unused (context) /* for now; in future this can reference a container object */ /* Check for parents in keychain cache */ @@ -4328,7 +4445,7 @@ SecItemCopyParentCertificates(SecCertificateRef certificate, void *context) } if ((status != errSecSuccess) && (status != errSecItemNotFound)) { - secitemlog(LOG_WARNING, "SecItemCopyParentCertificates: %d", (int)status); + secitemlog(LOG_WARNING, "SecItemCopyParentCertificates_osx: %d", (int)status); } CFRelease(query); @@ -4346,7 +4463,7 @@ SecItemCopyParentCertificates(SecCertificateRef certificate, void *context) } } } - } else if (resultType == CFDataGetTypeID()) { + } else if (results && resultType == CFDataGetTypeID()) { SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)results); if (cert) { CFArrayAppendValue(result, cert); @@ -4675,7 +4792,10 @@ ShouldTryUnlockKeybag(CFDictionaryRef query, OSErr status) OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result) { - secitemlog(LOG_NOTICE, "SecItemCopyMatching"); + os_activity_t activity = os_activity_create("SecItemCopyMatching", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + if (!query) { return errSecParam; } @@ -4732,7 +4852,10 @@ SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result) OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) { - secitemlog(LOG_NOTICE, "SecItemAdd"); + os_activity_t activity = os_activity_create("SecItemAdd", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + if (!attributes) { return errSecParam; } @@ -4789,7 +4912,10 @@ SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) { - secitemlog(LOG_NOTICE, "SecItemUpdate"); + os_activity_t activity = os_activity_create("SecItemUpdate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + if (!query || !attributesToUpdate) { return errSecParam; } @@ -4860,7 +4986,10 @@ SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) OSStatus SecItemDelete(CFDictionaryRef query) { - secitemlog(LOG_NOTICE, "SecItemDelete"); + os_activity_t activity = os_activity_create("SecItemDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + if (!query) { return errSecParam; } diff --git a/OSX/libsecurity_keychain/lib/SecItemConstants.c b/OSX/libsecurity_keychain/lib/SecItemConstants.c index 92e55064..50657944 100644 --- a/OSX/libsecurity_keychain/lib/SecItemConstants.c +++ b/OSX/libsecurity_keychain/lib/SecItemConstants.c @@ -113,6 +113,16 @@ SEC_CONST_DECL (kSecAttrTombstone, "tomb"); SEC_CONST_DECL (kSecAttrNoLegacy, "nleg"); SEC_CONST_DECL (kSecAttrMultiUser, "musr"); SEC_CONST_DECL (kSecAttrTokenOID, "toid"); +SEC_CONST_DECL (kSecAttrUUID, "UUID"); +SEC_CONST_DECL (kSecAttrPersistantReference, "persistref"); +SEC_CONST_DECL (kSecAttrPersistentReference, "persistref"); +SEC_CONST_DECL (kSecAttrSysBound, "sysb"); +SEC_CONST_DECL (kSecAttrSHA1, "sha1"); + +SEC_CONST_DECL (kSecAttrDeriveSyncIDFromItemAttributes, "dspk"); +SEC_CONST_DECL (kSecAttrPCSPlaintextServiceIdentifier, "pcss"); +SEC_CONST_DECL (kSecAttrPCSPlaintextPublicKey, "pcsk"); +SEC_CONST_DECL (kSecAttrPCSPlaintextPublicIdentity, "pcsi"); /* Predefined access groups constants */ SEC_CONST_DECL (kSecAttrAccessGroupToken, "com.apple.token"); @@ -230,6 +240,8 @@ SEC_CONST_DECL (kSecAttrKeyTypeECDSA, "73"); SEC_CONST_DECL (kSecAttrKeyTypeEC, "73"); /* rdar://13326326 */ SEC_CONST_DECL (kSecAttrKeyTypeECSECPrimeRandom, "73"); SEC_CONST_DECL (kSecAttrKeyTypeAES, "2147483649"); /* */ +SEC_CONST_DECL (kSecAttrKeyTypeECSECPrimeRandomPKA, "2147483678"); /* CSSM_ALGID__FIRST_UNUSED */ +SEC_CONST_DECL (kSecAttrKeyTypeSecureEnclaveAttestation, "2147483679"); /* CSSM_ALGID__FIRST_UNUSED + 1 */ SEC_CONST_DECL (kSecAttrPRFHmacAlgSHA1, "hsha1"); SEC_CONST_DECL (kSecAttrPRFHmacAlgSHA224, "hsha224"); @@ -244,4 +256,3 @@ SEC_CONST_DECL (kSecPrivateKeyAttrs, "private"); SEC_CONST_DECL (kSecPublicKeyAttrs, "public"); /* Used for SecKeyGenerateSymmetric */ SEC_CONST_DECL (kSecSymmetricKeyAttrs, "symmetric"); - diff --git a/OSX/libsecurity_keychain/lib/SecKey.cpp b/OSX/libsecurity_keychain/lib/SecKey.cpp index c346136c..229ee8bb 100644 --- a/OSX/libsecurity_keychain/lib/SecKey.cpp +++ b/OSX/libsecurity_keychain/lib/SecKey.cpp @@ -521,14 +521,14 @@ static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) { } if (result == NULL && key->publicKey()) { - KeyItem *publicKey = new KeyItem(key->publicKey()); + SecPointer publicKey(new KeyItem(key->publicKey())); result = reinterpret_cast(publicKey->handle()); } END_SECKEYAPI } -static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, +static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType &operation, SecKeyAlgorithm algorithm, CSSM_ALGORITHMS &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm, CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) { KeyItem *keyItem = key->key; @@ -586,6 +586,14 @@ static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType o } else { return NULL; } + } else if (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeDecrypt && + CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) { + // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption, + // because CDSA keys refuses to perform decrypt using public key. + operation = kSecKeyOperationTypeEncrypt; + secondaryAlgorithm = CSSM_ALGID_NONE; + paddingAlgorithm = CSSM_PADDING_NONE; + inputSizeLimit = 0; } else { return NULL; } @@ -850,13 +858,10 @@ static OSStatus SecKeyCreatePairInternal( SecPointer pubItem, privItem; if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) { keychain = Keychain::optional(keychainRef); - StLock _(*keychain->getKeychainMutex()); - KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr, - privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem); - } else { - KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr, - privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem); } + StMaybeLock _(keychain ? keychain->getKeychainMutex() : NULL); + KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr, + privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem); // Return the generated keys. if (publicKeyRef) @@ -904,13 +909,24 @@ SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey) // Private APIs // +static ModuleNexus gSecReturnedKeyCSPsMutex; +static std::set gSecReturnedKeyCSPs; + OSStatus SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) { BEGIN_SECAPI SecPointer keyItem(KeyItem::required(keyRef)); - Required(cspHandle) = keyItem->csp()->handle(); + + // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). + // Keep a global pointer to it to force the CSP to stay live forever. + CssmClient::CSP returnedKeyCSP = keyItem->csp(); + { + StLock _(gSecReturnedKeyCSPsMutex()); + gSecReturnedKeyCSPs.insert(returnedKeyCSP); + } + Required(cspHandle) = returnedKeyCSP->handle(); END_SECAPI } @@ -1076,13 +1092,19 @@ static u_int32_t ConvertCFStringToInteger(CFStringRef ref) // figure out the size of the string CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8); - char buffer[numChars]; + char *buffer = (char *)malloc(numChars); + if (NULL == buffer) { + UnixError::throwMe(ENOMEM); + } if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8)) { + free(buffer); MacOSError::throwMe(errSecParam); } - return atoi(buffer); + u_int32_t result = atoi(buffer); + free(buffer); + return result; } @@ -1439,6 +1461,7 @@ static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef t SecKeychainAttribute attributes[numToModify]; int i = 0; + void *data = NULL; if (label != NULL) { @@ -1448,11 +1471,12 @@ static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef t attributes[i].data = (void*) CFStringGetCStringPtr(label_string, kCFStringEncodingUTF8); if (NULL == attributes[i].data) { CFIndex buffer_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string), kCFStringEncodingUTF8); - attributes[i].data = alloca((size_t)buffer_length); + data = attributes[i].data = malloc((size_t)buffer_length); if (NULL == attributes[i].data) { UnixError::throwMe(ENOMEM); } if (!CFStringGetCString(label_string, static_cast(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) { + free(data); MacOSError::throwMe(errSecParam); } } @@ -1479,8 +1503,14 @@ static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef t attrList.count = numToModify; attrList.attr = attributes; - - return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL); + + OSStatus result = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL); + if (data) + { + free(data); + } + + return result; } @@ -1823,18 +1853,18 @@ SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error) } else { // we can set the label attributes on the generated key if it's a keychain item - size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 0; + size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 1; char *labelBuf = (char *)malloc(labelBufLen); - size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 0; + size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 1; char *appLabelBuf = (char *)malloc(appLabelBufLen); - size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 0; + size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 1; char *appTagBuf = (char *)malloc(appTagBufLen); - if (label && !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8)) + if (!label || !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8)) labelBuf[0]=0; - if (appLabel && !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8)) + if (!appLabel || !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8)) appLabelBuf[0]=0; - if (appTag && !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8)) + if (!appTag || !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8)) appTagBuf[0]=0; SecKeychainAttribute attrs[] = { @@ -1918,6 +1948,7 @@ SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef * CFRelease(ka); return sk; } else { + CFRelease(ka); if (error) { *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL); } @@ -1979,7 +2010,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr /* Pick Values from parameters */ if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL); + } goto errOut; } @@ -1995,7 +2028,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr saltLen = CFDataGetLength(saltDictValue); if((salt = (uint8_t *) malloc(saltLen)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + } goto errOut; } @@ -2003,13 +2038,17 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1; if((thePassword = (char *) malloc(passwordLen)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + } goto errOut; } CFStringGetBytes(password, CFRangeMake(0, CFStringGetLength(password)), kCFStringEncodingUTF8, '?', FALSE, (UInt8*)thePassword, passwordLen, &passwordLen); if((derivedKey = (uint8_t *) malloc(derivedKeyLen)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + } goto errOut; } @@ -2037,7 +2076,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr } if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); + } goto errOut; } diff --git a/OSX/libsecurity_keychain/lib/SecKeychain.cpp b/OSX/libsecurity_keychain/lib/SecKeychain.cpp index 842c2dfe..c6427967 100644 --- a/OSX/libsecurity_keychain/lib/SecKeychain.cpp +++ b/OSX/libsecurity_keychain/lib/SecKeychain.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "TokenLogin.h" @@ -42,7 +43,10 @@ OSStatus SecKeychainMDSInstall() { - BEGIN_SECAPI + BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Security::MDSClient::Directory d; d.install(); @@ -76,6 +80,9 @@ 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(); @@ -88,6 +95,9 @@ SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subse 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_scope(activity); + os_release(activity); // range check parameters RequiredParam (guid); @@ -110,6 +120,9 @@ SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *passw 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_scope(activity); + os_release(activity); KCThrowParamErrIf_(!pathName); Keychain keychain = globals().storageManager.make(pathName, true, true); @@ -134,6 +147,9 @@ 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_scope(activity); + os_release(activity); KCThrowIf_(!keychainOrArray, errSecInvalidKeychain); StorageManager::KeychainList keychains; @@ -149,6 +165,9 @@ 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_scope(activity); + os_release(activity); Keychain keychain = Keychain::optional(keychainRef); if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) @@ -166,6 +185,9 @@ 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_scope(activity); + os_release(activity); Keychain keychain = Keychain::optional(keychainRef); if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) @@ -186,6 +208,9 @@ 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_scope(activity); + os_release(activity); Keychain keychain = Keychain::optional(keychainRef); @@ -202,6 +227,9 @@ 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_scope(activity); + os_release(activity); Keychain keychain = Keychain::optional(keychainRef); keychain->lock(); @@ -214,6 +242,9 @@ OSStatus SecKeychainLockAll(void) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); globals().storageManager.lockAll(); @@ -224,6 +255,9 @@ 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_scope(activity); + os_release(activity); // // Get the current user (using fallback method if necessary) // @@ -284,6 +318,9 @@ 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_scope(activity); + os_release(activity); globals().storageManager.defaultKeychain(Keychain::optional(keychainRef)); @@ -293,6 +330,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(searchList); StorageManager &smr = globals().storageManager; @@ -306,6 +346,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(searchList); StorageManager &smr = globals().storageManager; @@ -319,6 +362,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle(); @@ -328,6 +374,9 @@ 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_scope(activity); + os_release(activity); globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef)); @@ -350,6 +399,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(searchList); StorageManager &smr = globals().storageManager; @@ -363,6 +415,9 @@ 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_scope(activity); + os_release(activity); globals().storageManager.domain(domain); @@ -372,6 +427,9 @@ 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_scope(activity); + os_release(activity); *domain = globals().storageManager.domain(); @@ -427,6 +485,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(masterKeyFilename); Keychain kc = Keychain::optional(keychain); @@ -522,6 +583,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(callbackFunction); CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext); @@ -534,6 +598,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(callbackFunction); CCallbackMgr::RemoveCallback(callbackFunction); @@ -545,6 +612,9 @@ 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_scope(activity); + os_release(activity); KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); // @@@ Get real itemClass @@ -604,6 +674,9 @@ 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_scope(activity); + os_release(activity); StorageManager::KeychainList keychains; globals().storageManager.optionalSearchList(keychainOrArray, keychains); @@ -680,6 +753,9 @@ 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_scope(activity); + os_release(activity); KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); // @@@ Get real itemClass @@ -690,17 +766,7 @@ SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLeng { CssmData service(const_cast(reinterpret_cast(serviceName)), serviceNameLength); item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service); - // use service name as default label (UNLESS the service is iTools and we have an account name [3787371]) - const char *iTools = "iTools"; - if (accountNameLength && serviceNameLength==strlen(iTools) && !memcmp(serviceName, iTools, serviceNameLength)) - { - CssmData account(const_cast(reinterpret_cast(accountName)), accountNameLength); - item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), account); - } - else - { - item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); - } + item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); } if (accountName && accountNameLength) @@ -736,6 +802,9 @@ 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_scope(activity); + os_release(activity); StorageManager::KeychainList keychains; globals().storageManager.optionalSearchList(keychainOrArray, keychains); @@ -805,6 +874,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(dldbHandle); @@ -814,6 +886,8 @@ SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHand END_SECAPI } +static ModuleNexus gSecReturnedKeyCSPsMutex; +static std::set gSecReturnedKeychainCSPs; OSStatus SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle) @@ -823,7 +897,15 @@ SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle) RequiredParam(cspHandle); Keychain keychain = Keychain::optional(keychainRef); - *cspHandle = keychain->csp()->handle(); + + // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). + // Keep a global pointer to it to force the CSP to stay live forever. + CssmClient::CSP returnedKeychainCSP = keychain->csp(); + { + StLock _(gSecReturnedKeyCSPsMutex()); + gSecReturnedKeychainCSPs.insert(returnedKeychainCSP); + } + *cspHandle = returnedKeychainCSP->handle(); END_SECAPI } @@ -858,6 +940,9 @@ 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_scope(activity); + os_release(activity); Keychain keychain = Keychain::optional(keychainRef); keychain->changePassphrase (oldPasswordLength, oldPassword, newPasswordLength, newPassword); @@ -870,6 +955,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle(); @@ -881,6 +969,9 @@ 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_scope(activity); + os_release(activity); try { @@ -914,6 +1005,9 @@ 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_scope(activity); + os_release(activity); try { @@ -938,6 +1032,9 @@ OSStatus SecKeychainLogout() { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); globals().storageManager.logout(); @@ -980,6 +1077,9 @@ 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_scope(activity); + os_release(activity); StorageManager::KeychainList singleton; singleton.push_back(KeychainImpl::required(keychainRef)); globals().storageManager.remove(singleton); @@ -991,6 +1091,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(inPassword); KeychainImpl::required(keychainRef)->create(passwordLength, inPassword); END_SECAPI @@ -1001,6 +1104,9 @@ 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_scope(activity); + os_release(activity); // do error checking for required parameters RequiredParam(dbBlobArray); @@ -1076,6 +1182,9 @@ 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_scope(activity); + os_release(activity); // do error checking for required parameters RequiredParam(keychainSignature); @@ -1100,6 +1209,9 @@ 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_scope(activity); + os_release(activity); // do error checking for required parameters RequiredParam(dbBlob); @@ -1119,6 +1231,9 @@ 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_scope(activity); + os_release(activity); KCThrowParamErrIf_(!fullPathName); KCThrowParamErrIf_(!dbBlob); @@ -1143,6 +1258,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(dbName); StorageManager &smr = globals().storageManager; @@ -1167,6 +1285,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(dbName); StorageManager &smr = globals().storageManager; smr.removeFromDomainList(domain, dbName, *guid, subServiceType); @@ -1185,6 +1306,9 @@ 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_scope(activity); + os_release(activity); RequiredParam(kcRef); Keychain keychain = Keychain::optional(kcRef); keychain->setBatchMode(mode, rollback); @@ -1202,6 +1326,9 @@ OSStatus SecKeychainCleanupHandles() 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_scope(activity); + os_release(activity); SecurityServer::ClientSession().verifyKeyStorePassphrase(retries); END_SECAPI } @@ -1209,6 +1336,9 @@ 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_scope(activity); + os_release(activity); SecurityServer::ClientSession().changeKeyStorePassphrase(); END_SECAPI } @@ -1216,6 +1346,9 @@ 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_scope(activity); + os_release(activity); // make a keychain object "wrapper" for this keychain ref Keychain keychain = Keychain::optional(userKeychainRef); @@ -1431,6 +1564,9 @@ 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); if(attempts) { SecurityServer::ClientSession().getUserPromptAttempts(*attempts); diff --git a/OSX/libsecurity_keychain/lib/SecKeychain.h b/OSX/libsecurity_keychain/lib/SecKeychain.h index a27af901..1a2d3fd1 100644 --- a/OSX/libsecurity_keychain/lib/SecKeychain.h +++ b/OSX/libsecurity_keychain/lib/SecKeychain.h @@ -606,7 +606,8 @@ OSStatus SecKeychainGetDLDBHandle(SecKeychainRef __nullable keychain, CSSM_DL_DB @param access On return, a pointer to the access reference. @result A result code. See "Security Error Codes" (SecBase.h). */ -OSStatus SecKeychainCopyAccess(SecKeychainRef __nullable keychain, SecAccessRef * __nonnull CF_RETURNS_RETAINED access); +OSStatus SecKeychainCopyAccess(SecKeychainRef __nullable keychain, SecAccessRef * __nonnull CF_RETURNS_RETAINED access) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_13, __IPHONE_NA, __IPHONE_NA); /*! @function SecKeychainSetAccess @@ -615,7 +616,8 @@ OSStatus SecKeychainCopyAccess(SecKeychainRef __nullable keychain, SecAccessRef @param access An access reference. @result A result code. See "Security Error Codes" (SecBase.h). */ -OSStatus SecKeychainSetAccess(SecKeychainRef __nullable keychain, SecAccessRef access); +OSStatus SecKeychainSetAccess(SecKeychainRef __nullable keychain, SecAccessRef access) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_13, __IPHONE_NA, __IPHONE_NA); CF_ASSUME_NONNULL_END diff --git a/OSX/libsecurity_keychain/lib/SecKeychainAddIToolsPassword.cpp b/OSX/libsecurity_keychain/lib/SecKeychainAddIToolsPassword.cpp index 5983311a..db82b83a 100644 --- a/OSX/libsecurity_keychain/lib/SecKeychainAddIToolsPassword.cpp +++ b/OSX/libsecurity_keychain/lib/SecKeychainAddIToolsPassword.cpp @@ -32,74 +32,15 @@ #include #include #include -#include "SecBridge.h" #include -#include -OSStatus SecKeychainAddIToolsPassword(SecKeychainRef keychain, UInt32 accountNameLength, const char *accountName, - UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) +OSStatus SecKeychainAddIToolsPassword(SecKeychainRef __unused keychain, + UInt32 __unused accountNameLength, + const char * __unused accountName, + UInt32 __unused passwordLength, + const void * __unused passwordData, + SecKeychainItemRef * __unused itemRef) { - BEGIN_SECAPI - - const char *serviceUTF8 = "iTools"; - - // create the initial ACL label string (use the account name, not "iTools") - CFRef itemLabel = CFStringCreateWithBytes(kCFAllocatorDefault, - (const UInt8 *)accountName, accountNameLength, kCFStringEncodingUTF8, FALSE); - - // accumulate applications in this list - CFRef apps = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - - // add entries for application groups - CFRef dotMacGroup, accountsGroup; - MacOSError::check(SecTrustedApplicationCreateApplicationGroup("dot-mac", NULL, &dotMacGroup.aref())); - CFArrayAppendValue(apps, dotMacGroup); - MacOSError::check(SecTrustedApplicationCreateApplicationGroup("InternetAccounts", NULL, &accountsGroup.aref())); - CFArrayAppendValue(apps, accountsGroup); - - // now add "myself" as an ordinary application - CFRef myself; - MacOSError::check(SecTrustedApplicationCreateFromPath(NULL, &myself.aref())); - CFArrayAppendValue(apps, myself); - - // now add the pre-cooked list of .Mac applications for systems that don't understand the group semantics - if (CFRef myBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"))) - if (CFRef url = CFBundleCopyResourceURL(myBundle, - CFSTR("iToolsTrustedApps"), CFSTR("plist"), NULL)) { - CFRef data; - if (CFURLCreateDataAndPropertiesFromResource(NULL, url, &data.aref(), NULL, NULL, NULL)) - if (CFRef list = - CFArrayRef(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL))) { - CFIndex size = CFArrayGetCount(list); - for (CFIndex n = 0; n < size; n++) { - CFStringRef path = (CFStringRef)CFArrayGetValueAtIndex(list, n); - CFRef app; - if (SecTrustedApplicationCreateFromPath(cfString(path).c_str(), &app.aref()) == errSecSuccess) - CFArrayAppendValue(apps, app); - } - } - } - - // form a SecAccess from this - CFRef access; - MacOSError::check(SecAccessCreate(itemLabel, (CFArrayRef)apps, &access.aref())); - - // set up attribute vector (each attribute consists of {tag, length, pointer}) - SecKeychainAttribute attrs[] = { - { kSecLabelItemAttr, accountNameLength, (char *)accountName }, // use the account name as the label for display purposes [3787371] - { kSecAccountItemAttr, accountNameLength, (char *)accountName }, - { kSecServiceItemAttr, (UInt32)strlen(serviceUTF8), (char *)serviceUTF8 } - }; - SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; - - return SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, - &attributes, - passwordLength, - (const char *)passwordData, - keychain, - access, - itemRef); - - END_SECAPI + return errSecParam; } diff --git a/OSX/libsecurity_keychain/lib/SecKeychainItem.cpp b/OSX/libsecurity_keychain/lib/SecKeychainItem.cpp index ca8f3623..dea894f9 100644 --- a/OSX/libsecurity_keychain/lib/SecKeychainItem.cpp +++ b/OSX/libsecurity_keychain/lib/SecKeychainItem.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "SecBridge.h" #include "KCExceptions.h" @@ -91,6 +92,9 @@ SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAttributeLis SecAccessRef initialAccess, SecKeychainItemRef *itemRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemCreateFromContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); KCThrowParamErrIf_(length!=0 && data==NULL); Item item(itemClass, attrList, length, data); @@ -124,6 +128,9 @@ OSStatus SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data) { 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); Item item = ItemImpl::required(__itemImplRef); item->modifyContent(attrList, length, data); @@ -136,6 +143,9 @@ OSStatus SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemCopyContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Item item = ItemImpl::required(__itemImplRef); item->getContent(itemClass, attrList, length, outData); @@ -148,6 +158,9 @@ OSStatus SecKeychainItemFreeContent(SecKeychainAttributeList *attrList, void *data) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemFreeContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); ItemImpl::freeContent(attrList, data); @@ -159,6 +172,9 @@ OSStatus SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data) { 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); Item item = ItemImpl::required(__itemImplRef); item->modifyAttributesAndData(attrList, length, data); @@ -194,6 +210,9 @@ OSStatus SecKeychainItemDelete(SecKeychainItemRef itemRef) { 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); Item item = ItemImpl::required(__itemImplRef); Keychain keychain = item->keychain(); @@ -245,6 +264,9 @@ SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef destKeychai SecAccessRef initialAccess, SecKeychainItemRef *itemCopy) { 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); Item copy = ItemImpl::required(__itemImplRef)->copyTo(Keychain::optional(destKeychainRef), Access::optional(initialAccess)); if (itemCopy) { @@ -259,6 +281,9 @@ OSStatus SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef, const CSSM_DB_UNIQUE_RECORD **uniqueRecordID) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemGetUniqueRecordID", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Required(uniqueRecordID) = ItemImpl::required(__itemImplRef)->dbUniqueRecord(); @@ -270,6 +295,9 @@ OSStatus SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef, CSSM_DL_DB_HANDLE* dldbHandle) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); *dldbHandle = ItemImpl::required(__itemImplRef)->keychain()->database()->handle(); @@ -308,6 +336,9 @@ OSStatus SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef* accessRef) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemCopyAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Required(accessRef); // preflight SecPointer access = new Access(*aclBearer(reinterpret_cast(__itemImplRef))); @@ -321,6 +352,9 @@ OSStatus SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef accessRef) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemSetAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Access::required(accessRef)->setAccess(*aclBearer(reinterpret_cast(__itemImplRef)), true); @@ -332,9 +366,16 @@ SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef accessRef) OSStatus SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef, SecAccessRef accessRef, UInt32 passwordLength, const void * password) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemSetAccessWithPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); OSStatus result; + if(!__itemImplRef) { + return errSecParam; + } + // try to unlock the keychain with this password first SecKeychainRef kc = NULL; result = SecKeychainItemCopyKeychain(__itemImplRef, &kc); @@ -363,6 +404,9 @@ OSStatus SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef, SecAcc OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const void* data) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemSetData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); ItemImpl::required(__itemImplRef)->setData(length, data); @@ -375,6 +419,9 @@ OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, void* data, UInt32* actualLength) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemGetData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); /* The caller either needs to specify data and maxLength or an actualLength, * so we return either the data itself or the actual length of the data or both. @@ -404,6 +451,9 @@ OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, vo OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemUpdate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); ItemImpl::required(__itemImplRef)->update(); @@ -415,6 +465,9 @@ OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef) OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef itemRef) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemAddNoUI", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Item item = ItemImpl::required(__itemImplRef); Keychain::optional(keychainRef)->add(item); @@ -427,6 +480,9 @@ OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef i OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemAdd", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Item item = ItemImpl::required(__itemImplRef); Keychain defaultKeychain = globals().storageManager.defaultKeychainUI(item); @@ -440,6 +496,9 @@ OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef) OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, SecKeychainItemRef* itemRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); RequiredParam(itemRef) = Item(itemClass, itemCreator, length, data, false)->handle(); @@ -451,6 +510,9 @@ OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UI OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute, UInt32* actualLength) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemGetAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); ItemImpl::required(__itemImplRef)->getAttribute(RequiredParam(attribute), actualLength); @@ -462,6 +524,9 @@ OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttr OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemSetAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); ItemImpl::required(__itemImplRef)->setAttribute(RequiredParam(attribute)); @@ -476,6 +541,9 @@ OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttr OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef, SecKeychainItemRef *itemRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemFindFirst", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); KCCursor cursor; if (keychainRef) { @@ -619,6 +687,9 @@ OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CF // otherwise, not a certificate, so proceed as usual for keychain item BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemCreatePersistentReference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Item item = ItemImpl::required(itemRef); item->copyPersistentReference(*persistentItemRef, false); END_SECAPI @@ -627,6 +698,9 @@ OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CF OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemCopyFromPersistentReference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); KCThrowParamErrIf_(!persistentItemRef || !itemRef); // first, query the iOS keychain @@ -696,6 +770,9 @@ OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataRef *recordIdentifier) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemCopyRecordIdentifier", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); CSSM_DATA data; RequiredParam (recordIdentifier); @@ -713,6 +790,9 @@ SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef, CFDataRef recordIdentifier) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemCopyFromRecordIdentifier", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); // make a local Keychain reference RequiredParam (keychainRef); @@ -768,6 +848,9 @@ OSStatus SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass, SecAccessRef initialAccess, SecKeychainItemRef *itemRef, CFDataRef *localID) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemCreateFromEncryptedContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); KCThrowParamErrIf_(length!=0 && data==NULL); RequiredParam (localID); @@ -839,6 +922,9 @@ OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRe UInt32 *length, void **outData) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemCopyAttributesAndEncryptedData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Item item = ItemImpl::required(__itemImplRef); item->doNotEncrypt (); @@ -850,6 +936,9 @@ OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRe OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 length, const void *data) { BEGIN_SECKCITEMAPI + os_activity_t activity = os_activity_create("SecKeychainItemModifyEncryptedData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Item item = ItemImpl::required(__itemImplRef); item->doNotEncrypt (); diff --git a/OSX/libsecurity_keychain/lib/SecKeychainItemExtendedAttributes.cpp b/OSX/libsecurity_keychain/lib/SecKeychainItemExtendedAttributes.cpp index 0088d0de..60c98f31 100644 --- a/OSX/libsecurity_keychain/lib/SecKeychainItemExtendedAttributes.cpp +++ b/OSX/libsecurity_keychain/lib/SecKeychainItemExtendedAttributes.cpp @@ -28,6 +28,7 @@ #include "SecBridge.h" #include "StorageManager.h" #include "KCCursor.h" +#include /* I'm not sure we need this */ #if 0 @@ -147,6 +148,9 @@ OSStatus SecKeychainItemSetExtendedAttribute( //%%% This needs to detect SecCertificateRef items, and when it does, SecKeychainItemDelete must be updated BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemSetExtendedAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); if((itemRef == NULL) || (attrName == NULL)) { return errSecParam; @@ -197,6 +201,9 @@ OSStatus SecKeychainItemCopyExtendedAttribute( //%%% This needs to detect SecCertificateRef items BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemCopyExtendedAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); if((itemRef == NULL) || (attrName == NULL) || (attrValue == NULL)) { return errSecParam; @@ -238,6 +245,9 @@ OSStatus SecKeychainItemCopyAllExtendedAttributes( //%%% This needs to detect SecCertificateRef items, and when it does, SecKeychainItemDelete must be updated BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainItemCopyAllExtendedAttributes", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); if((itemRef == NULL) || (attrNames == NULL)) { return errSecParam; diff --git a/OSX/libsecurity_keychain/lib/SecKeychainSearch.cpp b/OSX/libsecurity_keychain/lib/SecKeychainSearch.cpp index 32d8c6f6..5e94b58c 100644 --- a/OSX/libsecurity_keychain/lib/SecKeychainSearch.cpp +++ b/OSX/libsecurity_keychain/lib/SecKeychainSearch.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "SecBridge.h" @@ -47,6 +48,9 @@ OSStatus SecKeychainSearchCreateFromAttributes(CFTypeRef keychainOrArray, SecItemClass itemClass, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSearchCreateFromAttributes", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Required(searchRef); @@ -63,6 +67,9 @@ OSStatus SecKeychainSearchCreateFromAttributesExtended(CFTypeRef keychainOrArray, SecItemClass itemClass, const SecKeychainAttributeList *attrList, CSSM_DB_CONJUNCTIVE dbConjunctive, CSSM_DB_OPERATOR dbOperator, SecKeychainSearchRef *searchRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSearchCreateFromAttributesExtended", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Required(searchRef); // Make sure that searchRef is an invalid SearchRef @@ -81,6 +88,9 @@ OSStatus SecKeychainSearchCopyNext(SecKeychainSearchRef searchRef, SecKeychainItemRef *itemRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecKeychainSearchCopyNext", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); RequiredParam(itemRef); Item item; diff --git a/OSX/libsecurity_keychain/lib/SecPassword.cpp b/OSX/libsecurity_keychain/lib/SecPassword.cpp index 477c9bac..6ac71ed4 100644 --- a/OSX/libsecurity_keychain/lib/SecPassword.cpp +++ b/OSX/libsecurity_keychain/lib/SecPassword.cpp @@ -30,6 +30,8 @@ #include #include +#include + #if 0 static CFTypeID SecPasswordGetTypeID(void) @@ -46,6 +48,9 @@ OSStatus SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList, SecPasswordRef *itemRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecGenericPasswordCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); KCThrowParamErrIf_( (itemRef == NULL) ); KCThrowParamErrIf_( (searchAttrList == NULL) ^ (itemAttrList == NULL) ); // Both or neither @@ -60,6 +65,9 @@ OSStatus SecPasswordSetInitialAccess(SecPasswordRef itemRef, SecAccessRef accessRef) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecPasswordSetInitialAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); PasswordImpl::required(itemRef)->setAccess(Access::required(accessRef)); END_SECAPI } @@ -68,6 +76,9 @@ OSStatus SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt32 *length, const void **data) { BEGIN_SECAPI + os_activity_t activity = os_activity_create("SecPasswordAction", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); + os_activity_scope(activity); + os_release(activity); Password passwordRef = PasswordImpl::required(itemRef); @@ -235,8 +246,10 @@ SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt3 } } } - - AuthorizationFreeItemSet(returnedInfo); + + if(returnedInfo) { + AuthorizationFreeItemSet(returnedInfo); + } AuthorizationFree(authRef, 0); } diff --git a/OSX/libsecurity_keychain/lib/SecPolicy.cpp b/OSX/libsecurity_keychain/lib/SecPolicy.cpp index 273cfc29..f4d09996 100644 --- a/OSX/libsecurity_keychain/lib/SecPolicy.cpp +++ b/OSX/libsecurity_keychain/lib/SecPolicy.cpp @@ -242,12 +242,12 @@ static bool SecPolicyGetCSSMDataValueForString(SecPolicyRef policyRef, CFStringR // stash this in a place where it will be released when the policy is destroyed if (policyRef) { SecPolicySetOptionsValue(policyRef, CFSTR("policy_data"), data); - CFRelease(data); } else { syslog(LOG_ERR, "WARNING: policy dictionary not found to store returned data; will leak!"); } } + CFReleaseNull(data); return true; } @@ -575,22 +575,35 @@ SecPolicyCreateWithOID(CFTypeRef policyOID) CFArrayRef SecPolicyCreateAppleTimeStampingAndRevocationPolicies(CFTypeRef policyOrArray) { - /* implement with unified SecPolicyRef instances */ - SecPolicyRef policy = NULL; CFMutableArrayRef resultPolicyArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (!resultPolicyArray) { return NULL; } - policy = SecPolicyCreateWithProperties(kSecPolicyAppleTimeStamping, NULL); - if (policy) { - CFArrayAppendValue(resultPolicyArray, policy); - CFReleaseNull(policy); + SecPolicyRef tsPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleTimeStamping, NULL); + if (tsPolicy) { + CFArrayAppendValue(resultPolicyArray, tsPolicy); + CFReleaseNull(tsPolicy); } - policy = SecPolicyCreateWithProperties(kSecPolicyAppleRevocation, NULL); - if (policy) { - CFArrayAppendValue(resultPolicyArray, policy); - CFReleaseNull(policy); + + /* check the provided argument for a revocation policy */ + CFMutableArrayRef policies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (policies && policyOrArray) { + if (CFGetTypeID(policyOrArray) == SecPolicyGetTypeID()) { + CFArrayAppendValue(policies, policyOrArray); + } else if (CFGetTypeID(policyOrArray) == CFArrayGetTypeID()) { + CFIndex arrayLength = CFArrayGetCount((CFArrayRef)policyOrArray); + CFArrayAppendArray(policies, (CFArrayRef)policyOrArray, CFRangeMake(0, arrayLength)); + } + } + CFIndex numPolicies = (policies) ? CFArrayGetCount(policies) : 0; + for (CFIndex index=0; index #include #include +#include #include #include #include @@ -89,19 +90,17 @@ sec_debug_imp(int level, const char *funcname, char *format, ...) { // Read /dev/random for random bytes static CFDataRef -getRandomBytes(size_t len) +createRandomBytes(size_t len) { - uint8_t *buffer; - CFDataRef randData = NULL; - int fdrand; - - if((buffer = malloc(len)) == NULL) return NULL; - if((fdrand = open("/dev/random", O_RDONLY)) == -1) return NULL; - if(read(fdrand, buffer, len) == len) randData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *) buffer, len); - close(fdrand); - - free(buffer); - return randData; + CFMutableDataRef data = CFDataCreateMutable(NULL, len); + if (data == NULL) + return NULL; + CFDataSetLength(data, len); + if (SecRandomCopyBytes(kSecRandomDefault, len, CFDataGetMutableBytePtr(data)) != noErr) { + CFRelease(data); + return NULL; + } + return data; } // This is the normalization routine - subject to change. We need to make sure that whitespace is removed and @@ -132,7 +131,8 @@ static void secNormalize(CFMutableStringRef theString, CFLocaleRef theLocale) #define MAXANSWERBUFF 4096 #define PBKDF_ROUNDS 100000 -static SecKeyRef secDeriveKeyFromAnswers(CFArrayRef answers, CFLocaleRef theLocale) +static SecKeyRef CF_RETURNS_RETAINED +secDeriveKeyFromAnswers(CFArrayRef answers, CFLocaleRef theLocale) { static const uint8_t salt[16] = { 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F }; static const int saltLen = sizeof(salt); @@ -210,7 +210,7 @@ static SecKeyRef secDeriveKeyFromAnswers(CFArrayRef answers, CFLocaleRef theLoca // Single shot CFString processing routines for digests/encoding/encrypt/decrypt static CFDataRef -digestString(CFStringRef str) +createDigestString(CFStringRef str) { CFDataRef retval = NULL; CFErrorRef error = NULL; @@ -223,12 +223,14 @@ digestString(CFStringRef str) if(error == NULL) { retval = SecTransformExecute(digestTrans, &error); if(retval == NULL) { - secDebug(ASL_LEVEL_ERR, "Couldn't create digest %s\n", CFStringGetCStringPtr(CFErrorCopyFailureReason(error), kCFStringEncodingUTF8)); + CFStringRef errorReason = CFErrorCopyFailureReason(error); + secDebug(ASL_LEVEL_ERR, "Couldn't create digest %s\n", CFStringGetCStringPtr(errorReason, kCFStringEncodingUTF8)); + CFReleaseNull(errorReason); } } - CFRelease(digestTrans); } - CFRelease(inputString); + CFReleaseNull(digestTrans); + CFReleaseNull(inputString); return retval; } @@ -256,7 +258,7 @@ b64decode(CFDataRef input) return retval; } -static CFDataRef +static CFDataRef CF_RETURNS_RETAINED encryptString(SecKeyRef wrapKey, CFDataRef iv, CFStringRef str) { CFDataRef retval = NULL; @@ -354,7 +356,7 @@ createIVFromPassword(CFStringRef password) { CFDataRef hashedPassword, retval; CFMutableDataRef iv; - if((hashedPassword = digestString(password)) == NULL) return NULL; + if((hashedPassword = createDigestString(password)) == NULL) return NULL; iv = CFDataCreateMutableCopy(kCFAllocatorDefault, CFDataGetLength(hashedPassword)+1, hashedPassword); CFDataDeleteBytes(iv, CFRangeMake(IVBYTECOUNT, CFDataGetLength(iv)-IVBYTECOUNT)); retval = CFDataCreateCopy(kCFAllocatorDefault, iv); @@ -375,54 +377,66 @@ createIVFromPassword(CFStringRef password) * recovery dictionary. */ -CFDictionaryRef +CFDictionaryRef CF_RETURNS_RETAINED SecWrapRecoveryPasswordWithAnswers(CFStringRef password, CFArrayRef questions, CFArrayRef answers) { uint32_t vers = 1; - CFDataRef iv; - CFDataRef wrappedPassword; + CFDataRef iv = NULL; + CFDataRef wrappedPassword = NULL; CFMutableDictionaryRef retval = NULL; CFLocaleRef theLocale = CFLocaleCopyCurrent(); CFStringRef theLocaleString = CFLocaleGetIdentifier(theLocale); + SecKeyRef wrapKey = NULL; CFIndex ix, limit; - if (!password || !questions || !answers) - return NULL; + if (!password || !questions || !answers) { + goto error; + } limit = CFArrayGetCount(answers); - if (limit != CFArrayGetCount(questions)) - return NULL; // Error + if (limit != CFArrayGetCount(questions)) { + goto error; + } CFTypeRef chkval; for (ix=0; ixflags; - CFMutableDictionaryRef filteredException = ctx->filteredException; - CFStringRef keystr = (CFStringRef)key; - - if (ctx->oldException && CFDictionaryContainsKey(ctx->oldException, key)) { - // Keep existing exception in filtered dictionary, regardless of options - CFDictionaryAddValue(filteredException, key, CFDictionaryGetValue(ctx->oldException, key)); - return; - } - - bool allowed = false; - - if (CFEqual(keystr, CFSTR("SHA1Digest"))) { - allowed = true; // this key is informational and always permitted - } - else if (CFEqual(keystr, CFSTR("NotValidBefore"))) { - allowed = ((options & kSecTrustOptionAllowExpired) != 0); - } - else if (CFEqual(keystr, CFSTR("ValidLeaf"))) { - allowed = ((options & kSecTrustOptionAllowExpired) != 0); - } - else if (CFEqual(keystr, CFSTR("ValidIntermediates"))) { - allowed = ((options & kSecTrustOptionAllowExpired) != 0); - } - else if (CFEqual(keystr, CFSTR("ValidRoot"))) { - if (((options & kSecTrustOptionAllowExpired) != 0) || - ((options & kSecTrustOptionAllowExpiredRoot) != 0)) { - allowed = true; - } - } - else if (CFEqual(keystr, CFSTR("AnchorTrusted"))) { - bool implicitAnchors = ((options & kSecTrustOptionImplicitAnchors) != 0); - // Implicit anchors option only filters exceptions for self-signed certs - if (implicitAnchors && ctx->trustRef && - (ctx->certIX < SecTrustGetCertificateCount(ctx->trustRef))) { - Boolean isSelfSigned = false; - SecCertificateRef cert = SecTrustGetCertificateAtIndex(ctx->trustRef, ctx->certIX); - if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) && - isSelfSigned) { - allowed = true; - } - } - } - else if (CFEqual(keystr, CFSTR("KeyUsage")) || - CFEqual(keystr, CFSTR("ExtendedKeyUsage")) || - CFEqual(keystr, CFSTR("BasicConstraints")) || - CFEqual(keystr, CFSTR("NonEmptySubject")) || - CFEqual(keystr, CFSTR("IdLinkage"))) { - // Cannot override these exceptions - allowed = false; - } - else { - // Unhandled exceptions should not be overridden, - // but we want to know which ones we're missing - char *cstr = CFStringToCString(keystr); - syslog(LOG_ERR, "Unfiltered exception: %s", (cstr) ? cstr : ""); - if (cstr) { free(cstr); } - allowed = false; - } - - if (allowed) { - CFDictionaryAddValue(filteredException, key, value); - } -} - -/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ -OSStatus -SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options) -{ - /* bridge to support API functionality for legacy callers */ - OSStatus status = errSecSuccess; - CFDataRef encodedExceptions = SecTrustCopyExceptions(trustRef); - CFArrayRef exceptions = NULL, - oldExceptions = SecTrustGetTrustExceptionsArray(trustRef); - - if (encodedExceptions) { - exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault, - encodedExceptions, kCFPropertyListImmutable, NULL, NULL); - CFRelease(encodedExceptions); - encodedExceptions = NULL; - } - - if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) { - CFRelease(exceptions); - exceptions = NULL; - } - - if (oldExceptions && exceptions && - CFArrayGetCount(oldExceptions) > CFArrayGetCount(exceptions)) { - oldExceptions = NULL; - } - - /* verify both exceptions are for the same leaf */ - if (oldExceptions && exceptions && CFArrayGetCount(oldExceptions) > 0) { - CFDictionaryRef oldLeafExceptions = (CFDictionaryRef)CFArrayGetValueAtIndex(oldExceptions, 0); - CFDictionaryRef leafExceptions = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, 0); - CFDataRef oldDigest = (CFDataRef)CFDictionaryGetValue(oldLeafExceptions, CFSTR("SHA1Digest")); - CFDataRef digest = (CFDataRef)CFDictionaryGetValue(leafExceptions, CFSTR("SHA1Digest")); - if (!oldDigest || !digest || !CFEqual(oldDigest, digest)) { - oldExceptions = NULL; - } - } - - /* add only those exceptions which are allowed by the supplied options */ - if (exceptions) { - CFMutableArrayRef filteredExceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFIndex i, exceptionCount = (filteredExceptions) ? CFArrayGetCount(exceptions) : 0; - - for (i = 0; i < exceptionCount; ++i) { - CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, i); - CFDictionaryRef oldException = NULL; - if (oldExceptions && i < CFArrayGetCount(oldExceptions)) { - oldException = (CFDictionaryRef)CFArrayGetValueAtIndex(oldExceptions, i); - } - CFMutableDictionaryRef filteredException = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (exception && filteredException) { - SecExceptionFilterContext filterContext = { options, i, trustRef, filteredException, oldException }; - CFDictionaryApplyFunction(exception, filter_exception, &filterContext); - CFArrayAppendValue(filteredExceptions, filteredException); - CFRelease(filteredException); - } - } - - if (filteredExceptions) { - CFIndex filteredCount = CFArrayGetCount(filteredExceptions); - /* remove empty trailing entries to match iOS behavior */ - for (i = filteredCount; i-- > 1;) { - CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(filteredExceptions, i); - if (CFDictionaryGetCount(exception) == 0) { - CFArrayRemoveValueAtIndex(filteredExceptions, i); - } else { - break; - } - } - encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault, - filteredExceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL); - CFRelease(filteredExceptions); - - SecTrustSetExceptions(trustRef, encodedExceptions); - CFRelease(encodedExceptions); - } - CFRelease(exceptions); - } - -#if SECTRUST_DEPRECATION_WARNINGS - bool displayModifyMsg = false; - bool displayNetworkMsg = false; - bool displayPolicyMsg = false; - const char *baseMsg = "WARNING: SecTrustSetOptions called with"; - const char *modifyMsg = "Use SecTrustSetExceptions and SecTrustCopyExceptions to modify default trust results."; - const char *networkMsg = "Use SecTrustSetNetworkFetchAllowed to specify whether missing certificates can be fetched from the network."; - const char *policyMsg = "Use SecPolicyCreateRevocation to specify revocation policy requirements."; - - if (options & kSecTrustOptionAllowExpired) { - syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpired"); - displayModifyMsg = true; - } - if (options & kSecTrustOptionAllowExpiredRoot) { - syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpiredRoot"); - displayModifyMsg = true; - } - if (options & kSecTrustOptionFetchIssuerFromNet) { - syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionFetchIssuerFromNet"); - displayNetworkMsg = true; - } - if (options & kSecTrustOptionRequireRevPerCert) { - syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionRequireRevPerCert"); - displayPolicyMsg = true; - } - if (displayModifyMsg || displayNetworkMsg || displayPolicyMsg) { - syslog(LOG_ERR, "%s %s %s", - (displayModifyMsg) ? modifyMsg : "", - (displayNetworkMsg) ? networkMsg : "", - (displayPolicyMsg) ? policyMsg : ""); - } -#endif - - return status; -} - /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */ OSStatus SecTrustSetParameters( SecTrustRef trustRef, @@ -439,65 +165,6 @@ OSStatus SecTrustGetCssmResult(SecTrustRef trust, CSSM_TP_VERIFY_CONTEXT_RESULT_ return errSecServiceNotAvailable; } -// -// Returns a malloced array of CSSM_RETURN values, with the length in numStatusCodes, -// for the certificate specified by chain index in the given SecTrustRef. -// -// To match legacy behavior, the array actually allocates one element more than the -// value of numStatusCodes; if the certificate is revoked, the additional element -// at the end contains the CrlReason value. -// -// Caller must free the returned pointer. -// -static CSSM_RETURN *copyCssmStatusCodes(SecTrustRef trust, - unsigned int index, unsigned int *numStatusCodes) -{ - if (!trust || !numStatusCodes) { - return NULL; - } - *numStatusCodes = 0; - CFArrayRef details = SecTrustCopyFilteredDetails(trust); - CFIndex chainLength = (details) ? CFArrayGetCount(details) : 0; - if (!(index < chainLength)) { - CFReleaseSafe(details); - return NULL; - } - CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, index); - CFIndex ix, detailCount = CFDictionaryGetCount(detail); - *numStatusCodes = (unsigned int)detailCount; - - // Allocate one more entry than we need; this is used to store a CrlReason - // at the end of the array. - CSSM_RETURN *statusCodes = (CSSM_RETURN*)malloc((detailCount+1) * sizeof(CSSM_RETURN)); - statusCodes[*numStatusCodes] = 0; - - const unsigned int resultmaplen = sizeof(cssmresultmap) / sizeof(resultmap_entry_t); - const void *keys[detailCount]; - CFDictionaryGetKeysAndValues(detail, &keys[0], NULL); - for (ix = 0; ix < detailCount; ix++) { - CFStringRef key = (CFStringRef)keys[ix]; - CSSM_RETURN statusCode = CSSM_OK; - for (unsigned int mapix = 0; mapix < resultmaplen; mapix++) { - CFStringRef str = (CFStringRef) cssmresultmap[mapix].checkstr; - if (CFStringCompare(str, key, 0) == kCFCompareEqualTo) { - statusCode = (CSSM_RETURN) cssmresultmap[mapix].resultcode; - break; - } - } - if (statusCode == CSSMERR_TP_CERT_REVOKED) { - SInt32 reason; - CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(detail, key); - if (number && CFNumberGetValue(number, kCFNumberSInt32Type, &reason)) { - statusCodes[*numStatusCodes] = (CSSM_RETURN)reason; - } - } - statusCodes[ix] = statusCode; - } - - CFReleaseSafe(details); - return statusCodes; -} - static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode) { switch (resultCode) { /* explicitly not trusted */ @@ -625,9 +292,9 @@ OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result) uint8_t resultCodePriority = 0xFF; CFIndex ix, count = SecTrustGetCertificateCount(trustRef); for (ix = 0; ix < count; ix++) { - unsigned int numStatusCodes; + CFIndex numStatusCodes; CSSM_RETURN *statusCodes = NULL; - statusCodes = copyCssmStatusCodes(trustRef, (uint32_t)ix, &numStatusCodes); + statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trustRef, ix, &numStatusCodes); if (statusCodes && numStatusCodes > 0) { unsigned int statusIX; for (statusIX = 0; statusIX < numStatusCodes; statusIX++) { @@ -669,11 +336,50 @@ OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle) OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates) { BEGIN_SECAPI - - return SecTrustSettingsCopyUnrestrictedRoots( + CFArrayRef outArray; + OSStatus status = SecTrustSettingsCopyUnrestrictedRoots( true, true, true, /* all domains */ - anchorCertificates); - + &outArray); + if (status != errSecSuccess) { + return status; + } + CFIndex count = outArray ? CFArrayGetCount(outArray) : 0; + if(count == 0) { + return errSecNoTrustSettings; + } + + /* Go through outArray and do a SecTrustEvaluate */ + CFIndex i; + SecPolicyRef policy = SecPolicyCreateBasicX509(); + CFMutableArrayRef trustedCertArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + for (i = 0; i < count ; i++) { + SecTrustRef trust; + SecTrustResultType result; + SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(outArray, i); + status = SecTrustCreateWithCertificates(certificate, policy, &trust); + if (status != errSecSuccess) { + CFReleaseSafe(trustedCertArray); + goto out; + } + status = SecTrustEvaluate(trust, &result); + if (status != errSecSuccess) { + CFReleaseSafe(trustedCertArray); + goto out; + } + if (result != kSecTrustResultFatalTrustFailure) { + CFArrayAppendValue(trustedCertArray, certificate); + } + } + if (CFArrayGetCount(trustedCertArray) == 0) { + status = errSecNoTrustSettings; + CFReleaseSafe(trustedCertArray); + goto out; + } + *anchorCertificates = trustedCertArray; +out: + CFReleaseSafe(outArray); + CFReleaseSafe(policy); + return status; END_SECAPI } @@ -708,7 +414,6 @@ typedef struct __TSecTrust { bool _keychainsAllowed; void* _legacy_info_array; void* _legacy_status_array; - SecTrustResultType _trustResultBeforeExceptions; dispatch_queue_t _trustQueue; } TSecTrust; @@ -819,7 +524,7 @@ SecTrustGetEvidenceInfo(SecTrustRef trust) CSSM_TP_APPLE_EVIDENCE_INFO *infoArray = (CSSM_TP_APPLE_EVIDENCE_INFO *)calloc(count, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO)); CSSM_RETURN *statusArray = NULL; - unsigned int numStatusCodes = 0; + CFIndex numStatusCodes = 0; // Set status codes for each certificate in the constructed chain for (idx=0; idx < count; idx++) { @@ -918,19 +623,19 @@ SecTrustGetEvidenceInfo(SecTrustRef trust) CFRelease(hashStr); } - unsigned int numCodes=0; - CSSM_RETURN *statusCodes = copyCssmStatusCodes(trust, (unsigned int)idx, &numCodes); + CFIndex numCodes=0; + CSSM_RETURN *statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trust, idx, &numCodes); if (statusCodes) { // Realloc space for these status codes at end of our status codes block. // Two important things to note: - // 1. the actual length is numCodes+1 because copyCssmStatusCodes + // 1. the actual length is numCodes+1 because SecTrustCopyStatusCodes // allocates one more element at the end for the CrlReason value. // 2. realloc may cause the pointer to move, which means we will // need to fix up the StatusCodes fields after we're done with this loop. - unsigned int totalStatusCodes = numStatusCodes + numCodes + 1; + CFIndex totalStatusCodes = numStatusCodes + numCodes + 1; statusArray = (CSSM_RETURN *)realloc(statusArray, totalStatusCodes * sizeof(CSSM_RETURN)); evInfo->StatusCodes = &statusArray[numStatusCodes]; - evInfo->NumStatusCodes = numCodes; + evInfo->NumStatusCodes = (uint32)numCodes; // Copy the new codes (plus one) into place for (unsigned int cpix = 0; cpix <= numCodes; cpix++) { evInfo->StatusCodes[cpix] = statusCodes[cpix]; @@ -1008,11 +713,11 @@ CFArrayRef SecTrustCopyProperties(SecTrustRef trust) { } /* Populate a revocation reason if the cert was revoked */ - unsigned int numStatusCodes; + CFIndex numStatusCodes; CSSM_RETURN *statusCodes = NULL; - statusCodes = copyCssmStatusCodes(trust, (uint32_t)ix, &numStatusCodes); + statusCodes = (CSSM_RETURN*)SecTrustCopyStatusCodes(trust, ix, &numStatusCodes); if (statusCodes) { - int32_t reason = statusCodes[numStatusCodes]; // stored at end of status codes array + SInt32 reason = statusCodes[numStatusCodes]; // stored at end of status codes array if (reason > 0) { CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); if (cfreason) { diff --git a/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp b/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp index 205ccbb2..ffe7e3a1 100644 --- a/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp +++ b/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp @@ -43,25 +43,13 @@ #include #include -#include #include #include -#include #include -/* - * MARK: CFRunloop - */ - -static void *SecTrustOSXCFRunloop(__unused void *unused) { - CFRunLoopTimerRef timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, (CFTimeInterval) UINT_MAX, 0, 0, 0, ^(__unused CFRunLoopTimerRef _timer) { - /* do nothing */ - }); - /* add a timer to force the runloop to stay running */ - CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); +void SecTrustLegacySourcesListenForKeychainEvents(void) { /* Register for CertificateTrustNotification */ - int out_token = 0; notify_register_dispatch(kSecServerCertificateTrustNotification, &out_token, dispatch_get_main_queue(), @@ -72,37 +60,6 @@ static void *SecTrustOSXCFRunloop(__unused void *unused) { SecTrustSettingsPurgeUserAdminCertsCache(); }); - - try { - CFRunLoopRun(); - } - catch (...) { - /* An exception was rethrown from the runloop. Since we can't reliably - * obtain info about changes to keychains or trust settings anymore, - * just exit and respawn the process when needed. */ - - secerror("Exception occurred in CFRunLoopRun; exiting"); - exit(0); - } - CFRelease(timer); - return NULL; -} - -void SecTrustLegacySourcesEventRunloopCreate(void) { - /* A runloop is currently necessary to receive notifications about changes in the - * legacy keychains and trust settings. */ - static dispatch_once_t once; - - dispatch_once(&once, ^{ - pthread_attr_t attrs; - pthread_t thread; - - pthread_attr_init(&attrs); - pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED); - - /* we do this with traditional pthread to avoid impacting our 512 WQ thread limit since this is a parked thread */ - pthread_create(&thread, &attrs, SecTrustOSXCFRunloop, NULL); - }); } /* diff --git a/OSX/libsecurity_keychain/lib/SecTrustSettings.cpp b/OSX/libsecurity_keychain/lib/SecTrustSettings.cpp index c4bb5738..8b25b2de 100644 --- a/OSX/libsecurity_keychain/lib/SecTrustSettings.cpp +++ b/OSX/libsecurity_keychain/lib/SecTrustSettings.cpp @@ -31,6 +31,7 @@ #include "SecTrustSettings.h" #include "SecTrustSettingsPriv.h" #include "SecTrustSettingsCertificates.h" +#include "SecCFRelease.h" #include "TrustSettingsUtils.h" #include "TrustSettings.h" #include "TrustSettingsSchema.h" @@ -424,7 +425,7 @@ static OSStatus tsCopyCertsCommon( tsAddConditionalCerts(outArray); } *certArray = outArray; - CFRetain(*certArray); + CFRetainSafe(*certArray); trustSettingsDbg("tsCopyCertsCommon: %ld certs found", CFArrayGetCount(outArray)); return errSecSuccess; @@ -842,18 +843,19 @@ OSStatus SecTrustSettingsCopyCertificates( TS_REQUIRED(certArray) - OSStatus result; + OSStatus status; TrustSettings* ts; + CFMutableArrayRef trustedCertArray = NULL; - result = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts); - if (result != errSecSuccess) { - return result; + status = TrustSettings::CreateTrustSettings(domain, CREATE_NO, TRIM_NO, ts); + if (status != errSecSuccess) { + return status; } auto_ptr_(ts); CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - + /* * Keychains to search: user's search list, System.keychain, system root store */ @@ -879,14 +881,51 @@ OSStatus SecTrustSettingsCopyCertificates( break; } ts->findCerts(keychains, outArray); - if(CFArrayGetCount(outArray) == 0) { - CFRelease(outArray); + CFIndex count = outArray ? CFArrayGetCount(outArray) : 0; + if(count == 0) { + CFReleaseSafe(outArray); return errSecNoTrustSettings; } + /* Go through outArray and do a SecTrustEvaluate only for DomainSystem */ if (kSecTrustSettingsDomainSystem == domain) { - tsAddConditionalCerts(outArray); - } - *certArray = outArray; + CFIndex i; + SecPolicyRef policy = SecPolicyCreateBasicX509(); + trustedCertArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + for (i = 0; i < count ; i++) { + SecTrustRef trust; + SecTrustResultType result; + SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(outArray, i); + status = SecTrustCreateWithCertificates(certificate, policy, &trust); + if (status != errSecSuccess) { + CFReleaseSafe(policy); + goto out; + } + status = SecTrustEvaluate(trust, &result); + if (status != errSecSuccess) { + CFReleaseSafe(policy); + goto out; + } + if (result != kSecTrustResultFatalTrustFailure) { + CFArrayAppendValue(trustedCertArray, certificate); + } + } + tsAddConditionalCerts(trustedCertArray); + if (CFArrayGetCount(trustedCertArray) == 0) { + status = errSecNoTrustSettings; + } else { + *certArray = trustedCertArray; + CFReleaseSafe(outArray); + } + CFReleaseSafe(policy); + } else { + *certArray = outArray; + } +out: + if (status != errSecSuccess) { + CFReleaseSafe(outArray); + CFReleaseSafe(trustedCertArray); + } + return status; END_RCSAPI } @@ -1020,3 +1059,221 @@ OSStatus SecTrustSettingsImportExternalRepresentation( END_RCSAPI } +/* + * SecTrustSettingsSetTrustSettings convenience wrapper function. + */ +void SecTrustSettingsSetTrustedCertificateForSSLHost( + SecCertificateRef certificate, + CFStringRef hostname, + void (^result)(SecTrustSettingsResult trustResult, CFErrorRef error)) +{ + __block CFMutableArrayRef trustSettings = NULL; + __block CFNumberRef trustSettingsResult = NULL; + __block SecTrustSettingsDomain domain = kSecTrustSettingsDomainUser; + + CFDictionaryRef policyProperties = NULL; + CFStringRef policyOid = NULL; + SecPolicyRef policy = NULL; + + Boolean isSelfSigned = false; + Boolean hasPolicyConstraint = false; + Boolean hasPolicyValue = false; + Boolean policyConstraintChanged = false; + Boolean changed = false; + CFIndex indexOfEntryWithAllowedErrorForExpiredCert = kCFNotFound; + CFIndex indexOfEntryWithAllowedErrorForHostnameMismatch = kCFNotFound; + CFIndex indexOfEntryWithAllowedErrorNotSet = kCFNotFound; + CFIndex i, count; + int32_t trustSettingsResultCode = kSecTrustSettingsResultTrustAsRoot; + OSStatus status = errSecSuccess; + + CFRetainSafe(certificate); + CFRetainSafe(hostname); + if (!certificate || !hostname) { + status = errSecParam; + } else { + status = SecCertificateIsSelfSigned(certificate, &isSelfSigned); + } + if (status != errSecSuccess) { + goto reportErr; + } + if (isSelfSigned) { + trustSettingsResultCode = kSecTrustSettingsResultTrustRoot; + } + trustSettingsResult = CFNumberCreate(NULL, kCFNumberSInt32Type, &trustSettingsResultCode); + + /* start with the existing trust settings for this certificate, if any */ + { + CFArrayRef curTrustSettings = NULL; + (void)SecTrustSettingsCopyTrustSettings(certificate, domain, &curTrustSettings); + if (curTrustSettings) { + trustSettings = CFArrayCreateMutableCopy(NULL, 0, curTrustSettings); + CFReleaseNull(curTrustSettings); + } else { + trustSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + } + if (!trustSettings || !trustSettingsResult) { + status = errSecAllocate; + goto reportErr; + } + + /* set up policy and value instances to trust the certificate for SSL for a given hostname */ + policy = SecPolicyCreateSSL(true, hostname); + if (!policy) { + status = errSecInternal; + goto reportErr; + } + policyProperties = SecPolicyCopyProperties(policy); + if (!policyProperties) { + status = errSecInternal; + goto reportErr; + } + policyOid = (CFStringRef)CFDictionaryGetValue(policyProperties, kSecPolicyOid); + CFRetainSafe(policyOid); + if (!policyOid) { + status = errSecInternal; + goto reportErr; + } + + /* look for dictionaries in the trust settings array for this policy and value */ + count = CFArrayGetCount(trustSettings); + for (i=0; i < count; i++) { + CFDictionaryRef constraints = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, i); + if (!constraints) { continue; } + SecPolicyRef aPolicy = (SecPolicyRef)CFDictionaryGetValue(constraints, kSecTrustSettingsPolicy); + if (!aPolicy) { continue; } + CFDictionaryRef properties = SecPolicyCopyProperties(aPolicy); + if (!properties) { continue; } + CFStringRef aPolicyOid = (CFStringRef)CFDictionaryGetValue(properties, kSecPolicyOid); + if (aPolicyOid && kCFCompareEqualTo == CFStringCompare(aPolicyOid, policyOid, 0)) { + CFStringRef aPolicyString = (CFStringRef)CFDictionaryGetValue(constraints, kSecTrustSettingsPolicyString); + if (aPolicyString && kCFCompareEqualTo == CFStringCompare(aPolicyString, hostname, kCFCompareCaseInsensitive)) { + /* found existing entry */ + CFNumberRef allowedErr = (CFNumberRef)CFDictionaryGetValue(constraints, kSecTrustSettingsAllowedError); + int32_t eOld = 0; + if (!allowedErr || !CFNumberGetValue(allowedErr, kCFNumberSInt32Type, &eOld)) { + eOld = CSSM_OK; + } + CFNumberRef tsResult = (CFNumberRef)CFDictionaryGetValue(constraints, kSecTrustSettingsResult); + int32_t rOld = 0; + if (!tsResult || !CFNumberGetValue(allowedErr, kCFNumberSInt32Type, &rOld)) { + rOld = kSecTrustSettingsResultTrustRoot; + } + if (!hasPolicyValue) { hasPolicyValue = (aPolicyString != NULL); } + if (!hasPolicyConstraint) { hasPolicyConstraint = true; } + if (eOld == CSSMERR_TP_CERT_EXPIRED) { + indexOfEntryWithAllowedErrorForExpiredCert = i; + } else if (eOld == CSSMERR_APPLETP_HOSTNAME_MISMATCH) { + indexOfEntryWithAllowedErrorForHostnameMismatch = i; + } else if (eOld == CSSM_OK) { + indexOfEntryWithAllowedErrorNotSet = i; + } + if (trustSettingsResultCode != rOld) { + changed = policyConstraintChanged = true; // we are changing existing policy constraint's result + } + } + } + CFReleaseSafe(properties); + } + + if (!hasPolicyConstraint) { + policyConstraintChanged = true; // we are adding a new policy constraint + } else if (hostname && !hasPolicyValue) { + policyConstraintChanged = true; // we need to add the hostname to an existing policy constraint + } else if ((indexOfEntryWithAllowedErrorForExpiredCert == kCFNotFound) || + (indexOfEntryWithAllowedErrorForHostnameMismatch == kCFNotFound)) { + policyConstraintChanged = true; // we are missing one of the expected allowed-error entries for this policy + } + + if (policyConstraintChanged) { + CFMutableDictionaryRef policyDict[2] = { NULL, NULL }; + policyDict[0] = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + policyDict[1] = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + int32_t certExpiredCode = (int32_t)CSSMERR_TP_CERT_EXPIRED; + CFNumberRef certExpired = CFNumberCreate(NULL, kCFNumberSInt32Type, &certExpiredCode); + int32_t hostnameMismatchCode = (int32_t)CSSMERR_APPLETP_HOSTNAME_MISMATCH; + CFNumberRef hostnameMismatch = CFNumberCreate(NULL, kCFNumberSInt32Type, &hostnameMismatchCode); + if (!policyDict[0] || !policyDict[1] || !certExpired || !hostnameMismatch) { + status = errSecInternal; + } else { + /* set up entry for policy, hostname, expired cert error, and result */ + CFDictionarySetValue(policyDict[0], kSecTrustSettingsPolicy, policy); + CFDictionarySetValue(policyDict[0], kSecTrustSettingsPolicyString, hostname); + CFDictionarySetValue(policyDict[0], kSecTrustSettingsAllowedError, certExpired); + CFDictionarySetValue(policyDict[0], kSecTrustSettingsResult, trustSettingsResult); + if (indexOfEntryWithAllowedErrorForExpiredCert != kCFNotFound) { + /* if we found an existing constraint for this policy, hostname, and allowed error, replace it */ + CFArraySetValueAtIndex(trustSettings, indexOfEntryWithAllowedErrorForExpiredCert, policyDict[0]); + } else if (!(hasPolicyValue)) { + /* add a new policy constraint */ + CFArrayAppendValue(trustSettings, policyDict[0]); + } + /* set up additional entry for policy, hostname, hostname mismatch error, and result */ + CFDictionarySetValue(policyDict[1], kSecTrustSettingsPolicy, policy); + CFDictionarySetValue(policyDict[1], kSecTrustSettingsPolicyString, hostname); + CFDictionarySetValue(policyDict[1], kSecTrustSettingsAllowedError, hostnameMismatch); + CFDictionarySetValue(policyDict[1], kSecTrustSettingsResult, trustSettingsResult); + if (indexOfEntryWithAllowedErrorForHostnameMismatch != kCFNotFound) { + /* if we found an existing constraint for this policy, hostname, and allowed error, replace it */ + CFArraySetValueAtIndex(trustSettings, indexOfEntryWithAllowedErrorForHostnameMismatch, policyDict[1]); + } else if (!(hasPolicyValue)) { + /* add a new policy constraint */ + CFArrayAppendValue(trustSettings, policyDict[1]); + } + } + CFReleaseSafe(policyDict[0]); + CFReleaseSafe(policyDict[1]); + CFReleaseSafe(certExpired); + CFReleaseSafe(hostnameMismatch); + } + + if (status != errSecSuccess) { + goto reportErr; + } + CFReleaseSafe(policyOid); + CFReleaseSafe(policyProperties); + CFReleaseSafe(policy); + + dispatch_async(dispatch_get_main_queue(), ^{ + /* add certificate to keychain first */ + OSStatus status = SecCertificateAddToKeychain(certificate, NULL); + if (status == errSecSuccess || status == errSecDuplicateItem) { + /* this will block on authorization UI... */ + status = SecTrustSettingsSetTrustSettings(certificate, + domain, trustSettings); + } + if (result) { + CFErrorRef error = NULL; + if (status) { + error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL); + } + int32_t tsrc; + if (!CFNumberGetValue(trustSettingsResult, kCFNumberSInt32Type, (int32_t*)&tsrc)) { + tsrc = (int32_t)kSecTrustSettingsResultUnspecified; + } + result((SecTrustSettingsResult)tsrc, error); + CFReleaseSafe(error); + } + CFRelease(trustSettingsResult); + CFRelease(trustSettings); + CFRelease(certificate); + CFRelease(hostname); + }); + + return; + +reportErr: + CFReleaseSafe(policyOid); + CFReleaseSafe(policyProperties); + CFReleaseSafe(policy); + CFReleaseSafe(trustSettingsResult); + CFReleaseSafe(trustSettings); + CFReleaseSafe(certificate); + CFReleaseSafe(hostname); + if (result) { + CFErrorRef error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL); + result(kSecTrustSettingsResultInvalid, error); + CFReleaseSafe(error); + } +} diff --git a/OSX/libsecurity_keychain/lib/TokenLogin.cpp b/OSX/libsecurity_keychain/lib/TokenLogin.cpp index 888b4081..64b45fc9 100644 --- a/OSX/libsecurity_keychain/lib/TokenLogin.cpp +++ b/OSX/libsecurity_keychain/lib/TokenLogin.cpp @@ -41,7 +41,7 @@ extern "C" { #define kSecTokenLoginDomain CFSTR("com.apple.security.tokenlogin") -static CFStringRef cfDataToHex(CFDataRef bin) +static CFStringRef CF_RETURNS_RETAINED cfDataToHex(CFDataRef bin) { size_t len = CFDataGetLength(bin) * 2; CFMutableStringRef str = CFStringCreateMutable(NULL, len); diff --git a/OSX/libsecurity_keychain/lib/TrustAdditions.cpp b/OSX/libsecurity_keychain/lib/TrustAdditions.cpp index 8d88ba8d..b8163183 100644 --- a/OSX/libsecurity_keychain/lib/TrustAdditions.cpp +++ b/OSX/libsecurity_keychain/lib/TrustAdditions.cpp @@ -103,7 +103,7 @@ static void SafeCFRelease(void * CF_CONSUMED cfTypeRefPtr) // utility function to create a CFDataRef from the contents of the specified file; // caller must release // -static CFDataRef dataWithContentsOfFile(const char *fileName) +static CFDataRef CF_RETURNS_RETAINED dataWithContentsOfFile(const char *fileName) { int rtn; int fd; @@ -194,7 +194,7 @@ static SecKeychainRef systemRootStore() // returns a CFDictionaryRef created from the specified XML plist file; caller must release // -static CFDictionaryRef dictionaryWithContentsOfPlistFile(const char *fileName) +static CFDictionaryRef CF_RETURNS_RETAINED dictionaryWithContentsOfPlistFile(const char *fileName) { CFDictionaryRef resultDict = NULL; CFDataRef fileData = dataWithContentsOfFile(fileName); @@ -826,37 +826,6 @@ bool isRevocationStatusCode(CSSM_RETURN statusCode) return false; } -// returns true if the given revocation status code can be ignored. -// -bool ignorableRevocationStatusCode(CSSM_RETURN statusCode) -{ - if (!isRevocationStatusCode(statusCode)) - return false; - - // if OCSP and/or CRL revocation info was unavailable for this certificate, - // and revocation checking is not required, we can ignore this status code. - - CFStringRef ocsp_val = (CFStringRef) CFPreferencesCopyValue(kSecRevocationOcspStyle, CFSTR(kSecRevocationDomain), kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - CFStringRef crl_val = (CFStringRef) CFPreferencesCopyValue(kSecRevocationCrlStyle, CFSTR(kSecRevocationDomain), kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - bool ocspRequired = (ocsp_val && CFEqual(ocsp_val, kSecRevocationRequireForAll)); - bool crlRequired = (crl_val && CFEqual(crl_val, kSecRevocationRequireForAll)); - if (!ocspRequired && ocsp_val && CFEqual(ocsp_val, kSecRevocationRequireIfPresent)) - ocspRequired = (statusCode != CSSMERR_APPLETP_OCSP_UNAVAILABLE); - if (!crlRequired && crl_val && CFEqual(crl_val, kSecRevocationRequireIfPresent)) - crlRequired = (statusCode != CSSMERR_APPLETP_CRL_NOT_FOUND); - if (ocsp_val) - CFRelease(ocsp_val); - if (crl_val) - CFRelease(crl_val); - - if (isOCSPStatusCode(statusCode)) - return (ocspRequired) ? false : true; - if (isCRLStatusCode(statusCode)) - return (crlRequired) ? false : true; - - return false; -} - // returns a CFArrayRef of allowed root certificates for the provided leaf certificate // if it passes initial EV evaluation criteria and should be subject to OCSP revocation // checking; otherwise, NULL is returned. (Caller must release the result if not NULL.) diff --git a/OSX/libsecurity_keychain/lib/TrustAdditions.h b/OSX/libsecurity_keychain/lib/TrustAdditions.h index 222fc28a..cf386e1f 100644 --- a/OSX/libsecurity_keychain/lib/TrustAdditions.h +++ b/OSX/libsecurity_keychain/lib/TrustAdditions.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2002-2012,2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2002-2012,2014-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, @@ -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@ */ @@ -42,7 +42,6 @@ bool isOCSPStatusCode(CSSM_RETURN statusCode); bool isCRLStatusCode(CSSM_RETURN statusCode); bool isRevocationStatusCode(CSSM_RETURN statusCode); bool isRevocationServerMetaError(CSSM_RETURN statusCode); -bool ignorableRevocationStatusCode(CSSM_RETURN statusCode); CFDictionaryRef extendedTrustResults(CFArrayRef certChain, SecTrustResultType trustResult, OSStatus tpResult, bool isEVCandidate); #ifdef __cplusplus diff --git a/OSX/libsecurity_keychain/lib/TrustRevocation.cpp b/OSX/libsecurity_keychain/lib/TrustRevocation.cpp index b30f76e5..6338d1c0 100644 --- a/OSX/libsecurity_keychain/lib/TrustRevocation.cpp +++ b/OSX/libsecurity_keychain/lib/TrustRevocation.cpp @@ -1,15 +1,15 @@ /* - * Copyright (c) 2002-2004,2011-2012,2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2002-2004,2011-2012,2014-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, @@ -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@ */ @@ -253,34 +253,13 @@ CFMutableArrayRef Trust::addPreferenceRevocationPolicies( { numAdded = 0; - /* any per-user prefs? */ - Dictionary* pd = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_User, true); - if (pd) - { - if (!pd->dict()) { - delete pd; - pd = NULL; - } - } - - if(pd == NULL) - { - pd = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_System, true); - if (!pd->dict()) { - delete pd; - pd = NULL; - } + Dictionary* pd = NULL; + CFDictionaryRef tempDict = defaultRevocationSettings(); + if (tempDict == NULL) { + return NULL; } - - if(pd == NULL) - { - CFDictionaryRef tempDict = defaultRevocationSettings(); - if (tempDict == NULL) - return NULL; - - pd = new Dictionary(tempDict); - CFRelease(tempDict); - } + pd = new Dictionary(tempDict); + CFRelease(tempDict); auto_ptr prefsDict(pd); @@ -534,18 +513,6 @@ void Trust::orderRevocationPolicies( } /* check revocation prefs to determine which policy goes first */ CFBooleanRef ocspFirst = kCFBooleanTrue; - Dictionary* pd = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_User, true); - if (pd) { - if (!pd->dict()) { - delete pd; - } else { - auto_ptr prefsDict(pd); - CFStringRef val = prefsDict->getStringValue(kSecRevocationWhichFirst); - if((val != NULL) && CFEqual(val, kSecRevocationCrlFirst)) { - ocspFirst = kCFBooleanFalse; - } - } - } #if POLICIES_DEBUG CFShow(policies); // before sort CFArraySortValues(policies, CFRangeMake(0, CFArrayGetCount(policies)), compareRevocationPolicies, (void*)ocspFirst); @@ -665,40 +632,6 @@ CFMutableArrayRef Trust::forceRevocationPolicies( opts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; opts.Flags = ocspFlags; - /* Check prefs dict for local responder info */ - Dictionary *prefsDict = NULL; - try { /* per-user prefs */ - prefsDict = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_User, true); - if (!prefsDict->dict()) { - delete prefsDict; - prefsDict = NULL; - } - } - catch(...) {} - if(prefsDict == NULL) { - try { /* system prefs */ - prefsDict = Dictionary::CreateDictionary(kSecRevocationDomain, Dictionary::US_System, true); - if (!prefsDict->dict()) { - delete prefsDict; - prefsDict = NULL; - } - } - catch(...) {} - } - if(prefsDict != NULL) { - CFStringRef val = prefsDict->getStringValue(kSecOCSPLocalResponder); - if(val != NULL) { - CFDataRef cfData = CFStringCreateExternalRepresentation(NULL, - val, kCFStringEncodingUTF8, 0); - CFIndex len = CFDataGetLength(cfData); - opts.LocalResponder = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA)); - opts.LocalResponder->Data = (uint8 *)alloc.malloc(len); - opts.LocalResponder->Length = len; - memmove(opts.LocalResponder->Data, CFDataGetBytePtr(cfData), len); - CFRelease(cfData); - } - } - /* Policy manages its own copy of the options data */ CSSM_DATA optData = {sizeof(opts), (uint8 *)&opts}; ocspPolicy->value() = optData; @@ -706,9 +639,6 @@ CFMutableArrayRef Trust::forceRevocationPolicies( /* Policies array retains the Policy object */ CFArrayAppendValue(policies, ocspPolicy->handle(false)); numAdded++; - - if(prefsDict != NULL) - delete prefsDict; } if(!hasCrlPolicy && crlEnabled) { diff --git a/OSX/libsecurity_keychain/lib/defaultcreds.cpp b/OSX/libsecurity_keychain/lib/defaultcreds.cpp index baf11213..d1b862d7 100644 --- a/OSX/libsecurity_keychain/lib/defaultcreds.cpp +++ b/OSX/libsecurity_keychain/lib/defaultcreds.cpp @@ -77,6 +77,9 @@ bool DefaultCredentials::operator () (Db database) case CSSM_APPLE_UNLOCK_TYPE_WRAPPED_PRIVATE: keyReferral(**it); break; + case CSSM_APPLE_UNLOCK_TYPE_KEYBAG: + keybagReferral(**it); + break; default: secinfo("kcreferral", "referral type %lu (to %s) not supported", (unsigned long)(*it)->type(), (*it)->dbName().c_str()); @@ -97,7 +100,7 @@ bool DefaultCredentials::operator () (Db database) // // Process a single referral record. This will handle all known types -// of referrals. +// of referrals, other than keybag (see keybagReferral). // void DefaultCredentials::keyReferral(const UnlockReferralRecord &ref) { @@ -170,6 +173,21 @@ bool DefaultCredentials::unlockKey(const UnlockReferralRecord &ref, const Keycha return foundSome; } +void +DefaultCredentials::keybagReferral(const UnlockReferralRecord &ref) +{ + secinfo("kcreferral", "processing type %ld referral", (long)ref.type()); + + try { + // assemble and add CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK item + append(TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, + new(allocator) ListElement(CSSM_WORDID_KEYBAG_KEY), + new(allocator) ListElement(allocator, CssmData::wrap(ref.dbGuid())), + new(allocator) ListElement(allocator, ref.get()) + )); + } catch (...) { + } +} // // Take the official keychain search list, and return those keychains whose diff --git a/OSX/libsecurity_keychain/lib/defaultcreds.h b/OSX/libsecurity_keychain/lib/defaultcreds.h index 86e3fb5e..f16dbd85 100644 --- a/OSX/libsecurity_keychain/lib/defaultcreds.h +++ b/OSX/libsecurity_keychain/lib/defaultcreds.h @@ -63,6 +63,8 @@ private: void keyReferral(const CssmClient::UnlockReferralRecord &ref); bool unlockKey(const CssmClient::UnlockReferralRecord &ref, const KeychainList &list); + void keybagReferral(const CssmClient::UnlockReferralRecord &ref); + KeychainList fallbackSearchList(const DLDbIdentifier &ident); private: diff --git a/OSX/libsecurity_keychain/lib/tsaDERUtilities.c b/OSX/libsecurity_keychain/lib/tsaDERUtilities.c index 87cc6df1..169e4eb1 100644 --- a/OSX/libsecurity_keychain/lib/tsaDERUtilities.c +++ b/OSX/libsecurity_keychain/lib/tsaDERUtilities.c @@ -76,7 +76,7 @@ int DERDecodeTimeStampResponse( size_t *numUsedBytes) /* RETURNED */ { DERReturn drtn = DR_ParamErr; - DERDecodedInfo decodedPackage; + DERDecodedInfo decodedPackage = {}; if (contents) { @@ -114,7 +114,7 @@ int DERDecodeTimeStampResponse( badResponse: if (numUsedBytes) *numUsedBytes = decodedPackage.content.length + - decodedPackage.content.data - contents->Data; + decodedPackage.content.data - (contents ? contents->Data : 0); return drtn; } diff --git a/OSX/libsecurity_keychain/libDER/libDER/asn1Types.h b/OSX/libsecurity_keychain/libDER/libDER/asn1Types.h index e1e9510c..db992d79 100644 --- a/OSX/libsecurity_keychain/libDER/libDER/asn1Types.h +++ b/OSX/libsecurity_keychain/libDER/libDER/asn1Types.h @@ -30,7 +30,9 @@ #ifndef _ASN1_TYPES_H_ #define _ASN1_TYPES_H_ +#if !defined(__WIN32__) #include +#endif #include diff --git a/OSX/libsecurity_keychain/libDER/libDER/module.modulemap b/OSX/libsecurity_keychain/libDER/libDER/module.modulemap new file mode 100644 index 00000000..af2d15b0 --- /dev/null +++ b/OSX/libsecurity_keychain/libDER/libDER/module.modulemap @@ -0,0 +1,3 @@ +module libDER [extern_c] { + header "libDER.h" +} diff --git a/OSX/libsecurity_keychain/libDER/libDERUtils/fileIo.c b/OSX/libsecurity_keychain/libDER/libDERUtils/fileIo.c index 93f8d642..a050fe5a 100644 --- a/OSX/libsecurity_keychain/libDER/libDERUtils/fileIo.c +++ b/OSX/libsecurity_keychain/libDER/libDERUtils/fileIo.c @@ -20,7 +20,7 @@ int writeFile( int fd; fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600); - if(fd <= 0) { + if(fd == -1) { return errno; } rtn = (int)write(fd, bytes, (size_t)numBytes); @@ -54,7 +54,7 @@ int readFile( *numBytes = 0; *bytes = NULL; fd = open(fileName, O_RDONLY, 0); - if(fd <= 0) { + if(fd == -1) { return errno; } rtn = fstat(fd, &sb); diff --git a/OSX/libsecurity_keychain/plist/iToolsTrustedApps.plist b/OSX/libsecurity_keychain/plist/iToolsTrustedApps.plist deleted file mode 100644 index c37beab8..00000000 --- a/OSX/libsecurity_keychain/plist/iToolsTrustedApps.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - /Applications/Mail.app - /Applications/System Preferences.app - /Applications/iCal.app - /Applications/iChat.app - /Applications/iMovie.app - /Applications/iPhoto.app - /Applications/iSync.app - /Applications/iTunes.app - /Applications/Address Book.app - /System/Library/CoreServices/Finder.app - /System/Library/CoreServices/MirrorAgent.app - /System/Library/CoreServices/dotmacsyncclient - /System/Library/Frameworks/InstantMessage.framework/iChatAgent.app - /System/Library/Frameworks/SecurityFoundation.framework/Versions/A/dotmacfx.app - /System/Library/Frameworks/SecurityFoundation.framework/Versions/A/kcSync.app - /System/Library/PreferencePanes/Mac.prefPane/Contents/Resources/dotMacPrefTool - /System/Library/PrivateFrameworks/DotmacLegacy.framework/Resources/dotMacTranslator - /System/Library/PrivateFrameworks/DMNotification.framework/Resources/dmnotifyd - /System/Library/PrivateFrameworks/Syndication.framework/Resources/SyndicationAgent.app/Contents/MacOS/SyndicationAgent - /usr/sbin/mDNSResponder - /System/Library/PreferencePanes/Mac.prefPane - /System/Library/CoreServices/Certificate Assistant.app - - diff --git a/OSX/libsecurity_keychain/regressions/kc-03-status.c b/OSX/libsecurity_keychain/regressions/kc-03-status.c index 696b0c9d..10ea2d8e 100644 --- a/OSX/libsecurity_keychain/regressions/kc-03-status.c +++ b/OSX/libsecurity_keychain/regressions/kc-03-status.c @@ -15,7 +15,7 @@ static void tests(void) if (!home || strlen(home) > 200) plan_skip_all("home too big"); - sprintf(kcname1, "%s/kctests/kc1/kc1", home); + snprintf(kcname1, sizeof(kcname1), "%s/kctests/kc1/kc1", home); SecKeychainRef kc1 = NULL, kc2 = NULL; kc1 = createNewKeychainAt(kcname1, "test"); @@ -34,7 +34,7 @@ static void tests(void) /* Make keychain non writable. */ char kcdir1[256]; - sprintf(kcdir1, "%s/kctests/kc1", home); + snprintf(kcdir1, sizeof(kcdir1), "%s/kctests/kc1", home); ok_unix(chmod(kcdir1, 0555), "chmod kcdir1 0555"); ok_status(SecKeychainGetStatus(kc1, &status1), "get kc1 status"); @@ -62,7 +62,7 @@ static void tests(void) "status unlocked readable"); } - sprintf(kcname2, "%s/kctests/kc2/kc2", home); + snprintf(kcname2, sizeof(kcname2), "%s/kctests/kc2/kc2", home); kc2 = createNewKeychainAt(kcname2, "test"); ok_unix(chmod(kcname2, 0444), "chmod kc2 0444"); ok_status(SecKeychainGetStatus(kc2, &status2), "get kc2 status"); diff --git a/OSX/libsecurity_keychain/regressions/kc-06-cert-search-email.m b/OSX/libsecurity_keychain/regressions/kc-06-cert-search-email.m index 6675ca17..4722cd2d 100644 --- a/OSX/libsecurity_keychain/regressions/kc-06-cert-search-email.m +++ b/OSX/libsecurity_keychain/regressions/kc-06-cert-search-email.m @@ -148,7 +148,11 @@ static void doCertificateSearchForEmailAddress(SecKeychainRef kc, const char *em } // Set this certificate as preferred for this email address - ok_status(SecCertificateSetPreferred((SecCertificateRef)itemRef, emailStr, 0), "%s: SecCertificateSetPreferred", testName); + if(emailStr) { + ok_status(SecCertificateSetPreferred((SecCertificateRef)itemRef, emailStr, 0), "%s: SecCertificateSetPreferred", testName); + } else { + fail("No email for SecCertificateSetPreferred"); + } CFRelease(itemRef); } @@ -158,7 +162,11 @@ static void doCertificateSearchForEmailAddress(SecKeychainRef kc, const char *em } // Check that our certificate is new preferred - status = SecCertificateCopyPreference(emailStr, (CSSM_KEYUSE) 0, &preferredCert); + if(emailStr) { + status = SecCertificateCopyPreference(emailStr, (CSSM_KEYUSE) 0, &preferredCert); + } else { + status = errSecParam; + } ok_status(status, "%s: SecCertificateCopyPreference", testName); if (preferredCert) diff --git a/OSX/libsecurity_keychain/regressions/kc-10-item-add-generic.c b/OSX/libsecurity_keychain/regressions/kc-10-item-add-generic.c index aee9f4bc..25ca444c 100644 --- a/OSX/libsecurity_keychain/regressions/kc-10-item-add-generic.c +++ b/OSX/libsecurity_keychain/regressions/kc-10-item-add-generic.c @@ -29,7 +29,8 @@ static void tests(void) UInt32 length = 0; void *data = NULL; ok_status(SecKeychainItemCopyContent(item, &itemClass, &attrList, &length, &data), "SecKeychainItemCopyContent"); - eq_string(data, "test", "Item data is wrong"); + is(length, strlen("test"), "item data is right length"); + eq_stringn(data, length, "test", strlen("test"), "Item data is right"); ok_status(SecKeychainItemFreeContent(&attrList, data), "SecKeychainItemCopyContent"); is(CFGetRetainCount(item), 1, "item retaincount is 1"); @@ -43,7 +44,7 @@ static void tests(void) int kc_10_item_add_generic(int argc, char *const *argv) { initializeKeychainTests("kc-10-item-add-generic"); - plan_tests(13); + plan_tests(14); tests(); diff --git a/OSX/libsecurity_keychain/regressions/kc-18-find-combined.c b/OSX/libsecurity_keychain/regressions/kc-18-find-combined.c index 45e2dc17..ca92be7e 100644 --- a/OSX/libsecurity_keychain/regressions/kc-18-find-combined.c +++ b/OSX/libsecurity_keychain/regressions/kc-18-find-combined.c @@ -51,7 +51,7 @@ #include #include #include -#include "test/testenv.h" +#include "regressions/test/testenv.h" #include "utilities/SecCFRelease.h" #include "keychain_regressions.h" @@ -1052,6 +1052,12 @@ static void PrintStringToMatch(CFStringRef nameStr) } } +static void PrintStringToMatchRelease(CFStringRef CF_CONSUMED nameStr) +{ + PrintStringToMatch(nameStr); + CFReleaseNull(nameStr); +} + static void PrintSecCertificate(SecCertificateRef certificate) { @@ -1671,7 +1677,7 @@ static int FindCertificateByNameAndValidDate(SecKeychainRef keychain, CFTypeRef results = NULL; if (debug) { PrintStringToMatch(nameStr); - PrintStringToMatch(CFCopyDescription(validOnDate)); + PrintStringToMatchRelease(CFCopyDescription(validOnDate)); } OSStatus status = SecItemCopyMatching(query, &results); @@ -1732,8 +1738,8 @@ static int FindCertificateForSMIMEEncryption(SecKeychainRef keychain, CFTypeRef results = NULL; if (debug) { PrintStringToMatch(emailAddr); - PrintStringToMatch(CFCopyDescription(kSecPolicyAppleSMIME)); - PrintStringToMatch(CFCopyDescription(validOnDate)); + PrintStringToMatchRelease(CFCopyDescription(kSecPolicyAppleSMIME)); + PrintStringToMatchRelease(CFCopyDescription(validOnDate)); } OSStatus status = SecItemCopyMatching(query, &results); @@ -1806,7 +1812,7 @@ static int FindPreferredCertificateForSMIMEEncryption(SecKeychainRef keychain, if (debug) { PrintStringToMatch(emailAddr); - PrintStringToMatch(CFCopyDescription(validOnDate)); + PrintStringToMatchRelease(CFCopyDescription(validOnDate)); } status = SecItemCopyMatching(query, (CFTypeRef*)&validatedCertificate); @@ -2031,7 +2037,7 @@ static int FindIdentityByPolicyAndValidDate(SecKeychainRef keychain, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (debug) PrintStringToMatch(CFCopyDescription(policyIdentifier)); + if (debug) PrintStringToMatchRelease(CFCopyDescription(policyIdentifier)); status = SecItemCopyMatching(query, &results); @@ -2100,7 +2106,7 @@ static int FindIdentityByNameAndValidDate(SecKeychainRef keychain, CFTypeRef results = NULL; if (debug) { PrintStringToMatch(nameStr); - PrintStringToMatch(CFCopyDescription(validOnDate)); + PrintStringToMatchRelease(CFCopyDescription(validOnDate)); } OSStatus status = SecItemCopyMatching(query, &results); @@ -2170,7 +2176,7 @@ static int FindPreferredIdentityForSMIMESigning(SecKeychainRef keychain, CFStrin if (debug) { PrintStringToMatch(emailAddr); - PrintStringToMatch(CFCopyDescription(validOnDate)); + PrintStringToMatchRelease(CFCopyDescription(validOnDate)); } status = SecItemCopyMatching(query, (CFTypeRef*)&validatedIdentity); @@ -2767,9 +2773,11 @@ static int TestIdentityLookup(SecKeychainRef keychain) // look up identity by policy, want first result as a CFDictionary of attributes (should find "Test SSL User" identity) result += FindIdentityByPolicy(keychain, sslPolicy, kSecReturnAttributes, kSecMatchLimitOne, 1, noErr); + CFReleaseNull(sslPolicy); // look up identity by policy, expect errSecItemNotFound error (this assumes no code signing identity is present!) result += FindIdentityByPolicy(keychain, codeSigningPolicy, kSecReturnRef, kSecMatchLimitOne, 0, errSecItemNotFound); + CFReleaseNull(codeSigningPolicy); // ------------------------- // test kSecMatchValidOnDate diff --git a/OSX/libsecurity_keychain/regressions/kc-20-identity-find-stress.c b/OSX/libsecurity_keychain/regressions/kc-20-identity-find-stress.c index 88fbfb69..43803490 100644 --- a/OSX/libsecurity_keychain/regressions/kc-20-identity-find-stress.c +++ b/OSX/libsecurity_keychain/regressions/kc-20-identity-find-stress.c @@ -33,6 +33,8 @@ #define BLOCKS 7000 +static long concurrentBlocks = 64; + static void tests() { SecKeychainRef kc = getPopulatedTestKeychain(); @@ -55,21 +57,34 @@ static void tests() { }); dispatch_group_t g = dispatch_group_create(); - for(int i = 0; i < BLOCKS; i++) { - dispatch_group_async(g, release_queue, ^() { - SecIdentityRef blockId = NULL; - SecKeyRef blockKeyRef = NULL; + __block int iteration = 0; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(concurrentBlocks); + + dispatch_block_t identityBlock = ^() { + SecIdentityRef blockId = NULL; + SecKeyRef blockKeyRef = NULL; + + ok_status(SecIdentityCreateWithCertificate(kc, certRef, &blockId), "%s: SecIdentityCreateWithCertificate", testName); + ok_status(SecIdentityCopyPrivateKey(blockId, &blockKeyRef), "%s: SecIdentityCopyPrivateKey", testName); + + CFReleaseNull(blockKeyRef); + CFReleaseNull(blockId); - ok_status(SecIdentityCreateWithCertificate(kc, certRef, &blockId), "%s: SecIdentityCreateWithCertificate", testName); - ok_status(SecIdentityCopyPrivateKey(blockId, &blockKeyRef), "%s: SecIdentityCopyPrivateKey", testName); + dispatch_semaphore_signal(semaphore); + }; - CFReleaseNull(blockKeyRef); - CFReleaseNull(blockId); - }); - } + // Send this to background queue, so that when we wait, it doesn't block main queue + + dispatch_group_async(g, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + for (iteration = 0; iteration < BLOCKS; iteration++) { + // Wait until one of our concurrentBlocks "slots" are available + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + dispatch_group_async(g, release_queue, identityBlock); + } + }); dispatch_group_wait(g, DISPATCH_TIME_FOREVER); - CFReleaseNull(certRef); ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", testName); CFReleaseNull(kc); diff --git a/OSX/libsecurity_keychain/regressions/kc-20-item-find-stress.c b/OSX/libsecurity_keychain/regressions/kc-20-item-find-stress.c index 2f40f1a4..937449b9 100644 --- a/OSX/libsecurity_keychain/regressions/kc-20-item-find-stress.c +++ b/OSX/libsecurity_keychain/regressions/kc-20-item-find-stress.c @@ -33,6 +33,8 @@ #define BLOCKS 7000 +static long concurrentBlocks = 64; + static void tests() { SecKeychainRef kc = getPopulatedTestKeychain(); @@ -44,18 +46,32 @@ static void tests() { }); dispatch_group_t g = dispatch_group_create(); - for(int i = 0; i < BLOCKS; i++) { - dispatch_group_async(g, release_queue, ^() { - SecKeychainItemRef blockItem = NULL; + __block int iteration = 0; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(concurrentBlocks); + + dispatch_block_t findBlock = ^() { + SecKeychainItemRef blockItem = NULL; + + CFMutableDictionaryRef query = createQueryCustomItemDictionaryWithService(kc, kSecClassInternetPassword, CFSTR("test_service"), CFSTR("test_service")); + CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne); - CFMutableDictionaryRef query = createQueryCustomItemDictionaryWithService(kc, kSecClassInternetPassword, CFSTR("test_service"), CFSTR("test_service")); - CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne); + ok_status(SecItemCopyMatching(query, (CFTypeRef*) &blockItem), "%s: SecItemCopyMatching (%d)", testName, iteration); + CFReleaseNull(query); - ok_status(SecItemCopyMatching(query, (CFTypeRef*) &blockItem), "%s: SecItemCopyMatching(%d)", testName, i); + CFReleaseNull(blockItem); + dispatch_semaphore_signal(semaphore); + }; - CFReleaseNull(blockItem); - }); - } + // Send this to background queue, so that when we wait, it doesn't block main queue + + dispatch_group_async(g, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + for (iteration = 0; iteration < BLOCKS; iteration++) { + // Wait until one of our concurrentBlocks "slots" are available + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + dispatch_group_async(g, release_queue, findBlock); + } + }); dispatch_group_wait(g, DISPATCH_TIME_FOREVER); diff --git a/OSX/libsecurity_keychain/regressions/kc-20-key-find-stress.c b/OSX/libsecurity_keychain/regressions/kc-20-key-find-stress.c index 88d248ad..a607998f 100644 --- a/OSX/libsecurity_keychain/regressions/kc-20-key-find-stress.c +++ b/OSX/libsecurity_keychain/regressions/kc-20-key-find-stress.c @@ -33,6 +33,8 @@ #define BLOCKS 7000 +static long concurrentBlocks = 64; + static void tests() { SecKeychainRef kc = getPopulatedTestKeychain(); @@ -44,18 +46,33 @@ static void tests() { }); dispatch_group_t g = dispatch_group_create(); - for(int i = 0; i < BLOCKS; i++) { - dispatch_group_async(g, release_queue, ^() { - SecKeychainItemRef blockItem = NULL; + __block int iteration = 0; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(concurrentBlocks); + + dispatch_block_t identityBlock = ^() { + SecKeychainItemRef blockItem = NULL; + + CFMutableDictionaryRef query = createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric); + CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne); + + ok_status(SecItemCopyMatching(query, (CFTypeRef*) &blockItem), "%s: SecItemCopyMatching", testName); - CFMutableDictionaryRef query = createQueryKeyDictionary(kc, kSecAttrKeyClassSymmetric); - CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne); + CFReleaseNull(blockItem); + CFReleaseNull(query); - ok_status(SecItemCopyMatching(query, (CFTypeRef*) &blockItem), "%s: SecItemCopyMatching(%d)", testName, i); + dispatch_semaphore_signal(semaphore); + }; - CFReleaseNull(blockItem); - }); - } + // Send this to background queue, so that when we wait, it doesn't block main queue + + dispatch_group_async(g, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + for (iteration = 0; iteration < BLOCKS; iteration++) { + // Wait until one of our concurrentBlocks "slots" are available + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + dispatch_group_async(g, release_queue, identityBlock); + } + }); dispatch_group_wait(g, DISPATCH_TIME_FOREVER); diff --git a/OSX/libsecurity_keychain/regressions/kc-21-item-xattrs.c b/OSX/libsecurity_keychain/regressions/kc-21-item-xattrs.c index 5628d9cf..412d29f7 100644 --- a/OSX/libsecurity_keychain/regressions/kc-21-item-xattrs.c +++ b/OSX/libsecurity_keychain/regressions/kc-21-item-xattrs.c @@ -25,7 +25,7 @@ #include "keychain_regressions.h" #include "kc-helpers.h" #include "kc-keychain-file-helpers.h" -#include "test/testenv.h" +#include "regressions/test/testenv.h" // // testKeychainXattrs.c // diff --git a/OSX/libsecurity_keychain/regressions/kc-23-key-export-symmetric.m b/OSX/libsecurity_keychain/regressions/kc-23-key-export-symmetric.m index 7c7c023d..81e9bafc 100644 --- a/OSX/libsecurity_keychain/regressions/kc-23-key-export-symmetric.m +++ b/OSX/libsecurity_keychain/regressions/kc-23-key-export-symmetric.m @@ -75,6 +75,7 @@ static SecKeyRef generateSymmetricKey(SecKeychainRef keychainRef, CFStringRef la num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &rawnum); CFDictionarySetValue(parameters, kSecAttrKeySizeInBits, num); + CFReleaseNull(num); // Store in keychain CFDictionarySetValue(parameters, kSecUseKeychain, keychainRef); @@ -108,6 +109,7 @@ int kc_23_key_export_symmetric(int argc, char *const *argv) CFStringRef label = (__bridge_retained CFStringRef)([NSString stringWithFormat:@"Symmetric Cryptotest %ld %d", (long)time(NULL), arc4random(), nil]); cryptokey = generateSymmetricKey(kc, label); + CFReleaseNull(label); // Using SecItemExport CFMutableArrayRef keyUsage = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); @@ -127,6 +129,8 @@ int kc_23_key_export_symmetric(int argc, char *const *argv) status = SecItemExport(cryptokey, kSecFormatRawKey, 0, &exportParams, (CFDataRef *)&exportedKey2); ok_status(status, "%s: SecItemExport", testName); + CFReleaseNull(cryptokey); + is(CFDataGetLength(exportedKey2), 32, "%s: wrong AES-256 key size", testName); CFRelease(exportedKey2); diff --git a/OSX/libsecurity_keychain/regressions/kc-28-cert-sign.c b/OSX/libsecurity_keychain/regressions/kc-28-cert-sign.c index c05661e6..1cfc24b5 100644 --- a/OSX/libsecurity_keychain/regressions/kc-28-cert-sign.c +++ b/OSX/libsecurity_keychain/regressions/kc-28-cert-sign.c @@ -25,7 +25,7 @@ #include "keychain_regressions.h" #include "kc-helpers.h" #include "kc-keychain-file-helpers.h" -#include "test/testenv.h" +#include "regressions/test/testenv.h" // // Test for Radar 17159227 diff --git a/OSX/libsecurity_keychain/regressions/kc-30-xara.c b/OSX/libsecurity_keychain/regressions/kc-30-xara.c index dff385c2..e10f600a 100644 --- a/OSX/libsecurity_keychain/regressions/kc-30-xara.c +++ b/OSX/libsecurity_keychain/regressions/kc-30-xara.c @@ -297,8 +297,8 @@ static void testKeychainUpgrade() { UInt32 len = 400; // To test multi-threading, we want the upgrade to take a while. Add a bunch of passwords... - char oldkcFile[100]; - sprintf(oldkcFile, "%s/Library/test.keychain", getenv("HOME")); + char oldkcFile[MAXPATHLEN]; + snprintf(oldkcFile, sizeof(oldkcFile), "%s/Library/test.keychain", getenv("HOME")); unlink(oldkcFile); writeOldKeychain(name, oldkcFile); @@ -820,6 +820,7 @@ static void testUidAccess() { CFTypeRef result = NULL; ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name); + CFReleaseNull(query); ok(result != NULL, "%s: SecItemAdd returned a result", name); SecKeychainItemRef item = checkNCopyFirst(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1); @@ -924,6 +925,7 @@ static void testMultipleUidAccess() { CFTypeRef result = NULL; ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name); + CFReleaseNull(query); ok(result != NULL, "%s: SecItemAdd returned a result", name); checkN(name, createQueryItemDictionary(kc, kSecClassGenericPassword), 1); @@ -938,7 +940,13 @@ static void testRootUidAccess() { sprintf(name, "testRootUidAccess"); secnotice("integrity", "************************************* %s", name); - SecAccessRef access = SecAccessCreateWithOwnerAndACL(getuid(), 0, (kSecUseOnlyUID | kSecHonorRoot), NULL, NULL); + CFErrorRef error = NULL; + + SecAccessRef access = SecAccessCreateWithOwnerAndACL(getuid(), 0, (kSecUseOnlyUID | kSecHonorRoot), NULL, &error); + ok(access, "%s: SecAccessCreateWithOwnerAndACL returned an access", name); + CFStringRef errorDesc = error ? CFErrorCopyDescription(error) : NULL; + is(error, NULL, "%s: SecAccessCreateWithOwnerAndACL did not return an error: %@", name, errorDesc ? errorDesc : CFSTR("no error")); + CFReleaseNull(errorDesc); SecKeychainRef kc = newKeychain(name); CFMutableDictionaryRef query = createAddItemDictionary(kc, kSecClassGenericPassword, CFSTR("test label")); @@ -946,6 +954,7 @@ static void testRootUidAccess() { CFTypeRef result = NULL; ok_status(SecItemAdd(query, &result), "%s: SecItemAdd", name); + CFReleaseNull(query); ok(result != NULL, "%s: SecItemAdd returned a result", name); query = createQueryItemDictionary(kc, kSecClassGenericPassword); @@ -959,7 +968,7 @@ static void testRootUidAccess() { ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", name); CFReleaseNull(kc); } -#define testRootUidAccessTests (newKeychainTests + checkNTests + 4 + checkNTests) +#define testRootUidAccessTests (newKeychainTests + 2 + checkNTests + 4 + checkNTests) static void testBadACL() { char name[100]; @@ -1093,6 +1102,17 @@ static void tests(void) { initializeKeychainTests("kc-30-xara"); + testKeychainUpgrade(); + testKeychainCreateOver(); + testKeychainDowngrade(); + testKeychainWrongFile256(); + testKeychainWrongFile512(); + testUidAccess(); + testMultipleUidAccess(); + testRootUidAccess(); + testBadACL(); + testIterateLockedKeychain(); + testAddItem(kSecClassGenericPassword, CFSTR("265438ea6807b509c9c6962df3f5033fd1af118f76c5f550e3ed90cb0d3ffce4")); testAddItem(kSecClassInternetPassword, CFSTR("be34c4562153063ce9cdefc2c34451d5e6e98a447f293d68a67349c1b5d1164f")); @@ -1132,17 +1152,6 @@ static void tests(void) testAddAfterCorruptKey(dldbHandle); unloadDL(&dldbHandle); - testKeychainUpgrade(); - testKeychainCreateOver(); - testKeychainDowngrade(); - testKeychainWrongFile256(); - testKeychainWrongFile512(); - testUidAccess(); - testMultipleUidAccess(); - testRootUidAccess(); - testBadACL(); - testIterateLockedKeychain(); - //makeOldKeychainBlob(); } diff --git a/OSX/libsecurity_keychain/regressions/kc-40-seckey.m b/OSX/libsecurity_keychain/regressions/kc-40-seckey.m index 61f087b5..da3a3eac 100644 --- a/OSX/libsecurity_keychain/regressions/kc-40-seckey.m +++ b/OSX/libsecurity_keychain/regressions/kc-40-seckey.m @@ -69,10 +69,11 @@ static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecA ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, sig, sigLen), "digest and verify"); /* Invalidate the signature. */ - sig[0] ^= 0xff; + /* Tweak the least-significant bit to avoid putting the signature out of range. */ + sig[sigLen-1] ^= 1; is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, sig, sigLen), errSSLCrypto, "digest and verify bad sig"); - sig[0] ^= 0xff; + sig[sigLen-1] ^= 1; dataToDigest[0] ^= 0xff; is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, sig, sigLen), errSSLCrypto, "digest and verify bad digest"); @@ -637,9 +638,14 @@ static void testsupportedalgos(size_t keySizeInBits) ok(SecKeyIsAlgorithmSupported(pubKey, kSecKeyOperationTypeEncrypt, algorithm), "pubKey supports encrypt algorithm %@", algorithm); ok(!SecKeyIsAlgorithmSupported(privKey, kSecKeyOperationTypeEncrypt, algorithm), - "privKey doesn't supports encrypt algorithm %@", algorithm); - ok(!SecKeyIsAlgorithmSupported(pubKey, kSecKeyOperationTypeDecrypt, algorithm), - "pubKey doesn't support decrypt algorithm %@", algorithm); + "privKey doesn't support encrypt algorithm %@", algorithm); + if (i >= 6 /* >= kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM */) { + ok(!SecKeyIsAlgorithmSupported(pubKey, kSecKeyOperationTypeDecrypt, algorithm), + "pubKey doesn't support algorithm %@", algorithm); + } else { + ok(SecKeyIsAlgorithmSupported(pubKey, kSecKeyOperationTypeDecrypt, algorithm), + "pubKey supports decrypt algorithm %@", algorithm); + } CFReleaseNull(algorithm); } ok(!SecKeyIsAlgorithmSupported(privKey, kSecKeyOperationTypeDecrypt, kSecKeyAlgorithmRSAEncryptionOAEPSHA512), diff --git a/OSX/libsecurity_keychain/regressions/kc-41-sececkey.m b/OSX/libsecurity_keychain/regressions/kc-41-sececkey.m index 3b0b0ff0..2c5678b9 100644 --- a/OSX/libsecurity_keychain/regressions/kc-41-sececkey.m +++ b/OSX/libsecurity_keychain/regressions/kc-41-sececkey.m @@ -195,9 +195,21 @@ static void testkeygen(size_t keySizeInBits) { CFRelease(kzib); CFRelease(kgp); + SecKeyRef pubKeybis = SecKeyCopyPublicKey(privKey); + ok(pubKeybis!=NULL); + is(CFGetRetainCount(pubKeybis),2); // pubKey + pubKeybis + CFDataRef PubKeyData = SecKeyCopyExternalRepresentation(pubKey, NULL); + CFDataRef PubKeybisData = SecKeyCopyExternalRepresentation(pubKeybis, NULL); + isnt(CFDataGetLength(PubKeyData),0); + ok(CFEqual(PubKeyData,PubKeybisData)); + CFReleaseNull(PubKeyData); + CFReleaseNull(PubKeybisData); + CFReleaseNull(pubKeybis); + + SKIP: { skip("keygen failed", 8, status == errSecSuccess); - ok(pubKey, "pubkey returned"); + ok(pubKey, "pubKey returned"); ok(privKey, "privKey returned"); is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok"); is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok"); @@ -229,14 +241,14 @@ SKIP: { ok_status(SecItemDelete(privitem), "delete private key"); CFReleaseNull(privitem); - const void *pubkeys[] = { + const void *pubKeys[] = { kSecValueRef }; const void *pubvalues[] = { pubKey }; - CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubkeys, pubvalues, - sizeof(pubkeys) / sizeof(*pubkeys), NULL, NULL); + CFDictionaryRef pubitem = CFDictionaryCreate(NULL, pubKeys, pubvalues, + sizeof(pubKeys) / sizeof(*pubKeys), NULL, NULL); #if TARGET_OS_IPHONE ok_status(SecItemAdd(pubitem, NULL), "add public key"); #endif @@ -288,7 +300,7 @@ static void testkeygen2(size_t keySizeInBits) { SKIP: { skip("keygen failed", 8, status == errSecSuccess); - ok(pubKey, "pubkey returned"); + ok(pubKey, "pubKey returned"); ok(privKey, "privKey returned"); is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok"); is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok"); @@ -336,6 +348,39 @@ SKIP: { CFRelease(privd); } +static void testkeygen3(size_t keySizeInBits) { + SecKeyRef pubKey = NULL, privKey = NULL; + size_t keySizeInBytes = (keySizeInBits + 7) / 8; + CFNumberRef kzib; + + kzib = CFNumberCreate(NULL, kCFNumberSInt64Type, &keySizeInBits); + CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(kgp, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom); + CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib); + CFDictionaryAddValue(kgp, kSecAttrIsPermanent, kCFBooleanFalse); + + ok(privKey = SecKeyCreateRandomKey(kgp, NULL)); + CFRelease(kzib); + CFRelease(kgp); + + ok(pubKey = SecKeyCopyPublicKey(privKey)); + is(CFGetRetainCount(pubKey),1); + + /* Sign something. */ + uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, }; + uint8_t sig[8+2*keySizeInBytes]; + size_t sigLen = sizeof(sig); + ok_status(SecKeyRawSign(privKey, kSecPaddingNone, + something, sizeof(something), sig, &sigLen), "sign something"); + ok_status(SecKeyRawVerify(pubKey, kSecPaddingNone, + something, sizeof(something), sig, sigLen), "verify sig on something"); + + /* Cleanup. */ + CFReleaseNull(pubKey); + CFReleaseNull(privKey); +} + + #if TARGET_OS_IPHONE // Raw DER Key const uint8_t EC_P256_KeyDER[]={ @@ -411,8 +456,8 @@ const uint8_t EC_P256_SigDER_LargeInt[]={ static void testsignformat(void) { - SecKeyRef pkey = NULL; - SecKeyRef pubkey = NULL; + SecKeyRef privKey = NULL; + SecKeyRef pubKey = NULL; CFArrayRef KeyArrayPub=NULL; CFArrayRef KeyArrayPriv=NULL; uint8_t EC_signature_DER[72]; @@ -423,13 +468,13 @@ static void testsignformat(void) #if TARGET_OS_IPHONE // Key import for iOS { - ok((pkey = SecKeyCreateECPrivateKey(kCFAllocatorDefault, + ok((privKey = SecKeyCreateECPrivateKey(kCFAllocatorDefault, EC_P256_KeyDER, sizeof(EC_P256_KeyDER), kSecKeyEncodingPkcs1)) != NULL, "import privkey"); CFDataRef pubdata = NULL; - ok_status(SecKeyCopyPublicBytes(pkey, &pubdata), "pub key from priv key"); + ok_status(SecKeyCopyPublicBytes(privKey, &pubdata), "pub key from priv key"); - ok((pubkey = SecKeyCreateECPublicKey(kCFAllocatorDefault, + ok((pubKey = SecKeyCreateECPublicKey(kCFAllocatorDefault, CFDataGetBytePtr(pubdata), CFDataGetLength(pubdata), kSecKeyEncodingBytes))!=NULL, "recreate seckey"); @@ -447,7 +492,7 @@ static void testsignformat(void) seit=kSecItemTypePublicKey; ok_status(SecItemImport(DER_key,NULL,&sef,&seit,0,NULL,NULL,&KeyArrayPub), "Import DER key"); ok((!(KeyArrayPub==NULL) && CFArrayGetCount(KeyArrayPub)==1), "One key imported"); - pubkey=(SecKeyRef)CFArrayGetValueAtIndex(KeyArrayPub,0); + pubKey=(SecKeyRef)CFArrayGetValueAtIndex(KeyArrayPub,0); CFReleaseNull(DER_key); // Private key @@ -455,41 +500,41 @@ static void testsignformat(void) seit=kSecItemTypePrivateKey; ok_status(SecItemImport(DER_key,NULL,&sef,&seit,0,NULL,NULL,&KeyArrayPriv), "Import DER key"); ok((!(KeyArrayPriv==NULL) && CFArrayGetCount(KeyArrayPriv)==1), "One key imported"); - pkey=(SecKeyRef)CFArrayGetValueAtIndex(KeyArrayPriv,0); + privKey=(SecKeyRef)CFArrayGetValueAtIndex(KeyArrayPriv,0); CFReleaseNull(DER_key); } #endif // Verify fixed signature - ok_status(SecKeyRawVerify(pubkey, kSecPaddingPKCS1, + ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1, EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigDER, sizeof(EC_P256_SigDER)), "verify DER sig on something"); - ok_status(SecKeyRawVerify(pubkey, kSecPaddingSigRaw, + ok_status(SecKeyRawVerify(pubKey, kSecPaddingSigRaw, EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigRaw, sizeof(EC_P256_SigRaw)), "verify RAW sig on something"); // Verify signature with mismatching format - ok_status(!SecKeyRawVerify(pubkey, kSecPaddingSigRaw, + ok_status(!SecKeyRawVerify(pubKey, kSecPaddingSigRaw, EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigDER, sizeof(EC_P256_SigDER)), "verify DER sig with RAW option"); - ok_status(!SecKeyRawVerify(pubkey, kSecPaddingPKCS1, + ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1, EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigRaw, sizeof(EC_P256_SigRaw)), "verify RAW sig with DER something"); // Sign something in each format - ok_status(SecKeyRawSign(pkey, kSecPaddingPKCS1, + ok_status(SecKeyRawSign(privKey, kSecPaddingPKCS1, EC_SigDigest, sizeof(EC_SigDigest), EC_signature_DER, &EC_signature_DER_size), "sign DER sig on something"); - ok_status(SecKeyRawSign(pkey, kSecPaddingSigRaw, + ok_status(SecKeyRawSign(privKey, kSecPaddingSigRaw, EC_SigDigest, sizeof(EC_SigDigest), EC_signature_RAW, &EC_signature_RAW_size), "sign RAW sig on something"); // Verify expecting that verification does the right thing. - ok_status(SecKeyRawVerify(pubkey, kSecPaddingPKCS1, + ok_status(SecKeyRawVerify(pubKey, kSecPaddingPKCS1, EC_SigDigest, sizeof(EC_SigDigest), EC_signature_DER, EC_signature_DER_size), "verify DER sig on something"); - ok_status(SecKeyRawVerify(pubkey, kSecPaddingSigRaw, + ok_status(SecKeyRawVerify(pubKey, kSecPaddingSigRaw, EC_SigDigest, sizeof(EC_SigDigest), EC_signature_RAW, EC_signature_RAW_size), "verify RAW sig on something"); // Verify signature with one integer larger than it should be - ok_status(!SecKeyRawVerify(pubkey, kSecPaddingPKCS1, + ok_status(!SecKeyRawVerify(pubKey, kSecPaddingPKCS1, EC_SigDigest, sizeof(EC_SigDigest), EC_P256_SigDER_LargeInt, sizeof(EC_P256_SigDER_LargeInt)), "verify DER sig with large integer"); @@ -524,6 +569,17 @@ static void testkeyexchange(unsigned long keySizeInBits) "Generate %ld bit (%ld byte) EC keypair (status = %d)", keySizeInBits, keySizeInBytes, (int)status); + SecKeyRef pubKey1bis = SecKeyCopyPublicKey(privKey1); + ok(pubKey1bis!=NULL); + is(CFGetRetainCount(pubKey1bis),1); + CFDataRef PubKey1Data = SecKeyCopyExternalRepresentation(pubKey1, NULL); + CFDataRef PubKey1bisData = SecKeyCopyExternalRepresentation(pubKey1bis, NULL); + isnt(CFDataGetLength(PubKey1Data),0); + ok(CFEqual(PubKey1Data,PubKey1bisData)); + CFReleaseNull(PubKey1Data); + CFReleaseNull(PubKey1bisData); + CFReleaseNull(pubKey1bis); + SecKeyRef pubKey2 = NULL, privKey2 = NULL; NSDictionary *kgp2 = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC, @@ -607,6 +663,10 @@ static void tests(void) testkeygen2(384); testkeygen2(521); + testkeygen3(256); + testkeygen3(384); + testkeygen3(521); + testkeyexchange(256); testkeyexchange(384); testkeyexchange(521); @@ -614,7 +674,7 @@ static void tests(void) int kc_41_sececkey(int argc, char *const *argv) { - plan_tests(245); + plan_tests(288); tests(); diff --git a/OSX/libsecurity_keychain/regressions/kc-helpers.h b/OSX/libsecurity_keychain/regressions/kc-helpers.h index b84d344a..60fc2583 100644 --- a/OSX/libsecurity_keychain/regressions/kc-helpers.h +++ b/OSX/libsecurity_keychain/regressions/kc-helpers.h @@ -59,10 +59,10 @@ static void startTest(const char* thisTestName) { static void initializeKeychainTests(const char* thisTestName) { const char *home_dir = getenv("HOME"); - sprintf(keychainName, "test-%s.asdf", thisTestName); - sprintf(keychainFile, "%s/Library/Keychains/%s", home_dir, keychainName); - sprintf(keychainDbFile, "%s/Library/Keychains/%s-db", home_dir, keychainName); - sprintf(keychainTempFile, "%s/Library/Keychains/test_temp", home_dir); + snprintf(keychainName, sizeof(keychainName), "test-%s.asdf", thisTestName); + snprintf(keychainFile, sizeof(keychainFile), "%s/Library/Keychains/%s", home_dir, keychainName); + snprintf(keychainDbFile, sizeof(keychainDbFile), "%s/Library/Keychains/%s-db", home_dir, keychainName); + snprintf(keychainTempFile, sizeof(keychainTempFile), "%s/Library/Keychains/test_temp", home_dir); deleteKeychainFiles(keychainFile); diff --git a/OSX/libsecurity_keychain/regressions/kc-item-helpers.h b/OSX/libsecurity_keychain/regressions/kc-item-helpers.h index 1532e72e..906f3556 100644 --- a/OSX/libsecurity_keychain/regressions/kc-item-helpers.h +++ b/OSX/libsecurity_keychain/regressions/kc-item-helpers.h @@ -56,7 +56,7 @@ static CFMutableDictionaryRef addLabel(CFMutableDictionaryRef query, CFStringRef return query; } -static CFMutableDictionaryRef makeBaseItemDictionary(CFStringRef itemclass, CFStringRef service) { +static CFMutableDictionaryRef createBaseItemDictionary(CFStringRef itemclass, CFStringRef service) { CFMutableDictionaryRef query = makeBaseDictionary(itemclass); if(CFEqual(itemclass, kSecClassInternetPassword)) { @@ -70,7 +70,7 @@ static CFMutableDictionaryRef makeBaseItemDictionary(CFStringRef itemclass, CFSt } static CFMutableDictionaryRef createQueryItemDictionaryWithService(SecKeychainRef kc, CFStringRef itemclass, CFStringRef service) { - return convertToQuery(makeBaseItemDictionary(itemclass, service), kc); + return convertToQuery(createBaseItemDictionary(itemclass, service), kc); } static CFMutableDictionaryRef createQueryItemDictionary(SecKeychainRef kc, CFStringRef itemclass) { return createQueryItemDictionaryWithService(kc, itemclass, NULL); @@ -90,7 +90,7 @@ static CFMutableDictionaryRef createQueryCustomItemDictionary(SecKeychainRef kc, } static CFMutableDictionaryRef createAddCustomItemDictionaryWithService(SecKeychainRef kc, CFStringRef itemclass, CFStringRef label, CFStringRef account, CFStringRef service) { - CFMutableDictionaryRef query = makeBaseItemDictionary(itemclass, service); + CFMutableDictionaryRef query = createBaseItemDictionary(itemclass, service); CFDictionaryAddValue(query, kSecUseKeychain, kc); CFDictionarySetValue(query, kSecAttrAccount, account); diff --git a/OSX/libsecurity_keychain/regressions/kc-keychain-file-helpers.h b/OSX/libsecurity_keychain/regressions/kc-keychain-file-helpers.h index f6d99a41..b5baede4 100644 --- a/OSX/libsecurity_keychain/regressions/kc-keychain-file-helpers.h +++ b/OSX/libsecurity_keychain/regressions/kc-keychain-file-helpers.h @@ -64,6 +64,7 @@ static void writeFile(const char* path, uint8_t* buf, size_t len) { FILE * fp = fopen(path, "w+"); fwrite(buf, sizeof(uint8_t), len, fp); fclose(fp); + sync(); } // The following keychain includes: diff --git a/OSX/libsecurity_keychain/regressions/keychain_regressions.h b/OSX/libsecurity_keychain/regressions/keychain_regressions.h index 80ad5d9b..b9ae13c9 100644 --- a/OSX/libsecurity_keychain/regressions/keychain_regressions.h +++ b/OSX/libsecurity_keychain/regressions/keychain_regressions.h @@ -2,7 +2,7 @@ 1) add it here 2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes */ -#include +#include ONE_TEST(kc_01_keychain_creation) ONE_TEST(kc_02_unlock_noui) diff --git a/OSX/libsecurity_keychain/xpc-tsa/main-tsa.m b/OSX/libsecurity_keychain/xpc-tsa/main-tsa.m index 807b1f28..ebcbe466 100644 --- a/OSX/libsecurity_keychain/xpc-tsa/main-tsa.m +++ b/OSX/libsecurity_keychain/xpc-tsa/main-tsa.m @@ -221,12 +221,17 @@ static void communicateWithTimeStampingServer(xpc_object_t event, const char *re } size_t length = (errStr || !data) ? 0 : [data length]; - xpc_object_t tsaReply = xpc_data_create([data bytes], length); + xpc_object_t tsaReply = data ? xpc_data_create([data bytes], length) : NULL; xpc_connection_t peer = xpc_dictionary_get_remote_connection(event); - xpc_object_t reply = (tsaError)? - xpc_create_reply_with_format(event, - "{TimeStampReply: %value, TimeStampError: %value, TimeStampStatus: %value}", tsaReply, tsaError, tsaStatusCode) : - xpc_create_reply_with_format(event, "{TimeStampReply: %value}", tsaReply); + xpc_object_t reply = NULL; + if (tsaError && tsaReply && tsaStatusCode) { + reply = xpc_create_reply_with_format(event, "{TimeStampReply: %value, TimeStampError: %value, TimeStampStatus: %value}", + tsaReply, tsaError, tsaStatusCode); + } else if (tsaReply) { + reply = xpc_create_reply_with_format(event, "{TimeStampReply: %value}", tsaReply); + } else { + reply = xpc_create_reply_with_format(event, "No TimeStampReply or TimeStampError"); + } xpc_connection_send_message(peer, reply); xpc_release(reply); diff --git a/OSX/libsecurity_keychain/xpc-tsa/timestampclient.h b/OSX/libsecurity_keychain/xpc-tsa/timestampclient.h index 190fe925..4f3d3ae0 100644 --- a/OSX/libsecurity_keychain/xpc-tsa/timestampclient.h +++ b/OSX/libsecurity_keychain/xpc-tsa/timestampclient.h @@ -39,7 +39,7 @@ void sendTSARequest(CFDataRef tsaReq, const char *tsaURL, TSARequestCompletionBl NSURL *url; NSMutableURLRequest *urlRequest; } -@property (retain) id delegate; +@property (weak) id delegate; @property (retain) id url; @property (retain) id urlRequest; diff --git a/OSX/libsecurity_keychain/xpc-tsa/timestampclient.m b/OSX/libsecurity_keychain/xpc-tsa/timestampclient.m index becfecf5..148be634 100644 --- a/OSX/libsecurity_keychain/xpc-tsa/timestampclient.m +++ b/OSX/libsecurity_keychain/xpc-tsa/timestampclient.m @@ -57,8 +57,8 @@ void sendTSARequest(CFDataRef tsaReq, const char *tsaURL, TSARequestCompletionBl if ((self = [super init])) { NSString *escapedURLStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - self.url = [NSURL URLWithString:escapedURLStr]; - self.urlRequest = [[NSMutableURLRequest alloc] initWithURL:self.url + url = [[NSURL alloc] initWithString:escapedURLStr]; + urlRequest = [[NSMutableURLRequest alloc] initWithURL:self.url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:(NSTimeInterval)15.0]; } return self; diff --git a/OSX/libsecurity_keychain/xpc/main.c b/OSX/libsecurity_keychain/xpc/main.c index 5cc39f1b..6b337e26 100644 --- a/OSX/libsecurity_keychain/xpc/main.c +++ b/OSX/libsecurity_keychain/xpc/main.c @@ -264,7 +264,7 @@ xpc_object_t create_all_sandbox_extensions(xpc_object_t path_dict) static void handle_request_event(struct connection_info *info, xpc_object_t event) { - xpc_connection_t peer = xpc_dictionary_get_connection(event); + xpc_connection_t peer = xpc_dictionary_get_remote_connection(event); xpc_type_t xtype = xpc_get_type(event); if (info->done) { syslog(LOG_ERR, "event %p while done", event); @@ -414,6 +414,9 @@ int main(int argc, const char *argv[]) syslog(LOG_ERR, "Can't lookup SecKeychainGetPath in %p: %s", security_framework, dlerror()); return EX_OSERR; } + } else { + syslog(LOG_ERR, "Failed to open Security framework: %s", dlerror()); + return EX_OSERR; } xpc_main(handle_connection_event); diff --git a/OSX/libsecurity_manifest/lib/Download.cpp b/OSX/libsecurity_manifest/lib/Download.cpp index 69171c43..ce4a4efc 100644 --- a/OSX/libsecurity_manifest/lib/Download.cpp +++ b/OSX/libsecurity_manifest/lib/Download.cpp @@ -109,7 +109,6 @@ void Download::GoOrNoGo (SecTrustResultType result) // we don't in this case, as the Apple signing root had better be // in X509 anchors. I'm leaving this broken out for ease of use // in case we change our minds... - case kSecTrustResultConfirm: case kSecTrustResultRecoverableTrustFailure: case kSecTrustResultUnspecified: { @@ -181,7 +180,7 @@ void Download::ParseTicket (CFDataRef ticket) // from the hashing dictionary, get the sector size number = (CFNumberRef) CFDictionaryGetValue (hashInfo, SD_XML_SECTOR_SIZE); - CFNumberGetValue (number, kCFNumberSInt32Type, &mSectorSize); + CFNumberGetValue (number, kCFNumberSInt64Type, &mSectorSize); // get the hashes mHashes = (CFDataRef) CFDictionaryGetValue (hashInfo, SD_XML_DIGESTS); diff --git a/OSX/libsecurity_manifest/lib/SecManifest.cpp b/OSX/libsecurity_manifest/lib/SecManifest.cpp index 88924a74..7e50263d 100644 --- a/OSX/libsecurity_manifest/lib/SecManifest.cpp +++ b/OSX/libsecurity_manifest/lib/SecManifest.cpp @@ -1,5 +1,6 @@ #include "SecManifest.h" #include +#include #include "Manifest.h" #include #include @@ -76,7 +77,10 @@ void SecManifestRelease (SecManifestRef manifest) #pragma clang diagnostic ignored "-Wunused-function" static const char* GetDescription (CFTypeRef object) { - return CFStringGetCStringPtr (CFCopyDescription (object), kCFStringEncodingMacRoman); + CFStringRef s = CFCopyDescription (object); + const char * p = CFStringGetCStringPtr (s, kCFStringEncodingMacRoman); + CFReleaseNull(s); + return p; } #pragma clang diagnostic pop diff --git a/OSX/libsecurity_manifest/lib/SecureDownload.h b/OSX/libsecurity_manifest/lib/SecureDownload.h index bf517f13..80fc43e8 100644 --- a/OSX/libsecurity_manifest/lib/SecureDownload.h +++ b/OSX/libsecurity_manifest/lib/SecureDownload.h @@ -55,7 +55,7 @@ extern "C" { #include #include - +#include /* SecTrustRef */ typedef struct OpaqueSecureDownload *SecureDownloadRef; diff --git a/OSX/libsecurity_manifest/lib/SecureDownloadInternal.c b/OSX/libsecurity_manifest/lib/SecureDownloadInternal.c index 99fd2f9c..e035ca50 100644 --- a/OSX/libsecurity_manifest/lib/SecureDownloadInternal.c +++ b/OSX/libsecurity_manifest/lib/SecureDownloadInternal.c @@ -1,6 +1,7 @@ #include #include "SecureDownloadInternal.h" +#include "SecCFRelease.h" // // SecureDownloadXML: SecureDownloadXML.c @@ -556,20 +557,20 @@ static void _parseXMLNode(const void *value, void *context) { CFStringRef name = copyChildWithNameAsString(tree, namespaces, SD_XML_NAMESPACE, SD_XML_NAME); if (name && state->plist) { CFDictionarySetValue(state->plist, SD_XML_NAME, name); - CFRelease(name); } + CFReleaseNull(name); CFNumberRef size = copyChildWithNameAsInteger(tree, namespaces, SD_XML_NAMESPACE, SD_XML_SIZE); if (size && state->plist) { CFDictionarySetValue(state->plist, SD_XML_SIZE, size); - CFRelease(size); } + CFReleaseNull(size); CFDateRef created = copyChildWithNameAsDate(tree, namespaces, SD_XML_NAMESPACE, SD_XML_CREATED); if (created && state->plist) { CFDictionarySetValue(state->plist, SD_XML_CREATED, created); - CFRelease(created); } + CFReleaseNull(created); descend = 1; @@ -577,8 +578,8 @@ static void _parseXMLNode(const void *value, void *context) { CFArrayRef urls = copyChildrenWithNameAsURLs(tree, namespaces, SD_XML_NAMESPACE, SD_XML_URL); if (urls && state->plist) { CFDictionarySetValue(state->plist, SD_XML_URL, urls); - CFRelease(urls); } + CFReleaseNull(urls); } else if (CFEqual(name, SD_XML_VERIFICATIONS)) { CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -750,7 +751,7 @@ static void _appendCFDate(CFMutableDataRef data, CFDateRef date) { static CFArrayRef dictionaryGetSortedKeys(CFDictionaryRef dictionary) { CFIndex count = CFDictionaryGetCount(dictionary); - const void** keys = malloc(sizeof(CFStringRef) * count); + const void** keys = malloc(sizeof(CFTypeRef) * count); CFDictionaryGetKeysAndValues(dictionary, keys, NULL); CFArrayRef keysArray = CFArrayCreate(NULL, keys, count, &kCFTypeArrayCallBacks); CFMutableArrayRef sortedKeys = CFArrayCreateMutableCopy(NULL, count, keysArray); diff --git a/OSX/libsecurity_mds/lib/MDSAttrUtils.cpp b/OSX/libsecurity_mds/lib/MDSAttrUtils.cpp index a47ecc4f..17a5f30e 100644 --- a/OSX/libsecurity_mds/lib/MDSAttrUtils.cpp +++ b/OSX/libsecurity_mds/lib/MDSAttrUtils.cpp @@ -158,7 +158,7 @@ bool MDSCfTypeToUInt32( MPDebug("MDS cfTypeToInt: Bad CFNumber type (%ld) key %s", numType, key); return false; } - Boolean brtn = CFNumberGetValue(cfNum, numType, &tmpValue); + Boolean brtn = CFNumberGetValue(cfNum, kCFNumberSInt64Type, &tmpValue); if(!brtn) { MPDebug("MDS cfTypeToInt: Bad CFNumber conversion"); return false; diff --git a/OSX/libsecurity_mds/lib/MDSSession.cpp b/OSX/libsecurity_mds/lib/MDSSession.cpp index 6e5052c2..f11949ef 100644 --- a/OSX/libsecurity_mds/lib/MDSSession.cpp +++ b/OSX/libsecurity_mds/lib/MDSSession.cpp @@ -146,8 +146,8 @@ static std::string GetMDSBaseDBDir(bool isRoot) if (result == 0) { // we have an error, log it - syslog(LOG_CRIT, "confstr on _CS_DARWIN_USER_CACHE_DIR returned an error."); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + syslog(LOG_CRIT, "confstr on _CS_DARWIN_USER_CACHE_DIR returned an error: %d", errno); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } retValue = strBuffer; @@ -326,7 +326,7 @@ static bool doesFileExist( } if(purge) { /* If we can't stat it we sure can't delete it. */ - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } return false; } @@ -344,17 +344,17 @@ static bool doesFileExist( if(fileType == S_IFDIR) { /* directory: clean then remove */ if(cleanDir(filePath, NULL, 0)) { - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } if(rmdir(filePath)) { MSDebug("rmdir(%s) returned %d", filePath, errno); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } } else { if(unlink(filePath)) { MSDebug("unlink(%s) returned %d", filePath, errno); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } } @@ -397,13 +397,13 @@ static bool doFilesExist( if(objectExist) { if(unlink(objDbFile)) { MSDebug("unlink(%s) returned %d", objDbFile, errno); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } } if(directExist) { if(unlink(directDbFile)) { MSDebug("unlink(%s) returned %d", directDbFile, errno); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } } return false; @@ -580,7 +580,7 @@ MDSSession::install () // Installation requires root // if(geteuid() != (uid_t)0) { - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } // @@ -593,19 +593,19 @@ MDSSession::install () /* ensure MDS base directory exists with correct permissions */ if(createDir(MDS_BASE_DB_DIR, MDS_SYSTEM_UID, MDS_BASE_DB_DIR_MODE)) { MSDebug("Error creating base MDS dir; aborting."); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } /* ensure the the system MDS DB directory exists with correct permissions */ if(createDir(MDS_SYSTEM_DB_DIR, MDS_SYSTEM_UID, MDS_SYSTEM_DB_DIR_MODE)) { MSDebug("Error creating system MDS dir; aborting."); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } LockHelper lh; if(!lh.obtainLock(MDS_INSTALL_LOCK_PATH, DB_LOCK_TIMEOUT)) { - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } /* @@ -616,13 +616,13 @@ MDSSession::install () const char *savedFile = MDS_INSTALL_LOCK_NAME; if(cleanDir(MDS_SYSTEM_DB_DIR, &savedFile, 1)) { /* this should never happen - we're root */ - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } const char *savedFiles[] = {MDS_SYSTEM_DB_COMP, kExceptionDeletePath}; if(cleanDir(MDS_BASE_DB_DIR, savedFiles, 2)) { /* this should never happen - we're root */ - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } /* @@ -645,7 +645,7 @@ MDSSession::install () void MDSSession::uninstall () { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + CssmError::throwMeNoLogging(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); } /* @@ -698,7 +698,7 @@ void MDSSession::DbOpen(const char *DbName, * a system MDS DB file or a per-user MDS DB file). */ if(DbName == NULL) { - CssmError::throwMe(CSSMERR_DL_INVALID_DB_NAME); + CssmError::throwMeNoLogging(CSSMERR_DL_INVALID_DB_NAME); } const char *dbName; if(!strcmp(DbName, MDS_OBJECT_DIRECTORY_NAME)) { @@ -708,7 +708,7 @@ void MDSSession::DbOpen(const char *DbName, dbName = MDS_DIRECT_DB_NAME; } else { - CssmError::throwMe(CSSMERR_DL_INVALID_DB_NAME); + CssmError::throwMeNoLogging(CSSMERR_DL_INVALID_DB_NAME); } char fullPath[MAXPATHLEN]; dbFullPath(dbName, fullPath); @@ -750,7 +750,7 @@ void MDSSession::GetDbNameFromHandle(CSSM_DB_HANDLE DBHandle, char **DbName) { printf("GetDbNameFromHandle: code on demand\n"); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } // @@ -891,7 +891,7 @@ static void safeCopyFile( if(!doesFileExist(fromPath, fromUid, false, sb)) { MSDebug("safeCopyFile: bad system DB file %s", fromPath); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } /* create temp destination */ @@ -900,7 +900,7 @@ static void safeCopyFile( if(destFd < 0) { error = errno; MSDebug("Error %d opening user DB file %s\n", error, tmpToPath); - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } struct flock fl; @@ -909,7 +909,7 @@ static void safeCopyFile( if(fchmod(destFd, toMode)) { error = errno; MSDebug("Error %d chmoding user DB file %s\n", error, tmpToPath); - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } /* open source for reading */ @@ -917,7 +917,7 @@ static void safeCopyFile( if(srcFd < 0) { error = errno; MSDebug("Error %d opening system DB file %s\n", error, fromPath); - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } /* acquire the same kind of lock AtomicFile uses */ @@ -936,7 +936,7 @@ static void safeCopyFile( continue; } MSDebug("Error %d locking system DB file %s\n", error, fromPath); - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } else { break; @@ -960,7 +960,7 @@ static void safeCopyFile( delete [] buf; error = errno; MSDebug("Error %d reading system DB file %s\n", error, fromPath); - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } ssize_t bytesWritten; @@ -973,7 +973,7 @@ static void safeCopyFile( delete [] buf; error = errno; MSDebug("Error %d writing user DB file %s\n", error, tmpToPath); - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } } delete [] buf; @@ -1004,7 +1004,7 @@ static void safeCopyFile( } } if(error) { - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } } @@ -1104,7 +1104,7 @@ void MDSSession::updateDataBases() LockHelper lh; if(!lh.obtainLock(userDbLockPath.c_str(), DB_LOCK_TIMEOUT)) { - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } try { if(!isRoot) { @@ -1326,7 +1326,7 @@ MDSSession::createSystemDatabase( free(dbInfoP->DefaultParsingModules); free(dbInfoP->RecordAttributeNames); free(dbInfoP->RecordIndexes); - CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR); + CssmError::throwMeNoLogging(CSSM_ERRCODE_MDS_ERROR); } free(dbInfoP->DefaultParsingModules); free(dbInfoP->RecordAttributeNames); @@ -1403,7 +1403,7 @@ MDSSession::DbFilesInfo::DbFilesInfo( if(rtn) { int error = errno; MSDebug("Error %d statting DB file %s", error, path); - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } mLaterTimestamp = sb.st_mtimespec.tv_sec; sprintf(path, "%s/%s", mDbPath, MDS_DIRECT_DB_NAME); @@ -1412,7 +1412,7 @@ MDSSession::DbFilesInfo::DbFilesInfo( if(rtn) { int error = errno; MSDebug("Error %d statting DB file %s", error, path); - UnixError::throwMe(error); + UnixError::throwMeNoLogging(error); } if(sb.st_mtimespec.tv_sec > mLaterTimestamp) { mLaterTimestamp = sb.st_mtimespec.tv_sec; @@ -1494,12 +1494,11 @@ void MDSSession::DbFilesInfo::updateSystemDbInfo( MDSSession::DbFilesInfo::TbdRecord::TbdRecord( const CSSM_DATA &guid) { - assert(guid.Length <= MAX_GUID_LEN); - assert(guid.Length != 0); - memmove(mGuid, guid.Data, guid.Length); - if(mGuid[guid.Length - 1] != '\0') { - mGuid[guid.Length] = '\0'; - } + if (guid.Length != 0 && guid.Length < MAX_GUID_LEN) { + memmove(mGuid, guid.Data, guid.Length); + // mGuid is treated as a string elsewhere; terminate + mGuid[guid.Length] = '\0'; + } } /* @@ -1530,9 +1529,13 @@ void MDSSession::DbFilesInfo::checkOutdatedPlugin( obsolete = true; } if(obsolete) { - TbdRecord *tbdRecord = new TbdRecord(guidValue); - tbdVector.push_back(tbdRecord); - MSDebug("checkOutdatedPlugin: flagging %s obsolete", path.c_str()); + if (guidValue.Length != 0 && guidValue.Length < MAX_GUID_LEN) { + TbdRecord *tbdRecord = new TbdRecord(guidValue); + tbdVector.push_back(tbdRecord); + MSDebug("checkOutdatedPlugin: flagging %s obsolete", path.c_str()); + } else { + MSDebug("checkOutdatedPlugin: flagging %s obsolete, but guid length is invalid (%zu)", path.c_str(), guidValue.Length); + } } } diff --git a/OSX/libsecurity_mds/lib/mdsapi.cpp b/OSX/libsecurity_mds/lib/mdsapi.cpp index d594fa9b..2f18194a 100644 --- a/OSX/libsecurity_mds/lib/mdsapi.cpp +++ b/OSX/libsecurity_mds/lib/mdsapi.cpp @@ -271,12 +271,15 @@ MDS_Initialize (const CSSM_GUID *inCallerGuid, MDS_FUNCS_PTR outDlFunctions, MDS_HANDLE *outMDSHandle) { +// The clang analyzer is not a fan of handing handles to your caller and trusting them to release later. +#ifndef __clang_analyzer__ BEGIN_API Required (outDlFunctions); Required (outMDSHandle) = (new MDSSession (Guid::optional(inCallerGuid), Required(inMemoryFunctions)))->handle (); *outDlFunctions = gMDSFunctionTable; END_API(MDS) +#endif } CSSM_RETURN CSSMAPI diff --git a/OSX/libsecurity_ocspd/client/ocspdClient.cpp b/OSX/libsecurity_ocspd/client/ocspdClient.cpp index b7b0372a..01db7249 100644 --- a/OSX/libsecurity_ocspd/client/ocspdClient.cpp +++ b/OSX/libsecurity_ocspd/client/ocspdClient.cpp @@ -39,7 +39,8 @@ class ocspdGlobals public: ocspdGlobals(); ~ocspdGlobals(); - mach_port_t serverPort(); + void resetServerPort(); + mach_port_t serverPort(); private: UnixPlusPlus::ForkMonitor mForkMonitor; MachPlusPlus::Port mServerPort; @@ -89,6 +90,15 @@ mach_port_t ocspdGlobals::serverPort() return mServerPort; } +void ocspdGlobals::resetServerPort() +{ + try { + mServerPort.deallocate(); + } catch(...) { + } +} + + static ModuleNexus OcspdGlobals; /* @@ -171,6 +181,8 @@ CSSM_RETURN ocspdCacheFlushStale() } krtn = ocsp_client_ocspdCacheFlushStale(serverPort); if(krtn) { + if (krtn == MACH_SEND_INVALID_DEST) + OcspdGlobals().resetServerPort(); ocspdErrorLog("ocsp_client_ocspdCacheFlushStale: RPC returned %d\n", krtn); return (CSSM_RETURN)krtn; } @@ -201,6 +213,8 @@ CSSM_RETURN ocspdCertFetch( krtn = ocsp_client_certFetch(serverPort, certURL.Data, (mach_msg_type_number_t)certURL.Length, (void **)&rtnData, &rtnLen); if(krtn) { + if (krtn == MACH_SEND_INVALID_DEST) + OcspdGlobals().resetServerPort(); ocspdErrorLog("ocspdCertFetch: RPC returned %d\n", krtn); return CSSMERR_APPLETP_NETWORK_FAILURE; } @@ -252,6 +266,8 @@ CSSM_RETURN ocspdCRLFetch( verifyTime, (mach_msg_type_number_t)strlen(verifyTime), (void **)&rtnData, &rtnLen); if(krtn) { + if (krtn == MACH_SEND_INVALID_DEST) + OcspdGlobals().resetServerPort(); ocspdErrorLog("ocspdCRLFetch: RPC returned %d\n", krtn); return CSSMERR_APPLETP_NETWORK_FAILURE; } @@ -297,6 +313,8 @@ 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) + OcspdGlobals().resetServerPort(); return krtn; } @@ -323,6 +341,8 @@ CSSM_RETURN ocspdCRLRefresh( krtn = ocsp_client_crlRefresh(serverPort, staleDays, expireOverlapSeconds, purgeAll, fullCryptoVerify); if(krtn) { + if (krtn == MACH_SEND_INVALID_DEST) + OcspdGlobals().resetServerPort(); ocspdErrorLog("ocspdCRLRefresh: RPC returned %d\n", krtn); return CSSMERR_APPLETP_NETWORK_FAILURE; } @@ -350,6 +370,8 @@ CSSM_RETURN ocspdCRLFlush( krtn = ocsp_client_crlFlush(serverPort, crlURL.Data, (mach_msg_type_number_t)crlURL.Length); if(krtn) { + if (krtn == MACH_SEND_INVALID_DEST) + OcspdGlobals().resetServerPort(); ocspdErrorLog("ocspdCRLFlush: RPC returned %d\n", krtn); return CSSMERR_APPLETP_NETWORK_FAILURE; } @@ -381,6 +403,8 @@ OSStatus ocspdTrustSettingsRead( krtn = ocsp_client_trustSettingsRead(serverPort, domain, (void **)&rtnData, &rtnLen, &ortn); if(krtn) { + if (krtn == MACH_SEND_INVALID_DEST) + OcspdGlobals().resetServerPort(); ocspdErrorLog("ocspdTrustSettingsRead: RPC returned %d\n", krtn); return errSecNotAvailable; } @@ -426,6 +450,8 @@ OSStatus ocspdTrustSettingsWrite( trustSettings.Data, (mach_msg_type_number_t)trustSettings.Length, &ortn); if(krtn) { + if (krtn == MACH_SEND_INVALID_DEST) + OcspdGlobals().resetServerPort(); ocspdErrorLog("ocspdTrustSettingsWrite: RPC returned %d\n", krtn); return errSecInternalComponent; } diff --git a/OSX/libsecurity_pkcs12/lib/pkcs12BagAttrs.cpp b/OSX/libsecurity_pkcs12/lib/pkcs12BagAttrs.cpp index d3f7a144..a1e93fd2 100644 --- a/OSX/libsecurity_pkcs12/lib/pkcs12BagAttrs.cpp +++ b/OSX/libsecurity_pkcs12/lib/pkcs12BagAttrs.cpp @@ -118,6 +118,7 @@ void P12BagAttrs::getAttr( for(unsigned dex=0; dexattrValue[dex]); CFArrayAppendValue(vals, val); + CFRelease(val); } *attrValues = vals; } diff --git a/OSX/libsecurity_pkcs12/lib/pkcs12Keychain.cpp b/OSX/libsecurity_pkcs12/lib/pkcs12Keychain.cpp index ce7a3b4f..b3d0ec8b 100644 --- a/OSX/libsecurity_pkcs12/lib/pkcs12Keychain.cpp +++ b/OSX/libsecurity_pkcs12/lib/pkcs12Keychain.cpp @@ -30,6 +30,7 @@ #include "pkcs12Utils.h" #include "pkcs12Debug.h" #include "pkcs12Crypto.h" +#include "SecCFRelease.h" #include #include // cuAddCrlToDb() #include @@ -305,11 +306,13 @@ void P12Coder::addSecKey( for(unsigned i=0; icount; i++) { SecKeychainAttribute *attr = &attrList->attr[i]; if(attr->tag == printNameTag) { + CFReleaseNull(friendName); friendName = CFStringCreateWithBytes(NULL, (UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8, false); } else if(attr->tag == labelHashTag) { + CFReleaseNull(localKeyId); localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length); } else { @@ -401,15 +404,20 @@ void P12Coder::addSecCert( SecKeychainAttribute *attr = &attrList->attr[i]; switch(attr->tag) { case kSecPublicKeyHashItemAttr: + CFReleaseNull(localKeyId); localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length); break; case kSecLabelItemAttr: + CFReleaseNull(friendName); /* FIXME: always in UTF8? */ friendName = CFStringCreateWithBytes(NULL, (UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8, false); break; default: + SecKeychainItemFreeAttributesAndData(attrList, certData); + CFReleaseNull(friendName); + CFReleaseNull(localKeyId); p12ErrorLog("addSecCert: unexpected attr tag\n"); MacOSError::throwMe(errSecParam); diff --git a/OSX/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp b/OSX/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp index 51de12d2..2725348c 100644 --- a/OSX/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp +++ b/OSX/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp @@ -366,7 +366,9 @@ SecCertificateRef P12CertBag::getSecCert() } /* One ref count for us, one for the caller */ - CFRetain(mCertRef); + if (mCertRef) { + CFRetain(mCertRef); + } return mCertRef; } diff --git a/OSX/libsecurity_pkcs12/lib/pkcs12Utils.h b/OSX/libsecurity_pkcs12/lib/pkcs12Utils.h index e39ebc3e..aa70b2de 100644 --- a/OSX/libsecurity_pkcs12/lib/pkcs12Utils.h +++ b/OSX/libsecurity_pkcs12/lib/pkcs12Utils.h @@ -56,7 +56,7 @@ void p12IntToData( /* CFDataRef <--> CSSM_DATA */ CFDataRef p12CssmDataToCf( - const CSSM_DATA &c); + const CSSM_DATA &c) CF_RETURNS_RETAINED; void p12CfDataToCssm( CFDataRef cf, CSSM_DATA &c, diff --git a/OSX/libsecurity_smime/lib/SecCMS.c b/OSX/libsecurity_smime/lib/SecCMS.c index 6c3b4933..11026ca4 100644 --- a/OSX/libsecurity_smime/lib/SecCMS.c +++ b/OSX/libsecurity_smime/lib/SecCMS.c @@ -54,6 +54,7 @@ CFTypeRef kSecCMSAdditionalCerts = CFSTR("kSecCMSAdditionalCerts"); CFTypeRef kSecCMSSignedAttributes = CFSTR("kSecCMSSignedAttributes"); CFTypeRef kSecCMSSignDate = CFSTR("kSecCMSSignDate"); CFTypeRef kSecCMSAllCerts = CFSTR("kSecCMSAllCerts"); +CFTypeRef kSecCMSHashAgility = CFSTR("kSecCMSHashAgility"); CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm"); CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC"); @@ -182,6 +183,20 @@ out: return status; } +OSStatus SecCMSSignDataAndAttributes(SecIdentityRef identity, CFDataRef data, bool detached, + CFMutableDataRef signed_data, CFDictionaryRef signed_attributes) +{ + return SecCMSSignDataOrDigestAndAttributes(identity, data, detached, false, SEC_OID_SHA1, + signed_data, signed_attributes, SecCmsCMCertChain, NULL); +} + +OSStatus SecCMSSignDigestAndAttributes(SecIdentityRef identity, CFDataRef digest, + CFMutableDataRef signed_data, CFDictionaryRef signed_attributes) +{ + return SecCMSSignDataOrDigestAndAttributes(identity, digest, true, true, SEC_OID_SHA1, + signed_data, signed_attributes, SecCmsCMCertChain, NULL); +} + OSStatus SecCMSCreateSignedData(SecIdentityRef identity, CFDataRef data, CFDictionaryRef parameters, CFDictionaryRef signed_attributes, CFMutableDataRef signed_data) @@ -373,6 +388,13 @@ static OSStatus SecCMSVerifySignedData_internal(CFDataRef message, CFDataRef det } } + CFDataRef hash_agility_value = NULL; + if (errSecSuccess == SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd->signerInfos[0], &hash_agility_value)) { + if (hash_agility_value) { + CFDictionarySetValue(attrs, kSecCMSHashAgility, hash_agility_value); + } + } + *signed_attributes = attrs; if (certs) CFRelease(certs); } @@ -618,9 +640,12 @@ OSStatus SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof, (SecCertificateRef)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof, dex); SecCmsRecipientInfoRef rinfo; require(rinfo = SecCmsRecipientInfoCreate(cmsg, recip), out); + require_noerr(SecCmsEnvelopedDataAddRecipient(envd, rinfo), out); } } else if (CFGetTypeID(recipient_or_cfarray_thereof) == SecCertificateGetTypeID()) { - require(SecCmsRecipientInfoCreate(cmsg, (SecCertificateRef)recipient_or_cfarray_thereof), out); + SecCmsRecipientInfoRef rinfo; + require(rinfo = SecCmsRecipientInfoCreate(cmsg, (SecCertificateRef)recipient_or_cfarray_thereof), out); + require_noerr(SecCmsEnvelopedDataAddRecipient(envd, rinfo), out); } else goto out; diff --git a/OSX/libsecurity_smime/lib/SecCMS.h b/OSX/libsecurity_smime/lib/SecCMS.h index 52ca2d72..3c07a0ad 100644 --- a/OSX/libsecurity_smime/lib/SecCMS.h +++ b/OSX/libsecurity_smime/lib/SecCMS.h @@ -37,6 +37,7 @@ extern const void * kSecCMSAdditionalCerts; extern const void * kSecCMSSignedAttributes; extern const void * kSecCMSSignDate; extern const void * kSecCMSAllCerts; +extern const void * kSecCMSHashAgility; extern const void * kSecCMSHashingAlgorithmSHA1; extern const void * kSecCMSHashingAlgorithmSHA256; @@ -95,6 +96,35 @@ OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents, CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates, CFDataRef *attached_contents, CFDictionaryRef *message_attributes); +/*! + @function SecCMSSignDataAndAttributes + @abstract create a signed data cms blob. + @param identity signer + @param data message to be signed + @param detached sign detached or not + @param signed_data (output) return signed message. + @param signed_attributes (input/optional) signed attributes to insert + as a CFDictionary from oids (CFData) to value (CFData). + @result A result code. See "Security Error Codes" (SecBase.h). + errSecParam garbage in, garbage out. + */ +OSStatus SecCMSSignDataAndAttributes(SecIdentityRef identity, CFDataRef data, + bool detached, CFMutableDataRef signed_data, CFDictionaryRef signed_attributes); + +/*! + @function SecCMSSignDigestAndAttributes + @abstract create a detached signed data cms blob for a SHA-1 hash. + @param identity signer + @param digest SHA-1 digest of message to be signed + @param signed_data (output) return signed message. + @param signed_attributes (input/optional) signed attributes to insert + as a CFDictionary from oids (CFData) to value (CFData). + @result A result code. See "Security Error Codes" (SecBase.h). + errSecParam garbage in, garbage out. + */ +OSStatus SecCMSSignDigestAndAttributes(SecIdentityRef identity, CFDataRef digest, + CFMutableDataRef signed_data, CFDictionaryRef signed_attributes); + /*! @function SecCMSCreateSignedData @abstract create a signed data cms blob. diff --git a/OSX/libsecurity_smime/lib/SecCmsSignerInfo.h b/OSX/libsecurity_smime/lib/SecCmsSignerInfo.h index 7c94cabb..49894c45 100644 --- a/OSX/libsecurity_smime/lib/SecCmsSignerInfo.h +++ b/OSX/libsecurity_smime/lib/SecCmsSignerInfo.h @@ -38,6 +38,7 @@ #include #include +#include #if defined(__cplusplus) @@ -274,6 +275,15 @@ SecCmsUtilVerificationStatusToString(SecCmsVerificationStatus vs); #define kMSCompatibilityDomain "com.apple.security.smime" #define kMSCompatibilityMode CFSTR("MSCompatibilityMode") +/*! + @function SecCmsSignerInfoCopyCertFromEncryptionKeyPreference + @abstract Copy the certificate specified in the encryption key preference. + @param signerinfo The SecCmsSignerInfo object for which we verified the signature. + @result The preferred encryption certificate of the user who signed this message, if found. + @discussion This function should be called after the signer info has been verified. + */ +SecCertificateRef SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo); + #if defined(__cplusplus) } #endif diff --git a/OSX/libsecurity_smime/lib/SecSMIMEPriv.h b/OSX/libsecurity_smime/lib/SecSMIMEPriv.h index 8888e49b..0201a22b 100644 --- a/OSX/libsecurity_smime/lib/SecSMIMEPriv.h +++ b/OSX/libsecurity_smime/lib/SecSMIMEPriv.h @@ -160,7 +160,8 @@ extern OSStatus SecSMIMECreateMSSMIMEEncKeyPrefs(SecArenaPoolRef pool, CSSM_DATA * SecSMIMEGetCertFromEncryptionKeyPreference - find cert marked by EncryptionKeyPreference * attribute */ -extern SecCertificateRef SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, CSSM_DATA_PTR DERekp); +extern SecCertificateRef SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, CSSM_DATA_PTR *rawCerts, CSSM_DATA_PTR DERekp); + #ifdef __cplusplus diff --git a/OSX/libsecurity_smime/lib/cert.c b/OSX/libsecurity_smime/lib/cert.c index ea5c9b9e..97a5e3d0 100644 --- a/OSX/libsecurity_smime/lib/cert.c +++ b/OSX/libsecurity_smime/lib/cert.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -244,82 +244,63 @@ endNewClass() CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot) { - SecPolicySearchRef searchRef = NULL; SecPolicyRef policy = NULL; CFArrayRef wrappedCert = NULL; SecTrustRef trust = NULL; - CFArrayRef certChain = NULL; - CSSM_TP_APPLE_EVIDENCE_INFO *statusChain; - CFDataRef actionData = NULL; + CFMutableArrayRef certs = NULL; OSStatus status = 0; if (!cert) goto loser; - status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef); - if (status) - goto loser; - status = SecPolicySearchCopyNext(searchRef, &policy); - if (status) - goto loser; + policy = SecPolicyCreateBasicX509(); + if (!policy) + goto loser; wrappedCert = CERT_CertListFromCert(cert); status = SecTrustCreateWithCertificates(wrappedCert, policy, &trust); if (status) goto loser; - /* Tell SecTrust that we don't care if any certs in the chain have expired, - nor do we want to stop when encountering a cert with a trust setting; - we always want to build the full chain. - */ - CSSM_APPLE_TP_ACTION_DATA localActionData = { - CSSM_APPLE_TP_ACTION_VERSION, - CSSM_TP_ACTION_ALLOW_EXPIRED | CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT - }; - actionData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)&localActionData, sizeof(localActionData), kCFAllocatorNull); - if (!actionData) - goto loser; - - status = SecTrustSetParameters(trust, CSSM_TP_ACTION_DEFAULT, actionData); - if (status) - goto loser; - + /* SecTrustEvaluate will build us the best chain available using its heuristics. + * We'll ignore the trust result. */ status = SecTrustEvaluate(trust, NULL); if (status) goto loser; + CFIndex idx, count = SecTrustGetCertificateCount(trust); + + /* If we weren't able to build a chain to a self-signed cert, warn. */ + Boolean isSelfSigned = false; + SecCertificateRef lastCert = SecTrustGetCertificateAtIndex(trust, count - 1); + if (lastCert && (0 == SecCertificateIsSelfSigned(lastCert, &isSelfSigned)) && !isSelfSigned) { + CFStringRef commonName = NULL; + (void)SecCertificateCopyCommonName(cert, &commonName); + fprintf(stderr, "Warning: unable to build chain to self-signed root for signer \"%s\"", + commonName ? CFStringGetCStringPtr(commonName, kCFStringEncodingUTF8) : ""); + if (commonName) { CFRelease(commonName); } + } - status = SecTrustGetResult(trust, NULL, &certChain, &statusChain); - if (status) - goto loser; + /* We don't drop the root if there is only 1 certificate in the chain. */ + if (!includeRoot && count > 1) { count--; } - /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */ - if (!includeRoot && CFArrayGetCount(certChain) > 1) - { - CFMutableArrayRef subChain = CFArrayCreateMutableCopy(NULL, 0, certChain); - CFRelease(certChain); - certChain = subChain; - if (subChain) - CFArrayRemoveValueAtIndex(subChain, CFArrayGetCount(subChain) - 1); - } + certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); + for(idx = 0; idx < count; idx++) + CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx)); loser: - if (searchRef) - CFRelease(searchRef); if (policy) CFRelease(policy); if (wrappedCert) CFRelease(wrappedCert); if (trust) CFRelease(trust); - if (actionData) - CFRelease(actionData); - if (certChain && status) + if (certs && status) { - CFRelease(certChain); - certChain = NULL; + CFRelease(certs); + certs = NULL; } - return certChain; + return certs; } CFArrayRef CERT_CertListFromCert(SecCertificateRef cert) @@ -395,9 +376,9 @@ static int compareCssmData( // Generate a certificate key from the issuer and serialnumber, then look it up in the database. // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray, - CSSM_DATA_PTR *rawCerts, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN) + CSSM_DATA_PTR *rawCerts, CFArrayRef certList, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN) { - SecCertificateRef certificate; + SecCertificateRef certificate = NULL; int numRawCerts = SecCmsArrayCount((void **)rawCerts); int dex; OSStatus ortn; @@ -429,6 +410,27 @@ SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray, dprintf("CERT_FindCertByIssuerAndSN: found cert %p\n", certificate); return certificate; } + + /* Search the user-added certList */ + if (certList && CFArrayGetCount(certList)) { + CFIndex c, count = CFArrayGetCount(certList); + for (c = 0; c < count; c++) { + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certList, c); + SecCmsIssuerAndSN *isn = CERT_GetCertIssuerAndSN(pl, cert); + if(isn == NULL) { + continue; + } + if(!compareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) { + continue; + } + if(!compareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) { + continue; + } + certificate = cert; + break; + } + if (certificate) { return certificate; } + } /* now search keychain(s) */ OSStatus status = SecCertificateFindByIssuerAndSN(keychainOrArray, &issuerAndSN->derIssuer, @@ -443,7 +445,7 @@ SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray, } SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray, - CSSM_DATA_PTR *rawCerts, const SECItem *subjKeyID) + CSSM_DATA_PTR *rawCerts, CFArrayRef certList, const SECItem *subjKeyID) { SecCertificateRef certificate; int numRawCerts = SecCmsArrayCount((void **)rawCerts); @@ -476,6 +478,23 @@ SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray, CFRelease(certificate); } + /* Search the user-added certList */ + if (certList && CFArrayGetCount(certList)) { + CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull); + CFIndex c, count = CFArrayGetCount(certList); + for (c = 0; c < count; c++) { + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certList, c); + CFDataRef skid = (cert) ? SecCertificateGetSubjectKeyID(cert) : NULL; + if (skid && CFEqual(skid, subjectkeyid)) { + CFRetain(cert); + certificate = cert; + break; + } + } + if (subjectkeyid) { CFRelease(subjectkeyid); }; + if (certificate) { return certificate; } + } + /* now search keychain(s) */ OSStatus status = SecCertificateFindBySubjectKeyID(keychainOrArray,subjKeyID,&certificate); if (status) @@ -504,7 +523,7 @@ CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef CF_ SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN) { - SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, issuerAndSN); + SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, NULL, issuerAndSN); if (!certificate) return NULL; @@ -514,7 +533,7 @@ CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAnd SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SECItem *subjKeyID) { - SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, subjKeyID); + SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, NULL, subjKeyID); if (!certificate) return NULL; @@ -809,10 +828,7 @@ loser: CFTypeRef CERT_PolicyForCertUsage(SECCertUsage certUsage) { - SecPolicySearchRef search = NULL; SecPolicyRef policy = NULL; - const CSSM_OID *policyOID; - OSStatus rv; switch (certUsage) { @@ -823,35 +839,25 @@ CERT_PolicyForCertUsage(SECCertUsage certUsage) goto loser; break; case certUsageSSLClient: + policy = SecPolicyCreateSSL(false, NULL); + break; case certUsageSSLServer: - policyOID = &CSSMOID_APPLE_TP_SSL; - break; - case certUsageUserCertImport: - policyOID = &CSSMOID_APPLE_TP_CSR_GEN; + policy = SecPolicyCreateSSL(true, NULL); break; case certUsageStatusResponder: - policyOID = &CSSMOID_APPLE_TP_REVOCATION_OCSP; + policy = SecPolicyCreateOCSPSigner(); break; case certUsageObjectSigner: case certUsageProtectedObjectSigner: - policyOID = &CSSMOID_APPLE_ISIGN; - break; + case certUsageUserCertImport: case certUsageEmailSigner: case certUsageEmailRecipient: - policyOID = &CSSMOID_APPLE_X509_BASIC; + policy = SecPolicyCreateBasicX509(); break; default: goto loser; } - rv = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &search); - if (rv) - goto loser; - - rv = SecPolicySearchCopyNext(search, &policy); - if (rv) - goto loser; loser: - if(search) CFRelease(search); return policy; } diff --git a/OSX/libsecurity_smime/lib/cert.h b/OSX/libsecurity_smime/lib/cert.h index 4458d3d8..500eb9c1 100644 --- a/OSX/libsecurity_smime/lib/cert.h +++ b/OSX/libsecurity_smime/lib/cert.h @@ -91,10 +91,11 @@ SecCertificateRef CERT_FindCertByDERCert(SecKeychainRef keychainOrArray, const S // Generate a certificate key from the issuer and serialnumber, then look it up in the database. // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray, - CSSM_DATA_PTR *rawCerts, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN); + CSSM_DATA_PTR *rawCerts, CFArrayRef certList, + PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN); SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray, - CSSM_DATA_PTR *rawCerts, const SECItem *subjKeyID); + CSSM_DATA_PTR *rawCerts, CFArrayRef certList, const SECItem *subjKeyID); SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN); diff --git a/OSX/libsecurity_smime/lib/cmsdigest.c b/OSX/libsecurity_smime/lib/cmsdigest.c index 6aa46146..cbdc0912 100644 --- a/OSX/libsecurity_smime/lib/cmsdigest.c +++ b/OSX/libsecurity_smime/lib/cmsdigest.c @@ -193,8 +193,6 @@ SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, SecArenaPoolR cmsdigcx->digobjs[i] = 0; } rv = SECSuccess; - if (digestsp) - *digestsp = NULL; goto cleanup; } diff --git a/OSX/libsecurity_smime/lib/cmsencode.c b/OSX/libsecurity_smime/lib/cmsencode.c index 65d0f9ad..9d2db04e 100644 --- a/OSX/libsecurity_smime/lib/cmsencode.c +++ b/OSX/libsecurity_smime/lib/cmsencode.c @@ -564,8 +564,11 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg, result = paramErr; break; } - if (result) + + if (result) { + PORT_Free(p7ecx); goto loser; + } /* Initialize the BER encoder. * Note that this will not encode anything until the first call to SEC_ASN1EncoderUpdate */ @@ -573,7 +576,7 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg, nss_cms_encoder_out, &(p7ecx->output)); if (p7ecx->ecx == NULL) { result = PORT_GetError(); - PORT_Free (p7ecx); + PORT_Free(p7ecx); goto loser; } p7ecx->ecxupdated = PR_FALSE; @@ -594,7 +597,7 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg, * a child encoder). */ if (SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0) != SECSuccess) { result = PORT_GetError(); - PORT_Free (p7ecx); + PORT_Free(p7ecx); goto loser; } diff --git a/OSX/libsecurity_smime/lib/cmslocal.h b/OSX/libsecurity_smime/lib/cmslocal.h index abda2456..29cc3373 100644 --- a/OSX/libsecurity_smime/lib/cmslocal.h +++ b/OSX/libsecurity_smime/lib/cmslocal.h @@ -48,7 +48,9 @@ #include extern const SecAsn1Template SecCmsIssuerAndSNTemplate[]; +#if 0 extern const SecAsn1Template SecCmsContentInfoTemplate[]; +#endif /************************************************************************/ SEC_BEGIN_PROTOS diff --git a/OSX/libsecurity_smime/lib/cmssiginfo.c b/OSX/libsecurity_smime/lib/cmssiginfo.c index 7f60d60c..ac389d3c 100644 --- a/OSX/libsecurity_smime/lib/cmssiginfo.c +++ b/OSX/libsecurity_smime/lib/cmssiginfo.c @@ -56,6 +56,7 @@ #include #include #include +#include #include "tsaSupport.h" #include "tsaSupportPriv.h" @@ -213,12 +214,22 @@ SecCmsSignerInfoCreate(SecCmsMessageRef cmsg, SecIdentityRef identity, SECOidTag SecCmsSignerInfoRef signerInfo = NULL; SecCertificateRef cert = NULL; SecPrivateKeyRef signingKey = NULL; + CFDictionaryRef keyAttrs = NULL; if (SecIdentityCopyCertificate(identity, &cert)) goto loser; if (SecIdentityCopyPrivateKey(identity, &signingKey)) goto loser; + /* In some situations, the "Private Key" in the identity is actually a public key. */ + keyAttrs = SecKeyCopyAttributes(signingKey); + if (!keyAttrs) + goto loser; + CFTypeRef class = CFDictionaryGetValue(keyAttrs, kSecAttrKeyClass); + if (!class || (CFGetTypeID(class) != CFStringGetTypeID()) || !CFEqual(class, kSecAttrKeyClassPrivate)) + goto loser; + + signerInfo = nss_cmssignerinfo_create(cmsg, SecCmsSignerIDIssuerSN, cert, NULL, NULL, signingKey, digestalgtag); loser: @@ -226,6 +237,8 @@ loser: CFRelease(cert); if (signingKey) CFRelease(signingKey); + if (keyAttrs) + CFRelease(keyAttrs); return signerInfo; } @@ -588,11 +601,11 @@ OSStatus SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType) { SecPublicKeyRef publickey = NULL; - SecCmsAttribute *attr; + SecCmsAttribute *attr = NULL; CSSM_DATA encoded_attrs; - SecCertificateRef cert; + SecCertificateRef cert = NULL; SecCmsVerificationStatus vs = SecCmsVSUnverified; - PLArenaPool *poolp; + PLArenaPool *poolp = NULL; SECOidTag digestAlgTag, digestEncAlgTag; if (signerinfo == NULL) @@ -993,11 +1006,11 @@ SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo, SecKeychai sid = &signerinfo->signerIdentifier; switch (sid->identifierType) { case SecCmsSignerIDIssuerSN: - cert = CERT_FindCertByIssuerAndSN(keychainOrArray, rawCerts, signerinfo->cmsg->poolp, + cert = CERT_FindCertByIssuerAndSN(keychainOrArray, rawCerts, signerinfo->sigd->certs, signerinfo->cmsg->poolp, sid->id.issuerAndSN); break; case SecCmsSignerIDSubjectKeyID: - cert = CERT_FindCertBySubjectKeyID(keychainOrArray, rawCerts, sid->id.subjectKeyID); + cert = CERT_FindCertBySubjectKeyID(keychainOrArray, rawCerts, signerinfo->sigd->certs, sid->id.subjectKeyID); break; default: cert = NULL; @@ -1030,7 +1043,9 @@ SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo) if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL) return NULL; - SecCertificateCopyCommonName(signercert, &commonName); + if (errSecSuccess != SecCertificateCopyCommonName(signercert, &commonName)) { + return NULL; + } return commonName; } @@ -1399,6 +1414,36 @@ loser: return status; } +SecCertificateRef SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo) { + SecCertificateRef cert = NULL; + SecCmsAttribute *attr; + CSSM_DATA_PTR ekp; + SecKeychainRef keychainOrArray; + + (void)SecKeychainCopyDefault(&keychainOrArray); + + /* sanity check - see if verification status is ok (unverified does not count...) */ + if (signerinfo->verificationStatus != SecCmsVSGoodSignature) + return NULL; + + /* find preferred encryption cert */ + if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr) && + (attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, + SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL) + { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */ + ekp = SecCmsAttributeGetValue(attr); + if (ekp == NULL) + return NULL; + + CSSM_DATA_PTR *rawCerts = NULL; + if (signerinfo->sigd) { + rawCerts = signerinfo->sigd->rawCerts; + } + cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, rawCerts, ekp); + } + return cert; +} + /* * XXXX the following needs to be done in the S/MIME layer code * after signature of a signerinfo is verified @@ -1434,7 +1479,7 @@ SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo) /* we assume that all certs coming with the message have been imported to the */ /* temporary database */ - cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, ekp); + cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, NULL, ekp); if (cert == NULL) return SECFailure; must_free_cert = PR_TRUE; diff --git a/OSX/libsecurity_smime/lib/cryptohi.c b/OSX/libsecurity_smime/lib/cryptohi.c index 68a7c715..5438c0b3 100644 --- a/OSX/libsecurity_smime/lib/cryptohi.c +++ b/OSX/libsecurity_smime/lib/cryptohi.c @@ -42,7 +42,10 @@ #include #include #include + +#if !USE_CDSA_CRYPTO #include +#endif #ifdef NDEBUG #define CSSM_PERROR(f, r) diff --git a/OSX/libsecurity_smime/lib/smimeutil.c b/OSX/libsecurity_smime/lib/smimeutil.c index 3de3cbcb..87dfc41b 100644 --- a/OSX/libsecurity_smime/lib/smimeutil.c +++ b/OSX/libsecurity_smime/lib/smimeutil.c @@ -746,7 +746,7 @@ loser: * they are assumed to have been imported already. */ SecCertificateRef -SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, CSSM_DATA_PTR DERekp) +SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, CSSM_DATA_PTR *rawCerts, CSSM_DATA_PTR DERekp) { PLArenaPool *tmppoolp = NULL; SecCertificateRef cert = NULL; @@ -763,11 +763,11 @@ SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, CSSM_ /* find cert */ switch (ekp.selector) { case NSSSMIMEEncryptionKeyPref_IssuerSN: - cert = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, ekp.id.issuerAndSN); + cert = CERT_FindCertByIssuerAndSN(keychainOrArray, rawCerts, NULL, tmppoolp, ekp.id.issuerAndSN); break; case NSSSMIMEEncryptionKeyPref_RKeyID: case NSSSMIMEEncryptionKeyPref_SubjectKeyID: - /* XXX not supported yet - we need to be able to look up certs by SubjectKeyID */ + cert = CERT_FindCertBySubjectKeyID(keychainOrArray, rawCerts, NULL, ekp.id.subjectKeyID); break; default: PORT_Assert(0); diff --git a/OSX/libsecurity_smime/lib/tsaSupport.c b/OSX/libsecurity_smime/lib/tsaSupport.c index df2be402..b1dccdda 100644 --- a/OSX/libsecurity_smime/lib/tsaSupport.c +++ b/OSX/libsecurity_smime/lib/tsaSupport.c @@ -208,8 +208,9 @@ int tsaWriteFileX(const char *fileName, const unsigned char *bytes, size_t numBy int fd; fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600); - if (fd <= 0) + if (fd == -1) { return errno; + } rtn = (int)write(fd, bytes, numBytes); if(rtn != (int)numBytes) @@ -1014,7 +1015,6 @@ static const char *trustResultTypeString(SecTrustResultType trustResultType) case kSecTrustResultUnspecified: return "TrustResultUnspecified"; case kSecTrustResultDeny: return "TrustResultDeny"; // user reject case kSecTrustResultInvalid: return "TrustResultInvalid"; - case kSecTrustResultConfirm: return "TrustResultConfirm"; case kSecTrustResultRecoverableTrustFailure: return "TrustResultRecoverableTrustFailure"; case kSecTrustResultFatalTrustFailure: return "TrustResultUnspecified"; case kSecTrustResultOtherError: return "TrustResultOtherError"; @@ -1072,7 +1072,6 @@ static OSStatus verifySigners(SecCmsSignedDataRef signedData, int numberOfSigner assert(false); // should never happen result = errSecTimestampNotTrusted; // SecCmsVSTimestampNotTrusted ? break; - case kSecTrustResultConfirm: case kSecTrustResultRecoverableTrustFailure: case kSecTrustResultFatalTrustFailure: case kSecTrustResultOtherError: @@ -1340,12 +1339,12 @@ OSStatus decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo, CFTypeRe dtprintf("inner content length: %ld\n", innerContent->Length); SecAsn1TSAMessageImprint fakeMessageImprint = {{{0}},}; OSStatus status = createTSAMessageImprint(signedData, innerContent, &fakeMessageImprint); - if (status) - { dtprintf("createTSAMessageImprint status: %d\n", (int)status); } + require_noerr_action(status, xit, dtprintf("createTSAMessageImprint status: %d\n", (int)status); result = status); printDataAsHex("inner content hash",&fakeMessageImprint.hashedMessage, 0); CSSM_DATA_PTR digestdata = &fakeMessageImprint.hashedMessage; CSSM_DATA_PTR digests[2] = {digestdata, NULL}; - SecCmsSignedDataSetDigests(signedData, digestAlgorithms, (CSSM_DATA_PTR *)&digests); + status = SecCmsSignedDataSetDigests(signedData, digestAlgorithms, (CSSM_DATA_PTR *)&digests); + require_noerr_action(status, xit, dtprintf("createTSAMessageImprint status: %d\n", (int)status); result = status); } else dtprintf("no inner content\n"); diff --git a/OSX/libsecurity_smime/lib/tsaTemplates.c b/OSX/libsecurity_smime/lib/tsaTemplates.c index 22068473..9fb460ee 100644 --- a/OSX/libsecurity_smime/lib/tsaTemplates.c +++ b/OSX/libsecurity_smime/lib/tsaTemplates.c @@ -167,6 +167,7 @@ const SecAsn1Template kSecAsn1TSAPKIStatusInfoTemplateRFC3161[] = { { 0 } }; +#if 0 const SecAsn1Template kSecAsn1TSATimeStampRespTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SecAsn1TimeStampResp) }, @@ -176,6 +177,7 @@ const SecAsn1Template kSecAsn1TSATimeStampRespTemplate[] = { SecCmsContentInfoTemplate }, { 0 } }; +#endif // Decode the status but not the TimeStampToken const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER[] = { diff --git a/OSX/libsecurity_smime/regressions/cms-01-basic.c b/OSX/libsecurity_smime/regressions/cms-01-basic.c index c1323698..e5e037a1 100644 --- a/OSX/libsecurity_smime/regressions/cms-01-basic.c +++ b/OSX/libsecurity_smime/regressions/cms-01-basic.c @@ -46,6 +46,8 @@ #include #include +#include + #define TMP_KEYCHAIN_PATH "/tmp/cms_01_test.keychain" #pragma clang diagnostic push diff --git a/OSX/libsecurity_smime/regressions/smime-cms-test.c b/OSX/libsecurity_smime/regressions/smime-cms-test.c index 05340ac3..080daa1c 100644 --- a/OSX/libsecurity_smime/regressions/smime-cms-test.c +++ b/OSX/libsecurity_smime/regressions/smime-cms-test.c @@ -22,7 +22,7 @@ */ -#include +#include #include #include #include diff --git a/OSX/libsecurity_smime/regressions/smime_regressions.h b/OSX/libsecurity_smime/regressions/smime_regressions.h index 13843842..c9687a23 100644 --- a/OSX/libsecurity_smime/regressions/smime_regressions.h +++ b/OSX/libsecurity_smime/regressions/smime_regressions.h @@ -23,7 +23,7 @@ -#include +#include ONE_TEST(smime_cms_test) ONE_TEST(cms_01_basic) diff --git a/OSX/libsecurity_ssl/lib/CipherSuite.h b/OSX/libsecurity_ssl/lib/CipherSuite.h index ea6c2817..8d352897 100644 --- a/OSX/libsecurity_ssl/lib/CipherSuite.h +++ b/OSX/libsecurity_ssl/lib/CipherSuite.h @@ -30,6 +30,7 @@ #include #include +#include /* CF_ENUM */ /* * Defined as enum for debugging, but in the protocol @@ -127,8 +128,6 @@ CF_ENUM(SSLCipherSuite) TLS_RSA_WITH_RC4_128_MD5 = 0x0004, TLS_RSA_WITH_RC4_128_SHA = 0x0005, TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A, - //TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F, - //TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035, TLS_RSA_WITH_NULL_SHA256 = 0x003B, TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C, TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D, @@ -138,14 +137,6 @@ CF_ENUM(SSLCipherSuite) TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010, TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013, TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016, - //TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030, - //TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031, - //TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032, - //TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033, - //TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036, - //TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037, - //TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038, - //TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039, TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E, TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040, @@ -158,13 +149,10 @@ CF_ENUM(SSLCipherSuite) /* Completely anonymous Diffie-Hellman */ TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018, TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B, - //TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034, - //TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A, TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006C, TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006D, /* Addendum from RFC 4279, TLS PSK */ - TLS_PSK_WITH_RC4_128_SHA = 0x008A, TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B, TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C, @@ -179,13 +167,11 @@ CF_ENUM(SSLCipherSuite) TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095, /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */ - TLS_PSK_WITH_NULL_SHA = 0x002C, TLS_DHE_PSK_WITH_NULL_SHA = 0x002D, TLS_RSA_PSK_WITH_NULL_SHA = 0x002E, - /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites - for TLS. */ + /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites for TLS. */ TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C, TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E, @@ -222,6 +208,14 @@ CF_ENUM(SSLCipherSuite) TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8, TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9, + /* TLS 1.3 standard cipher suites for ChaCha20+Poly1305. + Note: TLS 1.3 ciphersuites do not specify the key exchange + algorithm -- they only specify the symmetric ciphers. */ + TLS_AES_128_GCM_SHA256 = 0x1301, + TLS_AES_256_GCM_SHA384 = 0x1302, + TLS_CHACHA20_POLY1305_SHA256 = 0x1303, + TLS_AES_128_CCM_SHA256 = 0x1304, + TLS_AES_128_CCM_8_SHA256 = 0x1305, /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with HMAC SHA-256/384. */ @@ -245,12 +239,16 @@ CF_ENUM(SSLCipherSuite) TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032, + /* Addenda from rfc 7905 ChaCha20-Poly1305 Cipher Suites for + Transport Layer Security (TLS). */ + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9, + /* RFC 5746 - Secure Renegotiation */ TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF, - /* - * Tags for SSL 2 cipher kinds which are not specified - * for SSL 3. - */ + + /* Tags for SSL 2 cipher kinds which are not specified + * for SSL 3. */ SSL_RSA_WITH_RC2_CBC_MD5 = 0xFF80, SSL_RSA_WITH_IDEA_CBC_MD5 = 0xFF81, SSL_RSA_WITH_DES_CBC_MD5 = 0xFF82, diff --git a/OSX/libsecurity_ssl/lib/SecureTransport.h b/OSX/libsecurity_ssl/lib/SecureTransport.h index e815d88f..c753a278 100644 --- a/OSX/libsecurity_ssl/lib/SecureTransport.h +++ b/OSX/libsecurity_ssl/lib/SecureTransport.h @@ -84,19 +84,20 @@ typedef const void * SSLConnectionRef; /* SSL Protocol version */ typedef CF_ENUM(int, SSLProtocol) { - kSSLProtocolUnknown = 0, /* no protocol negotiated/specified; use default */ - kSSLProtocol3 = 2, /* SSL 3.0 */ - kTLSProtocol1 = 4, /* TLS 1.0 */ - kTLSProtocol11 = 7, /* TLS 1.1 */ - kTLSProtocol12 = 8, /* TLS 1.2 */ - kDTLSProtocol1 = 9, /* DTLS 1.0 */ - - /* DEPRECATED on iOS */ - kSSLProtocol2 = 1, /* SSL 2.0 */ - kSSLProtocol3Only = 3, /* SSL 3.0 Only */ - kTLSProtocol1Only = 5, /* TLS 1.0 Only */ - kSSLProtocolAll = 6, /* All TLS supported protocols */ - + kSSLProtocolUnknown = 0, /* no protocol negotiated/specified; use default */ + kSSLProtocol3 = 2, /* SSL 3.0 */ + kTLSProtocol1 = 4, /* TLS 1.0 */ + kTLSProtocol11 = 7, /* TLS 1.1 */ + kTLSProtocol12 = 8, /* TLS 1.2 */ + kDTLSProtocol1 = 9, /* DTLS 1.0 */ + kTLSProtocol13 = 10, /* TLS 1.3 */ + + kTLSProtocolMaxSupported = 999, /* Max system-supported version */ + + kSSLProtocol2 = 1, /* SSL 2.0. DEPRECATED on iOS. */ + kSSLProtocol3Only = 3, /* SSL 3.0. DEPRECATED on iOS. */ + kTLSProtocol1Only = 5, /* TLS 1.0 Only. DEPRECATED on iOS. */ + kSSLProtocolAll = 6, /* All TLS supported protocols. DEPRECATED on iOS. */ }; /* SSL session options */ @@ -151,7 +152,10 @@ typedef CF_ENUM(int, SSLSessionOption) { * Set this option to Allow renegotations. False by default. */ kSSLSessionOptionAllowRenegotiation = 8, - + /* + * Set this option to enable session tickets. False by default. + */ + kSSLSessionOptionEnableSessionTickets = 9, }; /* State of an SSLSession */ @@ -184,7 +188,7 @@ typedef CF_ENUM(int, SSLClientCertificateState) { * Server app can inspect the cert via SSLCopyPeerCertificates(). */ kSSLClientCertRejected -} ; +}; /* * R/W functions. The application using this library provides @@ -312,29 +316,52 @@ typedef CF_ENUM(int, SSLConnectionType) */ /* Default configuration (has 3DES, no RC4) */ -extern const CFStringRef kSSLSessionConfig_default; +extern const CFStringRef kSSLSessionConfig_default +__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2,__MAC_10_13,__IPHONE_5_0,__IPHONE_11_0); + /* ATS v1 Config: TLS v1.2, only PFS ciphersuites */ -extern const CFStringRef kSSLSessionConfig_ATSv1; +extern const CFStringRef kSSLSessionConfig_ATSv1 +__OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); + /* ATS v1 Config without PFS: TLS v1.2, include non PFS ciphersuites */ -extern const CFStringRef kSSLSessionConfig_ATSv1_noPFS; +extern const CFStringRef kSSLSessionConfig_ATSv1_noPFS +__OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); + /* TLS v1.2 to TLS v1.0, with default ciphersuites (no 3DES, no RC4) */ -extern const CFStringRef kSSLSessionConfig_standard; +extern const CFStringRef kSSLSessionConfig_standard +__OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); + /* TLS v1.2 to TLS v1.0, with default ciphersuites + RC4 + 3DES */ -extern const CFStringRef kSSLSessionConfig_RC4_fallback; +extern const CFStringRef kSSLSessionConfig_RC4_fallback +__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2,__MAC_10_13,__IPHONE_5_0,__IPHONE_11_0); + /* TLS v1.0 only, with default ciphersuites + fallback SCSV */ -extern const CFStringRef kSSLSessionConfig_TLSv1_fallback; +extern const CFStringRef kSSLSessionConfig_TLSv1_fallback +__OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); + /* TLS v1.0, with default ciphersuites + RC4 + 3DES + fallback SCSV */ -extern const CFStringRef kSSLSessionConfig_TLSv1_RC4_fallback; +extern const CFStringRef kSSLSessionConfig_TLSv1_RC4_fallback +__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2,__MAC_10_13,__IPHONE_5_0,__IPHONE_11_0); + /* TLS v1.2 to TLS v1.0, defaults + RC4 + DHE ciphersuites */ -extern const CFStringRef kSSLSessionConfig_legacy; +extern const CFStringRef kSSLSessionConfig_legacy +__OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); + /* TLS v1.2 to TLS v1.0, default + RC4 + DHE ciphersuites */ -extern const CFStringRef kSSLSessionConfig_legacy_DHE; +extern const CFStringRef kSSLSessionConfig_legacy_DHE +__OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); + /* TLS v1.2, anonymous ciphersuites only */ -extern const CFStringRef kSSLSessionConfig_anonymous; +extern const CFStringRef kSSLSessionConfig_anonymous +__OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); + /* TLS v1.2 to TLS v1.0, has 3DES, no RC4 */ -extern const CFStringRef kSSLSessionConfig_3DES_fallback; +extern const CFStringRef kSSLSessionConfig_3DES_fallback +__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2,__MAC_10_13,__IPHONE_5_0,__IPHONE_11_0); + /* TLS v1.0, with default ciphersuites + 3DES, no RC4 */ -extern const CFStringRef kSSLSessionConfig_TLSv1_3DES_fallback; +extern const CFStringRef kSSLSessionConfig_TLSv1_3DES_fallback +__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2,__MAC_10_13,__IPHONE_5_0,__IPHONE_11_0); /****************** @@ -783,6 +810,15 @@ SSLGetEnabledCiphers (SSLContextRef context, size_t *numCiphers) /* IN/OUT */ __OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); +/* + * Forcibly enable or disable session ticket resumption. By default, session tickets + * are disabled. + */ +OSStatus +SSLSetSessionTicketsEnabled (SSLContextRef context, + Boolean enabled) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) /* @@ -1140,6 +1176,48 @@ SSLGetNegotiatedCipher (SSLContextRef context, SSLCipherSuite *cipherSuite) __OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); +/* + * Set the ALPN protocols to be passed in the ALPN negotiation. + * This is the list of supported application-layer protocols supported. + * + * The protocols parameter must be an array of CFStringRef values + * with ASCII-encoded reprensetations of the supported protocols, e.g., "http/1.1". + * + * See RFC 7301 for more information. + */ +OSStatus +SSLSetALPNProtocols (SSLContextRef context, + CFArrayRef protocols) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + +/* + * Get the ALPN protocols associated with this SSL context. + * This is the list of supported application-layer protocols supported. + * + * The resultant protocols array will contain CFStringRef values containing + * ASCII-encoded representations of the supported protocols, e.g., "http/1.1". + * + * See RFC 7301 for more information. + * + * Note: The `protocols` pointer must be NULL, otherwise the copy will fail. + * This function will allocate memory for the CFArrayRef container + * if there is data to provide. Otherwise, the pointer will remain NULL. + */ +OSStatus +SSLCopyALPNProtocols (SSLContextRef context, + CFArrayRef __nullable * __nonnull protocols) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + +/* + * Set the OCSP response for the given SSL session. + * + * The response parameter must be a non-NULL CFDataRef containing the + * bytes of the OCSP response. + */ +OSStatus +SSLSetOCSPResponse (SSLContextRef context, + CFDataRef __nonnull response) +__OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); /******************************************************** *** Session context configuration, server side only. *** @@ -1413,6 +1491,15 @@ OSStatus SSLClose (SSLContextRef context) __OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_5_0); +/* + * Set the status of a SSLContextRef. This is to be done after handling + * steps of the SSL handshake such as server certificate validation. + */ +OSStatus +SSLSetError (SSLContextRef context, + OSStatus status) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + CF_IMPLICIT_BRIDGING_DISABLED CF_ASSUME_NONNULL_END diff --git a/OSX/libsecurity_ssl/lib/SecureTransportPriv.h b/OSX/libsecurity_ssl/lib/SecureTransportPriv.h index 66f8b845..4df1cbc3 100644 --- a/OSX/libsecurity_ssl/lib/SecureTransportPriv.h +++ b/OSX/libsecurity_ssl/lib/SecureTransportPriv.h @@ -738,6 +738,13 @@ _SSLDisposeContext (SSLContextRef context); #endif /* TARGET_OS_IPHONE */ +/* + * Map the SSLProtocol enum to an enum capturing the wire format (coreTLS) version. + */ +#define SECURITY_HAS_TLS_VERSION_TRANSLATOR 1 +tls_protocol_version +_SSLProtocolVersionToWireFormatValue (SSLProtocol protocol); + /* * Create a new Datagram TLS session context. diff --git a/OSX/libsecurity_ssl/lib/sslBuildFlags.h b/OSX/libsecurity_ssl/lib/sslBuildFlags.h index af18517e..650d0909 100644 --- a/OSX/libsecurity_ssl/lib/sslBuildFlags.h +++ b/OSX/libsecurity_ssl/lib/sslBuildFlags.h @@ -32,6 +32,14 @@ extern "C" { #endif +/* + * Implementation-specific functionality. + */ +#if 1 +#undef USE_CDSA_CRYPTO /* use corecrypto, instead of CDSA */ +#undef USE_SSLCERTIFICATE /* use CF-based certs, not structs */ +#endif + /* * Work around the Netscape Server Key Exchange bug. When this is * true, only do server key exchange if both of the following are @@ -75,16 +83,16 @@ extern "C" { /* Experimental */ #define ENABLE_DTLS 1 -#define ENABLE_3DES 1 /* normally enabled */ -#define ENABLE_RC4 1 /* normally enabled */ -#define ENABLE_DES 0 /* normally disabled */ -#define ENABLE_RC2 0 /* normally disabled */ -#define ENABLE_AES 1 /* normally enabled, our first preference */ -#define ENABLE_AES256 1 /* normally enabled */ -#define ENABLE_ECDHE 1 -#define ENABLE_ECDHE_RSA 1 -#define ENABLE_ECDH 1 -#define ENABLE_ECDH_RSA 1 +#define ENABLE_3DES 1 /* normally enabled */ +#define ENABLE_RC4 1 /* normally enabled */ +#define ENABLE_DES 0 /* normally disabled */ +#define ENABLE_RC2 0 /* normally disabled */ +#define ENABLE_AES 1 /* normally enabled, our first preference */ +#define ENABLE_AES256 1 /* normally enabled */ +#define ENABLE_ECDHE 1 +#define ENABLE_ECDHE_RSA 1 +#define ENABLE_ECDH 1 +#define ENABLE_ECDH_RSA 1 #if defined(__cplusplus) } diff --git a/OSX/libsecurity_ssl/lib/sslCipherSpecs.c b/OSX/libsecurity_ssl/lib/sslCipherSpecs.c index 144d585e..bb59efcf 100644 --- a/OSX/libsecurity_ssl/lib/sslCipherSpecs.c +++ b/OSX/libsecurity_ssl/lib/sslCipherSpecs.c @@ -45,9 +45,12 @@ /* SecureTransport needs it's own copy of KnownCipherSuites for now, there is a copy in coreTLS, that is exported, but it actually should only included the "default" not the supported */ -#define ENABLE_ECDH 1 -#define ENABLE_AES_GCM 1 -#define ENABLE_PSK 1 +#define ENABLE_ECDH 1 +#define ENABLE_AES_GCM 1 +#define ENABLE_PSK 1 +#define ENABLE_CHACHA20_POLY1305 1 +#define ENABLE_AES_CCM 0 + static const uint16_t STKnownCipherSuites[] = { #if ENABLE_AES_GCM @@ -118,6 +121,18 @@ static const uint16_t STKnownCipherSuites[] = { SSL_RSA_WITH_RC4_128_MD5, #endif + /* TLS 1.3 ciphersuites */ +#if ENABLE_AES_GCM + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, +#endif +#if ENABLE_CHACHA20_POLY1305 + TLS_CHACHA20_POLY1305_SHA256, +#endif +#if ENABLE_AES_CCM + TLS_AES_128_CCM_SHA256, + TLS_AES_128_CCM_8_SHA256, +#endif /* Unsafe ciphersuites */ @@ -236,26 +251,48 @@ SSLSetEnabledCiphers (SSLContextRef ctx, if((ctx == NULL) || (ciphers == NULL) || (numCiphers == 0)) { return errSecParam; } + if(sslIsSessionActive(ctx)) { /* can't do this with an active session */ return errSecBadReq; } - cs = (uint16_t *)sslMalloc(numCiphers * sizeof(uint16_t)); + int matchCount = 0; + for(int i=0; ihdsk, cs, (unsigned) numCiphers); + OSStatus result = tls_handshake_set_ciphersuites(ctx->hdsk, cs, (unsigned) matchCount); sslFree(cs); - return errSecSuccess; + return result; } /* @@ -310,3 +347,14 @@ SSLGetEnabledCiphers (SSLContextRef ctx, numCiphers); } } + +OSStatus +SSLSetSessionTicketsEnabled (SSLContextRef context, + Boolean enabled) +{ + if (context == NULL) { + return errSecParam; + } + + return tls_handshake_set_session_ticket_enabled(context->hdsk, enabled); +} diff --git a/OSX/libsecurity_ssl/lib/sslContext.c b/OSX/libsecurity_ssl/lib/sslContext.c index 796b1c2f..eed80f1b 100644 --- a/OSX/libsecurity_ssl/lib/sslContext.c +++ b/OSX/libsecurity_ssl/lib/sslContext.c @@ -85,6 +85,7 @@ Boolean sslIsSessionActive(const SSLContext *ctx) case SSL_HdskStateUninit: case SSL_HdskStateGracefulClose: case SSL_HdskStateErrorClose: + case SSL_HdskStateOutOfBandError: return false; default: return true; @@ -421,6 +422,7 @@ void SSLContextDestroy(CFTypeRef arg) SSLFreeBuffer(&ctx->peerID); SSLFreeBuffer(&ctx->resumableSession); SSLFreeBuffer(&ctx->receivedDataBuffer); + SSLFreeBuffer(&ctx->contextConfigurationBuffer); CFReleaseSafe(ctx->acceptableCAs); #if !TARGET_OS_IPHONE @@ -469,6 +471,7 @@ SSLGetSessionState (SSLContextRef context, break; case SSL_HdskStateErrorClose: case SSL_HdskStateNoNotifyClose: + case SSL_HdskStateOutOfBandError: rtnState = kSSLAborted; break; case SSL_HdskStateReady: @@ -490,13 +493,15 @@ SSLSetSessionOption (SSLContextRef context, SSLSessionOption option, Boolean value) { - if(context == NULL) { - return errSecParam; + if (context == NULL) { + return errSecParam; } - if(sslIsSessionActive(context)) { - /* can't do this with an active session */ - return errSecBadReq; + + if (sslIsSessionActive(context)) { + /* can't do this with an active session */ + return errSecBadReq; } + switch(option) { case kSSLSessionOptionBreakOnServerAuth: context->breakOnServerAuth = value; @@ -511,11 +516,13 @@ SSLSetSessionOption (SSLContextRef context, break; case kSSLSessionOptionSendOneByteRecord: /* Only call the record layer function if the value changed */ - if(value != context->oneByteRecordEnable) + if (value != context->oneByteRecordEnable) { context->recFuncs->setOption(context->recCtx, kSSLRecordOptionSendOneByteRecord, value); + } context->oneByteRecordEnable = value; break; case kSSLSessionOptionFalseStart: + tls_handshake_set_false_start(context->hdsk, value); context->falseStartEnabled = value; break; case kSSLSessionOptionFallback: @@ -527,9 +534,15 @@ SSLSetSessionOption (SSLContextRef context, break; case kSSLSessionOptionAllowServerIdentityChange: tls_handshake_set_server_identity_change(context->hdsk, value); + context->allowServerIdentityChange = true; break; case kSSLSessionOptionAllowRenegotiation: tls_handshake_set_renegotiation(context->hdsk, value); + context->allowRenegotiation = true; + break; + case kSSLSessionOptionEnableSessionTickets: + tls_handshake_set_session_ticket_enabled(context->hdsk, value); + context->enableSessionTickets = true; break; default: return errSecParam; @@ -718,25 +731,135 @@ SSLSetALPNData(SSLContextRef context, const void * SSLGetALPNData(SSLContextRef context, - size_t *length) + size_t *length) { - if (context == NULL || length == NULL) + if (context == NULL || length == NULL) { return NULL; + } + + const tls_buffer *alpnData = tls_handshake_get_peer_alpn_data(context->hdsk); + + if (alpnData) { + *length = alpnData->length; + return alpnData->data; + } else { + return NULL; + } +} + +OSStatus +SSLSetALPNProtocols(SSLContextRef context, + CFArrayRef protocols) +{ + if (context == NULL || protocols == NULL || CFArrayGetCount(protocols) == 0) { + return errSecParam; + } + + // Per RFC 7301, the protocol name can be at most 32B long. + const int maxBufferLength = 32; + + // Append each element in the array to a mutable buffer + CFMutableDataRef alpnData = CFDataCreateMutable(NULL, 0); + CFArrayForEach(protocols, ^(const void *value) { + CFStringRef protocolString = (CFStringRef) value; + uint8_t len = CFStringGetLength(protocolString); + if (len <= maxBufferLength) { + char stringBytes[maxBufferLength]; + if (CFStringGetCString(protocolString, stringBytes, maxBufferLength, kCFStringEncodingASCII)) { + CFDataAppendBytes(alpnData, (const UInt8 *) &len, sizeof(len)); + CFDataAppendBytes(alpnData, (const UInt8 *) stringBytes, len); + } + } + }); + + // Length check + if (CFDataGetLength(alpnData) > 255) { + CFRelease(alpnData); + return errSecParam; + } - const tls_buffer *alpn_data; + // Pass the buffer down to coreTLS + tls_buffer payload; + payload.data = (uint8_t *) CFDataGetBytePtr(alpnData); + payload.length = CFDataGetLength(alpnData); + int success = tls_handshake_set_alpn_data(context->hdsk, payload); - alpn_data = tls_handshake_get_peer_alpn_data(context->hdsk); + // Free up memory and return + CFRelease(alpnData); + + return success; +} - if(alpn_data) { - *length = alpn_data->length; - return alpn_data->data; +OSStatus +SSLCopyALPNProtocols(SSLContextRef context, + CFArrayRef *protocolArray) +{ + if (context == NULL || protocolArray == NULL) { + return errSecParam; + } + + CFMutableArrayRef array = CFArrayCreateMutableForCFTypes(NULL); + + const tls_buffer *alpnData = tls_handshake_get_peer_alpn_data(context->hdsk); + if (alpnData) { + size_t offset = 0; + + // Extract each encoded parameter, wrap it in a CFStringRef, and append it to the running list + while (offset < alpnData->length) { + char length = alpnData->data[offset]; + offset++; + + // Make sure we don't exceed the buffer bounds + if (offset + length > alpnData->length) { + CFReleaseNull(array); + *protocolArray = NULL; + return errSecParam; + } + + CFStringRef protocol = CFStringCreateWithBytes(NULL, alpnData->data + offset, length, kCFStringEncodingASCII, false); + offset += length; + CFArrayAppendValue(array, protocol); + CFReleaseNull(protocol); + + // Sanity check + if (offset > alpnData->length) { + CFReleaseNull(array); + *protocolArray = NULL; + return errSecParam; + } + } + + *protocolArray = array; + return errSecSuccess; } else { - return NULL; + CFReleaseNull(array); + *protocolArray = NULL; + return errSecParam; } } // ALPN end +// OCSP response begin + +OSStatus +SSLSetOCSPResponse(SSLContextRef context, + CFDataRef response) +{ + if (context == NULL || response == NULL) { + return errSecParam; + } + + tls_buffer responsePayload; + responsePayload.data = (uint8_t *) CFDataGetBytePtr(response); + responsePayload.length = CFDataGetLength(response); + + int success = tls_handshake_set_ocsp_response(context->hdsk, &responsePayload); + return success; +} + +// OCSP response end + OSStatus SSLSetConnection (SSLContextRef ctx, SSLConnectionRef connection) @@ -1098,6 +1221,46 @@ SSLGetProtocolVersionMax (SSLContextRef ctx, return errSecSuccess; } +tls_protocol_version +_SSLProtocolVersionToWireFormatValue (SSLProtocol protocol) +{ + switch (protocol) { + case kSSLProtocol3: { + return tls_protocol_version_SSL_3; + } + case kTLSProtocol1: { + return tls_protocol_version_TLS_1_0; + } + case kTLSProtocol11: { + return tls_protocol_version_TLS_1_1; + } + case kTLSProtocol12: { + return tls_protocol_version_TLS_1_2; + } + case kTLSProtocol13: { + return tls_protocol_version_TLS_1_3; + } + case kTLSProtocolMaxSupported: { + return tls_protocol_version_TLS_1_3; + } + case kDTLSProtocol1: { + return tls_protocol_version_DTLS_1_0; + } + case kSSLProtocolUnknown: { + return tls_protocol_version_Undertermined; + } + case kSSLProtocol2: + case kSSLProtocol3Only: + case kTLSProtocol1Only: + case kSSLProtocolAll: { + sslErrorLog("SSLProtocol %d is deprecated. Setting to the default value (%d)", protocol, tls_protocol_version_Undertermined); + return tls_protocol_version_Undertermined; + } + } + + return tls_protocol_version_Undertermined; +} + #define max(x,y) ((x)<(y)?(y):(x)) OSStatus @@ -2597,3 +2760,79 @@ SSLSetSessionConfig(SSLContextRef context, return errSecParam; } } + +OSStatus +SSLGetSessionConfigurationIdentifier(SSLContext *ctx, SSLBuffer *buffer) +{ + if (buffer == NULL) { + return errSecParam; + } + + // Don't recompute the buffer if we've done it before and cached the result. + // Just copy out the result. + if (ctx->contextConfigurationBuffer.data != NULL) { + buffer->length = ctx->contextConfigurationBuffer.length; + buffer->data = (uint8_t *) malloc(buffer->length); + if (buffer->data == NULL) { + return errSecAllocate; + } + memcpy(buffer->data, ctx->contextConfigurationBuffer.data, buffer->length); + return errSecSuccess; + } + + // Allocate the buffer, freeing up any data that was previously stored + // 10 here is the number of attributes we're adding below. Change it as needed. + buffer->length = 10 * sizeof(Boolean); + if (buffer->data) { + free(buffer->data); + } + buffer->data = malloc(buffer->length); + if (buffer->data == NULL) { + return errSecAllocate; + } + + // Copy in the session configuration options + int offset = 0; + memcpy(buffer->data + offset, &ctx->breakOnServerAuth, sizeof(ctx->breakOnServerAuth)); + offset += sizeof(ctx->breakOnServerAuth); + + memcpy(buffer->data + offset, &ctx->breakOnCertRequest, sizeof(ctx->breakOnCertRequest)); + offset += sizeof(ctx->breakOnCertRequest); + + memcpy(buffer->data + offset, &ctx->breakOnClientAuth, sizeof(ctx->breakOnClientAuth)); + offset += sizeof(ctx->breakOnClientAuth); + + memcpy(buffer->data + offset, &ctx->signalServerAuth, sizeof(ctx->signalServerAuth)); + offset += sizeof(ctx->signalServerAuth); + + memcpy(buffer->data + offset, &ctx->signalCertRequest, sizeof(ctx->signalCertRequest)); + offset += sizeof(ctx->signalCertRequest); + + memcpy(buffer->data + offset, &ctx->signalClientAuth, sizeof(ctx->signalClientAuth)); + offset += sizeof(ctx->signalClientAuth); + + memcpy(buffer->data + offset, &ctx->breakOnClientHello, sizeof(ctx->breakOnClientHello)); + offset += sizeof(ctx->breakOnClientHello); + + memcpy(buffer->data + offset, &ctx->allowServerIdentityChange, sizeof(ctx->allowServerIdentityChange)); + offset += sizeof(ctx->allowServerIdentityChange); + + memcpy(buffer->data + offset, &ctx->allowRenegotiation, sizeof(ctx->allowRenegotiation)); + offset += sizeof(ctx->allowRenegotiation); + + memcpy(buffer->data + offset, &ctx->enableSessionTickets, sizeof(ctx->enableSessionTickets)); + offset += sizeof(ctx->enableSessionTickets); + + // Sanity check on the length + if (offset != buffer->length) { + free(buffer->data); + return errSecInternal; + } + + // Save the configuration buffer for later use + ctx->contextConfigurationBuffer.length = buffer->length; + ctx->contextConfigurationBuffer.data = (uint8_t *) malloc(buffer->length); + memcpy(ctx->contextConfigurationBuffer.data, buffer->data, buffer->length); + + return errSecSuccess; +} diff --git a/OSX/libsecurity_ssl/lib/sslContext.h b/OSX/libsecurity_ssl/lib/sslContext.h index 73113a35..82f5ffc7 100644 --- a/OSX/libsecurity_ssl/lib/sslContext.h +++ b/OSX/libsecurity_ssl/lib/sslContext.h @@ -36,7 +36,9 @@ #include #include - +#ifdef USE_CDSA_CRYPTO +#include +#else #if TARGET_OS_IPHONE #include #include @@ -45,6 +47,7 @@ // typedef struct OpaqueSecDHContext *SecDHContext; #endif #include +#endif #include #include @@ -73,8 +76,8 @@ typedef enum SSL_HdskStateReady, /* Handshake is done */ SSL_HdskStateGracefulClose, SSL_HdskStateErrorClose, - SSL_HdskStateNoNotifyClose, /* server disconnected with no - * notify msg */ + SSL_HdskStateNoNotifyClose, /* Server disconnected with no notify msg */ + SSL_HdskStateOutOfBandError, /* The caller encountered an error with out-of-band message processing */ } SSLHandshakeState; #define SSLChangeHdskState(ctx, newState) { ctx->state=newState; } @@ -93,6 +96,7 @@ struct SSLContext int writeCipher_ready; SSLHandshakeState state; + OSStatus outOfBandError; /* * Prior to successful protocol negotiation, negProtocolVersion @@ -205,6 +209,12 @@ struct SSLContext Boolean signalCertRequest; Boolean signalClientAuth; Boolean breakOnClientHello; + Boolean allowServerIdentityChange; + Boolean allowRenegotiation; + Boolean enableSessionTickets; + + /* cached configuration buffer */ + SSLBuffer contextConfigurationBuffer; /* List of peer-specified supported_signature_algorithms */ unsigned numPeerSigAlgs; @@ -258,8 +268,10 @@ static inline bool sslVersionIsLikeTls12(SSLContext *ctx) return ctx->isDTLS ? ctx->negProtocolVersion > DTLS_Version_1_0 : ctx->negProtocolVersion >= TLS_Version_1_2; } +OSStatus SSLGetSessionConfigurationIdentifier(SSLContext *ctx, SSLBuffer *buffer); + /* This is implemented in tls_callbacks.c */ - int sslGetSessionID(SSLContext *myCtx, SSLBuffer *sessionID); +int sslGetSessionID(SSLContext *myCtx, SSLBuffer *sessionID); #ifdef __cplusplus } diff --git a/OSX/libsecurity_ssl/lib/sslCrypto.c b/OSX/libsecurity_ssl/lib/sslCrypto.c index 1142c7f9..166a105b 100644 --- a/OSX/libsecurity_ssl/lib/sslCrypto.c +++ b/OSX/libsecurity_ssl/lib/sslCrypto.c @@ -118,21 +118,14 @@ sslGetMatchingCertInArray( return NULL; } - CFDataRef certData = SecCertificateCopyData(certRef); - if (certData) { - CFIndex idx, count = CFArrayGetCount(certArray); - for(idx=0; idxallowAnyRoot) { diff --git a/OSX/libsecurity_ssl/lib/sslTransport.c b/OSX/libsecurity_ssl/lib/sslTransport.c index bc44005d..616b9d49 100644 --- a/OSX/libsecurity_ssl/lib/sslTransport.c +++ b/OSX/libsecurity_ssl/lib/sslTransport.c @@ -60,6 +60,7 @@ extern int kSplitDefaultValue; static OSStatus SSLProcessProtocolMessage(SSLRecord *rec, SSLContext *ctx); static OSStatus SSLHandshakeProceed(SSLContext *ctx); +static OSStatus SSLSendAlert(SSLContext *ctx, tls_alert_level_t level, tls_alert_t description); OSStatus SSLWrite( @@ -84,6 +85,7 @@ SSLWrite( err = errSSLClosedGraceful; goto abort; case SSL_HdskStateErrorClose: + case SSL_HdskStateOutOfBandError: err = errSSLClosedAbort; goto abort; case SSL_HdskStateReady: @@ -172,6 +174,7 @@ readRetry: err = errSSLClosedGraceful; goto abort; case SSL_HdskStateErrorClose: + case SSL_HdskStateOutOfBandError: err = errSSLClosedAbort; goto abort; case SSL_HdskStateNoNotifyClose: @@ -374,12 +377,17 @@ SSLReHandshake(SSLContext *ctx) return errSecParam; } - if (ctx->state == SSL_HdskStateGracefulClose) - return errSSLClosedGraceful; - if (ctx->state == SSL_HdskStateErrorClose) - return errSSLClosedAbort; - if (ctx->state == SSL_HdskStatePending) - return errSecBadReq; + switch (ctx->state) { + case SSL_HdskStateGracefulClose: + return errSSLClosedGraceful; + case SSL_HdskStateErrorClose: + case SSL_HdskStateOutOfBandError: + return errSSLClosedAbort; + case SSL_HdskStatePending: + return errSecBadReq; + default: + break; + } /* If we are the client, we start the negotiation */ if(ctx->protocolSide == kSSLClientSide) { @@ -397,10 +405,15 @@ SSLHandshake(SSLContext *ctx) if(ctx == NULL) { return errSecParam; } - if (ctx->state == SSL_HdskStateGracefulClose) - return errSSLClosedGraceful; - if (ctx->state == SSL_HdskStateErrorClose) - return errSSLClosedAbort; + + switch (ctx->state) { + case SSL_HdskStateGracefulClose: + return errSSLClosedGraceful; + case SSL_HdskStateErrorClose: + return errSSLClosedAbort; + default: + break; + } if(ctx->isDTLS && ctx->timeout_deadline) { CFAbsoluteTime current = CFAbsoluteTimeGetCurrent(); @@ -426,6 +439,27 @@ SSLHandshake(SSLContext *ctx) SSLChangeHdskState(ctx, SSL_HdskStatePending); } + /* If an out-of-band error occurred, handle it here and then terminate + the connection as needed. */ + if (ctx->state == SSL_HdskStateOutOfBandError) { + bool shouldClose = true; + switch (ctx->outOfBandError) { + case errSecCertificateExpired: + SSLSendAlert(ctx, tls_handshake_alert_level_fatal, tls_handshake_alert_CertExpired); + break; + case errSecCertificateRevoked: + SSLSendAlert(ctx, tls_handshake_alert_level_fatal, tls_handshake_alert_CertRevoked); + break; + default: + shouldClose = false; + break; + } + + if (shouldClose) { + return SSLClose(ctx); + } + } + do { err = SSLHandshakeProceed(ctx); if((err != 0) && (err != errSSLUnexpectedRecord)) @@ -545,11 +579,30 @@ SSLClose(SSLContext *ctx) err = SSLServiceWriteQueue(ctx); SSLChangeHdskState(ctx, SSL_HdskStateGracefulClose); - if (err == errSecIO) + if (err == errSecIO) err = errSecSuccess; /* Ignore errors related to closed streams */ return err; } +static OSStatus +SSLSendAlert(SSLContext *ctx, tls_alert_level_t alertLevel, tls_alert_t alert) +{ + sslHdskStateDebug("SSLSendAlert"); + if (ctx == NULL) { + return errSecParam; + } + + return tls_handshake_send_alert(ctx->hdsk, alertLevel, alert); +} + +OSStatus +SSLSetError(SSLContext *ctx, OSStatus error) +{ + ctx->state = SSL_HdskStateOutOfBandError; + ctx->outOfBandError = error; + return errSecSuccess; +} + /* * Determine how much data the client can be guaranteed to * obtain via SSLRead() without blocking or causing any low-level diff --git a/OSX/libsecurity_ssl/lib/tlsCallbacks.c b/OSX/libsecurity_ssl/lib/tlsCallbacks.c index 5bad6e77..d17e73d4 100644 --- a/OSX/libsecurity_ssl/lib/tlsCallbacks.c +++ b/OSX/libsecurity_ssl/lib/tlsCallbacks.c @@ -80,7 +80,7 @@ tls_handshake_message_callback(tls_handshake_ctx_t ctx, tls_handshake_message_t case tls_handshake_message_server_hello: myCtx->serverHelloReceived = true; alpn_data = tls_handshake_get_peer_alpn_data(myCtx->hdsk); - if(alpn_data) { + if (alpn_data && myCtx->alpnFunc != NULL) { myCtx->alpnFunc(myCtx, myCtx->alpnFuncInfo, alpn_data->data, alpn_data->length); } else { npn_data = tls_handshake_get_peer_npn_data(myCtx->hdsk); @@ -196,17 +196,56 @@ int tls_handshake_set_protocol_version_callback(tls_handshake_ctx_t ctx, return myCtx->recFuncs->setProtocolVersion(myCtx->recCtx, protocolVersion); } +static int +_buildConfigurationSpecificSessionCacheKey(SSLContext *myCtx, SSLBuffer *sessionKey, SSLBuffer *outputBuffer) +{ + SSLBuffer configurationBuffer; + configurationBuffer.data = NULL; + configurationBuffer.length = 0; + int err = SSLGetSessionConfigurationIdentifier(myCtx, &configurationBuffer); + if (err != errSecSuccess) { + return err; + } + + outputBuffer->length = configurationBuffer.length + sessionKey->length; + outputBuffer->data = (uint8_t *) malloc(outputBuffer->length); + if (outputBuffer->data == NULL) { + free(configurationBuffer.data); + return errSecAllocate; + } + + memcpy(outputBuffer->data, configurationBuffer.data, configurationBuffer.length); + memcpy(outputBuffer->data + configurationBuffer.length, sessionKey->data, sessionKey->length); + + free(configurationBuffer.data); + + return errSecSuccess; +} + static int tls_handshake_save_session_data_callback(tls_handshake_ctx_t ctx, SSLBuffer sessionKey, SSLBuffer sessionData) { int err = errSSLSessionNotFound; SSLContext *myCtx = (SSLContext *)ctx; - sslDebugLog("%s: %p, key len=%zd, k[0]=%02x, data len=%zd\n", __FUNCTION__, myCtx, sessionKey.length, sessionKey.data[0], sessionData.length); + if (myCtx->cache == NULL) { + return errSSLSessionNotFound; + } - if(myCtx->cache) { - err = tls_cache_save_session_data(myCtx->cache, &sessionKey, &sessionData, myCtx->sessionCacheTimeout); + SSLBuffer configurationSpecificKey; + configurationSpecificKey.data = NULL; + configurationSpecificKey.length = 0; + err = _buildConfigurationSpecificSessionCacheKey(myCtx, &sessionKey, &configurationSpecificKey); + if (err != errSecSuccess) { + return err; } + + sslDebugLog("%s: %p, key len=%zd, k[0]=%02x, data len=%zd\n", __FUNCTION__, myCtx, configurationSpecificKey.length, configurationSpecificKey.data[0], sessionData.length); + + err = tls_cache_save_session_data(myCtx->cache, &configurationSpecificKey, &sessionData, myCtx->sessionCacheTimeout); + + free(configurationSpecificKey.data); + return err; } @@ -217,12 +256,24 @@ tls_handshake_load_session_data_callback(tls_handshake_ctx_t ctx, SSLBuffer sess int err = errSSLSessionNotFound; SSLFreeBuffer(&myCtx->resumableSession); - if(myCtx->cache) { - err = tls_cache_load_session_data(myCtx->cache, &sessionKey, &myCtx->resumableSession); + if (myCtx->cache == NULL) { + return errSSLSessionNotFound; + } + + SSLBuffer configurationSpecificKey; + configurationSpecificKey.data = NULL; + configurationSpecificKey.length = 0; + err = _buildConfigurationSpecificSessionCacheKey(myCtx, &sessionKey, &configurationSpecificKey); + if (err != errSecSuccess) { + return err; } - sslDebugLog("%p, key len=%zd, data len=%zd, err=%d\n", ctx, sessionKey.length, sessionData->length, err); + + err = tls_cache_load_session_data(myCtx->cache, &configurationSpecificKey, &myCtx->resumableSession); + sslDebugLog("%p, key len=%zd, data len=%zd, err=%d\n", ctx, configurationSpecificKey.length, sessionData->length, err); *sessionData = myCtx->resumableSession; + free(configurationSpecificKey.data); + return err; } diff --git a/OSX/libsecurity_ssl/regressions/ssl-39-echo.c b/OSX/libsecurity_ssl/regressions/ssl-39-echo.c index 80020471..cce99baa 100644 --- a/OSX/libsecurity_ssl/regressions/ssl-39-echo.c +++ b/OSX/libsecurity_ssl/regressions/ssl-39-echo.c @@ -723,7 +723,7 @@ tests(void) pthread_create(&client_thread, NULL, securetransport_ssl_thread, client); pthread_create(&server_thread, NULL, securetransport_ssl_thread, server); - int server_err, client_err; + intptr_t server_err, client_err; pthread_join(client_thread, (void*)&client_err); pthread_join(server_thread, (void*)&server_err); diff --git a/OSX/libsecurity_ssl/regressions/ssl-42-ciphers.c b/OSX/libsecurity_ssl/regressions/ssl-42-ciphers.c index b637558f..3d20d1fa 100644 --- a/OSX/libsecurity_ssl/regressions/ssl-42-ciphers.c +++ b/OSX/libsecurity_ssl/regressions/ssl-42-ciphers.c @@ -354,7 +354,6 @@ static bool check_peer_cert(SSLContextRef ctx, const ssl_test_handle *ssl, SecTr require_noerr(SecTrustEvaluate(*trust, &trust_result), out); CFIndex n_certs = SecTrustGetCertificateCount(*trust); - /* fprintf(stderr, "%ld certs; trust_eval: %d\n", n_certs, trust_result); */ peer_cert_array = CFArrayCreateMutable(NULL, n_certs, &kCFTypeArrayCallBacks); orig_peer_cert_array = CFArrayCreateMutableCopy(NULL, n_certs, ssl->peer_certs); @@ -373,14 +372,6 @@ static bool check_peer_cert(SSLContextRef ctx, const ssl_test_handle *ssl, SecTr CFReleaseNull(orig_peer_cert_array); CFReleaseNull(peer_cert_array); - /* - CFStringRef cert_name = SecCertificateCopySubjectSummary(cert); - char cert_name_buffer[1024]; - require(CFStringGetFileSystemRepresentation(cert_name, - cert_name_buffer, sizeof(cert_name_buffer)), out); - fprintf(stderr, "cert name: %s\n", cert_name_buffer); - CFRelease(trust); - */ return true; out: CFReleaseNull(orig_peer_cert_array); @@ -412,7 +403,6 @@ static void *securetransport_ssl_thread(void *arg) require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out); require_action(ssl_state==kSSLIdle, out, ortn = -1); - //uint64_t start = mach_absolute_time(); do { ortn = SSLHandshake(ctx); require_noerr(SSLGetSessionState(ctx,&ssl_state), out); @@ -473,21 +463,13 @@ static void *securetransport_ssl_thread(void *arg) require_string(!got_server_auth, out, "got server auth during resumption??"); require_string(check_peer_cert(ctx, ssl, &trust), out, "Certificate check failed (resumption case)"); } - //uint64_t elapsed = mach_absolute_time() - start; - //fprintf(stderr, "setr elapsed: %lld\n", elapsed); - - /* - SSLProtocol proto = kSSLProtocolUnknown; - require_noerr_quiet(SSLGetNegotiatedProtocolVersion(ctx, &proto), out); */ SSLCipherSuite cipherSuite; require_noerr_quiet(ortn = SSLGetNegotiatedCipher(ctx, &cipherSuite), out); - //fprintf(stderr, "st negotiated %s\n", sslcipher_itoa(cipherSuite)); if(ssl->is_dtls) { size_t sz; SSLGetDatagramWriteSize(ctx, &sz); - //fprintf(stderr, "Max Write Size = %ld\n", sz); } Boolean sessionWasResumed = false; @@ -495,8 +477,6 @@ static void *securetransport_ssl_thread(void *arg) size_t session_id_length = sizeof(session_id_data); require_noerr_quiet(ortn = SSLGetResumableSessionInfo(ctx, &sessionWasResumed, session_id_data, &session_id_length), out); require_action(ssl->dh_anonymous || (ssl->is_session_resume == sessionWasResumed), out, ortn = -1); - // if (sessionWasResumed) fprintf(stderr, "st resumed session\n"); - //hexdump(session_id_data, session_id_length); #define BUFSIZE (8*1024) unsigned char ibuf[BUFSIZE], obuf[BUFSIZE]; @@ -505,7 +485,6 @@ static void *securetransport_ssl_thread(void *arg) size_t len; if (ssl->is_server) { memset(obuf, i, BUFSIZE); - // SecRandomCopyBytes(kSecRandomDefault, sizeof(obuf), obuf); require_noerr(ortn = SSLWrite(ctx, obuf, BUFSIZE, &len), out); require_action(len == BUFSIZE, out, ortn = -1); @@ -518,11 +497,8 @@ static void *securetransport_ssl_thread(void *arg) size_t l=len; ortn = SSLRead(ctx, ibuf+len, BUFSIZE-len, &l); len+=l; - //printf("SSLRead [%p] %d, l=%zd len=%zd\n", ctx, (int)ortn, l, len); } - //printf("SSLRead [%p] done\n", ctx); - require_noerr(ortn, out); require_action(len == BUFSIZE, out, ortn = -1); @@ -577,14 +553,10 @@ tests(void) CFArrayRef server_rsa_certs = server_chain(); CFArrayRef server_ec_certs = server_ec_chain(); CFArrayRef client_certs = trusted_client_chain(); - ok(server_rsa_certs, "got rsa server cert chain"); - ok(server_ec_certs, "got ec server cert chain"); - ok(client_certs, "got rsa client cert chain"); + require(server_rsa_certs != NULL, end); + require(server_ec_certs != NULL, end); + require(client_certs != NULL, end); -/* Enable this if you want to test a specific d/i/k/l/m/p combination */ -#if 0 - int i=0, l=0, k=0, p=0; { { -#else int i,k,l, p; for (p=0; p +#include DISABLED_ONE_TEST(ssl_39_echo) diff --git a/OSX/libsecurity_transform/custom.mm b/OSX/libsecurity_transform/custom.mm index 496048c2..64dbe89e 100644 --- a/OSX/libsecurity_transform/custom.mm +++ b/OSX/libsecurity_transform/custom.mm @@ -5083,12 +5083,11 @@ static NSString *CopyLeakLine() CFErrorRef err = NULL; // Derived from Matt Wright's 10242560 test.c - int fd = open("/dev/random", O_RDONLY); SecTransformRef b64encode = SecEncodeTransformCreate(kSecBase64Encoding, NULL); const int buffer_size = 1024; void *buffer = malloc(buffer_size); - // For this test, ignore short reads - read(fd, buffer, buffer_size); + STAssert(SecRandomCopyBytes(kSecRandomDefault, buffer_size, buffer) == noErr), @"Random failed"); + CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, (UInt8*)buffer, buffer_size, kCFAllocatorMalloc); SecTransformSetAttribute(b64encode, kSecTransformInputAttributeName, data, &err); STAssertNil((id)err, @"Expected no SecTransformSetAttribute error, got: %@", err); diff --git a/OSX/libsecurity_transform/lib/CEncryptDecrypt.c b/OSX/libsecurity_transform/lib/CEncryptDecrypt.c index 458831c3..3897796f 100644 --- a/OSX/libsecurity_transform/lib/CEncryptDecrypt.c +++ b/OSX/libsecurity_transform/lib/CEncryptDecrypt.c @@ -29,12 +29,13 @@ #include "corecrypto/ccn.h" #include "stdio.h" #include "misc.h" +#include "Utilities.h" // corecrypto headers don't like C++ (on a deaper level then extern "C" {} can fix // so we need a C "shim" for all our corecrypto use. CFDataRef oaep_padding_via_c(int desired_message_length, CFDataRef dataValue); -CFDataRef oaep_padding_via_c(int desired_message_length, CFDataRef dataValue) +CFDataRef oaep_padding_via_c(int desired_message_length, CFDataRef dataValue) CF_RETURNS_RETAINED { cc_unit paddingBuffer[ccn_nof_size(desired_message_length)]; bzero(paddingBuffer, sizeof(cc_unit) * ccn_nof_size(desired_message_length)); // XXX needed?? @@ -55,7 +56,7 @@ CFDataRef oaep_padding_via_c(int desired_message_length, CFDataRef dataValue) } CFDataRef oaep_unpadding_via_c(CFDataRef encodedMessage); -CFDataRef oaep_unpadding_via_c(CFDataRef encodedMessage) +CFDataRef oaep_unpadding_via_c(CFDataRef encodedMessage) CF_RETURNS_RETAINED { size_t mlen = CFDataGetLength(encodedMessage); cc_size n = ccn_nof_size(mlen); @@ -68,7 +69,9 @@ CFDataRef oaep_unpadding_via_c(CFDataRef encodedMessage) if (err) { // XXX should make a CFError or something. - return (void*)fancy_error(CFSTR("CoreCrypto"), err, CFSTR("OAEP decode error")); + CFErrorRef error = fancy_error(CFSTR("CoreCrypto"), err, CFSTR("OAEP decode error")); + CFRetainSafe(error); + return (void*)error; } CFDataRef result = CFDataCreate(NULL, (UInt8*)plainText, plainTextLength); return result; diff --git a/OSX/libsecurity_transform/lib/CoreFoundationBasics.cpp b/OSX/libsecurity_transform/lib/CoreFoundationBasics.cpp index cb1bb51f..819ff943 100644 --- a/OSX/libsecurity_transform/lib/CoreFoundationBasics.cpp +++ b/OSX/libsecurity_transform/lib/CoreFoundationBasics.cpp @@ -46,7 +46,7 @@ CFErrorRef GetNoMemoryError() CFErrorRef GetNoMemoryErrorAndRetain() { - return (CFErrorRef) CFRetain(gNoMemory); + return (CFErrorRef) CFRetainSafe(gNoMemory); } @@ -164,7 +164,7 @@ static CFHashCode MakeHash(CFTypeRef typeRef) -static CFStringRef MakeFormattingDescription(CFTypeRef typeRef, CFDictionaryRef formatOptions) +static CFStringRef MakeFormattingDescription(CFTypeRef typeRef, CFDictionaryRef formatOptions) CF_RETURNS_RETAINED { // get the string CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef; @@ -180,7 +180,7 @@ static CFStringRef MakeFormattingDescription(CFTypeRef typeRef, CFDictionaryRef } -static CFStringRef MakeDebugDescription(CFTypeRef typeRef) +static CFStringRef MakeDebugDescription(CFTypeRef typeRef) CF_RETURNS_RETAINED { // get the string CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef; diff --git a/OSX/libsecurity_transform/lib/Digest.cpp b/OSX/libsecurity_transform/lib/Digest.cpp index 20c9abd4..be75c453 100644 --- a/OSX/libsecurity_transform/lib/Digest.cpp +++ b/OSX/libsecurity_transform/lib/Digest.cpp @@ -39,7 +39,7 @@ CFDictionaryRef Digest::CopyState() CFIndex size = mDigestLength; CFNumberRef nr = CFNumberCreate(NULL, kCFNumberCFIndexType, &size); CFDictionaryAddValue(dr, kSecDigestLengthAttribute, nr); - CFRelease(nr); + CFReleaseNull(nr); return dr; } @@ -339,6 +339,7 @@ CFErrorRef DigestTransform::Setup(CFTypeRef dt, CFIndex length) default: { CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "%d is an invalid digest size (use 224, 256, 384, 512, or 0).", length); + CFAutorelease(result); return result; } } @@ -385,21 +386,23 @@ CFErrorRef DigestTransform::Setup(CFTypeRef dt, CFIndex length) default: { CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "%d is an invalid digest size (use 224, 256, 384, 512, or 0).", length); - return result; + CFAutorelease(result); + return result; } } } else { CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidAlgorithm, "%@ is not a supported digest algorithm (use kSecDigestSHA2, kSecDigestMD2, kSecDigestMD5, kSecDigestSHA or kSecDigestSHA2", digestType); - return result; + CFAutorelease(result); + return result; } } long lengthInt = mDigest->DigestLength(); CFNumberRef lengthNumber = CFNumberCreate(NULL, kCFNumberLongType, &lengthInt); SendAttribute(kSecDigestLengthAttribute, lengthNumber); - CFRelease(lengthNumber); + CFReleaseNull(lengthNumber); return NULL; } @@ -407,7 +410,7 @@ CFErrorRef DigestTransform::Setup(CFTypeRef dt, CFIndex length) static CFStringRef gDigestTransformName = CFSTR("SecDigestTransform"); -CFTypeRef DigestTransform::Make() +CFTypeRef DigestTransform::Make() CF_RETURNS_RETAINED { DigestTransform* dt = new DigestTransform(); return CoreFoundationHolder::MakeHolder(gDigestTransformName, dt); @@ -437,7 +440,7 @@ void DigestTransform::AttributeChanged(CFStringRef name, CFTypeRef value) // send the result CFDataRef resultRef = CFDataCreate(NULL, (UInt8*) result, mDigest->DigestLength()); SendAttribute(kSecTransformOutputAttributeName, resultRef); - CFRelease(resultRef); + CFReleaseNull(resultRef); // send the EOS SendAttribute(kSecTransformOutputAttributeName, NULL); @@ -454,7 +457,7 @@ void DigestTransform::AttributeChanged(CFStringRef name, CFTypeRef value) { CFStringRef idType = CFCopyTypeIDDescription(valueType); CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "value is not a CFDataRef -- it's a %@ instead", idType); - CFRelease(idType); + CFReleaseNull(idType); SetAttributeNoCallback(kSecTransformOutputAttributeName, result); } else diff --git a/OSX/libsecurity_transform/lib/Digest.h b/OSX/libsecurity_transform/lib/Digest.h index 1b5900a2..5b1d8298 100644 --- a/OSX/libsecurity_transform/lib/Digest.h +++ b/OSX/libsecurity_transform/lib/Digest.h @@ -187,7 +187,7 @@ protected: DigestTransform(); public: - static CFTypeRef Make(); + static CFTypeRef Make() CF_RETURNS_RETAINED; virtual ~DigestTransform(); CFErrorRef Setup(CFTypeRef digestType, CFIndex length); diff --git a/OSX/libsecurity_transform/lib/EncodeDecodeTransforms.c b/OSX/libsecurity_transform/lib/EncodeDecodeTransforms.c index 413d7ec9..ed0d8051 100644 --- a/OSX/libsecurity_transform/lib/EncodeDecodeTransforms.c +++ b/OSX/libsecurity_transform/lib/EncodeDecodeTransforms.c @@ -239,7 +239,7 @@ static SecTransformInstanceBlock DecodeTransform(CFStringRef name, if (!d) { SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, ret); - CFRelease(ret); + CFReleaseNull(ret); ret = NULL; } return (CFTypeRef)ret; @@ -331,7 +331,7 @@ static SecTransformInstanceBlock DecodeTransform(CFStringRef name, if (!d) { SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, ret); - CFRelease(ret); + CFReleaseNull(ret); ret = NULL; } return (CFTypeRef)ret; @@ -401,7 +401,7 @@ static SecTransformInstanceBlock DecodeTransform(CFStringRef name, } SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, d); - CFRelease(d); + CFReleaseNull(d); } else if (rc == Z_BUF_ERROR) { free(buf); if ((int)buf_sz > (1 << Z_BEST_COMPRESSION) && 0 == zs.avail_in) { @@ -419,7 +419,7 @@ static SecTransformInstanceBlock DecodeTransform(CFStringRef name, free(buf); CFStringRef emsg = CFStringCreateWithFormat(NULL, NULL, CFSTR("Zlib error#%d"), rc); CFErrorRef err = fancy_error(kSecTransformErrorDomain, kSecTransformErrorInvalidInput, emsg); - CFRelease(emsg); + CFReleaseNull(emsg); return (CFTypeRef)err; } } @@ -429,7 +429,7 @@ static SecTransformInstanceBlock DecodeTransform(CFStringRef name, CFNumberRef ratio = CFNumberCreate(NULL, kCFNumberFloatType, &r); SecTransformCustomSetAttribute(ref, kSecCompressionRatio, kSecTransformMetaAttributeValue, ratio); - CFRelease(ratio); + CFReleaseNull(ratio); } if (rc == Z_OK) { @@ -441,7 +441,7 @@ static SecTransformInstanceBlock DecodeTransform(CFStringRef name, } CFStringRef emsg = CFStringCreateWithFormat(NULL, NULL, CFSTR("Zlib error#%d"), rc); CFErrorRef err = fancy_error(kSecTransformErrorDomain, kSecTransformErrorInvalidInput, emsg); - CFRelease(emsg); + CFReleaseNull(emsg); return (CFTypeRef)err; }); } @@ -494,13 +494,14 @@ SecTransformRef SecDecodeTransformCreate(CFTypeRef DecodeType, CFErrorRef* error { *error = localError; } + CFSafeRelease(tr); // protect against leaking tr return NULL; } SecTransformSetAttribute(tr, kSecDecodeTypeAttribute, DecodeType, &localError); if (NULL != localError) { - CFRelease(tr); + CFReleaseNull(tr); tr = NULL; if (NULL != error) { @@ -583,14 +584,18 @@ static SecTransformInstanceBlock EncodeTransform(CFStringRef name, } else if (CFGetTypeID(value) == CFStringGetTypeID()) { int requested_length = CFStringGetIntValue(value); if (requested_length == 0 && CFStringCompare(CFSTR("0"), value, kCFCompareAnchored)) { - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Could not convert '%@' to a number, please set %@ to a numeric value", kSecEncodeLineLengthAttribute, value)); + CFErrorRef error = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Could not convert '%@' to a number, please set %@ to a numeric value", kSecEncodeLineLengthAttribute, value); + SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error); + CFReleaseNull(error); } else { target_line_length = requested_length; } } else { CFStringRef valueType = CFCopyTypeIDDescription(CFGetTypeID(value)); - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ requires a CFNumber, but was set to a %@ (%@)", kSecEncodeLineLengthAttribute, valueType, value)); - CFRelease(valueType); + CFErrorRef error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ requires a CFNumber, but was set to a %@ (%@)", kSecEncodeLineLengthAttribute, valueType, value); + SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error); + CFReleaseNull(valueType); + CFReleaseNull(error); } target_line_length -= target_line_length % out_chunk_size; @@ -722,7 +727,7 @@ static SecTransformInstanceBlock EncodeTransform(CFStringRef name, if (!d) { SecTransformCustomSetAttribute(ref,kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, ret); - CFRelease(ret); + CFReleaseNull(ret); ret = NULL; } return ret; @@ -759,7 +764,7 @@ static SecTransformInstanceBlock EncodeTransform(CFStringRef name, }); SecTransformSetDataAction(ref, kSecTransformActionProcessData, - ^(CFTypeRef value) + ^(CFTypeRef value) { CFDataRef d = value; CFIndex in_len = d ? CFDataGetLength(d) : 0; @@ -842,20 +847,20 @@ static SecTransformInstanceBlock EncodeTransform(CFStringRef name, if (out - out_base) { ret = CFDataCreateWithBytesNoCopy(NULL, out_base, out - out_base, kCFAllocatorMalloc); } else { - ret = SecTransformNoData(); + ret = CFRetainSafe(SecTransformNoData()); } if (!d) { if (ret != SecTransformNoData()) { SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, ret); - CFRelease(ret); } + CFSafeRelease(ret); ret = NULL; } - return ret; + return ret; }); } - else if (kCFCompareEqualTo == CFStringCompare(value, kSecZLibEncoding, 0)) + else if (kCFCompareEqualTo == CFStringCompare(value, kSecZLibEncoding, 0)) { __block z_stream zs; bzero(&zs, sizeof(zs)); @@ -918,7 +923,7 @@ static SecTransformInstanceBlock EncodeTransform(CFStringRef name, } SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, d); - CFRelease(d); + CFReleaseNull(d); } else if (rc == Z_BUF_ERROR) { free(buf); buf_sz = malloc_good_size(buf_sz * 2); @@ -926,7 +931,7 @@ static SecTransformInstanceBlock EncodeTransform(CFStringRef name, free(buf); CFStringRef emsg = CFStringCreateWithFormat(NULL, NULL, CFSTR("Zlib error#%d"), rc); CFErrorRef err = fancy_error(kSecTransformErrorDomain, kSecTransformErrorInvalidInput, emsg); - CFRelease(emsg); + CFReleaseNull(emsg); return (CFTypeRef)err; } } @@ -935,7 +940,7 @@ static SecTransformInstanceBlock EncodeTransform(CFStringRef name, CFNumberRef ratio = CFNumberCreate(NULL, kCFNumberFloatType, &r); SecTransformCustomSetAttribute(ref, kSecCompressionRatio, kSecTransformMetaAttributeValue, ratio); - CFRelease(ratio); + CFReleaseNull(ratio); } if (d) { return (CFTypeRef)SecTransformNoData(); @@ -997,19 +1002,18 @@ SecTransformRef SecEncodeTransformCreate(CFTypeRef EncodeType, CFErrorRef* error SecTransformRef tr = SecTransformCreate(EncodeName, &localError); if (!tr || NULL != localError) { - // There might be a leak if tr is returned but localError is - // not NULL, but that should not happen if (NULL != error) { *error = localError; } + CFSafeRelease(tr); return NULL; } SecTransformSetAttribute(tr, kSecEncodeTypeAttribute, EncodeType, &localError); if (NULL != localError) { - CFRelease(tr); + CFReleaseNull(tr); tr = NULL; if (NULL != error) { diff --git a/OSX/libsecurity_transform/lib/EncryptTransform.cpp b/OSX/libsecurity_transform/lib/EncryptTransform.cpp index 9b8d7d89..fd2963da 100644 --- a/OSX/libsecurity_transform/lib/EncryptTransform.cpp +++ b/OSX/libsecurity_transform/lib/EncryptTransform.cpp @@ -94,12 +94,12 @@ EncryptDecryptBase::~EncryptDecryptBase() { if (NULL != m_processedData) { - CFRelease(m_processedData); + CFReleaseNull(m_processedData); m_processedData = NULL; } if (NULL != m_accumulator) { - CFRelease(m_accumulator); + CFReleaseNull(m_accumulator); m_accumulator = NULL; } } @@ -139,7 +139,7 @@ CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution() { CFStringRef result = SecCopyErrorMessageString(err, NULL); CFErrorRef retValue = CreateSecTransformErrorRef(err, "CDSA error (%@).", result); - CFRelease(result); + CFReleaseNull(result); return retValue; } @@ -149,7 +149,7 @@ CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution() { CFStringRef result = SecCopyErrorMessageString(err, NULL); CFErrorRef retValue = CreateSecTransformErrorRef(err, "CDSA error (%@).", result); - CFRelease(result); + CFReleaseNull(result); return retValue; } @@ -220,6 +220,9 @@ CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution() if (isSymmetrical) { + // Clang thinks we're leaking initVect.data. + // While it's difficult to analyze whether that ends up being true or not, this is not code we love enough to refactor +#ifndef __clang_analyzer__ CSSM_DATA initVector; if (hasIVData) { @@ -241,9 +244,10 @@ CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution() { CFStringRef result = SecCopyErrorMessageString(crtn, NULL); CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result); - CFRelease(result); + CFReleaseNull(result); return retValue; } +#endif } else { @@ -254,7 +258,7 @@ CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution() { CFStringRef result = SecCopyErrorMessageString(crtn, NULL); CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA error (%@).", result); - CFRelease(result); + CFReleaseNull(result); return retValue; } } @@ -266,7 +270,7 @@ CFErrorRef EncryptDecryptBase::SerializedTransformStartingExecution() { CFStringRef result = SecCopyErrorMessageString(crtn, NULL); CFErrorRef retValue = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "CDSA encrypt/decrypt init error (%@).", result); - CFRelease(result); + CFReleaseNull(result); return retValue; } @@ -314,10 +318,10 @@ void EncryptDecryptBase::SendCSSMError(CSSM_RETURN retCode) // make a CFErrorRef for the error message CFStringRef errorString = SecCopyErrorMessageString(retCode, NULL); CFErrorRef errorRef = CreateGenericErrorRef(kCFErrorDomainOSStatus, retCode, "%@", errorString); - CFRelease(errorString); + CFReleaseNull(errorString); SendAttribute(kSecTransformOutputAttributeName, errorRef); - CFRelease(errorRef); + CFReleaseNull(errorRef); } void xor_bytes(UInt8 *dst, const UInt8 *src1, const UInt8 *src2, CFIndex length); @@ -515,7 +519,7 @@ CFDataRef EncryptDecryptBase::apply_oaep_padding(CFDataRef dataValue) if (status != errSecSuccess) { CFStringRef errorString = SecCopyErrorMessageString(status, NULL); error = CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "CDSA error (%@).", errorString); - CFRelease(errorString); + CFReleaseNull(errorString); SetAttributeNoCallback(kSecTransformOutputAttributeName, error); (void)transforms_assume_zero(EM); return EM; @@ -562,7 +566,7 @@ CFDataRef EncryptDecryptBase::apply_oaep_padding(CFDataRef dataValue) if (status != errSecSuccess) { CFStringRef errorString = SecCopyErrorMessageString(status, NULL); error = CreateSecTransformErrorRef(kSecTransformErrorInvalidOperation, "CDSA error (%@).", errorString); - CFRelease(errorString); + CFReleaseNull(errorString); goto out; } (void)transforms_assume(RSA_size.SizeInputBlock <= RSA_size.SizeOutputBlock); @@ -749,7 +753,7 @@ void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef { CFStringRef realType = CFCopyTypeIDDescription(valueType); CFErrorRef error = CreateSecTransformErrorRef(kSecTransformErrorNotInitializedCorrectly, "Value is not a CFDataRef -- this one is a %@", realType); - CFRelease(realType); + CFReleaseNull(realType); SetAttributeNoCallback(kSecTransformOutputAttributeName, error); return; } @@ -874,7 +878,7 @@ void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef if (NULL != m_processedData) { SendAttribute(kSecTransformOutputAttributeName, m_processedData); - CFRelease(m_processedData); + CFReleaseNull(m_processedData); m_processedData = NULL; } @@ -883,7 +887,7 @@ void EncryptDecryptBase::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef if (m_oaep_padding && m_forEncryption == false) { CFTypeRef unpadded = remove_oaep_padding(m_accumulator); SendAttribute(kSecTransformOutputAttributeName, unpadded); - CFRelease(unpadded); + CFReleaseNull(unpadded); } SendAttribute(kSecTransformOutputAttributeName, NULL); } diff --git a/OSX/libsecurity_transform/lib/GroupTransform.cpp b/OSX/libsecurity_transform/lib/GroupTransform.cpp index a14400ea..783c5243 100644 --- a/OSX/libsecurity_transform/lib/GroupTransform.cpp +++ b/OSX/libsecurity_transform/lib/GroupTransform.cpp @@ -23,7 +23,7 @@ void GroupTransform::FinalizePhase2() dispatch_group_notify(mPendingStartupActivity, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ if (mMembers) { this->mMembers = NULL; - CFRelease(members); + CFReleaseSafe(members); } }); @@ -404,7 +404,7 @@ void GroupTransform::RecurseForAllNodes(dispatch_group_t group, CFErrorRef *err_ void (^set_error)(CFErrorRef new_err) = ^(CFErrorRef new_err) { if (new_err) { if (!OSAtomicCompareAndSwapPtrBarrier(NULL, (void *)new_err, (void**)err)) { - CFRelease(new_err); + CFReleaseNull(new_err); } } }; @@ -467,7 +467,7 @@ CFStringRef GroupTransform::DotForDebugging() __block CFMutableStringRef group_connections_out = CFStringCreateMutable(NULL, 0); CFStringRef line_out = CFStringCreateWithFormat(NULL, NULL, CFSTR("\tsubgraph \"cluster_%@\" {\n"), name); CFStringAppend(group_nodes_out, line_out); - CFRelease(line_out); + CFReleaseNull(line_out); line_out = NULL; CFIndex n_attributes = t->GetAttributeCount(); @@ -491,32 +491,37 @@ CFStringRef GroupTransform::DotForDebugging() } line_out = CFStringCreateWithFormat(NULL, NULL, CFSTR("\t\t%@ [shape=plaintext, label=\"%@\"]\n"), dot_node_name, label); CFStringAppend(group_nodes_out, line_out); - CFRelease(line_out); + CFReleaseNull(line_out); line_out = NULL; - CFRelease(label); + CFReleaseNull(label); CFIndex n_connections = attributes[i]->connections ? CFArrayGetCount(attributes[i]->connections) : 0; for(int j = 0; j < n_connections; j++) { transform_attribute *connected_to = ah2ta(CFArrayGetValueAtIndex(attributes[i]->connections, j)); line_out = CFStringCreateWithFormat(NULL, NULL, CFSTR("\t%@ -> \"%@#%@\"\n"), dot_node_name, connected_to->transform->GetName(), connected_to->name); CFStringAppend(group_connections_out, line_out); - CFRelease(line_out); + CFReleaseNull(line_out); } + + CFSafeRelease(dot_node_name); } - line_out = CFStringCreateWithFormat(NULL, NULL, CFSTR("\t\t\"%@#NAME\" -> { %@ } [style=invis]\n\t}\n"), name, CFStringCreateByCombiningStrings(NULL, most_dot_names, CFSTR(" "))); + CFStringRef combinedString = CFStringCreateByCombiningStrings(NULL, most_dot_names, CFSTR(" ")); + line_out = CFStringCreateWithFormat(NULL, NULL, CFSTR("\t\t\"%@#NAME\" -> { %@ } [style=invis]\n\t}\n"), name, combinedString); CFStringAppend(group_nodes_out, line_out); - CFRelease(line_out); + CFReleaseNull(line_out); + CFSafeRelease(most_dot_names); + CFSafeRelease(combinedString); if (t->mGroup) { line_out = CFStringCreateWithFormat(NULL, NULL, CFSTR("\t\"%@#NAME\" -> \"%@#NAME\" [style=dotted,weight=5]\n"), name, t->mGroup->GetName()); CFStringAppend(group_connections_out, line_out); - CFRelease(line_out); + CFReleaseNull(line_out); } line_out = NULL; dispatch_async(collect_nodes, ^(void) { CFStringAppend(result, group_nodes_out); - CFRelease(group_nodes_out); + CFReleaseNull(group_nodes_out); }); dispatch_group_async(complete_connections, collect_connections, ^(void) { // We don't really need to append to result on the collect_nodes queue @@ -524,7 +529,7 @@ CFStringRef GroupTransform::DotForDebugging() // queue, but if that ever changed we would have a hard to track down bug... dispatch_async(collect_nodes, ^(void) { CFStringAppend(result, group_connections_out); - CFRelease(group_connections_out); + CFReleaseNull(group_connections_out); }); }); }); diff --git a/OSX/libsecurity_transform/lib/Monitor.cpp b/OSX/libsecurity_transform/lib/Monitor.cpp index 2b9958d3..1cbc19a1 100644 --- a/OSX/libsecurity_transform/lib/Monitor.cpp +++ b/OSX/libsecurity_transform/lib/Monitor.cpp @@ -45,11 +45,8 @@ void BlockMonitor::AttributeChanged(CFStringRef name, CFTypeRef value) } mSeenFinal = isFinal; - - if (realValue) - { - CFRetain(realValue); - } + + CFRetainSafe(realValue); if (mDispatchQueue == NULL) { @@ -74,7 +71,7 @@ BlockMonitor::BlockMonitor(dispatch_queue_t queue, SecMessageBlock block) : Moni block(value, error, isFinal); if (value) { - CFRelease(value); + CFReleaseNull(value); } if (isFinal && mGroup) { LastValueSent(); @@ -98,7 +95,7 @@ void BlockMonitor::LastValueSent() Transform *rootGroup = this->GetRootGroup(); CFTypeRef rootGroupRef = rootGroup->GetCFObject(); dispatch_async(rootGroup->mDispatchQueue, ^{ - CFRelease(rootGroupRef); + CFReleaseSafe(rootGroupRef); }); } diff --git a/OSX/libsecurity_transform/lib/NullTransform.cpp b/OSX/libsecurity_transform/lib/NullTransform.cpp index 4db1a700..ae36aafd 100644 --- a/OSX/libsecurity_transform/lib/NullTransform.cpp +++ b/OSX/libsecurity_transform/lib/NullTransform.cpp @@ -6,7 +6,7 @@ NullTransform::NullTransform() : Transform(CFSTR("NullTransform")) -CFTypeRef NullTransform::Make() +CFTypeRef NullTransform::Make() CF_RETURNS_RETAINED { return CoreFoundationHolder::MakeHolder(gInternalCFObjectName, new NullTransform()); } diff --git a/OSX/libsecurity_transform/lib/NullTransform.h b/OSX/libsecurity_transform/lib/NullTransform.h index 44afcf22..1355886a 100644 --- a/OSX/libsecurity_transform/lib/NullTransform.h +++ b/OSX/libsecurity_transform/lib/NullTransform.h @@ -15,7 +15,7 @@ protected: NullTransform(); public: - static CFTypeRef Make(); + static CFTypeRef Make() CF_RETURNS_RETAINED; static TransformFactory* MakeTransformFactory(); virtual void AttributeChanged(CFStringRef name, CFTypeRef value); diff --git a/OSX/libsecurity_transform/lib/SecCollectTransform.cpp b/OSX/libsecurity_transform/lib/SecCollectTransform.cpp index 6cc471dc..f8e4cb77 100644 --- a/OSX/libsecurity_transform/lib/SecCollectTransform.cpp +++ b/OSX/libsecurity_transform/lib/SecCollectTransform.cpp @@ -62,7 +62,7 @@ static SecTransformInstanceBlock CollectTransform(CFStringRef name, { if (NULL != allValues) { - CFRelease(allValues); + CFReleaseNull(allValues); } return (CFTypeRef) NULL; @@ -107,7 +107,7 @@ static SecTransformInstanceBlock CollectTransform(CFStringRef name, CFDataRef copy = CFDataCreateCopy(NULL, (CFDataRef)value); CFArrayAppendValue(allValues, copy); - CFRelease(copy); + CFReleaseNull(copy); } else { @@ -162,6 +162,7 @@ static SecTransformInstanceBlock CollectTransform(CFStringRef name, if (CFDataGetLength(result) != total_len) { oom(); + CFReleaseNull(result); return value; } @@ -170,13 +171,13 @@ static SecTransformInstanceBlock CollectTransform(CFStringRef name, SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef)resultData); - CFRelease(resultData); + CFReleaseNull(resultData); SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef)value); no_more_output(); - CFRelease(result); + CFReleaseNull(result); return value; } else if (CFStringGetTypeID() == type) @@ -189,6 +190,7 @@ static SecTransformInstanceBlock CollectTransform(CFStringRef name, SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef)value); no_more_output(); + CFReleaseNull(resultStr); return value; } @@ -197,13 +199,14 @@ static SecTransformInstanceBlock CollectTransform(CFStringRef name, // special case the singleton if (1 == CFArrayGetCount(allValues)) { - CFTypeRef result = (CFTypeRef)CFRetain(CFArrayGetValueAtIndex(allValues, 0)); + CFTypeRef result = (CFTypeRef)CFRetainSafe(CFArrayGetValueAtIndex(allValues, 0)); SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef)result); SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef)value); no_more_output(); + CFReleaseNull(result); return value; } @@ -216,6 +219,7 @@ static SecTransformInstanceBlock CollectTransform(CFStringRef name, SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, (CFTypeRef)value); no_more_output(); + CFReleaseNull(resultArray); return value; } diff --git a/OSX/libsecurity_transform/lib/SecCustomTransform.cpp b/OSX/libsecurity_transform/lib/SecCustomTransform.cpp index 9653f901..6ae31b84 100644 --- a/OSX/libsecurity_transform/lib/SecCustomTransform.cpp +++ b/OSX/libsecurity_transform/lib/SecCustomTransform.cpp @@ -567,12 +567,15 @@ CustomTransformFactory::CustomTransformFactory(CFStringRef uniqueName, SecTransf RegisterTransform(this, kSecCustom); } -CFTypeRef CustomTransformFactory::Make() +// clang cannot possibly reason about the way in which we turn Transforms into CFRefs, and it just looks like a leak +#ifndef __clang_analyzer__ +CFTypeRef CustomTransformFactory::Make() CF_RETURNS_RETAINED { CustomTransform *ct = new CustomTransform(this->GetTypename(), createFuncPtr); ct->Create(); return ct->get_ref(); } +#endif #pragma mark MISC @@ -590,12 +593,12 @@ extern "C" { null_allowed ? CFSTR(" either") : CFSTR(""), expected_type_name, null_allowed ? CFSTR(" or a NULL") : CFSTR("")); - CFRelease(value_type_name); + CFReleaseNull(value_type_name); } else { error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ received NULL value, expected a %@", attr, expected_type_name); } - CFRelease(expected_type_name); + CFReleaseNull(expected_type_name); return error; }; @@ -621,6 +624,8 @@ extern "C" { } } +// clang cannot reason about this business of creating an object for the side-effects of doing so +#ifndef __clang_analyzer__ Boolean SecTransformRegister(CFStringRef uniqueName, SecTransformCreateFP createFP, CFErrorRef *caller_error) { CFErrorRef error = NULL; @@ -640,6 +645,7 @@ Boolean SecTransformRegister(CFStringRef uniqueName, SecTransformCreateFP create return TRUE; } } +#endif SecTransformRef SecTransformCreate(CFStringRef name, CFErrorRef *error) { @@ -750,12 +756,15 @@ void CustomTransform::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef va if (vr) { if (CFGetTypeID(vr) == CFErrorGetTypeID()) { SendAttribute(AbortAH, vr); - CFRelease(vr); + CFReleaseNull(vr); } else { - CFErrorRef e = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "Invalid return type from a validate action, expected a CFErrorRef got a %@ (%@)", CFCopyTypeIDDescription(CFGetTypeID(vr)), vr); + CFStringRef idDescription = CFCopyTypeIDDescription(CFGetTypeID(vr)); + CFErrorRef e = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "Invalid return type from a validate action, expected a CFErrorRef got a %@ (%@)", idDescription, vr); SendAttribute(AbortAH, e); - CFRelease(vr); - // XXX: this causes a core dump -- I think AbortAH doesn't take it's own reference!! CFRelease(e); + CFReleaseNull(vr); + CFReleaseNull(e); + CFReleaseNull(idDescription); + // XXX: this causes a core dump -- I think AbortAH doesn't take it's own reference!! CFReleaseNull(e); } return; } @@ -779,7 +788,7 @@ void CustomTransform::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef va if (output != value && output != NULL) { - CFRelease(output); + CFReleaseNull(output); } } } @@ -838,7 +847,7 @@ CFTypeRef CustomTransform::rebind_data_action(CFStringRef action, char *utf8_message = utf8(msg); syslog(LOG_ERR, "%s", utf8_message); free(utf8_message); - CFRelease(msg); + CFReleaseNull(msg); } return result; } @@ -1022,7 +1031,7 @@ CFDictionaryRef CustomTransform::GetCustomExternalData() if (CFGetTypeID(result) == CFErrorGetTypeID()) { // Ouch! we should deal with this - CFRelease(result); + CFReleaseNull(result); return NULL; } @@ -1031,7 +1040,7 @@ CFDictionaryRef CustomTransform::GetCustomExternalData() return (CFDictionaryRef)result; } - CFRelease(result); + CFReleaseNull(result); result = NULL; return (CFDictionaryRef)result; } @@ -1053,9 +1062,9 @@ CFErrorRef SecTransformSetAttributeAction(SecTransformImplementationRef ref, { if (NULL == ref) { - CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, + CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref"); - + CFAutorelease(result); return result; } @@ -1068,9 +1077,9 @@ CFErrorRef SecTransformSetDataAction(SecTransformImplementationRef ref, { if (NULL == ref) { - CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, + CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref"); - + CFAutorelease(result); return result; } @@ -1083,9 +1092,9 @@ CFErrorRef SecTransformSetTransformAction(SecTransformImplementationRef ref, { if (NULL == ref) { - CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, + CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref"); - + CFAutorelease(result); return result; } @@ -1100,7 +1109,7 @@ CFTypeRef SecTranformCustomGetAttribute(SecTransformImplementationRef ref, { CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "SecTransformCustomGetAttribute called with a NULL SecTransformImplementationRef ref"); - + CFAutorelease(result); return result; } @@ -1114,9 +1123,9 @@ CFTypeRef SecTransformCustomSetAttribute(SecTransformImplementationRef ref, { if (NULL == ref) { - CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, + CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "SecTransformCustomSetAttribute called with a NULL SecTransformImplementationRef ref"); - + CFAutorelease(result); return result; } @@ -1130,9 +1139,9 @@ CFTypeRef SecTransformPushbackAttribute(SecTransformImplementationRef ref, { if (NULL == ref) { - CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, + CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "SecTransformPushbackAttribute called with a NULL SecTransformImplementationRef ref"); - + CFAutorelease(result); return (CFTypeRef)result; } diff --git a/OSX/libsecurity_transform/lib/SecDigestTransform.cpp b/OSX/libsecurity_transform/lib/SecDigestTransform.cpp index 9ab767c5..e58545a2 100644 --- a/OSX/libsecurity_transform/lib/SecDigestTransform.cpp +++ b/OSX/libsecurity_transform/lib/SecDigestTransform.cpp @@ -1,4 +1,5 @@ #include "SecDigestTransform.h" +#include "SecCFRelease.h" #include "Digest.h" @@ -28,10 +29,11 @@ SecTransformRef SecDigestTransformCreate(CFTypeRef digestType, if (result != NULL) { // an error occurred - CFRelease(tr); + CFReleaseNull(tr); if (error) { + CFRetainSafe(result); *error = result; } diff --git a/OSX/libsecurity_transform/lib/SecEncodeTransform.h b/OSX/libsecurity_transform/lib/SecEncodeTransform.h index 1a5ec411..499b242f 100644 --- a/OSX/libsecurity_transform/lib/SecEncodeTransform.h +++ b/OSX/libsecurity_transform/lib/SecEncodeTransform.h @@ -83,7 +83,7 @@ extern const CFStringRef kSecCompressionRatio; /*! @function SecEncodeTransformCreate @abstract Creates an encode computation object. - @param encodeType The type of digest to compute. You may pass NULL + @param encodeType The type of encoding to compute. You may pass NULL for this parameter, in which case an appropriate algorithm will be chosen for you. @param error A pointer to a CFErrorRef. This pointer will be set diff --git a/OSX/libsecurity_transform/lib/SecEncryptTransform.cpp b/OSX/libsecurity_transform/lib/SecEncryptTransform.cpp index eba99ab7..5ee1c15d 100644 --- a/OSX/libsecurity_transform/lib/SecEncryptTransform.cpp +++ b/OSX/libsecurity_transform/lib/SecEncryptTransform.cpp @@ -22,6 +22,7 @@ */ #include "SecEncryptTransform.h" +#include "SecTransformInternal.h" #include "EncryptTransform.h" /* -------------------------------------------------------------------------- @@ -61,7 +62,7 @@ SecTransformRef SecEncryptTransformCreate(SecKeyRef keyRef, CFErrorRef* error) else { - CFRelease(etRef); + CFReleaseNull(etRef); return NULL; } } @@ -83,7 +84,7 @@ SecTransformRef SecDecryptTransformCreate(SecKeyRef keyRef, CFErrorRef* error) } else { - CFRelease(dtRef); + CFReleaseNull(dtRef); return NULL; } } diff --git a/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.c b/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.c index 8cbb1197..83fa4a29 100644 --- a/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.c +++ b/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.c @@ -42,7 +42,7 @@ static SecTransformInstanceBlock MaskGenerationFunctionTransform(CFStringRef nam SecTransformInstanceBlock instanceBlock = ^{ SecTransformSetTransformAction(ref, kSecTransformActionFinalize, ^{ - CFRelease(accumulator); + CFReleaseNull(accumulator); return (CFTypeRef)NULL; }); @@ -52,7 +52,9 @@ static SecTransformInstanceBlock MaskGenerationFunctionTransform(CFStringRef nam SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kLengthName, ^CFTypeRef(SecTransformAttributeRef attribute, CFTypeRef value) { CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &outputLength); if (outputLength <= 0) { - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "MaskGenerationFunction Length must be one or more (not %@)", value)); + CFErrorRef error = CreateSecTransformErrorRef(kSecTransformErrorInvalidLength, "MaskGenerationFunction Length must be one or more (not %@)", value); + SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error); + CFSafeRelease(error); } return (CFTypeRef)NULL; @@ -69,8 +71,11 @@ static SecTransformInstanceBlock MaskGenerationFunctionTransform(CFStringRef nam SecTransformRef digest0 = transforms_assume(SecDigestTransformCreate(digestType, 0, NULL)); int32_t digestLength = 0; { + // we've already asserted that digest0 is non-null, but clang doesn't know that +#ifndef __clang_analyzer__ CFNumberRef digestLengthAsCFNumber = SecTransformGetAttribute(digest0, kSecDigestLengthAttribute); CFNumberGetValue(transforms_assume(digestLengthAsCFNumber), kCFNumberSInt32Type, &digestLength); +#endif } (void)transforms_assume(digestLength >= 0); @@ -90,10 +95,12 @@ static SecTransformInstanceBlock MaskGenerationFunctionTransform(CFStringRef nam digest = digest0; } else { digest = SecDigestTransformCreate(digestType, 0, &err); - if (digest == NULL) { - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, err); - return (CFErrorRef)NULL; - } + } + + if (digest == NULL) { + SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, err); + free(buffer); + return (CFErrorRef)NULL; } // NOTE: we shuld be able to do this without the copy, make a transform that takes an @@ -102,7 +109,7 @@ static SecTransformInstanceBlock MaskGenerationFunctionTransform(CFStringRef nam int32_t bigendian_i = htonl(i); CFDataAppendBytes(accumulatorPlusCounter, (UInt8*)&bigendian_i, sizeof(bigendian_i)); SecTransformSetAttribute(digest, kSecTransformInputAttributeName, accumulatorPlusCounter, &err); - CFRelease(accumulatorPlusCounter); + CFReleaseNull(accumulatorPlusCounter); UInt8 *buf = buffer + l; SecTransformExecuteAsync(digest, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFTypeRef message, CFErrorRef error, Boolean isFinal) { @@ -117,14 +124,14 @@ static SecTransformInstanceBlock MaskGenerationFunctionTransform(CFStringRef nam dispatch_group_leave(all_hashed); } }); - CFRelease(digest); + CFReleaseNull(digest); } dispatch_group_leave(all_hashed); dispatch_group_wait(all_hashed, DISPATCH_TIME_FOREVER); CFDataRef out = CFDataCreateWithBytesNoCopy(NULL, buffer, outputLength, kCFAllocatorMalloc); SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, out); - CFRelease(out); + CFReleaseNull(out); SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, NULL); } return (CFErrorRef)NULL; @@ -162,15 +169,15 @@ SecTransformRef SecCreateMaskGenerationFunctionTransform(CFStringRef hashType, i } if (!SecTransformSetAttribute(ret, kSecDigestTypeAttribute, hashType ? hashType : kSecDigestSHA1, error)) { - CFRelease(ret); + CFReleaseNull(ret); return NULL; } CFNumberRef len = CFNumberCreate(NULL, kCFNumberIntType, &length); ok = SecTransformSetAttribute(ret, kLengthName, len, error); - CFRelease(len); + CFReleaseNull(len); if (!ok) { - CFRelease(ret); + CFReleaseNull(ret); return NULL; } diff --git a/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.h b/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.h index 410b4e05..68290610 100644 --- a/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.h +++ b/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.h @@ -40,7 +40,6 @@ extern "C" { algorithms may only support certain sizes. You may pass 0 for this parameter, in which case an appropriate length will be chosen for you. - @param maskLength The desired mask length. @param error A pointer to a CFErrorRef. This pointer will be set if an error occurred. This value may be NULL if you do not want an error returned. diff --git a/OSX/libsecurity_transform/lib/SecSignVerifyTransform.c b/OSX/libsecurity_transform/lib/SecSignVerifyTransform.c index 50cea228..a4665279 100644 --- a/OSX/libsecurity_transform/lib/SecSignVerifyTransform.c +++ b/OSX/libsecurity_transform/lib/SecSignVerifyTransform.c @@ -27,7 +27,7 @@ #include "Utilities.h" #include #include "misc.h" - +#include // for dyld_get_program_sdk_version 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"); @@ -38,7 +38,7 @@ static CFErrorRef do_sec_fail(OSStatus code, const char *func, const char *file, int line) { CFStringRef msg = CFStringCreateWithFormat(NULL, NULL, CFSTR("Internal error #%x at %s %s:%d"), (unsigned)code, func, file, line); CFErrorRef err = fancy_error(CFSTR("Internal CSSM error"), code, msg); - CFRelease(msg); + CFReleaseNull(msg); return err; } @@ -62,7 +62,7 @@ CFErrorRef accumulate_data(CFMutableArrayRef *a, CFDataRef d) { } CFIndex c = CFArrayGetCount(*a); CFArrayAppendValue(*a, dc); - CFRelease(dc); + CFReleaseNull(dc); if (CFArrayGetCount(*a) != c+1) { return GetNoMemoryError(); } @@ -99,17 +99,17 @@ CFErrorRef fetch_and_clear_accumulated_data(CFMutableArrayRef *a, CFDataRef *dat } if (CFDataGetLength(out) != total) { - CFRelease(out); + CFReleaseNull(out); return GetNoMemoryError(); } CFArrayRef accumulator = *a; - CFRelease(accumulator); + CFReleaseNull(accumulator); *a = NULL; // This might be nice: // *data_out = CFDataCreateCopy(NULL, out); - // CFRelease(out); + // CFReleaseNull(out); // but that is slow (for large values) AND isn't really all that important anyway *data_out = out; @@ -279,12 +279,12 @@ static SecTransformInstanceBlock SignTransform(CFStringRef name, // Could use NoCopy and hold onto the allocation, and that will be a good idea when we can have it not so oversized CFDataRef result = CFDataCreate(NULL, sig.Data, sig.Length); SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, result); - CFRelease(result); + CFReleaseNull(result); free(sig_data); key = NULL; - CFRelease(digest); + CFReleaseNull(digest); digest = NULL; digest_length = 0; @@ -313,6 +313,7 @@ static SecTransformInstanceBlock SignTransform(CFStringRef name, CFDataRef alldata; CFErrorRef err = fetch_and_clear_accumulated_data(&data_accumulator, &alldata); if (err) { + free(sig_data); return (CFTypeRef)err; } CSSM_DATA c_d; @@ -321,19 +322,19 @@ static SecTransformInstanceBlock SignTransform(CFStringRef name, OSStatus rc = CSSM_SignData(cch, &c_d, 1, (input_is == kSecInputIsDigest) ? sign_alg->digest_algo : CSSM_ALGID_NONE, &sig); SEC_FAIL(rc); - CFRelease(alldata); + CFReleaseNull(alldata); assert(sig.Length <= 32*1024); CSSM_DeleteContext(cch); // Could use NoCopy and hold onto the allocation, and that will be a good idea when we can have it not so oversized CFDataRef result = CFDataCreate(NULL, sig.Data, sig.Length); SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, result); - CFRelease(result); + CFReleaseNull(result); free(sig_data); key = NULL; - CFRelease(digest); + CFReleaseNull(digest); digest = NULL; digest_length = 0; @@ -392,7 +393,7 @@ static SecTransformInstanceBlock SignTransform(CFStringRef name, SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecDigestTypeAttribute, ^(SecTransformAttributeRef ah, CFTypeRef value) { - digest = CFRetain(value); + digest = CFRetainSafe(value); return value; }); @@ -408,15 +409,17 @@ static SecTransformInstanceBlock SignTransform(CFStringRef name, OSStatus rc = SecKeyGetCSSMKey(key, &cssm_key); SEC_FAIL(rc); - - if (!cssm_key->KeyHeader.KeyUsage & CSSM_KEYUSE_SIGN) + + 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 + && !(cssm_key->KeyHeader.KeyUsage & (CSSM_KEYUSE_SIGN|CSSM_KEYUSE_ANY)))) { - key = NULL; - + key = NULL; // This key cannot sign! CFTypeRef error = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Key %@ can not be used to sign", key); SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error); return (CFTypeRef)NULL; } + return value; }); @@ -535,13 +538,17 @@ static SecTransformInstanceBlock VerifyTransform(CFStringRef name, rc = SecKeyGetCSSMKey((SecKeyRef)value, &cssm_key); SEC_FAIL(rc); - - if (!cssm_key->KeyHeader.KeyUsage & CSSM_KEYUSE_VERIFY) + + 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 + && !(cssm_key->KeyHeader.KeyUsage & (CSSM_KEYUSE_VERIFY|CSSM_KEYUSE_ANY)))) { - // This key cannot verify! - return (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Key %@ can not be used to verify", key); + key = NULL; // This key cannot verify! + CFTypeRef error = (CFTypeRef)CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Key %@ can not be used to verify", key); + SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, error); + return (CFTypeRef)NULL; } - + // we don't need to retain this because the owning transform is doing that for us key = (SecKeyRef) value; return value; @@ -557,7 +564,7 @@ static SecTransformInstanceBlock VerifyTransform(CFStringRef name, OSStatus rc; sig.Data = (void*)CFDataGetBytePtr(signature); sig.Length = CFDataGetLength(signature); - CFRelease(signature); + CFReleaseNull(signature); signature = NULL; if (input_is == kSecInputIsPlainText) { @@ -574,7 +581,7 @@ static SecTransformInstanceBlock VerifyTransform(CFStringRef name, c_d.Data = (void*)CFDataGetBytePtr(alldata); c_d.Length = CFDataGetLength(alldata); rc = CSSM_VerifyData(cch, &c_d, 1, (input_is == kSecInputIsDigest) ? verify_alg->digest_algo : CSSM_ALGID_NONE, &sig); - CFRelease(alldata); + CFReleaseNull(alldata); } CSSM_DeleteContext(cch); @@ -661,7 +668,7 @@ static SecTransformInstanceBlock VerifyTransform(CFStringRef name, SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, kSecDigestTypeAttribute, ^(SecTransformAttributeRef ah, CFTypeRef value) { - digest = CFRetain(value); + digest = CFRetainSafe(value); return value; }); @@ -715,7 +722,6 @@ SecTransformRef SecVerifyTransformCreate(SecKeyRef key, CFDataRef signature, CFE SecTransformSetAttribute(tr, kSecSignatureAttributeName, signature, error); } SecTransformSetAttribute(tr, kSecDigestTypeAttribute, kSecDigestSHA1, NULL); - SecTransformSetAttribute(tr, kSecDigestTypeAttribute, kSecDigestSHA1, NULL); SecTransformSetAttribute(tr, kSecInputIsAttributeName, kSecInputIsPlainText, NULL); return tr; diff --git a/OSX/libsecurity_transform/lib/SecTransform.cpp b/OSX/libsecurity_transform/lib/SecTransform.cpp index 12ee1cfc..6b59d982 100644 --- a/OSX/libsecurity_transform/lib/SecTransform.cpp +++ b/OSX/libsecurity_transform/lib/SecTransform.cpp @@ -84,6 +84,7 @@ SecGroupTransformRef SecTransformConnectTransforms(SecTransformRef sourceTransfo if (error) { + CFRetainSafe(temp); *error = temp; } @@ -133,14 +134,8 @@ Boolean SecTransformSetAttribute(SecTransformRef transformRef, result = (temp == NULL); if (error) { - *error = temp; - } - else - { - if (temp) - { - CFRelease(temp); - } + CFRetainSafe(temp); + *error = temp; } return result; @@ -159,7 +154,9 @@ CFTypeRef SecTransformGetAttribute(SecTransformRef transformRef, Transform* transform = (Transform*) CoreFoundationHolder::ObjectFromCFType(transformRef); if (transform->mIsActive) { - return CreateSecTransformErrorRef(kSecTransformTransformIsExecuting, "Can not get the value of attributes during execution (attempt to fetch %@/%@)", transform->GetName(), key); + CFErrorRef error = CreateSecTransformErrorRef(kSecTransformTransformIsExecuting, "Can not get the value of attributes during execution (attempt to fetch %@/%@)", transform->GetName(), key); + CFAutorelease(error); + return error; } return transform->GetAttribute(key); } @@ -190,7 +187,7 @@ static CFTypeRef InternalSecTransformExecute(SecTransformRef transformRef, } else { - CFRelease(localError); + CFReleaseNull(localError); } return (CFTypeRef)NULL; @@ -263,12 +260,17 @@ CFTypeRef SecTransformExecute(SecTransformRef transformRef, CFErrorRef* errorRef releaseTheGroup = true; +#ifdef __clang_analyzer__ + // we've already asserted that collectTransform is non-NULL, but clang doesn't know that, we skip use of it for the analyzer + SecGroupTransformRef connectResult = NULL; +#else SecGroupTransformRef connectResult = SecTransformConnectTransforms(transformRef, kSecTransformOutputAttributeName, collectTransform, kSecTransformInputAttributeName, theGroup, errorRef); +#endif if (NULL == connectResult) { @@ -312,6 +314,10 @@ CFTypeRef SecTransformExecute(SecTransformRef transformRef, CFErrorRef* errorRef SecTransformRef outputTransform = myGroup->FindLastTransform(); +#ifdef __clang_analyzer__ + // we've already asserted that collectTransform is non-NULL, but clang doesn't know that, we skip use of it for the analyzer + SecGroupTransformRef connectResult = NULL; +#else SecGroupTransformRef connectResult = SecTransformConnectTransforms(outputTransform, kSecTransformOutputAttributeName, @@ -321,13 +327,14 @@ CFTypeRef SecTransformExecute(SecTransformRef transformRef, CFErrorRef* errorRef if (NULL == connectResult) { - CFRelease(collectTransform); + CFReleaseNull(collectTransform); if (releaseTheGroup) { - CFRelease(theGroup); + CFReleaseNull(theGroup); } return (CFTypeRef)NULL; } +#endif // __clang_analyzer__ } __block CFTypeRef myResult = NULL; @@ -339,13 +346,13 @@ CFTypeRef SecTransformExecute(SecTransformRef transformRef, CFErrorRef* errorRef { if (NULL != errorRef) { - CFRetain(error); + CFRetainSafe(error); *errorRef = error; } if (NULL != myResult) { - CFRelease(myResult); + CFReleaseNull(myResult); myResult = NULL; } } @@ -353,7 +360,7 @@ CFTypeRef SecTransformExecute(SecTransformRef transformRef, CFErrorRef* errorRef if (NULL != message) { myResult = message; - CFRetain(myResult); + CFRetainSafe(myResult); } if (isFinal) @@ -477,6 +484,7 @@ SecTransformRef SecTransformCreateFromExternalRepresentation( *error = CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary, "Out of memory, or damaged input dictonary (duplicate label %@?)", xName); } + CFSafeRelease(aTransform); return NULL; } } diff --git a/OSX/libsecurity_transform/lib/SecTransformInternal.h b/OSX/libsecurity_transform/lib/SecTransformInternal.h index 0aef288b..b339ff8d 100644 --- a/OSX/libsecurity_transform/lib/SecTransformInternal.h +++ b/OSX/libsecurity_transform/lib/SecTransformInternal.h @@ -7,7 +7,7 @@ extern "C" { #endif #include "SecTransform.h" - +#include "SecCFRelease.h" CFErrorRef SecTransformConnectTransformsInternal(SecGroupTransformRef groupRef, SecTransformRef sourceTransformRef, CFStringRef sourceAttributeName, SecTransformRef destinationTransformRef, CFStringRef destinationAttributeName); diff --git a/OSX/libsecurity_transform/lib/SecTransformReadTransform.cpp b/OSX/libsecurity_transform/lib/SecTransformReadTransform.cpp index 332ad58a..e920746e 100644 --- a/OSX/libsecurity_transform/lib/SecTransformReadTransform.cpp +++ b/OSX/libsecurity_transform/lib/SecTransformReadTransform.cpp @@ -91,7 +91,7 @@ static SecTransformInstanceBlock StreamTransformImplementation(CFStringRef name, SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, value); // cleanup - CFRelease(value); + CFReleaseNull(value); bytesRead = CFReadStreamRead(input, buffer, blockSize); } @@ -142,7 +142,7 @@ SecTransformRef SecTransformCreateReadTransformWithReadStream(CFReadStreamRef in // add the input to the transform SecTransformSetAttribute(transform, kSecTransformInputAttributeName, arrayRef, &result); - CFRelease(arrayRef); + CFReleaseNull(arrayRef); } return transform; diff --git a/OSX/libsecurity_transform/lib/SingleShotSource.cpp b/OSX/libsecurity_transform/lib/SingleShotSource.cpp index f5121f21..9d5f2574 100644 --- a/OSX/libsecurity_transform/lib/SingleShotSource.cpp +++ b/OSX/libsecurity_transform/lib/SingleShotSource.cpp @@ -1,5 +1,6 @@ #include "SingleShotSource.h" +#include "Utilities.h" #include using namespace std; @@ -15,7 +16,7 @@ SingleShotSource::SingleShotSource(CFTypeRef value, Transform* t, CFStringRef na void SingleShotSource::DoActivate() { // Make sure our destination doesn't vanish while we are sending it data (or the final NULL) - CFRetain(mDestination->GetCFObject()); + CFRetainSafe(mDestination->GetCFObject()); // take our value and send it on its way mDestination->SetAttribute(mDestinationName, GetValue()); @@ -23,7 +24,7 @@ void SingleShotSource::DoActivate() // send an end of stream mDestination->SetAttribute(mDestinationName, NULL); - CFRelease(mDestination->GetCFObject()); + CFReleaseSafe(mDestination->GetCFObject()); } diff --git a/OSX/libsecurity_transform/lib/Source.cpp b/OSX/libsecurity_transform/lib/Source.cpp index ad26b5b4..3bdbe5c7 100644 --- a/OSX/libsecurity_transform/lib/Source.cpp +++ b/OSX/libsecurity_transform/lib/Source.cpp @@ -17,7 +17,7 @@ Source::Source(CFStringRef sourceObjectName, Transform* destination, CFStringRef mLastValue = NULL; mDispatchQueue = MyDispatchQueueCreate(queueName_cstr, NULL); free((void*)queueName_cstr); - CFRelease(queueName); + CFReleaseNull(queueName); } @@ -26,7 +26,7 @@ Source::~Source() { if (mLastValue != NULL) { - CFRelease(mLastValue); + CFReleaseNull(mLastValue); } dispatch_release(mDispatchQueue); @@ -48,19 +48,10 @@ void Source::SetValue(CFTypeRef value) return; } - if (mLastValue != NULL) // is there an existing value? If so, release it - { - CFRelease(mLastValue); - } - - if (value != NULL) - { - mLastValue = CFRetain(value); - } - else - { - mLastValue = NULL; - } + // is there an existing value? If so, release it + CFReleaseNull(mLastValue); + + mLastValue = CFRetainSafe(value); } diff --git a/OSX/libsecurity_transform/lib/StreamSource.cpp b/OSX/libsecurity_transform/lib/StreamSource.cpp index 73845b33..62c397fd 100644 --- a/OSX/libsecurity_transform/lib/StreamSource.cpp +++ b/OSX/libsecurity_transform/lib/StreamSource.cpp @@ -1,6 +1,7 @@ #include "StreamSource.h" #include #include "misc.h" +#include "SecCFRelease.h" using namespace std; @@ -14,7 +15,7 @@ StreamSource::StreamSource(CFReadStreamRef input, Transform* transform, CFString mReading(dispatch_group_create()) { dispatch_group_enter(mReading); - CFRetain(mReadStream); + CFRetainSafe(mReadStream); } void StreamSource::BackgroundActivate() @@ -36,7 +37,7 @@ void StreamSource::BackgroundActivate() CFErrorRef error = mDestination->SetAttribute(mDestinationName, data); - CFRelease(data); + CFReleaseNull(data); if (error != NULL) // we have a problem, there was probably an abort on the chain { @@ -53,8 +54,8 @@ void StreamSource::BackgroundActivate() if (error) { // NOTE: CF doesn't always tell us about this error. Arguably it could be better to - // "invent" a generic error, but it is a hard argument that we want to crash in CFRelease(NULL)... - CFRelease(error); + // "invent" a generic error, but it is a hard argument that we want to crash in CFReleaseNull(NULL)... + CFReleaseNull(error); } } else @@ -66,10 +67,10 @@ void StreamSource::BackgroundActivate() void StreamSource::DoActivate() { - CFRetain(mDestination->GetCFObject()); + CFRetainSafe(mDestination->GetCFObject()); dispatch_group_async(mReading, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ this->BackgroundActivate(); - CFRelease(mDestination->GetCFObject()); + CFReleaseSafe(mDestination->GetCFObject()); }); dispatch_group_leave(mReading); } @@ -83,7 +84,7 @@ void StreamSource::Finalize() StreamSource::~StreamSource() { - CFRelease(mReadStream); + CFReleaseNull(mReadStream); mReadStream = NULL; dispatch_release(mReading); mReading = NULL; diff --git a/OSX/libsecurity_transform/lib/Transform.cpp b/OSX/libsecurity_transform/lib/Transform.cpp index eea4a673..9046c3ce 100644 --- a/OSX/libsecurity_transform/lib/Transform.cpp +++ b/OSX/libsecurity_transform/lib/Transform.cpp @@ -28,17 +28,17 @@ static char RandomChar() } -static CFStringRef ah_set_describe(const void *v) { +static CFStringRef ah_set_describe(const void *v) CF_RETURNS_RETAINED { transform_attribute *ta = ah2ta(static_cast(const_cast(v))); return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@=%@ (conn: %@)"), ta->transform->GetName(), ta->name, ta->value ? ta->value : CFSTR("NULL"), ta->connections ? static_cast(ta->connections) : static_cast(CFSTR("NONE"))); } -static CFStringRef AttributeHandleFormat(CFTypeRef ah, CFDictionaryRef dict) { +static CFStringRef AttributeHandleFormat(CFTypeRef ah, CFDictionaryRef dict) CF_RETURNS_RETAINED { transform_attribute *ta = ah2ta(ah); return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), ta->transform->GetName(), ta->name); } -static CFStringRef AttributeHandleDebugFormat(CFTypeRef ah) { +static CFStringRef AttributeHandleDebugFormat(CFTypeRef ah) CF_RETURNS_RETAINED { transform_attribute *ta = ah2ta(ah); return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@ (%p)"), ta->transform->GetName(), ta->name, ta); } @@ -61,14 +61,14 @@ static void AttributeHandleFinalize(CFTypeRef ah) if (ta->value) { - CFRelease(ta->value); + CFReleaseNull(ta->value); } // ta->q already released if (ta->connections) { - CFRelease(ta->connections); + CFReleaseNull(ta->connections); } if (ta->semaphore) @@ -117,7 +117,7 @@ SecTransformAttributeRef Transform::makeAH(transform_attribute *ta) { static pthread_key_t ah_search_key_slot; static void destroy_ah_search_key(void *ah) { - CFRelease(ah); + CFReleaseNull(ah); pthread_setspecific(ah_search_key_slot, NULL); } @@ -198,7 +198,7 @@ SecTransformAttributeRef Transform::getAH(SecTransformStringOrAttributeRef attri CFSetAddValue(mAttributes, ah); if (CFSetGetCount(mAttributes) != cnt+1) { - CFRelease(ta->name); + CFReleaseNull(ta->name); free(ta); return NULL; } @@ -209,7 +209,7 @@ SecTransformAttributeRef Transform::getAH(SecTransformStringOrAttributeRef attri CFStringGetBytes(qname, CFRangeMake(0, CFStringGetLength(qname)), kCFStringEncodingUTF8, '?', FALSE, qnbuf, sz, &used); qnbuf[used] = '\0'; ta->q = dispatch_queue_create((char*)qnbuf, NULL); - CFRelease(qname); + CFReleaseNull(qname); ta->semaphore = dispatch_semaphore_create(kMaxPendingTransactions); @@ -375,7 +375,7 @@ Transform::Transform(CFStringRef transformType, CFStringRef CFobjectType) : ta->ignore_while_externalizing = 1; CFStringRef attributeName = CFStringCreateWithCStringNoCopy(NULL, name, 0, kCFAllocatorMalloc); SetAttributeNoCallback(kSecTransformTransformName, attributeName); - CFRelease(attributeName); + CFReleaseNull(attributeName); free(dqName); free(aqName); @@ -423,7 +423,7 @@ void Transform::FinalizeForClang() set_dispatch_finalizer(ta->q, ^{ // NOTE: not done until all pending use of the attribute queue has ended AND retain count is zero ta->transform = NULL; - CFRelease(ah); + CFReleaseSafe(ah); }); // If there is a pending pushback the attribute queue will be suspended, and needs a kick before it can be destructed. if (__sync_bool_compare_and_swap(&ta->pushback_state, transform_attribute::pb_value, transform_attribute::pb_discard)) { @@ -474,25 +474,25 @@ void Transform::Finalize() Transform::~Transform() { - CFRelease(mAttributes); + CFReleaseNull(mAttributes); if (mAbortError) { - CFRelease(mAbortError); + CFReleaseNull(mAbortError); mAbortError = NULL; } // See if we can catch anything using us after our death mDispatchQueue = (dispatch_queue_t)0xdeadbeef; - CFRelease(mTypeName); + CFReleaseNull(mTypeName); if (NULL != mPushedback) { - CFRelease(mPushedback); + CFReleaseNull(mPushedback); } dispatch_release(mActivationPending); } -CFStringRef Transform::GetName() { +CFStringRef Transform::GetName() CF_RETURNS_NOT_RETAINED { return (CFStringRef)GetAttribute(kSecTransformTransformName); } @@ -599,14 +599,14 @@ CFErrorRef Transform::RefactorErrorToIncludeAbortingTransform(CFErrorRef sourceE CFStringRef domain = CFErrorGetDomain(sourceError); CFDictionaryRef oldUserInfo = CFErrorCopyUserInfo(sourceError); CFMutableDictionaryRef userInfo = CFDictionaryCreateMutableCopy(NULL, 0, oldUserInfo); - CFRelease(oldUserInfo); + CFReleaseNull(oldUserInfo); // add the new key and value to the dictionary CFDictionaryAddValue(userInfo, kSecTransformAbortOriginatorKey, GetCFObject()); // make a new CFError CFErrorRef newError = CFErrorCreate(NULL, domain, code, userInfo); - CFRelease(userInfo); + CFReleaseNull(userInfo); return newError; } @@ -627,7 +627,7 @@ void Transform::AbortJustThisTransform(CFErrorRef abortErr) // by the dispatch queue finalizer so we don't need a retain/release of // abortErr for the abortAction block, but we do need to retain it // here to match with the release by the destructor. - CFRetain(abortErr); + CFRetainSafe(abortErr); dispatch_block_t abortAction = ^{ // This actually makes the abort happen, it needs to run on the transform's queue while the @@ -674,14 +674,18 @@ void Transform::AbortAllTransforms(CFTypeRef err) if (CFGetTypeID(err) != CFErrorGetTypeID()) { - replacementErr = err = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "ABORT set to a %@ (%@) not a %@", CFCopyTypeIDDescription(CFGetTypeID(err)), err, CFCopyTypeIDDescription(CFErrorGetTypeID())); + CFStringRef thisErrorTypeDescription = CFCopyTypeIDDescription(CFGetTypeID(err)); + CFStringRef regularErrorTypeDescription = CFCopyTypeIDDescription(CFErrorGetTypeID()); + replacementErr = err = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "ABORT set to a %@ (%@) not a %@", thisErrorTypeDescription, err, regularErrorTypeDescription); + CFReleaseNull(thisErrorTypeDescription); + CFReleaseNull(regularErrorTypeDescription); } error = RefactorErrorToIncludeAbortingTransform((CFErrorRef)err); if (replacementErr) { - CFRelease(replacementErr); + CFReleaseNull(replacementErr); } GroupTransform *root = GetRootGroup(); @@ -693,7 +697,7 @@ void Transform::AbortAllTransforms(CFTypeRef err) t->AbortJustThisTransform(error); }); dispatch_group_notify(all_aborted, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) { - CFRelease(error); + CFReleaseSafe(error); dispatch_release(all_aborted); }); } @@ -871,10 +875,10 @@ CFErrorRef Transform::SetAttributeNoCallback(SecTransformStringOrAttributeRef ke if (ta->value != value) { if (value && !doNotRetain) { - CFRetain(value); + CFRetainSafe(value); } if (ta->value) { - CFRelease(ta->value); + CFReleaseNull(ta->value); } } @@ -947,7 +951,9 @@ CFErrorRef Transform::SetAttribute(CFTypeRef key, CFTypeRef value) { if (mAbortError) { - return CreateSecTransformErrorRef(kSecTransformErrorAborted, "ABORT has been sent to the transform (%@)", mAbortError); + CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorAborted, "ABORT has been sent to the transform (%@)", mAbortError); + CFAutorelease(result); + return result; } // queue up the setting of the key and value @@ -961,32 +967,27 @@ CFErrorRef Transform::SetAttribute(CFTypeRef key, CFTypeRef value) ah = getAH(static_cast(key)); if (!ah) { - return CreateSecTransformErrorRef(kSecTransformErrorUnsupportedAttribute, "Can't set attribute %@ in transform %@", key, GetName()); + CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorUnsupportedAttribute, "Can't set attribute %@ in transform %@", key, GetName()); + CFAutorelease(result); + return result; } } else { - return CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "Transform::SetAttribute called with %@, requires a string or an AttributeHandle", key); + CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "Transform::SetAttribute called with %@, requires a string or an AttributeHandle", key); + CFAutorelease(result); + return result; } // Do this after the error check above so we don't leak - if (value != NULL) - { - CFRetain(value); // if we use dispatch_async we need to own the value (the matching release is in the set block) - } - + CFRetainSafe(value); // if we use dispatch_async we need to own the value (the matching release is in the set block) transform_attribute *ta = ah2ta(ah); dispatch_block_t set = ^{ Do(ah, value); - dispatch_semaphore_signal(ta->semaphore); - - if (value != NULL) - { - CFRelease(value); - } + CFReleaseSafe(value); }; @@ -1062,7 +1063,7 @@ CFErrorRef Transform::Pushback(SecTransformAttributeRef ah, CFTypeRef value) } if (value) { - CFRetain(value); + CFRetainSafe(value); } ta->pushback_value = value; dispatch_suspend(ta->q); @@ -1094,7 +1095,7 @@ void Transform::try_pushbacks() { Do(ah, v); if (v) { - CFRelease(v); + CFReleaseNull(v); } if (ta->pushback_state == transform_attribute::pb_repush) { ta->pushback_state = transform_attribute::pb_empty; @@ -1106,7 +1107,7 @@ void Transform::try_pushbacks() { dispatch_resume(ta->q); } - CFRelease(pb); + CFReleaseNull(pb); if (succeeded && CFArrayGetCount(mPushedback)) { // some attribute changed while we proceeded the last batch of pushbacks, so any "new" pushbacks are eligible to run again. @@ -1130,7 +1131,7 @@ void Transform::Debug(const char *cfmt, ...) { CFURLRef p = CFURLCreateWithFileSystemPath(NULL, CFSTR("/dev/stderr"), kCFURLPOSIXPathStyle, FALSE); StdErrWriteStream = CFWriteStreamCreateWithFile(NULL, p); CFWriteStreamOpen(StdErrWriteStream); - CFRelease(p); + CFReleaseNull(p); }); out = StdErrWriteStream; } @@ -1140,7 +1141,7 @@ void Transform::Debug(const char *cfmt, ...) { CFStringRef fmt = CFStringCreateWithCString(NULL, cfmt, kCFStringEncodingUTF8); CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, ap); - CFRelease(fmt); + CFReleaseNull(fmt); va_end(ap); @@ -1171,7 +1172,7 @@ void Transform::Debug(const char *cfmt, ...) { } }); - CFRelease(str); + CFReleaseNull(str); } } @@ -1252,7 +1253,7 @@ CFTypeRef Transform::Execute(dispatch_queue_t deliveryQueue, SecMessageBlock del if (isFinal) { dispatch_async(this->mDispatchQueue, ^{ - CFRelease(g); + CFReleaseSafe(g); }); } }; @@ -1261,7 +1262,7 @@ CFTypeRef Transform::Execute(dispatch_queue_t deliveryQueue, SecMessageBlock del if (!deliveryBlock) { - CFRelease(g); + CFReleaseNull(g); } return ret; @@ -1279,7 +1280,7 @@ CFTypeRef Transform::Execute(dispatch_queue_t deliveryQueue, SecMessageBlock del // Do a retain on our parent since we are using it GroupTransform *rootGroup = GetRootGroup(); - CFRetain(rootGroup->GetCFObject()); + CFRetainSafe(rootGroup->GetCFObject()); CFTypeRef result = NULL; @@ -1311,8 +1312,8 @@ CFTypeRef Transform::Execute(dispatch_queue_t deliveryQueue, SecMessageBlock del // It is safe to keep the monitors attached, because it is invalid to try to execute again, BUT // we do need to release the reference to the group that the monitor would normally release // when it processes the final message. - CFRelease(rootGroup->GetCFObject()); - CFRelease(monitorRef); + CFReleaseSafe(rootGroup->GetCFObject()); + CFReleaseNull(monitorRef); rootGroup->StartedExecutionInGroup(false); return NULL; } @@ -1335,7 +1336,7 @@ CFTypeRef Transform::Execute(dispatch_queue_t deliveryQueue, SecMessageBlock del dispatch_group_notify(activated, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_release(activated); // once we have been activated (but not before!), the monitor belongs to the group, and we can drop our claim - CFRelease(monitorRef); + CFReleaseSafe(monitorRef); rootGroup->StartedExecutionInGroup(true); }); }); @@ -1411,8 +1412,8 @@ CFErrorRef Transform::ExecuteOperation(CFStringRef &outputAttached, SecMonitorRe if (still_need) { CFStringRef elist = CFStringCreateByCombiningStrings(NULL, still_need, CFSTR(", ")); CFErrorRef err = CreateSecTransformErrorRef(kSecTransformErrorMissingParameter, "Can not execute %@, missing required attributes: %@", GetName(), elist); - CFRelease(elist); - CFRelease(still_need); + CFReleaseNull(elist); + CFReleaseNull(still_need); return err; } @@ -1514,17 +1515,11 @@ bool Transform::IsExternalizable() } static const void *CFTypeOrNULLRetain(CFAllocatorRef allocator, const void *value) { - if (value != NULL) { - return CFRetain(value); - } else { - return value; - } + return CFRetainSafe(value); } static void CFTypeOrNULLRelease(CFAllocatorRef allocator, const void *value) { - if (value != NULL) { - CFRelease(value); - } + CFReleaseNull(value); } static CFStringRef CFTypeOrNULLCopyDescription (const void *value) { @@ -1593,7 +1588,7 @@ CFDictionaryRef Transform::GetAHDictForSaveState(SecTransformStringOrAttributeRe for(i = 0; i < cnt; ++i) { - CFRelease(keys[i]); + CFReleaseNull(keys[i]); } return ret; @@ -1624,7 +1619,7 @@ CFDictionaryRef Transform::CopyState() transform_attribute *ta = attrs[i]; if (!ta->ignore_while_externalizing) { - CFRelease(values[j++]); + CFReleaseNull(values[j++]); } } @@ -1673,18 +1668,12 @@ void Transform::RestoreState(CFDictionaryRef state) else { CFErrorRef result = SendMetaAttribute(ah, (SecTransformMetaAttributeType)t, meta_values[j]); - if (result) - { - CFRelease(result); // see Transform::RestoreState is ignoring error returns - } + CFReleaseNull(result); // see Transform::RestoreState is ignoring error returns } } CFErrorRef result = SendMetaAttribute(ah, kSecTransformMetaAttributeExternalize, kCFBooleanTrue); - if (result) - { - CFRelease(result); // see Transform::RestoreState is ignoring error returns - } + CFReleaseNull(result); // see Transform::RestoreState is ignoring error returns } } @@ -1737,6 +1726,7 @@ CFDictionaryRef Transform::Externalize(CFErrorRef* error) // Really? This just seems like a bad idea if (NULL != error) { + CFRetainSafe(err); *error = err; } return NULL; @@ -1749,8 +1739,8 @@ CFDictionaryRef Transform::Externalize(CFErrorRef* error) CFDictionaryAddValue(output, EXTERN_TRANSFORM_CONNECTION_ARRAY, connections); // clean up - CFRelease(connections); - CFRelease(transforms); + CFReleaseNull(connections); + CFReleaseNull(transforms); return output; } @@ -1772,24 +1762,24 @@ CFErrorRef Transform::ProcessExternalize(CFMutableArrayRef transforms, CFMutable CFTypeRef type = CFStringCreateCopy(NULL, mTypeName); CFDictionaryAddValue(node, EXTERN_TRANSFORM_TYPE, type); - CFRelease(type); + CFReleaseNull(type); if (state != NULL) { CFDictionaryAddValue(node, EXTERN_TRANSFORM_STATE, state); - CFRelease(state); + CFReleaseNull(state); } CFDictionaryRef customItems = GetCustomExternalData(); if (NULL != customItems) { CFDictionaryAddValue(node, EXTERN_TRANSFORM_CUSTOM_EXPORTS_DICTIONARY, customItems); - CFRelease(customItems); + CFReleaseNull(customItems); } // append the resulting dictionary to the node list CFArrayAppendValue(transforms, node); - CFRelease(node); + CFReleaseNull(node); // now walk the attribute list CFIndex numAttributes = CFSetGetCount(mAttributes); @@ -1824,7 +1814,7 @@ CFErrorRef Transform::ProcessExternalize(CFMutableArrayRef transforms, CFMutable CFDictionaryAddValue(connection, EXTERN_TRANSFORM_TO_ATTRIBUTE, ta->name); CFArrayAppendValue(connections, connection); - CFRelease(connection); + CFReleaseNull(connection); } } } diff --git a/OSX/libsecurity_transform/lib/TransformFactory.cpp b/OSX/libsecurity_transform/lib/TransformFactory.cpp index 2eb68f28..6ab2ea34 100644 --- a/OSX/libsecurity_transform/lib/TransformFactory.cpp +++ b/OSX/libsecurity_transform/lib/TransformFactory.cpp @@ -70,7 +70,7 @@ TransformFactory* TransformFactory::FindTransformFactoryByType(CFStringRef name) -SecTransformRef TransformFactory::MakeTransformWithType(CFStringRef type, CFErrorRef* baseError) +SecTransformRef TransformFactory::MakeTransformWithType(CFStringRef type, CFErrorRef* baseError) CF_RETURNS_RETAINED { TransformFactory* tf = FindTransformFactoryByType(type); if (!tf) diff --git a/OSX/libsecurity_transform/lib/TransformFactory.h b/OSX/libsecurity_transform/lib/TransformFactory.h index 2e9ec455..d92a0442 100644 --- a/OSX/libsecurity_transform/lib/TransformFactory.h +++ b/OSX/libsecurity_transform/lib/TransformFactory.h @@ -23,7 +23,7 @@ private: static bool RegisterTransform_prelocked(TransformFactory* tf, CFStringRef name); public: - static SecTransformRef MakeTransformWithType(CFStringRef type, CFErrorRef* baseError); + static SecTransformRef MakeTransformWithType(CFStringRef type, CFErrorRef* baseError) CF_RETURNS_RETAINED; TransformFactory(CFStringRef type, bool registerGlobally = false, CFStringRef cftype = NULL); static void Setup(); diff --git a/OSX/libsecurity_transform/lib/Utilities.cpp b/OSX/libsecurity_transform/lib/Utilities.cpp index 2d396a56..b3e82e30 100644 --- a/OSX/libsecurity_transform/lib/Utilities.cpp +++ b/OSX/libsecurity_transform/lib/Utilities.cpp @@ -49,13 +49,13 @@ static CFErrorRef CreateErrorRefCore(CFStringRef domain, int errorCode, const ch CFStringRef fmt = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8); CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, ap); va_end(ap); - CFRelease(fmt); + CFReleaseNull(fmt); CFStringRef keys[] = {kCFErrorDescriptionKey}; CFStringRef values[] = {str}; CFErrorRef result = CFErrorCreateWithUserInfoKeysAndValues(NULL, domain, errorCode, (const void**) keys, (const void**) values, 1); - CFRelease(str); + CFReleaseNull(str); return result; } @@ -95,7 +95,7 @@ CFTypeRef gAnnotatedRef = NULL; CFTypeRef DebugRetain(const void* owner, CFTypeRef type) { - CFTypeRef result = CFRetain(type); + CFTypeRef result = CFRetainSafe(type); if (type == gAnnotatedRef) { fprintf(stderr, "Object %p was retained by object %p, count = %ld\n", type, owner, CFGetRetainCount(type)); @@ -113,7 +113,7 @@ void DebugRelease(const void* owner, CFTypeRef type) fprintf(stderr, "Object %p was released by object %p, count = %ld\n", type, owner, CFGetRetainCount(type) - 1); } - CFRelease(type); + CFReleaseNull(type); } // Cribbed from _dispatch_bug and altered a bit diff --git a/OSX/libsecurity_transform/lib/Utilities.h b/OSX/libsecurity_transform/lib/Utilities.h index 52bbf256..830e7ce2 100644 --- a/OSX/libsecurity_transform/lib/Utilities.h +++ b/OSX/libsecurity_transform/lib/Utilities.h @@ -7,7 +7,7 @@ extern "C" { #include - +#include "SecCFRelease.h" void MyDispatchAsync(dispatch_queue_t queue, void(^block)(void)); dispatch_queue_t MyDispatchQueueCreate(const char* name, dispatch_queue_attr_t attr); diff --git a/OSX/libsecurity_transform/lib/c++utils.cpp b/OSX/libsecurity_transform/lib/c++utils.cpp index 798ea84f..787e8866 100644 --- a/OSX/libsecurity_transform/lib/c++utils.cpp +++ b/OSX/libsecurity_transform/lib/c++utils.cpp @@ -1,4 +1,5 @@ #include "c++utils.h" +#include "SecCFRelease.h" using namespace std; @@ -41,7 +42,7 @@ CFTypeRefHolder::~CFTypeRefHolder() { if (mTypeRef != NULL) { - CFRelease(mTypeRef); + CFReleaseNull(mTypeRef); } } @@ -51,7 +52,7 @@ void CFTypeRefHolder::Set(CFTypeRef typeRef) { if (mTypeRef != NULL) { - CFRelease(mTypeRef); + CFReleaseNull(mTypeRef); } mTypeRef = typeRef; diff --git a/OSX/libsecurity_transform/lib/c++utils.h b/OSX/libsecurity_transform/lib/c++utils.h index b22810f3..45223ed5 100644 --- a/OSX/libsecurity_transform/lib/c++utils.h +++ b/OSX/libsecurity_transform/lib/c++utils.h @@ -5,7 +5,7 @@ #include std::string StringFromCFString(CFStringRef theString); -CFStringRef CFStringFromString(std::string theString); +CFStringRef CFStringFromString(std::string theString) CF_RETURNS_RETAINED; // class to automatically manage the lifetime of a CFObject diff --git a/OSX/libsecurity_transform/lib/misc.c b/OSX/libsecurity_transform/lib/misc.c index 54ac7848..7d921ba2 100644 --- a/OSX/libsecurity_transform/lib/misc.c +++ b/OSX/libsecurity_transform/lib/misc.c @@ -23,7 +23,7 @@ #include "misc.h" - +#include "SecCFRelease.h" // NOTE: the return may or allocate a fair bit more space then it needs. // Use it for short lived conversions (or strdup the result). @@ -47,7 +47,7 @@ void CFfprintf(FILE *f, const char *format, ...) { CFStringRef fmt = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8); CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, ap); va_end(ap); - CFRelease(fmt); + CFReleaseNull(fmt); CFIndex sz = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8); sz += 1; @@ -64,6 +64,7 @@ void CFfprintf(FILE *f, const char *format, ...) { CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, '?', FALSE, buf, sz, &used); } else { buf = (unsigned char *)"malloc failue during CFfprintf\n"; + needs_free = false; } fwrite(buf, 1, used, f); @@ -71,13 +72,14 @@ void CFfprintf(FILE *f, const char *format, ...) { free(buf); } - CFRelease(str); + CFReleaseNull(str); } CFErrorRef fancy_error(CFStringRef domain, CFIndex code, CFStringRef description) { const void *v_ekey = kCFErrorDescriptionKey; const void *v_description = description; CFErrorRef err = CFErrorCreateWithUserInfoKeysAndValues(NULL, domain, code, &v_ekey, &v_description, 1); + CFAutorelease(err); return err; } @@ -94,7 +96,7 @@ void add_t2ca(CFMutableDictionaryRef t2ca, CFStringRef t, CFStringRef a) { void CFSafeRelease(CFTypeRef object) { if (object) { - CFRelease(object); + CFReleaseNull(object); } } @@ -139,6 +141,7 @@ void graphviz(FILE *f, SecTransformRef tr) { CFfprintf(f, "\t\t\"%@#%@\" [label=\"%@\"];\n", name, attrs[j], attrs[j]); } CFfprintf(f, "\t\t\"%@\" [fontcolor=blue, fontsize=20];\n\t}\n"); + free(attrs); } } diff --git a/OSX/libsecurity_transform/regressions/transform-01-sigverify.m b/OSX/libsecurity_transform/regressions/transform-01-sigverify.m new file mode 100644 index 00000000..47277920 --- /dev/null +++ b/OSX/libsecurity_transform/regressions/transform-01-sigverify.m @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2007-2009,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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utilities/SecCFRelease.h" +#include "utilities/array_size.h" + +#include "transform_regressions.h" + +static const char *keyDataBase64 = "\ +MIIEogIBAAKCAQEAubvYJ2BA80CFbu8guNFXF02dNQ/QiaA/5h+trXmxBxHX1Ty1inqvrgB5yen0yCUL\ +5LGiEjscIjqLBY7SN9Jm3ui2f6CttsGF/jlMCoQGI2UD8kWH7miXv+dhdM5n1Eifik21Ga121VRZmuMT\ +36YOG6bb7RpBSVp7n7xBB4pjhpjuTuvZVwNB4rdci1NPwDEKyDJmU/IG/CzGRj2Xmq0/dCoQm0xwMY3A\ +X7MGWHi/Kt8bhFR1wuxDLOpqvCIGS+5s0gZqwn5gQCDtFY1tpL5stDRcZIyHh1EobWG9daGGMnx7s/tb\ +69cuhSKC5g3oylZ8H3LjW+eOZtuqPs/5vS7/WwIDAQABAoIBAGcwmQAPdyZus3OVwa1NCUD2KyB+39KG\ +yNmWwgx+br9Jx4s+RnJghVh8BS4MIKZOBtSRaEUOuCvAMNrupZbD+8leq34vDDRcQpCizr+M6Egj6FRj\ +Ewl+7Mh+yeN2hbMoghL552MTv9D4Iyxteu4nuPDd/JQ3oQwbDFIL6mlBFtiBDUr9ndemmcJ0WKuzor6a\ +3rgsygLs8SPyMefwIKjh5rJZls+iv3AyVEoBdCbHBz0HKgLVE9ZNmY/gWqda2dzAcJxxMdafeNVwHovv\ +BtyyRGnA7Yikx2XT4WLgKfuUsYLnDWs4GdAa738uxPBfiddQNeRjN7jRT1GZIWCk0P29rMECgYEA8jWi\ +g1Dph+4VlESPOffTEt1aCYQQWtHs13Qex95HrXX/L49fs6cOE7pvBh7nVzaKwBnPRh5+3bCPsPmRVb7h\ +k/GreOriCjTZtyt2XGp8eIfstfirofB7c1lNBjT61BhgjJ8Moii5c2ksNIOOZnKtD53n47mf7hiarYkw\ +xFEgU6ECgYEAxE8Js3gIPOBjsSw47XHuvsjP880nZZx/oiQ4IeJb/0rkoDMVJjU69WQu1HTNNAnMg4/u\ +RXo31h+gDZOlE9t9vSXHdrn3at67KAVmoTbRknGxZ+8tYpRJpPj1hyufynBGcKwevv3eHJHnE5eDqbHx\ +ynZFkXemzT9aMy3R4CCFMXsCgYAYyZpnG/m6WohE0zthMFaeoJ6dSLGvyboWVqDrzXjCbMf/4wllRlxv\ +cm34T2NXjpJmlH2c7HQJVg9uiivwfYdyb5If3tHhP4VkdIM5dABnCWoVOWy/NvA7XtE+KF/fItuGqKRP\ +WCGaiRHoEeqZ23SQm5VmvdF7OXNi/R5LiQ3o4QKBgAGX8qg2TTrRR33ksgGbbyi1UJrWC3/TqWWTjbEY\ +uU51OS3jvEQ3ImdjjM3EtPW7LqHSxUhjGZjvYMk7bZefrIGgkOHx2IRRkotcn9ynKURbD+mcE249beuc\ +6cFTJVTrXGcFvqomPWtV895A2JzECQZvt1ja88uuu/i2YoHDQdGJAoGAL2TEgiMXiunb6PzYMMKKa+mx\ +mFnagF0Ek3UJ9ByXKoLz3HFEl7cADIkqyenXFsAER/ifMyCoZp/PDBd6ZkpqLTdH0jQ2Yo4SllLykoiZ\ +fBWMfjRu4iw9E0MbPB3blmtzfv53BtWKy0LUOlN4juvpqryA7TgaUlZkfMT+T1TC7xU=\ +"; + +static const int kTestTransformSignVerify = 85; + +static void sign_verify_transform_from_key(SecKeyRef privateKey, SecKeyRef publicKey, bool expect_success) { + // Create signature transform with private key + CFErrorRef error=NULL; + NSData *testData = [NSData dataWithBytes:"test" length:4]; + SecTransformRef signer = SecSignTransformCreate(privateKey, &error); + + ok(signer != nil, "transform execution succeeded"); + ok(expect_success==(error==NULL), "no error %@",error); + CFReleaseNull(error); + + ok(expect_success==SecTransformSetAttribute(signer, kSecTransformInputAttributeName, (CFDataRef)testData, &error), + "set input data to verify transform"); + ok(expect_success==(error==NULL), "error reported %@",error); + CFReleaseNull(error); + + NSData *signature = (__bridge_transfer NSData *)SecTransformExecute(signer, &error); + ok(expect_success==(signature!=nil), "create signature with transform"); + ok(expect_success==(error==NULL), "error reported %@",error); + CFReleaseNull(error); + + // Create verify transform with public key. + ok(publicKey != NULL, "get public key from private key"); + SecTransformRef verifier = SecVerifyTransformCreate(publicKey, (CFDataRef)signature, &error); + ok(verifier, "create verification transform"); + ok(expect_success==(error==NULL), "no error %@",error); + CFReleaseNull(error); + + ok(expect_success==SecTransformSetAttribute(verifier, kSecTransformInputAttributeName, (CFDataRef)testData, &error), + "set input data to verify transform"); + ok(expect_success==(error==NULL), "no error %@",error); + CFReleaseNull(error); + + NSNumber *result = (__bridge_transfer NSNumber *)SecTransformExecute(verifier, &error); + ok(expect_success==(result!=nil), "transform execution succeeded"); + ok(expect_success==(error==NULL), "no error %@",error); + ok(expect_success==result.boolValue, "transform verified signature"); + + CFReleaseNull(signer); + CFReleaseNull(verifier); + CFReleaseNull(error); +} + +static void createKeysWithUsage(SecKeyRef *privateKey, SecKeyRef *publicKey, CFTypeRef privKeyUsage, CFTypeRef pubKeyUsage, CFDataRef keyData) { + + + CFArrayRef keyUsagesArray = NULL; + // First the private key + { + CFArrayRef itemsRef = 0; + CFTypeRef keyAtt[1] = { kSecAttrIsExtractable }; + CFArrayRef keyAttArray = CFArrayCreate(NULL, keyAtt, 1, &kCFTypeArrayCallBacks); + CFTypeRef keyUsagesPriv[1] = { privKeyUsage }; + keyUsagesArray = CFArrayCreate(NULL, keyUsagesPriv, 1, &kCFTypeArrayCallBacks); + SecItemImportExportKeyParameters priv_params={.keyUsage=keyUsagesArray,.keyAttributes=keyAttArray}; + + ok_status(SecItemImport(keyData, 0, 0, 0, 0, &priv_params, 0, &itemsRef)); + NSArray *items_priv = CFBridgingRelease(itemsRef); + is(items_priv.count,1); + *privateKey = (SecKeyRef)CFBridgingRetain([items_priv objectAtIndex:0]); + CFReleaseNull(keyUsagesArray); + CFReleaseNull(keyAttArray); + } + + // Public key + { + CFErrorRef error=NULL; + CFArrayRef itemsRef = 0; + CFTypeRef keyUsagesPub[1] = { pubKeyUsage }; + SecKeyRef publicKey_tmp = SecKeyCopyPublicKey(*privateKey); // It does not have the attribute we want + CFDataRef publicKeyData = SecKeyCopyExternalRepresentation(publicKey_tmp,&error); // Extract the external representation and import with attributes + keyUsagesArray = CFArrayCreate(NULL, keyUsagesPub, 1, &kCFTypeArrayCallBacks); + SecItemImportExportKeyParameters pub_params={.keyUsage=keyUsagesArray}; + + ok_status(SecItemImport(publicKeyData, 0, 0, 0, 0, &pub_params, 0, &itemsRef)); + NSArray *items_pub = CFBridgingRelease(itemsRef); + is(items_pub.count,1); + *publicKey = (SecKeyRef)CFBridgingRetain([items_pub objectAtIndex:0]); + CFReleaseNull(keyUsagesArray); + CFReleaseNull(publicKeyData); + CFReleaseNull(publicKey_tmp); + } +} + + + +static void test_transform_sign_verify() { + SecKeyRef privateKey = NULL; + SecKeyRef publicKey = NULL; + // Create private key instance. + NSData *keyData = [[NSData alloc] initWithBase64EncodedString:[NSString stringWithUTF8String:keyDataBase64] + options:NSDataBase64DecodingIgnoreUnknownCharacters]; + + // Import key with SecKeyCreateWithData + { + NSDictionary *keyAttrs = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @2048, + (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate }; + privateKey = SecKeyCreateWithData((CFDataRef)keyData, (CFDictionaryRef)keyAttrs, NULL); + ok(privateKey != NULL, "create private key from data"); + publicKey = SecKeyCopyPublicKey(privateKey); + sign_verify_transform_from_key(privateKey,publicKey,true); + CFReleaseNull(privateKey); + CFReleaseNull(publicKey); + } + + // Import the key with default attribute (no key Usage specified) + { + CFArrayRef itemsRef = 0; + CFTypeRef keyAtt[1] = { kSecAttrIsExtractable }; + CFArrayRef keyAttArray = CFArrayCreate(NULL, keyAtt, 1, &kCFTypeArrayCallBacks); + SecItemImportExportKeyParameters params={.keyAttributes=keyAttArray}; + ok_status(SecItemImport((__bridge CFDataRef)keyData, 0, 0, 0, 0, ¶ms, 0, &itemsRef)); + NSArray *items = CFBridgingRelease(itemsRef); + is(items.count,1); + privateKey = ((SecKeyRef)CFBridgingRetain([items objectAtIndex:0])); + SecKeyRef publicKey = SecKeyCopyPublicKey(privateKey); + sign_verify_transform_from_key(privateKey,publicKey,true); + CFReleaseNull(privateKey); + CFReleaseNull(publicKey); + } + + // Import the key with sign attribute + { + createKeysWithUsage(&privateKey,&publicKey,kSecAttrCanSign,kSecAttrCanVerify,(__bridge CFDataRef)keyData); + sign_verify_transform_from_key(privateKey,publicKey,true); + CFReleaseNull(privateKey); + CFReleaseNull(publicKey); + } + + // Import the key with sign attribute + { + createKeysWithUsage(&privateKey,&publicKey,kSecAttrCanSign,kSecAttrCanVerify,(__bridge CFDataRef)keyData); + sign_verify_transform_from_key(privateKey,publicKey,true); + CFReleaseNull(privateKey); + CFReleaseNull(publicKey); + } + + // Import the key with enc attribute + { + createKeysWithUsage(&privateKey,&publicKey,kSecAttrCanDecrypt,kSecAttrCanEncrypt,(__bridge CFDataRef)keyData); + sign_verify_transform_from_key(privateKey,publicKey,false); + CFReleaseNull(privateKey); + CFReleaseNull(publicKey); + } +} + +static const int kTestCount = kTestTransformSignVerify; + +int transform_01_sigverify(int argc, char *const *argv) { + plan_tests(kTestCount); + + test_transform_sign_verify(); + + return 0; +} diff --git a/OSX/libsecurity_transform/regressions/transform_regressions.h b/OSX/libsecurity_transform/regressions/transform_regressions.h new file mode 100644 index 00000000..3cdeab73 --- /dev/null +++ b/OSX/libsecurity_transform/regressions/transform_regressions.h @@ -0,0 +1,3 @@ +#include + +ONE_TEST(transform_01_sigverify) diff --git a/OSX/libsecurity_translocate/lib/SecTranslocateDANotification.cpp b/OSX/libsecurity_translocate/lib/SecTranslocateDANotification.cpp index e600a745..97f1cd9c 100644 --- a/OSX/libsecurity_translocate/lib/SecTranslocateDANotification.cpp +++ b/OSX/libsecurity_translocate/lib/SecTranslocateDANotification.cpp @@ -39,11 +39,19 @@ namespace Security { namespace SecTranslocate { +typedef enum { + SCT_DA_DISK_DISAPPEARED, + SCT_DA_DISK_UNMOUNT_APPROVAL, + SCT_DA_DISK_DESCRIPTION_CHANGE +} SecTranslocateDACallbackType_t; + typedef CFDictionaryRef (*DiskCopyDescription_t)(DADiskRef); typedef DASessionRef (*SessionCreate_t) (CFAllocatorRef); typedef void (*SessionSetDispatchQueue_t)(DASessionRef,dispatch_queue_t); typedef void (*RegisterDiskDisappearedCallback_t) (DASessionRef, CFDictionaryRef, DADiskDisappearedCallback, void*); typedef void (*RegisterDiskUnmountApprovalCallback_t) (DASessionRef, CFDictionaryRef, DADiskUnmountApprovalCallback, void*); +typedef void (*RegisterDiskDescriptionChangedCallback_t) (DASessionRef, CFDictionaryRef, CFArrayRef, + DADiskDescriptionChangedCallback, void*); typedef void (*UnregisterCallback_t)(DASessionRef, void*, void*); class DiskArbitrationProxy @@ -61,6 +69,8 @@ public: { if(pRegisterDiskDisappearedCallback) pRegisterDiskDisappearedCallback(s,d,c,x); }; inline void registerDiskUnmountApprovalCallback (DASessionRef s, CFDictionaryRef d, DADiskUnmountApprovalCallback c, void* x) const { if(pRegisterDiskUnmountApprovalCallback) pRegisterDiskUnmountApprovalCallback(s,d,c,x); }; + inline void registerDiskDescriptionChangedCallback (DASessionRef s, CFDictionaryRef d, CFArrayRef a, DADiskDescriptionChangedCallback c, void* x) const + { if(pRegisterDiskDescriptionChangedCallback) pRegisterDiskDescriptionChangedCallback(s,d,a,c,x); }; inline void unregisterCallback (DASessionRef s, void* c, void* x) const { if(pUnregisterCallback) pUnregisterCallback(s,c,x); }; inline CFDictionaryRef diskDescriptionMatchVolumeMountable() const @@ -77,6 +87,7 @@ private: SessionSetDispatchQueue_t pSessionSetDispatchQueue; RegisterDiskDisappearedCallback_t pRegisterDiskDisappearedCallback; RegisterDiskUnmountApprovalCallback_t pRegisterDiskUnmountApprovalCallback; + RegisterDiskDescriptionChangedCallback_t pRegisterDiskDescriptionChangedCallback; UnregisterCallback_t pUnregisterCallback; CFDictionaryRef* pDiskDescriptionMatchVolumeMountable; CFStringRef* pDiskDescriptionVolumePathKey; @@ -92,6 +103,7 @@ DiskArbitrationProxy::DiskArbitrationProxy() pSessionSetDispatchQueue = (SessionSetDispatchQueue_t) checkedDlsym(handle, "DASessionSetDispatchQueue"); pRegisterDiskDisappearedCallback = (RegisterDiskDisappearedCallback_t) checkedDlsym(handle, "DARegisterDiskDisappearedCallback"); pRegisterDiskUnmountApprovalCallback = (RegisterDiskUnmountApprovalCallback_t) checkedDlsym(handle, "DARegisterDiskUnmountApprovalCallback"); + pRegisterDiskDescriptionChangedCallback = (RegisterDiskDescriptionChangedCallback_t) checkedDlsym(handle,"DARegisterDiskDescriptionChangedCallback"); pUnregisterCallback = (UnregisterCallback_t) checkedDlsym(handle, "DAUnregisterCallback"); pDiskDescriptionMatchVolumeMountable = (CFDictionaryRef*) checkedDlsym(handle, "kDADiskDescriptionMatchVolumeMountable"); pDiskDescriptionVolumePathKey = (CFStringRef*) checkedDlsym(handle, "kDADiskDescriptionVolumePathKey"); @@ -134,13 +146,13 @@ DiskArbitrationProxy* DiskArbitrationProxy::get() For Disk Arbitration need to 1. create a session and hold on to it. 2. associate it with a queue - 3. register for call backs (DADiskDisappearedCallback and DADiskUnmountApprovalCallback) + 3. register for call backs (DADiskDisappearedCallback, DADiskDescriptionChangedCallback and DADiskUnmountApprovalCallback) 4. provide a function to get the mounton path from DADiskref 5. Return a dissenter if unmount is gonna fail because something is in use (i.e. if my unmount fails) */ /* Returns false if we failed an unmount call. anything else returns true */ -static bool cleanupDisksOnVolume(DADiskRef disk) +static bool cleanupDisksOnVolume(DADiskRef disk, SecTranslocateDACallbackType_t type) { bool result = true; string fspathString; @@ -159,8 +171,14 @@ static bool cleanupDisksOnVolume(DADiskRef disk) if(fspath) { - //For the disk disappeared call back, it looks like we won't get a volume path so we'll keep the empty string - fspathString = cfString(fspath); + if (type != SCT_DA_DISK_DESCRIPTION_CHANGE) { + //For the disk disappeared call back, it looks like we won't get a volume path so we'll keep the empty string + fspathString = cfString(fspath); + } else { + // For disk description changed, volume path key will be populated on mount and null on unmount + // we only care about unmount, so bail if there is a volume path key + return result; + } } result = destroyTranslocatedPathsForUserOnVolume(fspathString); @@ -176,17 +194,22 @@ static bool cleanupDisksOnVolume(DADiskRef disk) return result; } -static void diskDisappearedCallback(DADiskRef disk, void* context) +static void diskDisappearedCallback(DADiskRef disk, void* __unused context) { - (void)cleanupDisksOnVolume(disk); + (void)cleanupDisksOnVolume(disk, SCT_DA_DISK_DISAPPEARED); } -static DADissenterRef unmountApprovalCallback(DADiskRef disk, void *context) +static DADissenterRef unmountApprovalCallback(DADiskRef disk, void* __unused context) { - (void)cleanupDisksOnVolume(disk); + (void)cleanupDisksOnVolume(disk, SCT_DA_DISK_UNMOUNT_APPROVAL); return NULL; //For now, we won't raise a dissent, just let the unmount fail. The dissent text would get used by UI. } +static void diskDescriptionChangedCallback(DADiskRef disk, CFArrayRef __unused daKeys, void* __unused context) +{ + (void)cleanupDisksOnVolume(disk, SCT_DA_DISK_DESCRIPTION_CHANGE); +} + DANotificationMonitor::DANotificationMonitor(dispatch_queue_t q) { DiskArbitrationProxy *dap = DiskArbitrationProxy::get(); @@ -206,6 +229,7 @@ DANotificationMonitor::DANotificationMonitor(dispatch_queue_t q) dap->sessionSetDispatchQueue(diskArbitrationSession, q); /* register so we can cleanup from force unmounts */ dap->registerDiskDisappearedCallback( diskArbitrationSession, dap->diskDescriptionMatchVolumeMountable(), diskDisappearedCallback, NULL ); + dap->registerDiskDescriptionChangedCallback(diskArbitrationSession, dap->diskDescriptionMatchVolumeMountable(), NULL, diskDescriptionChangedCallback, NULL); /* register so we can clean up pre-unmount */ dap->registerDiskUnmountApprovalCallback( diskArbitrationSession, dap->diskDescriptionMatchVolumeMountable(), unmountApprovalCallback, NULL ); } diff --git a/OSX/libsecurity_translocate/lib/SecTranslocateShared.cpp b/OSX/libsecurity_translocate/lib/SecTranslocateShared.cpp index f03c070e..9c1595ae 100644 --- a/OSX/libsecurity_translocate/lib/SecTranslocateShared.cpp +++ b/OSX/libsecurity_translocate/lib/SecTranslocateShared.cpp @@ -73,7 +73,9 @@ static void setMountPointQuarantineIfNecessary(const string &mountPoint, const s static string getMountpointFromAppPath(const string &appPath, const string &originalPath); static vector getMountTableSnapshot(); -static string mountExistsForUser(const string &translationDirForUser, const string &originalPath, const string &destMount); +static string mountExistsForUser(const string &translationDirForUser, + const TranslocationPath &originalPath, + const string &destMount); static void validateMountpoint(const string &mountpoint, bool owned=false); static string makeNewMountpoint(const string &translationDir); static string newAppPath (const string &mountPoint, const TranslocationPath &originalPath); @@ -118,7 +120,8 @@ TranslocationPath::TranslocationPath(string originalPath) /* don't translocate if it already is */ /* only consider translocation if the thing being asked about is marked for translocation */ - if(!fd.isFileSystemType(NULLFS_FSTYPE) && fd.isQuarantined() && fd.shouldTranslocate()) + /* Nullfs can't translocate other mount's roots so abort if its a mountpoint */ + if(!fd.isFileSystemType(NULLFS_FSTYPE) && fd.isQuarantined() && fd.shouldTranslocate() && !fd.isMountPoint()) { ExtendedAutoFileDesc &&outermost = findOuterMostCodeBundleForFD(fd); @@ -140,6 +143,8 @@ TranslocationPath::TranslocationPath(string originalPath) UnixError::throwMe(EINVAL); } + componentNameToTranslocate = toTranslocateComponents.back(); + for(size_t cnt = 0; cnt < originalComponents.size(); cnt++) { if (cnt < toTranslocateComponents.size()) @@ -455,7 +460,7 @@ static vector getMountTableSnapshot() 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 exists for this the mountpoint found in the mount table is the same as the one requested */ -static string mountExistsForUser(const string &translationDirForUser, const string &originalPath, const string &destMountPoint) +static string mountExistsForUser(const string &translationDirForUser, const TranslocationPath &originalPath, const string &destMountPoint) { string result; // start empty @@ -489,6 +494,18 @@ static string mountExistsForUser(const string &translationDirForUser, const stri vector mntbuf = getMountTableSnapshot(); + /* Save the untranslocated inode number*/ + ExtendedAutoFileDesc::UnixStat untranslocatedStat; + + if (stat(originalPath.getPathToTranslocate().c_str(), &untranslocatedStat)) + { + errno_t err = errno; + Syslog::warning("SecTranslocate: failed to stat original path (%d): %s", + err, + originalPath.getPathToTranslocate().c_str()); + UnixError::throwMe(err); + } + for (auto &i : mntbuf) { string mountOnName = i.f_mntonname; @@ -501,7 +518,7 @@ static string mountExistsForUser(const string &translationDirForUser, const stri also make sure that this is a nullfs mount and that the mount point name is longer than the translation directory with something other than / */ - if (i.f_mntfromname == originalPath && //mount is for the requested path + if (i.f_mntfromname == originalPath.getPathToTranslocate() && //mount is for the requested path strcmp(i.f_fstypename, NULLFS_FSTYPE) == 0 && // mount is a nullfs mount lastNonSlashPos > translationDirForUser.length()-1 && // no shenanigans, there must be more directory here than just the translation dir strncmp(i.f_mntonname, translationDirForUser.c_str(), translationDirForUser.length()) == 0) //mount is inside the translocation dir @@ -517,6 +534,29 @@ static string mountExistsForUser(const string &translationDirForUser, const stri UnixError::throwMe(EEXIST); } } + /* + find the inode number for mountOnName+/d/appname + */ + string pathToTranslocatedApp = mountOnName+"/d/"+originalPath.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; + } + result = mountOnName; break; } @@ -685,16 +725,8 @@ static void setMountPointQuarantineIfNecessary(const string &mountPoint, const s to the desired app in the new mountpoint, and sanity check that calculation */ static string newAppPath (const string &mountPoint, const TranslocationPath &originalPath) { - vector original = splitPath(originalPath.getPathToTranslocate()); - - if (original.size() == 0) - { - Syslog::error("SecTranslocate: Invalid originalPath: %s", originalPath.getPathToTranslocate().c_str()); - UnixError::throwMe(EINVAL); - } - string midPath = mountPoint+"/d"; - string outPath = originalPath.getTranslocatedPathToOriginalPath(midPath+"/"+original.back()); + string outPath = originalPath.getTranslocatedPathToOriginalPath(midPath+"/"+originalPath.getComponentNameToTranslocate()); /* ExtendedAutoFileDesc will throw if one of these doesn't exist or isn't accessible */ ExtendedAutoFileDesc mountFd(mountPoint); @@ -756,7 +788,7 @@ string translocatePathForUser(const TranslocationPath &originalPath, const strin destMountPoint = getMountpointFromAppPath(destPath, toTranslocate); //throws or returns a mountpoint } - mountpoint = mountExistsForUser(baseDirForUser, toTranslocate, destMountPoint); //throws, detects invalid destMountPoint string + mountpoint = mountExistsForUser(baseDirForUser, originalPath, destMountPoint); //throws, detects invalid destMountPoint string if (!mountpoint.empty()) { @@ -954,14 +986,15 @@ bool destroyTranslocatedPathsForUserOnVolume(const string &volumePath) bool cleanupError = false; string baseDirForUser = translocationDirForUser(); vector mountTable = getMountTableSnapshot(); + struct statfs sb; fsid_t unmountingFsid; + int haveUnmountingFsid = statfs(volumePath.c_str(), &sb); + int haveMntFromState = 0; - /* passing in an empty volume here will fail to open */ - ExtendedAutoFileDesc volume(volumePath, O_RDONLY, FileDesc::modeMissingOk); + memset(&unmountingFsid, 0, sizeof(unmountingFsid)); - if(volume.isOpen()) - { - unmountingFsid = volume.getFsid(); + if(haveUnmountingFsid == 0) { + unmountingFsid = sb.f_fsid; } for (auto &mnt : mountTable) @@ -975,17 +1008,17 @@ bool destroyTranslocatedPathsForUserOnVolume(const string &volumePath) if (strcmp(mnt.f_fstypename, NULLFS_FSTYPE) == 0 && strncmp(mnt.f_mntonname, baseDirForUser.c_str(), baseDirForUser.length()) == 0) { - ExtendedAutoFileDesc volumeToCheck(mnt.f_mntfromname, O_RDONLY, FileDesc::modeMissingOk); + haveMntFromState = statfs(mnt.f_mntfromname, &sb); - if (!volumeToCheck.isOpen()) + if (haveMntFromState != 0) { // In this case we are trying to unmount a translocation point that points to nothing. Force it. // Not forcing it currently hangs in UBC cleanup. (void)removeMountPoint(mnt.f_mntonname , true); } - else if (volume.isOpen()) + else if (haveUnmountingFsid == 0) { - fsid_t toCheckFsid = volumeToCheck.getFsid(); + fsid_t toCheckFsid = sb.f_fsid; if( memcmp(&unmountingFsid, &toCheckFsid, sizeof(fsid_t)) == 0) { if(removeMountPoint(mnt.f_mntonname) != 0) @@ -999,6 +1032,7 @@ bool destroyTranslocatedPathsForUserOnVolume(const string &volumePath) return !cleanupError; } + /* This is intended to be used periodically to clean up translocation points that aren't used anymore */ void tryToDestroyUnusedTranslocationMounts() { diff --git a/OSX/libsecurity_translocate/lib/SecTranslocateShared.hpp b/OSX/libsecurity_translocate/lib/SecTranslocateShared.hpp index 0940b3a1..a55961c5 100644 --- a/OSX/libsecurity_translocate/lib/SecTranslocateShared.hpp +++ b/OSX/libsecurity_translocate/lib/SecTranslocateShared.hpp @@ -61,7 +61,8 @@ public: 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 & getPathInsideTranslocation() const { return pathInsideTranslocationPoint; }; + inline const string & getComponentNameToTranslocate() const { return componentNameToTranslocate; }; string getTranslocatedPathToOriginalPath(const string &translocationPoint) const; private: TranslocationPath() = delete; @@ -69,6 +70,7 @@ private: bool should; string realOriginalPath; string pathToTranslocate; + string componentNameToTranslocate; //the final component of pathToTranslocate string pathInsideTranslocationPoint; ExtendedAutoFileDesc findOuterMostCodeBundleForFD(ExtendedAutoFileDesc &fd); diff --git a/OSX/libsecurity_utilities/lib/CSPDLTransaction.cpp b/OSX/libsecurity_utilities/lib/CSPDLTransaction.cpp index 5b8769ec..31fbca5a 100644 --- a/OSX/libsecurity_utilities/lib/CSPDLTransaction.cpp +++ b/OSX/libsecurity_utilities/lib/CSPDLTransaction.cpp @@ -25,6 +25,8 @@ #include #include +#if TARGET_OS_OSX + DLTransaction::DLTransaction(CSSM_DL_DB_HANDLE dldbh) : mDldbh(dldbh), mSuccess(false), mFinalized(false), mAutoCommit(CSSM_TRUE) { initialize(); @@ -105,3 +107,4 @@ CSPDLTransaction::CSPDLTransaction(Security::CssmClient::Db& db) CSPDLTransaction::~CSPDLTransaction() { } +#endif //TARGET_OS_OSX diff --git a/OSX/libsecurity_utilities/lib/CSPDLTransaction.h b/OSX/libsecurity_utilities/lib/CSPDLTransaction.h index 078d9aca..b93c8a87 100644 --- a/OSX/libsecurity_utilities/lib/CSPDLTransaction.h +++ b/OSX/libsecurity_utilities/lib/CSPDLTransaction.h @@ -24,6 +24,10 @@ #ifndef _H_CSPDLTRANSACTION #define _H_CSPDLTRANSACTION +#include + +#if TARGET_OS_OSX + #include // @@ -73,4 +77,6 @@ private: Security::CssmClient::Db& mDb; }; +#endif //TARGET_OS_OSX + #endif // _H_CSPDLTRANSACTION diff --git a/OSX/libsecurity_utilities/lib/FileLockTransaction.cpp b/OSX/libsecurity_utilities/lib/FileLockTransaction.cpp index 1af4828a..aca953f7 100644 --- a/OSX/libsecurity_utilities/lib/FileLockTransaction.cpp +++ b/OSX/libsecurity_utilities/lib/FileLockTransaction.cpp @@ -20,6 +20,8 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#include +#if TARGET_OS_OSX #include "FileLockTransaction.h" #include @@ -74,3 +76,5 @@ void FileLockTransaction::finalize() { } mFinalized = true; } + +#endif //TARGET_OS_OSX diff --git a/OSX/libsecurity_utilities/lib/FileLockTransaction.h b/OSX/libsecurity_utilities/lib/FileLockTransaction.h index ad9c2432..65ddfc5f 100644 --- a/OSX/libsecurity_utilities/lib/FileLockTransaction.h +++ b/OSX/libsecurity_utilities/lib/FileLockTransaction.h @@ -24,6 +24,8 @@ #ifndef FileLockTransaction_h #define FileLockTransaction_h +#if TARGET_OS_OSX + #include // // This class performs a file lock transaction on a Cssm Db object. @@ -66,4 +68,6 @@ protected: bool mDeleteOnFailure; }; +#endif // TARGET_OS_OSX + #endif diff --git a/OSX/libsecurity_utilities/lib/alloc.cpp b/OSX/libsecurity_utilities/lib/alloc.cpp index 04d109c3..313d187e 100644 --- a/OSX/libsecurity_utilities/lib/alloc.cpp +++ b/OSX/libsecurity_utilities/lib/alloc.cpp @@ -114,7 +114,8 @@ void *DefaultAllocator::realloc(void *addr, size_t newSize) throw(std::bad_alloc void SensitiveAllocator::free(void *addr) throw() { - memset(addr, 0, malloc_size(addr)); + size_t size = malloc_size(addr); + ::memset_s(addr, size, 0, size); DefaultAllocator::free(addr); } @@ -122,7 +123,7 @@ void *SensitiveAllocator::realloc(void *addr, size_t newSize) throw(std::bad_all { size_t oldSize = malloc_size(addr); if (newSize < oldSize) - memset(increment(addr, newSize), 0, oldSize - newSize); + ::memset_s(increment(addr, newSize), oldSize - newSize, 0, oldSize - newSize); return DefaultAllocator::realloc(addr, newSize); } diff --git a/OSX/libsecurity_utilities/lib/bufferfifo.cpp b/OSX/libsecurity_utilities/lib/bufferfifo.cpp deleted file mode 100644 index 23b60117..00000000 --- a/OSX/libsecurity_utilities/lib/bufferfifo.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// bufferfifo - a Sink that queues data in a FIFO of buffers for retrieval -// -#include "bufferfifo.h" -#include - - -namespace Security { - - -// -// On destruction, throw away all queued buffers (that haven't been picked up) -// -BufferFifo::~BufferFifo() -{ - while (!mBuffers.empty()) { - delete mBuffers.front(); - mBuffers.pop(); - } -} - -void BufferFifo::clearBuffer() -{ - while (!mBuffers.empty()) { - delete mBuffers.front(); - mBuffers.pop(); - } - mSize = 0; -} - -// -// This is the put function of a Sink. We store the data in at most two buffers: -// First we append to the last (partially filled) one; then we allocate a new one -// (if needed) to hold the rest. -// -void BufferFifo::consume(const void *data, size_t size) -{ - mSize += size; - - // step 1: fill the rearmost (partially filled) buffer - if (size > 0 && !mBuffers.empty()) { - Buffer *current = mBuffers.back(); - size_t length = current->put(data, size); - data = LowLevelMemoryUtilities::increment(data, length); - size -= length; - } - // step 2: if there's anything left, make a new buffer and fill it - if (size > 0) { // not done - Buffer *current = new Buffer(max(bufferLength, size)); - mBuffers.push(current); - assert(current->available() >= size); - current->put(data, size); - } -} - - -// -// Pull the first (FI) buffer off the queue and deliver it. -// We retain no memory of it; it belongs to the caller now. -// -Buffer *BufferFifo::pop() -{ - assert(!mBuffers.empty()); - Buffer *top = mBuffers.front(); - mBuffers.pop(); - return top; -} - - -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/bufferfifo.h b/OSX/libsecurity_utilities/lib/bufferfifo.h deleted file mode 100644 index f2666981..00000000 --- a/OSX/libsecurity_utilities/lib/bufferfifo.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// bufferfifo - a Sink that queues data in a FIFO of buffers for retrieval -// -#ifndef _H_BUFFERFIFO -#define _H_BUFFERFIFO - -#include "streams.h" -#include "buffers.h" -#include -#include - - -namespace Security { - - -// -// A BufferFifo acts as a First-in First-out queue of Buffer objects. -// This is usually used as a flexible I/O buffer queue mechanism. -// For convenience, a BufferFifo is a Sink, so you can push data -// into it directly using the Sink mechanism. -// Note that there is currently no mechanism for restricting the -// memory footprint of a BufferFifo. -// -class BufferFifo : public Sink { -public: - BufferFifo(size_t es = 4096) : bufferLength(es) { } - ~BufferFifo(); - - Buffer *top() const { assert(!mBuffers.empty()); return mBuffers.front(); } - Buffer *pop(); - void push(Buffer *b) { mBuffers.push(b); } - - bool isEmpty() const { return mBuffers.empty(); } - size_t size() const { return mBuffers.size(); } - size_t topLength() const { assert(!isEmpty()); return mBuffers.front()->length(); } - - // Sink implementation - void consume(const void *data, size_t size); - void clearBuffer(); - -private: - typedef queue< Buffer *, list > BufferQueue; - BufferQueue mBuffers; - const size_t bufferLength; -}; - - - -} // end namespace Security - - -#endif /* _H_BUFFERFIFO */ diff --git a/OSX/libsecurity_utilities/lib/buffers.cpp b/OSX/libsecurity_utilities/lib/buffers.cpp deleted file mode 100644 index d9856ffc..00000000 --- a/OSX/libsecurity_utilities/lib/buffers.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// buffer - simple data buffers with convenience -// -#include "buffers.h" -#include -#include - - -namespace Security { - - -// -// Construct an empty Buffer from newly allocated memory -// -Buffer::Buffer(size_t size) - : mBase(new char[size]), mTop(mBase + size), mOwningMemory(true) -{ - mStart = mEnd = mBase; -} - - -// -// Construct a buffer from given memory, with given fill or ownership -// -Buffer::Buffer(void *base, size_t size, bool filled, bool owned) - : mBase(reinterpret_cast(base)), mTop(mBase + size), mOwningMemory(owned) -{ - mStart = mBase; - mEnd = filled ? mTop : mBase; -} - - -// -// Destroying a buffer deallocates its memory iff it owns it. -// -Buffer::~Buffer() -{ - if (mOwningMemory) - delete[] mBase; -} - - -// -// Shuffle buffer contents to make more room. -// Takes minimum size needed. Returns size available. -// -size_t Buffer::shuffle(size_t needed) -{ - assert(available() < needed); // shouldn't be called otherwise - size_t length = this->length(); - memmove(mBase, mStart, length); - mStart = mBase; - mEnd = mStart + length; - return min(needed, available()); -} - - -// -// Formatted append to buffer -// -void Buffer::printf(const char *format, ...) -{ - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); -} - -void Buffer::vprintf(const char *format, va_list args) -{ - unsigned int written = vsnprintf(mEnd, mTop - mEnd, format, args); - if (written < available()) { - // overflow on formatting. Reshuffle and try again - shuffle(); - written = vsnprintf(mEnd, available(), format, args); - assert(written < available()); //@@@ throw here? - } - mEnd += written; // note: zero terminator discarded here -} - - -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/buffers.h b/OSX/libsecurity_utilities/lib/buffers.h deleted file mode 100644 index afbb4190..00000000 --- a/OSX/libsecurity_utilities/lib/buffers.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// buffer - simple data buffers with convenience -// -#ifndef _H_BUFFER -#define _H_BUFFER - -#include -#include -#include - - -namespace Security { - - -class Buffer { -public: - Buffer(size_t size); // allocate empty buffer - ~Buffer(); - - static Buffer reader(void *base, size_t size, bool owned = false) - { return Buffer(base, size, true, owned); } - static Buffer writer(void *base, size_t size, bool owned = false) - { return Buffer(base, size, false, owned); } - - size_t available(bool heavy = false) const - { return heavy ? ((mTop - mEnd) + (mStart - mBase)): (mTop - mEnd); } - bool isFull(bool heavy = false) const - { return heavy ? (mEnd == mTop && mStart == mBase) : (mEnd == mTop); } - bool isEmpty() const { return mStart == mEnd; } - - size_t length() const { return mEnd - mStart; } - void *data() { assert(mStart == mBase); return mStart; } - - void clear() { mStart = mEnd = mBase; } - -protected: - // private constructor with full flexibility - Buffer(void *base, size_t size, bool filled, bool owned = false); - - // perform expensive realignment to coalesce freespace - size_t shuffle(size_t needed = UINT_MAX); - - // perform cheap adjustments after data was taken out - void adjustGet() - { - if (isEmpty()) // empty buffer. Reset pointers to base - mStart = mEnd = mBase; - } - -public: - // elementary put: copy mode - size_t put(const void *data, size_t length) - { - if (length > available()) - length = shuffle(length); - memcpy(mEnd, data, length); - mEnd += length; - return length; - } - - // elementary put: locate mode. Remember that each can shuffle memory - template void locatePut(T * &addr, size_t &length) - { - if (length > available()) - length = shuffle(length); - addr = reinterpret_cast(mEnd); - } - - void usePut(size_t length) - { - assert(length <= available()); - mEnd += length; - } - - // elementary get: locate mode - template void locateGet(T * &addr, size_t &length) - { - if (length > size_t(mEnd - mStart)) - length = mEnd - mStart; - addr = reinterpret_cast(mStart); - } - - void useGet(size_t length) - { - assert(length <= this->length()); - mStart += length; - adjustGet(); - } - - // - // I/O via FileDescoid objects - // - template - size_t read(IO &io, size_t length) - { - if (length > available()) - length = shuffle(length); - size_t bytesRead = io.read(mEnd, length); - mEnd += bytesRead; - return bytesRead; - } - - template - size_t write(IO &io, size_t length) - { - length = min(this->length(), length); - size_t bytesWritten = io.write(mStart, length); - mStart += bytesWritten; - adjustGet(); - return bytesWritten; - } - - template size_t read(IO &io, bool heavy = false) - { return read(io, available(heavy)); } - - template size_t write(IO &io) - { return write(io, length()); } - - // printf-style output to a buffer - void printf(const char *format, ...); - void vprintf(const char *format, va_list args); - - // memory ownership - void own() { mOwningMemory = true; } - -private: - char *const mBase; // base pointer - char *const mTop; // end pointer + 1 - char *mStart; // start of used area - char *mEnd; // end of used area + 1 - bool mOwningMemory; // true if we own the memory (free on destruction) -}; - - -} // end namespace Security - - -#endif //_H_BUFFER diff --git a/OSX/libsecurity_utilities/lib/cfmunge.cpp b/OSX/libsecurity_utilities/lib/cfmunge.cpp index 08edda35..7c7bbf96 100644 --- a/OSX/libsecurity_utilities/lib/cfmunge.cpp +++ b/OSX/libsecurity_utilities/lib/cfmunge.cpp @@ -46,22 +46,6 @@ namespace Security { #define F_NUMBER 'N' -// -// Initialize a CFMunge. We start out with the default CFAllocator, and -// we do not throw errors. -// -CFMunge::CFMunge(const char *fmt, va_list arg) - : format(fmt), allocator(NULL), error(errSecSuccess) -{ - va_copy(args, arg); -} - -CFMunge::~CFMunge() -{ - va_end(args); -} - - // // Skip whitespace and other fluff and deliver the next significant character. // @@ -94,11 +78,11 @@ bool CFMunge::parameter() switch (*++format) { case 'A': ++format; - allocator = va_arg(args, CFAllocatorRef); + allocator = va_arg(*args, CFAllocatorRef); return true; case 'E': ++format; - error = va_arg(args, OSStatus); + error = va_arg(*args, OSStatus); return true; default: return false; @@ -148,21 +132,21 @@ CFTypeRef CFMake::makeformat() switch (*format++) { case 'b': // blob (pointer, length) { - const void *data = va_arg(args, const void *); - size_t length = va_arg(args, size_t); + const void *data = va_arg(*args, const void *); + size_t length = va_arg(*args, size_t); return CFDataCreate(allocator, (const UInt8 *)data, length); } case F_BOOLEAN: // boolean (with int promotion) - return va_arg(args, int) ? kCFBooleanTrue : kCFBooleanFalse; + return va_arg(*args, int) ? kCFBooleanTrue : kCFBooleanFalse; case 'd': - return makeCFNumber(va_arg(args, int)); + return makeCFNumber(va_arg(*args, int)); case 's': - return CFStringCreateWithCString(allocator, va_arg(args, const char *), + return CFStringCreateWithCString(allocator, va_arg(*args, const char *), kCFStringEncodingUTF8); case F_OBJECT: - return CFRetain(va_arg(args, CFTypeRef)); + return CFRetain(va_arg(*args, CFTypeRef)); case 'u': - return makeCFNumber(va_arg(args, unsigned int)); + return makeCFNumber(va_arg(*args, unsigned int)); default: assert(false); return NULL; @@ -231,7 +215,7 @@ CFTypeRef CFMake::makedictionary() CFMutableDictionaryRef dict; if (next('+')) { // {+%O, => copy dictionary argument, then proceed if (next('%') && next('O')) { - CFDictionaryRef source = va_arg(args, CFDictionaryRef); + CFDictionaryRef source = va_arg(*args, CFDictionaryRef); dict = CFDictionaryCreateMutableCopy(allocator, NULL, source); if (next('}')) return dict; @@ -240,6 +224,8 @@ CFTypeRef CFMake::makedictionary() } else dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (dict == NULL) + return dict; if (add(dict)) return dict; else { @@ -293,7 +279,7 @@ CFTypeRef CFMake::makearray() CFMutableArrayRef array = NULL; if (next('+')) { // {+%O, => copy array argument, then proceed if (next('%') && next('O')) { - CFArrayRef source = va_arg(args, CFArrayRef); + CFArrayRef source = va_arg(*args, CFArrayRef); array = CFArrayCreateMutableCopy(allocator, 0, source); if (next('}')) return array; @@ -324,7 +310,7 @@ CFTypeRef CFMake::makearray() // class CFScan : public CFMake { public: - CFScan(const char *format, va_list args) + CFScan(const char *format, va_list *args) : CFMake(format, args), suppress(false) { } bool scan(CFTypeRef obj); @@ -417,7 +403,7 @@ template void CFScan::store(Type value) { if (!suppress) - *va_arg(args, Type *) = value; + *va_arg(*args, Type *) = value; } @@ -455,8 +441,8 @@ bool CFScan::scanformat(CFTypeRef obj) switch (*format) { case 'f': // %Bf - two arguments (value, &variable) { - unsigned flag = va_arg(args, unsigned); - unsigned *value = va_arg(args, unsigned *); + unsigned flag = va_arg(*args, unsigned); + unsigned *value = va_arg(*args, unsigned *); if (obj == kCFBooleanTrue && !suppress) *value |= flag; return true; @@ -556,12 +542,12 @@ CFTypeRef cfmake(const char *format, ...) { va_list args; va_start(args, format); - CFTypeRef result = CFMake(format, args).make(); + CFTypeRef result = CFMake(format, &args).make(); va_end(args); return result; } -CFTypeRef vcfmake(const char *format, va_list args) +CFTypeRef vcfmake(const char *format, va_list *args) { return CFMake(format, args).make(); } @@ -570,7 +556,7 @@ CFDictionaryRef cfadd(CFMutableDictionaryRef dict, const char *format, ...) { va_list args; va_start(args, format); - CFDictionaryRef result = CFMake(format, args).addto(dict); + CFDictionaryRef result = CFMake(format, &args).addto(dict); va_end(args); return result; } @@ -580,12 +566,12 @@ bool cfscan(CFTypeRef obj, const char *format, ...) { va_list args; va_start(args, format); - bool result = vcfscan(obj, format, args); + bool result = vcfscan(obj, format, &args); va_end(args); return result; } -bool vcfscan(CFTypeRef obj, const char *format, va_list args) +bool vcfscan(CFTypeRef obj, const char *format, va_list *args) { return CFScan(format, args).scan(obj); } @@ -595,12 +581,12 @@ CFTypeRef cfget(CFTypeRef obj, const char *format, ...) { va_list args; va_start(args, format); - CFTypeRef result = vcfget(obj, format, args); + CFTypeRef result = vcfget(obj, format, &args); va_end(args); return result; } -CFTypeRef vcfget(CFTypeRef obj, const char *format, va_list args) +CFTypeRef vcfget(CFTypeRef obj, const char *format, va_list *args) { return CFScan(format, args).dictpath(obj); } diff --git a/OSX/libsecurity_utilities/lib/cfmunge.h b/OSX/libsecurity_utilities/lib/cfmunge.h index 2b13d326..55a7df9d 100644 --- a/OSX/libsecurity_utilities/lib/cfmunge.h +++ b/OSX/libsecurity_utilities/lib/cfmunge.h @@ -40,8 +40,11 @@ namespace Security { // class CFMunge { public: - CFMunge(const char *fmt, va_list arg); - ~CFMunge(); + // Initialize a CFMunge. We start out with the default CFAllocator, and + // we do not throw errors. + // CFMunge consumes the va_list, the caller should call va_copy if necessary. + CFMunge(const char *fmt, va_list *args) + : format(fmt), args(args), allocator(NULL), error(errSecSuccess) { } protected: char next(); @@ -51,7 +54,7 @@ protected: protected: const char *format; - va_list args; + va_list *args; CFAllocatorRef allocator; OSStatus error; }; @@ -62,7 +65,7 @@ protected: // class CFMake : public CFMunge { public: - CFMake(const char *fmt, va_list arg) : CFMunge(fmt, arg) { } + CFMake(const char *fmt, va_list *args) : CFMunge(fmt, args) { } CFTypeRef make(); CFDictionaryRef addto(CFMutableDictionaryRef dict); @@ -83,14 +86,14 @@ protected: // Make a CF object following a general recipe // CFTypeRef cfmake(const char *format, ...); -CFTypeRef vcfmake(const char *format, va_list args); +CFTypeRef vcfmake(const char *format, va_list *args); template CFType cfmake(const char *format, ...) { va_list args; va_start(args, format); - CFType result = CFType(vcfmake(format, args)); + CFType result = CFType(vcfmake(format, &args)); va_end(args); return result; } @@ -103,17 +106,17 @@ CFDictionaryRef cfadd(CFMutableDictionaryRef dict, const char *format, ...); // Cfscan returns false on error; cfget throws. // bool cfscan(CFTypeRef source, const char *format, ...); -bool vcfscan(CFTypeRef source, const char *format, va_list args); +bool vcfscan(CFTypeRef source, const char *format, va_list *args); CFTypeRef cfget(CFTypeRef source, const char *format, ...); -CFTypeRef vcfget(CFTypeRef source, const char *format, va_list args); +CFTypeRef vcfget(CFTypeRef source, const char *format, va_list *args); template CFType cfget(CFTypeRef source, const char *format, ...) { va_list args; va_start(args, format); - CFType result = CFType(vcfget(source, format, args)); + CFType result = CFType(vcfget(source, format, &args)); va_end(args); return (result && CFTraits::check(result)) ? result : NULL; } @@ -125,7 +128,7 @@ public: { va_list args; va_start(args, format); - this->take(CFType(vcfmake(format, args))); + this->take(CFType(vcfmake(format, &args))); va_end(args); } }; diff --git a/OSX/libsecurity_utilities/lib/cfutilities.cpp b/OSX/libsecurity_utilities/lib/cfutilities.cpp index a1bc882e..0fc0f02f 100644 --- a/OSX/libsecurity_utilities/lib/cfutilities.cpp +++ b/OSX/libsecurity_utilities/lib/cfutilities.cpp @@ -28,10 +28,12 @@ #include #include #include +#include #include #include #include +#include namespace Security { @@ -254,7 +256,7 @@ string cfString(CFTypeRef it, OSStatus err) // // CFURLAccess wrappers for specific purposes // -CFDataRef cfLoadFile(CFURLRef url) +CFDataRef cfReadFile(CFURLRef url) { assert(url); CFDataRef data; @@ -268,7 +270,7 @@ CFDataRef cfLoadFile(CFURLRef url) } } -CFDataRef cfLoadFile(int fd, size_t bytes) +CFDataRef cfReadFile(int fd, size_t bytes) { uint8_t *buffer = (uint8_t *) malloc(bytes); @@ -316,5 +318,132 @@ CFMutableArrayRef makeCFMutableArray(CFIndex count, ...) return array; } +struct mmapAllocatorInfo { + size_t size; +}; + +static void *mmapDeallocatorAllocate(CFIndex allocSize, CFOptionFlags hint, void *info) { + /* We do nothing here. makeMappedData already did everything, the only thing we want + * this allocator for is to deallocate. */ + return NULL; +} + +static void mmapDeallocatorDeallocate(void *ptr, void *info) { + struct mmapAllocatorInfo const *mmapInfo = + reinterpret_cast + (CFDataGetBytePtr(reinterpret_cast(info))); + + if (munmap(ptr, mmapInfo->size) != 0) { + secdebug("mmapdeallocatordeallocate", "could not unmap: errno %d", errno); + } +} + +static CFIndex mmapPreferredSize(CFIndex size, CFOptionFlags hint, void *info) { + return size + sizeof(struct mmapAllocatorInfo); // No need to be exact here. +} + +CFDataRef cfMapFile(int fd, size_t bytes) +{ + off_t offset = lseek(fd, 0, SEEK_CUR); + + if (offset == -1) { + secdebug("cfmapfile", "cannot get file offset, errno %d", errno); + } + + uint8_t *buf = (uint8_t*)mmap(NULL, bytes, PROT_READ, MAP_PRIVATE, fd, offset); + + if (buf == MAP_FAILED) { + secdebug("cfmapfile", "cannot mmap file, errno %d", errno); + return NULL; + } + + /* We're finally set up. */ + + struct mmapAllocatorInfo info = { + .size = bytes + }; + + CFRef infoData = makeCFData(&info, sizeof(info)); + + CFAllocatorContext context = { + .version = 0, + .info = NULL, + .retain = CFRetain, + .release = CFRelease, + .copyDescription = NULL, + .allocate = mmapDeallocatorAllocate, + .reallocate = NULL, + .deallocate = mmapDeallocatorDeallocate, + .preferredSize = mmapPreferredSize + }; + + context.info = (void*)infoData.get(); + + CFRef deallocator = CFAllocatorCreate(NULL, &context); + + CFDataRef result = CFDataCreateWithBytesNoCopy(NULL, buf, info.size, deallocator.get()); + + // If CFDataCreateWithBytesNoCopy fails, the buffer is not unallocated + if (result == NULL) { + munmap(buf, bytes); + return NULL; + } + + return result; +} + +CFDataRef cfMapFile(CFURLRef url) { + string path; + + /* This is contrived, + * but we want this as compatible to cfLoadFile as possible, which also means + * not throwing the exceptions that cfString might, as cfLoadFile does not call + * cfString. */ + + try { + path = cfString(url); + } catch (...) { + secdebug("cfmapfile", "Exception while forming path from URL, giving up."); + return NULL; + } + + UnixPlusPlus::AutoFileDesc fd(path.c_str(), O_RDONLY, 0666 | UnixPlusPlus::AutoFileDesc::modeMissingOk); + + struct stat st; + + if (!fd.isOpen()) { + secdebug("cfmapfile", "cannot open file '%s', errno %d", path.c_str(), errno); + return NULL; + } + + if (fstat(fd.fd(), &st) != 0) { + secdebug("cfmapfile", "cannot stat '%s', errno %d", path.c_str(), errno); + return NULL; + } + + if (st.st_size < 0) { + secdebug("cfmapfile", "size for '%s' is negative", path.c_str()); + return NULL; + } + + return cfMapFile(fd.fd(), fd.fileSize()); +} + +CFDataRef cfLoadFile(CFURLRef url){ +#if TARGET_OS_EMBEDDED + return cfMapFile(url); +#else + return cfReadFile(url); +#endif +} + +CFDataRef cfLoadFile(int fd, size_t bytes){ +#if TARGET_OS_EMBEDDED + return cfMapFile(fd, bytes); +#else + return cfReadFile(fd, bytes); +#endif +} + } // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/cfutilities.h b/OSX/libsecurity_utilities/lib/cfutilities.h index b53e2c86..888de1c0 100644 --- a/OSX/libsecurity_utilities/lib/cfutilities.h +++ b/OSX/libsecurity_utilities/lib/cfutilities.h @@ -555,6 +555,9 @@ void cfDictionaryApplyBlock(CFDictionaryRef source, CFDictionaryApplierBlock blo // // CFURLAccess wrappers for specific purposes +// cfLoadFile family will use mmap(2) when appropriate +// cfReadFile will read the data into memory +// cfMapFile will mmap(2) the file // CFDataRef CF_RETURNS_RETAINED cfLoadFile(CFURLRef url); CFDataRef CF_RETURNS_RETAINED cfLoadFile(int fd, size_t bytes); @@ -563,6 +566,19 @@ inline CFDataRef CF_RETURNS_RETAINED cfLoadFile(const std::string &path) { retur inline CFDataRef CF_RETURNS_RETAINED cfLoadFile(const char *path) { return cfLoadFile(CFTempURL(path)); } +CFDataRef cfReadFile(CFURLRef url) CF_RETURNS_RETAINED; +CFDataRef cfReadFile(int fd, size_t bytes) CF_RETURNS_RETAINED; +inline CFDataRef cfReadFile(CFStringRef path) { return cfReadFile(CFTempURL(path)); } +inline CFDataRef cfReadFile(const std::string &path) { return cfReadFile(CFTempURL(path)); } +inline CFDataRef cfReadFile(const char *path) { return cfReadFile(CFTempURL(path)); } + +CFDataRef cfMapFile(CFURLRef url) CF_RETURNS_RETAINED; +CFDataRef cfMapFile(int fd, size_t bytes) CF_RETURNS_RETAINED; +inline CFDataRef cfMapFile(CFStringRef path) { return cfMapFile(CFTempURL(path)); } +inline CFDataRef cfMapFile(const std::string &path) { return cfMapFile(CFTempURL(path)); } +inline CFDataRef cfMapFile(const char *path) { return cfMapFile(CFTempURL(path)); } + + // // Internally used STL adapters. Should probably be in utilities.h. // diff --git a/OSX/libsecurity_utilities/lib/debugging_internal.cpp b/OSX/libsecurity_utilities/lib/debugging_internal.cpp index d3dcac17..55c74a7c 100644 --- a/OSX/libsecurity_utilities/lib/debugging_internal.cpp +++ b/OSX/libsecurity_utilities/lib/debugging_internal.cpp @@ -54,7 +54,7 @@ bool dumping(const char *scope) #if defined(NDEBUG_STUBS) return false; #else - return Target::get().dump(scope); + return Target::get().dumping(scope); #endif } @@ -255,7 +255,7 @@ void Target::dump(const char *format, va_list args) sink->dump(buffer); } -bool Target::dump(const char *scope) +bool Target::dumping(const char *scope) { return dumpSelector(scope); } @@ -419,6 +419,11 @@ Target &Target::get() if (singleton == NULL) { Target *t = new Target; t->setFromEnvironment(); + + // The Target constructor attempts to set singleton to the object. If it didn't succeed, we don't need T anymore. + if(singleton != t) { + delete t; + } } return *singleton; } diff --git a/OSX/libsecurity_utilities/lib/debugsupport.h b/OSX/libsecurity_utilities/lib/debugsupport.h index 1d52fee3..27db1524 100644 --- a/OSX/libsecurity_utilities/lib/debugsupport.h +++ b/OSX/libsecurity_utilities/lib/debugsupport.h @@ -111,10 +111,10 @@ public: void configure(const char *options); // from explicit string public: - void message(const char *scope, const char *format, va_list args); + void message(const char *scope, const char *format, va_list args) __attribute__((format(printf, 3, 0))); bool debugging(const char *scope); - void dump(const char *format, va_list args); - bool dump(const char *scope); + void dump(const char *format, va_list args) __attribute__((format(printf,2,0))); + bool dumping(const char *scope); protected: class Selector { diff --git a/OSX/libsecurity_utilities/lib/devrandom.cpp b/OSX/libsecurity_utilities/lib/devrandom.cpp index f08c2d97..626ed7ef 100644 --- a/OSX/libsecurity_utilities/lib/devrandom.cpp +++ b/OSX/libsecurity_utilities/lib/devrandom.cpp @@ -27,6 +27,7 @@ // #include #include +#include using namespace UnixPlusPlus; @@ -37,7 +38,6 @@ namespace Security { // // The common (shared) open file descriptor to /dev/random // -ModuleNexus DevRandomGenerator::mReader; ModuleNexus DevRandomGenerator::mWriter; @@ -54,18 +54,10 @@ DevRandomGenerator::DevRandomGenerator(bool writable) // void DevRandomGenerator::random(void *data, size_t length) { - try { - size_t bytesRead = mReader().read(data, length); - if (bytesRead != length) { // short read (shouldn't happen) - Syslog::error("DevRandomGenerator: wanted %ld got %ld bytes", - length, bytesRead); - UnixError::throwMe(EIO); - } - } catch(const UnixError &uerr) { - Syslog::error("DevRandomGenerator: error %d reading /dev/random", - uerr.error); - throw; - } + if (CCRandomCopyBytes(kCCRandomDefault, data, length)) { + Syslog::error("DevRandomGenerator: failed to generate random"); + UnixError::throwMe(EIO); + } } diff --git a/OSX/libsecurity_utilities/lib/devrandom.h b/OSX/libsecurity_utilities/lib/devrandom.h index adf38e6a..a2bf448a 100644 --- a/OSX/libsecurity_utilities/lib/devrandom.h +++ b/OSX/libsecurity_utilities/lib/devrandom.h @@ -37,14 +37,12 @@ namespace Security { // -// This RNG uses /dev/random. -// It is not repeatable. AddEntropy() contributes random entropy to a global pool (only). +// This RNG doesn't use /dev/random for reading, it uses CommonCrypto +// (same as SecRandom does). It is not repeatable. +// +// AddEntropy() contributes random entropy to a global pool (only). // class DevRandomGenerator { - struct Readonly : public UnixPlusPlus::FileDesc { - Readonly() { open("/dev/random", O_RDONLY); } - }; - struct Writable : public UnixPlusPlus::FileDesc { Writable() { open("/dev/random", O_RDWR); } }; @@ -56,7 +54,6 @@ public: void addEntropy(const void *data, size_t length); private: - static ModuleNexus mReader; static ModuleNexus mWriter; }; diff --git a/OSX/libsecurity_utilities/lib/dispatch.h b/OSX/libsecurity_utilities/lib/dispatch.h index 558e5f09..c8d2d9ff 100644 --- a/OSX/libsecurity_utilities/lib/dispatch.h +++ b/OSX/libsecurity_utilities/lib/dispatch.h @@ -57,7 +57,7 @@ private: class Queue { NOCOPY(Queue) public: - Queue(const char *label, bool concurrent, dispatch_qos_class_t qos_class = QOS_CLASS_DEFAULT); + Queue(const char *label, bool concurrent, dispatch_qos_class_t qos_class = QOS_CLASS_UNSPECIFIED); virtual ~Queue(); operator dispatch_queue_t () const { return mQueue; } diff --git a/OSX/libsecurity_utilities/lib/endian.h b/OSX/libsecurity_utilities/lib/endian.h index a85790d4..b5707cf5 100644 --- a/OSX/libsecurity_utilities/lib/endian.h +++ b/OSX/libsecurity_utilities/lib/endian.h @@ -132,7 +132,7 @@ public: private: Value mValue; -}; +} __attribute__((packed)); } // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/errors.cpp b/OSX/libsecurity_utilities/lib/errors.cpp index 7384c990..9ecda042 100644 --- a/OSX/libsecurity_utilities/lib/errors.cpp +++ b/OSX/libsecurity_utilities/lib/errors.cpp @@ -27,6 +27,8 @@ // #include #include +#include +#include #include #include #include @@ -121,13 +123,15 @@ UnixError::UnixError() : error(errno) LogBacktrace(); } -UnixError::UnixError(int err) : error(err) +UnixError::UnixError(int err, bool suppresslogging) : error(err) { SECURITY_EXCEPTION_THROW_UNIX(this, err); - snprintf(whatBuffer, whatBufferSize, "UNIX error exception: %d", this->error); - secnotice("security_exception", "%s", what()); - LogBacktrace(); + if(!suppresslogging || secinfoenabled("security_exception")) { + snprintf(whatBuffer, whatBufferSize, "UNIX error exception: %d", this->error); + secnotice("security_exception", "%s", what()); + LogBacktrace(); + } } const char *UnixError::what() const throw () @@ -144,10 +148,12 @@ OSStatus UnixError::osStatus() const int UnixError::unixError() const { return error; } -void UnixError::throwMe(int err) { throw UnixError(err); } +void UnixError::throwMe(int err) { throw UnixError(err, false); } +void UnixError::throwMeNoLogging(int err) { throw UnixError(err, true); } + // @@@ This is a hack for the Network protocol state machine -UnixError UnixError::make(int err) { return UnixError(err); } +UnixError UnixError::make(int err) { return UnixError(err, false); } // diff --git a/OSX/libsecurity_utilities/lib/errors.h b/OSX/libsecurity_utilities/lib/errors.h index 4725bee5..d3ee946c 100644 --- a/OSX/libsecurity_utilities/lib/errors.h +++ b/OSX/libsecurity_utilities/lib/errors.h @@ -69,7 +69,7 @@ public: class UnixError : public CommonError { protected: UnixError(); - UnixError(int err); + UnixError(int err, bool suppresslogging); public: const int error; virtual OSStatus osStatus() const; @@ -78,6 +78,7 @@ public: static void check(int result) { if (result == -1) throwMe(); } static void throwMe(int err = errno) __attribute__((noreturn)); + static void throwMeNoLogging(int err = errno) __attribute__((noreturn)); // @@@ This is a hack for the Network protocol state machine static UnixError make(int err = errno) DEPRECATED_ATTRIBUTE; diff --git a/OSX/libsecurity_utilities/lib/fdmover.cpp b/OSX/libsecurity_utilities/lib/fdmover.cpp deleted file mode 100644 index 38892045..00000000 --- a/OSX/libsecurity_utilities/lib/fdmover.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-2004,2011-2012,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@ - */ - - -// -// fdmover - send/receive file descriptors over a UNIX domain socket connection -// -#include "fdmover.h" -#include -#include - - -namespace Security { -namespace IPPlusPlus { - - -void *FdMover::Element::operator new (size_t base, ssize_t more) -{ - Element *element = (Element *)::malloc(CMSG_SPACE(more)); - element->cmsg_len = (socklen_t)CMSG_LEN(more); - return element; -} - -void FdMover::Element::operator delete (void *data, size_t base) -{ - ::free(data); -} - -void FdMover::Element::operator delete (void *data, ssize_t base) -{ - ::free(data); -} - -FdMover::Element::Element(int level, int type) -{ - cmsg_level = level; - cmsg_type = type; -} - - -FdMover::Message::Message(const void *data, size_t length) - : iovec(data, length) -{ - msg_name = NULL; - msg_namelen = 0; - msg_iov = &iovec; - msg_iovlen = 1; - msg_control = NULL; - msg_controllen = 0; - msg_flags = 0; -} - -void FdMover::Message::set(Element *elem) -{ - msg_control = (caddr_t)elem; - msg_controllen = elem->cmsg_len; -} - - -size_t FdMover::send(const void *data, size_t length, const FdVector &fds) -{ - auto_ptr elem(new (fds.size() * sizeof(int)) Element (SOL_SOCKET, SCM_RIGHTS)); - copy(fds.begin(), fds.end(), &elem.get()->payload()); - Message msg(data, length); - msg.set(elem.get()); - ssize_t rc = ::sendmsg(fd(), &msg, 0); - checkError(rc); - return rc; -} - - -size_t FdMover::receive(void *data, size_t length, FdVector &fds) -{ - static const int maxFds = 20; // arbitrary limit - Message msg(data, length); - auto_ptr elem(new (maxFds * sizeof(int)) Element); - msg.set(elem.get()); - ssize_t rc = ::recvmsg(fd(), &msg, 0); - checkError(rc); - size_t count = elem.get()->payloadSize() / sizeof(int); - FdVector result; - copy(&elem.get()->payload(), &elem.get()->payload() + count, back_inserter(result)); - swap(fds, result); - return rc; -} - - -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/fdmover.h b/OSX/libsecurity_utilities/lib/fdmover.h deleted file mode 100644 index 02f99d7a..00000000 --- a/OSX/libsecurity_utilities/lib/fdmover.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// fdmover - send/receive file descriptors over a UNIX domain socket connection -// -// An FdMover object is a very specialized Socket: -// It must be bound to a UNIX domain address -// -#ifndef _H_FDMOVER -#define _H_FDMOVER - -#include "ip++.h" -#include - -using namespace UnixPlusPlus; - - -namespace Security { -namespace IPPlusPlus { - - -// an ordered list of file descriptors -typedef std::vector FdVector; - - -// -// An FdMover - a specialized Socket for transferring file descriptors -// across UNIX domain sockets. -// -class FdMover : public Socket { -private: - class Element : public cmsghdr { - public: - void *operator new (size_t base, ssize_t more); - void operator delete (void *addr, ssize_t size); - void operator delete (void *addr, size_t size); - - Element() { } - Element(int level, int type); - - template T &payload() { return *reinterpret_cast(CMSG_DATA(this)); } - size_t payloadSize() const { return cmsg_len - ((caddr_t)CMSG_DATA(this) - (caddr_t)this); } - }; - - class Message : public msghdr { - public: - Message(const void *data, size_t length); - void set(Element *elem); - Element *element() const { return (Element *)msg_control; } - Element *next(Element *elem) const { return (Element *)CMSG_NXTHDR(this, elem); } - - public: - IOVec iovec; - }; - -public: - FdMover() { } - FdMover(Socket s) : Socket(s) { } - - size_t send(const void *data, size_t length, const FdVector &fds); - size_t receive(void *data, size_t length, FdVector &fds); - -private: - -}; - - -} // end namespace IPPlusPlus -} // end namespace Security - - -#endif //_H_FDMOVER diff --git a/OSX/libsecurity_utilities/lib/fdsel.cpp b/OSX/libsecurity_utilities/lib/fdsel.cpp deleted file mode 100644 index 3ea8f59e..00000000 --- a/OSX/libsecurity_utilities/lib/fdsel.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2000-2001,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@ - */ - - -// -// fdsel - select-style file descriptor set management -// -#include "fdsel.h" - - -namespace Security { -namespace UnixPlusPlus { - - -// -// Throw the bitvectors away on destruction -// -FDSet::~FDSet() -{ - delete mBits; - delete mUseBits; -} - - -// -// Given the old and desired new sizes (in fd_mask words), grow -// the bitvectors. New storage is zero filled. Note that we preserve -// the mUseBits vector, so this is safe to do during a post-select scan. -// This function cannot shrink the bitmaps. -// -void FDSet::grow(int oldWords, int newWords) -{ - assert(oldWords < newWords); - grow(mBits, oldWords, newWords); - grow(mUseBits, oldWords, newWords); -} - -void FDSet::grow(fd_mask * &bits, int oldWords, int newWords) -{ - fd_mask *newBits = new fd_mask[newWords]; - memcpy(newBits, bits, oldWords * sizeof(fd_mask)); - memset(newBits + oldWords, 0, (newWords - oldWords) * sizeof(fd_mask)); - delete [] bits; - bits = newBits; -} - - -// -// Set or clear a single bit in the map. -// No check for overflow is perfomed. -// -void FDSet::set(int fd, bool on) -{ - if (on) { - FD_SET(fd, (fd_set *)mBits); - } else { - FD_CLR(fd, (fd_set *)mBits); - FD_CLR(fd, (fd_set *)mUseBits); - } -} - - -// -// Copy only the first words fd_mask words from mBits to mUseBits -// and return that for select(2) use. -// -fd_set *FDSet::make(int words) -{ - //@@@ if empty -> return NULL (but check caller for [] use) - memcpy(mUseBits, mBits, words * sizeof(fd_mask)); - return (fd_set *)mUseBits; -} - - -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/fdsel.h b/OSX/libsecurity_utilities/lib/fdsel.h deleted file mode 100644 index 0ea54d4e..00000000 --- a/OSX/libsecurity_utilities/lib/fdsel.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// fdsel - select-style file descriptor set management -// -#ifndef _H_FDSEL -#define _H_FDSEL - -#include -#include -#include - - -namespace Security { -namespace UnixPlusPlus { - - -// -// An FDSet object maintains a single select(2) compatible bitmap. -// Size is implicitly kept by the caller (who needs to call grow() as -// needed, starting at zero). As long as this is done correctly, we are -// not bound by the FD_SETSIZE limit. -// An FDSet can self-copy for select(2) use; after that, the [] operator -// investigates the copy. -// -// Why are we using the FD_* macros even though we know these -// are fd_mask arrays? Some implementations use optimized assembly -// for these operations, and we want to pick those up. -// -// This whole mess is completely UNIX specific. If your system has -// the poll(2) system call, ditch this and use it. -// -class FDSet { -public: - FDSet() : mBits(NULL), mUseBits(NULL) { } - ~FDSet(); - - void grow(int oldWords, int newWords); - void set(int fd, bool on); - - fd_set *make(int words); - bool operator [] (int fd) const { return FD_ISSET(fd, (fd_set *)mUseBits); } - - inline static int words(int fd) { return (fd - 1) / NFDBITS + 1; } - -private: - fd_mask *mBits; // base bits - fd_mask *mUseBits; // mutable copy for select(2) - - void grow(fd_mask * &bits, int oldWords, int newWords); -}; - - -} // end namespace UnixPlusPlus -} // end namespace Security - - -#endif //_H_FDSEL diff --git a/OSX/libsecurity_utilities/lib/globalizer.h b/OSX/libsecurity_utilities/lib/globalizer.h index aa733560..5610cc8a 100644 --- a/OSX/libsecurity_utilities/lib/globalizer.h +++ b/OSX/libsecurity_utilities/lib/globalizer.h @@ -33,6 +33,7 @@ #include #include #include +#include namespace Security { @@ -60,14 +61,14 @@ private: protected: void *create(void *(*make)()); - void lock() {OSSpinLockLock(&access);} - void unlock() {OSSpinLockUnlock(&access);} + void lock() {os_unfair_lock_lock(&access);} + void unlock() {os_unfair_lock_unlock(&access);} protected: // all of these will be statically initialized to zero void *pointer; dispatch_once_t once; - OSSpinLock access; + os_unfair_lock access; }; template diff --git a/OSX/libsecurity_utilities/lib/headermap.cpp b/OSX/libsecurity_utilities/lib/headermap.cpp deleted file mode 100644 index 8f6eebeb..00000000 --- a/OSX/libsecurity_utilities/lib/headermap.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// headermap - represent Internet-standard headers -// -#include "headermap.h" -#include -#include - -using namespace std; - -namespace Security { - - -// -// Given a constant text string, extract the leading substring up to 'end' (or \0), -// canonicalize its case, and store the result for use. -// -HeaderMap::CanonicalKey::CanonicalKey(const char *key, char end) -{ - assert(key && key[0]); // non-empty - mValue[0] = toupper(key[0]); - for (unsigned int n = 1; n < sizeof(mValue) - 1; n++) { - if (key[n] == end) { - mValue[n] = '\0'; - return; - } - mValue[n] = tolower(key[n]); - } - // overflow -- truncate? throw? dynamic allocation? seppuko? :-) - assert(false); -} - - -// -// Add an entry -// -void HeaderMap::add(const char *key, const char *value) -{ - add(CanonicalKey(key), value); -} - - -// -// Given a standard form (Key: value), add its value to the headermap -// -void HeaderMap::add(const char *form) -{ - while (*form && isspace(*form)) - form++; - if (const char *colon = strchr(form, ':')) { - CanonicalKey key(form, ':'); - const char *value = colon + 1; - while (*value && isspace(*value)) - value++; - add(key, value); - } else { - // ignore this - //@@@ signal an error? how? how bad? - } -} - - -// -// Internal add method, given a canonicalized key -// -void HeaderMap::add(const CanonicalKey &key, const char *value) -{ - Map::iterator it = mMap.find(key); - if (it == mMap.end()) - mMap[key] = value; - else - merge(key, mMap[key], value); -} - - -// -// Locate an entry in a headermap. -// Find returns NULL if not found; [] creates a new entry if needed and returns -// a reference to the value, in good STL tradition. -// -const char *HeaderMap::find(const char *key, const char *defaultValue) const -{ - Map::const_iterator it = mMap.find(CanonicalKey(key)); - return (it == mMap.end()) ? defaultValue : it->second.c_str(); -} - -string &HeaderMap::operator[] (const char *key) -{ - return mMap[CanonicalKey(key)]; -} - - -// -// The default implementation of merge throws out the old contents and replaces -// them with the new. -// -void HeaderMap::merge(string key, string &old, string newValue) -{ - old = newValue; -} - - -// -// Collect the entire contents into a single string -// Note that this is NOT exactly what was passed in; certain canonicalizations have -// been done; fields are reordered; and duplicate-header fields have been coalesced. -//@@@ size could be pre-calculated (running counter). -// -string HeaderMap::collect(const char *lineEnding) const -{ - string value; - for (Map::const_iterator it = mMap.begin(); it != mMap.end(); it++) - value += it->first + ": " + it->second + lineEnding; - return value; -} - -size_t HeaderMap::collectLength(const char *lineEnding) const -{ - size_t size = 0; - size_t sepLength = strlen(lineEnding); - for (Map::const_iterator it = mMap.begin(); it != mMap.end(); it++) - size += it->first.length() + 2 + it->second.length() + sepLength; - return size; -} - - -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/headermap.h b/OSX/libsecurity_utilities/lib/headermap.h deleted file mode 100644 index f989e92a..00000000 --- a/OSX/libsecurity_utilities/lib/headermap.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// headermap - represent Internet-standard headers -// -//@@@ Handle duplicate entries. -//@@@ Be flexible: think HTTP (append with commas) vs. RFC822 (multiple Received: headers etc.) -// -#ifndef _H_HEADERMAP -#define _H_HEADERMAP - -#include -#include - - -namespace Security { - - -// -// Header-maps -// -class HeaderMap { - static const int maxKeyLength = 80; - typedef std::map Map; -public: - HeaderMap() { } - virtual ~HeaderMap() { } - - virtual void merge(std::string key, std::string &old, std::string newValue); - - void add(const char *key, const char *value); - void add(const char *line); // Key: value - void remove(const char *key); - - const char *find(const char *key, const char *def = NULL) const; - std::string &operator [] (const char *key); - - typedef Map::const_iterator ConstIterator; - ConstIterator begin() const { return mMap.begin(); } - ConstIterator end() const { return mMap.end(); } - - typedef Map::const_iterator Iterator; - Iterator begin() { return mMap.begin(); } - Iterator end() { return mMap.end(); } - - std::string collect(const char *lineEnding = "\r\n") const; - size_t collectLength(const char *lineEnding = "\r\n") const; - -private: - // - // In-place case canonicalization of header keys - // - struct CanonicalKey { - CanonicalKey(const char *key, char end = '\0'); - operator const char *() const { return mValue; } - operator std::string () const { return mValue; } - private: - char mValue[maxKeyLength]; - }; - - void add(const CanonicalKey &key, const char *value); - -private: - Map mMap; // map of key: value pairs -}; - - -} // end namespace Security - - -#endif /* _H_HEADERMAP */ diff --git a/OSX/libsecurity_utilities/lib/hosts.cpp b/OSX/libsecurity_utilities/lib/hosts.cpp deleted file mode 100644 index 689d46fc..00000000 --- a/OSX/libsecurity_utilities/lib/hosts.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// hosts - value-semantics host identifier class -// -#include "hosts.h" -#include -#include - - -namespace Security { -namespace IPPlusPlus { - - -class NamedHost : public Host::Spec { -public: - NamedHost(const char *name); - - string name() const; - set addresses() const; - - bool operator == (const NamedHost &other) const - { return mName == other.mName; } - -private: - string mName; - set mAddrs; -}; - - -class IPv4NumberHost : public Host::Spec { -public: - IPv4NumberHost(IPAddress addr) : mAddr(addr) { } - - string name() const; - set addresses() const; - - bool operator == (const IPv4NumberHost &other) const - { return mAddr == other.mAddr; } - -private: - IPAddress mAddr; -}; - - -// -// Host basics -// -Host::Host(const char *form) -{ - //@@@ IPv4 only at this time - IPAddress addr; - if (inet_aton(form, &addr)) - mSpec = new IPv4NumberHost(addr); - else - mSpec = new NamedHost(form); -} - - -// -// Compare for equality -// -bool Host::operator == (const Host &other) const -{ - // really silly hack alert: just compare lexicographically by name - return mSpec ? (name() == other.name()) : !other.mSpec; -} - -bool Host::operator < (const Host &other) const -{ - // really silly hack alert: just compare lexicographically by name - return !mSpec || (other.mSpec && name() < other.name()); -} - - -// -// Compare for subsumption -// -bool Host::operator <= (const Host &other) const -{ - return false; -} - - -// -// IPv4 address host specs (a single IPv4 address) -// -string IPv4NumberHost::name() const -{ - return mAddr; -} - -set IPv4NumberHost::addresses() const -{ - set result; - result.insert(mAddr); - return result; -} - - -// -// IPv4 hostname host specs (a set of addresses derived from a name lookup) -// @@@ If we want to support IPv6, this should ALSO contain IPv6 lookup results. -// -NamedHost::NamedHost(const char *name) : mName(name) -{ - //@@@ NOT THREAD SAFE - find another way to do name resolution - if (hostent *he = gethostbyname(name)) { - for (char **p = he->h_addr_list; *p; p++) - mAddrs.insert(*reinterpret_cast(*p)); - secinfo("ipname", "host %s resolves to %ld address(es)", mName.c_str(), mAddrs.size()); - return; - } - UnixError::throwMe(ENOENT); //@@@ h_errno translation or other source -} - -string NamedHost::name() const -{ - return mName; -} - -set NamedHost::addresses() const -{ - return mAddrs; -} - - -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/hosts.h b/OSX/libsecurity_utilities/lib/hosts.h deleted file mode 100644 index 75d4b1ab..00000000 --- a/OSX/libsecurity_utilities/lib/hosts.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// hosts - value-semantics host identifier class -// -// @@@ use vector instead of set to preserve resolver-generated order? -// @@@ preliminary implementation: at the very least, there'll be more subclasses (deferred, etc.) -// -#ifndef _H_HOSTS -#define _H_HOSTS - -#include "ip++.h" -#include -#include - - -namespace Security { -namespace IPPlusPlus { - - -// -// Host identities -// -class Host { -public: - Host(const char *form); - Host() { } - - // equality is defined strongly: same host specification - bool operator == (const Host &other) const; - bool operator != (const Host &other) const { return !(*this == other); } - bool operator < (const Host &other) const; // for STL sorting - - // inclusion (<=) is defined semi-weakly: greater subsumes smaller, same access specs - bool operator <= (const Host &other) const; - bool operator >= (const Host &other) const { return other <= *this; } - - string name() const { return mSpec->name(); } - set addresses() const { return mSpec->addresses(); } - -public: - class Spec : public RefCount { - public: - virtual ~Spec() { } - - virtual set addresses() const = 0; - virtual string name() const = 0; - - private: - }; - -private: - RefPointer mSpec; -}; - -} // end namespace IPPlusPlus -} // end namespace Security - - -#endif /* _H_HOSTS */ diff --git a/OSX/libsecurity_utilities/lib/inetreply.cpp b/OSX/libsecurity_utilities/lib/inetreply.cpp deleted file mode 100644 index 1eaf8765..00000000 --- a/OSX/libsecurity_utilities/lib/inetreply.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2000-2004,2011-2012,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@ - */ - - -// -// inetreply - manage Internet-standard reply strings -// -#include "inetreply.h" -#include -#include - -namespace Security { -namespace IPPlusPlus { - - -// -// Construct an InetReply object from a WRITABLE buffer. -// The buffer will be alterered by this constructor, and needs to be left alone -// until the InetReply object is destroyed. -// -InetReply::InetReply(const char *buffer) : mBuffer(buffer) -{ - analyze(); -} - -void InetReply::analyze() -{ - // follow Internet rule #1: be lenient in what you accept - /*const*/ char *p; // (un-const is ANSI bogosity in strtol) - mCode = (int) strtol(mBuffer, &p, 10); - if (p == mBuffer) { // conversion failed - mCode = -1; // error indicator - mSeparator = ' '; - mMessage = "?invalid?"; - return; - } - if (!*p) { // just "nnn" (tolerate) - mCode = atoi(p); - mSeparator = ' '; - mMessage = ""; - return; - } - mSeparator = *p++; - while (isspace(*p)) p++; - mMessage = p; -} - - -// -// Continuation handling -// -bool InetReply::Continuation::operator () (const char *input) -{ - if (mActive && !strncmp(input, mTestString, 4)) - mActive = false; - return mActive; -} - -bool InetReply::Continuation::operator () (const InetReply &reply) -{ - if (!mActive && reply.isContinued()) { - mActive = true; - snprintf(mTestString, 4, "%03d", reply.code()); - mTestString[3] = ' '; // no \0 left in this string - } - return mActive; -} - - -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/inetreply.h b/OSX/libsecurity_utilities/lib/inetreply.h deleted file mode 100644 index 014210eb..00000000 --- a/OSX/libsecurity_utilities/lib/inetreply.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// inetreply - manage Internet-standard reply strings -// -// The InetReply class represents an Internet-standard reply line of the form -// nnn some text -// -#ifndef _H_INETREPLY -#define _H_INETREPLY - -#include -#include - - -namespace Security { -namespace IPPlusPlus { - - -// -// An InetReply object represents a broken-up reply line of the form -// nnn(sp)text-form -// Note that this will take a *writable* input line buffer and munge it -// into shape. This means that -// (a) You have to keep the input line buffer alive until the InetReply dies, and -// (b) You can't use the input line buffer after the InetReply is constructed. -// -class InetReply { -public: - InetReply(const char *buffer); - - bool valid() const { return mCode >= 0; } - unsigned int code() const { return mCode; } - operator unsigned int () const { return code(); } - unsigned int type() const { return mCode / 100; } - const char *message() const { return mMessage; } - bool isContinued() const { return mSeparator == '-'; } - -private: - const char *mBuffer; // base buffer - int mCode; // integer code (usually nnn) - char mSeparator; // character after code (usually space; '-' for continued lines) - const char *mMessage; // rest of message - - void analyze(); - -public: - // - // Handle FTP-style continuations: nnn- ... nnnMessage - // Instructions for use: - // Continuation myCont; // in some persistent place - // ... get a line of reply -> const char *input ... - // if (myCont(input)) /* in (old) continuation */; - // InetReply reply(input); - // if (myCont(reply)) /* in (newly started) continuation */; - // /* not (any more) in continuation; reply has last message line - // - class Continuation { - public: - Continuation() : mActive(false) { } - - bool operator () (const char *input); - bool operator () (const InetReply &reply); - - bool active() const { return mActive; } - - private: - bool mActive; - char mTestString[4]; - }; -}; - - -} // end namespace IPPlusPlus -} // end namespace Security - - -#endif //_H_INETREPLY diff --git a/OSX/libsecurity_utilities/lib/iodevices.cpp b/OSX/libsecurity_utilities/lib/iodevices.cpp deleted file mode 100644 index 42874c4d..00000000 --- a/OSX/libsecurity_utilities/lib/iodevices.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (c) 2004-2007,2011 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@ - */ - - -// -// iodevices - code for finding and tracking devices via IOKit -// -#include "iodevices.h" -#include -#include -#include - -using namespace MachPlusPlus; - - -namespace Security { -namespace IOKit { - - -// -// Master Ports. -// Note that multiple MasterPort objects may refer to the same Mach port. -// -MasterPort::MasterPort() -{ - Error::check(::IOMasterPort(MACH_PORT_NULL, &port())); -} - - -// -// IOKit Devices (a small subset of functionality) -// -Device::~Device() -{ - ::IOObjectRelease(mService); -} - -string Device::name() const -{ - io_name_t tName; - Error::check(::IORegistryEntryGetName(mService, tName)); - return tName; -} - -string Device::name(const char *plane) const -{ - io_name_t tName; - Error::check(::IORegistryEntryGetNameInPlane(mService, plane, tName)); - return tName; -} - -string Device::path(const char *plane) const -{ - io_string_t tPath; - Error::check(::IORegistryEntryGetPath(mService, plane, tPath)); - return tPath; -} - -CFDictionaryRef Device::properties() const -{ - CFMutableDictionaryRef dict; - Error::check(::IORegistryEntryCreateCFProperties(mService, &dict, NULL, 0)); - return dict; -} - -CFTypeRef Device::property(const char *name) const -{ - return ::IORegistryEntryCreateCFProperty(mService, CFTempString(name), NULL, 0); -} - - -// -// DeviceIterators -// -DeviceIterator::~DeviceIterator() -{ - // drain the iterator to avoid port leakage - while (Device dev = (*this)()) - ; -} - - -io_service_t DeviceIterator::operator () () -{ - io_service_t dev = ::IOIteratorNext(mIterator); - mAtEnd = !dev; - return dev; -} - - -// -// DeviceMatches -// -DeviceMatch::DeviceMatch() - : CFRef(makeCFMutableDictionary()) -{ - CFError::check(*this); -} - -DeviceMatch::DeviceMatch(const char *cls) - : CFRef(::IOServiceMatching(cls)) -{ - CFError::check(*this); -} - -DeviceMatch::DeviceMatch(const char *cls, const char *name, uint32_t value, ...) - : CFRef(::IOServiceMatching(cls)) -{ - CFError::check(*this); - - va_list args; - va_start(args, value); - while (name) { - add(name, value); - name = va_arg(args, const char *); - if (!name) - break; - value = va_arg(args, uint32_t); - } -} - -void DeviceMatch::add(const char *name, uint32_t value) -{ - CFRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value); - CFDictionarySetValue(*this, CFTempString(name), number); -} - - -// -// NotificationPorts -// -NotificationPort::NotificationPort() -{ - CFError::check(mPortRef = ::IONotificationPortCreate(MasterPort())); -} - -NotificationPort::NotificationPort(const MasterPort &master) -{ - CFError::check(mPortRef = ::IONotificationPortCreate(master)); -} - -NotificationPort::~NotificationPort() -{ - ::IONotificationPortDestroy(mPortRef); -} - - -mach_port_t NotificationPort::port() const -{ - mach_port_t p = ::IONotificationPortGetMachPort(mPortRef); - CFError::check(p); - return p; -} - -CFRunLoopSourceRef NotificationPort::source() const -{ - CFRunLoopSourceRef rls = ::IONotificationPortGetRunLoopSource(mPortRef); - CFError::check(rls); - return rls; -} - - -void NotificationPort::add(const DeviceMatch &match, Receiver &receiver, const char *type) -{ - io_iterator_t iterator; - CFRetain(match); // compensate for IOSAMN not retaining its argument - Error::check(::IOServiceAddMatchingNotification(mPortRef, type, - match, - ioNotify, &receiver, - &iterator)); - - // run initial iterator to process existing devices - secinfo("iokit", "dispatching initial device match iterator %d", iterator); - DeviceIterator it(iterator); - receiver.ioChange(it); -} - -void NotificationPort::addInterestNotification(Receiver &receiver, io_service_t service, - const io_name_t interestType) -{ - io_iterator_t iterator; - - secinfo("iokit", "NotificationPort::addInterest - type: %s [port: %p (0x%08X), service: 0x%08X]", - interestType, mPortRef, NotificationPort::port(), service); - - // We cannot throw if we get an error here since we will receive notifications - // from each plane, and not all planes have the necessary information to be - // able to add an interest notification - kern_return_t kr = ::IOServiceAddInterestNotification(mPortRef, - service, interestType, ioDeviceNotification, &receiver, &iterator); - const char *msgstr = mach_error_string(kr); - const char *msgtyp = mach_error_type(kr); - if (msgstr && msgtyp) - secinfo("iokit", " msg: %s, typ: %s", msgstr, msgtyp); -} - -void NotificationPort::ioNotify(void *refCon, io_iterator_t iterator) -{ - secinfo("iokit", "dispatching new device match iterator %d", iterator); - DeviceIterator it(iterator); - try { - reinterpret_cast(refCon)->ioChange(it); - } catch (...) { - secinfo("iokit", "ioChange callback threw an exception (ignored)"); - } -} - -void NotificationPort::ioDeviceNotification(void *refCon, io_service_t service, - natural_t messageType, void *messageArgument) -{ - secinfo("iokit", "dispatching NEW device notification iterator, service 0x%08X, msg: 0x%04X, arg: %p", - service, messageType, messageArgument); - - const char *msgstr = mach_error_string(messageType); - const char *msgtyp = mach_error_type(messageType); - if (msgstr && msgtyp) - secinfo("iokit", " msg: %s, typ: %s", msgstr, msgtyp); - - if (service!=io_service_t(-1)) - reinterpret_cast(refCon)->ioServiceChange(refCon, service, messageType, messageArgument); -} - -// -// Abstract NotificationPort::Receivers -// -NotificationPort::Receiver::~Receiver() -{ /* virtual */ } - - -// -// MachPortNotificationPorts -// -MachPortNotificationPort::MachPortNotificationPort() -{ - NoReplyHandler::port(NotificationPort::port()); -} - -MachPortNotificationPort::~MachPortNotificationPort() -{ -} - -boolean_t MachPortNotificationPort::handle(mach_msg_header_t *in) -{ - ::IODispatchCalloutFromMessage(NULL, in, mPortRef); - return TRUE; -} - - - -} // end namespace IOKit -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/iodevices.h b/OSX/libsecurity_utilities/lib/iodevices.h deleted file mode 100644 index d0b04958..00000000 --- a/OSX/libsecurity_utilities/lib/iodevices.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 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@ - */ - - -// -// iodevices - code for finding and tracking devices via IOKit -// -#ifndef _H_IODEVICES -#define _H_IODEVICES - -#include -#include -#include -#include - - -namespace Security { -namespace IOKit { - - -// -// An IOKit master port -// -class MasterPort : public MachPlusPlus::AutoPort { -public: - MasterPort(); -}; - - -// -// An IOKit device -// -class Device { -public: - Device() : mService(MACH_PORT_NULL) { } - Device(io_service_t d) : mService(d) { } - ~Device(); - - io_service_t ioObject() const { return mService; } - - operator bool () const { return mService; } - bool operator ! () const { return !mService; } - - std::string name() const; - std::string name(const char *plane) const; - std::string path(const char *plane = kIOServicePlane) const; - CFDictionaryRef properties() const; - CFTypeRef property(const char *name) const; - - template - T property(const char *name) const - { return static_cast(property(name)); } - -private: - io_service_t mService; -}; - - -// -// A device iterator. -// This isn't an STL iterator. It's not important enough. -// -class DeviceIterator { -public: - DeviceIterator(io_iterator_t iter) : mIterator(iter), mAtEnd(false) { } - ~DeviceIterator(); - - io_service_t operator () (); - -private: - io_iterator_t mIterator; // iterator port (handle) - bool mAtEnd; // already hit end -}; - - -// -// An IOKit-style device matching dictionary, with convenient helper methods -// -class DeviceMatch : public CFRef { - NOCOPY(DeviceMatch) -public: - DeviceMatch(CFMutableDictionaryRef dict) : CFRef(dict) { } // this dictionary - DeviceMatch(); // empty dictionary - DeviceMatch(const char *cls); // this class - DeviceMatch(const char *cls, const char *name, uint32_t value, ...); // class plus value pairs - - CFRef &dict() { return static_cast &>(*this); } - operator bool () const { return this->get() != NULL; } - bool operator ! () const { return this->get() == NULL; } - - void add(const char *name, uint32_t value); // add one name/value pair -}; - - -// -// An IOKit notification port object -// -class NotificationPort { -public: - NotificationPort(); - NotificationPort(const MasterPort &master); - ~NotificationPort(); - - mach_port_t port() const; - operator mach_port_t () const { return port(); } - - CFRunLoopSourceRef source() const; - - class Receiver { - public: - virtual ~Receiver(); - - virtual void ioChange(DeviceIterator &iterator) = 0; - virtual void ioServiceChange(void *refCon, io_service_t service, //IOServiceInterestCallback - natural_t messageType, void *messageArgument) {} - }; - - void add(const DeviceMatch &match, Receiver &receiver, const char *type = kIOFirstMatchNotification); - void addInterestNotification(Receiver &receiver, io_service_t service, - const io_name_t interestType = kIOGeneralInterest); - -private: - - static void ioNotify(void *refCon, io_iterator_t iterator); - static void ioDeviceNotification(void *refCon, io_service_t service, - natural_t messageType, void *messageArgument); - -protected: - IONotificationPortRef mPortRef; -}; - - -class MachPortNotificationPort : public NotificationPort, public MachPlusPlus::MachServer::NoReplyHandler { -public: - MachPortNotificationPort(); - virtual ~MachPortNotificationPort(); - -private: - boolean_t handle(mach_msg_header_t *in); -}; - - -} // end namespace MachPlusPlus -} // end namespace Security - -#endif //_H_IODEVICES diff --git a/OSX/libsecurity_utilities/lib/ip++.cpp b/OSX/libsecurity_utilities/lib/ip++.cpp deleted file mode 100644 index 030b678f..00000000 --- a/OSX/libsecurity_utilities/lib/ip++.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// ip++ - C++ layer for IP socket and address management -// -// [Also see comments in header file.] -// -#include "ip++.h" -#include "hosts.h" -#include -#include -#include - - -namespace Security { -namespace IPPlusPlus { - - -typedef unsigned char Byte; // occasionally useful - - -// -// IPAddress -// -static const struct in_addr in_addr_any = { INADDR_ANY }; -#if BUG_GCC -const IPAddress &IPAddress::any = *static_cast(&in_addr_any); -#else -const IPAddress &IPAddress::any = static_cast(in_addr_any); -#endif - -IPAddress::IPAddress(const char *s) -{ - if (!inet_aton(s, this)) - UnixError::throwMe(EINVAL); -} - -IPAddress::operator string() const -{ - // This code is esentially equivalent to inet_ntoa, which we can't use for thread safety. - // Note: contents in NBO = always high-endian, thus this cast works everywhere. - const Byte *p = reinterpret_cast(this); - char buffer[(3+1)*4]; // nnn.nnn.nnn.nnn\0 - snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); - return buffer; -} - - -// -// IPSockAddress -// -IPSockAddress::IPSockAddress() -{ - sin_family = AF_INET; -} - -IPSockAddress::IPSockAddress(const IPAddress &addr, IPPort port) -{ - sin_family = AF_INET; - sin_addr = addr; - sin_port = htons(port); -} - -IPSockAddress::operator string () const -{ - char buffer[4*(3+1)+5+1]; // nnn.nnn.nnn.nnn:ppppp - snprintf(buffer, sizeof(buffer), "%s:%d", string(address()).c_str(), port()); - return buffer; -} - - -IPSockAddress IPSockAddress::defaults(const IPSockAddress &defaultAddr) const -{ - return defaults(defaultAddr.address(), defaultAddr.port()); -} - -IPSockAddress IPSockAddress::defaults(const IPAddress &defaultAddr, IPPort defaultPort) const -{ - return IPSockAddress( - address() ? address() : defaultAddr, - port() ? port() : defaultPort - ); -} - -IPSockAddress IPSockAddress::defaults(IPPort defaultPort) const -{ - return IPSockAddress(address(), port() ? port() : defaultPort); -} - - -// -// UNSockAddress -// -UNSockAddress::UNSockAddress() -{ - sun_family = AF_UNIX; -} - -UNSockAddress::UNSockAddress(const char *path) -{ - sun_family = AF_UNIX; - size_t length = strlen(path); - if (length >= sizeof(sun_path)) // won't fit into struct sockaddr_un - UnixError::throwMe(EINVAL); - memcpy(sun_path, path, length + 1); -} - -UNSockAddress::UNSockAddress(const string &path) -{ - sun_family = AF_UNIX; - if (path.length() >= sizeof(sun_path)) // won't fit into struct sockaddr_un - UnixError::throwMe(EINVAL); - memcpy(sun_path, path.c_str(), path.length() + 1); -} - - -string UNSockAddress::path() const -{ - return sun_path; -} - - -// -// Sockets -// -Socket::Socket(int type) -{ - open(type); -} - -Socket::Socket(int domain, int type, int protocol) -{ - open(domain, type, protocol); -} - -void Socket::open(int domain, int type, int protocol) -{ - checkSetFd(::socket(domain, type, protocol)); - mAtEnd = false; - secinfo("sockio", "socket(%d,%d) -> %d", type, protocol, fd()); -} - -void Socket::prepare(int fdFlags, int domain, int type, int protocol) -{ - // if file descriptor is closed, open it - otherwise take what's there - if (!isOpen()) - open(domain, type, protocol); - - // if flags were passed in, set them on the file descriptor now - if (fdFlags) - setFlag(fdFlags); -} - - -void Socket::bind(const IPAddress &addr, IPPort port) -{ - bind(IPSockAddress(addr, port)); -} - -void Socket::bind(const IPSockAddress &local) -{ - checkError(::bind(fd(), local, sizeof(local))); - secinfo("sockio", "%d bind to %s", fd(), string(local).c_str()); -} - -void Socket::bind(const UNSockAddress &local) -{ - checkError(::bind(fd(), local, sizeof(local))); - secinfo("sockio", "%d bind to %s", fd(), string(local).c_str()); -} - - -void Socket::listen(int backlog) -{ - checkError(::listen(fd(), backlog)); -} - - -void Socket::accept(Socket &s) -{ - IPSockAddress dummy; // ignored - return accept(s, dummy); -} - -void Socket::accept(Socket &s, IPSockAddress &peer) -{ - socklen_t length = sizeof(IPSockAddress); - s.checkSetFd(::accept(fd(), peer, &length)); - assert(length == sizeof(IPSockAddress)); -} - -void Socket::accept(Socket &s, UNSockAddress &peer) -{ - socklen_t length = sizeof(UNSockAddress); - s.checkSetFd(::accept(fd(), peer, &length)); - assert(length == sizeof(UNSockAddress)); -} - - -bool Socket::connect(const IPSockAddress &peer) -{ - if (::connect(fd(), peer, sizeof(peer))) { - switch (errno) { - case EINPROGRESS: - secinfo("sockio", "%d connecting to %s", fd(), string(peer).c_str()); - return false; - case EALREADY: - if (int err = error()) // connect failed - UnixError::throwMe(err); - // just keep trying - secinfo("sockio", "%d still trying to connect", fd()); - return false; - case EISCONN: - if (flags() & O_NONBLOCK) { - secinfo("sockio", "%d now connected", fd()); - return true; - } else { - UnixError::throwMe(); - } - default: - UnixError::throwMe(); - } - } else { - secinfo("sockio", "%d connect to %s", fd(), string(peer).c_str()); - return true; - } -} - -bool Socket::connect(const IPAddress &addr, IPPort port) -{ - return connect(IPSockAddress(addr, port)); -} - -bool Socket::connect(const UNSockAddress &peer) -{ - // no nice async support here: local operation (but keep the niceties) - checkError(::connect(fd(), peer, sizeof(peer))); - secinfo("sockio", "%d connect to %s", fd(), string(peer).c_str()); - return true; -} - -// void Socket::connect(const Host &host, ...): see below. - - -void Socket::shutdown(int how) -{ - assert(how >= 0 && how <= 2); - checkError(::shutdown(fd(), how)); -} - - -IPSockAddress Socket::localAddress() const -{ - IPSockAddress addr; - socklen_t length = sizeof(addr); - checkError(::getsockname(fd(), addr, &length)); - assert(length == sizeof(addr)); - return addr; -} - -IPSockAddress Socket::peerAddress() const -{ - IPSockAddress addr; - socklen_t length = sizeof(addr); - checkError(::getpeername(fd(), addr, &length)); - assert(length == sizeof(addr)); - return addr; -} - -void Socket::getOption(void *value, socklen_t &length, int name, int level /*= SOL_SOCKET*/) const -{ - UnixError::check(::getsockopt(fd(), level, name, value, &length)); -} - -void Socket::setOption(const void *value, int length, int name, int level /*= SOL_SOCKET*/) const -{ - UnixError::check(::setsockopt(fd(), level, name, value, length)); -} - - -// -// Connect to a Host object. -// This version of connect performs nontrivial work and makes interesting decisions. -// -void Socket::connect(const Host &host, IPPort port) -{ - //@@@ use two-step stutter algorithm? - //@@@ randomize order? - //@@@ keep worked-recently information? - //@@@ what about nonblocking operation? - set addrs = host.addresses(); - for (set::const_iterator it = addrs.begin(); it != addrs.end(); it++) { - const IPSockAddress address(*it, port); - if (::connect(fd(), address, sizeof(IPSockAddress)) == 0) { - secinfo("sockio", "%d connect to %s", fd(), string(address).c_str()); - return; - } - } - // no joy on any of the candidate addresses. Throw last error - //@@@ clean up errno? - UnixError::throwMe(); -} - - -// -// TCP*Sockets. -// Note that these will TCP*Socket::open() will *use* its existing file descriptor, -// on the theory that the caller may have prepared it specially (e.g. to make it nonblocking). -// -void TCPClientSocket::open(const IPSockAddress &peer, int fdFlags) -{ - prepare(fdFlags, AF_INET, SOCK_STREAM); - connect(peer); -} - -void TCPClientSocket::open(const IPAddress &addr, IPPort port, int fdFlags) -{ - prepare(fdFlags, AF_INET, SOCK_STREAM); - connect(addr, port); -} - -void TCPClientSocket::open(const Host &host, IPPort port, int fdFlags) -{ - prepare(fdFlags, AF_INET, SOCK_STREAM); - connect(host, port); -} - -TCPClientSocket::~TCPClientSocket() -{ - close(); -} - - -void TCPServerSocket::open(const IPSockAddress &addr, int depth) -{ - prepare(0, AF_INET, SOCK_STREAM); - bind(addr); - listen(depth); -} - -void TCPServerSocket::operator () (TCPClientSocket &newClient) -{ - accept(newClient); -} - -void TCPServerSocket::receive(TCPClientSocket &newClient) -{ - accept(newClient); - close(); -} - -TCPServerSocket::~TCPServerSocket() -{ - close(); -} - - -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/ip++.h b/OSX/libsecurity_utilities/lib/ip++.h deleted file mode 100644 index 306c4ab6..00000000 --- a/OSX/libsecurity_utilities/lib/ip++.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// ip++ - C++ layer for IP socket and address management -// -// Key to comments: -// HBO = host byte order, NBO = network byte order -// -// Rules for byte ordering: C++ objects store addresses and ports in NBO. -// Struct in_addr arguments are in NBO. Integer type arguments are in HBO. -// Stick with the conversion methods and you win. Cast around and you lose. -// -// @@@ Which namespace should we be in? -// -#ifndef _H_IPPLUSPLUS -#define _H_IPPLUSPLUS - -#include "unix++.h" -#include "timeflow.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace UnixPlusPlus; - - -namespace Security { -namespace IPPlusPlus { - -class Host; - - -// -// For now, ports are simply a short unsigned integer type, in HBO. -// -typedef UInt16 IPPort; - - -// -// An IP host address. -// -class IPAddress : public in_addr { -public: - IPAddress() { s_addr = htonl(INADDR_ANY); } - IPAddress(const struct in_addr &addr) { s_addr = addr.s_addr; } - explicit IPAddress(UInt32 addr) { s_addr = htonl(addr); } - IPAddress(const char *s); // ONLY dotted-quad form - use hosts.h for name resolution - - operator UInt32 () const { return ntohl(s_addr); } - operator string () const; // "n.n.n.n" (no name resolution) - -public: - bool operator == (const IPAddress &other) const { return s_addr == other.s_addr; } - bool operator != (const IPAddress &other) const { return s_addr != other.s_addr; } - bool operator < (const IPAddress &other) const { return s_addr < other.s_addr; } - - operator bool () const { return s_addr != htonl(INADDR_ANY); } - bool operator ! () const { return s_addr == htonl(INADDR_ANY); } - -public: - static const IPAddress &any; -}; - - -// -// An IP "socket address", i.e. a combined host address and port. -// -class IPSockAddress : public sockaddr_in { -public: - IPSockAddress(); - IPSockAddress(const struct sockaddr_in &sockaddr) { *(sockaddr_in *)this = sockaddr; } - IPSockAddress(const IPAddress &addr, IPPort port); - - IPAddress address() const { return sin_addr; } - void address(IPAddress addr) { sin_addr = addr; } - IPPort port() const { return ntohs(sin_port); } - void port(IPPort p) { sin_port = htons(p); } - - operator string () const; // "n.n.n.n:p" (no name resolution) - - // automatically convert to struct sockaddr * for use in system calls - operator struct sockaddr * () - { return reinterpret_cast(this); } - operator const struct sockaddr * () const - { return reinterpret_cast(this); } - - // conveniences - IPSockAddress defaults(const IPSockAddress &defaultAddr) const; - IPSockAddress defaults(const IPAddress &defaultAddr, IPPort defaultPort = 0) const; - IPSockAddress defaults(IPPort defaultPort) const; -}; - - -// -// UNIX Domain Socket addresses, for those who care. -// An "UNAddress", such as it were, is simply a string. -// -class UNSockAddress : public sockaddr_un { -public: - UNSockAddress(); - UNSockAddress(const char *path); - UNSockAddress(const std::string &path); - - string path() const; - operator string () const { return path(); } - - // automatically convert to struct sockaddr * for use in system calls - operator struct sockaddr * () - { return reinterpret_cast(this); } - operator const struct sockaddr * () const - { return reinterpret_cast(this); } -}; - - -// -// An IP socket. -// This inherits all functionality of a FileDesc, so I/O is fun and easy. -// Socket is "passive"; it doesn't own any resources and does nothing on destruction. -// On the upside, you can assign Sockets freely. -// If you want self-managing sockets that clean up after themselves, -// use the subclasses below. -// -class Socket : public FileDesc { -public: - Socket() { } - explicit Socket(int domain, int type, int protocol = 0); - explicit Socket(int type); - - Socket &operator = (int fd) { setFd(fd); return *this; } - - // basic open (socket system call) - void open(int domain, int type, int protocol = 0); - void open(int type) { open(AF_INET, type, 0); } - - // standard socket operations - void bind(const IPSockAddress &addr); // to this socket address - void bind(const IPAddress &addr = IPAddress::any, IPPort port = 0); - void bind(const UNSockAddress &addr); // to this UNIX domain socket - void listen(int backlog = 1); - void accept(Socket &s); - void accept(Socket &s, IPSockAddress &peer); - void accept(Socket &s, UNSockAddress &peer); - bool connect(const struct sockaddr *peer); - bool connect(const IPSockAddress &peer); - bool connect(const IPAddress &addr, IPPort port); - bool connect(const UNSockAddress &peer); - void connect(const Host &host, IPPort port); // any address of this host - void shutdown(int type); - enum { shutdownRead = 0, shutdownWrite = 1, shutdownBoth = 2 }; - - // get endpoint addresses - IPSockAddress localAddress() const; - IPSockAddress peerAddress() const; - - // socket options - void setOption(const void *value, int length, int name, int level = SOL_SOCKET) const; - void getOption(void *value, socklen_t &length, int name, int level = SOL_SOCKET) const; - - template void setOption(const T &value, int name, int level = SOL_SOCKET) const - { setOption(&value, sizeof(value), name, level); } - - template T getOption(int name, int level = SOL_SOCKET) const - { - T value; socklen_t length = sizeof(value); - getOption(&value, length, name, level); - assert(length == sizeof(value)); - return value; - } - - // some specific useful options - int type() const { return getOption(SO_TYPE); } - int error() const { return getOption(SO_ERROR); } - -public: -#if defined(SOMAXCONN) - static const int listenMaxQueue = SOMAXCONN; -#else - static const int listenMaxQueue = 5; // the traditional BSD UNIX value -#endif - -protected: - void prepare(int fdFlags, int domain, int type, int protocol = 0); -}; - - -// -// A TCPClientSocket is a self-connecting TCP socket that connects (actively) to a server. -// Since TCP, once established, is symmetric, it can also be used for the server side -// of a TCP pipe. You can think of it as the least complex embodiment of a TCP connection. -// -class TCPClientSocket : public Socket { - NOCOPY(TCPClientSocket) -public: - TCPClientSocket() { } - ~TCPClientSocket(); // closes connection - -#if BUG_GCC - void open(int type, int protocol = 0) { Socket::open(type, protocol); } -#else - using Socket::open; -#endif - - void open(const IPSockAddress &peer, int fdFlags = 0); - void open(const IPAddress &addr, IPPort port, int fdFlags = 0); - void open(const Host &host, IPPort port, int fdFlags = 0); - - TCPClientSocket(const IPSockAddress &peer, int fdFlags = 0) - { open(peer, fdFlags); } - TCPClientSocket(const IPAddress &addr, IPPort port, int fdFlags = 0) - { open(addr, port, fdFlags); } - TCPClientSocket(const Host &host, IPPort port, int fdFlags = 0) - { open(host, port, fdFlags); } - -protected: // for serverSocket/clientSocket footsy play - void setFd(int fd) { Socket::setFd(fd); } - -private: - TCPClientSocket(int sockfd); -}; - - -// -// A TCPServerSocket is a self-initializing listener socket for incoming TCP requests -// (usually to a server). Its function operator yields the next incoming connection request -// as a TCPClientSocket (see above). For one-shot receivers, the receive() method will -// create the client and close the listener atomically (which is sometimes faster). -// -class TCPServerSocket : public Socket { - NOCOPY(TCPServerSocket) -public: - TCPServerSocket() { } - ~TCPServerSocket(); // closes listener; existing connections unaffected - - void open(const IPSockAddress &local, int depth = 1); - void open(IPPort port = 0, int depth = 1) - { open(IPSockAddress(IPAddress::any, port), depth); } - - TCPServerSocket(const IPSockAddress &local, int depth = 1) { open(local, depth); } - TCPServerSocket(IPPort port, int depth = 1) { open(port, depth); } - - void operator () (TCPClientSocket &newClient); // retrieve next connection - void receive(TCPClientSocket &client); // accept once, then close listener -}; - - -} // end namespace IPPlusPlus -} // end namespace Security - - -#endif //_H_IPPLUSPLUS diff --git a/OSX/libsecurity_utilities/lib/ktracecodes.h b/OSX/libsecurity_utilities/lib/ktracecodes.h deleted file mode 100644 index 415277ac..00000000 --- a/OSX/libsecurity_utilities/lib/ktracecodes.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2003-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@ - */ - - -#ifndef _KTRACE_CODES_H_ -#define _KTRACE_CODES_H_ - -#include -#include - -/* - we format as follows (not really done this way because bitfields are compiler dependent): - - struct DebugCode - { - int DebugClass : 8; - int SubClass : 8; - int SecurityAppClass : 4; - int SecurityCodeClass : 10; - int FunctionQualifier : 2; - }; -*/ - -// Define the following as macros to keep objective c happy. - -// define app class constants -#define APP_DEBUG_CLASS 0x40 - -// define the sub class for security -#define SECURITY_SUB_CLASS 0xAA - -// define the app classes used by security -#define APP_CLASS_SFAUTHORIZATION 0 -#define APP_CLASS_SECURITY_AGENT 1 -#define APP_CLASS_AUTHORIZATION 2 -#define APP_CLASS_SECURITY_SERVER 3 -#define APP_CLASS_ADHOC 4 - -// define function qualifiers -#define FUNCTION_START DBG_FUNC_START -#define FUNCTION_END DBG_FUNC_END -#define FUNCTION_TIMEPOINT DBG_FUNC_NONE - -// define SFAuthorization code class -#define CODE_CLASS_SFAUTHORIZATION_BUTTON_PRESSED 0 -#define CODE_CLASS_SFAUTHORIZATION_AUTHORIZATION 1 - -// define SecurityAgent code class -#define CODE_CLASS_SECURITY_AGENT_START 0 -#define CODE_CLASS_SECURITY_AGENT_STARTED_BY_SECURITY_SERVER 1 -#define CODE_CLASS_SECURITY_AGENT_BEFORE_MECHANISM_INVOKE 2 -#define CODE_CLASS_SECURITY_AGENT_CONFIRM_ACCESS 3 - -// define Authorization code classes -#define CODE_CLASS_AUTHORIZATION_CREATE 0 -#define CODE_CLASS_AUTHORIZATION_COPY_RIGHTS 1 -#define CODE_CLASS_AUTHORIZATION_COPY_INFO 2 - -// define SecurityServer code classes -#define CODE_CLASS_SECURITY_SERVER_INITIALIZE 0 - -// define adhoc code classes (may change by need) -#define CODE_CLASS_ADHOC_FINDGENERICPASSWORD_BEGIN 0 -#define CODE_CLASS_ADHOC_UCSP_CLIENT_BEGIN 1 -#define CODE_CLASS_ADHOC_UCSP_SERVER_DECRYPT_BEGIN 2 -#define CODE_CLASS_ADHOC_UCSP_QUERYKEYCHAINACCESS_BEGIN 3 - -// define SecurityServer code classes -#define TRACECODE(_debugclass, _subclass, _appclass, _codeclass, _functionqualifier) \ - ((_debugclass << 24) | (_subclass << 16) | (_appclass << 12) | (_codeclass << 2) | (_functionqualifier)) - -/* - * Trace code allocations. - */ - enum { - kSecTraceSFAuthorizationButtonPressedStart = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SFAUTHORIZATION, CODE_CLASS_SFAUTHORIZATION_BUTTON_PRESSED, FUNCTION_START), - kSecTraceSFAuthorizationAuthorizationStart = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SFAUTHORIZATION, CODE_CLASS_SFAUTHORIZATION_AUTHORIZATION, FUNCTION_START), - kSecTraceSFAuthorizationAuthorizationEnd = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SFAUTHORIZATION, CODE_CLASS_SFAUTHORIZATION_AUTHORIZATION, FUNCTION_END), - kSecTraceSFAuthorizationButtonPressedEnd = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SFAUTHORIZATION, CODE_CLASS_SFAUTHORIZATION_BUTTON_PRESSED, FUNCTION_END), - - kSecTraceSecurityAgentStart = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SECURITY_AGENT, CODE_CLASS_SECURITY_AGENT_START, FUNCTION_TIMEPOINT), - kSecTraceSecurityAgentStartedBySecurityServer = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SECURITY_AGENT, CODE_CLASS_SECURITY_AGENT_STARTED_BY_SECURITY_SERVER, - FUNCTION_TIMEPOINT), - kSecTraceSecurityAgentBeforeMechanismInvoke = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SECURITY_AGENT, CODE_CLASS_SECURITY_AGENT_BEFORE_MECHANISM_INVOKE, - FUNCTION_TIMEPOINT), - kSecTraceSecurityAgentConfimAccess = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SECURITY_AGENT, CODE_CLASS_SECURITY_AGENT_CONFIRM_ACCESS, FUNCTION_TIMEPOINT), - - kSecTraceAuthorizationCreateStart = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_AUTHORIZATION, CODE_CLASS_AUTHORIZATION_CREATE, FUNCTION_START), - kSecTraceAuthorizationCreateEnd = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_AUTHORIZATION, CODE_CLASS_AUTHORIZATION_CREATE, FUNCTION_END), - kSecTraceAuthorizationCopyRightsStart = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_AUTHORIZATION, CODE_CLASS_AUTHORIZATION_COPY_RIGHTS, FUNCTION_START), - kSecTraceAuthorizationCopyRightsEnd = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_AUTHORIZATION, CODE_CLASS_AUTHORIZATION_COPY_RIGHTS, FUNCTION_END), - kSecTraceAuthorizationCopyInfoStart = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_AUTHORIZATION, CODE_CLASS_AUTHORIZATION_COPY_INFO, FUNCTION_START), - kSecTraceAuthorizationCopyInfoEnd = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_AUTHORIZATION, CODE_CLASS_AUTHORIZATION_COPY_INFO, FUNCTION_END), - - kSecTraceSecurityServerStart = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SECURITY_SERVER, CODE_CLASS_SECURITY_SERVER_INITIALIZE, FUNCTION_START), - kSecTraceSecurityServerInitialized = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_SECURITY_SERVER, CODE_CLASS_SECURITY_SERVER_INITIALIZE, FUNCTION_END), - - kSecTraceSecurityFrameworkSecKeychainFindGenericPasswordBegin = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_ADHOC, CODE_CLASS_ADHOC_FINDGENERICPASSWORD_BEGIN, FUNCTION_TIMEPOINT), - kSecTraceUCSPClientDecryptBegin = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_ADHOC, CODE_CLASS_ADHOC_UCSP_CLIENT_BEGIN, FUNCTION_TIMEPOINT), - kSecTraceUCSPServerDecryptBegin = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_ADHOC, CODE_CLASS_ADHOC_UCSP_SERVER_DECRYPT_BEGIN, FUNCTION_TIMEPOINT), - kSecTraceSecurityServerQueryKeychainAccess = - TRACECODE (APP_DEBUG_CLASS, SECURITY_SUB_CLASS, APP_CLASS_ADHOC, CODE_CLASS_ADHOC_UCSP_QUERYKEYCHAINACCESS_BEGIN, FUNCTION_TIMEPOINT) - }; - -#endif /* _KTRACE_CODES_H_ */ diff --git a/OSX/libsecurity_utilities/lib/logging.cpp b/OSX/libsecurity_utilities/lib/logging.cpp index 25c2ba94..a519234a 100644 --- a/OSX/libsecurity_utilities/lib/logging.cpp +++ b/OSX/libsecurity_utilities/lib/logging.cpp @@ -52,6 +52,10 @@ void open(const char *ident, int facility, int options /*= 0*/) // // General output method // + +static void output(int priority, const char *format, va_list args) __attribute__((format(printf, 2, 0))); + + static void output(int priority, const char *format, va_list args) { ::vsyslog(priority, format, args); diff --git a/OSX/libsecurity_utilities/lib/mach++.cpp b/OSX/libsecurity_utilities/lib/mach++.cpp index 616dcdf7..fcd1c4a7 100644 --- a/OSX/libsecurity_utilities/lib/mach++.cpp +++ b/OSX/libsecurity_utilities/lib/mach++.cpp @@ -28,7 +28,6 @@ #include #include #include -#include // error codes #include // debug #include @@ -55,7 +54,7 @@ OSStatus Error::osStatus() const case MIG_BAD_ARGUMENTS: case MIG_TYPE_ERROR: case MIG_REMOTE_ERROR: - return CSSMERR_CSSM_SERVICE_NOT_AVAILABLE; // IPC mismatch of some sort + return errSecServiceNotAvailable; // IPC mismatch of some sort default: return -1; //@@@ some "internal error" code, perhaps? } diff --git a/OSX/libsecurity_utilities/lib/mach++.h b/OSX/libsecurity_utilities/lib/mach++.h index 84236769..db092231 100644 --- a/OSX/libsecurity_utilities/lib/mach++.h +++ b/OSX/libsecurity_utilities/lib/mach++.h @@ -107,8 +107,8 @@ 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)); } - void destroy() { check(mach_port_destroy(self(), 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; } void insertRight(mach_msg_type_name_t type) { check(mach_port_insert_right(self(), mPort, mPort, type)); } diff --git a/OSX/libsecurity_utilities/lib/muscle++.cpp b/OSX/libsecurity_utilities/lib/muscle++.cpp index 575edce6..face9600 100644 --- a/OSX/libsecurity_utilities/lib/muscle++.cpp +++ b/OSX/libsecurity_utilities/lib/muscle++.cpp @@ -29,6 +29,7 @@ #include "muscle++.h" #include +#if TARGET_OS_OSX namespace Security { namespace Muscle { @@ -255,3 +256,5 @@ void Object::debugDump() } // namespace Muscle } // namespace Security + +#endif //TARGET_OS_OSX diff --git a/OSX/libsecurity_utilities/lib/muscle++.h b/OSX/libsecurity_utilities/lib/muscle++.h index f1a2f2f7..016940ec 100644 --- a/OSX/libsecurity_utilities/lib/muscle++.h +++ b/OSX/libsecurity_utilities/lib/muscle++.h @@ -32,6 +32,10 @@ #ifndef _H_MUSCLE_PP #define _H_MUSCLE_PP +#include + +#if TARGET_OS_OSX + #include #include #include @@ -194,5 +198,5 @@ public: } // namespace Muscle } // namespace Security - +#endif //TARGET_OS_OSX #endif //_H_MUSCLE_PP diff --git a/OSX/libsecurity_utilities/lib/osxcode.h b/OSX/libsecurity_utilities/lib/osxcode.h index 664fd101..f8569490 100644 --- a/OSX/libsecurity_utilities/lib/osxcode.h +++ b/OSX/libsecurity_utilities/lib/osxcode.h @@ -21,6 +21,8 @@ // #ifndef _H_OSXCODE #define _H_OSXCODE +#include + #include #include diff --git a/OSX/libsecurity_utilities/lib/pcsc++.cpp b/OSX/libsecurity_utilities/lib/pcsc++.cpp index fe80fee0..67161287 100644 --- a/OSX/libsecurity_utilities/lib/pcsc++.cpp +++ b/OSX/libsecurity_utilities/lib/pcsc++.cpp @@ -21,11 +21,13 @@ * @APPLE_LICENSE_HEADER_END@ */ - // // pcsc++ - PCSC client interface layer in C++ // #include "pcsc++.h" + +#if TARGET_OS_OSX + #include #include #include @@ -418,3 +420,5 @@ void Transaction::commitAction() } // namespace PCSC } // namespace Security + +#endif // TARGET_OS_OSX diff --git a/OSX/libsecurity_utilities/lib/pcsc++.h b/OSX/libsecurity_utilities/lib/pcsc++.h index 66ba4b4a..46e045d1 100644 --- a/OSX/libsecurity_utilities/lib/pcsc++.h +++ b/OSX/libsecurity_utilities/lib/pcsc++.h @@ -30,6 +30,10 @@ #ifndef _H_PCSC_PP #define _H_PCSC_PP +#include + +#if TARGET_OS_OSX + #include #include #include @@ -195,5 +199,6 @@ private: } // namespce PCSC } // namespace Security +#endif //TARGET_OS_OSX #endif //_H_PCSC_PP diff --git a/OSX/libsecurity_utilities/lib/powerwatch.cpp b/OSX/libsecurity_utilities/lib/powerwatch.cpp index 239f1acb..80448e04 100644 --- a/OSX/libsecurity_utilities/lib/powerwatch.cpp +++ b/OSX/libsecurity_utilities/lib/powerwatch.cpp @@ -28,6 +28,7 @@ #include "powerwatch.h" #include +#if TARGET_OS_OSX namespace Security { namespace MachPlusPlus { @@ -252,3 +253,5 @@ boolean_t PortPowerWatcher::handle(mach_msg_header_t *in) } // end namespace MachPlusPlus } // end namespace Security + +#endif //TARGET_OS_OSX diff --git a/OSX/libsecurity_utilities/lib/powerwatch.h b/OSX/libsecurity_utilities/lib/powerwatch.h index f9440007..a688759f 100644 --- a/OSX/libsecurity_utilities/lib/powerwatch.h +++ b/OSX/libsecurity_utilities/lib/powerwatch.h @@ -28,6 +28,10 @@ #ifndef _H_POWERWATCH #define _H_POWERWATCH +#include + +#if TARGET_OS_OSX + #include #include #include @@ -111,4 +115,6 @@ public: } // end namespace Security +#endif //TARGET_OS_OSX + #endif //_H_POWERWATCH diff --git a/OSX/libsecurity_utilities/lib/seccfobject.cpp b/OSX/libsecurity_utilities/lib/seccfobject.cpp index 9fcfc7c0..93185ffc 100644 --- a/OSX/libsecurity_utilities/lib/seccfobject.cpp +++ b/OSX/libsecurity_utilities/lib/seccfobject.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -156,12 +157,12 @@ SecCFObject::operator delete(void *object) throw() SecCFObject::SecCFObject() { mRetainCount = 1; - mRetainSpinLock = OS_SPINLOCK_INIT; + mRetainLock = OS_UNFAIR_LOCK_INIT; } uint32_t SecCFObject::updateRetainCount(intptr_t direction, uint32_t *oldCount) { - OSSpinLockLock(&mRetainSpinLock); + os_unfair_lock_lock(&mRetainLock); if (oldCount != NULL) { @@ -179,7 +180,7 @@ uint32_t SecCFObject::updateRetainCount(intptr_t direction, uint32_t *oldCount) uint32_t result = mRetainCount; - OSSpinLockUnlock(&mRetainSpinLock); + os_unfair_lock_unlock(&mRetainLock); return result; } diff --git a/OSX/libsecurity_utilities/lib/seccfobject.h b/OSX/libsecurity_utilities/lib/seccfobject.h index dd593883..0cbec6b1 100644 --- a/OSX/libsecurity_utilities/lib/seccfobject.h +++ b/OSX/libsecurity_utilities/lib/seccfobject.h @@ -29,6 +29,7 @@ #include #include #include "threading.h" +#include #if( __cplusplus <= 201103L) #include @@ -82,7 +83,7 @@ private: static const size_t kAlignedRuntimeSize = SECALIGNUP(sizeof(SecRuntimeBase), 4); uint32_t mRetainCount; - OSSpinLock mRetainSpinLock; + os_unfair_lock mRetainLock; public: // For use by SecPointer only. Returns true once the first time it's called after the object has been created. diff --git a/OSX/libsecurity_utilities/lib/security_utilities.h b/OSX/libsecurity_utilities/lib/security_utilities.h index 37ccc776..d5350a3f 100644 --- a/OSX/libsecurity_utilities/lib/security_utilities.h +++ b/OSX/libsecurity_utilities/lib/security_utilities.h @@ -26,39 +26,25 @@ #if defined(__cplusplus) -#include -#include #include #include #include #include #include #include -#include -#include #include -#include -#include -#include -#include #include #include #include #include #include #include -#include -#include -#include -#include #include #include #include #include #include -#include #include -#include #include #include diff --git a/OSX/libsecurity_utilities/lib/selector.cpp b/OSX/libsecurity_utilities/lib/selector.cpp deleted file mode 100644 index 599e4b64..00000000 --- a/OSX/libsecurity_utilities/lib/selector.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// selector - I/O stream multiplexing -// -#include "selector.h" -#include -#include -#include // min/max - - -namespace Security { -namespace UnixPlusPlus { - - -// -// construct a Selector object. -// -Selector::Selector() : fdMin(INT_MAX), fdMax(-1) -{ - // initially allocate room for FD_SETSIZE file descriptors (usually good enough) - fdSetSize = FD_SETSIZE / NFDBITS; - inSet.grow(0, fdSetSize); - outSet.grow(0, fdSetSize); - errSet.grow(0, fdSetSize); -} - -Selector::~Selector() -{ } - - -// -// Add a Client to a Selector -// -void Selector::add(int fd, Client &client, Type type) -{ - // plausibility checks - assert(!client.isActive()); // one Selector per client, and no re-adding - assert(fd >= 0); - - secinfo("selector", "add client %p fd %d type=%d", &client, fd, type); - - // grow FDSets if needed - unsigned int pos = fd / NFDBITS; - if (pos >= fdSetSize) { - int newSize = (fd - 1) / NFDBITS + 2; // as much as needed + 1 spare word - inSet.grow(fdSetSize, newSize); - outSet.grow(fdSetSize, newSize); - errSet.grow(fdSetSize, newSize); - } - - // adjust boundaries - if (fd < fdMin) - fdMin = fd; - if (fd > fdMax) - fdMax = fd; - - // add client - Client * &slot = clientMap[fd]; - assert(!slot); - slot = &client; - client.mFd = fd; - client.mSelector = this; - client.mEvents = type; - set(fd, type); -} - - -// -// Remove a Client from a Selector -// -void Selector::remove(int fd) -{ - // sanity checks - assert(fd >= 0); - ClientMap::iterator it = clientMap.find(fd); - assert(it != clientMap.end()); - assert(it->second->mSelector == this); - - secinfo("selector", "remove client %p fd %d", it->second, fd); - - // remove from FDSets - set(fd, none); - - // remove client - it->second->mSelector = NULL; - clientMap.erase(it); - - // recompute fdMin/fdMax if needed - if (isEmpty()) { - fdMin = INT_MAX; - fdMax = -1; - } else if (fd == fdMin) { - fdMin = clientMap.begin()->first; - } else if (fd == fdMax) { - fdMax = clientMap.rbegin()->first; - } -} - - -// -// Adjust the FDSets for a single given Client according to a new event Type mask. -// -void Selector::set(int fd, Type type) -{ - assert(fd >= 0); - inSet.set(fd, type & input); - outSet.set(fd, type & output); - errSet.set(fd, type & critical); - secinfo("selector", "fd %d notifications 0x%x", fd, type); -} - - -void Selector::operator () () -{ - if (!clientMap.empty()) - singleStep(0); -} - - -void Selector::operator () (Time::Absolute stopTime) -{ - if (!clientMap.empty()) - singleStep(stopTime - Time::now()); -} - - -// -// Perform a single pass through the Selector and notify all clients -// that have selected I/O pending at this time. -// There is not time limit on how long this may take; if the clients -// are well written, it won't be too long. -// -void Selector::singleStep(Time::Interval maxWait) -{ - assert(!clientMap.empty()); - secinfo("selector", "select(%d) [%d-%d] for %ld clients", - fdMax + 1, fdMin, fdMax, clientMap.size()); - for (;;) { // pseudo-loop - only retries - struct timeval duration = maxWait.timevalInterval(); -#if defined(__APPLE__) - // ad-hoc fix: MacOS X's BSD rejects times of more than 100E6 seconds - if (duration.tv_sec > 100000000) - duration.tv_sec = 100000000; -#endif - const int size = FDSet::words(fdMax); // number of active words in sets - switch (int hits = ::select(fdMax + 1, - inSet.make(size), outSet.make(size), errSet.make(size), - &duration)) { - case -1: // error - if (errno == EINTR) - continue; - secinfo("selector", "select failed: errno=%d", errno); - UnixError::throwMe(); - case 0: // no events - secinfo("selector", "select returned nothing"); - return; - default: // some events - secinfo("selector", "%d pending descriptors", hits); - //@@@ This could be optimized as a word-merge scan. - //@@@ The typical case doesn't benefit from this though, though browsers might - //@@@ and integrated servers definitely would. - for (int fd = fdMin; fd <= fdMax && hits > 0; fd++) { - int types = 0; - if (inSet[fd]) types |= input; - if (outSet[fd]) types |= output; - if (errSet[fd]) types |= critical; - if (types) { - secinfo("selector", "notify fd %d client %p type %d", - fd, clientMap[fd], types); - clientMap[fd]->notify(fd, types); - hits--; - } - } - return; - } - } -} - - -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/selector.h b/OSX/libsecurity_utilities/lib/selector.h deleted file mode 100644 index 88ca753f..00000000 --- a/OSX/libsecurity_utilities/lib/selector.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// selector - I/O stream multiplexing -// -#ifndef _H_SELECTOR -#define _H_SELECTOR - -#include -#include -#include "timeflow.h" -#include -#include -#include -#include -#include - - -namespace Security { -namespace UnixPlusPlus { - - -// -// A Selector is an I/O dispatch facility that can supervise any number of "file descriptors", -// each of which can perform I/O. Obviously this is geared towards the UNIX facility. -// -class Selector { -public: - class Client; friend class Client; - - Selector(); - virtual ~Selector(); - - //@@@ preliminary interface - void operator () (); // run just once (now) - void operator () (Time::Absolute stopTime); - void operator () (Time::Interval duration) - { (*this)(Time::now() + duration); } - - typedef unsigned int Type; - static const Type none = 0x00; - static const Type input = 0x01; - static const Type output = 0x02; - static const Type critical = 0x04; - static const Type all = input | output | critical; - -public: - class Client { - public: - typedef Selector::Type Type; - friend class Selector; - - Client() : mSelector(NULL) { } - virtual void notify(int fd, Type type) = 0; - virtual ~Client() { } - - bool isActive() const { return mSelector != NULL; } - - static const Type input = Selector::input; - static const Type output = Selector::output; - static const Type critical = Selector::critical; - - protected: - void events(Type type) { mSelector->set(mFd, type); mEvents = type; } - Type events() const { return mEvents; } - - void enable(Type type) { events(events() | type); } - void disable(Type type) { events(events() & ~type); } - - template Sel &selectorAs() - { assert(mSelector); return safer_cast(*mSelector); } - - private: - int mFd; - Selector *mSelector; - Type mEvents; - }; - - void add(int fd, Client &client, Type type = all); - void remove(int fd); - bool isEmpty() const { return clientMap.empty(); } - -private: - void set(int fd, Type type); // (re)set mask for one client - - void singleStep(Time::Interval maxWait); - -private: - unsigned int fdSetSize; // number of fd_masks allocated in FDSets - int fdMin, fdMax; // highest/lowest fds in use - FDSet inSet, outSet, errSet; // current in/out/error select masks - -private: - typedef map ClientMap; - ClientMap clientMap; -}; - - -} // end namespace UnixPlusPlus -} // end namespace Security - - -#endif //_H_SELECTOR diff --git a/OSX/libsecurity_utilities/lib/socks++.cpp b/OSX/libsecurity_utilities/lib/socks++.cpp deleted file mode 100644 index 0ab7d50c..00000000 --- a/OSX/libsecurity_utilities/lib/socks++.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2000-2001,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@ - */ - - -// -// socks - socks version of IP sockets -// -// [Also see comments in header file.] -// -// This file contains the "generic" Socks functionality. -// Socks4 and Socks5 implementations are in their separate files. -// -#include "socks++.h" -#include "socks++4.h" -#include "socks++5.h" -#include "hosts.h" - - -namespace Security { -namespace IPPlusPlus { - - -// -// Static objects -// -ModuleNexus SocksServer::global; - - -// -// SocksServer destruction -// -SocksServer::~SocksServer() -{ /* virtual */ } - - -// -// Create a SocksServer object -// -SocksServer *SocksServer::make(Version version, const IPSockAddress &addr) -{ - switch (version) { - case 0: - return NULL; // no socks - case 4: - return new Socks4::Server(addr); - case 5: - return new Socks5::Server(addr); - default: - UnixError::throwMe(EINVAL); - } -} - - -// -// TCPClientSockets (CONNECT access) -// -void SocksClientSocket::open(const IPSockAddress &peer) -{ - if (mServer) { - Support::connect(*this, peer); - lastConnected(mPeerAddress.address()); - } else { - TCPClientSocket::open(peer); - } -} - -void SocksClientSocket::open(const IPAddress &addr, IPPort port) -{ - open(IPSockAddress(addr, port)); -} - -void SocksClientSocket::open(const Host &host, IPPort port) -{ - if (mServer) { - Support::connect(*this, host, port); - lastConnected(mPeerAddress.address()); - } else { - TCPClientSocket::open(host, port); - } -} - -void SocksClientSocket::setFd(int fd, const IPSockAddress &local, const IPSockAddress &peer) -{ - Socket::setFd(fd); - mLocalAddress = local; - mPeerAddress = peer; -} - - -// -// TCPServerSockets (BIND access) -// -void SocksServerSocket::open(const IPSockAddress &local, int) -{ - if (mServer) { -#if BUG_GCC - if (mConnectionPeer) - Support::bind(*this, mConnectionPeer, local.port()); - else - Support::bind(*this, lastConnected(), local.port()); -#else - Support::bind(*this, - mConnectionPeer ? mConnectionPeer : lastConnected(), - local.port()); -#endif - } else { - TCPServerSocket::open(local, 1); - } -} - -void SocksServerSocket::receive(SocksClientSocket &client) -{ - if (mServer) { - Support::receive(*this, client); - } else { - TCPServerSocket::receive(client); - } -} - - -// -// Address functions -// -IPSockAddress SocksServer::Support::localAddress(const Socket &me) const -{ - if (mServer) - return mLocalAddress; - else - return me.localAddress(); -} - -IPSockAddress SocksServer::Support::peerAddress(const Socket &me) const -{ - if (mServer) - return mPeerAddress; - else - return me.peerAddress(); -} - - -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/socks++.h b/OSX/libsecurity_utilities/lib/socks++.h deleted file mode 100644 index ffd49a95..00000000 --- a/OSX/libsecurity_utilities/lib/socks++.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// socks - socks version of IP sockets -// -// This Socks implementation replaces the TCP-functional layer of the socket interface -// (TCPClientSocket and TCPServerSocket), not the raw Socket layer. Remember what -// Socks was invented for -- it's NOT a generic socket abstraction layer, valiant efforts -// of the various -lsocks libraries nonwithstanding. -// Do note that these are not virtual overrides, but textual replacements. -// -// This implementation supports Socks versions 4 and 5, as well as direct (un-socksed) sockets. -// The choice is per socket object. -// -// API Synopsis: -// SocksServer *server = SocksServer::make(version, IP-address); -// SocksServer::defaultServer(server); // for new sockets -// SocksClientSocket clientSocket(...); -// clientSocket.server(server); // for this socket -// SocksServerSocket serverSocket(...); // only supports .receive() -// Otherwise, Socks{Client,Server}Socket is functionally equivalent to {Client,Server}Socket. -// Sockets without a Server (explicit or by default) are direct. -// -// Minimum replacement strategy: -// #define TCPClientSocket SocksClientSocket -// #define TCPServerSocket SocksServerSocket -// SocksServer::defaultServer(SocksServer::make(...)); -// -// Limitations: -// There is no UDP Socks support. -// @@@ Nonblocking sockets may not work quite right. -// -#ifndef _H_SOCKSPLUSPLUS -#define _H_SOCKSPLUSPLUS - -#include "ip++.h" -#include -#include - - -using namespace UnixPlusPlus; - - -namespace Security { -namespace IPPlusPlus { - - -class SocksServerSocket; -class SocksClientSocket; - - -// -// A particular Socks server and version. Get one by calling SocksServer::make(). -// You can express "no socks server" (direct connect) with a NULL pointer (or version==0). -// -class SocksServer { -public: - class Support; friend class Support; - -private: - struct Global { - mutable Mutex lock; // lock for mGlobalServerAddress - SocksServer *mServer; // global default server - ThreadNexus lastConnected; // last address connected to (for aux. bind) - - Global() : mServer(NULL) { } - - void server(SocksServer *srv) { StLock _(lock); mServer = srv; } - SocksServer *server() const { StLock _(lock); return mServer; } - }; - static ModuleNexus global; // global state - -public: - typedef unsigned int Version; - - static SocksServer *make(Version version, const IPSockAddress &addr); - - const IPSockAddress &address() const { return mServerAddress; } - Version version() const { return mVersion; } - -public: - static SocksServer *defaultServer() { return global().server(); } - static void defaultServer(SocksServer *server) { global().server(server); } - -protected: - virtual ~SocksServer(); - - virtual void connect(SocksClientSocket &me, const IPSockAddress &peer) = 0; - virtual void connect(SocksClientSocket &me, const Host &host, IPPort port) = 0; - virtual void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) = 0; - virtual void receive(SocksServerSocket &me, SocksClientSocket &receiver) = 0; - - SocksServer(Version v, const IPSockAddress &addr) : mVersion(v), mServerAddress(addr) { } - -protected: - Version mVersion; - IPSockAddress mServerAddress; - -public: - class Support { - public: - SocksServer *server() const { return mServer; } - void server(SocksServer *srv) { mServer = srv; } - - IPSockAddress localAddress(const Socket &me) const; - IPSockAddress peerAddress(const Socket &me) const; - - protected: - Support() : mServer(defaultServer()) { } - - void connect(SocksClientSocket &me, const IPSockAddress &peer) - { mServer->connect(me, peer); } - void connect(SocksClientSocket &me, const Host &host, IPPort port) - { mServer->connect(me, host, port); } - void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) - { mServer->bind(me, peer, port); } - void receive(SocksServerSocket &me, SocksClientSocket &receiver) - { mServer->receive(me, receiver); } - - void lastConnected(IPAddress addr) { global().lastConnected() = addr; } - IPAddress lastConnected() const { return global().lastConnected(); } - - public: - SocksServer *mServer; // server for this socket - IPSockAddress mLocalAddress; // my own address, as reported by server - IPSockAddress mPeerAddress; // peer address - }; -}; - - -// -// The Socks version of a TCPClientSocket -// -class SocksClientSocket : public TCPClientSocket, public SocksServer::Support { -public: - SocksClientSocket() { } - SocksClientSocket(const IPSockAddress &peer) { open(peer); } - SocksClientSocket(const IPAddress &addr, IPPort port) { open(addr, port); } - SocksClientSocket(const Host &host, IPPort port) { open(host, port); } - - void open(const IPSockAddress &peer); - void open(const IPAddress &addr, IPPort port); - void open(const Host &host, IPPort port); - - IPSockAddress localAddress() const { return Support::localAddress(*this); } - IPSockAddress peerAddress() const { return Support::peerAddress(*this); } - -public: - void setFd(int fd, const IPSockAddress &local, const IPSockAddress &peer); -}; - - -// -// The Socks version of a TCPServerSocket. -// Note that this version only supports the receive() access method. -// By the nature of things, the queue-length argument is ignored (it's always 1). -// -// A note about setMainConnection: There is a structural problem -// with the Socks protocol. When a SocksServerSocket goes active, -// the protocol requires the IP address of the host the connection will be -// coming from. Typical Socks library layers simply assume that this will -// be the address of the last server connected to by another (TCP) socket. -// We do this heuristic too, but it's unreliable: it's a per-thread global, and will -// fail if you interleave multiple socks "sessions" in the same thread. For this -// case (or if you just want to be safe and explicit), you can call setMainConnection to -// explicitly link this socket to a TCPClientSocket whose peer we should use. -// Do note that this call does not exist in the plain (non-socks) socket layer. -// -class SocksServerSocket : public TCPServerSocket, public SocksServer::Support { -public: - SocksServerSocket() { } - SocksServerSocket(const IPSockAddress &local, int = 1) { open(local); } - SocksServerSocket(IPPort port, int = 1) { open(port); } - - void open(const IPSockAddress &local, int = 1); - void open(IPPort port = 0, int = 1) - { open(IPSockAddress(IPAddress::any, port)); } - - void receive(SocksClientSocket &client); // accept incoming and close listener - - IPSockAddress localAddress() const { return Support::localAddress(*this); } - IPSockAddress peerAddress() const { return Support::peerAddress(*this); } - - // this special call is not an overlay of TCPServerSocket - it exists only for Socks - void setMainConnection(TCPClientSocket &main) - { mConnectionPeer = main.peerAddress().address(); } - -private: - IPAddress mConnectionPeer; // address to say we're peered with - -private: - void operator () (TCPClientSocket &newClient); // not supported by Socks -}; - - -} // end namespace IPPlusPlus -} // end namespace Security - - -#endif //_H_IPPLUSPLUS diff --git a/OSX/libsecurity_utilities/lib/socks++4.cpp b/OSX/libsecurity_utilities/lib/socks++4.cpp deleted file mode 100644 index 20e2e9bb..00000000 --- a/OSX/libsecurity_utilities/lib/socks++4.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// socks++int - internal Socks implementation -// -#include "socks++4.h" -#include "hosts.h" -#include - - -namespace Security { -namespace IPPlusPlus { -namespace Socks4 { - - - -// -// Socks4 Protocol implementation -// -void Server::connect(SocksClientSocket &me, const IPSockAddress &peer) -{ - me.Socket::open(SOCK_STREAM); - me.Socket::connect(mServerAddress); - Message request(socksConnect, peer); - request.send(me, "nobody"); - (Message(me)); // read and check reply message - me.mPeerAddress = peer; // best guess, Mr. Sulu - secinfo("socks", "%d socks4 connected to %s", me.fd(), string(peer).c_str()); -} - -void Server::connect(SocksClientSocket &me, const Host &host, IPPort port) -{ - // Socks4 has no name resolution support. Do it here - //@@@ error reporting sucks here - set addrs = host.addresses(); - for (set::const_iterator it = addrs.begin(); it != addrs.end(); it++) { - try { - IPSockAddress addr(*it, port); - connect(me, addr); - return; - } catch (const UnixError &err) { - errno = err.error; - } - } - // exhausted - UnixError::throwMe(); -} - - -void Server::bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) -{ - me.Socket::open(SOCK_STREAM); - me.Socket::connect(mServerAddress); - Message request(socksBind, IPSockAddress(peer, port)); - request.send(me, "nobody"); - Message reply(me); - me.mLocalAddress = reply.address().defaults(mServerAddress.address()); - secinfo("socks", "%d socks4 bound to %s", me.fd(), string(me.mLocalAddress).c_str()); -} - -void Server::receive(SocksServerSocket &me, SocksClientSocket &receiver) -{ - Message reply(me); - receiver.setFd(me.fd(), me.mLocalAddress, reply.address()); - me.clear(); // clear our own (don't close on destruction) - secinfo("socks", "%d socks4 inbound connect", receiver.fd()); -} - - -// -// Message properties -// -Message::Message(Command cmd, const IPSockAddress &address) - : version(4), message(cmd), port(htons(address.port())), addr(address.address()) -{ -} - - -void Message::send(Socket &s, const char *userid) -{ - if (s.write(this, sizeof(*this)) != sizeof(*this)) - UnixError::throwMe(); - // now append zero-terminated userid (what a crock) - size_t length = strlen(userid) + 1; - if (s.write(userid, length) != length) { - s.close(); - UnixError::throwMe(); - } -} - -Message::Message(Socket &s) -{ - if (s.read(this, sizeof(*this)) != sizeof(*this)) { - s.close(); - UnixError::throwMe(); - } - if (version != 0) { - s.close(); - UnixError::throwMe(EPROTONOSUPPORT); - } - switch (message) { - case requestAccepted: - return; - default: - UnixError::throwMe(ECONNREFUSED); //@@@ hardly any diagnostics here - } -} - - -} // end namespace Socks -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/socks++4.h b/OSX/libsecurity_utilities/lib/socks++4.h deleted file mode 100644 index 8a82af8e..00000000 --- a/OSX/libsecurity_utilities/lib/socks++4.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2000-2001,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@ - */ - - -// -// socks++int - internal header for Socks implementation -// -#ifndef _H_SOCKSPLUSPLUSINT -#define _H_SOCKSPLUSPLUSINT - -#include "socks++.h" - - -namespace Security { -namespace IPPlusPlus { -namespace Socks4 { - - -typedef unsigned char Byte; - - -enum Command { - socksConnect = 1, - socksBind = 2 -}; - -enum Reply { - requestAccepted = 90, - requestFailed = 91, - requestIdentFailed = 92, - requestIdentRejected = 93 -}; - - -class Server : public SocksServer { -public: - Server(const IPSockAddress &s) : SocksServer(4, s) { } - - virtual void connect(SocksClientSocket &me, const IPSockAddress &peer); - virtual void connect(SocksClientSocket &me, const Host &host, IPPort port); - virtual void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port); - virtual void receive(SocksServerSocket &me, SocksClientSocket &receiver); -}; - - -struct Message { - Byte version; - Byte message; - IPPort port; - IPAddress addr; - - Message(Command cmd, const IPSockAddress &addr); - void send(Socket &s, const char *userid); - - Message(Socket &s); - - IPSockAddress address() const { return IPSockAddress(addr, port); } -}; - - - -} // end namespace Socks -} // end namespace IPPlusPlus -} // end namespace Security - -#endif //_H_SOCKSPLUSPLUSINT diff --git a/OSX/libsecurity_utilities/lib/socks++5.cpp b/OSX/libsecurity_utilities/lib/socks++5.cpp deleted file mode 100644 index 0f6856b0..00000000 --- a/OSX/libsecurity_utilities/lib/socks++5.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// socks++int - internal Socks implementation -// -#include "socks++5.h" -#include "hosts.h" - - -namespace Security { -namespace IPPlusPlus { -namespace Socks5 { - - -// -// Socks5 Protocol implementation -// -void Server::open(Socket &s, Support &my) -{ - s.open(SOCK_STREAM); - s.connect(my.mServer->address()); - secinfo("socks", "%d connected to server %s", s.fd(), string(my.mServer->address()).c_str()); - Byte request[] = { 5, 1, socksAuthPublic }; - s.write(request, sizeof(request)); - Byte reply[2]; - s.read(reply, sizeof(reply)); - if (reply[0] != 5 || reply[1] != socksAuthPublic) { - secinfo("socks", "%d server failed (v%d auth=%d)", s.fd(), reply[0], reply[1]); - s.close(); - UnixError::throwMe(EPROTONOSUPPORT); - } -} - -void Server::connect(SocksClientSocket &me, const IPSockAddress &peer) -{ - open(me, me); - Message request(socksConnect, peer.address(), peer.port()); - request.send(me); - Message reply(me); - me.mLocalAddress = reply.address(); - me.mPeerAddress = peer; - secinfo("socks", "%d socks connected to %s", me.fd(), string(peer).c_str()); -} - -void Server::connect(SocksClientSocket &me, const Host &host, IPPort port) -{ -#if 1 - //@@@ should be using Hostname (server resolution) mode, but this won't get us - //@@@ any useful peer address to use for bind relaying. Need to rethink this scenario. - set addrs = host.addresses(); - for (set::const_iterator it = addrs.begin(); it != addrs.end(); it++) { - try { - IPSockAddress addr(*it, port); - connect(me, addr); - return; - } catch (const UnixError &err) { - errno = err.error; - } - } - // exhausted - UnixError::throwMe(); -#else - open(me, me); - Message request(socksConnect, host.name().c_str(), port); - request.send(me); - Message reply(me); - me.mLocalAddress = reply.address(); - //me.mPeerAddress = not provided by Socks5 protocol; - secinfo("socks", "%d socks connected to %s", me.fd(), host.name().c_str()); -#endif -} - - -void Server::bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) -{ - open(me, me); - Message request(socksBind, peer, port); - request.send(me); - Message reply(me); - me.mLocalAddress = reply.address(); - //me.mPeerAddress not available yet; - secinfo("socks", "%d socks bound to %s", me.fd(), string(me.mLocalAddress).c_str()); -} - -void Server::receive(SocksServerSocket &me, SocksClientSocket &receiver) -{ - Message reply(me); - receiver.setFd(me.fd(), me.mLocalAddress, reply.address()); - me.clear(); // clear our own (don't close on destruction) - secinfo("socks", "%d socks received from %s", receiver.fd(), string(reply.address()).c_str()); -} - - -// -// Construct a request from an IPv4 address and port -// -Message::Message(Command cmd, IPAddress addr, IPPort port) -{ - version = 5; - message = cmd; - reserved = 0; - addressType = socksIPv4; - this->addr = addr; - this->port = htons(port); - length = 4 + sizeof(this->addr) + sizeof(this->port); -} - - -// -// Construct a request from a hostname and port (server resolves name) -// -Message::Message(Command cmd, const char *hostname, IPPort port) -{ - version = 5; - message = cmd; - reserved = 0; - addressType = socksName; - - size_t nameLength = strlen(hostname); - if (nameLength > 255) - UnixError::throwMe(ENAMETOOLONG); - char *addrp = reinterpret_cast(&addr); - addrp[0] = nameLength; - memcpy(addrp + 1, hostname, nameLength); - IPPort nboPort = htons(port); - memcpy(addrp + 1 + nameLength, &nboPort, sizeof(nboPort)); - length = 4 + 1 + nameLength + sizeof(nboPort); -} - - -// -// Send a completed request message -// -void Message::send(Socket &s) -{ - if (s.write(this, length) != length) { - s.close(); - UnixError::throwMe(EIO); - } -} - - -// -// Construct a reply object from a socket source. -// Throws exceptions if the reply is not successful and supported. -// -Message::Message(Socket &socket) -{ - length = 4 + sizeof(addr) + sizeof(port); //@@@ calculate if addrType != 1 supported - - if (socket.read(this, length) != length) { - socket.close(); - UnixError::throwMe(EIO); - } - - // check error code - switch (message) { - case socksSuccess: - break; - case socksDenied: - UnixError::throwMe(EPERM); - case socksNetUnreach: - UnixError::throwMe(ENETUNREACH); - case socksHostUnreach: - UnixError::throwMe(EHOSTUNREACH); - case socksConRefused: - UnixError::throwMe(ECONNREFUSED); - case socksTTLExpired: - UnixError::throwMe(ETIMEDOUT); // not really, but what's better? - case socksUnsupported: - UnixError::throwMe(EOPNOTSUPP); - case socksAddressNotSupported: - UnixError::throwMe(EADDRNOTAVAIL); - default: - UnixError::throwMe(EIO); // what else? :-) - } - - // can't deal with non-IPv4 address replies - if (addressType != socksIPv4 || reserved != 0) - UnixError::throwMe(ENOTSUP); -} - - -} // end namespace Socks -} // end namespace IPPlusPlus -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/socks++5.h b/OSX/libsecurity_utilities/lib/socks++5.h deleted file mode 100644 index 5bcb9129..00000000 --- a/OSX/libsecurity_utilities/lib/socks++5.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2000-2001,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@ - */ - - -// -// socks++5 - version 5 Socks protocol -// -#ifndef _H_SOCKSPLUSPLUS5 -#define _H_SOCKSPLUSPLUS5 - -#include "socks++.h" - - -namespace Security { -namespace IPPlusPlus { -namespace Socks5 { - - -typedef unsigned char Byte; - - -class Server : public SocksServer { -public: - Server(const IPSockAddress &s) : SocksServer(5, s) { } - - virtual void connect(SocksClientSocket &me, const IPSockAddress &peer); - virtual void connect(SocksClientSocket &me, const Host &host, IPPort port); - virtual void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port); - virtual void receive(SocksServerSocket &me, SocksClientSocket &receiver); - -private: - void open(Socket &s, Support &me); -}; - - -// request code (message field outbound) -enum Command { - socksConnect = 1, // connect (outbound) - socksBind = 2, // bind (single inbound) - socksUDP = 3 // UDP associate (not implemented) -}; - -// reply code (message field inbound) -enum SocksReply { - socksSuccess = 0, - socksFailed = 1, - socksDenied = 2, - socksNetUnreach = 3, - socksHostUnreach = 4, - socksConRefused = 5, - socksTTLExpired = 6, - socksUnsupported = 7, - socksAddressNotSupported = 8 -}; - -// authentication type (in setup request) -enum AuthenticationType { - socksAuthPublic = 0, // anonymous access - socksAuthGSSAPI = 1, // GSSAPI (yuk) - socksAuthUsername = 2, // username/password - socksAuthNoneAcceptable = 0xff // can't help you there... -}; - -// address types (inbound/outbound) -enum AddressType { - socksIPv4 = 1, - socksName = 3, - socksIPv6 = 4 -}; - - -// -// A Message object contains a single request or reply of the Socks5 protocol. -// Since some of the data is dynamically sized, we have to fudge a bit. The static -// layout corresponds to IPv4 addresses, the common case. The object itself is big -// enough for all cases. -// -struct Message { - Byte version; // Socks version - Byte message; // message/reply - Byte reserved; // not used (zero) - Byte addressType; // address type - IPAddress addr; // address starts here (IPv4 case) - // following fields dynamically located if (addressType != socksIPv4) - IPPort port; // port field IF addr is IPv4 - Byte pad[256-sizeof(IPAddress)-sizeof(IPPort)]; // enough room for type 3 addresses (256 bytes) - - // the following fields are not part of the message data - size_t length; // calculated length of message (bytes, starting at version) - - Message(Command cmd, IPAddress addr, IPPort port); // type 1 request - Message(Command cmd, const char *hostname, IPPort port); // type 3 request - void send(Socket &s); // send request - - Message(Socket &socket); // receive (type 1 only) - - IPSockAddress address() const { return IPSockAddress(addr, ntohs(port)); } -}; - - -} // end namespace Socks -} // end namespace IPPlusPlus -} // end namespace Security - -#endif //_H_SOCKSPLUSPLUS5 diff --git a/OSX/libsecurity_utilities/lib/sqlite++.cpp b/OSX/libsecurity_utilities/lib/sqlite++.cpp index 4a5e05e8..12e030d8 100644 --- a/OSX/libsecurity_utilities/lib/sqlite++.cpp +++ b/OSX/libsecurity_utilities/lib/sqlite++.cpp @@ -26,6 +26,7 @@ #include "sqlite++.h" #include #include +#include //@@@ diff --git a/OSX/libsecurity_utilities/lib/transactions.cpp b/OSX/libsecurity_utilities/lib/transactions.cpp index be165b5a..fea4b0da 100644 --- a/OSX/libsecurity_utilities/lib/transactions.cpp +++ b/OSX/libsecurity_utilities/lib/transactions.cpp @@ -35,13 +35,13 @@ TransactionBase::Outcome TransactionBase::finalOutcome() const { switch (mOutcome) { case successful: - case cancelled: + case canceled: return mOutcome; case conditional: - return std::uncaught_exception() ? cancelled : successful; + return std::uncaught_exception() ? canceled : successful; default: assert(false); - return cancelled; + return canceled; } } diff --git a/OSX/libsecurity_utilities/lib/transactions.h b/OSX/libsecurity_utilities/lib/transactions.h index dc236a5b..c82a76a1 100644 --- a/OSX/libsecurity_utilities/lib/transactions.h +++ b/OSX/libsecurity_utilities/lib/transactions.h @@ -43,8 +43,8 @@ public: // what happens if this object gets destroyed? enum Outcome { successful, // succeeds as set - cancelled, // cancelled (rolled back) - conditional // succeeds normally, cancelled on exception + canceled, // canceled (rolled back) + conditional // succeeds normally, canceled on exception }; public: @@ -84,7 +84,7 @@ public: case successful: this->commitAction(); break; - case cancelled: + case canceled: this->cancelAction(); break; default: diff --git a/OSX/libsecurity_utilities/lib/typedvalue.h b/OSX/libsecurity_utilities/lib/typedvalue.h deleted file mode 100644 index 5f7d2298..00000000 --- a/OSX/libsecurity_utilities/lib/typedvalue.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2000-2001,2003-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@ - */ - - -// -// typedvalue - type-safe reference transmission of arbitrary types. -// -// This slight-of-hand pair of classes allows arbitrary types to be passed through an API -// without losing C++ type safety. Specifically, the type is encapsulated in C++ polymorphism, -// and can be resolved through the C++ typeinfo/dynamic_cast system in a fairly -// convenient way. This is intended to replace passing (void *) arguments around. -// It is obviously not meant to replace proper class hierarchies in APIs. -// -#ifndef _H_TYPEDVALUE -#define _H_TYPEDVALUE - -#include -#include - - -namespace Security { - - -// -// A GenericValue can represent any (one) type. Note the template assignment -// that works *only* for the type it actually represents. Note particularly that -// no automatic conversions are made (other than to subclass). -// -class GenericValue { -public: - virtual ~GenericValue(); - - template - void operator = (const V &value); -}; - - -// -// A TypedValue is a particular typed instance of a GenericValue -// -template -class TypedValue : public GenericValue { -public: - TypedValue() : mValue() { } - TypedValue(const Value &v) : mValue(v) { } - Value &value() { return mValue; } - operator Value &() { return mValue; } - void operator = (const Value &value) { mValue = value; } - -private: - Value mValue; -}; - - -// -// The polymorphic assignment access method -// -template -void GenericValue::operator = (const Value &value) -{ safer_cast &>(*this) = value; } - - -} // end namespace Security - - -#endif //_H_TYPEDVALUE diff --git a/OSX/libsecurity_utilities/lib/unix++.cpp b/OSX/libsecurity_utilities/lib/unix++.cpp index d3ee98e7..225e8150 100644 --- a/OSX/libsecurity_utilities/lib/unix++.cpp +++ b/OSX/libsecurity_utilities/lib/unix++.cpp @@ -71,6 +71,29 @@ void FileDesc::close() } } +void FileDesc::closeAndLog() +{ + int result = 0; + int retryCount = 2; + int error = 0; + if (mFd >= 0) { + while((result = ::close(mFd)) == -1 && retryCount) { + error = errno; + switch (error) { + case EINTR: + case EIO: + retryCount --; + break; + default: + secinfo("unixio", "close(%d) error %d", mFd, error); + retryCount = 0; + break; + } + } + secinfo("unixio", "close(%d) err: %d", mFd, error); + mFd = invalidFd; + } +} // // Filedescoid operations @@ -449,11 +472,19 @@ FILE *FileDesc::fdopen(const char *form) return ::fdopen(mFd, form); } +AutoFileDesc::AutoFileDesc(const AutoFileDesc& rhs) +{ + if (rhs.fd() != invalidFd) { + checkSetFd(::dup(rhs.fd())); + } + mAtEnd = rhs.mAtEnd; +} + // // Device characteristics // -static CFDictionaryRef deviceCharacteristics(FileDesc &fd) +static CFDictionaryRef CF_RETURNS_RETAINED deviceCharacteristics(FileDesc &fd) { // get device name FileDesc::UnixStat st; diff --git a/OSX/libsecurity_utilities/lib/unix++.h b/OSX/libsecurity_utilities/lib/unix++.h index d51a6146..b41ccd7d 100644 --- a/OSX/libsecurity_utilities/lib/unix++.h +++ b/OSX/libsecurity_utilities/lib/unix++.h @@ -90,6 +90,7 @@ protected: void checkSetFd(int fd) { checkError(fd); mFd = fd; mAtEnd = false; } FileDesc(int fd, bool atEnd) : mFd(fd), mAtEnd(atEnd) { } + void closeAndLog(); // close and clear without throwing public: FileDesc() : mFd(invalidFd), mAtEnd(false) { } @@ -114,7 +115,7 @@ public: void clear() { mFd = invalidFd; } void close(); // close and clear - + void open(const char *path, int flag = O_RDONLY, mode_t mode = 0666); void open(const std::string &path, int flag = O_RDONLY, mode_t mode = 0666) { this->open(path.c_str(), flag, mode); } @@ -271,8 +272,8 @@ public: : FileDesc(path, flag, mode) { } AutoFileDesc(const std::string &path, int flag = O_RDONLY, mode_t mode = 0666) : FileDesc(path, flag, mode) { } - - ~AutoFileDesc() { close(); } + AutoFileDesc(const AutoFileDesc& rhs); + ~AutoFileDesc() { closeAndLog(); } }; @@ -335,8 +336,8 @@ public: // void makedir(const char *path, int flags, mode_t mode = 0777); -int ffprintf(const char *path, int flags, mode_t mode, const char *format, ...); -int ffscanf(const char *path, const char *format, ...); +int ffprintf(const char *path, int flags, mode_t mode, const char *format, ...) __attribute__((format(printf, 4, 5))); +int ffscanf(const char *path, const char *format, ...) __attribute__((format(scanf, 2, 3))); } // end namespace UnixPlusPlus diff --git a/OSX/libsecurity_utilities/lib/url.cpp b/OSX/libsecurity_utilities/lib/url.cpp deleted file mode 100644 index 3916bbae..00000000 --- a/OSX/libsecurity_utilities/lib/url.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// url - URL object with decomposition -// -#include "url.h" -#include -#include -#include -#include - - -namespace Security { -namespace Network { - - -// -// Turn a CFStringRef into an STL string and release the incoming CFStringRef -// -static string mkstr(CFStringRef CF_CONSUMED str) -{ - if (!str) - return ""; - char buffer[2048]; - if (CFStringGetCString(str, buffer, sizeof(buffer), kCFStringEncodingUTF8)) { - CFReleaseSafe(str); - return buffer; - } else - UnixError::throwMe(EINVAL); -} - - -// -// Construction -// -URL::URL() -{ - ref = NULL; -} - -URL::URL(const char *s) -{ - ref = CFURLCreateWithBytes(NULL, (const UInt8 *)s, strlen(s), kCFStringEncodingUTF8, NULL); - if (!ref) - UnixError::throwMe(EINVAL); -} - -URL::URL(const char *s, const URL &base) -{ - ref = CFURLCreateWithBytes(NULL, (const UInt8 *)s, strlen(s), kCFStringEncodingUTF8, base.ref); - if (!ref) - UnixError::throwMe(EINVAL); -} - -URL::~URL() -{ - if (ref) - CFRelease(ref); -} - - -// -// Extraction: These methods produce UTF8 strings -// -URL::operator string() const -{ - return mkstr(CFRetainSafe(CFURLGetString(ref))); -} - -string URL::scheme() const -{ - return mkstr(CFURLCopyScheme(ref)); -} - -string URL::host() const -{ - return mkstr(CFURLCopyHostName(ref)); -} - -IPPort URL::port(IPPort defaultPort) const -{ - SInt32 port = CFURLGetPortNumber(ref); - return (port == -1) ? defaultPort : port; -} - -string URL::username() const -{ - return mkstr(CFURLCopyUserName(ref)); -} - -string URL::password() const -{ - return mkstr(CFURLCopyPassword(ref)); -} - -string URL::path() const -{ - Boolean isAbsolute; - return "/" + mkstr(CFURLCopyStrictPath(ref, &isAbsolute)); -} - -string URL::resourceSpec() const -{ - return mkstr(CFURLCopyResourceSpecifier(ref)); -} - -string URL::fullPath() const -{ - return path() + resourceSpec(); -} - -string URL::basename() const -{ - return mkstr(CFURLCopyLastPathComponent(ref)); -} - -string URL::extension() const -{ - return mkstr(CFURLCopyPathExtension(ref)); -} - -void URL::recreateURL(const char* url) -{ - if(ref) - CFRelease(ref); - ref = CFURLCreateWithBytes(NULL, (const UInt8 *)url, strlen(url), kCFStringEncodingUTF8, NULL); -} - -} // end namespace Network -} // end namespace Security diff --git a/OSX/libsecurity_utilities/lib/url.h b/OSX/libsecurity_utilities/lib/url.h deleted file mode 100644 index d038a903..00000000 --- a/OSX/libsecurity_utilities/lib/url.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2000-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@ - */ - - -// -// url - URL object with decomposition -// -// This is a wrapper around CoreFoundation CFURL objects, -// without any attempt at re-interpretation (other than cleaning -// up the obvious CFishness). -// -#ifndef _H_URL -#define _H_URL - -#include -#include "ip++.h" - - -struct __CFURL; -using IPPlusPlus::IPPort; - - -namespace Security { -namespace Network { - - -// -// A thin encapsulation of a URL -// -class URL { -public: - URL(); - URL(const char *url); - URL(const char *url, const URL &base); - ~URL(); - - operator string() const; - - string scheme() const; - string host() const; - IPPort port(IPPort defaultPort = 0) const; - string path() const; - string resourceSpec() const; - string fullPath() const; - - string username() const; - string password() const; - string basename() const; - string extension() const; - - void recreateURL(const char* url); - -private: - const __CFURL *ref; -}; - - -} // end namespace Network -} // end namespace Security - - -#endif /* _H_URL */ diff --git a/OSX/libsecurity_utilities/lib/vproc++.cpp b/OSX/libsecurity_utilities/lib/vproc++.cpp index 721c7566..62d1758b 100644 --- a/OSX/libsecurity_utilities/lib/vproc++.cpp +++ b/OSX/libsecurity_utilities/lib/vproc++.cpp @@ -27,10 +27,12 @@ // #include "vproc++.h" #include +#include +#include #include +#include #include - namespace Security { namespace VProc { @@ -48,7 +50,11 @@ void Transaction::activate() // size_t Transaction::debugCount() { +#if TARGET_OS_OSX return ::_vproc_transaction_count(); +#else + MacOSError::throwMe(errSecUnimplemented); +#endif } diff --git a/OSX/libsecurityd/lib/dictionary.cpp b/OSX/libsecurityd/lib/dictionary.cpp index 9b26f58c..a54970ab 100644 --- a/OSX/libsecurityd/lib/dictionary.cpp +++ b/OSX/libsecurityd/lib/dictionary.cpp @@ -80,7 +80,7 @@ NameValuePair::NameValuePair (const CssmData &data) NameValuePair::~NameValuePair () { - delete (unsigned char*) mValue.data (); + delete[] (unsigned char*) mValue.data (); } diff --git a/OSX/libsecurityd/lib/eventlistener.cpp b/OSX/libsecurityd/lib/eventlistener.cpp index 8c768b87..efe37a67 100644 --- a/OSX/libsecurityd/lib/eventlistener.cpp +++ b/OSX/libsecurityd/lib/eventlistener.cpp @@ -127,6 +127,7 @@ static bool InitializeNotifications () { { StLock lock (gNotificationLock ()); EventListenerList& eventList = gEventListeners(); + std::set processedListeners; // route the message to its destination u_int32_t* ptr = (u_int32_t*) buffer; @@ -141,20 +142,34 @@ static bool InitializeNotifications () { EventListenerList::iterator it = eventList.begin (); while (it != eventList.end ()) { - try - { - EventPointer ep = *it++; - if (ep->GetDomain () == domain && - (ep->GetMask () & (1 << event)) != 0) - { - ep->consume (domain, event, data); - } + EventPointer ep = *it++; + /* + * We can't hold the global event lock when processing callback handers + * so remember what items we have processes and don't process them again. + * and when we have done a callback we loop back and try again. + */ + if (processedListeners.find(&ep) != processedListeners.end()) { + continue; } - catch (CssmError &e) - { + processedListeners.insert(&ep); + + /* is this event for this Event handler */ + if (ep->GetDomain() != domain || (ep->GetMask() & (1 << event)) == 0) + continue; + + lock.unlock(); + + try { + ep->consume (domain, event, data); + } catch (CssmError &e) { // If we throw, libnotify will abort the process. Log these... secerror("caught CssmError while processing notification: %d %s", e.error, cssmErrorString(e.error)); } + lock.lock(); + /* + * If we have to grab the lock again, start over iteration + */ + it = eventList.begin (); } } diff --git a/OSX/libsecurityd/lib/ssclient.cpp b/OSX/libsecurityd/lib/ssclient.cpp index 444247aa..76853a35 100644 --- a/OSX/libsecurityd/lib/ssclient.cpp +++ b/OSX/libsecurityd/lib/ssclient.cpp @@ -101,7 +101,6 @@ void ClientSession::activate() } } - // // The contactName method allows the caller to explicitly override the bootstrap // name under which SecurityServer is located. Use this only with great caution, @@ -131,7 +130,7 @@ ClientSession::Global::Global() serverPort = findSecurityd(); mach_port_t originPort = MACH_PORT_NULL; - IPCN(ucsp_client_verifyPrivileged2(serverPort.port(), mig_get_reply_port(), &securitydCreds, &rcode, &originPort)); + IPCBASIC(ucsp_client_verifyPrivileged2(serverPort.port(), mig_get_reply_port(), &securitydCreds, &rcode, &originPort)); if (originPort != serverPort.port()) CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE); mach_port_mod_refs(mach_task_self(), originPort, MACH_PORT_RIGHT_SEND, -1); @@ -143,7 +142,7 @@ ClientSession::Global::Global() // cannot use UCSP_ARGS here because it uses mGlobal() -> deadlock Thread &thread = this->thread(); - IPCN(ucsp_client_setup(serverPort, thread.replyPort, &securitydCreds, &rcode, + IPCBASIC(ucsp_client_setup(serverPort, thread.replyPort, &securitydCreds, &rcode, mach_task_self(), info, extForm)); thread.registered = true; // as a side-effect of setup call above IFDEBUG(serverPort.requestNotify(thread.replyPort)); diff --git a/OSX/libsecurityd/lib/sstransit.h b/OSX/libsecurityd/lib/sstransit.h index 1881c7ef..cf5c37a2 100644 --- a/OSX/libsecurityd/lib/sstransit.h +++ b/OSX/libsecurityd/lib/sstransit.h @@ -42,18 +42,40 @@ namespace SecurityServer { #define UCSP_ARGS mGlobal().serverPort, mGlobal().thread().replyPort, &securitydCreds, &rcode // common invocation profile (don't use directly) -#define IPCSTART(statement) \ - CSSM_RETURN rcode; security_token_t securitydCreds; check(statement) -#define IPCEND \ +#define IPCSTART \ + CSSM_RETURN rcode = CSSM_ERRCODE_INTERNAL_ERROR; security_token_t securitydCreds = {}; +#define IPCEVAL(statement) check(statement) +#define IPCEVALRESET(statement) { \ + kern_return_t r = statement; \ + if(r == MACH_SEND_INVALID_DEST) { \ + ClientSession::reset(); \ + } \ + check(r); \ +} + +#define IPC_CHECK_VALIDITY \ if (securitydCreds.val[0] != 0 IFDEBUG( && !getenv("SECURITYSERVER_NONROOT"))) \ CssmError::throwMe(CSSM_ERRCODE_VERIFICATION_FAILURE) -#define IPCEND_CHECK IPCEND; if (rcode != CSSM_OK) CssmError::throwMe(rcode); +#define IPC_CHECK_RETCODE if (rcode != CSSM_OK) CssmError::throwMe(rcode); + +#define IPCBASIC(statement) { \ + IPCSTART \ + IPCEVAL(statement); \ + IPC_CHECK_VALIDITY; \ + IPC_CHECK_RETCODE; \ +} #define IPCN(statement) { \ - IPCSTART(statement); IPCEND_CHECK; \ - } + IPCSTART \ + IPCEVALRESET(statement); \ + IPC_CHECK_VALIDITY; \ + IPC_CHECK_RETCODE; \ +} #define IPC(statement) { activate(); IPCN(statement); } #define IPCKEY(statement, key, tag) { \ - activate(); IPCSTART(statement); IPCEND; \ + IPCSTART \ + activate(); \ + IPCEVALRESET(statement); \ + IPC_CHECK_VALIDITY; \ switch (rcode) { \ case CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT: \ notifyAclChange(key, tag); \ diff --git a/OSX/regressions/test/testcert.c b/OSX/regressions/test/testcert.c index 79365167..bdfd11cc 100644 --- a/OSX/regressions/test/testcert.c +++ b/OSX/regressions/test/testcert.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009,2012-2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2009,2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,8 +25,6 @@ #include -#if TARGET_OS_IPHONE - #include #include #include @@ -170,5 +168,3 @@ test_cert_generate_key(uint32_t key_size_in_bits, CFTypeRef sec_attr_key_type, return SecKeyGeneratePair(parameters, public_key, private_key); } - -#endif /* TARGET_OS_IPHONE */ diff --git a/OSX/regressions/test/testenv.m b/OSX/regressions/test/testenv.m index 81f8d596..e6a96cd3 100644 --- a/OSX/regressions/test/testenv.m +++ b/OSX/regressions/test/testenv.m @@ -53,6 +53,7 @@ #include +#include "keychain/ckks/CKKS.h" int test_strict_bats = 1; int test_verbose = 0; @@ -126,8 +127,10 @@ static int tests_init(void) { error:&error], "Failed to make %@: %@", preferencesURL, error); - if (ok > 0) + if (ok > 0) { securityd_init((__bridge CFURLRef) tmpDirURL); + SecCKKSDisable(); + } #endif diff --git a/OSX/regressions/test/testmore.c b/OSX/regressions/test/testmore.c index 92922202..bb36f8df 100644 --- a/OSX/regressions/test/testmore.c +++ b/OSX/regressions/test/testmore.c @@ -62,9 +62,9 @@ static void fprint_string(FILE *file, CFStringRef string) { } } -static void cffprint(FILE *file, CFStringRef fmt, ...) CF_FORMAT_FUNCTION(2,0); +static void cffprint(FILE *file, CFStringRef fmt, ...) CF_FORMAT_FUNCTION(2,3); -static void cffprint_v(FILE *file, CFStringRef fmt, va_list args); +static void cffprint_v(FILE *file, CFStringRef fmt, va_list args) CF_FORMAT_FUNCTION(2,0); static void cffprint_c_v(FILE *file, const char *fmt, va_list args); static void cffprint_v(FILE *file, CFStringRef fmt, va_list args) { @@ -73,12 +73,18 @@ static void cffprint_v(FILE *file, CFStringRef fmt, va_list args) { CFRelease(line); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" + static void cffprint_c_v(FILE *file, const char *fmt, va_list args) { CFStringRef cffmt = CFStringCreateWithCString(kCFAllocatorDefault, fmt, kCFStringEncodingUTF8); cffprint_v(file, cffmt, args); CFRelease(cffmt); } +#pragma clang diagnostic pop + + static void cffprint(FILE *file, CFStringRef fmt, ...) { va_list args; va_start(args, fmt); @@ -133,6 +139,8 @@ static int test_plan_pass(void) { return 0; } +static int test_plan_fail(CFStringRef reason, ...) CF_FORMAT_FUNCTION(1, 2); + static int test_plan_fail(CFStringRef reason, ...) { const char *name = test_plan_name(); va_list ap; diff --git a/OSX/regressions/test/testmore.h b/OSX/regressions/test/testmore.h index 6a776f78..7bf5e726 100644 --- a/OSX/regressions/test/testmore.h +++ b/OSX/regressions/test/testmore.h @@ -164,6 +164,12 @@ static void test_failed_noreturn() __attribute((analyzer_noreturn)) { #define plan_skip_all(REASON) test_plan_skip_all(REASON) #define plan_tests(COUNT) test_plan_tests(COUNT, __FILE__, __LINE__) +#define test_IsTrue(THIS, ...) ok(THIS, __VA_ARGS__) +#define test_IsEqual(THIS, THAT, ...) is(THIS, THAT, __VA_ARGS__) +#define test_IsNotEqual(THIS, THAT, ...) isnt(THIS, THAT, __VA_ARGS__) +#define test_Pass(...) pass(__VA_ARGS__) +#define test_Fail(...) fail(__VA_ARGS__) + #define ok_status(THIS, ...) \ ({ \ OSStatus _this = THIS; \ @@ -214,7 +220,7 @@ extern const char *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, ...); + 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); diff --git a/OSX/sec/CloudKeychainProxy/CloudKeychainProxy.1 b/OSX/sec/CloudKeychainProxy/CloudKeychainProxy.1 deleted file mode 100644 index 9cbfd792..00000000 --- a/OSX/sec/CloudKeychainProxy/CloudKeychainProxy.1 +++ /dev/null @@ -1,79 +0,0 @@ -.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. -.\"See Also: -.\"man mdoc.samples for a complete listing of options -.\"man mdoc for the short list of editing options -.\"/usr/share/misc/mdoc.template -.Dd 12/20/12 \" DATE -.Dt CloudKeychainProxy 1 \" Program name and manual section number -.Os Darwin -.Sh NAME \" Section Header - required - don't modify -.Nm CloudKeychainProxy, -.\" The following lines are read in generating the apropos(man -k) database. Use only key -.\" words here as the database is built based on the words here and in the .ND line. -.Nm Other_name_for_same_program(), -.Nm Yet another name for the same program. -.\" Use .Nm macro to designate other names for the documented program. -.Nd This line parsed for whatis database. -.Sh SYNOPSIS \" Section Header - required - don't modify -.Nm -.Op Fl abcd \" [-abcd] -.Op Fl a Ar path \" [-a path] -.Op Ar file \" [file] -.Op Ar \" [file ...] -.Ar arg0 \" Underlined argument - use .Ar anywhere to underline -arg2 ... \" Arguments -.Sh DESCRIPTION \" Section Header - required - don't modify -Use the .Nm macro to refer to your program throughout the man page like such: -.Nm -Underlining is accomplished with the .Ar macro like this: -.Ar underlined text . -.Pp \" Inserts a space -A list of items with descriptions: -.Bl -tag -width -indent \" Begins a tagged list -.It item a \" Each item preceded by .It macro -Description of item a -.It item b -Description of item b -.El \" Ends the list -.Pp -A list of flags and their descriptions: -.Bl -tag -width -indent \" Differs from above in tag removed -.It Fl a \"-a flag as a list item -Description of -a flag -.It Fl b -Description of -b flag -.El \" Ends the list -.Pp -.\" .Sh ENVIRONMENT \" May not be needed -.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 -.\" .It Ev ENV_VAR_1 -.\" Description of ENV_VAR_1 -.\" .It Ev ENV_VAR_2 -.\" Description of ENV_VAR_2 -.\" .El -.Sh FILES \" File used or created by the topic of the man page -.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact -.It Pa /usr/share/file_name -FILE_1 description -.It Pa /Users/joeuser/Library/really_long_file_name -FILE_2 description -.El \" Ends the list -.\" .Sh DIAGNOSTICS \" May not be needed -.\" .Bl -diag -.\" .It Diagnostic Tag -.\" Diagnostic informtion here. -.\" .It Diagnostic Tag -.\" Diagnostic informtion here. -.\" .El -.Sh SEE ALSO -.\" List links in ascending order by section, alphabetically within a section. -.\" Please do not reference files that do not exist without filing a bug report -.Xr a 1 , -.Xr b 1 , -.Xr c 1 , -.Xr a 2 , -.Xr b 2 , -.Xr a 3 , -.Xr b 3 -.\" .Sh BUGS \" Document known, unremedied bugs -.\" .Sh HISTORY \" Document history if command behaves in a unique manner \ No newline at end of file diff --git a/OSX/sec/CloudKeychainProxy/CloudKeychainProxy.8 b/OSX/sec/CloudKeychainProxy/CloudKeychainProxy.8 new file mode 100644 index 00000000..063cb220 --- /dev/null +++ b/OSX/sec/CloudKeychainProxy/CloudKeychainProxy.8 @@ -0,0 +1,9 @@ +.Dd November 02, 2016 +.Dt CloudKeychainProxy 8 +.Os +.Sh NAME +.Nm CloudKeychainProxy +.Nd part of iCloud keychain syncing +.Sh DESCRIPTION +.Nm +part of iCloud keychain syncing. diff --git a/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.c b/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.c index 5886d732..dcce498e 100644 --- a/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.c +++ b/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.c @@ -28,7 +28,7 @@ /* This XPC service is essentially just a proxy to iCloud KVS, which exists since - the main security code cannot link against Foundation. + at one time the main security code could not link against Foundation. See sendTSARequestWithXPC in tsaSupport.c for how to call the service @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -53,7 +54,6 @@ #include "SOSCloudKeychainConstants.h" #include "SOSCloudKeychainClient.h" -#include "SOSKVSKeys.h" #include "SOSUserKeygen.h" #include "SecOTRSession.h" @@ -262,36 +262,74 @@ static bool xpc_event_filter(const xpc_connection_t peer, xpc_object_t event, CF return false; } -static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport) +static void setupIDSProxyServiceConnection(SOSXPCCloudTransportRef transport) { - secdebug(SOSCKCSCOPE, "initXPCConnection\n"); - - transport->xpc_queue = dispatch_queue_create(xpcServiceName, DISPATCH_QUEUE_SERIAL); + secnotice(SOSCKCSCOPE, "IDS Transport: setting up xpc connection"); + transport->idsProxyServiceConnection = xpc_connection_create_mach_service(xpcIDSServiceName, transport->xpc_queue, 0); - transport->serviceConnection = xpc_connection_create_mach_service(xpcServiceName, transport->xpc_queue, 0); + secdebug(SOSCKCSCOPE, "ids service connection: %p\n", transport->idsProxyServiceConnection); + xpc_connection_set_event_handler(transport->idsProxyServiceConnection, ^(xpc_object_t event) { + secdebug(SOSCKCSCOPE, "IDS Transport, xpc_connection_set_event_handler\n"); + if(event == XPC_ERROR_CONNECTION_INVALID){ + secnotice(SOSCKCSCOPE, "IDS Transport: xpc connection invalid. Oh well."); + } + }); + xpc_connection_activate(transport->idsProxyServiceConnection); + xpc_retain(transport->idsProxyServiceConnection); +} + +static void teardownIDSProxyServiceConnection(SOSXPCCloudTransportRef transport) +{ + secnotice(SOSCKCSCOPE, "IDS Transport: tearing down xpc connection"); + xpc_release(transport->idsProxyServiceConnection); + transport->idsProxyServiceConnection = NULL; +} + +static void setupServiceConnection(SOSXPCCloudTransportRef transport) +{ + secnotice(SOSCKCSCOPE, "CKP Transport: setting up xpc connection"); + transport->serviceConnection = xpc_connection_create_mach_service(xpcServiceName, transport->xpc_queue, 0); + secdebug(SOSCKCSCOPE, "serviceConnection: %p\n", transport->serviceConnection); - - - xpc_connection_set_event_handler(transport->serviceConnection, ^(xpc_object_t event) - { - secdebug(SOSCKCSCOPE, "xpc_connection_set_event_handler\n"); - }); - - xpc_connection_resume(transport->serviceConnection); + + xpc_connection_set_event_handler(transport->serviceConnection, ^(xpc_object_t event) { + secdebug(SOSCKCSCOPE, "CKP Transport, xpc_connection_set_event_handler\n"); + if(event == XPC_ERROR_CONNECTION_INVALID){ + secnotice(SOSCKCSCOPE, "CKP Transport: xpc connection invalid. Oh well."); + } + }); + + xpc_connection_activate(transport->serviceConnection); xpc_retain(transport->serviceConnection); +} + +static void teardownServiceConnection(SOSXPCCloudTransportRef transport) +{ + secnotice(SOSCKCSCOPE, "CKP Transport: tearing down xpc connection"); + xpc_release(transport->serviceConnection); + transport->serviceConnection = NULL; +} + +static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport) +{ + secdebug(SOSCKCSCOPE, "initXPCConnection\n"); - transport->idsProxyServiceConnection = xpc_connection_create_mach_service(xpcIDSServiceName, transport->xpc_queue, 0); + transport->xpc_queue = dispatch_queue_create(xpcServiceName, DISPATCH_QUEUE_SERIAL); - secdebug(SOSCKCSCOPE, "ids service connection: %p\n", transport->idsProxyServiceConnection); - - xpc_connection_set_event_handler(transport->idsProxyServiceConnection, ^(xpc_object_t object) { - secdebug(SOSCKCSCOPE, "IDS Transport, xpc_connection_set_event_handler\n"); + setupServiceConnection(transport); + setupIDSProxyServiceConnection(transport); + + // Any time a new session starts, reestablish the XPC connections. + int token; + notify_register_dispatch("com.apple.system.loginwindow.desktopUp", &token, transport->xpc_queue, ^(int token2) { + secnotice(SOSCKCSCOPE, "CKP/IDS Transport: desktopUp happened, reestablishing xpc connections"); + teardownServiceConnection(transport); + setupServiceConnection(transport); + teardownIDSProxyServiceConnection(transport); + setupIDSProxyServiceConnection(transport); }); - xpc_connection_resume(transport->idsProxyServiceConnection); - xpc_retain(transport->idsProxyServiceConnection); - } static void talkWithIDS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) @@ -525,6 +563,18 @@ static void SOSCloudTransportGetIDSDeviceID(SOSCloudTransportRef transport, Clou xpc_release(message); } +static void SOSCloudTransportGetPerformanceStats(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) +{ + SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport; + + xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion); + xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGetIDSPerfCounters); + + talkWithIDS(xpcTransport, message, processQueue, replyBlock); + xpc_release(message); +} + static void SOSCloudTransportSendFragmentedIDSMessage(SOSCloudTransportRef transport, CFDictionaryRef messageData, CFStringRef deviceName, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){ SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport; @@ -617,6 +667,25 @@ static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport, xpc_release(xkeysOfInterest); } +static void SOSCloudTransportRemoveKeys(SOSCloudTransportRef transport, + CFArrayRef keys, + CFStringRef accountUUID, + dispatch_queue_t processQueue, + CloudKeychainReplyBlock replyBlock) +{ + SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport; + + xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion); + + xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRemoveKeys); + SecXPCDictionarySetCFObject(message, kMessageKeyAccountUUID, accountUUID); + SecXPCDictionarySetCFObject(message, kMessageKeyValue, keys); + + talkWithKVS(xpcTransport, message, processQueue, replyBlock); + xpc_release(message); +} + static void SOSCloudTransportGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) { secdebug(SOSCKCSCOPE, "start"); @@ -751,6 +820,21 @@ static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef xpc_release(xpcmessage); } +static void SOSCloudTransportRequestPerfCounters(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) +{ + secdebug(SOSCKCSCOPE, "start"); + SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport; + + xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion); + xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationPerfCounters); + + talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock); + + xpc_release(xpcmessage); +} + + static void SOSCloudTransportFlush(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) { secdebug(SOSCKCSCOPE, "start"); @@ -785,8 +869,11 @@ static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void) st->transport.hasPeerSyncPending = SOSCloudTransportHasPeerSyncPending; st->transport.hasPendingKey = SOSCloudTransportHasPendingKey; st->transport.requestEnsurePeerRegistration = SOSCloudTransportRequestEnsurePeerRegistration; + st->transport.requestPerfCounters = SOSCloudTransportRequestPerfCounters; st->transport.getIDSDeviceAvailability = SOSCloudTransportCheckIDSDeviceIDAvailability; st->transport.flush = SOSCloudTransportFlush; + st->transport.removeKeys = SOSCloudTransportRemoveKeys; + st->transport.counters = SOSCloudTransportGetPerformanceStats; st->transport.itemsChangedBlock = Block_copy(^CFArrayRef(CFDictionaryRef changes) { secerror("Calling default itemsChangedBlock - fatal: %@", changes); assert(false); @@ -820,6 +907,14 @@ void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys, CFStringRef accountUUID, d cTransportRef->updateKeys(cTransportRef, keys, accountUUID, processQueue, replyBlock); } + +void SOSCloudKeychainRemoveKeys(CFArrayRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) +{ + SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); + if (cTransportRef) + cTransportRef->removeKeys(cTransportRef, keys, accountUUID, processQueue, replyBlock); +} + void SOSCloudKeychainSendIDSMessage(CFDictionaryRef message, CFStringRef deviceName, CFStringRef peerID, dispatch_queue_t processQueue, CFBooleanRef fragmentation, CloudKeychainReplyBlock replyBlock) { SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); @@ -838,6 +933,14 @@ void SOSCloudKeychainRetrievePendingMessageFromProxy(dispatch_queue_t processQue if(cTransportRef) cTransportRef->retrieveMessages(cTransportRef, processQueue, replyBlock); +} +void SOSCloudKeychainRetrieveCountersFromIDSProxy(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) +{ + SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); + + if(cTransportRef) + cTransportRef->counters(cTransportRef, processQueue, replyBlock); + } void SOSCloudKeychainGetIDSDeviceID(CloudKeychainReplyBlock replyBlock) { @@ -925,6 +1028,14 @@ void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue cTransportRef->requestEnsurePeerRegistration(cTransportRef, processQueue, replyBlock); } +void SOSCloudKeychainRequestPerfCounters(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) +{ + SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); + if (cTransportRef) + cTransportRef->requestPerfCounters(cTransportRef, processQueue, replyBlock); +} + + void SOSCloudKeychainFlush(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) { SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); diff --git a/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.h b/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.h index a33fbb89..ee8174e8 100644 --- a/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.h +++ b/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.h @@ -87,9 +87,12 @@ struct SOSCloudTransport bool (*hasPeerSyncPending)(SOSCloudTransportRef transport, CFStringRef peerID, CFErrorRef* error); void (*requestEnsurePeerRegistration)(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); + void (*requestPerfCounters)(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); void (*flush)(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); const void *itemsChangedBlock; void (*getIDSDeviceAvailability)(SOSCloudTransportRef transport, CFArrayRef ids, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); + void (*removeKeys)(SOSCloudTransportRef transport, CFArrayRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); + void (*counters)(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); }; @@ -123,10 +126,14 @@ void SOSCloudKeychainRequestSyncWithPeers(CFArrayRef /* CFStringRef */ peers, CF bool SOSCloudKeychainHasPendingSyncWithPeer(CFStringRef peerID, CFErrorRef* error); void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); +void SOSCloudKeychainRequestPerfCounters(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); void SOSCloudKeychainFlush(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); CFDictionaryRef SOSCloudCopyKVSState(void); void SOSCloudKeychainGetIDSDeviceAvailability(CFArrayRef ids, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); +void SOSCloudKeychainRemoveKeys(CFArrayRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); +void SOSCloudKeychainRetrieveCountersFromIDSProxy(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); + __END_DECLS diff --git a/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainConstants.c b/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainConstants.c index 9e69d9ef..a2099527 100644 --- a/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainConstants.c +++ b/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainConstants.c @@ -82,11 +82,16 @@ const char *kOperationSynchronizeAndWait = "SynchronizeAndWait"; const char *kOperationFlush = "Flush"; +const char *kOperationPerfCounters = "PerfCounters"; + const char *kOperationPUTDictionary = "PUTDictionary"; const char *kOperationGETv2 = "GETv2"; const char *kOperationRegisterKeys = "RegisterKeys"; +const char *kOperationRemoveKeys = "RemoveKeys"; + const char *kOperationGetDeviceID = "DeviceID"; +const char *kOperationGetIDSPerfCounters = "IDSPerf"; const char *kOperationHasPendingKey = "hasPendingKey"; diff --git a/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainConstants.h b/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainConstants.h index d374954e..e4a3c6cf 100644 --- a/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainConstants.h +++ b/OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainConstants.h @@ -72,13 +72,18 @@ extern const char *kOperationSynchronizeAndWait; extern const char *kOperationPUTDictionary; extern const char *kOperationGETv2; extern const char *kOperationRegisterKeys; +extern const char *kOperationRemoveKeys; + extern const char *kOperationGetDeviceID; extern const char *kOperationHasPendingKey; +extern const char *kOperationGetIDSPerfCounters; extern const uint64_t kCKDXPCVersion; extern const char *kOperationFlush; +extern const char *kOperationPerfCounters; + extern const char *kOperationRequestSyncWithPeers; extern const char *kOperationHasPendingSyncWithPeer; diff --git a/OSX/sec/SOSCircle/Regressions/SOSCircle_regressions.h b/OSX/sec/SOSCircle/Regressions/SOSCircle_regressions.h index ac4c888b..fb048fd4 100644 --- a/OSX/sec/SOSCircle/Regressions/SOSCircle_regressions.h +++ b/OSX/sec/SOSCircle/Regressions/SOSCircle_regressions.h @@ -2,7 +2,7 @@ 1) add it here 2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes */ -#include +#include ONE_TEST(sc_20_keynames) ONE_TEST(sc_25_soskeygen) @@ -14,7 +14,6 @@ ONE_TEST(sc_45_digestvector) ONE_TEST(sc_130_resignationticket) ONE_TEST(sc_150_Ring) -ONE_TEST(sc_140_hsa2) ONE_TEST(sc_150_backupkeyderivation) ONE_TEST(sc_153_backupslicekeybag) diff --git a/OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.h b/OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.h index 1521d074..3fdc2205 100644 --- a/OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.h +++ b/OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.h @@ -61,8 +61,8 @@ bool testClearAll(dispatch_queue_t processQueue, dispatch_group_t dgroup); CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name); -SOSPeerInfoRef SOSCreatePeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, CFErrorRef *error); -SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, CFErrorRef *error); +SOSPeerInfoRef SOSCreatePeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, SecKeyRef* outOctagonSigningKey, CFErrorRef *error); +SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, SecKeyRef* outOctagonSigningKey, CFErrorRef *error); __END_DECLS diff --git a/OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.c b/OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.m similarity index 95% rename from OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.c rename to OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.m index 75a6892d..1b3295bb 100644 --- a/OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.c +++ b/OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.m @@ -187,7 +187,6 @@ CFTypeRef testGetObjectFromCloud(CFStringRef key, dispatch_queue_t processQueue, }); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull { CFRelease(object); @@ -203,9 +202,8 @@ CFTypeRef testGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t process dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds); - dispatch_group_enter(dgroup); - + CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error) { @@ -228,7 +226,6 @@ CFTypeRef testGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t process SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull { CFRelease(object); @@ -254,7 +251,6 @@ bool testSynchronize(dispatch_queue_t processQueue, dispatch_group_t dgroup) }); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); return result; } @@ -275,7 +271,6 @@ bool testClearAll(dispatch_queue_t processQueue, dispatch_group_t dgroup) }); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); secnotice("test", "SOSCloudKeychainClearAll exit"); return result; } @@ -297,44 +292,49 @@ CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name) } -SOSPeerInfoRef SOSCreatePeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, CFErrorRef *error) +SOSPeerInfoRef SOSCreatePeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, SecKeyRef* outOctagonSigningKey, CFErrorRef *error) { SOSPeerInfoRef result = NULL; SecKeyRef publicKey = NULL; + SecKeyRef octagonPublicKey = NULL; CFDictionaryRef gestalt = NULL; require(outSigningKey, exit); require_quiet(SecError(GeneratePermanentECPair(256, &publicKey, outSigningKey), error, CFSTR("Failed To Create Key")), exit); + require_quiet(SecError(GeneratePermanentECPair(384, &octagonPublicKey, outOctagonSigningKey), error, CFSTR("Failed To Creaete Key")), exit); gestalt = SOSCreatePeerGestaltFromName(name); require(gestalt, exit); - result = SOSPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey, error); + result = SOSPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey, *outOctagonSigningKey, error); exit: CFReleaseNull(gestalt); CFReleaseNull(publicKey); + CFReleaseNull(octagonPublicKey); return result; } -SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, CFErrorRef *error) +SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, SecKeyRef* outOctagonSigningKey, CFErrorRef *error) { SOSFullPeerInfoRef result = NULL; SecKeyRef publicKey = NULL; CFDictionaryRef gestalt = NULL; require(outSigningKey, exit); - - //GeneratePermanentECPair(256, &publicKey, outSigningKey); *outSigningKey = GeneratePermanentFullECKey(256, name, error); require(*outSigningKey, exit); + + require(outOctagonSigningKey, exit); + *outOctagonSigningKey = GeneratePermanentFullECKey(384, name, error); + require(*outOctagonSigningKey, exit); gestalt = SOSCreatePeerGestaltFromName(name); require(gestalt, exit); - result = SOSFullPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey, error); + result = SOSFullPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey, *outOctagonSigningKey, error); exit: CFReleaseNull(gestalt); diff --git a/OSX/sec/SOSCircle/Regressions/SOSTestDevice.c b/OSX/sec/SOSCircle/Regressions/SOSTestDevice.c index ff8f8b8e..f803683b 100644 --- a/OSX/sec/SOSCircle/Regressions/SOSTestDevice.c +++ b/OSX/sec/SOSCircle/Regressions/SOSTestDevice.c @@ -26,7 +26,7 @@ #include "SOSTestDevice.h" #include "SOSTestDataSource.h" -#include +#include #include #include @@ -141,7 +141,7 @@ SOSTestDeviceRef SOSTestDeviceCreateWithDb(CFAllocatorRef allocator, CFStringRef SOSTestDeviceRef SOSTestDeviceCreateWithDbNamed(CFAllocatorRef allocator, CFStringRef engineID, CFStringRef dbName) { CFURLRef url = SecCopyURLForFileInKeychainDirectory(dbName); CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); - SecDbRef db = SecKeychainDbCreate(path); + SecDbRef db = SecKeychainDbCreate(path, NULL); SOSTestDeviceRef td = SOSTestDeviceCreateWithDb(allocator, engineID, db); CFReleaseSafe(db); CFReleaseSafe(path); @@ -257,8 +257,8 @@ CFDataRef SOSTestDeviceCreateMessage(SOSTestDeviceRef td, CFStringRef peerID) { CFErrorRef error = NULL; SOSEnginePeerMessageSentBlock sent = NULL; CFDataRef msgData; - - ok(msgData = SOSEngineCreateMessageToSyncToPeer(td->ds->engine, peerID, &sent, &error), + CFMutableArrayRef attributeList = NULL; + ok(msgData = SOSEngineCreateMessageToSyncToPeer(td->ds->engine, peerID, &attributeList, &sent, &error), "create message to %@: %@", peerID, error); if (sent) sent(true); diff --git a/OSX/sec/SOSCircle/Regressions/sc-130-resignationticket.c b/OSX/sec/SOSCircle/Regressions/sc-130-resignationticket.c index c74d3d67..d565e797 100644 --- a/OSX/sec/SOSCircle/Regressions/sc-130-resignationticket.c +++ b/OSX/sec/SOSCircle/Regressions/sc-130-resignationticket.c @@ -43,6 +43,7 @@ typedef struct piStuff_t { SecKeyRef signingKey; + SecKeyRef octagonSigningKey; SOSFullPeerInfoRef fpi; SOSPeerInfoRef pi; SOSPeerInfoRef resignation_ticket; @@ -54,7 +55,7 @@ static piStuff *makeSimplePeer(char *name) { if(!pi) return NULL; pi->signingKey = NULL; CFStringRef cfName = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingMacRoman); - pi->fpi = SOSCreateFullPeerInfoFromName(cfName, &pi->signingKey, NULL); + pi->fpi = SOSCreateFullPeerInfoFromName(cfName, &pi->signingKey, &pi->octagonSigningKey, NULL); CFReleaseSafe(cfName); pi->pi = SOSFullPeerInfoGetPeerInfo(pi->fpi); pi->resignation_ticket = SOSPeerInfoCreateRetirementTicket(kCFAllocatorDefault, pi->signingKey, pi->pi, NULL); @@ -65,6 +66,7 @@ static void freeSimplePeer(piStuff *pi) { CFReleaseSafe(pi->fpi); CFReleaseSafe(pi->signingKey); + CFReleaseSafe(pi->octagonSigningKey); CFReleaseSafe(pi->resignation_ticket); free(pi); } diff --git a/OSX/sec/SOSCircle/Regressions/sc-150-ring.c b/OSX/sec/SOSCircle/Regressions/sc-150-ring.m similarity index 90% rename from OSX/sec/SOSCircle/Regressions/sc-150-ring.c rename to OSX/sec/SOSCircle/Regressions/sc-150-ring.m index e4cc6ea1..bbff1e10 100644 --- a/OSX/sec/SOSCircle/Regressions/sc-150-ring.c +++ b/OSX/sec/SOSCircle/Regressions/sc-150-ring.m @@ -54,10 +54,10 @@ #include "SOSRegressionUtilities.h" static SOSFullPeerInfoRef SOSCreateApplicantFullPeerInfoFromName(CFStringRef peerName, SecKeyRef user_private_key, - SecKeyRef* outSigningKey, CFErrorRef *error) + SecKeyRef* outSigningKey, SecKeyRef* outOctagonSigningKey, CFErrorRef *error) { SOSFullPeerInfoRef result = NULL; - SOSFullPeerInfoRef fullPeer = SOSCreateFullPeerInfoFromName(peerName, outSigningKey, error); + SOSFullPeerInfoRef fullPeer = SOSCreateFullPeerInfoFromName(peerName, outSigningKey, outOctagonSigningKey, error); if (fullPeer && SOSFullPeerInfoPromoteToApplication(fullPeer, user_private_key, error)) CFTransferRetained(result, fullPeer); @@ -74,6 +74,9 @@ static void tests(void) SecKeyRef dev_a_key = NULL; SecKeyRef dev_b_key = NULL; SecKeyRef dev_c_key = NULL; + SecKeyRef oct_dev_a_key = NULL; + SecKeyRef oct_dev_b_key = NULL; + SecKeyRef oct_dev_c_key = NULL; CFErrorRef error = NULL; CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); @@ -90,9 +93,9 @@ static void tests(void) SecKeyRef user_pubkey = SecKeyCreatePublicFromPrivate(user_privkey); - SOSFullPeerInfoRef peer_a_full_info = SOSCreateApplicantFullPeerInfoFromName(CFSTR("Peer A"), user_privkey, &dev_a_key, NULL); - SOSFullPeerInfoRef peer_b_full_info = SOSCreateApplicantFullPeerInfoFromName(CFSTR("Peer B"), user_privkey, &dev_b_key, NULL); - SOSFullPeerInfoRef peer_c_full_info = SOSCreateApplicantFullPeerInfoFromName(CFSTR("Peer C"), user_privkey, &dev_c_key, NULL); + SOSFullPeerInfoRef peer_a_full_info = SOSCreateApplicantFullPeerInfoFromName(CFSTR("Peer A"), user_privkey, &dev_a_key, &oct_dev_a_key, NULL); + SOSFullPeerInfoRef peer_b_full_info = SOSCreateApplicantFullPeerInfoFromName(CFSTR("Peer B"), user_privkey, &dev_b_key, &oct_dev_b_key, NULL); + SOSFullPeerInfoRef peer_c_full_info = SOSCreateApplicantFullPeerInfoFromName(CFSTR("Peer C"), user_privkey, &dev_c_key, &oct_dev_c_key, NULL); CFStringRef peerID_a = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(peer_a_full_info)); CFStringRef peerID_b = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(peer_b_full_info)); SOSRingRef Ring = SOSRingCreate(CFSTR("TESTRING"), peerID_a, kSOSRingBase, NULL); @@ -144,6 +147,9 @@ static void tests(void) CFReleaseNull(dev_a_key); CFReleaseNull(dev_b_key); CFReleaseNull(dev_c_key); + CFReleaseNull(oct_dev_a_key); + CFReleaseNull(oct_dev_b_key); + CFReleaseNull(oct_dev_c_key); CFReleaseNull(cfpassword); CFReleaseNull(user_privkey); diff --git a/OSX/sec/SOSCircle/Regressions/sc-153-backupslicekeybag.c b/OSX/sec/SOSCircle/Regressions/sc-153-backupslicekeybag.c index 354d3f8f..656f81c9 100644 --- a/OSX/sec/SOSCircle/Regressions/sc-153-backupslicekeybag.c +++ b/OSX/sec/SOSCircle/Regressions/sc-153-backupslicekeybag.c @@ -93,7 +93,8 @@ static void tests(void) CFDataRef entropy2 = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, sEntropy2, sizeof(sEntropy2), kCFAllocatorNull); SecKeyRef peer1SigningKey = NULL; - SOSFullPeerInfoRef fullPeer1WithBackup = SOSCreateFullPeerInfoFromName(CFSTR("peer1WithBackupID"), &peer1SigningKey, &localError); + SecKeyRef peer1OctagonSigningKey = NULL; + SOSFullPeerInfoRef fullPeer1WithBackup = SOSCreateFullPeerInfoFromName(CFSTR("peer1WithBackupID"), &peer1SigningKey, &peer1OctagonSigningKey, &localError); ok(fullPeer1WithBackup, "Allocate peer 1 (%@)", localError); CFReleaseNull(localError); @@ -106,7 +107,8 @@ static void tests(void) SOSPeerInfoRef peer1WithBackup = SOSFullPeerInfoGetPeerInfo(fullPeer1WithBackup); SecKeyRef peer2SigningKey = NULL; - SOSFullPeerInfoRef fullPeer2WithBackup = SOSCreateFullPeerInfoFromName(CFSTR("peer2WithBackupID"), &peer2SigningKey, &localError); + SecKeyRef peer2OctagonSigningKey = NULL; + SOSFullPeerInfoRef fullPeer2WithBackup = SOSCreateFullPeerInfoFromName(CFSTR("peer2WithBackupID"), &peer2SigningKey, &peer2OctagonSigningKey, &localError); ok(fullPeer2WithBackup, "Allocate peer 2 (%@)", localError); CFReleaseNull(localError); @@ -156,10 +158,12 @@ TODO:{ CFReleaseNull(piSet); CFReleaseNull(peer1SigningKey); + CFReleaseNull(peer2OctagonSigningKey); CFReleaseNull(peer1BackupPublic); CFReleaseNull(fullPeer1WithBackup); CFReleaseNull(peer2SigningKey); + CFReleaseNull(peer2OctagonSigningKey); CFReleaseNull(peer2BackupPublic); CFReleaseNull(fullPeer2WithBackup); diff --git a/OSX/sec/SOSCircle/Regressions/sc-20-keynames.c b/OSX/sec/SOSCircle/Regressions/sc-20-keynames.m similarity index 97% rename from OSX/sec/SOSCircle/Regressions/sc-20-keynames.c rename to OSX/sec/SOSCircle/Regressions/sc-20-keynames.m index 53012fe3..b75af154 100644 --- a/OSX/sec/SOSCircle/Regressions/sc-20-keynames.c +++ b/OSX/sec/SOSCircle/Regressions/sc-20-keynames.m @@ -48,6 +48,7 @@ static int kTestTestCount = 15; static void tests(void) { SecKeyRef publicKey = NULL; + SecKeyRef octagonPublicKey = NULL; CFErrorRef error = NULL; @@ -64,7 +65,7 @@ static void tests(void) CFReleaseNull(circle_name); CFReleaseNull(circle_key); - SOSPeerInfoRef pi = SOSCreatePeerInfoFromName(CFSTR("Test Peer"), &publicKey, &error); + SOSPeerInfoRef pi = SOSCreatePeerInfoFromName(CFSTR("Test Peer"), &publicKey, &octagonPublicKey, &error); CFStringRef other_peer_id = CFSTR("OTHER PEER"); @@ -115,6 +116,7 @@ static void tests(void) SOSPeerInfoGetPeerID(pi), retirement_peer_id); CFReleaseNull(publicKey); + CFReleaseNull(octagonPublicKey); CFReleaseNull(circle); CFReleaseNull(error); CFReleaseNull(pi); diff --git a/OSX/sec/SOSCircle/Regressions/sc-30-peerinfo.c b/OSX/sec/SOSCircle/Regressions/sc-30-peerinfo.c index 1c9ab40d..24cf068c 100644 --- a/OSX/sec/SOSCircle/Regressions/sc-30-peerinfo.c +++ b/OSX/sec/SOSCircle/Regressions/sc-30-peerinfo.c @@ -92,7 +92,8 @@ static int kTestTestCount = 24; static void tests(void) { SecKeyRef signingKey = NULL; - SOSFullPeerInfoRef fpi = SOSCreateFullPeerInfoFromName(CFSTR("Test Peer"), &signingKey, NULL); + SecKeyRef octagonSigningKey = NULL; + SOSFullPeerInfoRef fpi = SOSCreateFullPeerInfoFromName(CFSTR("Test Peer"), &signingKey, &octagonSigningKey, NULL); SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); ok(NULL != pi, "info creation"); @@ -146,6 +147,7 @@ static void tests(void) CFReleaseNull(user_pubkey); CFReleaseNull(signingKey); + CFReleaseNull(octagonSigningKey); CFReleaseNull(fpi); } diff --git a/OSX/sec/SOSCircle/Regressions/sc-31-peerinfo-simplefuzz.c b/OSX/sec/SOSCircle/Regressions/sc-31-peerinfo-simplefuzz.c index 9f879fd6..711f6197 100644 --- a/OSX/sec/SOSCircle/Regressions/sc-31-peerinfo-simplefuzz.c +++ b/OSX/sec/SOSCircle/Regressions/sc-31-peerinfo-simplefuzz.c @@ -39,7 +39,8 @@ static unsigned long kTestFuzzerCount = 20000; static void tests(void) { SecKeyRef signingKey = NULL; - SOSFullPeerInfoRef fpi = SOSCreateFullPeerInfoFromName(CFSTR("Test Peer"), &signingKey, NULL); + SecKeyRef octagonSigningKey = NULL; + SOSFullPeerInfoRef fpi = SOSCreateFullPeerInfoFromName(CFSTR("Test Peer"), &signingKey, &octagonSigningKey, NULL); SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); unsigned long count; @@ -73,6 +74,7 @@ static void tests(void) errOut: CFReleaseNull(signingKey); + CFReleaseNull(octagonSigningKey); CFReleaseNull(fpi); } diff --git a/OSX/sec/SOSCircle/Regressions/sc-40-circle.c b/OSX/sec/SOSCircle/Regressions/sc-40-circle.c index b75940a8..cf379780 100644 --- a/OSX/sec/SOSCircle/Regressions/sc-40-circle.c +++ b/OSX/sec/SOSCircle/Regressions/sc-40-circle.c @@ -77,6 +77,10 @@ static void tests(void) SecKeyRef dev_b_key = NULL; SecKeyRef dev_c_key = NULL; SecKeyRef dev_d_key = NULL; + SecKeyRef oct_dev_a_key = NULL; + SecKeyRef oct_dev_b_key = NULL; + SecKeyRef oct_dev_c_key = NULL; + SecKeyRef oct_dev_d_key = NULL; CFErrorRef error = NULL; CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); @@ -90,13 +94,13 @@ static void tests(void) SecKeyRef user_privkey = SOSUserKeygen(cfpassword, parameters, &error); CFReleaseNull(parameters); - SOSFullPeerInfoRef peer_a_full_info = SOSCreateFullPeerInfoFromName(CFSTR("Peer A"), &dev_a_key, NULL); + SOSFullPeerInfoRef peer_a_full_info = SOSCreateFullPeerInfoFromName(CFSTR("Peer A"), &dev_a_key, &oct_dev_a_key, NULL); - SOSFullPeerInfoRef peer_b_full_info = SOSCreateFullPeerInfoFromName(CFSTR("Peer B"), &dev_b_key, NULL); + SOSFullPeerInfoRef peer_b_full_info = SOSCreateFullPeerInfoFromName(CFSTR("Peer B"), &dev_b_key, &oct_dev_b_key, NULL); - SOSFullPeerInfoRef peer_c_full_info = SOSCreateFullPeerInfoFromName(CFSTR("Peer C"), &dev_c_key, NULL); + SOSFullPeerInfoRef peer_c_full_info = SOSCreateFullPeerInfoFromName(CFSTR("Peer C"), &dev_c_key, &oct_dev_c_key, NULL); - SOSFullPeerInfoRef peer_d_full_info = SOSCreateFullPeerInfoFromName(CFSTR("Peer D"), &dev_d_key, NULL); + SOSFullPeerInfoRef peer_d_full_info = SOSCreateFullPeerInfoFromName(CFSTR("Peer D"), &dev_d_key, &oct_dev_d_key, NULL); ok(SOSCircleRequestAdmission(circle, user_privkey, peer_a_full_info, NULL)); ok(SOSCircleRequestAdmission(circle, user_privkey, peer_a_full_info, NULL)); @@ -155,6 +159,10 @@ static void tests(void) CFReleaseNull(dev_b_key); CFReleaseNull(dev_c_key); CFReleaseNull(dev_d_key); + CFReleaseNull(oct_dev_a_key); + CFReleaseNull(oct_dev_b_key); + CFReleaseNull(oct_dev_c_key); + CFReleaseNull(oct_dev_d_key); CFReleaseNull(cfpassword); diff --git a/OSX/sec/SOSCircle/SOSPeerInfoDER.c b/OSX/sec/SOSCircle/SOSPeerInfoDER.c deleted file mode 100644 index 2aca2253..00000000 --- a/OSX/sec/SOSCircle/SOSPeerInfoDER.c +++ /dev/null @@ -1,154 +0,0 @@ -*************** -*** 0 **** ---- 1,151 ---- -+ // -+ // SOSPeerInfoDER.c -+ // sec -+ // -+ // Created by Richard Murphy on 2/9/15. -+ // -+ // -+ -+ #include -+ #include "SOSPeerInfoDER.h" -+ -+ #include -+ #include -+ #include -+ #include -+ #include -+ -+ #include -+ #include -+ #include -+ #include -+ -+ #include -+ -+ size_t SOSPeerInfoGetDEREncodedSize(SOSPeerInfoRef peer, CFErrorRef *error) { -+ size_t plist_size = der_sizeof_plist(peer->description, error); -+ if (plist_size == 0) -+ return 0; -+ -+ size_t signature_size = der_sizeof_data(peer->signature, error); -+ if (signature_size == 0) -+ return 0; -+ -+ return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, -+ plist_size + signature_size); -+ } -+ -+ uint8_t* SOSPeerInfoEncodeToDER(SOSPeerInfoRef peer, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { -+ if(peer->version >= 2) SOSPeerInfoPackV2Data(peer); -+ return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, -+ der_encode_plist(peer->description, error, der, -+ der_encode_data(peer->signature, error, der, der_end))); -+ } -+ -+ CFDataRef SOSPeerInfoCopyEncodedData(SOSPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error) { -+ size_t size = SOSPeerInfoGetDEREncodedSize(peer, error); -+ if (size == 0) return NULL; -+ -+ uint8_t buffer[size]; -+ uint8_t* start = SOSPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer)); -+ CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size); -+ return result; -+ } -+ -+ -+ -+ SOSPeerInfoRef SOSPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error, -+ const uint8_t** der_p, const uint8_t *der_end) { -+ SOSPeerInfoRef pi = SOSPeerInfoAllocate(allocator); -+ SecKeyRef pubKey = NULL; -+ const uint8_t *sequence_end; -+ -+ CFPropertyListRef pl = NULL; -+ -+ 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); -+ -+ if (*der_p == NULL || *der_p != sequence_end) { -+ SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Format of Peer Info DER"), NULL, error); -+ goto fail; -+ } -+ -+ if (CFGetTypeID(pl) != CFDictionaryGetTypeID()) { -+ CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(pl)); -+ SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL, -+ CFSTR("Expected dictionary got %@"), description); -+ CFReleaseSafe(description); -+ goto fail; -+ } -+ -+ pi->description = (CFMutableDictionaryRef) pl; -+ CFRetain(pi->description); -+ CFReleaseNull(pl); -+ -+ CFNumberRef versionNumber = CFDictionaryGetValue(pi->description, sVersionKey); -+ -+ if (versionNumber) { -+ if (CFGetTypeID(versionNumber) != CFNumberGetTypeID()) { -+ CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(versionNumber)); -+ SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL, -+ CFSTR("Expected (version) number got %@"), description); -+ CFReleaseSafe(description); -+ goto fail; -+ } -+ CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &pi->version); -+ } -+ -+ CFDictionaryRef gestalt = CFDictionaryGetValue(pi->description, sGestaltKey); -+ -+ if (gestalt == NULL) { -+ SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL, -+ CFSTR("gestalt key missing")); -+ goto fail; -+ } -+ -+ if (!isDictionary(gestalt)) { -+ CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(gestalt)); -+ SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL, -+ CFSTR("Expected dictionary got %@"), description); -+ CFReleaseSafe(description); -+ goto fail; -+ } -+ -+ pi->gestalt = gestalt; -+ CFRetain(pi->gestalt); -+ -+ pubKey = SOSPeerInfoCopyPubKey(pi); -+ require_quiet(pubKey, fail); -+ -+ pi->id = SOSCopyIDOfKey(pubKey, error); -+ require_quiet(pi->id, fail); -+ -+ if(pi->version >= 2) SOSPeerInfoExpandV2Data(pi, error); -+ -+ if(!SOSPeerInfoVerify(pi, error)) { -+ SOSCreateErrorWithFormat(kSOSErrorBadSignature, NULL, error, NULL, CFSTR("Signature doesn't validate")); -+ if (error) -+ secerror("Can't validate PeerInfo: %@", *error); -+ goto fail; -+ } -+ -+ CFReleaseNull(pubKey); -+ return pi; -+ -+ fail: -+ CFReleaseNull(pi); -+ CFReleaseNull(pl); -+ CFReleaseNull(pubKey); -+ -+ return NULL; -+ } -+ -+ SOSPeerInfoRef SOSPeerInfoCreateFromData(CFAllocatorRef allocator, CFErrorRef* error, -+ CFDataRef peerinfo_data) { -+ const uint8_t *der = CFDataGetBytePtr(peerinfo_data); -+ CFIndex len = CFDataGetLength(peerinfo_data); -+ return SOSPeerInfoCreateFromDER(NULL, error, &der, der+len); -+ } diff --git a/OSX/sec/SOSCircle/SecureObjectSync/CKDSimulatedStore.h b/OSX/sec/SOSCircle/SecureObjectSync/CKDSimulatedStore.h index a4444888..bcdc6f17 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/CKDSimulatedStore.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/CKDSimulatedStore.h @@ -27,6 +27,7 @@ - (void)pushWrites; - (BOOL)pullUpdates:(NSError**) failure; +- (void)addOneToOutGoing; - (void)remoteSetObject:(id)obj forKey:(NSString*)key; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/CKDSimulatedStore.m b/OSX/sec/SOSCircle/SecureObjectSync/CKDSimulatedStore.m index 562607b5..f42bc0cf 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/CKDSimulatedStore.m +++ b/OSX/sec/SOSCircle/SecureObjectSync/CKDSimulatedStore.m @@ -65,6 +65,9 @@ - (void)pushWrites { } +- (void)addOneToOutGoing{ + +} - (BOOL) pullUpdates:(NSError **)failure { return true; @@ -74,9 +77,12 @@ { [self.data setObject:obj forKey:key]; - if (self.proxy) { - [self.proxy storeKeysChanged: [NSSet setWithObject:key] initial: NO]; - } + [self.proxy storeKeysChanged: [NSSet setWithObject:key] initial: NO]; +} + +- (void)perfCounters:(void(^)(NSDictionary *counters))callback +{ + callback(@{}); } @end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.c deleted file mode 100644 index c428a071..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.c +++ /dev/null @@ -1,2192 +0,0 @@ -/* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. - */ - -/* - * SOSAccount.c - Implementation of the secure object syncing account. - * An account contains a SOSCircle for each protection domain synced. - */ - -#include "SOSAccountPriv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -CFGiblisWithCompareFor(SOSAccount); - -const CFStringRef SOSTransportMessageTypeIDS = CFSTR("IDS"); -const CFStringRef SOSTransportMessageTypeIDSV2 = CFSTR("IDS2.0"); -const CFStringRef SOSTransportMessageTypeKVS = CFSTR("KVS"); -const CFStringRef kSOSDSIDKey = CFSTR("AccountDSID"); -const CFStringRef kSOSEscrowRecord = CFSTR("EscrowRecord"); -const CFStringRef kSOSUnsyncedViewsKey = CFSTR("unsynced"); -const CFStringRef kSOSPendingEnableViewsToBeSetKey = CFSTR("pendingEnableViews"); -const CFStringRef kSOSPendingDisableViewsToBeSetKey = CFSTR("pendingDisableViews"); -const CFStringRef kSOSTestV2Settings = CFSTR("v2dictionary"); -const CFStringRef kSOSRecoveryKey = CFSTR("RecoveryKey"); -const CFStringRef kSOSRecoveryRing = CFSTR("RecoveryRing"); -const CFStringRef kSOSAccountUUID = CFSTR("UUID"); - -#define DATE_LENGTH 25 -const CFStringRef kSOSAccountDebugScope = CFSTR("Scope"); - -bool SOSAccountEnsureFactoryCircles(SOSAccountRef a) -{ - bool result = false; - CFStringRef circle_name = NULL; - - require_quiet(a, xit); - require_quiet(a->factory, xit); - - circle_name = SOSDataSourceFactoryCopyName(a->factory); - require(circle_name, xit); - - SOSAccountEnsureCircle(a, circle_name, NULL); - - result = true; - -xit: - // We don't own name, so don't release it. - CFReleaseNull(circle_name); - return result; -} - - -SOSAccountRef SOSAccountCreateBasic(CFAllocatorRef allocator, - CFDictionaryRef gestalt, - SOSDataSourceFactoryRef factory) { - SOSAccountRef a = CFTypeAllocate(SOSAccount, struct __OpaqueSOSAccount, allocator); - - a->queue = dispatch_queue_create("Account Queue", DISPATCH_QUEUE_SERIAL); - - a->gestalt = CFRetainSafe(gestalt); - - a->trusted_circle = NULL; - a->backups = CFDictionaryCreateMutableForCFTypes(allocator); - a->my_identity = NULL; - a->retirees = CFSetCreateMutableForSOSPeerInfosByID(allocator); - - a->factory = factory; // We adopt the factory. kthanksbai. - - a->isListeningForSync = false; - - a->_user_private = NULL; - a->_password_tmp = NULL; - a->user_private_timer = NULL; - a->lock_notification_token = NOTIFY_TOKEN_INVALID; - - a->change_blocks = CFArrayCreateMutableForCFTypes(allocator); - a->waitForInitialSync_blocks = NULL; - a->departure_code = kSOSNeverAppliedToCircle; - - a->key_transport = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(a, NULL); - a->circle_transport = NULL; - a->kvs_message_transport = NULL; - a->ids_message_transport = NULL; - a->expansion = CFDictionaryCreateMutableForCFTypes(allocator); - - SOSAccountAddRingDictionary(a); - - a->saveBlock = NULL; - a->circle_rings_retirements_need_attention = false; - a->engine_peer_state_needs_repair = false; - a->key_interests_need_updating = false; - a->deviceID = NULL; - - return a; -} - -// -// MARK: Transactional -// - -void SOSAccountWithTransaction_Locked(SOSAccountRef account, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)) { - SOSAccountTransactionRef at = SOSAccountTransactionCreate(account); - action(account, at); - SOSAccountTransactionFinish(at); - CFReleaseNull(at); -} - - - -void SOSAccountWithTransaction(SOSAccountRef account, bool sync, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)) { - dispatch_block_t with_transaction = ^{ - SOSAccountWithTransaction_Locked(account, action); - }; - - if (sync) { - dispatch_sync(SOSAccountGetQueue(account), with_transaction); - } else { - dispatch_async(SOSAccountGetQueue(account), with_transaction); - } -} - -void SOSAccountWithTransactionSync(SOSAccountRef account, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)) { - SOSAccountWithTransaction(account, true, action); -} - -void SOSAccountWithTransactionAsync(SOSAccountRef account, bool sync, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)) { - SOSAccountWithTransaction(account, false, action); -} - -// -// MARK: Save Block -// - -void SOSAccountSetSaveBlock(SOSAccountRef account, SOSAccountSaveBlock saveBlock) { - CFAssignRetained(account->saveBlock, Block_copy(saveBlock)); -} - -void SOSAccountFlattenToSaveBlock(SOSAccountRef account) { - if (account->saveBlock) { - CFErrorRef localError = NULL; - CFDataRef saveData = SOSAccountCopyEncodedData(account, kCFAllocatorDefault, &localError); - - (account->saveBlock)(saveData, localError); - - CFReleaseNull(saveData); - CFReleaseNull(localError); - } -} - -// -// MARK: Security Properties -// - -SOSSecurityPropertyResultCode SOSAccountUpdateSecurityProperty(SOSAccountRef account, CFStringRef property, SOSSecurityPropertyActionCode actionCode, CFErrorRef *error) { - SOSSecurityPropertyResultCode retval = kSOSCCGeneralSecurityPropertyError; - bool updateCircle = false; - require_action_quiet(account->trusted_circle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error)); - require_action_quiet(account->my_identity, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error)); - retval = SOSFullPeerInfoUpdateSecurityProperty(account->my_identity, actionCode, property, error); - - if(actionCode == kSOSCCSecurityPropertyEnable && retval == kSOSCCSecurityPropertyValid) { - updateCircle = true; - } else if(actionCode == kSOSCCSecurityPropertyDisable && retval == kSOSCCSecurityPropertyNotValid) { - updateCircle = true; - } else if(actionCode == kSOSCCSecurityPropertyPending) { - updateCircle = true; - } - - if (updateCircle) { - SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle_to_change) { - secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for security property change"); - return SOSCircleUpdatePeerInfo(circle_to_change, SOSFullPeerInfoGetPeerInfo(account->my_identity)); - }); - } - -errOut: - return retval; -} - -SOSSecurityPropertyResultCode SOSAccountSecurityPropertyStatus(SOSAccountRef account, CFStringRef property, CFErrorRef *error) { - SOSSecurityPropertyResultCode retval = kSOSCCGeneralViewError; - require_action_quiet(account->trusted_circle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error)); - require_action_quiet(account->my_identity, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error)); - retval = SOSFullPeerInfoSecurityPropertyStatus(account->my_identity, property, error); -errOut: - return retval; -} - -bool SOSAccountUpdateGestalt(SOSAccountRef account, CFDictionaryRef new_gestalt) -{ - if (CFEqualSafe(new_gestalt, account->gestalt)) - return false; - - if (account->trusted_circle && account->my_identity - && SOSFullPeerInfoUpdateGestalt(account->my_identity, new_gestalt, NULL)) { - SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle_to_change) { - secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); - return SOSCircleUpdatePeerInfo(circle_to_change, SOSAccountGetMyPeerInfo(account)); - }); - } - - CFRetainAssign(account->gestalt, new_gestalt); - return true; -} - -CFDictionaryRef SOSAccountCopyGestalt(SOSAccountRef account) { - return CFDictionaryCreateCopy(kCFAllocatorDefault, account->gestalt); -} - -bool SOSAccountUpdateV2Dictionary(SOSAccountRef account, CFDictionaryRef newV2Dict) { - if(!newV2Dict) return true; - SOSAccountSetValue(account, kSOSTestV2Settings, newV2Dict, NULL); - if (account->trusted_circle && account->my_identity - && SOSFullPeerInfoUpdateV2Dictionary(account->my_identity, newV2Dict, NULL)) { - SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle_to_change) { - secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); - return SOSCircleUpdatePeerInfo(circle_to_change, SOSAccountGetMyPeerInfo(account)); - }); - } - return true; -} - -CFDictionaryRef SOSAccountCopyV2Dictionary(SOSAccountRef account) { - CFDictionaryRef v2dict = SOSAccountGetValue(account, kSOSTestV2Settings, NULL); - return CFDictionaryCreateCopy(kCFAllocatorDefault, v2dict); -} - -static bool SOSAccountUpdateDSID(SOSAccountRef account, CFStringRef dsid){ - SOSAccountSetValue(account, kSOSDSIDKey, dsid, NULL); - //send new DSID over account changed - SOSTransportCircleSendOfficialDSID(account->circle_transport, dsid, NULL); - return true; -} - -void SOSAccountAssertDSID(SOSAccountRef account, CFStringRef dsid) { - CFStringRef accountDSID = SOSAccountGetValue(account, kSOSDSIDKey, NULL); - if(accountDSID == NULL) { - secdebug("updates", "Setting dsid, current dsid is empty for this account: %@", dsid); - - SOSAccountUpdateDSID(account, dsid); - } else if(CFStringCompare(dsid, accountDSID, 0) != kCFCompareEqualTo) { - secnotice("updates", "Changing DSID from: %@ to %@", accountDSID, dsid); - - //DSID has changed, blast the account! - SOSAccountSetToNew(account); - - //update DSID to the new DSID - SOSAccountUpdateDSID(account, dsid); - } else { - secnotice("updates", "Not Changing DSID: %@ to %@", accountDSID, dsid); - } -} - -bool SOSAccountUpdateFullPeerInfo(SOSAccountRef account, CFSetRef minimumViews, CFSetRef excludedViews) { - if (account->trusted_circle && account->my_identity) { - if(SOSFullPeerInfoUpdateToCurrent(account->my_identity, minimumViews, excludedViews)) { - SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle_to_change) { - secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); - return SOSCircleUpdatePeerInfo(circle_to_change, SOSFullPeerInfoGetPeerInfo(account->my_identity)); - }); - } - } - - return true; -} - -void SOSAccountPendEnableViewSet(SOSAccountRef account, CFSetRef enabledViews) -{ - if(CFSetGetValue(enabledViews, kSOSViewKeychainV0) != NULL) secnotice("viewChange", "Warning, attempting to Add KeychainV0"); - - SOSAccountValueUnionWith(account, kSOSPendingEnableViewsToBeSetKey, enabledViews); - SOSAccountValueSubtractFrom(account, kSOSPendingDisableViewsToBeSetKey, enabledViews); -} - - -void SOSAccountPendDisableViewSet(SOSAccountRef account, CFSetRef disabledViews) -{ - SOSAccountValueUnionWith(account, kSOSPendingDisableViewsToBeSetKey, disabledViews); - SOSAccountValueSubtractFrom(account, kSOSPendingEnableViewsToBeSetKey, disabledViews); -} - -static SOSViewResultCode SOSAccountVirtualV0Behavior(SOSAccountRef account, SOSViewActionCode actionCode) { - SOSViewResultCode retval = kSOSCCGeneralViewError; - // The V0 view switches on and off all on it's own, we allow people the delusion - // of control and status if it's what we're stuck at., otherwise error. - if (SOSAccountSyncingV0(account)) { - require_action_quiet(actionCode == kSOSCCViewDisable, errOut, CFSTR("Can't disable V0 view and it's on right now")); - retval = kSOSCCViewMember; - } else { - require_action_quiet(actionCode == kSOSCCViewEnable, errOut, CFSTR("Can't enable V0 and it's off right now")); - retval = kSOSCCViewNotMember; - } -errOut: - return retval; -} - - -SOSViewResultCode SOSAccountUpdateView(SOSAccountRef account, CFStringRef viewname, SOSViewActionCode actionCode, CFErrorRef *error) { - SOSViewResultCode retval = kSOSCCGeneralViewError; - SOSViewResultCode currentStatus = kSOSCCGeneralViewError; - bool alreadyInSync = SOSAccountHasCompletedInitialSync(account); - - bool updateCircle = false; - require_action_quiet(account->trusted_circle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error)); - require_action_quiet(account->my_identity, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error)); - require_action_quiet((actionCode == kSOSCCViewEnable) || (actionCode == kSOSCCViewDisable), errOut, CFSTR("Invalid View Action")); - currentStatus = SOSAccountViewStatus(account, viewname, error); - require_action_quiet((currentStatus == kSOSCCViewNotMember) || (currentStatus == kSOSCCViewMember), errOut, CFSTR("View Membership Not Actionable")); - - if (CFEqualSafe(viewname, kSOSViewKeychainV0)) { - retval = SOSAccountVirtualV0Behavior(account, actionCode); - } else if (SOSAccountSyncingV0(account) && SOSViewsIsV0Subview(viewname)) { - // Subviews of V0 syncing can't be turned off if V0 is on. - require_action_quiet(actionCode = kSOSCCViewDisable, errOut, CFSTR("Have V0 peer can't disable")); - retval = kSOSCCViewMember; - } else { - CFMutableSetRef pendingSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - CFSetAddValue(pendingSet, viewname); - - if(actionCode == kSOSCCViewEnable && currentStatus == kSOSCCViewNotMember) { - if(alreadyInSync) { - retval = SOSFullPeerInfoUpdateViews(account->my_identity, actionCode, viewname, error); - if(retval == kSOSCCViewMember) updateCircle = true; - } else { - SOSAccountPendEnableViewSet(account, pendingSet); - retval = kSOSCCViewMember; - updateCircle = false; - } - } else if(actionCode == kSOSCCViewDisable && currentStatus == kSOSCCViewMember) { - if(alreadyInSync) { - retval = SOSFullPeerInfoUpdateViews(account->my_identity, actionCode, viewname, error); - if(retval == kSOSCCViewNotMember) updateCircle = true; - } else { - SOSAccountPendDisableViewSet(account, pendingSet); - retval = kSOSCCViewNotMember; - updateCircle = false; - } - } else { - retval = currentStatus; - } - - CFReleaseNull(pendingSet); - - if (updateCircle) { - SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle_to_change) { - secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for views change"); - return SOSCircleUpdatePeerInfo(circle_to_change, SOSFullPeerInfoGetPeerInfo(account->my_identity)); - }); - } - } - -errOut: - return retval; -} - -SOSViewResultCode SOSAccountViewStatus(SOSAccountRef account, CFStringRef viewname, CFErrorRef *error) { - SOSViewResultCode retval = kSOSCCGeneralViewError; - require_action_quiet(account->trusted_circle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error)); - require_action_quiet(account->my_identity, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error)); - - if (SOSAccountValueSetContainsValue(account, kSOSPendingEnableViewsToBeSetKey, viewname)) { - retval = kSOSCCViewMember; - } else if (SOSAccountValueSetContainsValue(account, kSOSPendingDisableViewsToBeSetKey, viewname)) { - retval = kSOSCCViewNotMember; - } else { - retval = SOSFullPeerInfoViewStatus(account->my_identity, viewname, error); - } - - // If that doesn't say we're a member and this view is a V0 subview, and we're syncing V0 views we are a member - if (retval != kSOSCCViewMember) { - if ((CFEqualSafe(viewname, kSOSViewKeychainV0) || SOSViewsIsV0Subview(viewname)) - && SOSAccountSyncingV0(account)) { - retval = kSOSCCViewMember; - } - } - - // If we're only an applicant we report pending if we would be a view member - if (retval == kSOSCCViewMember) { - bool isApplicant = SOSCircleHasApplicant(account->trusted_circle, SOSAccountGetMyPeerInfo(account), error); - if (isApplicant) { - retval = kSOSCCViewPending; - } - } - -errOut: - return retval; -} - -static void dumpViewSet(CFStringRef label, CFSetRef views) { - if(views) { - CFStringSetPerformWithDescription(views, ^(CFStringRef description) { - secnotice("circleChange", "%@ list: %@", label, description); - }); - } else { - secnotice("circleChange", "No %@ list provided.", label); - } -} - -static bool SOSAccountScreenViewListForValidV0(SOSAccountRef account, CFMutableSetRef viewSet, SOSViewActionCode actionCode) { - bool retval = true; - if(viewSet && CFSetContainsValue(viewSet, kSOSViewKeychainV0)) { - retval = SOSAccountVirtualV0Behavior(account, actionCode) != kSOSCCGeneralViewError; - CFSetRemoveValue(viewSet, kSOSViewKeychainV0); - } - return retval; -} - -bool SOSAccountUpdateViewSets(SOSAccountRef account, CFSetRef origEnabledViews, CFSetRef origDisabledViews) { - bool retval = false; - bool updateCircle = false; - SOSPeerInfoRef pi = NULL; - CFMutableSetRef enabledViews = NULL; - CFMutableSetRef disabledViews = NULL; - if(origEnabledViews) enabledViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, origEnabledViews); - if(origDisabledViews) disabledViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, origDisabledViews); - dumpViewSet(CFSTR("Enabled"), enabledViews); - dumpViewSet(CFSTR("Disabled"), disabledViews); - - require_action_quiet(account->trusted_circle, errOut, secnotice("views", "Attempt to set viewsets with no trusted circle")); - - // Make sure we have a peerInfo capable of supporting views. - SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account); - require_action_quiet(fpi, errOut, secnotice("views", "Attempt to set viewsets with no fullPeerInfo")); - require_action_quiet(enabledViews || disabledViews, errOut, secnotice("views", "No work to do")); - - pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSFullPeerInfoGetPeerInfo(fpi), NULL); - - require_action_quiet(pi, errOut, secnotice("views", "Couldn't copy PeerInfoRef")); - - if(!SOSPeerInfoVersionIsCurrent(pi)) { - CFErrorRef updateFailure = NULL; - require_action_quiet(SOSPeerInfoUpdateToV2(pi, &updateFailure), errOut, - (secnotice("views", "Unable to update peer to V2- can't update views: %@", updateFailure), (void) CFReleaseNull(updateFailure))); - secnotice("V2update", "Updating PeerInfo to V2 within SOSAccountUpdateViewSets"); - updateCircle = true; - } - - CFStringSetPerformWithDescription(enabledViews, ^(CFStringRef description) { - secnotice("viewChange", "Enabling %@", description); - }); - - CFStringSetPerformWithDescription(disabledViews, ^(CFStringRef description) { - secnotice("viewChange", "Disabling %@", description); - }); - - 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(SOSAccountHasCompletedInitialSync(account)) { - if(enabledViews) updateCircle |= SOSViewSetEnable(pi, enabledViews); - if(disabledViews) updateCircle |= SOSViewSetDisable(pi, disabledViews); - retval = true; - } else { - //hold on to the views and enable them later - if(enabledViews) SOSAccountPendEnableViewSet(account, enabledViews); - if(disabledViews) SOSAccountPendDisableViewSet(account, disabledViews); - retval = true; - } - - if(updateCircle) { - /* UPDATE FULLPEERINFO VIEWS */ - require_quiet(SOSFullPeerInfoUpdateToThisPeer(fpi, pi, NULL), errOut); - - require_quiet(SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle_to_change) { - secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for views or peerInfo change"); - return SOSCircleUpdatePeerInfo(circle_to_change, SOSFullPeerInfoGetPeerInfo(account->my_identity)); - }), errOut); - - // Make sure we update the engine - account->circle_rings_retirements_need_attention = true; - } - -errOut: - CFReleaseNull(enabledViews); - CFReleaseNull(disabledViews); - CFReleaseNull(pi); - return retval; -} - - -SOSAccountRef SOSAccountCreate(CFAllocatorRef allocator, - CFDictionaryRef gestalt, - SOSDataSourceFactoryRef factory) { - SOSAccountRef a = SOSAccountCreateBasic(allocator, gestalt, factory); - - SOSAccountEnsureFactoryCircles(a); - - SOSAccountEnsureUUID(a); - - a->key_interests_need_updating = true; - - return a; -} - -static void SOSAccountDestroy(CFTypeRef aObj) { - SOSAccountRef a = (SOSAccountRef) aObj; - - // We don't own the factory, merely have a reference to the singleton - // Don't free it. - // a->factory - - SOSAccountCancelSyncChecking(a); - - SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(a->factory, SOSCircleGetName(a->trusted_circle), NULL); - - if (engine) - SOSEngineSetSyncCompleteListenerQueue(engine, NULL); - - dispatch_sync(a->queue, ^{ - CFReleaseNull(a->gestalt); - - CFReleaseNull(a->my_identity); - CFReleaseNull(a->trusted_circle); - CFReleaseNull(a->backups); - CFReleaseNull(a->retirees); - - a->user_public_trusted = false; - CFReleaseNull(a->user_public); - CFReleaseNull(a->user_key_parameters); - - SOSAccountPurgePrivateCredential(a); - CFReleaseNull(a->previous_public); - CFReleaseNull(a->_user_private); - CFReleaseNull(a->_password_tmp); - - a->departure_code = kSOSNeverAppliedToCircle; - CFReleaseNull(a->kvs_message_transport); - CFReleaseNull(a->ids_message_transport); - CFReleaseNull(a->key_transport); - CFReleaseNull(a->circle_transport); - dispatch_release(a->queue); - - dispatch_release(a->user_private_timer); - CFReleaseNull(a->change_blocks); - CFReleaseNull(a->waitForInitialSync_blocks); - CFReleaseNull(a->expansion); - - CFReleaseNull(a->saveBlock); - CFReleaseNull(a->deviceID); - }); -} - -static OSStatus do_delete(CFDictionaryRef query) { - OSStatus result; - - result = SecItemDelete(query); - if (result) { - secerror("SecItemDelete: %d", (int)result); - } - return result; -} - -static int -do_keychain_delete_aks_bags() -{ - OSStatus result; - CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecClass, kSecClassGenericPassword, - kSecAttrAccessGroup, CFSTR("com.apple.sbd"), - kSecAttrAccount, CFSTR("SecureBackupPublicKeybag"), - kSecAttrService, CFSTR("SecureBackupService"), - kSecAttrSynchronizable, kCFBooleanTrue, - kSecUseTombstones, kCFBooleanFalse, - NULL); - - result = do_delete(item); - CFReleaseSafe(item); - - return result; -} - -static int -do_keychain_delete_identities() -{ - OSStatus result; - CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecClass, kSecClassKey, - kSecAttrSynchronizable, kCFBooleanTrue, - kSecUseTombstones, kCFBooleanFalse, - kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), - NULL); - - result = do_delete(item); - CFReleaseSafe(item); - - return result; -} - -static int -do_keychain_delete_lakitu() -{ - OSStatus result; - CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecClass, kSecClassGenericPassword, - kSecAttrSynchronizable, kCFBooleanTrue, - kSecUseTombstones, kCFBooleanFalse, - kSecAttrAccessGroup, CFSTR("com.apple.lakitu"), - kSecAttrAccount, CFSTR("EscrowServiceBypassToken"), - kSecAttrService, CFSTR("EscrowService"), - NULL); - - result = do_delete(item); - CFReleaseSafe(item); - - return result; -} - -static int -do_keychain_delete_sbd() -{ - OSStatus result; - CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecClass, kSecClassGenericPassword, - kSecAttrSynchronizable, kCFBooleanTrue, - kSecUseTombstones, kCFBooleanFalse, - kSecAttrAccessGroup, CFSTR("com.apple.sbd"), - NULL); - - result = do_delete(item); - CFReleaseSafe(item); - - return result; -} - -void SOSAccountSetToNew(SOSAccountRef a) { - secnotice("accountChange", "Setting Account to New"); - int result = 0; - - CFReleaseNull(a->my_identity); - CFReleaseNull(a->trusted_circle); - CFReleaseNull(a->backups); - CFReleaseNull(a->retirees); - - CFReleaseNull(a->user_key_parameters); - CFReleaseNull(a->user_public); - CFReleaseNull(a->previous_public); - CFReleaseNull(a->_user_private); - CFReleaseNull(a->_password_tmp); - - CFReleaseNull(a->key_transport); - CFReleaseNull(a->circle_transport); - CFReleaseNull(a->kvs_message_transport); - CFReleaseNull(a->ids_message_transport); - CFReleaseNull(a->expansion); - CFReleaseNull(a->deviceID); - - /* remove all syncable items */ - result = do_keychain_delete_aks_bags(); (void) result; - secdebug("set to new", "result for deleting aks bags: %d", result); - - result = do_keychain_delete_identities(); (void) result; - secdebug("set to new", "result for deleting identities: %d", result); - - result = do_keychain_delete_lakitu(); (void) result; - secdebug("set to new", "result for deleting lakitu: %d", result); - - result = do_keychain_delete_sbd(); (void) result; - secdebug("set to new", "result for deleting sbd: %d", result); - - a->user_public_trusted = false; - a->departure_code = kSOSNeverAppliedToCircle; - - if (a->user_private_timer) { - dispatch_source_cancel(a->user_private_timer); - dispatch_release(a->user_private_timer); - a->user_private_timer = NULL; - xpc_transaction_end(); - - } - if (a->lock_notification_token != NOTIFY_TOKEN_INVALID) { - notify_cancel(a->lock_notification_token); - a->lock_notification_token = NOTIFY_TOKEN_INVALID; - } - - // keeping gestalt; - // keeping factory; - // Live Notification - // change_blocks; - // update_interest_block; - // update_block; - - a->key_transport = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(a, NULL); - a->circle_transport = NULL; - a->kvs_message_transport = NULL; - a->ids_message_transport = NULL; - - a->backups = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - a->retirees = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - a->expansion = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountAddRingDictionary(a); - - SOSAccountEnsureFactoryCircles(a); // Does rings too - - // By resetting our expansion dictionary we've reset our UUID, so we'll be notified properly - SOSAccountEnsureUUID(a); - - a->key_interests_need_updating = true; -} - -bool SOSAccountIsNew(SOSAccountRef account, CFErrorRef *error){ - bool result = false; - require_quiet(account->user_public_trusted == false, exit); - require_quiet(account->departure_code == kSOSNeverAppliedToCircle, exit); - require_quiet(account->user_private_timer == NULL, exit); - require_quiet(account->lock_notification_token == NOTIFY_TOKEN_INVALID, exit); - require_quiet (CFDictionaryGetCount(account->backups) == 0, exit); - require_quiet(CFSetGetCount(account->retirees) == 0, exit); - - result = true; -exit: - return result; -} - -static CFStringRef SOSAccountCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) { - SOSAccountRef a = (SOSAccountRef) aObj; - - CFStringRef gestaltDescription = CFDictionaryCopyCompactDescription(a->gestalt); - - CFStringRef result = CFStringCreateWithFormat(NULL, NULL, CFSTR(""), a, - a->user_public ? 'P' : 'p', - a->user_public_trusted ? 'T' : 't', - a->isListeningForSync ? 'L' : 'l', - SOSAccountHasCompletedInitialSync(a) ? 'C' : 'c', - SOSAccountHasCompletedRequiredBackupSync(a) ? 'B' : 'b', - gestaltDescription, a->my_identity, a->trusted_circle); - - CFReleaseNull(gestaltDescription); - - return result; -} - -CFStringRef SOSAccountCreateCompactDescription(SOSAccountRef a) { - - CFStringRef gestaltDescription = CFDictionaryCopySuperCompactDescription(a->gestalt); - - CFStringRef result = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), gestaltDescription); - - CFReleaseNull(gestaltDescription); - - return result; -} - -static Boolean SOSAccountCompare(CFTypeRef lhs, CFTypeRef rhs) -{ - SOSAccountRef laccount = (SOSAccountRef) lhs; - SOSAccountRef raccount = (SOSAccountRef) rhs; - - return CFEqualSafe(laccount->gestalt, raccount->gestalt) - && CFEqualSafe(laccount->trusted_circle, raccount->trusted_circle) - && CFEqualSafe(laccount->expansion, raccount->expansion) - && CFEqualSafe(laccount->my_identity, raccount->my_identity); -} - -dispatch_queue_t SOSAccountGetQueue(SOSAccountRef account) { - return account->queue; -} - -void SOSAccountSetUserPublicTrustedForTesting(SOSAccountRef account){ - account->user_public_trusted = true; -} - -SOSFullPeerInfoRef SOSAccountCopyAccountIdentityPeerInfo(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef* error) -{ - return CFRetainSafe(account->my_identity); -} - - - -bool SOSAccountCleanupAfterPeer(SOSAccountRef account, size_t seconds, SOSCircleRef circle, - SOSPeerInfoRef cleanupPeer, CFErrorRef* error) -{ - bool success = true; - - SOSPeerInfoRef myPeerInfo = SOSFullPeerInfoGetPeerInfo(account->my_identity); - require_action_quiet(account->my_identity && myPeerInfo, xit, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("I have no peer"))); - require_quiet(SOSCircleHasActivePeer(circle, SOSFullPeerInfoGetPeerInfo(account->my_identity), error), xit); - - CFStringRef cleanupPeerID = SOSPeerInfoGetPeerID(cleanupPeer); - - CFStringRef circle_name = SOSCircleGetName(circle); - - CFMutableDictionaryRef circleToPeerIDs = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayAppendValue(CFDictionaryEnsureCFArrayAndGetCurrentValue(circleToPeerIDs, circle_name), cleanupPeerID); - - CFErrorRef localError = NULL; - if (!(success &= SOSTransportMessageCleanupAfterPeerMessages(account->kvs_message_transport, circleToPeerIDs, &localError))) { - secnotice("account", "Failed to cleanup after peer %@ messages: %@", cleanupPeerID, localError); - } - - if (account->ids_message_transport && !SOSTransportMessageCleanupAfterPeerMessages(account->ids_message_transport, circleToPeerIDs, &localError)) { - secnotice("account", "Failed to cleanup after peer %@ messages: %@", cleanupPeerID, localError); - } - - CFReleaseNull(localError); - - if((success &= SOSPeerInfoRetireRetirementTicket(seconds, cleanupPeer))) { - if (!(success &= SOSTransportCircleExpireRetirementRecords(account->circle_transport, circleToPeerIDs, &localError))) { - secnotice("account", "Failed to cleanup after peer %@ retirement: %@", cleanupPeerID, localError); - } - } - CFReleaseNull(localError); - CFReleaseNull(circleToPeerIDs); - -xit: - return success; -} - -bool SOSAccountCleanupRetirementTickets(SOSAccountRef account, size_t seconds, CFErrorRef* error) { - CFMutableSetRef retirees_to_remove = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - - __block bool success = true; - - CFSetForEach(account->retirees, ^(const void *value) { - SOSPeerInfoRef retiree = (SOSPeerInfoRef) value; - - if (retiree) { - // Remove the entry if it's not a retired peer or if it's retirment ticket has expired AND he's no longer in the circle. - if (!SOSPeerInfoIsRetirementTicket(retiree) || - (SOSPeerInfoRetireRetirementTicket(seconds, retiree) && !SOSCircleHasActivePeer(account->trusted_circle, retiree, NULL))) { - CFSetAddValue(retirees_to_remove, retiree); - }; - } - }); - - CFMutableArrayRef retirees_to_cleanup = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFSetForEach(retirees_to_remove, ^(const void *value) { - CFArrayAppendValue(retirees_to_cleanup, value); - CFSetRemoveValue(account->retirees, value); - }); - - CFReleaseNull(retirees_to_remove); - - CFDictionaryRef retirements_to_remove = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - SOSCircleGetName(account->trusted_circle), retirees_to_cleanup, - NULL); - - CFReleaseNull(retirees_to_cleanup); - - success = SOSTransportCircleExpireRetirementRecords(account->circle_transport, retirements_to_remove, error); - - CFReleaseNull(retirements_to_remove); - - return success; -} - -bool SOSAccountScanForRetired(SOSAccountRef account, SOSCircleRef circle, CFErrorRef *error) { - SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) { - CFSetSetValue(account->retirees, peer); - CFErrorRef cleanupError = NULL; - if (!SOSAccountCleanupAfterPeer(account, RETIREMENT_FINALIZATION_SECONDS, circle, peer, &cleanupError)) { - secnotice("retirement", "Error cleaning up after peer, probably orphaned some stuff in KVS: (%@) – moving on", cleanupError); - } - CFReleaseSafe(cleanupError); - }); - return true; -} - -SOSCircleRef SOSAccountCloneCircleWithRetirement(SOSAccountRef account, SOSCircleRef starting_circle, CFErrorRef *error) { - SOSCircleRef new_circle = SOSCircleCopyCircle(NULL, starting_circle, error); - SOSFullPeerInfoRef meFull = SOSAccountGetMyFullPeerInfo(account); - SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(meFull); - bool iAmApplicant = me && SOSCircleHasApplicant(new_circle, me, NULL); - - if(!new_circle) return NULL; - __block bool workDone = false; - if (account->retirees) { - CFSetForEach(account->retirees, ^(const void* value) { - SOSPeerInfoRef pi = (SOSPeerInfoRef) value; - if (isSOSPeerInfo(pi)) { - SOSCircleUpdatePeerInfo(new_circle, pi); - workDone = true; - } - }); - } - - if(workDone && SOSCircleCountPeers(new_circle) == 0) { - SecKeyRef userPrivKey = SOSAccountGetPrivateCredential(account, error); - - if(iAmApplicant) { - if(userPrivKey) { - secnotice("resetToOffering", "Reset to offering with last retirement and me as applicant"); - if(!SOSCircleResetToOffering(new_circle, userPrivKey, meFull, error) || - !SOSAccountAddiCloudIdentity(account, new_circle, userPrivKey, error)) { - CFReleaseNull(new_circle); - return NULL; - } - } else { - // Do nothing. We can't resetToOffering without a userPrivKey. If we were to resetToEmpty - // we won't push the result later in handleUpdateCircle. If we leave the circle as it is - // we have a chance to set things right with a SetCreds/Join sequence. This will cause - // handleUpdateCircle to return false. - CFReleaseNull(new_circle); - return NULL; - } - } else { - // This case is when we aren't an applicant and the circle is retirement-empty. - secnotice("resetToEmpty", "Reset to empty with last retirement"); - SOSCircleResetToEmpty(new_circle, NULL); - } - } - - return new_circle; -} - -// -// MARK: Circle Membership change notificaion -// - -void SOSAccountAddChangeBlock(SOSAccountRef a, SOSAccountCircleMembershipChangeBlock changeBlock) { - SOSAccountCircleMembershipChangeBlock copy = Block_copy(changeBlock); - CFArrayAppendValue(a->change_blocks, copy); - CFReleaseNull(copy); -} - -void SOSAccountRemoveChangeBlock(SOSAccountRef a, SOSAccountCircleMembershipChangeBlock changeBlock) { - CFArrayRemoveAllValue(a->change_blocks, changeBlock); -} - -void SOSAccountAddSyncablePeerBlock(SOSAccountRef a, CFStringRef ds_name, SOSAccountSyncablePeersBlock changeBlock) { - if (!changeBlock) return; - - CFRetainSafe(ds_name); - SOSAccountCircleMembershipChangeBlock block_to_register = ^void (SOSCircleRef new_circle, - CFSetRef added_peers, CFSetRef removed_peers, - CFSetRef added_applicants, CFSetRef removed_applicants) { - - if (!CFEqualSafe(SOSCircleGetName(new_circle), ds_name)) - return; - - SOSPeerInfoRef myPi = SOSFullPeerInfoGetPeerInfo(a->my_identity); - CFStringRef myPi_id = myPi ? SOSPeerInfoGetPeerID(myPi) : NULL; - - CFMutableArrayRef peer_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFMutableArrayRef added_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFMutableArrayRef removed_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - - if (SOSCircleHasPeer(new_circle, myPi, NULL)) { - SOSCircleForEachPeer(new_circle, ^(SOSPeerInfoRef peer) { - CFArrayAppendValueIfNot(peer_ids, SOSPeerInfoGetPeerID(peer), myPi_id); - }); - - CFSetForEach(added_peers, ^(const void *value) { - CFArrayAppendValueIfNot(added_ids, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value), myPi_id); - }); - - CFSetForEach(removed_peers, ^(const void *value) { - CFArrayAppendValueIfNot(removed_ids, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value), myPi_id); - }); - } - - if (CFArrayGetCount(peer_ids) || CFSetContainsValue(removed_peers, myPi)) - changeBlock(peer_ids, added_ids, removed_ids); - - CFReleaseSafe(peer_ids); - CFReleaseSafe(added_ids); - CFReleaseSafe(removed_ids); - }; - - CFRetainSafe(changeBlock); - SOSAccountAddChangeBlock(a, block_to_register); - - CFSetRef empty = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - if (a->trusted_circle && CFEqualSafe(ds_name, SOSCircleGetName(a->trusted_circle))) { - block_to_register(a->trusted_circle, empty, empty, empty, empty); - } - CFReleaseSafe(empty); -} - -void SOSAccountPurgeIdentity(SOSAccountRef account) { - if (account->my_identity) { - // Purge private key but don't return error if we can't. - CFErrorRef purgeError = NULL; - if (!SOSFullPeerInfoPurgePersistentKey(account->my_identity, &purgeError)) { - secwarning("Couldn't purge persistent key for %@ [%@]", account->my_identity, purgeError); - } - CFReleaseNull(purgeError); - - CFReleaseNull(account->my_identity); - } -} - -bool sosAccountLeaveCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error) { - SOSFullPeerInfoRef fpi = account->my_identity; - if(!fpi) return false; - - CFErrorRef localError = NULL; - - bool retval = false; - - SOSPeerInfoRef retire_peer = SOSFullPeerInfoPromoteToRetiredAndCopy(fpi, &localError); - if (!retire_peer) { - secerror("Create ticket failed for peer %@: %@", fpi, localError); - } else { - // See if we need to repost the circle we could either be an applicant or a peer already in the circle - if(SOSCircleHasApplicant(circle, retire_peer, NULL)) { - // Remove our application if we have one. - SOSCircleWithdrawRequest(circle, retire_peer, NULL); - } else if (SOSCircleHasPeer(circle, retire_peer, NULL)) { - if (SOSCircleUpdatePeerInfo(circle, retire_peer)) { - CFErrorRef cleanupError = NULL; - if (!SOSAccountCleanupAfterPeer(account, RETIREMENT_FINALIZATION_SECONDS, circle, retire_peer, &cleanupError)) { - secerror("Error cleanup up after peer (%@): %@", retire_peer, cleanupError); - } - CFReleaseSafe(cleanupError); - } - } - - // Store the retirement record locally. - CFSetAddValue(account->retirees, retire_peer); - - // Write retirement to Transport - CFErrorRef postError = NULL; - if (!SOSTransportCirclePostRetirement(account->circle_transport, SOSCircleGetName(circle), retire_peer, &postError)){ - secwarning("Couldn't post retirement (%@)", postError); - } - if(!SOSTransportCircleFlushChanges(account->circle_transport, &postError)){ - secwarning("Couldn't flush retirement data (%@)", postError); - } - CFReleaseNull(postError); - } - - SOSAccountPurgeIdentity(account); - - retval = true; - - CFReleaseNull(localError); - CFReleaseNull(retire_peer); - return retval; -} - -bool sosAccountLeaveRing(SOSAccountRef account, SOSRingRef ring, CFErrorRef* error) { - SOSFullPeerInfoRef fpi = account->my_identity; - if(!fpi) return false; - SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); - CFStringRef peerID = SOSPeerInfoGetPeerID(pi); - - CFErrorRef localError = NULL; - - bool retval = false; - bool writeRing = false; - bool writePeerInfo = false; - - if(SOSRingHasPeerID(ring, peerID)) { - writePeerInfo = true; - } - -#if 0 - // this was circle behavior - at some point - if(SOSRingHasApplicant(ring, peerID)) { - writeRing = true; - } -#endif - - if(writePeerInfo || writeRing) { - SOSRingWithdraw(ring, NULL, fpi, error); - } - - // Write leave thing to Transport - CFDataRef peerInfoData = SOSFullPeerInfoCopyEncodedData(fpi, kCFAllocatorDefault, error); - SOSTransportCircleSendPeerInfo(account->circle_transport, peerID, peerInfoData, NULL); // TODO: Handle errors? - - if (writeRing) { - CFDataRef ring_data = SOSRingCopyEncodedData(ring, error); - - if (ring_data) { - SOSTransportCircleRingPostRing(account->circle_transport, SOSRingGetName(ring), ring_data, NULL); // TODO: Handle errors? - } - CFReleaseNull(ring_data); - } - retval = true; - CFReleaseNull(localError); - return retval; -} - -bool SOSAccountPostDebugScope(SOSAccountRef account, CFTypeRef scope, CFErrorRef *error) { - bool result = false; - SOSTransportCircleRef transport = account->circle_transport; - if (transport) { - result = SOSTransportCircleSendDebugInfo(transport, kSOSAccountDebugScope, scope, error); - } - return result; -} - -/* - NSUbiquitousKeyValueStoreInitialSyncChange is only posted if there is any - local value that has been overwritten by a distant value. If there is no - conflict between the local and the distant values when doing the initial - sync (e.g. if the cloud has no data stored or the client has not stored - any data yet), you'll never see that notification. - - NSUbiquitousKeyValueStoreInitialSyncChange implies an initial round trip - with server but initial round trip with server does not imply - NSUbiquitousKeyValueStoreInitialSyncChange. - */ - - -// -// MARK: Status summary -// - -static SOSCCStatus SOSCCThisDeviceStatusInCircle(SOSCircleRef circle, SOSPeerInfoRef this_peer) { - if (!circle) - return kSOSCCNotInCircle; - - if (circle && SOSCircleCountPeers(circle) == 0) - return kSOSCCCircleAbsent; - - if (this_peer) { - - if(SOSPeerInfoIsRetirementTicket(this_peer)) - return kSOSCCNotInCircle; - - if (SOSCircleHasPeer(circle, this_peer, NULL)) - return kSOSCCInCircle; - - if (SOSCircleHasApplicant(circle, this_peer, NULL)) - return kSOSCCRequestPending; - } - - return kSOSCCNotInCircle; -} - -CFStringRef SOSAccountGetSOSCCStatusString(SOSCCStatus status) { - switch(status) { - case kSOSCCInCircle: return CFSTR("kSOSCCInCircle"); - case kSOSCCNotInCircle: return CFSTR("kSOSCCNotInCircle"); - case kSOSCCRequestPending: return CFSTR("kSOSCCRequestPending"); - case kSOSCCCircleAbsent: return CFSTR("kSOSCCCircleAbsent"); - case kSOSCCError: return CFSTR("kSOSCCError"); - } - return CFSTR("kSOSCCError"); -} - -bool SOSAccountIsInCircle(SOSAccountRef account, CFErrorRef *error) { - SOSCCStatus result = SOSAccountGetCircleStatus(account, error); - - if (result != kSOSCCInCircle) { - SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("Not in circle")); - return false; - } - - return true; -} - -SOSCCStatus SOSAccountGetCircleStatus(SOSAccountRef account, CFErrorRef* error) { - if (!SOSAccountHasPublicKey(account, error)) { - return kSOSCCError; - } - - return SOSCCThisDeviceStatusInCircle(account->trusted_circle, SOSAccountGetMyPeerInfo(account)); -} - -// -// MARK: Account Reset Circles -// - -// This needs to be called within a SOSAccountModifyCircle() block - -bool SOSAccountAddiCloudIdentity(SOSAccountRef account, SOSCircleRef circle, SecKeyRef user_key, CFErrorRef *error) { - bool result = false; - SOSFullPeerInfoRef cloud_identity = NULL; - SOSPeerInfoRef cloud_peer = GenerateNewCloudIdentityPeerInfo(error); - require_quiet(cloud_peer, err_out); - cloud_identity = CopyCloudKeychainIdentity(cloud_peer, error); - CFReleaseNull(cloud_peer); - require_quiet(cloud_identity, err_out); - require_quiet(SOSCircleRequestAdmission(circle, user_key, cloud_identity, error), err_out); - require_quiet(SOSCircleAcceptRequest(circle, user_key, account->my_identity, SOSFullPeerInfoGetPeerInfo(cloud_identity), error), err_out); - result = true; -err_out: - return result; -} - -bool SOSAccountRemoveIncompleteiCloudIdentities(SOSAccountRef account, SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) { - bool retval = false; - CFMutableSetRef iCloud2Remove = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { - if(SOSPeerInfoIsCloudIdentity(peer)) { - SOSFullPeerInfoRef icfpi = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, NULL); - if(!icfpi) { - CFSetAddValue(iCloud2Remove, peer); - } - CFReleaseNull(icfpi); - } - }); - - if(CFSetGetCount(iCloud2Remove) > 0) { - retval = true; - SOSCircleRemovePeers(circle, privKey, account->my_identity, iCloud2Remove, error); - } - CFReleaseNull(iCloud2Remove); - return retval; -} - -static bool SOSAccountResetCircleToOffering(SOSAccountTransactionRef aTxn, SecKeyRef user_key, CFErrorRef *error) { - SOSAccountRef account = aTxn->account; - bool result = false; - - require(SOSAccountHasCircle(account, error), fail); - require(SOSAccountEnsureFullPeerAvailable(account, error), fail); - - (void) SOSAccountResetAllRings(account, error); - - SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle) { - bool result = false; - SOSFullPeerInfoRef cloud_identity = NULL; - CFErrorRef localError = NULL; - - require_quiet(SOSCircleResetToOffering(circle, user_key, account->my_identity, &localError), err_out); - - account->departure_code = kSOSNeverLeftCircle; - require_quiet(SOSAccountAddEscrowToPeerInfo(account, SOSAccountGetMyFullPeerInfo(account), error), err_out); - - require_quiet(SOSAccountAddiCloudIdentity(account, circle, user_key, error), err_out); - result = true; - SOSAccountPublishCloudParameters(account, NULL); - - err_out: - if (result == false) - secerror("error resetting circle (%@) to offering: %@", circle, localError); - if (localError && error && *error == NULL) { - *error = localError; - localError = NULL; - } - CFReleaseNull(localError); - CFReleaseNull(cloud_identity); - return result; - }); - - SOSAccountSetValue(account, kSOSUnsyncedViewsKey, kCFBooleanTrue, NULL); - SOSAccountUpdateOutOfSyncViews(aTxn, SOSViewsGetAllCurrent()); - - result = true; - -fail: - return result; -} - - -bool SOSAccountResetToOffering(SOSAccountTransactionRef aTxn, CFErrorRef* error) { - SOSAccountRef account = aTxn->account; - SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); - if (!user_key) - return false; - - CFReleaseNull(account->my_identity); - secnotice("resetToOffering", "Resetting circle to offering by request from client"); - - return user_key && SOSAccountResetCircleToOffering(aTxn, user_key, error); -} - -bool SOSAccountResetToEmpty(SOSAccountRef account, CFErrorRef* error) { - if (!SOSAccountHasPublicKey(account, error)) - return false; - __block bool result = true; - - result &= SOSAccountResetAllRings(account, error); - - CFReleaseNull(account->my_identity); - - account->departure_code = kSOSWithdrewMembership; - secnotice("resetToEmpty", "Reset Circle to empty by client request"); - result &= SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle) { - result = SOSCircleResetToEmpty(circle, error); - return result; - }); - - if (!result) { - secerror("error: %@", error ? *error : NULL); - } - return result; -} -// -// MARK: start backups -// - -bool SOSAccountEnsureInBackupRings(SOSAccountRef account) { - __block bool result = false; - __block CFErrorRef error = NULL; - secnotice("backup", "Ensuring in rings"); - - CFDataRef backupKey = NULL; - - require_action_quiet(account->backup_key, exit, result = true); - - backupKey = SOSPeerInfoV2DictionaryCopyData(SOSAccountGetMyPeerInfo(account), sBackupKeyKey); - - bool updateBackupKey = !CFEqualSafe(backupKey, account->backup_key); - - if(updateBackupKey) { - require_quiet(SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), &error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) { - return SOSFullPeerInfoUpdateBackupKey(fpi, account->backup_key, error); - }), exit); - } - require_quiet(account->backup_key, exit); // If it went null, we're done now. - - require_quiet(SOSBSKBIsGoodBackupPublic(account->backup_key, &error), exit); - - CFDataRef recoveryKeyBackFromRing = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, &error); - - if(updateBackupKey || recoveryKeyBackFromRing) { - // It's a good key, we're going with it. Stop backing up the old way. - CFErrorRef localError = NULL; - if (!SOSDeleteV0Keybag(&localError)) { - secerror("Failed to delete v0 keybag: %@", localError); - } - CFReleaseNull(localError); - - result = true; - - // Setup backups the new way. - SOSAccountForEachBackupView(account, ^(const void *value) { - CFStringRef viewName = (CFStringRef)value; - if(updateBackupKey || (recoveryKeyBackFromRing && !SOSAccountRecoveryKeyIsInBackupAndCurrentInView(account, viewName))) { - result &= SOSAccountNewBKSBForView(account, viewName, &error); - } - }); - } - -exit: - if (!result) { - secnotice("backupkey", "Failed to setup backup public key: %@", error ? (CFTypeRef) error : (CFTypeRef) CFSTR("No error space provided")); - } - CFReleaseNull(backupKey); - return result; -} - -// -// MARK: Recovery Public Key Functions -// - -bool SOSAccountRegisterRecoveryPublicKey(SOSAccountTransactionRef txn, CFDataRef recovery_key, CFErrorRef *error){ - bool retval = SOSAccountSetRecoveryKey(txn->account, recovery_key, error); - if(retval) secnotice("recovery", "successfully registered recovery public key"); - else secnotice("recovery", "could not register recovery public key: %@", *error); - SOSClearErrorIfTrue(retval, error); - return retval; -} - -bool SOSAccountClearRecoveryPublicKey(SOSAccountTransactionRef txn, CFDataRef recovery_key, CFErrorRef *error){ - bool retval = SOSAccountRemoveRecoveryKey(txn->account, error); - SOSClearErrorIfTrue(retval, error); - return retval; -} - -CFDataRef SOSAccountCopyRecoveryPublicKey(SOSAccountTransactionRef txn, CFErrorRef *error){ - CFDataRef result = NULL; - result = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, txn->account, error); - if(!result) secnotice("recovery", "Could not retrieve the recovery public key from the ring: %@", *error); - - if (!isData(result)) { - CFReleaseNull(result); - } - SOSClearErrorIfTrue(result != NULL, error); - - return result; -} - -// -// MARK: Joining -// - -static bool SOSAccountJoinCircle(SOSAccountTransactionRef aTxn, SecKeyRef user_key, - bool use_cloud_peer, CFErrorRef* error) { - SOSAccountRef account = aTxn->account; - - __block bool result = false; - __block SOSFullPeerInfoRef cloud_full_peer = NULL; - - require_action_quiet(account->trusted_circle, fail, SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("Don't have circle when joining???"))); - require_quiet(SOSAccountEnsureFullPeerAvailable(account, error), fail); - - SOSFullPeerInfoRef myCirclePeer = account->my_identity; - - if (SOSCircleCountPeers(account->trusted_circle) == 0 || SOSAccountGhostResultsInReset(account)) { - secnotice("resetToOffering", "Resetting circle to offering since there are no peers"); - // this also clears initial sync data - result = SOSAccountResetCircleToOffering(aTxn, user_key, error); - } else { - SOSAccountSetValue(account, kSOSUnsyncedViewsKey, kCFBooleanTrue, NULL); - - if (use_cloud_peer) { - cloud_full_peer = SOSCircleCopyiCloudFullPeerInfoRef(account->trusted_circle, NULL); - } - - SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle) { - result = SOSAccountAddEscrowToPeerInfo(account, myCirclePeer, error); - result &= SOSCircleRequestAdmission(circle, user_key, myCirclePeer, error); - account->departure_code = kSOSNeverLeftCircle; - if(result && cloud_full_peer) { - CFErrorRef localError = NULL; - CFStringRef cloudid = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(cloud_full_peer)); - require_quiet(cloudid, finish); - require_quiet(SOSCircleHasActivePeerWithID(circle, cloudid, &localError), finish); - require_quiet(SOSCircleAcceptRequest(circle, user_key, cloud_full_peer, SOSFullPeerInfoGetPeerInfo(myCirclePeer), &localError), finish); - - finish: - if (localError){ - secerror("Failed to join with cloud identity: %@", localError); - CFReleaseNull(localError); - } - } - return result; - }); - - if (use_cloud_peer) { - SOSAccountUpdateOutOfSyncViews(aTxn, SOSViewsGetAllCurrent()); - } - } - -fail: - CFReleaseNull(cloud_full_peer); - return result; -} - -static bool SOSAccountJoinCircles_internal(SOSAccountTransactionRef aTxn, bool use_cloud_identity, CFErrorRef* error) { - SOSAccountRef account = aTxn->account; - bool success = false; - - SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); - require_quiet(user_key, done); // Fail if we don't get one. - - require_action_quiet(account->trusted_circle, done, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to join"))); - - if (account->my_identity != NULL) { - SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(account->my_identity); - success = SOSCircleHasPeer(account->trusted_circle, myPeer, NULL); - require_quiet(!success, done); - - SOSCircleRemoveRejectedPeer(account->trusted_circle, myPeer, NULL); // If we were rejected we should remove it now. - - if (!SOSCircleHasApplicant(account->trusted_circle, myPeer, NULL)) { - secerror("Resetting my peer (ID: %@) for circle '%@' during application", SOSPeerInfoGetPeerID(myPeer), SOSCircleGetName(account->trusted_circle)); - - CFReleaseNull(account->my_identity); - myPeer = NULL; - } - } - - success = SOSAccountJoinCircle(aTxn, user_key, use_cloud_identity, error); - - require_quiet(success, done); - - account->departure_code = kSOSNeverLeftCircle; - -done: - return success; -} - -bool SOSAccountJoinCircles(SOSAccountTransactionRef aTxn, CFErrorRef* error) { - secnotice("circleJoin", "Normal path circle join (SOSAccountJoinCircles)"); - return SOSAccountJoinCircles_internal(aTxn, false, error); -} - -CFStringRef SOSAccountCopyDeviceID(SOSAccountRef account, CFErrorRef *error){ - CFStringRef result = NULL; - - require_action_quiet(account->my_identity, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No peer for me"))); - - result = SOSPeerInfoCopyDeviceID(SOSFullPeerInfoGetPeerInfo(account->my_identity)); - -fail: - return result; -} - -bool SOSAccountSetMyDSID(SOSAccountTransactionRef txn, CFStringRef IDS, CFErrorRef* error){ - bool result = true; - SOSAccountRef account = txn->account; - - secdebug("IDS Transport", "We are setting our device ID: %@", IDS); - if(IDS != NULL && (CFStringGetLength(IDS) > 0)){ - require_action_quiet(account->my_identity, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No peer for me"))); - - result = SOSAccountModifyCircle(account, error, ^bool(SOSCircleRef circle) { - - SOSFullPeerInfoUpdateDeviceID(account->my_identity, IDS, error); - SOSFullPeerInfoUpdateTransportType(account->my_identity, SOSTransportMessageTypeIDSV2, error); - SOSFullPeerInfoUpdateTransportPreference(account->my_identity, kCFBooleanFalse, error); - SOSFullPeerInfoUpdateTransportFragmentationPreference(account->my_identity, kCFBooleanTrue, error); - SOSFullPeerInfoUpdateTransportAckModelPreference(account->my_identity, kCFBooleanTrue, error); - return SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(account->my_identity), NULL); - }); - } - else - result = false; - - // Initiate sync with all IDS peers, since we just learned we can talk that way. - SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { - if (SOSPeerInfoShouldUseIDSTransport(SOSAccountGetMyPeerInfo(account), peer)) { - SOSAccountTransactionAddSyncRequestForPeerID(txn, SOSPeerInfoGetPeerID(peer)); - } - }); - -fail: - CFReleaseNull(account->deviceID); - account->deviceID = CFRetainSafe(IDS); - return result; -} - -bool SOSAccountSendIDSTestMessage(SOSAccountRef account, CFStringRef message, CFErrorRef *error){ - bool result = true; - //construct message dictionary, circle -> peerID -> message - - CFMutableDictionaryRef peerToMessage = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFStringRef operationString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kIDSSendOneMessage); - CFDictionaryRef rawMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kIDSOperationType, operationString, - kIDSMessageToSendKey, CFSTR("send IDS test message"), - NULL); - - SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { - CFDictionaryAddValue(peerToMessage, SOSPeerInfoGetPeerID(peer), rawMessage); - }); - - result = SOSTransportMessageSendMessages(account->ids_message_transport, peerToMessage, error); - - CFReleaseNull(peerToMessage); - CFReleaseNull(operationString); - CFReleaseNull(rawMessage); - return result; -} - -bool SOSAccountStartPingTest(SOSAccountRef account, CFStringRef message, CFErrorRef *error){ - bool result = false; - //construct message dictionary, circle -> peerID -> message - - if(account->ids_message_transport == NULL) - account->ids_message_transport = (SOSTransportMessageRef)SOSTransportMessageIDSCreate(account, SOSCircleGetName(account->trusted_circle), error); - - require_quiet(account->ids_message_transport, fail); - CFMutableDictionaryRef peerToMessage = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFStringRef operationString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kIDSStartPingTestMessage); - CFDictionaryRef rawMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kIDSOperationType, operationString, - kIDSMessageToSendKey, CFSTR("send IDS test message"), - NULL); - - - SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { - CFDictionaryAddValue(peerToMessage, SOSPeerInfoGetPeerID(peer), rawMessage); - }); - - result = SOSTransportMessageSendMessages(account->ids_message_transport, peerToMessage, error); - - CFReleaseNull(peerToMessage); - CFReleaseNull(rawMessage); - CFReleaseNull(operationString); -fail: - return result; -} - -bool SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(SOSAccountRef account, CFErrorRef *error){ - bool result = true; - - __block bool success = true; - __block CFErrorRef localError = NULL; - dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); - dispatch_retain(wait_for); // Both this scope and the block own it - - SOSCloudKeychainGetIDSDeviceID(^(CFDictionaryRef returnedValues, CFErrorRef sync_error){ - success = (sync_error == NULL); - if (!success) { - CFRetainAssign(localError, sync_error); - } - - dispatch_semaphore_signal(wait_for); - dispatch_release(wait_for); - }); - - dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); - dispatch_release(wait_for); - - if(!success && localError != NULL && error != NULL){ - secerror("Could not ask KeychainSyncingOverIDSProxy for Device ID: %@", localError); - *error = localError; - result = false; - } - else{ - secdebug("IDS Transport", "Attempting to retrieve the IDS Device ID"); - } - return result; -} - -bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransactionRef aTxn, CFErrorRef* error) { - secnotice("circleJoin", "Joining after restore (SOSAccountJoinCirclesAfterRestore)"); - return SOSAccountJoinCircles_internal(aTxn, true, error); -} - - -bool SOSAccountLeaveCircle(SOSAccountRef account, CFErrorRef* error) -{ - bool result = true; - - secnotice("leaveCircle", "Leaving circle by client request"); - result &= SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle) { - return sosAccountLeaveCircle(account, circle, error); - }); - - account->departure_code = kSOSWithdrewMembership; - - return result; -} - -bool SOSAccountRemovePeersFromCircle(SOSAccountRef account, CFArrayRef peers, CFErrorRef* error) -{ - bool result = false; - CFMutableSetRef peersToRemove = NULL; - SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); - require_action_quiet(user_key, errOut, secnotice("removePeers", "Can't remove without userKey")); - - SOSFullPeerInfoRef me_full = SOSAccountGetMyFullPeerInfo(account); - SOSPeerInfoRef me = SOSAccountGetMyPeerInfo(account); - require_action_quiet(me_full && me, errOut, { - SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("Can't remove without being active peer")); - secnotice("removePeers", "Can't remove without being active peer"); - }); - - result = true; // beyond this point failures would be rolled up in AccountModifyCircle. - - peersToRemove = CFSetCreateMutableForSOSPeerInfosByIDWithArray(kCFAllocatorDefault, peers); - require_action_quiet(peersToRemove, errOut, secnotice("removePeers", "No peerSet to remove")); - - // If we're one of the peers expected to leave - note that and then remove ourselves from the set (different handling). - bool leaveCircle = CFSetContainsValue(peersToRemove, me); - CFSetRemoveValue(peersToRemove, me); - - result &= SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle) { - bool success = false; - - if(CFSetGetCount(peersToRemove) != 0) { - require_quiet(SOSCircleRemovePeers(circle, user_key, me_full, peersToRemove, error), done); - success = SOSAccountGenerationSignatureUpdate(account, error); - } else success = true; - - if (success && leaveCircle) { - secnotice("leaveCircle", "Leaving circle by client request"); - success = sosAccountLeaveCircle(account, circle, error); - } - - done: - return success; - - }); - -errOut: - CFReleaseNull(peersToRemove); - return result; -} - - -bool SOSAccountBail(SOSAccountRef account, uint64_t limit_in_seconds, CFErrorRef* error) { - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_group_t group = dispatch_group_create(); - __block bool result = false; - secnotice("circle", "Attempting to leave circle - best effort - in %llu seconds\n", limit_in_seconds); - // Add a task to the group - dispatch_group_async(group, queue, ^{ - SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle) { - secnotice("leaveCircle", "Leaving circle by client request"); - return sosAccountLeaveCircle(account, circle, error); - }); - }); - dispatch_time_t milestone = dispatch_time(DISPATCH_TIME_NOW, limit_in_seconds * NSEC_PER_SEC); - dispatch_group_wait(group, milestone); - - account->departure_code = kSOSWithdrewMembership; - - dispatch_release(group); - return result; -} - - -// -// MARK: Application -// - -static void for_each_applicant_in_each_circle(SOSAccountRef account, CFArrayRef peer_infos, - bool (^action)(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer)) { - SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(account->my_identity); - CFErrorRef peer_error = NULL; - if (account->trusted_circle && me && - SOSCircleHasPeer(account->trusted_circle, me, &peer_error)) { - SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle) { - __block bool modified = false; - CFArrayForEach(peer_infos, ^(const void *value) { - SOSPeerInfoRef peer = (SOSPeerInfoRef) value; - if (isSOSPeerInfo(peer) && SOSCircleHasApplicant(circle, peer, NULL)) { - if (action(circle, account->my_identity, peer)) { - modified = true; - } - } - }); - return modified; - }); - } - if (peer_error) - secerror("Got error in SOSCircleHasPeer: %@", peer_error); - CFReleaseSafe(peer_error); // TODO: We should be accumulating errors here. -} - -bool SOSAccountAcceptApplicants(SOSAccountRef account, CFArrayRef applicants, CFErrorRef* error) { - SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); - if (!user_key) - return false; - - __block bool success = true; - __block int64_t num_peers = 0; - - for_each_applicant_in_each_circle(account, applicants, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer) { - bool accepted = SOSCircleAcceptRequest(circle, user_key, myCirclePeer, peer, error); - if (!accepted) - success = false; - else - num_peers = MAX(num_peers, SOSCircleCountPeers(circle)); - return accepted; - }); - - return success; -} - -bool SOSAccountRejectApplicants(SOSAccountRef account, CFArrayRef applicants, CFErrorRef* error) { - __block bool success = true; - __block int64_t num_peers = 0; - - for_each_applicant_in_each_circle(account, applicants, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer) { - bool rejected = SOSCircleRejectRequest(circle, myCirclePeer, peer, error); - if (!rejected) - success = false; - else - num_peers = MAX(num_peers, SOSCircleCountPeers(circle)); - return rejected; - }); - - return success; -} - - -CFStringRef SOSAccountCopyIncompatibilityInfo(SOSAccountRef account, CFErrorRef* error) { - return CFSTR("We're compatible, go away"); -} - -enum DepartureReason SOSAccountGetLastDepartureReason(SOSAccountRef account, CFErrorRef* error) { - return account->departure_code; -} - -void SOSAccountSetLastDepartureReason(SOSAccountRef account, enum DepartureReason reason) { - account->departure_code = reason; -} - - -CFArrayRef SOSAccountCopyGeneration(SOSAccountRef account, CFErrorRef *error) { - CFArrayRef result = NULL; - CFNumberRef generation = NULL; - - require_quiet(SOSAccountHasPublicKey(account, error), fail); - require_action_quiet(account->trusted_circle, fail, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle"))); - - generation = (CFNumberRef)SOSCircleGetGeneration(account->trusted_circle); - result = CFArrayCreateForCFTypes(kCFAllocatorDefault, generation, NULL); - -fail: - return result; -} - -bool SOSValidateUserPublic(SOSAccountRef account, CFErrorRef *error) { - if (!SOSAccountHasPublicKey(account, error)) - return NULL; - - return account->user_public_trusted; -} - -bool SOSAccountEnsurePeerRegistration(SOSAccountRef account, CFErrorRef *error) { - // TODO: this result is never set or used - bool result = true; - - secnotice("updates", "Ensuring peer registration."); - - require_quiet(account->trusted_circle, done); - require_quiet(account->my_identity, done); - require_quiet(account->user_public_trusted, done); - - // If we are not in the circle, there is no point in setting up peers - require_quiet(SOSAccountIsMyPeerActive(account, NULL), done); - - // This code only uses the SOSFullPeerInfoRef for two things: - // - Finding out if this device is in the trusted circle - // - Using the peerID for this device to see if the current peer is "me" - // - It is used indirectly by passing account->my_identity to SOSEngineInitializePeerCoder - - CFStringRef my_id = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(account->my_identity)); - - SOSCircleForEachValidSyncingPeer(account->trusted_circle, account->user_public, ^(SOSPeerInfoRef peer) { - if (!SOSPeerInfoPeerIDEqual(peer, my_id)) { - CFErrorRef localError = NULL; - SOSTransportMessageRef messageTransport = NULL; - - messageTransport = SOSPeerInfoHasDeviceID(peer) ? account->ids_message_transport : account->kvs_message_transport; - - SOSEngineInitializePeerCoder(messageTransport->engine, account->my_identity, peer, &localError); - if (localError) - secnotice("updates", "can't initialize transport for peer %@ with %@ (%@)", peer, account->my_identity, localError); - CFReleaseSafe(localError); - } - }); - - //Initialize our device ID - SOSTransportMessageIDSGetIDSDeviceID(account); - - -done: - return result; -} - -bool SOSAccountAddEscrowRecords(SOSAccountRef account, CFStringRef dsid, CFDictionaryRef record, CFErrorRef *error){ - CFMutableDictionaryRef escrowRecords = (CFMutableDictionaryRef)SOSAccountGetValue(account, kSOSEscrowRecord, error); - CFMutableDictionaryRef escrowCopied = NULL; - bool success = false; - - if(isDictionary(escrowRecords) && escrowRecords != NULL) - escrowCopied = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(escrowRecords), escrowRecords); - else - escrowCopied = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFDictionaryAddValue(escrowCopied, dsid, record); - SOSAccountSetValue(account, kSOSEscrowRecord, escrowCopied, error); - - if(*error == NULL) - success = true; - - CFReleaseNull(escrowCopied); - - return success; - -} - -bool SOSAccountAddEscrowToPeerInfo(SOSAccountRef account, SOSFullPeerInfoRef myPeer, CFErrorRef *error){ - bool success = false; - - CFDictionaryRef escrowRecords = SOSAccountGetValue(account, kSOSEscrowRecord, error); - success = SOSFullPeerInfoReplaceEscrowRecords(myPeer, escrowRecords, error); - - return success; -} - -bool SOSAccountCheckPeerAvailability(SOSAccountRef account, CFErrorRef *error) -{ - CFStringRef operationString = NULL; - CFDictionaryRef rawMessage = NULL; - CFMutableSetRef peers = NULL; - CFMutableDictionaryRef peerList = NULL; - char* message = NULL; - bool result = false; - - if(account->ids_message_transport == NULL) - account->ids_message_transport = (SOSTransportMessageRef)SOSTransportMessageIDSCreate(account, SOSCircleGetName(account->trusted_circle), error); - - require_quiet(account->ids_message_transport, fail); - - //adding message type kIDSPeerAvailability so KeychainSyncingOverIDSProxy does not send this message as a keychain item - - operationString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kIDSPeerAvailability); - rawMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kIDSOperationType, operationString, - kIDSMessageToSendKey, CFSTR("checking peers"), - NULL); - - peerList = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSCircleRef circle = account->trusted_circle; - - //check each peer to make sure they have the right view set enabled - CFSetRef mySubSet = SOSViewsGetV0SubviewSet(); - SOSCircleForEachValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) { - if(!CFEqualSafe(peer, SOSAccountGetMyPeerInfo(account))){ - CFMutableSetRef peerViews = SOSPeerInfoCopyEnabledViews(peer); - CFSetRef intersectSets = CFSetCreateIntersection(kCFAllocatorDefault, mySubSet, peerViews); - if(CFEqualSafe(intersectSets, mySubSet)){ - CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); - if(deviceID != NULL) - CFDictionaryAddValue(peerList, SOSPeerInfoGetPeerID(peer), rawMessage); - CFReleaseNull(deviceID); - } - CFReleaseNull(peerViews); - CFReleaseNull(intersectSets); - } - }); - - require_quiet(CFDictionaryGetCount(peerList) > 0 , fail); - result = SOSTransportMessageSendMessages(account->ids_message_transport, peerList, error); - -fail: - CFReleaseNull(rawMessage); - CFReleaseNull(operationString); - CFReleaseNull(peerList); - CFReleaseNull(peers); - free(message); - return result; -} - - -void SOSAccountRecordRetiredPeersInCircle(SOSAccountRef account) { - if (!SOSAccountIsInCircle(account, NULL)) - return; - - SOSAccountModifyCircle(account, NULL, ^bool (SOSCircleRef circle) { - __block bool updated = false; - CFSetForEach(account->retirees, ^(CFTypeRef element){ - SOSPeerInfoRef retiree = asSOSPeerInfo(element); - - if (retiree && SOSCircleUpdatePeerInfo(circle, retiree)) { - updated = true; - secnotice("retirement", "Updated retired peer %@ in %@", retiree, circle); - CFErrorRef cleanupError = NULL; - if (!SOSAccountCleanupAfterPeer(account, RETIREMENT_FINALIZATION_SECONDS, circle, retiree, &cleanupError)) - secerror("Error cleanup up after peer (%@): %@", retiree, cleanupError); - CFReleaseSafe(cleanupError); - } - }); - return updated; - }); -} - - -static size_t SOSPiggyBackBlobGetDEREncodedSize(SOSGenCountRef gencount, SecKeyRef pubKey, CFDataRef signature, CFErrorRef *error) { - size_t total_payload = 0; - - CFDataRef publicBytes = NULL; - OSStatus result = SecKeyCopyPublicBytes(pubKey, &publicBytes); - - if (result != errSecSuccess) { - SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error); - return 0; - } - - require_quiet(accumulate_size(&total_payload, der_sizeof_number(gencount, error)), errOut); - require_quiet(accumulate_size(&total_payload, der_sizeof_data_or_null(publicBytes, error)), errOut); - require_quiet(accumulate_size(&total_payload, der_sizeof_data_or_null(signature, error)), errOut); - return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, total_payload); - -errOut: - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error); - return 0; -} - -static uint8_t* SOSPiggyBackBlobEncodeToDER(SOSGenCountRef gencount, SecKeyRef pubKey, CFDataRef signature, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { - CFDataRef publicBytes = NULL; - - OSStatus result = SecKeyCopyPublicBytes(pubKey, &publicBytes); - - if (result != errSecSuccess) { - SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error); - return NULL; - } - - - der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, - der_encode_number(gencount, error, der, - der_encode_data_or_null(publicBytes, error, der, - der_encode_data_or_null(signature, error, der, der_end)))); - return der_end; -} - -static CFDataRef SOSPiggyBackBlobCopyEncodedData(SOSGenCountRef gencount, SecKeyRef pubKey, CFDataRef signature, CFAllocatorRef allocator, CFErrorRef *error) -{ - return CFDataCreateWithDER(kCFAllocatorDefault, SOSPiggyBackBlobGetDEREncodedSize(gencount, pubKey, signature, error), ^uint8_t*(size_t size, uint8_t *buffer) { - return SOSPiggyBackBlobEncodeToDER(gencount, pubKey, signature, error, buffer, (uint8_t *) buffer + size); - }); -} - -struct piggyBackBlob { - SOSGenCountRef gencount; - SecKeyRef pubKey; - CFDataRef signature; -}; - -static struct piggyBackBlob *SOSPiggyBackBlobCreateFromDER(CFAllocatorRef allocator, CFErrorRef *error, - const uint8_t** der_p, const uint8_t *der_end) { - const uint8_t *sequence_end; - struct piggyBackBlob *retval = NULL; - SOSGenCountRef gencount = NULL; - CFDataRef signature = NULL; - CFDataRef publicBytes = NULL; - - *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(allocator, 0, &gencount, error, *der_p, sequence_end); - *der_p = der_decode_data_or_null(kCFAllocatorDefault, &publicBytes, error, *der_p, der_end); - *der_p = der_decode_data_or_null(kCFAllocatorDefault, &signature, error, *der_p, der_end); - require_action_quiet(*der_p && *der_p == der_end, errOut, - SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes for pbblob"), (error != NULL) ? *error : NULL, error)); - retval = malloc(sizeof(struct piggyBackBlob)); - retval->gencount = gencount; - retval->signature = signature; - retval->pubKey = SecKeyCreateFromPublicData(kCFAllocatorDefault, kSecECDSAAlgorithmID, publicBytes); - -errOut: - if(!retval) { - CFReleaseNull(gencount); - CFReleaseNull(publicBytes); - CFReleaseNull(signature); - } - return retval; -} - -static struct piggyBackBlob *SOSPiggyBackBlobCreateFromData(CFAllocatorRef allocator, CFDataRef blobData, CFErrorRef *error) -{ - size_t size = CFDataGetLength(blobData); - const uint8_t *der = CFDataGetBytePtr(blobData); - struct piggyBackBlob *inflated = SOSPiggyBackBlobCreateFromDER(allocator, error, &der, der + size); - return inflated; -} - - - -SOSPeerInfoRef SOSAccountCopyApplication(SOSAccountRef account, CFErrorRef* error) { - SOSPeerInfoRef applicant = NULL; - SecKeyRef userKey = SOSAccountGetPrivateCredential(account, error); - if(!userKey) return false; - require_quiet(SOSAccountEnsureFullPeerAvailable(account, error), errOut); - require(SOSFullPeerInfoPromoteToApplication(account->my_identity, userKey, error), errOut); - applicant = SOSPeerInfoCreateCopy(kCFAllocatorDefault, (SOSFullPeerInfoGetPeerInfo(account->my_identity)), error); -errOut: - return applicant; -} - - -CFDataRef SOSAccountCopyCircleJoiningBlob(SOSAccountRef account, SOSPeerInfoRef applicant, CFErrorRef *error) { - SOSGenCountRef gencount = NULL; - CFDataRef signature = NULL; - SecKeyRef ourKey = NULL; - - CFDataRef pbblob = NULL; - - secnotice("circleJoin", "Making circle joining blob as sponsor (SOSAccountCopyCircleJoiningBlob)"); - - SecKeyRef userKey = SOSAccountGetTrustedPublicCredential(account, error); - require_quiet(userKey, errOut); - - require_action_quiet(applicant, errOut, SOSCreateError(kSOSErrorProcessingFailure, CFSTR("No applicant provided"), (error != NULL) ? *error : NULL, error)); - require_quiet(SOSPeerInfoApplicationVerify(applicant, userKey, error), errOut); - - { - SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account); - ourKey = SOSFullPeerInfoCopyDeviceKey(fpi, error); - require_quiet(ourKey, errOut); - } - - SOSCircleRef currentCircle = SOSAccountGetCircle(account, error); - require_quiet(currentCircle, errOut); - - SOSCircleRef prunedCircle = SOSCircleCopyCircle(NULL, currentCircle, error); - require_quiet(prunedCircle, errOut); - require_quiet(SOSCirclePreGenerationSign(prunedCircle, userKey, error), errOut); - - gencount = SOSGenerationIncrementAndCreate(SOSCircleGetGeneration(prunedCircle)); - - signature = SOSCircleCopyNextGenSignatureWithPeerAdded(prunedCircle, applicant, ourKey, error); - require_quiet(signature, errOut); - - pbblob = SOSPiggyBackBlobCopyEncodedData(gencount, ourKey, signature, kCFAllocatorDefault, error); - -errOut: - CFReleaseNull(gencount); - CFReleaseNull(signature); - CFReleaseNull(ourKey); - - if(!pbblob) { - secnotice("circleJoin", "Failed to make circle joining blob as sponsor %@", *error); - } - - return pbblob; -} - -bool SOSAccountJoinWithCircleJoiningBlob(SOSAccountRef account, CFDataRef joiningBlob, CFErrorRef *error) { - bool retval = false; - SecKeyRef userKey = NULL; - struct piggyBackBlob *pbb = NULL; - - secnotice("circleJoin", "Joining circles through piggy-back (SOSAccountCopyCircleJoiningBlob)"); - - userKey = SOSAccountGetPrivateCredential(account, error); - require_quiet(userKey, errOut); - pbb = SOSPiggyBackBlobCreateFromData(kCFAllocatorDefault, joiningBlob, error); - require_quiet(pbb, errOut); - - SOSAccountSetValue(account, kSOSUnsyncedViewsKey, kCFBooleanTrue, NULL); - - retval = SOSAccountModifyCircle(account, error, ^bool(SOSCircleRef copyOfCurrent) { - return SOSCircleAcceptPeerFromHSA2(copyOfCurrent, userKey, - pbb->gencount, - pbb->pubKey, - pbb->signature, - account->my_identity, error);; - - }); - -errOut: - if(pbb) { - CFReleaseNull(pbb->gencount); - CFReleaseNull(pbb->pubKey); - CFReleaseNull(pbb->signature); - free(pbb); - } - return retval; -} - -static char boolToChars(bool val, char truechar, char falsechar) { - return val? truechar: falsechar; -} - -#define ACCOUNTLOGSTATE "accountLogState" -void SOSAccountLogState(SOSAccountRef account) { - bool hasPubKey = account->user_public != NULL; - bool pubTrusted = account->user_public_trusted; - bool hasPriv = account->_user_private != NULL; - SOSCCStatus stat = SOSAccountGetCircleStatus(account, NULL); - CFStringRef userPubKeyID = (account->user_public) ? SOSCopyIDOfKeyWithLength(account->user_public, 8, NULL): - CFStringCreateCopy(kCFAllocatorDefault, CFSTR("*No Key*")); - - secnotice(ACCOUNTLOGSTATE, "Start"); - - secnotice(ACCOUNTLOGSTATE, "ACCOUNT: [keyStatus: %c%c%c hpub %@] [SOSCCStatus: %@]", - boolToChars(hasPubKey, 'U', 'u'), boolToChars(pubTrusted, 'T', 't'), boolToChars(hasPriv, 'I', 'i'), - userPubKeyID, - SOSAccountGetSOSCCStatusString(stat) - ); - CFReleaseNull(userPubKeyID); - if(account->trusted_circle) SOSCircleLogState(ACCOUNTLOGSTATE, account->trusted_circle, account->user_public, SOSAccountGetMyPeerID(account)); - else secnotice(ACCOUNTLOGSTATE, "ACCOUNT: No Circle"); -} - -void SOSAccountLogViewState(SOSAccountRef account) { - bool isInCircle = SOSAccountIsInCircle(account, NULL); - require_quiet(isInCircle, imOut); - SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(account); - bool isInitialComplete = SOSAccountHasCompletedInitialSync(account); - bool isBackupComplete = SOSAccountHasCompletedRequiredBackupSync(account); - - CFSetRef views = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL; - CFStringSetPerformWithDescription(views, ^(CFStringRef description) { - secnotice(ACCOUNTLOGSTATE, "Sync: %c%c PeerViews: %@", - boolToChars(isInitialComplete, 'I', 'i'), - boolToChars(isBackupComplete, 'B', 'b'), - description); - }); - CFReleaseNull(views); - CFSetRef unsyncedViews = SOSAccountCopyOutstandingViews(account); - CFStringSetPerformWithDescription(views, ^(CFStringRef description) { - secnotice(ACCOUNTLOGSTATE, "outstanding views: %@", description); - }); - CFReleaseNull(unsyncedViews); - -imOut: - secnotice(ACCOUNTLOGSTATE, "Finish"); - - return; -} - - -void SOSAccountSetTestSerialNumber(SOSAccountRef account, CFStringRef serial) { - if(!isString(serial)) return; - CFMutableDictionaryRef newv2dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionarySetValue(newv2dict, sSerialNumberKey, serial); - SOSAccountUpdateV2Dictionary(account, newv2dict); -} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.h index 80cdb325..9c21a109 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.h @@ -31,266 +31,216 @@ #ifndef _SOSACCOUNT_H_ #define _SOSACCOUNT_H_ -/* Forward declarations of SOS types. */ -typedef struct __OpaqueSOSAccount *SOSAccountRef; -typedef struct __OpaqueSOSRecoveryKeyBag *SOSRecoveryKeyBagRef; - #include - -#include +#include +#include #include #include #include #include -#include #include -#include #include #include #include - +#include #include +@class SOSAccount; + __BEGIN_DECLS #define RETIREMENT_FINALIZATION_SECONDS (24*60*60) - typedef void (^SOSAccountCircleMembershipChangeBlock)(SOSCircleRef new_circle, CFSetRef added_peers, CFSetRef removed_peers, CFSetRef added_applicants, CFSetRef removed_applicants); -typedef void (^SOSAccountSyncablePeersBlock)(CFArrayRef trustedPeers, CFArrayRef addedPeers, CFArrayRef removedPeers); -typedef bool (^SOSAccountWaitForInitialSyncBlock)(SOSAccountRef account); -typedef void (^SOSAccountSaveBlock)(CFDataRef flattenedAccount, CFErrorRef flattenFailError); -SOSAccountRef SOSAccountCreate(CFAllocatorRef allocator, - CFDictionaryRef gestalt, - SOSDataSourceFactoryRef factory); -SOSAccountRef SOSAccountCreateBasic(CFAllocatorRef allocator, +CFTypeID SOSAccountGetTypeID(void); + +SOSAccount* SOSAccountCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, SOSDataSourceFactoryRef factory); - -CFTypeID SOSAccountGetTypeID(void); - // // MARK: Persistent Encode decode // -SOSAccountRef SOSAccountCreateFromDER(CFAllocatorRef allocator, SOSDataSourceFactoryRef factory, - CFErrorRef* error, - const uint8_t** der_p, const uint8_t *der_end); -SOSAccountRef SOSAccountCreateFromData(CFAllocatorRef allocator, CFDataRef circleData, - SOSDataSourceFactoryRef factory, - CFErrorRef* error); - -size_t SOSAccountGetDEREncodedSize(SOSAccountRef cir, CFErrorRef *error); -uint8_t* SOSAccountEncodeToDER(SOSAccountRef cir, CFErrorRef* error, const uint8_t* der, uint8_t* der_end); -size_t SOSAccountGetDEREncodedSize_V3(SOSAccountRef cir, CFErrorRef *error); -uint8_t* SOSAccountEncodeToDER_V3(SOSAccountRef cir, CFErrorRef* error, const uint8_t* der, uint8_t* der_end); -CFDataRef SOSAccountCopyEncodedData(SOSAccountRef circle, CFAllocatorRef allocator, CFErrorRef *error); // //MARK: IDS Device ID -CFStringRef SOSAccountCopyDeviceID(SOSAccountRef account, CFErrorRef *error); -bool SOSAccountSetMyDSID(SOSAccountTransactionRef txn, CFStringRef IDS, CFErrorRef* errror); -bool SOSAccountSendIDSTestMessage(SOSAccountRef account, CFStringRef message, CFErrorRef *error); -bool SOSAccountStartPingTest(SOSAccountRef account, CFStringRef message, CFErrorRef *error); -bool SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(SOSAccountRef account, CFErrorRef *error); +CFStringRef SOSAccountCopyDeviceID(SOSAccount* account, CFErrorRef *error); +bool SOSAccountSetMyDSID(SOSAccountTransaction* txn, CFStringRef IDS, CFErrorRef* errror); +bool SOSAccountSendIDSTestMessage(SOSAccount* account, CFStringRef message, CFErrorRef *error); +bool SOSAccountStartPingTest(SOSAccount* account, CFStringRef message, CFErrorRef *error); +bool SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(SOSAccount* account, CFErrorRef *error); // // MARK: Credential management // -SecKeyRef SOSAccountGetTrustedPublicCredential(SOSAccountRef account, CFErrorRef* error); +SecKeyRef SOSAccountGetTrustedPublicCredential(SOSAccount* account, CFErrorRef* error); + +SecKeyRef SOSAccountGetPrivateCredential(SOSAccount* account, CFErrorRef* error); +CFDataRef SOSAccountGetCachedPassword(SOSAccount* account, CFErrorRef* error); +void SOSAccountStashAccountKey(SOSAccount* account); +SecKeyRef SOSAccountCopyStashedUserPrivateKey(SOSAccount* account, CFErrorRef *error); -SecKeyRef SOSAccountGetPrivateCredential(SOSAccountRef account, CFErrorRef* error); -CFDataRef SOSAccountGetCachedPassword(SOSAccountRef account, CFErrorRef* error); +void SOSAccountSetParameters(SOSAccount* account, CFDataRef parameters); -void SOSAccountSetParameters(SOSAccountRef account, CFDataRef parameters); +void SOSAccountPurgePrivateCredential(SOSAccount* account); -void SOSAccountPurgePrivateCredential(SOSAccountRef account); +void SOSAccountRestartPrivateCredentialTimer(SOSAccount* account); -bool SOSAccountTryUserCredentials(SOSAccountRef account, +bool SOSAccountTryUserCredentials(SOSAccount* account, CFStringRef user_account, CFDataRef user_password, CFErrorRef *error); -bool SOSAccountAssertUserCredentials(SOSAccountRef account, +bool SOSAccountTryUserPrivateKey(SOSAccount* account, SecKeyRef user_private, CFErrorRef *error); + +bool SOSAccountValidateAccountCredential(SOSAccount* account, SecKeyRef accountPrivateKey, CFErrorRef *error); +bool SOSAccountAssertStashedAccountCredential(SOSAccount* account, CFErrorRef *error); +bool SOSAccountAssertUserCredentials(SOSAccount* account, CFStringRef user_account, CFDataRef user_password, CFErrorRef *error); -bool SOSAccountRetryUserCredentials(SOSAccountRef account); -void SOSAccountSetUnTrustedUserPublicKey(SOSAccountRef account, SecKeyRef publicKey); +bool SOSAccountRetryUserCredentials(SOSAccount* account); +void SOSAccountSetUnTrustedUserPublicKey(SOSAccount* account, SecKeyRef publicKey); -bool SOSAccountGenerationSignatureUpdate(SOSAccountRef account, CFErrorRef *error); +bool SOSAccountGenerationSignatureUpdate(SOSAccount* account, CFErrorRef *error); // // MARK: Circle management // -bool SOSAccountUpdateCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef *error); -void SOSTransportEachMessage(SOSAccountRef account, CFDictionaryRef updates, CFErrorRef *error); +bool SOSAccountUpdateCircle(SOSAccount* account, SOSCircleRef circle, CFErrorRef *error); +void SOSTransportEachMessage(SOSAccount* account, CFDictionaryRef updates, CFErrorRef *error); -SOSCCStatus SOSAccountGetCircleStatus(SOSAccountRef account, CFErrorRef* error); CFStringRef SOSAccountGetSOSCCStatusString(SOSCCStatus status); -bool SOSAccountIsInCircle(SOSAccountRef account, CFErrorRef *error); -bool SOSAccountJoinCircles(SOSAccountTransactionRef aTxn, CFErrorRef* error); -bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransactionRef aTxn, CFErrorRef* error); -bool SOSAccountLeaveCircle(SOSAccountRef account,CFErrorRef* error); -bool SOSAccountRemovePeersFromCircle(SOSAccountRef account, CFArrayRef peers, CFErrorRef* error); -bool SOSAccountBail(SOSAccountRef account, uint64_t limit_in_seconds, CFErrorRef* error); -bool SOSAccountAcceptApplicants(SOSAccountRef account, CFArrayRef applicants, CFErrorRef* error); -bool SOSAccountRejectApplicants(SOSAccountRef account, CFArrayRef applicants, CFErrorRef* error); - -bool SOSAccountResetToOffering(SOSAccountTransactionRef aTxn, CFErrorRef* error); -bool SOSAccountResetToEmpty(SOSAccountRef account, CFErrorRef* error); -bool SOSValidateUserPublic(SOSAccountRef account, CFErrorRef* error); - -void SOSAccountForEachCirclePeerExceptMe(SOSAccountRef account, void (^action)(SOSPeerInfoRef peer)); - -CFArrayRef SOSAccountCopyApplicants(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyGeneration(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyValidPeers(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyPeersToListenTo(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyNotValidPeers(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyRetired(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyViewUnaware(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyPeers(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyActivePeers(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyActiveValidPeers(SOSAccountRef account, CFErrorRef *error); -CFArrayRef SOSAccountCopyConcurringPeers(SOSAccountRef account, CFErrorRef *error); - -SOSFullPeerInfoRef SOSAccountCopyAccountIdentityPeerInfo(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef* error); -bool SOSAccountIsAccountIdentity(SOSAccountRef account, SOSPeerInfoRef peer_info, CFErrorRef *error); - -enum DepartureReason SOSAccountGetLastDepartureReason(SOSAccountRef account, CFErrorRef* error); +SOSCCStatus SOSAccountGetSOSCCStatusFromString(CFStringRef status); +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); -// -// MARK: iCloud Identity -// -bool SOSAccountAddiCloudIdentity(SOSAccountRef account, SOSCircleRef circle, SecKeyRef user_key, CFErrorRef *error); -bool SOSAccountRemoveIncompleteiCloudIdentities(SOSAccountRef account, SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error); +bool SOSValidateUserPublic(SOSAccount* account, CFErrorRef* error); + +void SOSAccountForEachCirclePeerExceptMe(SOSAccount* account, void (^action)(SOSPeerInfoRef peer)); + +CFArrayRef SOSAccountCopyApplicants(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyGeneration(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyValidPeers(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyPeersToListenTo(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyNotValidPeers(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyRetired(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyViewUnaware(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyPeers(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyActivePeers(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyActiveValidPeers(SOSAccount* account, CFErrorRef *error); +CFArrayRef SOSAccountCopyConcurringPeers(SOSAccount* account, CFErrorRef *error); + +bool SOSAccountIsAccountIdentity(SOSAccount* account, SOSPeerInfoRef peer_info, CFErrorRef *error); + +enum DepartureReason SOSAccountGetLastDepartureReason(SOSAccount* account, CFErrorRef* error); // -// MARK: Save Block +// MARK: iCloud Identity // - -void SOSAccountSetSaveBlock(SOSAccountRef account, SOSAccountSaveBlock saveBlock); -void SOSAccountFlattenToSaveBlock(SOSAccountRef account); +bool SOSAccountRemoveIncompleteiCloudIdentities(SOSAccount* account, SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error); // // MARK: Change blocks // -void SOSAccountAddChangeBlock(SOSAccountRef a, SOSAccountCircleMembershipChangeBlock changeBlock); -void SOSAccountRemoveChangeBlock(SOSAccountRef a, SOSAccountCircleMembershipChangeBlock changeBlock); +void SOSAccountAddChangeBlock(SOSAccount* a, SOSAccountCircleMembershipChangeBlock changeBlock); +void SOSAccountRemoveChangeBlock(SOSAccount* a, SOSAccountCircleMembershipChangeBlock changeBlock); -void SOSAccountAddSyncablePeerBlock(SOSAccountRef a, - CFStringRef ds_name, - SOSAccountSyncablePeersBlock changeBlock); // // MARK: Local device gestalt change. // -bool SOSAccountUpdateGestalt(SOSAccountRef account, CFDictionaryRef new_gestalt); - -CFDictionaryRef SOSAccountCopyGestalt(SOSAccountRef account); +CFDictionaryRef SOSAccountCopyGestalt(SOSAccount* account); -CFDictionaryRef SOSAccountCopyV2Dictionary(SOSAccountRef account); +CFDictionaryRef SOSAccountCopyV2Dictionary(SOSAccount* account); -bool SOSAccountUpdateV2Dictionary(SOSAccountRef account, CFDictionaryRef newV2Dict); +void SOSAccountPendDisableViewSet(SOSAccount* account, CFSetRef disabledViews); -bool SOSAccountUpdateFullPeerInfo(SOSAccountRef account, CFSetRef minimumViews, CFSetRef excludedViews); +void SOSAccountUpdateOutOfSyncViews(SOSAccountTransaction* aTxn, CFSetRef viewsInSync); +void SOSAccountPeerGotInSync(SOSAccountTransaction* aTxn, CFStringRef peerID, CFSetRef views); -SOSViewResultCode SOSAccountUpdateView(SOSAccountRef account, CFStringRef viewname, SOSViewActionCode actionCode, CFErrorRef *error); - -SOSViewResultCode SOSAccountViewStatus(SOSAccountRef account, CFStringRef viewname, CFErrorRef *error); - -bool SOSAccountUpdateViewSets(SOSAccountRef account, CFSetRef enabledViews, CFSetRef disabledViews); - -void SOSAccountPendEnableViewSet(SOSAccountRef account, CFSetRef enabledViews); -void SOSAccountPendDisableViewSet(SOSAccountRef account, CFSetRef disabledViews); - - -SOSSecurityPropertyResultCode SOSAccountUpdateSecurityProperty(SOSAccountRef account, CFStringRef property, SOSSecurityPropertyActionCode actionCode, CFErrorRef *error); - -SOSSecurityPropertyResultCode SOSAccountSecurityPropertyStatus(SOSAccountRef account, CFStringRef property, CFErrorRef *error); - - -bool SOSAccountHandleParametersChange(SOSAccountRef account, CFDataRef updates, CFErrorRef *error); +bool SOSAccountHandleParametersChange(SOSAccount* account, CFDataRef updates, CFErrorRef *error); // // MARK: Requests for syncing later // -bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransactionRef txn, CFErrorRef *error); +bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransaction* txn, CFErrorRef *error); +CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peerIDs, CFErrorRef *error); +CF_RETURNS_RETAINED CFSetRef SOSAccountSyncWithPeersOverIDS(SOSAccountTransaction* txn, CFSetRef peers); +CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransaction* txn, CFSetRef peers); +bool SOSAccountInflateTransports(SOSAccount* account, CFStringRef circleName, CFErrorRef *error); // // MARK: Outgoing/Sync functions // -bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransactionRef txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error); -bool SOSAccountClearPeerMessageKey(SOSAccountTransactionRef txn, CFStringRef peerID, CFErrorRef *error); +bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransaction* txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error); +bool SOSAccountClearPeerMessageKey(SOSAccountTransaction* txn, CFStringRef peerID, CFErrorRef *error); -CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransactionRef txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error); +CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error); +CF_RETURNS_RETAINED CFSetRef SOSAccountCopyBackupPeersAndForceSync(SOSAccountTransaction* txn, CFErrorRef *error); -bool SOSAccountSendIKSPSyncList(SOSAccountRef account, CFErrorRef *error); -bool SOSAccountSyncWithKVSUsingIDSID(SOSAccountRef account, CFStringRef deviceID, CFErrorRef *error); +bool SOSAccountSendIKSPSyncList(SOSAccount* account, CFErrorRef *error); +bool SOSAccountSyncWithKVSUsingIDSID(SOSAccount* account, CFStringRef deviceID, CFErrorRef *error); // // MARK: Cleanup functions // -bool SOSAccountCleanupAfterPeer(SOSAccountRef account, size_t seconds, SOSCircleRef circle, - SOSPeerInfoRef cleanupPeer, CFErrorRef* error); - -bool SOSAccountCleanupRetirementTickets(SOSAccountRef account, size_t seconds, CFErrorRef* error); - -bool SOSAccountScanForRetired(SOSAccountRef account, SOSCircleRef circle, CFErrorRef *error); -SOSCircleRef SOSAccountCloneCircleWithRetirement(SOSAccountRef account, SOSCircleRef starting_circle, CFErrorRef *error); - -bool SOSAccountPostDebugScope(SOSAccountRef account, CFTypeRef scope, CFErrorRef *error); +bool SOSAccountScanForRetired(SOSAccount* account, SOSCircleRef circle, CFErrorRef *error); +SOSCircleRef SOSAccountCloneCircleWithRetirement(SOSAccount* account, SOSCircleRef starting_circle, CFErrorRef *error); // // MARK: Version incompatibility Functions // -CFStringRef SOSAccountCopyIncompatibilityInfo(SOSAccountRef account, CFErrorRef* error); +CFStringRef SOSAccountCopyIncompatibilityInfo(SOSAccount* account, CFErrorRef* error); // // MARK: Backup functions // -bool SOSAccountIsBackupRingEmpty(SOSAccountRef account, CFStringRef viewName); -bool SOSAccountNewBKSBForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error); +bool SOSAccountIsBackupRingEmpty(SOSAccount* account, CFStringRef viewName); +bool SOSAccountNewBKSBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error); -bool SOSAccountSetBackupPublicKey(SOSAccountTransactionRef aTxn, CFDataRef backupKey, CFErrorRef *error); -bool SOSAccountRemoveBackupPublickey(SOSAccountTransactionRef aTxn, CFErrorRef *error); -bool SOSAccountSetBSKBagForAllSlices(SOSAccountRef account, CFDataRef backupSlice, bool setupV0Only, CFErrorRef *error); +bool SOSAccountSetBackupPublicKey(SOSAccountTransaction* aTxn, CFDataRef backupKey, CFErrorRef *error); +bool SOSAccountRemoveBackupPublickey(SOSAccountTransaction* aTxn, CFErrorRef *error); +bool SOSAccountSetBSKBagForAllSlices(SOSAccount* account, CFDataRef backupSlice, bool setupV0Only, CFErrorRef *error); -SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef* error); +SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccount* account, CFStringRef viewName, CFErrorRef* error); -bool SOSAccountIsLastBackupPeer(SOSAccountRef account, CFErrorRef *error); +bool SOSAccountIsLastBackupPeer(SOSAccount* account, CFErrorRef *error); // // MARK: Recovery Public Key Functions // -bool SOSAccountRegisterRecoveryPublicKey(SOSAccountTransactionRef txn, CFDataRef recovery_key, CFErrorRef *error); -CFDataRef SOSAccountCopyRecoveryPublicKey(SOSAccountTransactionRef txn, CFErrorRef *error); -bool SOSAccountClearRecoveryPublicKey(SOSAccountTransactionRef txn, CFDataRef recovery_key, CFErrorRef *error); -bool SOSAccountSetRecoveryKey(SOSAccountRef account, CFDataRef pubData, CFErrorRef *error); -bool SOSAccountRemoveRecoveryKey(SOSAccountRef account, CFErrorRef *error); -SOSRecoveryKeyBagRef SOSAccountCopyRecoveryKeyBag(CFAllocatorRef allocator, SOSAccountRef account, CFErrorRef *error); -CFDataRef SOSAccountCopyRecoveryPublic(CFAllocatorRef allocator, SOSAccountRef account, CFErrorRef *error); -bool SOSAccountRecoveryKeyIsInBackupAndCurrentInView(SOSAccountRef account, CFStringRef viewname); -bool SOSAccountSetRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccountRef account, SOSRecoveryKeyBagRef rkbg, CFErrorRef *error); -SOSRecoveryKeyBagRef SOSAccountCopyRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccountRef account, CFErrorRef *error); -void SOSAccountEnsureRecoveryRing(SOSAccountRef account); +bool SOSAccountRegisterRecoveryPublicKey(SOSAccountTransaction* txn, CFDataRef recovery_key, CFErrorRef *error); +CFDataRef SOSAccountCopyRecoveryPublicKey(SOSAccountTransaction* txn, CFErrorRef *error); +bool SOSAccountClearRecoveryPublicKey(SOSAccountTransaction* txn, CFDataRef recovery_key, CFErrorRef *error); +bool SOSAccountSetRecoveryKey(SOSAccount* account, CFDataRef pubData, CFErrorRef *error); +bool SOSAccountRemoveRecoveryKey(SOSAccount* account, CFErrorRef *error); +SOSRecoveryKeyBagRef SOSAccountCopyRecoveryKeyBag(CFAllocatorRef allocator, SOSAccount* account, CFErrorRef *error); +CFDataRef SOSAccountCopyRecoveryPublic(CFAllocatorRef allocator, SOSAccount* account, CFErrorRef *error); +bool SOSAccountRecoveryKeyIsInBackupAndCurrentInView(SOSAccount* account, CFStringRef viewname); +bool SOSAccountSetRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccount* account, SOSRecoveryKeyBagRef rkbg, CFErrorRef *error); +SOSRecoveryKeyBagRef SOSAccountCopyRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccount* account, CFErrorRef *error); +void SOSAccountEnsureRecoveryRing(SOSAccount* account); // // MARK: Private functions // -dispatch_queue_t SOSAccountGetQueue(SOSAccountRef account); +dispatch_queue_t SOSAccountGetQueue(SOSAccount* account); typedef bool (^SOSAccountSendBlock)(CFStringRef key, CFDataRef message, CFErrorRef *error); @@ -298,63 +248,56 @@ typedef bool (^SOSAccountSendBlock)(CFStringRef key, CFDataRef message, CFErrorR // MARK: Utility functions // -CFStringRef SOSAccountCreateCompactDescription(SOSAccountRef a); CFStringRef SOSInterestListCopyDescription(CFArrayRef interests); -// -// MARK: View Funcitons -// - -// Use these to tell the engine what views are common to myPeer and other circle peers -CFArrayRef SOSCreateActiveViewIntersectionArrayForPeerID(SOSAccountRef account, CFStringRef peerID); -CFDictionaryRef SOSViewsCreateActiveViewMatrixDictionary(SOSAccountRef account, SOSCircleRef circle, CFErrorRef *error); - -const uint8_t* der_decode_cloud_parameters(CFAllocatorRef allocator, - CFIndex algorithmID, SecKeyRef* publicKey, - CFDataRef *parameters, - CFErrorRef* error, - const uint8_t* der, const uint8_t* der_end); - -/* CFSet <-> XPC functions */ -CFSetRef CreateCFSetRefFromXPCObject(xpc_object_t xpcSetDER, CFErrorRef* error); -xpc_object_t CreateXPCObjectWithCFSetRef(CFSetRef setref, CFErrorRef *error); - - // // MARK: HSA2 Piggyback Support Functions // - -SOSPeerInfoRef SOSAccountCopyApplication(SOSAccountRef account, CFErrorRef*); -CFDataRef SOSAccountCopyCircleJoiningBlob(SOSAccountRef account, SOSPeerInfoRef applicant, CFErrorRef *error); -bool SOSAccountJoinWithCircleJoiningBlob(SOSAccountRef account, CFDataRef joiningBlob, CFErrorRef *error); - +SOSPeerInfoRef SOSAccountCopyApplication(SOSAccount* account, CFErrorRef*); +CFDataRef SOSAccountCopyCircleJoiningBlob(SOSAccount* account, SOSPeerInfoRef applicant, CFErrorRef *error); +bool SOSAccountJoinWithCircleJoiningBlob(SOSAccount* account, CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); +CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, CFErrorRef *error); + // // MARK: Initial-Sync // -bool SOSAccountHasCompletedInitialSync(SOSAccountRef account); -CFMutableSetRef SOSAccountCopyUnsyncedInitialViews(SOSAccountRef account); -bool SOSAccountHasCompletedRequiredBackupSync(SOSAccountRef account); +CFMutableSetRef SOSAccountCopyUnsyncedInitialViews(SOSAccount* account); // // MARK: State Logging // -void SOSAccountLogState(SOSAccountRef account); -void SOSAccountLogViewState(SOSAccountRef account); +void SOSAccountLogState(SOSAccount* account); +void SOSAccountLogViewState(SOSAccount* account); +void SOSAccountConsiderLoggingEngineState(SOSAccountTransaction* txn); // // MARK: Checking other peer views // -CFBooleanRef SOSAccountPeersHaveViewsEnabled(SOSAccountRef account, CFArrayRef viewNames, CFErrorRef *error); +CFBooleanRef SOSAccountPeersHaveViewsEnabled(SOSAccount* account, CFArrayRef viewNames, CFErrorRef *error); -void SOSAccountSetTestSerialNumber(SOSAccountRef account, CFStringRef serial); +void SOSAccountSetTestSerialNumber(SOSAccount* account, CFStringRef serial); +SOSViewResultCode SOSAccountVirtualV0Behavior(SOSAccount* account, SOSViewActionCode actionCode); + + +bool SOSAccountIsPeerRetired(SOSAccount* account, CFSetRef peers); +void SOSAccountNotifyOfChange(SOSAccount* account, SOSCircleRef oldCircle, SOSCircleRef newCircle); // // MARK: Syncing status functions // -bool SOSAccountMessageFromPeerIsPending(SOSAccountTransactionRef txn, SOSPeerInfoRef peer, CFErrorRef *error); -bool SOSAccountSendToPeerIsPending(SOSAccountTransactionRef txn, SOSPeerInfoRef peer, CFErrorRef *error); +bool SOSAccountMessageFromPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error); +bool SOSAccountSendToPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error); + +// +// MARK: OTR +// +void SOSAccountResetOTRNegotiationCoder(SOSAccountTransaction* txn, CFStringRef peerid); +void SOSAccountTimerFiredSendNextMessage(SOSAccountTransaction* txn, NSString* peerid, NSString* accessGroup); + +NSMutableArray* SOSAccountGetAllTLKs(void); +CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* account); __END_DECLS diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.m new file mode 100644 index 00000000..90bf2549 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccount.m @@ -0,0 +1,2771 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + */ + +/* + * SOSAccount.c - Implementation of the secure object syncing account. + * An account contains a SOSCircle for each protection domain synced. + */ + +#import +#import +#import + + +#include +#include +#include +#include +#import "Security/SecureObjectSync/SOSTransportCircle.h" +#import "Security/SecureObjectSync/SOSTransportCircleKVS.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#import +#import +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Identity.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" +#import "Security/SecureObjectSync/SOSPeerOTRTimer.h" +#import "Security/SecureObjectSync/SOSPeerRateLimiter.h" +#import "Security/SecureObjectSync/SOSTypes.h" +#import "keychain/ckks/CKKSViewManager.h" + +#include +#include +#include + +#include + +#import "SecdWatchdog.h" + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +const CFStringRef kSOSDSIDKey = CFSTR("AccountDSID"); +const CFStringRef kSOSEscrowRecord = CFSTR("EscrowRecord"); +const CFStringRef kSOSUnsyncedViewsKey = CFSTR("unsynced"); +const CFStringRef kSOSInitialSyncTimeoutV0 = CFSTR("initialsynctimeout"); +const CFStringRef kSOSPendingEnableViewsToBeSetKey = CFSTR("pendingEnableViews"); +const CFStringRef kSOSPendingDisableViewsToBeSetKey = CFSTR("pendingDisableViews"); +const CFStringRef kSOSTestV2Settings = CFSTR("v2dictionary"); +const CFStringRef kSOSRecoveryKey = CFSTR("RecoveryKey"); +const CFStringRef kSOSRecoveryRing = CFSTR("RecoveryRing"); +const CFStringRef kSOSAccountUUID = CFSTR("UUID"); +const CFStringRef kSOSRateLimitingCounters = CFSTR("RateLimitCounters"); +const CFStringRef kSOSAccountPeerNegotiationTimeouts = CFSTR("PeerNegotiationTimeouts"); //Dictionary +const CFStringRef kSOSAccountPeerLastSentTimestamp = CFSTR("kSOSAccountPeerLastSentTimestamp"); //Dictionary +const CFStringRef kSOSAccountRenegotiationRetryCount = CFSTR("NegotiationRetryCount"); +const CFStringRef kOTRConfigVersion = CFSTR("OTRConfigVersion"); +NSString* const SecSOSAggdReattemptOTRNegotiation = @"com.apple.security.sos.otrretry"; + +const uint64_t max_packet_size_over_idms = 500; + + +#define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable" + +#define DATE_LENGTH 25 +const CFStringRef kSOSAccountDebugScope = CFSTR("Scope"); + +@interface SOSAccount () +@property (retain,nonnull) NSXPCListener *listener; +@end + + +@interface SOSClient : NSObject +@property (weak) NSXPCConnection * connection; +@property (strong) SOSAccount * account; + +- (instancetype)initWithConnection:(NSXPCConnection *)connection account:(SOSAccount *)account; +@end + +@implementation SOSClient + +@synthesize account = _account; +@synthesize connection = _connection; + +- (instancetype)initWithConnection:(NSXPCConnection *)connection account:(SOSAccount *)account +{ + if ((self = [super init])) { + _connection = connection; + _account = account; + } + return self; +} + +- (bool)checkEntitlement:(NSString *)entitlement +{ + NSXPCConnection *strongConnection = _connection; + + NSNumber *num = [strongConnection valueForEntitlement:entitlement]; + if (![num isKindOfClass:[NSNumber class]] || ![num boolValue]) { + secinfo("sos", "Client pid: %d doesn't have entitlement: %@", + [strongConnection processIdentifier], entitlement); + return false; + } + return true; +} + +- (void)userPublicKey:(void ((^))(BOOL trusted, NSData *spki, NSError *error))reply +{ + [self.account userPublicKey:reply]; +} + +- (void)kvsPerformanceCounters:(void(^)(NSDictionary *))reply +{ + [self.account kvsPerformanceCounters:reply]; +} + +- (void)idsPerformanceCounters:(void(^)(NSDictionary *))reply +{ + [self.account idsPerformanceCounters:reply]; +} + +- (void)rateLimitingPerformanceCounters:(void(^)(NSDictionary *))reply +{ + [self.account rateLimitingPerformanceCounters:reply]; +} + +- (void)stashedCredentialPublicKey:(void(^)(NSData *, NSError *error))reply +{ + [self.account stashedCredentialPublicKey:reply]; +} + +- (void)assertStashedAccountCredential:(void(^)(BOOL result, NSError *error))reply +{ + [self.account assertStashedAccountCredential:reply]; +} + +- (void)validatedStashedAccountCredential:(void(^)(NSData *credential, NSError *error))complete +{ + [self.account validatedStashedAccountCredential:complete]; +} + +- (void)stashAccountCredential:(NSData *)credential complete:(void(^)(bool success, NSError *error))complete +{ + [self.account stashAccountCredential:credential complete:complete]; +} + +- (void)myPeerInfo:(void (^)(NSData *, NSError *))complete +{ + [self.account myPeerInfo:complete]; +} + +- (void)circleJoiningBlob:(NSData *)applicant complete:(void (^)(NSData *blob, NSError *))complete +{ + [self.account circleJoiningBlob:applicant complete:complete]; +} + +- (void)joinCircleWithBlob:(NSData *)blob version:(PiggyBackProtocolVersion)version complete:(void (^)(bool success, NSError *))complete +{ + [self.account joinCircleWithBlob:blob version:version complete:complete]; +} + +- (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete +{ + if (![self checkEntitlement:(__bridge NSString *)kSecEntitlementKeychainInitialSync]) { + complete(@[], [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSEntitlementMissing userInfo:NULL]); + return; + } + + [self.account initialSyncCredentials:flags complete:complete]; +} + +- (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete +{ + if (![self checkEntitlement:(__bridge NSString *)kSecEntitlementKeychainInitialSync]) { + complete(false, [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSEntitlementMissing userInfo:NULL]); + return; + } + + [self.account importInitialSyncCredentials:items complete:complete]; +} + +- (void)triggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete +{ + if (![self checkEntitlement:(__bridge NSString *)kSecEntitlementKeychainCloudCircle]) { + complete(false, [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSEntitlementMissing userInfo:NULL]); + return; + } + + [self.account triggerSync:peers complete:complete]; +} + +- (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete +{ + [self.account getWatchdogParameters:complete]; +} + +- (void)setWatchdogParmeters:(NSDictionary*)parameters complete:(void (^)(NSError* error))complete +{ + [self.account setWatchdogParmeters:parameters complete:complete]; +} + +@end + + +@implementation SOSAccount + +// Auto synthesis for most fields works great. +// A few CF fields need retention work when assigning. + +-(id) init +{ + self = [super init]; + if(self){ + self.gestalt = [NSMutableDictionary dictionary]; + self.backup_key = nil; + self.deviceID = nil; + + self.trust = [SOSAccountTrustClassic trustClassic]; + + self.queue = NULL; + self.user_private_timer = NULL; + self.factory = NULL; + + self._password_tmp = nil; + self.isListeningForSync = false; + self.lock_notification_token = -1; + + self.key_transport = nil; + self.circle_transport = NULL; + self.kvs_message_transport = nil; + self.ids_message_transport = nil; + self.ck_storage = nil; + + self.circle_rings_retirements_need_attention = false; + self.engine_peer_state_needs_repair = false; + self.key_interests_need_updating = false; + + self.change_blocks = [NSMutableArray array]; + + self.waitForInitialSync_blocks = [NSMutableDictionary dictionary]; + self.isInitialSyncing = false; + + self.accountKeyIsTrusted = false; + self.accountKeyDerivationParamters = nil; + + self.accountKey = NULL; + self.accountPrivateKey = NULL; + self.previousAccountKey = NULL; + + self.saveBlock = nil; + + self.listener = [NSXPCListener anonymousListener]; + self.listener.delegate = self; + [self.listener resume]; + } + return self; +} + +- (void) finalize { + // All the CF objects stored here need clearing (implicitly releasing them). + self.accountKey = NULL; + self.accountPrivateKey = NULL; + self.previousAccountKey = NULL; + [super finalize]; +} + +@synthesize accountKey = _accountKey; + +- (void) setAccountKey: (SecKeyRef) key { + CFRetainAssign(self->_accountKey, key); +} + +@synthesize previousAccountKey = _previousAccountKey; + +- (void) setPreviousAccountKey: (SecKeyRef) key { + CFRetainAssign(self->_previousAccountKey, key); +} + +@synthesize accountPrivateKey = _accountPrivateKey; + +- (void) setAccountPrivateKey: (SecKeyRef) key { + CFRetainAssign(self->_accountPrivateKey, key); +} + +// Syntactic sugar getters + +- (BOOL) hasPeerInfo { + return self.fullPeerInfo != nil; +} + +- (SOSPeerInfoRef) peerInfo { + return self.trust.peerInfo; +} + +- (SOSFullPeerInfoRef) fullPeerInfo { + return self.trust.fullPeerInfo; +} + +- (NSString*) peerID { + return self.trust.peerID; +} + + +- (xpc_endpoint_t)xpcControlEndpoint { + return [self.listener.endpoint _endpoint]; +} + +- (BOOL)listener:(__unused NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection +{ + NSNumber *num = [newConnection valueForEntitlement:(__bridge NSString *)kSecEntitlementKeychainCloudCircle]; + if (![num isKindOfClass:[NSNumber class]] || ![num boolValue]) { + secinfo("sos", "Client pid: %d doesn't have entitlement: %@", + [newConnection processIdentifier], kSecEntitlementKeychainCloudCircle); + return NO; + } + + + SOSClient *sosClient = [[SOSClient alloc] initWithConnection:newConnection account:self]; + + newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SOSControlProtocol)]; + _SOSControlSetupInterface(newConnection.exportedInterface); + newConnection.exportedObject = sosClient; + + [newConnection resume]; + + return YES; +} + + +-(bool) ensureFactoryCircles +{ + if (!self){ + return false; + } + + if (!self.factory){ + return false; + } + + NSString* circle_name = (__bridge_transfer NSString*)SOSDataSourceFactoryCopyName(self.factory); + + if (!circle_name){ + return false; + } + + SOSAccountEnsureCircle(self, (__bridge CFStringRef) circle_name, NULL); + + return SOSAccountInflateTransports(self, (__bridge CFStringRef) circle_name, NULL); +} + +-(id) initWithGestalt:(CFDictionaryRef)newGestalt factory:(SOSDataSourceFactoryRef)f +{ + self = [super init]; + if(self){ + self.queue = dispatch_queue_create("Account Queue", DISPATCH_QUEUE_SERIAL); + + self.gestalt = [[NSDictionary alloc] initWithDictionary:(__bridge NSDictionary * _Nonnull)(newGestalt)]; + + SOSAccountTrustClassic *t = [[SOSAccountTrustClassic alloc] initWithRetirees:[NSMutableSet set] fpi:NULL circle:NULL departureCode:kSOSDepartureReasonError peerExpansion:[NSMutableDictionary dictionary]]; + + self.trust = t; + self.factory = f; // We adopt the factory. kthanksbai. + + self.isListeningForSync = false; + + self.accountPrivateKey = NULL; + self._password_tmp = NULL; + self.user_private_timer = NULL; + self.lock_notification_token = NOTIFY_TOKEN_INVALID; + + self.change_blocks = [NSMutableArray array]; + self.waitForInitialSync_blocks = NULL; + + self.key_transport = nil; + self.circle_transport = NULL; + self.ck_storage = nil; + self.kvs_message_transport = nil; + self.ids_message_transport = nil; + + self.circle_rings_retirements_need_attention = false; + self.engine_peer_state_needs_repair = false; + self.key_interests_need_updating = false; + + self.backup_key =nil; + self.deviceID = nil; + + self.waitForInitialSync_blocks = [NSMutableDictionary dictionary]; + self.isInitialSyncing = false; + self.accountKeyIsTrusted = false; + self.accountKeyDerivationParamters = NULL; + self.accountKey = NULL; + self.previousAccountKey = NULL; + + self.saveBlock = nil; + + self.listener = [NSXPCListener anonymousListener]; + self.listener.delegate = self; + [self.listener resume]; + } + return self; +} + +-(BOOL)isEqual:(id) object +{ + if(![object isKindOfClass:[SOSAccount class]]) + return NO; + + SOSAccount* left = object; + return ([self.gestalt isEqual: left.gestalt] && + CFEqualSafe(self.trust.trustedCircle, left.trust.trustedCircle) && + [self.trust.expansion isEqual: left.trust.expansion] && + CFEqualSafe(self.trust.fullPeerInfo, left.trust.fullPeerInfo)); + +} + +- (void)userPublicKey:(void ((^))(BOOL trusted, NSData *spki, NSError *error))reply +{ + dispatch_async(self.queue, ^{ + if (!self.accountKeyIsTrusted || self.accountKey == NULL) { + NSDictionary *userinfo = @{ + (id)kCFErrorDescriptionKey : @"User public key not trusted", + }; + reply(self.accountKeyIsTrusted, NULL, [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSErrorPublicKeyAbsent userInfo:userinfo]); + return; + } + + NSData *data = CFBridgingRelease(SecKeyCopySubjectPublicKeyInfo(self.accountKey)); + if (data == NULL) { + NSDictionary *userinfo = @{ + (id)kCFErrorDescriptionKey : @"User public not available", + }; + reply(self.accountKeyIsTrusted, NULL, [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSErrorPublicKeyAbsent userInfo:userinfo]); + return; + } + reply(self.accountKeyIsTrusted, data, NULL); + }); +} + +- (void)kvsPerformanceCounters:(void(^)(NSDictionary *))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) + { + reply((__bridge NSDictionary *)returnedValues); + }); +} +- (void)idsPerformanceCounters:(void(^)(NSDictionary *))reply +{ + SOSCloudKeychainRetrieveCountersFromIDSProxy(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef error) + { + reply((__bridge NSDictionary *)returnedValues); + }); +} + +- (void)rateLimitingPerformanceCounters:(void(^)(NSDictionary *))reply +{ + CFErrorRef error = NULL; + CFDictionaryRef rateLimitingCounters = (CFDictionaryRef)SOSAccountGetValue(self, kSOSRateLimitingCounters, &error); + reply((__bridge NSDictionary*)rateLimitingCounters ? (__bridge NSDictionary*)rateLimitingCounters : [NSDictionary dictionary]); +} + +- (void)stashedCredentialPublicKey:(void(^)(NSData *, NSError *error))reply +{ + dispatch_async(self.queue, ^{ + CFErrorRef error = NULL; + + SecKeyRef user_private = SOSAccountCopyStashedUserPrivateKey(self, &error); + if (user_private == NULL) { + reply(NULL, (__bridge NSError *)error); + CFReleaseNull(error); + return; + } + + NSData *publicKey = CFBridgingRelease(SecKeyCopySubjectPublicKeyInfo(user_private)); + CFReleaseNull(user_private); + reply(publicKey, NULL); + }); +} + +- (void)assertStashedAccountCredential:(void(^)(BOOL result, NSError *error))complete +{ + dispatch_async(self.queue, ^{ + CFErrorRef error = NULL; + bool result = SOSAccountAssertStashedAccountCredential(self, &error); + complete(result, (__bridge NSError *)error); + CFReleaseNull(error); + }); +} + +static bool SyncKVSAndWait(CFErrorRef *error) { + dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); + + __block bool success = false; + + 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) { + secnotice("fresh", "EFP returned, callback error: %@", sync_error); + + success = (sync_error == NULL); + if (error) { + CFRetainAssign(*error, sync_error); + } + + dispatch_semaphore_signal(wait_for); + }); + + + dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); + secnotice("fresh", "EFP complete: %s %@", success ? "success" : "failure", error ? *error : NULL); + }); + + return success; +} + +static bool Flush(CFErrorRef *error) { + __block bool success = false; + + 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) { + success = (sync_error == NULL); + if (error) { + CFRetainAssign(*error, sync_error); + } + + dispatch_semaphore_signal(wait_for); + }); + + dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); + + secnotice("flush", "Returned %s", success? "Success": "Failure"); + + return success; +} + +- (bool)syncWaitAndFlush:(CFErrorRef *)error +{ + secnotice("pairing", "sync and wait starting"); + + if (!SyncKVSAndWait(error)) { + secnotice("pairing", "failed sync and wait: %@", error ? *error : NULL); + return false; + } + if (!Flush(error)) { + secnotice("pairing", "failed flush: %@", error ? *error : NULL); + return false; + } + secnotice("pairing", "finished sync and wait"); + return true; +} + +- (void)validatedStashedAccountCredential:(void(^)(NSData *credential, NSError *error))complete +{ + CFErrorRef syncerror = NULL; + + if (![self syncWaitAndFlush:&syncerror]) { + complete(NULL, (__bridge NSError *)syncerror); + CFReleaseNull(syncerror); + return; + } + + dispatch_async(self.queue, ^{ + CFErrorRef error = NULL; + SecKeyRef key = NULL; + key = SOSAccountCopyStashedUserPrivateKey(self, &error); + if (key == NULL) { + secnotice("pairing", "no stashed credential"); + complete(NULL, (__bridge NSError *)error); + CFReleaseNull(error); + return; + } + + SecKeyRef publicKey = SecKeyCopyPublicKey(key); + if (publicKey) { + secnotice("pairing", "returning stash credential: %@", publicKey); + CFReleaseNull(publicKey); + } + + NSData *keydata = CFBridgingRelease(SecKeyCopyExternalRepresentation(key, &error)); + CFReleaseNull(key); + complete(keydata, (__bridge NSError *)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; + } + + [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; + } + + if (!SOSAccountTryUserPrivateKey(self, accountPrivateKey, &error)) { + CFReleaseNull(accountPrivateKey); + complete(false, (__bridge NSError *)error); + secnotice("pairing", "SOSAccountTryUserPrivateKey failed: %@", error); + CFReleaseNull(error); + return; + } + + secnotice("pairing", "SOSAccountTryUserPrivateKey succeeded"); + + CFReleaseNull(accountPrivateKey); + complete(true, NULL); + }]; +} + +- (void)myPeerInfo:(void (^)(NSData *, NSError *))complete +{ + __block CFErrorRef localError = NULL; + __block NSData *applicationBlob = NULL; + SecAKSDoWhileUserBagLocked(&localError, ^{ + [self performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + SOSPeerInfoRef application = SOSAccountCopyApplication(txn.account, &localError); + if (application) { + applicationBlob = CFBridgingRelease(SOSPeerInfoCopyEncodedData(application, kCFAllocatorDefault, &localError)); + CFReleaseNull(application); + } + }]; + }); + complete(applicationBlob, (__bridge NSError *)localError); + CFReleaseNull(localError); +} + +- (void)circleJoiningBlob:(NSData *)applicant complete:(void (^)(NSData *blob, NSError *))complete +{ + __block CFErrorRef localError = NULL; + __block NSData *blob = NULL; + SOSPeerInfoRef peer = SOSPeerInfoCreateFromData(NULL, &localError, (__bridge CFDataRef)applicant); + if (peer == NULL) { + complete(NULL, (__bridge NSError *)localError); + CFReleaseNull(localError); + return; + } + SecAKSDoWhileUserBagLocked(&localError, ^{ + [self performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + blob = CFBridgingRelease(SOSAccountCopyCircleJoiningBlob(txn.account, peer, &localError)); + }]; + }); + + CFReleaseNull(peer); + + complete(blob, (__bridge NSError *)localError); + CFReleaseNull(localError); +} + +- (void)joinCircleWithBlob:(NSData *)blob version:(PiggyBackProtocolVersion)version complete:(void (^)(bool success, NSError *))complete +{ + __block CFErrorRef localError = NULL; + __block bool res = false; + + SecAKSDoWhileUserBagLocked(&localError, ^{ + [self performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + res = SOSAccountJoinWithCircleJoiningBlob(txn.account, (__bridge CFDataRef)blob, version, &localError); + }]; + }); + + complete(res, (__bridge NSError *)localError); + CFReleaseNull(localError); +} + +- (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete +{ + CFErrorRef error = NULL; + uint32_t isflags = 0; + + if (flags & SOSControlInitialSyncFlagTLK) + isflags |= SecServerInitialSyncCredentialFlagTLK; + if (flags & SOSControlInitialSyncFlagPCS) + isflags |= SecServerInitialSyncCredentialFlagPCS; + if (flags & SOSControlInitialSyncFlagPCSNonCurrent) + isflags |= SecServerInitialSyncCredentialFlagPCSNonCurrent; + + NSArray *array = CFBridgingRelease(_SecServerCopyInitialSyncCredentials(isflags, &error)); + complete(array, (__bridge NSError *)error); + CFReleaseNull(error); +} + +- (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete +{ + CFErrorRef error = NULL; + bool res = _SecServerImportInitialSyncCredentials((__bridge CFArrayRef)items, &error); + complete(res, (__bridge NSError *)error); + CFReleaseNull(error); +} + +- (void)triggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete +{ + __block CFErrorRef localError = NULL; + __block bool res = false; + + secnotice("sync", "trigger a forced sync for %@", peers); + + SecAKSDoWhileUserBagLocked(&localError, ^{ + [self performTransaction:^(SOSAccountTransaction *txn) { + if ([peers count]) { + NSSet *peersSet = [NSSet setWithArray:peers]; + CFMutableSetRef handledPeers = SOSAccountSyncWithPeers(txn, (__bridge CFSetRef)peersSet, &localError); + if (handledPeers && CFSetGetCount(handledPeers) == (CFIndex)[peersSet count]) { + res = true; + } + CFReleaseNull(handledPeers); + } else { + res = SOSAccountRequestSyncWithAllPeers(txn, &localError); + } + }]; + }); + complete(res, (__bridge NSError *)localError); + CFReleaseNull(localError); +} + +- (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete +{ + // SecdWatchdog is only available in the secd/securityd - no other binary will contain that class + Class watchdogClass = NSClassFromString(@"SecdWatchdog"); + if (watchdogClass) { + NSDictionary* parameters = [[watchdogClass watchdog] watchdogParameters]; + complete(parameters, nil); + } + else { + complete(nil, [NSError errorWithDomain:@"com.apple.securityd.watchdog" code:1 userInfo:@{NSLocalizedDescriptionKey : @"failed to lookup SecdWatchdog class from ObjC runtime"}]); + } +} + +- (void)setWatchdogParmeters:(NSDictionary*)parameters complete:(void (^)(NSError* error))complete +{ + // SecdWatchdog is only available in the secd/securityd - no other binary will contain that class + NSError* error = nil; + Class watchdogClass = NSClassFromString(@"SecdWatchdog"); + if (watchdogClass) { + [[watchdogClass watchdog] setWatchdogParameters:parameters error:&error]; + complete(error); + } + else { + complete([NSError errorWithDomain:@"com.apple.securityd.watchdog" code:1 userInfo:@{NSLocalizedDescriptionKey : @"failed to lookup SecdWatchdog class from ObjC runtime"}]); + } +} + + +// +// MARK: Save Block +// + +- (void) flattenToSaveBlock { + if (self.saveBlock) { + NSError* error = nil; + NSData* saveData = [self encodedData:&error]; + + (self.saveBlock)((__bridge CFDataRef) saveData, (__bridge CFErrorRef) error); + } +} + +CFDictionaryRef SOSAccountCopyGestalt(SOSAccount* account) { + return CFDictionaryCreateCopy(kCFAllocatorDefault, (__bridge CFDictionaryRef)account.gestalt); +} + +CFDictionaryRef SOSAccountCopyV2Dictionary(SOSAccount* account) { + CFDictionaryRef v2dict = SOSAccountGetValue(account, kSOSTestV2Settings, NULL); + return CFDictionaryCreateCopy(kCFAllocatorDefault, v2dict); +} + +static bool SOSAccountUpdateDSID(SOSAccount* account, CFStringRef dsid){ + SOSAccountSetValue(account, kSOSDSIDKey, dsid, NULL); + //send new DSID over account changed + [account.circle_transport kvsSendOfficialDSID:dsid err:NULL]; + return true; +} + +void SOSAccountAssertDSID(SOSAccount* account, CFStringRef dsid) { + CFStringRef accountDSID = SOSAccountGetValue(account, kSOSDSIDKey, NULL); + if(accountDSID == NULL) { + secdebug("updates", "Setting dsid, current dsid is empty for this account: %@", dsid); + + SOSAccountUpdateDSID(account, dsid); + } else if(CFStringCompare(dsid, accountDSID, 0) != kCFCompareEqualTo) { + secnotice("updates", "Changing DSID from: %@ to %@", accountDSID, dsid); + + //DSID has changed, blast the account! + SOSAccountSetToNew(account); + + //update DSID to the new DSID + SOSAccountUpdateDSID(account, dsid); + } else { + secnotice("updates", "Not Changing DSID: %@ to %@", accountDSID, dsid); + } +} + + +void SOSAccountPendDisableViewSet(SOSAccount* account, CFSetRef disabledViews) +{ + [account.trust valueUnionWith:kSOSPendingDisableViewsToBeSetKey valuesToUnion:disabledViews]; + [account.trust valueSubtractFrom:kSOSPendingEnableViewsToBeSetKey valuesToSubtract:disabledViews]; +} + +SOSViewResultCode SOSAccountVirtualV0Behavior(SOSAccount* account, SOSViewActionCode actionCode) { + SOSViewResultCode retval = kSOSCCGeneralViewError; + // The V0 view switches on and off all on it's own, we allow people the delusion + // of control and status if it's what we're stuck at., otherwise error. + if (SOSAccountSyncingV0(account)) { + require_action_quiet(actionCode == kSOSCCViewDisable, errOut, CFSTR("Can't disable V0 view and it's on right now")); + retval = kSOSCCViewMember; + } else { + require_action_quiet(actionCode == kSOSCCViewEnable, errOut, CFSTR("Can't enable V0 and it's off right now")); + retval = kSOSCCViewNotMember; + } +errOut: + return retval; +} + +SOSAccount* SOSAccountCreate(CFAllocatorRef allocator, + CFDictionaryRef gestalt, + SOSDataSourceFactoryRef factory) { + + SOSAccount* a = [[SOSAccount alloc] initWithGestalt:gestalt factory:factory]; + [a ensureFactoryCircles]; + SOSAccountEnsureUUID(a); + a.key_interests_need_updating = true; + + return a; +} + +static OSStatus do_delete(CFDictionaryRef query) { + OSStatus result; + + result = SecItemDelete(query); + if (result) { + secerror("SecItemDelete: %d", (int)result); + } + return result; +} + +static int +do_keychain_delete_aks_bags() +{ + OSStatus result; + CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecClass, kSecClassGenericPassword, + kSecAttrAccessGroup, CFSTR("com.apple.sbd"), + kSecAttrAccount, CFSTR("SecureBackupPublicKeybag"), + kSecAttrService, CFSTR("SecureBackupService"), + kSecAttrSynchronizable, kCFBooleanTrue, + kSecUseTombstones, kCFBooleanFalse, + NULL); + + result = do_delete(item); + CFReleaseSafe(item); + + return result; +} + +static int +do_keychain_delete_identities() +{ + OSStatus result; + CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecClass, kSecClassKey, + kSecAttrSynchronizable, kCFBooleanTrue, + kSecUseTombstones, kCFBooleanFalse, + kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), + NULL); + + result = do_delete(item); + CFReleaseSafe(item); + + return result; +} + +static int +do_keychain_delete_lakitu() +{ + OSStatus result; + CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecClass, kSecClassGenericPassword, + kSecAttrSynchronizable, kCFBooleanTrue, + kSecUseTombstones, kCFBooleanFalse, + kSecAttrAccessGroup, CFSTR("com.apple.lakitu"), + kSecAttrAccount, CFSTR("EscrowServiceBypassToken"), + kSecAttrService, CFSTR("EscrowService"), + NULL); + + result = do_delete(item); + CFReleaseSafe(item); + + return result; +} + +static int +do_keychain_delete_sbd() +{ + OSStatus result; + CFDictionaryRef item = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecClass, kSecClassGenericPassword, + kSecAttrSynchronizable, kCFBooleanTrue, + kSecUseTombstones, kCFBooleanFalse, + kSecAttrAccessGroup, CFSTR("com.apple.sbd"), + NULL); + + result = do_delete(item); + CFReleaseSafe(item); + + return result; +} + +void SOSAccountSetToNew(SOSAccount* a) +{ + secnotice("accountChange", "Setting Account to New"); + int result = 0; + + /* remove all syncable items */ + result = do_keychain_delete_aks_bags(); (void) result; + secdebug("set to new", "result for deleting aks bags: %d", result); + + result = do_keychain_delete_identities(); (void) result; + secdebug("set to new", "result for deleting identities: %d", result); + + result = do_keychain_delete_lakitu(); (void) result; + secdebug("set to new", "result for deleting lakitu: %d", result); + + 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); + a.user_private_timer = NULL; + xpc_transaction_end(); + + } + if (a.lock_notification_token != NOTIFY_TOKEN_INVALID) { + notify_cancel(a.lock_notification_token); + a.lock_notification_token = NOTIFY_TOKEN_INVALID; + } + + // keeping gestalt; + // keeping factory; + // Live Notification + // change_blocks; + // update_interest_block; + // update_block; + SOSUnregisterTransportKeyParameter(a.key_transport); + SOSUnregisterTransportMessage(a.ids_message_transport); + SOSUnregisterTransportMessage(a.kvs_message_transport); + SOSUnregisterTransportCircle(a.circle_transport); + + a.circle_transport = NULL; + a.kvs_message_transport = NULL; + a.ids_message_transport = NULL; + + a.trust = nil; + a.trust = [[SOSAccountTrustClassic alloc]initWithRetirees:[NSMutableSet set] fpi:NULL circle:NULL departureCode:kSOSDepartureReasonError peerExpansion:[NSMutableDictionary dictionary]]; + + [a ensureFactoryCircles]; // Does rings too + + // By resetting our expansion dictionary we've reset our UUID, so we'll be notified properly + SOSAccountEnsureUUID(a); + + a.key_interests_need_updating = true; +} + +bool SOSAccountIsNew(SOSAccount* account, CFErrorRef *error){ + bool result = false; + SOSAccountTrustClassic* trust = account.trust; + if(account.accountKeyIsTrusted != false || trust.departureCode != kSOSNeverAppliedToCircle || + CFSetGetCount((__bridge CFSetRef)trust.retirees) != 0) + return result; + + if(trust.retirees != nil) + return result; + if(trust.expansion != nil) + return result; + + if(account.user_private_timer != NULL || account.lock_notification_token != NOTIFY_TOKEN_INVALID) + return result; + + result = true; + + return result; +} + +CFStringRef SOSAccountCreateCompactDescription(SOSAccount* a) { + + CFStringRef gestaltDescription = CFDictionaryCopySuperCompactDescription((__bridge CFDictionaryRef)(a.gestalt)); + + CFStringRef result = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), gestaltDescription); + + CFReleaseNull(gestaltDescription); + + return result; +} +dispatch_queue_t SOSAccountGetQueue(SOSAccount* account) { + return account.queue; +} + +void SOSAccountSetUserPublicTrustedForTesting(SOSAccount* account){ + account.accountKeyIsTrusted = true; +} + +-(SOSCCStatus) getCircleStatus:(CFErrorRef*) error +{ + SOSCCStatus circleStatus = kSOSCCError; + if (SOSAccountHasPublicKey(self, error)) { + circleStatus = [self.trust getCircleStatus:error]; + } + return circleStatus; +} +bool SOSAccountScanForRetired(SOSAccount* account, SOSCircleRef circle, CFErrorRef *error) { + + SOSAccountTrustClassic *trust = account.trust; + NSMutableSet* retirees = trust.retirees; + SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) { + CFSetSetValue((__bridge CFMutableSetRef) retirees, peer); + CFErrorRef cleanupError = NULL; + if (![account.trust cleanupAfterPeer:account.kvs_message_transport circleTransport:account.circle_transport seconds:RETIREMENT_FINALIZATION_SECONDS circle:circle cleanupPeer:peer err:&cleanupError]) { + secnotice("retirement", "Error cleaning up after peer, probably orphaned some stuff in KVS: (%@) – moving on", cleanupError); + } + CFReleaseSafe(cleanupError); + }); + return true; +} + +SOSCircleRef SOSAccountCloneCircleWithRetirement(SOSAccount* account, SOSCircleRef starting_circle, CFErrorRef *error) { + SOSCircleRef new_circle = SOSCircleCopyCircle(NULL, starting_circle, error); + SOSPeerInfoRef me = account.peerInfo; + bool iAmApplicant = me && SOSCircleHasApplicant(new_circle, me, NULL); + + SOSAccountTrustClassic *trust = account.trust; + NSMutableSet* retirees = trust.retirees; + + if(!new_circle) return NULL; + __block bool workDone = false; + if (retirees) { + CFSetForEach((__bridge CFSetRef)retirees, ^(const void* value) { + SOSPeerInfoRef pi = (SOSPeerInfoRef) value; + if (isSOSPeerInfo(pi)) { + SOSCircleUpdatePeerInfo(new_circle, pi); + workDone = true; + } + }); + } + + if(workDone && SOSCircleCountPeers(new_circle) == 0) { + SecKeyRef userPrivKey = SOSAccountGetPrivateCredential(account, error); + + if(iAmApplicant) { + if(userPrivKey) { + secnotice("resetToOffering", "Reset to offering with last retirement and me as applicant"); + if(!SOSCircleResetToOffering(new_circle, userPrivKey, account.fullPeerInfo, error) || + ![account.trust addiCloudIdentity:new_circle key:userPrivKey err:error]){ + CFReleaseNull(new_circle); + return NULL; + } + } else { + // Do nothing. We can't resetToOffering without a userPrivKey. If we were to resetToEmpty + // we won't push the result later in handleUpdateCircle. If we leave the circle as it is + // we have a chance to set things right with a SetCreds/Join sequence. This will cause + // handleUpdateCircle to return false. + CFReleaseNull(new_circle); + return NULL; + } + } else { + // This case is when we aren't an applicant and the circle is retirement-empty. + secnotice("resetToEmpty", "Reset to empty with last retirement"); + SOSCircleResetToEmpty(new_circle, NULL); + } + } + + return new_circle; +} + +// +// MARK: Circle Membership change notificaion +// + +void SOSAccountAddChangeBlock(SOSAccount* a, SOSAccountCircleMembershipChangeBlock changeBlock) { + SOSAccountCircleMembershipChangeBlock copy = changeBlock; + [a.change_blocks addObject:copy]; +} + +void SOSAccountRemoveChangeBlock(SOSAccount* a, SOSAccountCircleMembershipChangeBlock changeBlock) { + [a.change_blocks removeObject:changeBlock]; +} + +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; + } +} + +bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, CFErrorRef* error) { + SOSAccountTrustClassic *trust = account.trust; + SOSFullPeerInfoRef identity = trust.fullPeerInfo; + NSMutableSet* retirees = trust.retirees; + + SOSFullPeerInfoRef fpi = identity; + if(!fpi) return false; + + CFErrorRef localError = NULL; + + bool retval = false; + + SOSPeerInfoRef retire_peer = SOSFullPeerInfoPromoteToRetiredAndCopy(fpi, &localError); + if (!retire_peer) { + secerror("Create ticket failed for peer %@: %@", fpi, localError); + } else { + // See if we need to repost the circle we could either be an applicant or a peer already in the circle + if(SOSCircleHasApplicant(circle, retire_peer, NULL)) { + // Remove our application if we have one. + SOSCircleWithdrawRequest(circle, retire_peer, NULL); + } else if (SOSCircleHasPeer(circle, retire_peer, NULL)) { + if (SOSCircleUpdatePeerInfo(circle, retire_peer)) { + CFErrorRef cleanupError = NULL; + 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); + } + CFReleaseSafe(cleanupError); + } + } + + // Store the retirement record locally. + CFSetAddValue((__bridge CFMutableSetRef)retirees, retire_peer); + + trust.retirees = retirees; + + // Write retirement to Transport + CFErrorRef postError = NULL; + if(![account.circle_transport postRetirement:SOSCircleGetName(circle) peer:retire_peer err:&postError]){ + secwarning("Couldn't post retirement (%@)", postError); + } + if(![account.circle_transport flushChanges:&postError]){ + secwarning("Couldn't flush retirement data (%@)", postError); + } + CFReleaseNull(postError); + } + + SOSAccountPurgeIdentity(account); + + retval = true; + + CFReleaseNull(localError); + CFReleaseNull(retire_peer); + return retval; +} + +bool sosAccountLeaveRing(SOSAccount* account, SOSRingRef ring, CFErrorRef* error) { + SOSAccountTrustClassic *trust = account.trust; + SOSFullPeerInfoRef identity = trust.fullPeerInfo; + + SOSFullPeerInfoRef fpi = identity; + if(!fpi) return false; + SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); + CFStringRef peerID = SOSPeerInfoGetPeerID(pi); + + CFErrorRef localError = NULL; + + bool retval = false; + bool writeRing = false; + bool writePeerInfo = false; + + if(SOSRingHasPeerID(ring, peerID)) { + writePeerInfo = true; + } + + if(writePeerInfo || writeRing) { + SOSRingWithdraw(ring, NULL, fpi, error); + } + + if (writeRing) { + CFDataRef ring_data = SOSRingCopyEncodedData(ring, error); + + if (ring_data) { + [account.circle_transport kvsRingPostRing:SOSRingGetName(ring) ring:ring_data err:NULL]; + } + CFReleaseNull(ring_data); + } + retval = true; + CFReleaseNull(localError); + return retval; +} + +bool SOSAccountPostDebugScope(SOSAccount* account, CFTypeRef scope, CFErrorRef *error) { + bool result = false; + if (account.circle_transport) { + result = [account.circle_transport kvssendDebugInfo:kSOSAccountDebugScope debug:scope err:error]; + } + return result; +} + +/* + NSUbiquitousKeyValueStoreInitialSyncChange is only posted if there is any + local value that has been overwritten by a distant value. If there is no + conflict between the local and the distant values when doing the initial + sync (e.g. if the cloud has no data stored or the client has not stored + any data yet), you'll never see that notification. + + NSUbiquitousKeyValueStoreInitialSyncChange implies an initial round trip + with server but initial round trip with server does not imply + NSUbiquitousKeyValueStoreInitialSyncChange. + */ + + +// +// MARK: Status summary +// + + +CFStringRef SOSAccountGetSOSCCStatusString(SOSCCStatus status) { + switch(status) { + case kSOSCCInCircle: return CFSTR("kSOSCCInCircle"); + case kSOSCCNotInCircle: return CFSTR("kSOSCCNotInCircle"); + case kSOSCCRequestPending: return CFSTR("kSOSCCRequestPending"); + case kSOSCCCircleAbsent: return CFSTR("kSOSCCCircleAbsent"); + case kSOSCCError: return CFSTR("kSOSCCError"); + } + return CFSTR("kSOSCCError"); +} +SOSCCStatus SOSAccountGetSOSCCStatusFromString(CFStringRef status) { + if(CFEqualSafe(status, CFSTR("kSOSCCInCircle"))) { + return kSOSCCInCircle; + } else if(CFEqualSafe(status, CFSTR("kSOSCCInCircle"))) { + return kSOSCCInCircle; + } else if(CFEqualSafe(status, CFSTR("kSOSCCNotInCircle"))) { + return kSOSCCNotInCircle; + } else if(CFEqualSafe(status, CFSTR("kSOSCCRequestPending"))) { + return kSOSCCRequestPending; + } else if(CFEqualSafe(status, CFSTR("kSOSCCCircleAbsent"))) { + return kSOSCCCircleAbsent; + } else if(CFEqualSafe(status, CFSTR("kSOSCCError"))) { + return kSOSCCError; + } + return kSOSCCError; +} + +// +// MARK: Account Reset Circles +// + +// This needs to be called within a [trust modifyCircle()] block + + +bool SOSAccountRemoveIncompleteiCloudIdentities(SOSAccount* account, SOSCircleRef circle, SecKeyRef privKey, CFErrorRef *error) { + bool retval = false; + + SOSAccountTrustClassic *trust = account.trust; + SOSFullPeerInfoRef identity = trust.fullPeerInfo; + + CFMutableSetRef iCloud2Remove = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { + if(SOSPeerInfoIsCloudIdentity(peer)) { + SOSFullPeerInfoRef icfpi = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, NULL); + if(!icfpi) { + CFSetAddValue(iCloud2Remove, peer); + } + CFReleaseNull(icfpi); + } + }); + + if(CFSetGetCount(iCloud2Remove) > 0) { + retval = true; + SOSCircleRemovePeers(circle, privKey, identity, iCloud2Remove, error); + } + CFReleaseNull(iCloud2Remove); + return retval; +} + +// +// MARK: start backups +// + + +bool SOSAccountEnsureInBackupRings(SOSAccount* account) { + __block bool result = false; + __block CFErrorRef error = NULL; + secnotice("backup", "Ensuring in rings"); + + NSData *backupKey = nil; + + if(!account.backup_key){ + result = true; + return result; + } + + backupKey = (__bridge_transfer NSData*)SOSPeerInfoV2DictionaryCopyData(account.peerInfo, sBackupKeyKey); + + bool updateBackupKey = ![backupKey isEqual:account.backup_key]; + + if(updateBackupKey) { + result = SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), &error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) { + return SOSFullPeerInfoUpdateBackupKey(fpi, (__bridge CFDataRef)(account.backup_key), error); + }); + if (!result) { + secnotice("backupkey", "Failed to setup backup public key: %@", error ? (CFTypeRef) error : (CFTypeRef) CFSTR("No error space provided")); + return result; + } + } + if(!account.backup_key) + { + if (!result) { + secnotice("backupkey", "Failed to setup backup public key: %@", error ? (CFTypeRef) error : (CFTypeRef) CFSTR("No error space provided")); + } + return result; + } + if(!SOSBSKBIsGoodBackupPublic((__bridge CFDataRef)account.backup_key, &error)){ + if (!result) { + secnotice("backupkey", "Failed to setup backup public key: %@", error ? (CFTypeRef) error : (CFTypeRef) CFSTR("No error space provided")); + } + return result; + } + + CFDataRef recoveryKeyBackFromRing = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, &error); + + if(updateBackupKey || recoveryKeyBackFromRing) { + // It's a good key, we're going with it. Stop backing up the old way. + CFErrorRef localError = NULL; + if (!SOSDeleteV0Keybag(&localError)) { + secerror("Failed to delete v0 keybag: %@", localError); + } + CFReleaseNull(localError); + + result = true; + + // Setup backups the new way. + SOSAccountForEachBackupView(account, ^(const void *value) { + CFStringRef viewName = (CFStringRef)value; + if(updateBackupKey || (recoveryKeyBackFromRing && !SOSAccountRecoveryKeyIsInBackupAndCurrentInView(account, viewName))) { + result &= SOSAccountNewBKSBForView(account, viewName, &error); + } + }); + } + + if (!result) { + secnotice("backupkey", "Failed to setup backup public key: %@", error ? (CFTypeRef) error : (CFTypeRef) CFSTR("No error space provided")); + } + return result; +} + +// +// MARK: Recovery Public Key Functions +// + +bool SOSAccountRegisterRecoveryPublicKey(SOSAccountTransaction* txn, CFDataRef recovery_key, CFErrorRef *error){ + bool retval = SOSAccountSetRecoveryKey(txn.account, recovery_key, error); + if(retval) secnotice("recovery", "successfully registered recovery public key"); + else secnotice("recovery", "could not register recovery public key: %@", *error); + SOSClearErrorIfTrue(retval, error); + return retval; +} + +bool SOSAccountClearRecoveryPublicKey(SOSAccountTransaction* txn, CFDataRef recovery_key, CFErrorRef *error){ + bool retval = SOSAccountRemoveRecoveryKey(txn.account, error); + if(retval) secnotice("recovery", "RK Cleared"); + else secnotice("recovery", "Couldn't clear RK(%@)", *error); + SOSClearErrorIfTrue(retval, error); + return retval; +} + +CFDataRef SOSAccountCopyRecoveryPublicKey(SOSAccountTransaction* txn, CFErrorRef *error){ + CFDataRef result = NULL; + result = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, txn.account, error); + if(!result) secnotice("recovery", "Could not retrieve the recovery public key from the ring: %@", *error); + + if (!isData(result)) { + CFReleaseNull(result); + } + SOSClearErrorIfTrue(result != NULL, error); + + return result; +} + +// +// MARK: Joining +// + + +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; + require_action_quiet(trust.trustedCircle, fail, SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("Don't have circle when joining???"))); + require_quiet([account.trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)account.gestalt deviceID:(__bridge CFStringRef)account.deviceID backupKey:(__bridge CFDataRef)account.backup_key err:error], fail); + SOSFullPeerInfoRef myCirclePeer = trust.fullPeerInfo; + if (SOSCircleCountPeers(trust.trustedCircle) == 0 || SOSAccountGhostResultsInReset(account)) { + secnotice("resetToOffering", "Resetting circle to offering since there are no peers"); + // this also clears initial sync data + result = [account.trust resetCircleToOffering:aTxn userKey:user_key err:error]; + } else { + SOSAccountSetValue(account, kSOSUnsyncedViewsKey, kCFBooleanTrue, NULL); + if (use_cloud_peer) { + cloud_full_peer = SOSCircleCopyiCloudFullPeerInfoRef(trust.trustedCircle, NULL); + } + [account.trust modifyCircle:account.circle_transport err:error action:^bool(SOSCircleRef circle) { + result = SOSAccountAddEscrowToPeerInfo(account, myCirclePeer, error); + result &= SOSCircleRequestAdmission(circle, user_key, myCirclePeer, error); + trust.departureCode = kSOSNeverLeftCircle; + if(result && cloud_full_peer) { + CFErrorRef localError = NULL; + CFStringRef cloudid = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(cloud_full_peer)); + require_quiet(cloudid, finish); + require_quiet(SOSCircleHasActivePeerWithID(circle, cloudid, &localError), finish); + require_quiet(SOSCircleAcceptRequest(circle, user_key, cloud_full_peer, SOSFullPeerInfoGetPeerInfo(myCirclePeer), &localError), finish); + finish: + if (localError){ + secerror("Failed to join with cloud identity: %@", localError); + CFReleaseNull(localError); + } + } + return result; + }]; + if (use_cloud_peer) { + SOSAccountUpdateOutOfSyncViews(aTxn, SOSViewsGetAllCurrent()); + } + } +fail: + CFReleaseNull(cloud_full_peer); + return result; +} + +static bool SOSAccountJoinCircles_internal(SOSAccountTransaction* aTxn, bool use_cloud_identity, CFErrorRef* error) { + SOSAccount* account = aTxn.account; + SOSAccountTrustClassic *trust = account.trust; + bool success = false; + + SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); + require_quiet(user_key, done); // Fail if we don't get one. + + require_action_quiet(trust.trustedCircle, done, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to join"))); + + if (trust.fullPeerInfo != NULL) { + SOSPeerInfoRef myPeer = trust.peerInfo; + success = SOSCircleHasPeer(trust.trustedCircle, myPeer, NULL); + require_quiet(!success, done); + + SOSCircleRemoveRejectedPeer(trust.trustedCircle, myPeer, NULL); // If we were rejected we should remove it now. + + if (!SOSCircleHasApplicant(trust.trustedCircle, myPeer, NULL)) { + secerror("Resetting my peer (ID: %@) for circle '%@' during application", SOSPeerInfoGetPeerID(myPeer), SOSCircleGetName(trust.trustedCircle)); + + trust.fullPeerInfo = NULL; + } + } + + success = SOSAccountJoinCircle(aTxn, user_key, use_cloud_identity, error); + + require_quiet(success, done); + + trust.departureCode = kSOSNeverLeftCircle; + +done: + return success; +} + +bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, CFErrorRef* error) { + secnotice("circleJoin", "Normal path circle join (SOSAccountJoinCircles)"); + return SOSAccountJoinCircles_internal(aTxn, false, error); +} + +CFStringRef SOSAccountCopyDeviceID(SOSAccount* account, CFErrorRef *error){ + CFStringRef result = NULL; + SOSAccountTrustClassic *trust = account.trust; + + require_action_quiet(trust.fullPeerInfo, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No peer for me"))); + + result = SOSPeerInfoCopyDeviceID(trust.peerInfo); + +fail: + return result; +} + +bool SOSAccountSetMyDSID(SOSAccountTransaction* txn, CFStringRef IDS, CFErrorRef* error){ + bool result = true; + SOSAccount* account = txn.account; + SOSAccountTrustClassic *trust = account.trust; + + secdebug("IDS Transport", "We are setting our device ID: %@", IDS); + if(IDS != NULL && (CFStringGetLength(IDS) > 0)){ + if(!trust.fullPeerInfo){ + account.deviceID = [[NSString alloc] initWithString:(__bridge NSString * _Nonnull)(IDS)]; + SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No peer for me")); + return result; + } + result = [trust modifyCircle:account.circle_transport err:error action:^bool(SOSCircleRef circle) { + + SOSFullPeerInfoUpdateDeviceID(trust.fullPeerInfo, IDS, error); + SOSFullPeerInfoUpdateTransportType(trust.fullPeerInfo, SOSTransportMessageTypeIDSV2, error); + SOSFullPeerInfoUpdateTransportPreference(trust.fullPeerInfo, kCFBooleanFalse, error); + SOSFullPeerInfoUpdateTransportFragmentationPreference(trust.fullPeerInfo, kCFBooleanTrue, error); + SOSFullPeerInfoUpdateTransportAckModelPreference(trust.fullPeerInfo, kCFBooleanTrue, error); + return SOSCircleHasPeer(circle, trust.peerInfo, NULL); + }]; + } + else + result = false; + + // Initiate sync with all IDS peers, since we just learned we can talk that way. + SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { + if (SOSPeerInfoShouldUseIDSTransport(account.peerInfo, peer)) { + [txn requestSyncWith:(__bridge NSString*) SOSPeerInfoGetPeerID(peer)]; + } + }); + + account.deviceID = [[NSString alloc] initWithString:(__bridge NSString * _Nonnull)(IDS)]; + return result; +} + +bool SOSAccountSendIDSTestMessage(SOSAccount* account, CFStringRef message, CFErrorRef *error){ + bool result = true; + //construct message dictionary, circle -> peerID -> message + + CFMutableDictionaryRef peerToMessage = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFStringRef operationString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kIDSSendOneMessage); + CFDictionaryRef rawMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kIDSOperationType, operationString, + kIDSMessageToSendKey, CFSTR("send IDS test message"), + NULL); + + SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { + CFDictionaryAddValue(peerToMessage, SOSPeerInfoGetPeerID(peer), rawMessage); + }); + + result = [account.ids_message_transport SOSTransportMessageSendMessages:account.ids_message_transport pm:peerToMessage err:error]; + + CFReleaseNull(peerToMessage); + CFReleaseNull(operationString); + CFReleaseNull(rawMessage); + return result; +} + +bool SOSAccountStartPingTest(SOSAccount* account, CFStringRef message, CFErrorRef *error){ + bool result = false; + //construct message dictionary, circle -> peerID -> message + SOSAccountTrustClassic *trust = account.trust; + if(account.ids_message_transport == NULL) + account.ids_message_transport = [[SOSMessageIDS alloc] initWithAccount:account andName:(__bridge NSString *)(SOSCircleGetName(trust.trustedCircle))]; + + require_quiet(account.ids_message_transport, fail); + CFMutableDictionaryRef peerToMessage = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFStringRef operationString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kIDSStartPingTestMessage); + CFDictionaryRef rawMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kIDSOperationType, operationString, + kIDSMessageToSendKey, CFSTR("send IDS test message"), + NULL); + + + SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { + CFDictionaryAddValue(peerToMessage, SOSPeerInfoGetPeerID(peer), rawMessage); + }); + + result = [account.ids_message_transport SOSTransportMessageSendMessages:account.ids_message_transport pm:peerToMessage err:error]; + + CFReleaseNull(peerToMessage); + CFReleaseNull(rawMessage); + CFReleaseNull(operationString); +fail: + return result; +} + +bool SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(SOSAccount* account, CFErrorRef *error){ + bool result = true; + + __block bool success = true; + __block CFErrorRef localError = NULL; + dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); + + SOSCloudKeychainGetIDSDeviceID(^(CFDictionaryRef returnedValues, CFErrorRef sync_error){ + success = (sync_error == NULL); + if (!success) { + CFRetainAssign(localError, sync_error); + } + + dispatch_semaphore_signal(wait_for); + }); + + dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); + + if(!success && localError != NULL && error != NULL){ + secerror("Could not ask KeychainSyncingOverIDSProxy for Device ID: %@", localError); + *error = localError; + result = false; + } + else{ + secdebug("IDS Transport", "Attempting to retrieve the IDS Device ID"); + } + return result; +} + +bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, CFErrorRef* error) { + secnotice("circleJoin", "Joining after restore (SOSAccountJoinCirclesAfterRestore)"); + return SOSAccountJoinCircles_internal(aTxn, true, error); +} + +bool SOSAccountRemovePeersFromCircle(SOSAccount* account, CFArrayRef peers, CFErrorRef* error) +{ + bool result = false; + CFMutableSetRef peersToRemove = NULL; + SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); + if(!user_key){ + secnotice("removePeers", "Can't remove without userKey"); + return result; + } + SOSFullPeerInfoRef me_full = account.fullPeerInfo; + SOSPeerInfoRef me = account.peerInfo; + if(!(me_full && me)) + { + secnotice("removePeers", "Can't remove without being active peer"); + SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("Can't remove without being active peer")); + return result; + } + + result = true; // beyond this point failures would be rolled up in AccountModifyCircle. + + peersToRemove = CFSetCreateMutableForSOSPeerInfosByIDWithArray(kCFAllocatorDefault, peers); + if(!peersToRemove) + { + CFReleaseNull(peersToRemove); + secnotice("removePeers", "No peerSet to remove"); + return result; + } + + // If we're one of the peers expected to leave - note that and then remove ourselves from the set (different handling). + bool leaveCircle = CFSetContainsValue(peersToRemove, me); + CFSetRemoveValue(peersToRemove, me); + + result &= [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { + bool success = false; + + if(CFSetGetCount(peersToRemove) != 0) { + require_quiet(SOSCircleRemovePeers(circle, user_key, me_full, peersToRemove, error), done); + success = SOSAccountGenerationSignatureUpdate(account, error); + } else success = true; + + if (success && leaveCircle) { + secnotice("leaveCircle", "Leaving circle by client request"); + success = sosAccountLeaveCircle(account, circle, error); + } + + done: + return success; + + }]; + + CFReleaseNull(peersToRemove); + return result; +} + + +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_group_t group = dispatch_group_create(); + SOSAccountTrustClassic *trust = account.trust; + __block bool result = false; + secnotice("circle", "Attempting to leave circle - best effort - in %llu seconds\n", limit_in_seconds); + // Add a task to the group + dispatch_group_async(group, queue, ^{ + [trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { + secnotice("leaveCircle", "Leaving circle by client request"); + return sosAccountLeaveCircle(account, circle, error); + }]; + }); + dispatch_time_t milestone = dispatch_time(DISPATCH_TIME_NOW, limit_in_seconds * NSEC_PER_SEC); + dispatch_group_wait(group, milestone); + + trust.departureCode = kSOSWithdrewMembership; + + return result; +} + + +// +// MARK: Application +// + +static void for_each_applicant_in_each_circle(SOSAccount* account, CFArrayRef peer_infos, + bool (^action)(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer)) { + SOSAccountTrustClassic *trust = account.trust; + + SOSPeerInfoRef me = trust.peerInfo; + CFErrorRef peer_error = NULL; + if (trust.trustedCircle && me && + SOSCircleHasPeer(trust.trustedCircle, me, &peer_error)) { + [account.trust modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle) { + __block bool modified = false; + CFArrayForEach(peer_infos, ^(const void *value) { + SOSPeerInfoRef peer = (SOSPeerInfoRef) value; + if (isSOSPeerInfo(peer) && SOSCircleHasApplicant(circle, peer, NULL)) { + if (action(circle, trust.fullPeerInfo, peer)) { + modified = true; + } + } + }); + return modified; + }]; + } + if (peer_error) + secerror("Got error in SOSCircleHasPeer: %@", peer_error); + CFReleaseSafe(peer_error); // TODO: We should be accumulating errors here. +} + +bool SOSAccountAcceptApplicants(SOSAccount* account, CFArrayRef applicants, CFErrorRef* error) { + SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); + if (!user_key) + return false; + + __block bool success = true; + __block int64_t num_peers = 0; + + for_each_applicant_in_each_circle(account, applicants, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer) { + bool accepted = SOSCircleAcceptRequest(circle, user_key, myCirclePeer, peer, error); + if (!accepted) + success = false; + else + num_peers = MAX(num_peers, SOSCircleCountPeers(circle)); + return accepted; + }); + + return success; +} + +bool SOSAccountRejectApplicants(SOSAccount* account, CFArrayRef applicants, CFErrorRef* error) { + __block bool success = true; + __block int64_t num_peers = 0; + + for_each_applicant_in_each_circle(account, applicants, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer) { + bool rejected = SOSCircleRejectRequest(circle, myCirclePeer, peer, error); + if (!rejected) + success = false; + else + num_peers = MAX(num_peers, SOSCircleCountPeers(circle)); + return rejected; + }); + + return success; +} + + +CFStringRef SOSAccountCopyIncompatibilityInfo(SOSAccount* account, CFErrorRef* error) { + return CFSTR("We're compatible, go away"); +} + +enum DepartureReason SOSAccountGetLastDepartureReason(SOSAccount* account, CFErrorRef* error) { + SOSAccountTrustClassic *trust = account.trust; + return trust.departureCode; +} + +void SOSAccountSetLastDepartureReason(SOSAccount* account, enum DepartureReason reason) { + SOSAccountTrustClassic *trust = account.trust; + trust.departureCode = reason; +} + + +CFArrayRef SOSAccountCopyGeneration(SOSAccount* account, CFErrorRef *error) { + CFArrayRef result = NULL; + CFNumberRef generation = NULL; + SOSAccountTrustClassic *trust = account.trust; + + require_quiet(SOSAccountHasPublicKey(account, error), fail); + require_action_quiet(trust.trustedCircle, fail, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle"))); + + generation = (CFNumberRef)SOSCircleGetGeneration(trust.trustedCircle); + result = CFArrayCreateForCFTypes(kCFAllocatorDefault, generation, NULL); + +fail: + return result; +} + +bool SOSValidateUserPublic(SOSAccount* account, CFErrorRef *error) { + if (!SOSAccountHasPublicKey(account, error)) + return NULL; + + return account.accountKeyIsTrusted; +} + +bool SOSAccountEnsurePeerRegistration(SOSAccount* account, CFErrorRef *error) { + // TODO: this result is never set or used + bool result = true; + SOSAccountTrustClassic *trust = account.trust; + + secnotice("updates", "Ensuring peer registration."); + + if(!trust.trustedCircle || !trust.fullPeerInfo || !account.accountKeyIsTrusted) + return result; + + // If we are not in the circle, there is no point in setting up peers + if(!SOSAccountIsMyPeerActive(account, NULL)) + return result; + + // This code only uses the SOSFullPeerInfoRef for two things: + // - Finding out if this device is in the trusted circle + // - Using the peerID for this device to see if the current peer is "me" + // - It is used indirectly by passing trust.fullPeerInfo to SOSEngineInitializePeerCoder + + CFStringRef my_id = SOSPeerInfoGetPeerID(trust.peerInfo); + + SOSCircleForEachValidSyncingPeer(trust.trustedCircle, account.accountKey, ^(SOSPeerInfoRef peer) { + if (!SOSPeerInfoPeerIDEqual(peer, my_id)) { + CFErrorRef localError = NULL; + + SOSMessage *messageTransport = SOSPeerInfoHasDeviceID(peer) ? account.ids_message_transport : account.kvs_message_transport; + + SOSEngineInitializePeerCoder((SOSEngineRef)[messageTransport SOSTransportMessageGetEngine], trust.fullPeerInfo, peer, &localError); + if (localError) + secnotice("updates", "can't initialize transport for peer %@ with %@ (%@)", peer, trust.fullPeerInfo, localError); + CFReleaseSafe(localError); + } + }); + + //Initialize our device ID + [account.ids_message_transport SOSTransportMessageIDSGetIDSDeviceID:account]; + + return result; +} + +// +// Value manipulation +// + +CFTypeRef SOSAccountGetValue(SOSAccount* account, CFStringRef key, CFErrorRef *error) { + SOSAccountTrustClassic *trust = account.trust; + if (!trust.expansion) { + return NULL; + } + return (__bridge CFTypeRef)([trust.expansion objectForKey:(__bridge NSString* _Nonnull)(key)]); +} + +bool SOSAccountAddEscrowRecords(SOSAccount* account, CFStringRef dsid, CFDictionaryRef record, CFErrorRef *error){ + CFMutableDictionaryRef escrowRecords = (CFMutableDictionaryRef)SOSAccountGetValue(account, kSOSEscrowRecord, error); + CFMutableDictionaryRef escrowCopied = NULL; + bool success = false; + + if(isDictionary(escrowRecords) && escrowRecords != NULL) + escrowCopied = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(escrowRecords), escrowRecords); + else + escrowCopied = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFDictionaryAddValue(escrowCopied, dsid, record); + SOSAccountSetValue(account, kSOSEscrowRecord, escrowCopied, error); + + if(*error == NULL) + success = true; + + CFReleaseNull(escrowCopied); + + return success; + +} + +bool SOSAccountAddEscrowToPeerInfo(SOSAccount* account, SOSFullPeerInfoRef myPeer, CFErrorRef *error){ + bool success = false; + + CFDictionaryRef escrowRecords = SOSAccountGetValue(account, kSOSEscrowRecord, error); + success = SOSFullPeerInfoReplaceEscrowRecords(myPeer, escrowRecords, error); + + return success; +} + +bool SOSAccountCheckPeerAvailability(SOSAccount* account, CFErrorRef *error) +{ + CFStringRef operationString = NULL; + CFDictionaryRef rawMessage = NULL; + CFMutableSetRef peers = NULL; + CFMutableDictionaryRef peerList = NULL; + char* message = NULL; + bool result = false; + SOSAccountTrustClassic* trust = account.trust; + if(account.ids_message_transport == NULL) + account.ids_message_transport = [[SOSMessageIDS alloc] initWithAccount:account andName:(__bridge NSString *)SOSCircleGetName(trust.trustedCircle)]; + + if(!account.ids_message_transport) + return result; + + //adding message type kIDSPeerAvailability so KeychainSyncingOverIDSProxy does not send this message as a keychain item + + operationString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kIDSPeerAvailability); + rawMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kIDSOperationType, operationString, + kIDSMessageToSendKey, CFSTR("checking peers"), + NULL); + + peerList = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSCircleRef circle = trust.trustedCircle; + + //check each peer to make sure they have the right view set enabled + CFSetRef mySubSet = SOSViewsGetV0SubviewSet(); + SOSCircleForEachValidPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) { + if(!CFEqualSafe(peer, account.peerInfo)){ + CFMutableSetRef peerViews = SOSPeerInfoCopyEnabledViews(peer); + CFSetRef intersectSets = CFSetCreateIntersection(kCFAllocatorDefault, mySubSet, peerViews); + if(CFEqualSafe(intersectSets, mySubSet)){ + CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); + if(deviceID != NULL) + CFDictionaryAddValue(peerList, SOSPeerInfoGetPeerID(peer), rawMessage); + CFReleaseNull(deviceID); + } + CFReleaseNull(peerViews); + CFReleaseNull(intersectSets); + } + }); + + require_quiet(CFDictionaryGetCount(peerList) > 0 , fail); + + result = [account.ids_message_transport SOSTransportMessageSendMessages:account.ids_message_transport pm:peerList err:error]; + +fail: + CFReleaseNull(rawMessage); + CFReleaseNull(operationString); + CFReleaseNull(peerList); + CFReleaseNull(peers); + free(message); + return result; +} + + +void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account) { + if (![account.trust isInCircle:NULL]) + return; + SOSAccountTrustClassic *trust = account.trust; + [trust modifyCircle:account.circle_transport err:NULL action:^bool (SOSCircleRef circle) { + __block bool updated = false; + CFSetForEach((__bridge CFMutableSetRef)trust.retirees, ^(CFTypeRef element){ + SOSPeerInfoRef retiree = asSOSPeerInfo(element); + + if (retiree && SOSCircleUpdatePeerInfo(circle, retiree)) { + 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]) + secerror("Error cleanup up after peer (%@): %@", retiree, cleanupError); + CFReleaseSafe(cleanupError); + } + }); + return updated; + }]; +} + +static const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC; + +static CFDictionaryRef SOSAccountGetObjectsFromCloud(dispatch_queue_t processQueue, CFErrorRef *error) +{ + __block CFTypeRef object = NULL; + + dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); + dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds); + + CloudKeychainReplyBlock replyBlock = + ^ (CFDictionaryRef returnedValues, CFErrorRef error) + { + secnotice("key-cleanup", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues); + object = returnedValues; + if (object) + CFRetain(object); + if (error) + { + secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error); + } + secnotice("key-cleanup", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object); + dispatch_semaphore_signal(waitSemaphore); + }; + + SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock); + + dispatch_semaphore_wait(waitSemaphore, finishTime); + if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull + { + CFRelease(object); + object = NULL; + } + secnotice("key-cleanup", "returned: %@", object); + return asDictionary(object, error); +} + + +static void SOSAccountRemoveKVSKeys(SOSAccount* account, NSArray* keysToRemove, dispatch_queue_t processQueue) +{ + CFStringRef uuid = SOSAccountCopyUUID(account); + dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); + dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds); + + CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error){ + if (error){ + secerror("SOSCloudKeychainRemoveKeys returned error: %@", error); + } + dispatch_semaphore_signal(waitSemaphore); + }; + + SOSCloudKeychainRemoveKeys((__bridge CFArrayRef)(keysToRemove), uuid, processQueue, replyBlock); + dispatch_semaphore_wait(waitSemaphore, finishTime); + +} + +static void SOSAccountWriteLastCleanupTimestampToKVS(SOSAccount* account) +{ + NSMutableDictionary *writeTimestamp = [NSMutableDictionary dictionary]; + + CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); + CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); + + withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) { + CFStringAppend(timeDescription, decription); + }); + CFStringAppend(timeDescription, CFSTR("]")); + + [writeTimestamp setObject:(__bridge NSString*)(timeDescription) forKey:(__bridge NSString*)kSOSKVSLastCleanupTimestampKey]; + + 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); + + CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error){ + if (error){ + secerror("SOSCloudKeychainPutObjectsInCloud returned error: %@", error); + } + dispatch_semaphore_signal(waitSemaphore); + }; + + SOSCloudKeychainPutObjectsInCloud((__bridge CFDictionaryRef)(writeTimestamp), processQueue, replyBlock); + dispatch_semaphore_wait(waitSemaphore, finishTime); +} + +//Get all the key/values in KVS and remove old entries +bool SOSAccountCleanupAllKVSKeys(SOSAccount* account, CFErrorRef* error) +{ + dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + NSDictionary *keysAndValues = (__bridge_transfer NSDictionary*)SOSAccountGetObjectsFromCloud(processQueue, error); + NSMutableArray *peerIDs = [NSMutableArray array]; + NSMutableArray *keysToRemove = [NSMutableArray array]; + + CFArrayForEach(SOSAccountCopyActiveValidPeers(account, error), ^(const void *value) { + SOSPeerInfoRef peer = (SOSPeerInfoRef)value; + NSString* peerID = (__bridge NSString*) SOSPeerInfoGetPeerID(peer); + + //any peerid that is not ours gets added + if(![[account.trust peerID] isEqualToString:peerID]) + [peerIDs addObject:peerID]; + }); + + [keysAndValues enumerateKeysAndObjectsUsingBlock:^(NSString * KVSKey, NSNumber * KVSValue, BOOL *stop) { + __block bool keyMatchesPeerID = false; + + //checks for full peer ids + [peerIDs enumerateObjectsUsingBlock:^(id _Nonnull PeerID, NSUInteger idx, BOOL * _Nonnull stop) { + //if key contains peerid of one active peer + if([KVSKey containsString:PeerID]){ + secnotice("key-cleanup","key: %@", KVSKey); + keyMatchesPeerID = true; + } + }]; + if((([KVSKey hasPrefix:@"ak"] || [KVSKey hasPrefix:@"-ak"]) && !keyMatchesPeerID) + || [KVSKey hasPrefix:@"po"]) + [keysToRemove addObject:KVSKey]; + }]; + + secnotice("key-cleanup", "message keys that we should remove! %@", keysToRemove); + secnotice("key-cleanup", "total keys: %lu, cleaning up %lu", (unsigned long)[keysAndValues count], (unsigned long)[keysToRemove count]); + + SOSAccountRemoveKVSKeys(account, keysToRemove, processQueue); + + //add last cleanup timestamp + SOSAccountWriteLastCleanupTimestampToKVS(account); + return true; + +} + +bool SOSAccountPopulateKVSWithBadKeys(SOSAccount* account, CFErrorRef* error) { + + NSMutableDictionary *testKeysAndValues = [NSMutableDictionary dictionary]; + [testKeysAndValues setObject:@"deadbeef" forKey:@"-ak|asdfjkl;asdfjk;"]; + [testKeysAndValues setObject:@"foobar" forKey:@"ak|asdfasdfasdf:qwerqwerqwer"]; + [testKeysAndValues setObject:@"oldhistorycircle" forKey:@"poak|asdfasdfasdfasdf"]; + [testKeysAndValues setObject:@"oldhistorycircle" forKey:@"po|asdfasdfasdfasdfasdfasdf"]; + [testKeysAndValues setObject:@"oldhistorycircle" forKey:@"k>KeyParm"]; + + 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); + + CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error){ + if (error){ + secerror("SOSCloudKeychainPutObjectsInCloud returned error: %@", error); + } + dispatch_semaphore_signal(waitSemaphore); + }; + + SOSCloudKeychainPutObjectsInCloud((__bridge CFDictionaryRef)(testKeysAndValues), processQueue, replyBlock); + dispatch_semaphore_wait(waitSemaphore, finishTime); + + return true; +} + +SOSPeerInfoRef SOSAccountCopyApplication(SOSAccount* account, CFErrorRef* error) { + SOSPeerInfoRef applicant = NULL; + 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]) + return applicant; + if(!SOSFullPeerInfoPromoteToApplication(trust.fullPeerInfo, userKey, error)) + return applicant; + applicant = SOSPeerInfoCreateCopy(kCFAllocatorDefault, trust.peerInfo, error); + + return applicant; +} + + +static void +AddStrippedResults(NSMutableArray *results, NSArray *keychainItems, NSMutableSet *seenUUID, bool authoriative) +{ + [keychainItems enumerateObjectsUsingBlock:^(NSDictionary* keychainItem, NSUInteger idx, BOOL * _Nonnull stop) { + NSString* parentUUID = keychainItem[(id)kSecAttrPath]; + NSString* viewUUID = keychainItem[(id)kSecAttrAccount]; + NSString *viewName = [keychainItem objectForKey:(id)kSecAttrServer]; + + if (parentUUID == NULL || viewUUID == NULL || viewName == NULL) + return; + + if([parentUUID isEqualToString:viewUUID] || authoriative){ + + /* check if we already have this entry */ + if ([seenUUID containsObject:viewUUID]) + return; + + NSData* v_data = [keychainItem objectForKey:(id)kSecValueData]; + NSData *key = [[NSData alloc] initWithBase64EncodedData:v_data options:0]; + + if (key == NULL) + return; + + secnotice("piggy", "fetched TLK %@ with name %@", viewName, viewUUID); + + NSMutableDictionary* strippedDown = [@{ + (id)kSecValueData : key, + (id)kSecAttrServer : viewName, + (id)kSecAttrAccount : viewUUID + } mutableCopy]; + if (authoriative) + strippedDown[@"auth"] = @YES; + + [results addObject:strippedDown]; + [seenUUID addObject:viewUUID]; + } + }]; +} + +static void +AddViewManagerResults(NSMutableArray *results, NSMutableSet *seenUUID) +{ +#if OCTAGON + CKKSViewManager* manager = [CKKSViewManager manager]; + + NSDictionary *items = [manager activeTLKs]; + + for (NSString *view in items) { + NSString *uuid = items[view]; + NSDictionary *query = @{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @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); + } +#endif +} + + +NSMutableArray* +SOSAccountGetAllTLKs(void) +{ + CFTypeRef result = NULL; + NSMutableArray* results = [NSMutableArray array]; + NSMutableSet *seenUUID = [NSMutableSet set]; + + // first use the TLK from the view manager + AddViewManagerResults(results, seenUUID); + + //try to grab tlk-piggy items + NSDictionary* query = @{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrDescription: @"tlk", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @YES, + }; + + if (SecItemCopyMatching((__bridge CFDictionaryRef)query, &result) == 0) { + AddStrippedResults(results, (__bridge NSArray*)result, seenUUID, false); + } + CFReleaseNull(result); + + //try to grab tlk-piggy items + query = @{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrDescription: @"tlk-piggy", + (id)kSecAttrSynchronizable : (id)kSecAttrSynchronizableAny, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @YES, + }; + + if (SecItemCopyMatching((__bridge CFDictionaryRef)query, &result) == 0) { + AddStrippedResults(results, (__bridge NSArray*)result, seenUUID, false); + } + CFReleaseNull(result); + + secnotice("piggy", "Found %d TLKs", (int)[results count]); + + return results; +} + +static uint8_t* encode_tlk(kTLKTypes type, NSString *name, NSData *keychainData, NSData* uuid, + const uint8_t *der, uint8_t *der_end) +{ + if (type != kTLKUnknown) { + return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, + piggy_encode_data(keychainData, der, + piggy_encode_data(uuid, der, + ccder_encode_uint64((uint64_t)type, der, der_end)))); + } else { + return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, + piggy_encode_data(keychainData, der, + piggy_encode_data(uuid, der, + der_encode_string((__bridge CFStringRef)name, NULL, der, der_end)))); + } +} + +static uint8_t* piggy_encode_data(NSData* data, + const uint8_t *der, uint8_t *der_end) +{ + return ccder_encode_tl(CCDER_OCTET_STRING, data.length, der, + ccder_encode_body(data.length, data.bytes, der, der_end)); + +} + +static kTLKTypes +name2type(NSString *view) +{ + if ([view isEqualToString:@"Manatee"]) + return kTLKManatee; + else if ([view isEqualToString:@"Engram"]) + return kTLKEngram; + else if ([view isEqualToString:@"AutoUnlock"]) + return kTLKAutoUnlock; + if ([view isEqualToString:@"Health"]) + return kTLKHealth; + return kTLKUnknown; +} + +static unsigned +rank_type(NSString *view) +{ + if ([view isEqualToString:@"Manatee"]) + return 4; + else if ([view isEqualToString:@"Engram"]) + return 3; + else if ([view isEqualToString:@"AutoUnlock"]) + return 2; + if ([view isEqualToString:@"Health"]) + return 1; + return 0; +} + +static NSData * +parse_uuid(NSString *uuidString) +{ + NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString]; + uuid_t uuidblob; + [uuid getUUIDBytes:uuidblob]; + return [NSData dataWithBytes:uuidblob length:sizeof(uuid_t)]; +} +static size_t +piggy_sizeof_data(NSData* data) +{ + return ccder_sizeof(CCDER_OCTET_STRING, [data length]); +} + +static size_t sizeof_keychainitem(kTLKTypes type, NSString *name, NSData* keychainData, NSData* uuid) { + if (type != kTLKUnknown) { + return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, + piggy_sizeof_data(keychainData) + + piggy_sizeof_data(uuid) + + ccder_sizeof_uint64(type)); + } else { + return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, + piggy_sizeof_data(keychainData) + + piggy_sizeof_data(uuid) + + der_sizeof_string((__bridge CFStringRef)name, NULL)); + } +} + +NSArray* +SOSAccountSortTLKS(NSArray* tlks) +{ + NSMutableArray* sortedTLKs = [tlks mutableCopy]; + + [sortedTLKs sortUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) { + unsigned rank1 = rank_type(obj1[(__bridge id)kSecAttrServer]); + if (obj1[@"auth"] != NULL) + rank1 += 1000; + unsigned rank2 = rank_type(obj2[(__bridge id)kSecAttrServer]); + if (obj2[@"auth"] != NULL) + rank2 += 1000; + + /* + * Sort by rank (higher better), but prefer TLK that are authoriative (ie used by CKKSViewManager), + * since we are sorting backward, the Ascending/Descending looks wrong below. + */ + if (rank1 > rank2) { + return NSOrderedAscending; + } else if (rank1 < rank2) { + return NSOrderedDescending; + } + return NSOrderedSame; + }]; + + return sortedTLKs; +} + +static NSArray * +build_tlks(NSArray* tlks) +{ + NSMutableArray *array = [NSMutableArray array]; + NSArray* sortedTLKs = SOSAccountSortTLKS(tlks); + + for (NSDictionary *item in sortedTLKs) { + NSData* keychainData = item[(__bridge id)kSecValueData]; + NSString* name = item[(__bridge id)kSecAttrServer]; + NSString *uuidString = item[(__bridge id)kSecAttrAccount]; + NSData* uuid = parse_uuid(uuidString); + + NSMutableData *tlk = [NSMutableData dataWithLength:sizeof_keychainitem(name2type(name), name, keychainData, uuid)]; + + unsigned char *der = [tlk mutableBytes]; + unsigned char *der_end = der + [tlk length]; + + if (encode_tlk(name2type(name), name, keychainData, uuid, der, der_end) == NULL) + return NULL; + + secnotice("piggy", "preparing TLK in order: %@: %@", name, uuidString); + + [array addObject:tlk]; + } + return array; +} + +static NSArray * +build_identities(NSArray* identities) +{ + NSMutableArray *array = [NSMutableArray array]; + for (NSData *item in identities) { + NSMutableData *ident = [NSMutableData dataWithLength:ccder_sizeof_raw_octet_string([item length])]; + + unsigned char *der = [ident mutableBytes]; + unsigned char *der_end = der + [ident length]; + + ccder_encode_raw_octet_string([item length], [item bytes], der, der_end); + [array addObject:ident]; + } + return array; +} + + + +static unsigned char * +encode_data_array(NSArray* data, unsigned char *der, unsigned char *der_end) +{ + unsigned char *body_end = der_end; + for (NSData *datum in data) { + der_end = ccder_encode_body([datum length], [datum bytes], der, der_end); + if (der_end == NULL) + return NULL; + } + return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, body_end, der, der_end); +} + +static size_t sizeof_piggy(size_t identities_size, size_t tlk_size) +{ + return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, + ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, identities_size) + + ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, tlk_size)); +} + +static NSData *encode_piggy(size_t IdentitiesBudget, + size_t TLKBudget, + NSArray* identities, + NSArray* tlks) +{ + NSArray *encodedTLKs = build_tlks(tlks); + NSArray *encodedIdentities = build_identities(identities); + NSMutableArray *budgetArray = [NSMutableArray array]; + NSMutableArray *identitiesArray = [NSMutableArray array]; + size_t payloadSize = 0, identitiesSize = 0; + NSMutableData *result = NULL; + + for (NSData *tlk in encodedTLKs) { + if (TLKBudget - payloadSize < [tlk length]) + break; + [budgetArray addObject:tlk]; + payloadSize += tlk.length; + } + secnotice("piggy", "sending %d tlks", (int)budgetArray.count); + + for (NSData *ident in encodedIdentities) { + if (IdentitiesBudget - identitiesSize < [ident length]) + break; + [identitiesArray addObject:ident]; + identitiesSize += ident.length; + } + secnotice("piggy", "sending %d identities", (int)identitiesArray.count); + + + size_t piggySize = sizeof_piggy(identitiesSize, payloadSize); + + result = [NSMutableData dataWithLength:piggySize]; + + unsigned char *der = [result mutableBytes]; + unsigned char *der_end = der + [result length]; + + if (ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, + encode_data_array(identitiesArray, der, + encode_data_array(budgetArray, der, der_end))) != [result mutableBytes]) + return NULL; + + return result; +} + +static const size_t SOSCCIdentitiesBudget = 120; +static const size_t SOSCCTLKBudget = 500; + +NSData * +SOSPiggyCreateInitialSyncData(NSArray* identities, NSArray* tlks) +{ + return encode_piggy(SOSCCIdentitiesBudget, SOSCCTLKBudget, identities, tlks); +} + +CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* account) +{ + CFMutableArrayRef identities = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSCircleForEachActivePeer(account.trust.trustedCircle, ^(SOSPeerInfoRef peer) { + if(SOSPeerInfoIsCloudIdentity(peer)) { + CFArrayAppendValue(identities, peer); + } + }); + return identities; +} + +CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, CFErrorRef *error) { + CFMutableArrayRef identities = SOSAccountCopyiCloudIdentities(account); + secnotice("piggy", "identities: %@", identities); + + NSMutableArray *encodedIdenities = [NSMutableArray array]; + CFIndex i, count = CFArrayGetCount(identities); + for (i = 0; i < count; i++) { + SOSPeerInfoRef fpi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(identities, i); + NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(fpi, error)); + if (data) + [encodedIdenities addObject:data]; + } + CFRelease(identities); + + NSMutableArray* tlks = SOSAccountGetAllTLKs(); + + return CFBridgingRetain(SOSPiggyCreateInitialSyncData(encodedIdenities, tlks)); +} + +CFDataRef SOSAccountCopyCircleJoiningBlob(SOSAccount* account, SOSPeerInfoRef applicant, CFErrorRef *error) { + SOSGenCountRef gencount = NULL; + CFDataRef signature = NULL; + SecKeyRef ourKey = NULL; + + CFDataRef pbblob = NULL; + + secnotice("circleJoin", "Making circle joining blob as sponsor (SOSAccountCopyCircleJoiningBlob)"); + + SecKeyRef userKey = SOSAccountGetTrustedPublicCredential(account, error); + require_quiet(userKey, errOut); + + require_action_quiet(applicant, errOut, SOSCreateError(kSOSErrorProcessingFailure, CFSTR("No applicant provided"), (error != NULL) ? *error : NULL, error)); + require_quiet(SOSPeerInfoApplicationVerify(applicant, userKey, error), errOut); + + { + SOSFullPeerInfoRef fpi = account.fullPeerInfo; + ourKey = SOSFullPeerInfoCopyDeviceKey(fpi, error); + require_quiet(ourKey, errOut); + } + + SOSCircleRef currentCircle = [account.trust getCircle:error]; + require_quiet(currentCircle, errOut); + + SOSCircleRef prunedCircle = SOSCircleCopyCircle(NULL, currentCircle, error); + require_quiet(prunedCircle, errOut); + require_quiet(SOSCirclePreGenerationSign(prunedCircle, userKey, error), errOut); + + gencount = SOSGenerationIncrementAndCreate(SOSCircleGetGeneration(prunedCircle)); + + signature = SOSCircleCopyNextGenSignatureWithPeerAdded(prunedCircle, applicant, ourKey, error); + require_quiet(signature, errOut); + + pbblob = SOSPiggyBackBlobCopyEncodedData(gencount, ourKey, signature, error); + +errOut: + CFReleaseNull(gencount); + CFReleaseNull(signature); + CFReleaseNull(ourKey); + + if(!pbblob && error != NULL) { + secnotice("circleJoin", "Failed to make circle joining blob as sponsor %@", *error); + } + + return pbblob; +} + +bool SOSAccountJoinWithCircleJoiningBlob(SOSAccount* account, CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) { + bool retval = false; + SecKeyRef userKey = NULL; + SOSAccountTrustClassic *trust = account.trust; + SOSGenCountRef gencount = NULL; + CFDataRef signature = NULL; + SecKeyRef pubKey = NULL; + bool setInitialSyncTimeoutToV0 = false; + + secnotice("circleJoin", "Joining circles through piggy-back (SOSAccountCopyCircleJoiningBlob)"); + + if (!isData(joiningBlob)) + return false; + + userKey = SOSAccountGetPrivateCredential(account, error); + if(!userKey) + return retval; + + if (!SOSPiggyBackBlobCreateFromData(&gencount, &pubKey, &signature, joiningBlob, version, &setInitialSyncTimeoutToV0, error)) + return retval; + + if(setInitialSyncTimeoutToV0){ + secnotice("piggy", "setting flag in account for piggybacking v0"); + SOSAccountSetValue(account, kSOSInitialSyncTimeoutV0, kCFBooleanTrue, NULL); + } + else{ + secnotice("piggy", "setting flag in account for piggybacking v0"); + SOSAccountClearValue(account, kSOSInitialSyncTimeoutV0, NULL); + } + SOSAccountSetValue(account, kSOSUnsyncedViewsKey, kCFBooleanTrue, NULL); + + retval = [trust modifyCircle:account.circle_transport err:error action:^bool(SOSCircleRef copyOfCurrent) { + return SOSCircleAcceptPeerFromHSA2(copyOfCurrent, userKey, + gencount, + pubKey, + signature, + trust.fullPeerInfo, error);; + + }]; + + CFReleaseNull(gencount); + CFReleaseNull(pubKey); + CFReleaseNull(signature); + + return retval; +} + +static char boolToChars(bool val, char truechar, char falsechar) { + return val? truechar: falsechar; +} + +#define ACCOUNTLOGSTATE "accountLogState" +void SOSAccountLogState(SOSAccount* account) { + bool hasPubKey = account.accountKey != NULL; + SOSAccountTrustClassic *trust = account.trust; + bool pubTrusted = account.accountKeyIsTrusted; + bool hasPriv = account.accountPrivateKey != NULL; + SOSCCStatus stat = [account getCircleStatus:NULL]; + + CFStringRef userPubKeyID = (account.accountKey) ? SOSCopyIDOfKeyWithLength(account.accountKey, 8, NULL): + CFStringCreateCopy(kCFAllocatorDefault, CFSTR("*No Key*")); + + secnotice(ACCOUNTLOGSTATE, "Start"); + + secnotice(ACCOUNTLOGSTATE, "ACCOUNT: [keyStatus: %c%c%c hpub %@] [SOSCCStatus: %@]", + boolToChars(hasPubKey, 'U', 'u'), boolToChars(pubTrusted, 'T', 't'), boolToChars(hasPriv, 'I', 'i'), + userPubKeyID, + SOSAccountGetSOSCCStatusString(stat) + ); + CFReleaseNull(userPubKeyID); + if(trust.trustedCircle) SOSCircleLogState(ACCOUNTLOGSTATE, trust.trustedCircle, account.accountKey, (__bridge CFStringRef)(account.peerID)); + else secnotice(ACCOUNTLOGSTATE, "ACCOUNT: No Circle"); +} + +void SOSAccountLogViewState(SOSAccount* account) { + bool isInCircle = [account.trust isInCircle:NULL]; + require_quiet(isInCircle, imOut); + SOSPeerInfoRef mpi = account.peerInfo; + bool isInitialComplete = SOSAccountHasCompletedInitialSync(account); + bool isBackupComplete = SOSAccountHasCompletedRequiredBackupSync(account); + + CFSetRef views = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL; + CFStringSetPerformWithDescription(views, ^(CFStringRef description) { + secnotice(ACCOUNTLOGSTATE, "Sync: %c%c PeerViews: %@", + boolToChars(isInitialComplete, 'I', 'i'), + boolToChars(isBackupComplete, 'B', 'b'), + description); + }); + CFReleaseNull(views); + CFSetRef unsyncedViews = SOSAccountCopyOutstandingViews(account); + CFStringSetPerformWithDescription(views, ^(CFStringRef description) { + secnotice(ACCOUNTLOGSTATE, "outstanding views: %@", description); + }); + CFReleaseNull(unsyncedViews); + +imOut: + secnotice(ACCOUNTLOGSTATE, "Finish"); + + return; +} + + +void SOSAccountSetTestSerialNumber(SOSAccount* account, CFStringRef serial) { + if(!isString(serial)) return; + CFMutableDictionaryRef newv2dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionarySetValue(newv2dict, sSerialNumberKey, serial); + [account.trust updateV2Dictionary:account v2:newv2dict]; +} + +void SOSAccountResetOTRNegotiationCoder(SOSAccountTransaction* txn, CFStringRef peerid) +{ + secnotice("otrtimer", "timer fired!"); + CFErrorRef error = NULL; + SecADAddValueForScalarKey((__bridge CFStringRef) SecSOSAggdReattemptOTRNegotiation,1); + __block SOSAccount* account = txn.account; + + SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account.factory, SOSCircleGetName(account.trust.trustedCircle), NULL); + SOSEngineWithPeerID(engine, peerid, &error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + if(SOSCoderIsCoderInAwaitingState(coder)){ + secnotice("otrtimer", "coder is in awaiting state, restarting coder"); + CFErrorRef localError = NULL; + SOSCoderReset(coder); + if(SOSCoderStart(coder, &localError) == kSOSCoderFailure){ + secerror("Attempt to recover coder failed to restart: %@", localError); + } + else{ + secnotice("otrtimer", "coder restarted!"); + SOSEngineSetCodersNeedSaving(engine, true); + SOSPeerSetMustSendMessage(peer, true); + SOSCCRequestSyncWithPeer(SOSPeerGetID(peer)); + } + SOSPeerOTRTimerIncreaseOTRNegotiationRetryCount(account, (__bridge NSString*)SOSPeerGetID(peer)); + SOSPeerRemoveOTRTimerEntry(peer); + SOSPeerOTRTimerRemoveRTTTimeoutForPeer(account, (__bridge NSString*)SOSPeerGetID(peer)); + SOSPeerOTRTimerRemoveLastSentMessageTimestamp(account, (__bridge NSString*)SOSPeerGetID(peer)); + } + else{ + secnotice("otrtimer", "time fired but out of negotiation! Not restarting coder"); + } + }); + if(error) + { + secnotice("otrtimer","error grabbing engine for peer id: %@, error:%@", peerid, error); + } + CFReleaseNull(error); +} + +void SOSAccountTimerFiredSendNextMessage(SOSAccountTransaction* txn, NSString* peerid, NSString* accessGroup) +{ + __block SOSAccount* account = txn.account; + CFErrorRef error = NULL; + + SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(txn.account.factory, SOSCircleGetName(account.trust.trustedCircle), NULL); + SOSEngineWithPeerID(engine, (__bridge CFStringRef)peerid, &error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + + NSString *peer_id = (__bridge NSString*)SOSPeerGetID(peer); + PeerRateLimiter *limiter = (__bridge PeerRateLimiter*)SOSPeerGetRateLimiter(peer); + CFErrorRef error = NULL; + NSData* message = [limiter.accessGroupToNextMessageToSend objectForKey:accessGroup]; + + if(message){ + secnotice("ratelimit","SOSPeerRateLimiter timer went off! sending:%@ \n to peer:%@", message, peer_id); + bool sendResult = [account.ids_message_transport SOSTransportMessageSendMessage:account.ids_message_transport id:(__bridge CFStringRef)peer_id messageToSend:(__bridge CFDataRef)message err:&error]; + + if(!sendResult || error){ + secnotice("ratelimit", "could not send message: %@", error); + } + } + [limiter.accessGroupRateLimitState setObject:[[NSNumber alloc]initWithLong:RateLimitStateCanSend] forKey:accessGroup]; + [limiter.accessGroupToTimer removeObjectForKey:accessGroup]; + [limiter.accessGroupToNextMessageToSend removeObjectForKey:accessGroup]; + }); + + if(error) + { + secnotice("otrtimer","error grabbing engine for peer id: %@, error:%@", peerid, error); + } + CFReleaseNull(error); +} + +@end + + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.m similarity index 72% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.m index f27550f4..e3974808 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.m @@ -3,12 +3,14 @@ // sec // -#include "SOSAccountPriv.h" +#include "SOSAccount.h" #include "SOSCloudKeychainClient.h" #include #include #include +#include +#include #include "SOSInternal.h" @@ -51,7 +53,7 @@ bool SOSDeleteV0Keybag(CFErrorRef *error) { CFReleaseNull(attributes); - return SecError(result != errSecItemNotFound ? result : errSecSuccess, error, CFSTR("Deleting V0 Keybag failed - %ld"), result); + return SecError(result != errSecItemNotFound ? result : errSecSuccess, error, CFSTR("Deleting V0 Keybag failed - %d"), (int)result); } static bool SOSSaveV0Keybag(CFDataRef v0Keybag, CFErrorRef *error) { @@ -77,14 +79,14 @@ static bool SOSPeerInfoIsViewBackupEnabled(SOSPeerInfoRef peerInfo, CFStringRef return SOSPeerInfoHasBackupKey(peerInfo) && SOSPeerInfoIsViewPermitted(peerInfo, viewName); } -static CFSetRef SOSAccountCopyBackupPeersForView(SOSAccountRef account, CFStringRef viewName) { +static CFSetRef SOSAccountCopyBackupPeersForView(SOSAccount* account, CFStringRef viewName) { CFMutableSetRef backupPeers = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - SOSCircleRef circle = SOSAccountGetCircle(account, NULL); + SOSCircleRef circle = [account.trust getCircle:NULL]; require_quiet(circle, exit); - SOSCircleForEachValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) { + SOSCircleForEachValidPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) { if (SOSPeerInfoIsViewBackupEnabled(peer, viewName)) CFSetAddValue(backupPeers, peer); }); @@ -93,7 +95,7 @@ exit: return backupPeers; } -static void SOSAccountWithBackupPeersForView(SOSAccountRef account, CFStringRef viewName, void (^action)(CFSetRef peers)) { +static void SOSAccountWithBackupPeersForView(SOSAccount* account, CFStringRef viewName, void (^action)(CFSetRef peers)) { CFSetRef backupPeersForView = SOSAccountCopyBackupPeersForView(account, viewName); action(backupPeersForView); @@ -102,11 +104,11 @@ static void SOSAccountWithBackupPeersForView(SOSAccountRef account, CFStringRef } -static bool SOSAccountWithBSKBForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error, +static bool SOSAccountWithBSKBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error, bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) { __block SOSBackupSliceKeyBagRef bskb = NULL; bool result = false; - CFDataRef rkbg = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, error); + CFDataRef rkbg = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL); SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) { if(! rkbg) { @@ -135,13 +137,13 @@ CFStringRef SOSBackupCopyRingNameForView(CFStringRef viewName) { return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-tomb"), viewName); } -static bool SOSAccountUpdateBackupRing(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error, +static bool SOSAccountUpdateBackupRing(SOSAccount* account, CFStringRef viewName, CFErrorRef *error, SOSRingRef (^modify)(SOSRingRef existing, CFErrorRef *error)) { CFStringRef ringName = SOSBackupCopyRingNameForView(viewName); bool result = SOSAccountUpdateNamedRing(account, ringName, error, ^SOSRingRef(CFStringRef ringName, CFErrorRef *error) { - return SOSRingCreate(ringName, SOSAccountGetMyPeerID(account), kSOSRingBackup, error); + return SOSRingCreate(ringName, (__bridge CFStringRef) account.peerID, kSOSRingBackup, error); }, modify); CFReleaseNull(ringName); @@ -149,35 +151,28 @@ static bool SOSAccountUpdateBackupRing(SOSAccountRef account, CFStringRef viewNa return result; } -static CFSetRef SOSAccountCopyPeerSetForView(SOSAccountRef account, CFStringRef viewName) { - CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - - if (account->trusted_circle) { - SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) { - if (CFSetContainsValue(SOSPeerInfoGetPermittedViews(peer), viewName)) { - CFSetAddValue(result, peer); - } - }); - } - - return result; -} -static bool SOSAccountSetKeybagForViewBackupRing(SOSAccountRef account, CFStringRef viewName, SOSBackupSliceKeyBagRef keyBag, CFErrorRef *error) { + +static bool SOSAccountSetKeybagForViewBackupRing(SOSAccount* account, CFStringRef viewName, SOSBackupSliceKeyBagRef keyBag, CFErrorRef *error) { CFMutableSetRef backupViewSet = CFSetCreateMutableForCFTypes(NULL); bool result = false; - require_quiet(SecAllocationError(backupViewSet, error, CFSTR("No backup view set created")), errOut); + + if(!SecAllocationError(backupViewSet, error, CFSTR("No backup view set created"))){ + secnotice("backupring", "Got error setting keybag for backup view '%@': %@", viewName, error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space.")); + + return result; + } CFSetAddValue(backupViewSet, viewName); result = SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) { SOSRingRef newRing = NULL; - CFSetRef viewPeerSet = SOSAccountCopyPeerSetForView(account, viewName); + CFSetRef viewPeerSet = [account.trust copyPeerSetForView:viewName]; CFMutableSetRef cleared = CFSetCreateMutableForCFTypes(NULL); SOSRingSetPeerIDs(existing, cleared); SOSRingAddAll(existing, viewPeerSet); - require_quiet(SOSRingSetBackupKeyBag(existing, SOSAccountGetMyFullPeerInfo(account), backupViewSet, keyBag, error), exit); + require_quiet(SOSRingSetBackupKeyBag(existing, account.fullPeerInfo, backupViewSet, keyBag, error), exit); newRing = CFRetainSafe(existing); exit: @@ -185,9 +180,7 @@ static bool SOSAccountSetKeybagForViewBackupRing(SOSAccountRef account, CFString CFReleaseNull(cleared); return newRing; }); - -errOut: - + if (result && NULL != error && NULL != *error) { secerror("Got Success and Error (dropping error): %@", *error); CFReleaseNull(*error); @@ -201,7 +194,7 @@ errOut: return result; } -bool SOSAccountNewBKSBForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error) +bool SOSAccountNewBKSBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error) { return SOSAccountWithBSKBForView(account, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) { bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error); @@ -209,9 +202,9 @@ bool SOSAccountNewBKSBForView(SOSAccountRef account, CFStringRef viewName, CFErr }); } -bool SOSAccountIsBackupRingEmpty(SOSAccountRef account, CFStringRef viewName) { +bool SOSAccountIsBackupRingEmpty(SOSAccount* account, CFStringRef viewName) { CFStringRef backupRing = SOSBackupCopyRingNameForView(viewName); - SOSRingRef ring = SOSAccountCopyRing(account, backupRing, NULL); + SOSRingRef ring = [account.trust copyRing:backupRing err:NULL]; CFReleaseNull(backupRing); int peercnt = 0; if(ring) peercnt = SOSRingCountPeers(ring); @@ -219,33 +212,34 @@ bool SOSAccountIsBackupRingEmpty(SOSAccountRef account, CFStringRef viewName) { return peercnt == 0; } -bool SOSAccountUpdatePeerInfo(SOSAccountRef account, CFStringRef updateDescription, CFErrorRef *error, bool (^update)(SOSFullPeerInfoRef fpi, CFErrorRef *error)) { - if (account->my_identity == NULL) +bool SOSAccountUpdatePeerInfo(SOSAccount* account, CFStringRef updateDescription, CFErrorRef *error, bool (^update)(SOSFullPeerInfoRef fpi, CFErrorRef *error)) { + + if (!account.hasPeerInfo) return true; - bool result = update(account->my_identity, error); + bool result = update(account.fullPeerInfo, error); if (result && SOSAccountHasCircle(account, NULL)) { - return SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle_to_change) { + return [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle_to_change) { secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for %@", updateDescription); - return SOSCircleUpdatePeerInfo(circle_to_change, SOSAccountGetMyPeerInfo(account)); - }); + return SOSCircleUpdatePeerInfo(circle_to_change, account.peerInfo); + }]; } return result; } -bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccountRef account, CFStringRef viewname){ +bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccount* account, CFStringRef viewname){ bool result = false; CFErrorRef bsError = NULL; CFDataRef backupSliceData = NULL; SOSRingRef ring = NULL; SOSBackupSliceKeyBagRef backupSlice = NULL; - require_quiet(SOSPeerInfoIsViewBackupEnabled(SOSAccountGetMyPeerInfo(account), viewname), errOut); + require_quiet(SOSPeerInfoIsViewBackupEnabled(account.peerInfo, viewname), errOut); CFStringRef ringName = SOSBackupCopyRingNameForView(viewname); - ring = SOSAccountCopyRing(account, ringName, &bsError); + ring = [account.trust copyRing:ringName err:&bsError]; CFReleaseNull(ringName); require_quiet(ring, errOut); @@ -258,7 +252,7 @@ bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccountRef account, CFStringR require_quiet(backupSlice, errOut); CFSetRef peers = SOSBSKBGetPeers(backupSlice); - SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account); + SOSPeerInfoRef myPeer = account.peerInfo; SOSPeerInfoRef myPeerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer); require_quiet(isSOSPeerInfo(myPeerInBSKB), errOut); @@ -279,7 +273,7 @@ errOut: return result; } -bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccountRef account, SOSPeerInfoRef testPeer, CFStringRef viewname){ +bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccount* account, SOSPeerInfoRef testPeer, CFStringRef viewname){ bool result = false; CFErrorRef bsError = NULL; CFDataRef backupSliceData = NULL; @@ -289,7 +283,8 @@ bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccountRef account, SOSPeerInfo require_quiet(testPeer, errOut); CFStringRef ringName = SOSBackupCopyRingNameForView(viewname); - ring = SOSAccountCopyRing(account, ringName, &bsError); + + ring = [account.trust copyRing:ringName err:&bsError]; CFReleaseNull(ringName); require_quiet(ring, errOut); @@ -319,7 +314,7 @@ errOut: } -bool SOSAccountUpdateOurPeerInBackup(SOSAccountRef account, SOSRingRef oldRing, CFErrorRef *error){ +bool SOSAccountUpdateOurPeerInBackup(SOSAccount* account, SOSRingRef oldRing, CFErrorRef *error){ bool result = false; CFSetRef viewNames = SOSBackupRingGetViews(oldRing, error); __block CFStringRef viewName = NULL; @@ -339,8 +334,8 @@ fail: return result; } -void SOSAccountForEachRingName(SOSAccountRef account, void (^operation)(CFStringRef value)) { - SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account); +void SOSAccountForEachBackupRingName(SOSAccount* account, void (^operation)(CFStringRef value)) { + SOSPeerInfoRef myPeer = account.peerInfo; if (myPeer) { CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views. @@ -359,8 +354,29 @@ void SOSAccountForEachRingName(SOSAccountRef account, void (^operation)(CFString } } -void SOSAccountForEachBackupView(SOSAccountRef account, void (^operation)(const void *value)) { - SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account); + +void SOSAccountForEachRingName(SOSAccount* account, void (^operation)(CFStringRef value)) { + SOSPeerInfoRef myPeer = account.peerInfo; + if (myPeer) { + CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views. + + CFSetForEach(allViews, ^(const void *value) { + CFStringRef viewName = asString(value, NULL); + + if (viewName) { + CFStringRef ringName = SOSBackupCopyRingNameForView(viewName); + operation(ringName); + CFReleaseNull(ringName); + } + }); + CFReleaseNull(allViews); + // Only one "ring" now (other than backup rings) when there's more this will need to be modified. + operation(kSOSRecoveryRing); + } +} + +void SOSAccountForEachBackupView(SOSAccount* account, void (^operation)(const void *value)) { + SOSPeerInfoRef myPeer = account.peerInfo; if (myPeer) { CFMutableSetRef myBackupViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerInfoGetPermittedViews(myPeer)); @@ -371,26 +387,27 @@ void SOSAccountForEachBackupView(SOSAccountRef account, void (^operation)(const } -bool SOSAccountSetBackupPublicKey(SOSAccountTransactionRef aTxn, CFDataRef backupKey, CFErrorRef *error) +bool SOSAccountSetBackupPublicKey(SOSAccountTransaction* aTxn, CFDataRef cfBackupKey, CFErrorRef *error) { - SOSAccountRef account = aTxn->account; + SOSAccount* account = aTxn.account; + NSData* backupKey = [[NSData alloc]initWithData:(__bridge NSData * _Nonnull)(cfBackupKey)]; __block bool result = false; - CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) { - CFDataPerformWithHexString(account->backup_key, ^(CFStringRef oldBackupKey) { + CFDataPerformWithHexString((__bridge CFDataRef)(backupKey), ^(CFStringRef backupKeyString) { + CFDataPerformWithHexString((__bridge CFDataRef)((account.backup_key)), ^(CFStringRef oldBackupKey) { secnotice("backup", "SetBackupPublic: %@ from %@", backupKeyString, oldBackupKey); }); }); - require_quiet(SOSAccountIsInCircle(account, error), exit); + require_quiet([account.trust isInCircle:error], exit); - if (CFEqualSafe(backupKey, account->backup_key)) + if ([backupKey isEqual:account.backup_key]) return true; - - CFRetainAssign(account->backup_key, backupKey); - account->circle_rings_retirements_need_attention = true; + account.backup_key = [[NSData alloc] initWithData:backupKey]; + + account.circle_rings_retirements_need_attention = true; result = true; @@ -401,7 +418,7 @@ exit: return result; } -static bool SOSAccountWithBSKBAndPeerInfosForView(SOSAccountRef account, CFArrayRef retiree, CFStringRef viewName, CFErrorRef *error, +static bool SOSAccountWithBSKBAndPeerInfosForView(SOSAccount* account, CFArrayRef retiree, CFStringRef viewName, CFErrorRef *error, bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) { __block SOSBackupSliceKeyBagRef bskb = NULL; bool result = false; @@ -438,22 +455,24 @@ exit: return result; } -bool SOSAccountRemoveBackupPublickey(SOSAccountTransactionRef aTxn, CFErrorRef *error) +bool SOSAccountRemoveBackupPublickey(SOSAccountTransaction* aTxn, CFErrorRef *error) { - SOSAccountRef account = aTxn->account; + SOSAccount* account = aTxn.account; __block bool result = false; __block CFArrayRef removals = NULL; - CFReleaseNull(account->backup_key); - - require_quiet(SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), error, - ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) { - return SOSFullPeerInfoUpdateBackupKey(fpi, NULL, error); - }), exit); + account.backup_key = nil; + if(!SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), error, + ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) { + return SOSFullPeerInfoUpdateBackupKey(fpi, NULL, error); + })){ + return result; + } + removals = CFArrayCreateForCFTypes(kCFAllocatorDefault, - SOSAccountGetMyPeerInfo(account), NULL); + account.peerInfo, NULL); SOSAccountForEachBackupView(account, ^(const void *value) { CFStringRef viewName = (CFStringRef)value; @@ -465,17 +484,16 @@ bool SOSAccountRemoveBackupPublickey(SOSAccountTransactionRef aTxn, CFErrorRef * result = true; - -exit: + return result; } -bool SOSAccountSetBSKBagForAllSlices(SOSAccountRef account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){ +bool SOSAccountSetBSKBagForAllSlices(SOSAccount* account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){ __block bool result = false; SOSBackupSliceKeyBagRef backup_slice = NULL; - require_quiet(SOSAccountIsInCircle(account, error), exit); + require_quiet([account.trust isInCircle:error], exit); if (setupV0Only) { result = SOSSaveV0Keybag(aks_bag, error); @@ -496,7 +514,7 @@ exit: return result; } -static CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccountRef account, CFArrayRef peers, CFSetRef peersInBackup){ +static CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccount* account, CFArrayRef peers, CFSetRef peersInBackup){ CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFSetForEach(peersInBackup, ^(const void *value) { @@ -515,10 +533,10 @@ static CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccountRef } -bool SOSAccountRemoveBackupPeers(SOSAccountRef account, CFArrayRef peers, CFErrorRef *error){ +bool SOSAccountRemoveBackupPeers(SOSAccount* account, CFArrayRef peers, CFErrorRef *error){ __block bool result = true; - SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account); + SOSFullPeerInfoRef fpi = account.fullPeerInfo; SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi); CFSetRef permittedViews = SOSPeerInfoGetPermittedViews(myPeer); @@ -540,15 +558,14 @@ bool SOSAccountRemoveBackupPeers(SOSAccountRef account, CFArrayRef peers, CFErro } -SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef* error){ +SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccount* account, CFStringRef viewName, CFErrorRef* error){ CFDataRef backupSliceData = NULL; CFStringRef ringName = NULL; SOSRingRef ring = NULL; SOSBackupSliceKeyBagRef bskb = NULL; ringName = SOSBackupCopyRingNameForView(viewName); - - ring = SOSAccountCopyRing(account, ringName, NULL); + ring = [account.trust copyRing:ringName err:NULL]; require_action_quiet(ring, exit, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("failed to get ring"))); //grab the backup slice from the ring @@ -564,13 +581,19 @@ exit: return bskb; } -bool SOSAccountIsLastBackupPeer(SOSAccountRef account, CFErrorRef *error) { +bool SOSAccountIsLastBackupPeer(SOSAccount* account, CFErrorRef *error) { __block bool retval = false; - SOSPeerInfoRef pi = SOSAccountGetMyPeerInfo(account); - require_quiet(SOSPeerInfoHasBackupKey(pi), errOut); - SOSCircleRef circle = SOSAccountGetCircle(account, error); - require_quiet(SOSAccountIsInCircle(account, error), errOut); - require_action_quiet(SOSCircleCountValidSyncingPeers(circle, SOSAccountGetTrustedPublicCredential(account, error)) != 1, errOut, retval = true); + SOSPeerInfoRef pi = account.peerInfo; + if(!SOSPeerInfoHasBackupKey(pi)) + return retval; + + SOSCircleRef circle = [account.trust getCircle:error]; + if(![account.trust isInCircle:error]) + return retval; + if(SOSCircleCountValidSyncingPeers(circle, SOSAccountGetTrustedPublicCredential(account, error)) == 1){ + retval = true; + return retval; + } // We're in a circle with more than 1 ActiveValidPeers - are they in the backups? SOSAccountForEachBackupView(account, ^(const void *value) { CFStringRef viewname = (CFStringRef) value; @@ -581,6 +604,5 @@ bool SOSAccountIsLastBackupPeer(SOSAccountRef account, CFErrorRef *error) { CFReleaseNull(keybag); }); -errOut: return retval; } diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c deleted file mode 100644 index 04afbfb8..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c +++ /dev/null @@ -1,158 +0,0 @@ -// -// SOSAccountCircles.c -// sec -// - -#include "SOSAccountPriv.h" -#include -#include -#include -#include -#include -#include -#include "SOSCloudKeychainClient.h" - - -// -// MARK: Circle management -// - -SecKeyRef SOSAccountCopyPublicKeyForPeer(SOSAccountRef account, CFStringRef peer_id, CFErrorRef *error) { - SecKeyRef publicKey = NULL; - SOSPeerInfoRef peer = NULL; - - require_action_quiet(account->trusted_circle, fail, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to get peer key from"))); - - peer = SOSCircleCopyPeerWithID(account->trusted_circle, peer_id, error); - require_quiet(peer, fail); - - publicKey = SOSPeerInfoCopyPubKey(peer, error); - -fail: - CFReleaseSafe(peer); - return publicKey; -} - - -SOSCircleRef SOSAccountGetCircle(SOSAccountRef a, CFErrorRef *error) -{ - CFTypeRef entry = a->trusted_circle; - - require_action_quiet(!isNull(entry), fail, - SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Incompatible circle in KVS"), NULL, error)); - - require_action_quiet(entry, fail, - SOSCreateError(kSOSErrorNoCircle, CFSTR("No circle found"), NULL, error)); - - - return (SOSCircleRef) entry; - -fail: - return NULL; -} - -static bool SOSAccountInflateTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){ - bool success = false; - - SOSTransportKeyParameterRef tKey = NULL; - SOSTransportCircleRef tCircle = NULL; - SOSTransportMessageRef tidsMessage = NULL; - SOSTransportMessageRef tkvsMessage = NULL; - - tKey = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(account, error); - tCircle = (SOSTransportCircleRef)SOSTransportCircleKVSCreate(account, circleName, error); - - require_quiet(tKey, fail); - require_quiet(tCircle, fail); - - tidsMessage = (SOSTransportMessageRef)SOSTransportMessageIDSCreate(account, circleName, error); - require_quiet(tidsMessage, fail); - - CFRetainAssign(account->ids_message_transport, tidsMessage); - - tkvsMessage = (SOSTransportMessageRef)SOSTransportMessageKVSCreate(account, circleName, error); - require_quiet(tkvsMessage, fail); - - CFRetainAssign(account->kvs_message_transport, tkvsMessage); - - CFRetainAssign(account->key_transport, (SOSTransportKeyParameterRef)tKey); - CFRetainAssign(account->circle_transport, tCircle); - - - success = true; -fail: - CFReleaseNull(tKey); - CFReleaseNull(tCircle); - CFReleaseNull(tidsMessage); - CFReleaseNull(tkvsMessage); - return success; -} - -SOSCircleRef SOSAccountEnsureCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error) -{ - CFErrorRef localError = NULL; - - if (a->trusted_circle == NULL) { - a->trusted_circle = SOSCircleCreate(NULL, name, NULL); - a->key_interests_need_updating = true; - } - - - SOSCircleRef circle = SOSAccountGetCircle(a, &localError); - - require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail, - if (error) { *error = localError; localError = NULL; }); - - require_quiet(SOSAccountInflateTransportsForCircle(a, name, error), fail); - -fail: - CFReleaseNull(localError); - return circle; -} - - -bool SOSAccountUpdateCircleFromRemote(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) -{ - return SOSAccountHandleUpdateCircle(account, newCircle, false, error); -} - -bool SOSAccountUpdateCircle(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) -{ - return SOSAccountHandleUpdateCircle(account, newCircle, true, error); -} - -bool SOSAccountModifyCircle(SOSAccountRef account, - CFErrorRef* error, - bool (^action)(SOSCircleRef circle)) -{ - bool success = false; - - SOSCircleRef circle = NULL; - require_action_quiet(account->trusted_circle, fail, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to get peer key from"))); - - circle = SOSCircleCopyCircle(kCFAllocatorDefault, account->trusted_circle, error); - require_quiet(circle, fail); - - success = true; - require_quiet(action(circle), fail); - - success = SOSAccountUpdateCircle(account, circle, error); - -fail: - CFReleaseSafe(circle); - return success; -} - -CFSetRef SOSAccountCopyPeerSetMatching(SOSAccountRef account, bool (^action)(SOSPeerInfoRef peer)) { - CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - - if (account->trusted_circle) { - SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) { - if (action(peer)) { - CFSetAddValue(result, peer); - } - }); - } - - return result; -} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.m new file mode 100644 index 00000000..db625268 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.m @@ -0,0 +1,43 @@ +// +// SOSAccountCircles.c +// sec +// + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#include +#include "SOSCloudKeychainClient.h" + +// +// MARK: Circle management +// + + +SOSCircleRef SOSAccountEnsureCircle(SOSAccount* a, CFStringRef name, CFErrorRef *error) +{ + CFErrorRef localError = NULL; + SOSAccountTrustClassic *trust = a.trust; + SOSCircleRef circle = trust.trustedCircle; + + if (circle == NULL) { + circle = SOSCircleCreate(NULL, name, NULL); + a.key_interests_need_updating = true; + [trust setTrustedCircle:circle]; + } + + require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail, + if (error) { *error = localError; localError = NULL; }); + +fail: + CFReleaseNull(localError); + return circle; +} + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCloudParameters.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCloudParameters.m similarity index 79% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCloudParameters.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCloudParameters.m index 8a1b99e5..88cdf2fe 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCloudParameters.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCloudParameters.m @@ -5,6 +5,7 @@ #include "SOSAccountPriv.h" #include +#include // // Cloud Paramters encode/decode // @@ -42,21 +43,21 @@ const uint8_t* der_decode_cloud_parameters(CFAllocatorRef allocator, } -bool SOSAccountPublishCloudParameters(SOSAccountRef account, CFErrorRef* error){ +bool SOSAccountPublishCloudParameters(SOSAccount* account, CFErrorRef* error){ bool success = false; - CFIndex cloud_der_len = der_sizeof_cloud_parameters( - account->user_public, - account->user_key_parameters, + CFIndex cloud_der_len = der_sizeof_cloud_parameters(account.accountKey, + (__bridge CFDataRef)(account.accountKeyDerivationParamters), error); - CFMutableDataRef cloudParameters = - CFDataCreateMutableWithScratch(kCFAllocatorDefault, cloud_der_len); + + CFMutableDataRef cloudParameters = CFDataCreateMutableWithScratch(kCFAllocatorDefault, cloud_der_len); - if (der_encode_cloud_parameters(account->user_public, account->user_key_parameters, error, + if (der_encode_cloud_parameters(account.accountKey, (__bridge CFDataRef)(account.accountKeyDerivationParamters), error, CFDataGetMutableBytePtr(cloudParameters), CFDataGetMutablePastEndPtr(cloudParameters)) != NULL) { CFErrorRef changeError = NULL; - if (SOSTransportKeyParameterPublishCloudParameters(account->key_transport, cloudParameters, error)) { + + if ([account.key_transport SOSTransportKeyParameterPublishCloudParameters:account.key_transport data:cloudParameters err:error]) { success = true; } else { SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL, @@ -72,7 +73,7 @@ bool SOSAccountPublishCloudParameters(SOSAccountRef account, CFErrorRef* error){ return success; } -bool SOSAccountRetrieveCloudParameters(SOSAccountRef account, SecKeyRef *newKey, +bool SOSAccountRetrieveCloudParameters(SOSAccount* account, SecKeyRef *newKey, CFDataRef derparms, CFDataRef *newParameters, CFErrorRef* error) { const uint8_t *parse_end = der_decode_cloud_parameters(kCFAllocatorDefault, kSecECDSAAlgorithmID, diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCredentials.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCredentials.c deleted file mode 100644 index 3efa2412..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCredentials.c +++ /dev/null @@ -1,351 +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 -#include "SOSAccountPriv.h" -#include "SOSPeerInfoCollections.h" -#include "SOSTransport.h" - -#define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable" - -// -// MARK: User Credential management -// - -void SOSAccountSetPreviousPublic(SOSAccountRef account) { - CFReleaseNull(account->previous_public); - account->previous_public = account->user_public; - CFRetain(account->previous_public); -} - -static void SOSAccountRemoveInvalidApplications(SOSAccountRef account, SOSCircleRef circle) -{ - CFMutableSetRef peersToRemove = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) { - if (!SOSPeerInfoApplicationVerify(peer, account->user_public, NULL)) - CFSetAddValue(peersToRemove, peer); - }); - - CFSetForEach(peersToRemove, ^(const void *value) { - SOSPeerInfoRef peer = (SOSPeerInfoRef) value; - - SOSCircleWithdrawRequest(circle, peer, NULL); - }); -} - -// List of things to do -// Update myFullPeerInfo in circle if needed -// Fix iCloud Identity if needed -// Gen sign if private key changed - -static bool sosAccountUpgradeiCloudIdentity(SOSCircleRef circle, SecKeyRef privKey) { - bool retval = false; - SOSFullPeerInfoRef cloud_fpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL); - require_quiet(cloud_fpi != NULL, errOut); - require_quiet(SOSFullPeerInfoUpgradeSignatures(cloud_fpi, privKey, NULL), errOut); - retval = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(cloud_fpi)); -errOut: - return retval; -} - -static void SOSAccountGenerationSignatureUpdateWith(SOSAccountRef account, SecKeyRef privKey) { - if (account->trusted_circle && account->my_identity) { - SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle) { - SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account); - bool iAmPeer = SOSCircleHasPeer(account->trusted_circle, myPI, NULL); - bool change = SOSCircleUpdatePeerInfo(circle, myPI); - if(iAmPeer && !SOSCircleVerify(circle, account->user_public, NULL)) { - change |= sosAccountUpgradeiCloudIdentity(circle, privKey); - SOSAccountRemoveInvalidApplications(account, circle); - change |= SOSCircleGenerationSign(circle, privKey, account->my_identity, NULL); - account->departure_code = kSOSNeverLeftCircle; - } else if(iAmPeer) { - SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL); - if(!icfpi) { - SOSAccountRemoveIncompleteiCloudIdentities(account, circle, privKey, NULL); - change |= SOSAccountAddiCloudIdentity(account, circle, privKey, NULL); - } else { - CFReleaseNull(icfpi); - } - } - secnotice("updatingGenSignature", "we changed the circle? %@", change ? CFSTR("YES") : CFSTR("NO")); - return change; - }); - } -} - -bool SOSAccountGenerationSignatureUpdate(SOSAccountRef account, CFErrorRef *error) { - bool result = false; - SecKeyRef priv_key = SOSAccountGetPrivateCredential(account, error); - require_quiet(priv_key, bail); - - SOSAccountGenerationSignatureUpdateWith(account, priv_key); - - result = true; -bail: - return result; -} - -/* this one is meant to be local - not published over KVS. */ -static bool SOSAccountPeerSignatureUpdate(SOSAccountRef account, SecKeyRef privKey, CFErrorRef *error) { - return account->my_identity && SOSFullPeerInfoUpgradeSignatures(account->my_identity, privKey, error); -} - - -void SOSAccountPurgePrivateCredential(SOSAccountRef account) -{ - CFReleaseNull(account->_user_private); - CFReleaseNull(account->_password_tmp); - if (account->user_private_timer) { - dispatch_source_cancel(account->user_private_timer); - dispatch_release(account->user_private_timer); - account->user_private_timer = NULL; - xpc_transaction_end(); - } - if (account->lock_notification_token != NOTIFY_TOKEN_INVALID) { - notify_cancel(account->lock_notification_token); - account->lock_notification_token = NOTIFY_TOKEN_INVALID; - } -} - - -static void SOSAccountSetTrustedUserPublicKey(SOSAccountRef account, bool public_was_trusted, SecKeyRef privKey) -{ - if (!privKey) return; - SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey); - - if (account->user_public && account->user_public_trusted && CFEqual(publicKey, account->user_public)) { - CFReleaseNull(publicKey); - return; - } - - if(public_was_trusted && account->user_public) { - CFReleaseNull(account->previous_public); - account->previous_public = account->user_public; - CFRetain(account->previous_public); - } - - CFReleaseNull(account->user_public); - account->user_public = publicKey; - account->user_public_trusted = true; - - if(!account->previous_public) { - account->previous_public = account->user_public; - CFRetain(account->previous_public); - } - - secnotice("keygen", "trusting new public key: %@", account->user_public); -} - -void SOSAccountSetUnTrustedUserPublicKey(SOSAccountRef account, SecKeyRef publicKey) { - if(account->user_public_trusted && account->user_public) { - secnotice("keygen", "Moving : %@ to previous_public", account->user_public); - CFRetainAssign(account->previous_public, account->user_public); - } - - CFReleaseNull(account->user_public); - account->user_public = publicKey; - account->user_public_trusted = false; - - if(!account->previous_public) { - CFRetainAssign(account->previous_public, account->user_public); - } - - secnotice("keygen", "not trusting new public key: %@", account->user_public); - notify_post(kPublicKeyNotAvailable); -} - - -static void SOSAccountSetPrivateCredential(SOSAccountRef account, SecKeyRef private, CFDataRef password) { - if (!private) - return SOSAccountPurgePrivateCredential(account); - - CFRetain(private); - CFReleaseSafe(account->_user_private); - account->_user_private = private; - CFReleaseSafe(account->_password_tmp); - account->_password_tmp = CFDataCreateCopy(kCFAllocatorDefault, password); - - bool resume_timer = false; - if (!account->user_private_timer) { - xpc_transaction_begin(); - resume_timer = true; - account->user_private_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, account->queue); - dispatch_source_set_event_handler(account->user_private_timer, ^{ - SOSAccountPurgePrivateCredential(account); - }); - - notify_register_dispatch(kUserKeybagStateChangeNotification, &account->lock_notification_token, account->queue, ^(int token) { - bool locked = false; - CFErrorRef lockCheckError = NULL; - - if (!SecAKSGetIsLocked(&locked, &lockCheckError)) { - secerror("Checking for locked after change failed: %@", lockCheckError); - } - - if (locked) { - SOSAccountPurgePrivateCredential(account); - } - }); - } - - // (Re)set the timer's fire time to now + 120 seconds with a 5 second fuzz factor. - dispatch_time_t purgeTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * 60 * NSEC_PER_SEC)); - dispatch_source_set_timer(account->user_private_timer, purgeTime, DISPATCH_TIME_FOREVER, (int64_t)(5 * NSEC_PER_SEC)); - if (resume_timer) - dispatch_resume(account->user_private_timer); -} - -SecKeyRef SOSAccountGetPrivateCredential(SOSAccountRef account, CFErrorRef* error) -{ - if (account->_user_private == NULL) { - SOSCreateError(kSOSErrorPrivateKeyAbsent, CFSTR("Private Key not available - failed to prompt user recently"), NULL, error); - } - return account->_user_private; -} - -CFDataRef SOSAccountGetCachedPassword(SOSAccountRef account, CFErrorRef* error) -{ - if (account->_password_tmp == NULL) { - secnotice("keygen", "Password cache expired"); - } - return account->_password_tmp; -} - -SecKeyRef SOSAccountGetTrustedPublicCredential(SOSAccountRef account, CFErrorRef* error) -{ - if (account->user_public == NULL || account->user_public_trusted == false) { - SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Public Key not available - failed to register before call"), NULL, error); - return NULL; - } - return account->user_public; -} - - - -bool SOSAccountHasPublicKey(SOSAccountRef account, CFErrorRef* error) -{ - return SOSAccountGetTrustedPublicCredential(account, error); -} - -static void sosAccountSetTrustedCredentials(SOSAccountRef account, CFDataRef user_password, SecKeyRef user_private, bool public_was_trusted) { - if(!SOSAccountFullPeerInfoVerify(account, user_private, NULL)) { - (void) SOSAccountPeerSignatureUpdate(account, user_private, NULL); - } - SOSAccountSetTrustedUserPublicKey(account, public_was_trusted, user_private); - SOSAccountSetPrivateCredential(account, user_private, user_password); - SOSAccountCheckForAlwaysOnViews(account); -} - -static SecKeyRef sosAccountCreateKeyIfPasswordIsCorrect(SOSAccountRef account, CFDataRef user_password, CFErrorRef *error) { - SecKeyRef user_private = NULL; - require_quiet(account->user_public && account->user_key_parameters, errOut); - user_private = SOSUserKeygen(user_password, account->user_key_parameters, error); - require_quiet(user_private, errOut); - SecKeyRef public_candidate = SecKeyCreatePublicFromPrivate(user_private); - if(!CFEqualSafe(account->user_public, public_candidate)) { - secnotice("keygen", "Public keys don't match: expected: %@, calculated: %@", account->user_public, public_candidate); - CFReleaseNull(user_private); - } - CFReleaseSafe(public_candidate); -errOut: - return user_private; -} - -static bool sosAccountValidatePasswordOrFail(SOSAccountRef account, CFDataRef user_password, CFErrorRef *error) { - SecKeyRef privKey = sosAccountCreateKeyIfPasswordIsCorrect(account, user_password, error); - if(!privKey) { - if(account->user_key_parameters) debugDumpUserParameters(CFSTR("sosAccountValidatePasswordOrFail"), account->user_key_parameters); - SOSCreateError(kSOSErrorWrongPassword, CFSTR("Could not create correct key with password."), NULL, error); - return false; - } - sosAccountSetTrustedCredentials(account, user_password, privKey, account->user_public_trusted); - CFReleaseNull(privKey); - return true; -} - -void SOSAccountSetParameters(SOSAccountRef account, CFDataRef parameters) { - CFRetainAssign(account->user_key_parameters, parameters); -} - -bool SOSAccountAssertUserCredentials(SOSAccountRef account, CFStringRef user_account __unused, CFDataRef user_password, CFErrorRef *error) -{ - bool public_was_trusted = account->user_public_trusted; - account->user_public_trusted = false; - SecKeyRef user_private = NULL; - CFDataRef parameters = NULL; - - // if this succeeds, skip to the end. Success will update account->user_public_trusted by side-effect. - require_quiet(!sosAccountValidatePasswordOrFail(account, user_password, error), errOut); - - // We may or may not have parameters here. - // In any case we tried using them and they didn't match - // So forget all that and start again, assume we're the first to push anything useful. - - if (CFDataGetLength(user_password) > 20) { - secwarning("Long password (>20 byte utf8) being used to derive account key – this may be a PET by mistake!!"); - } - - parameters = SOSUserKeyCreateGenerateParameters(error); - require_quiet(user_private = SOSUserKeygen(user_password, parameters, error), errOut); - SOSAccountSetParameters(account, parameters); - sosAccountSetTrustedCredentials(account, user_password, user_private, public_was_trusted); - - CFErrorRef publishError = NULL; - if (!SOSAccountPublishCloudParameters(account, &publishError)) { - secerror("Failed to publish new cloud parameters: %@", publishError); - } - - CFReleaseSafe(publishError); - -errOut: - CFReleaseSafe(parameters); - CFReleaseSafe(user_private); - account->key_interests_need_updating = true; - return account->user_public_trusted; -} - - -bool SOSAccountTryUserCredentials(SOSAccountRef account, CFStringRef user_account __unused, CFDataRef user_password, CFErrorRef *error) { - bool success = sosAccountValidatePasswordOrFail(account, user_password, error); - account->key_interests_need_updating = true; - return success; -} - -bool SOSAccountRetryUserCredentials(SOSAccountRef account) { - CFDataRef cachedPassword = SOSAccountGetCachedPassword(account, NULL); - if (cachedPassword == NULL) - return false; - /* - * SOSAccountTryUserCredentials reset the cached password internally, - * so we must have a retain of the password over SOSAccountTryUserCredentials(). - */ - CFRetain(cachedPassword); - bool res = SOSAccountTryUserCredentials(account, NULL, cachedPassword, NULL); - CFRelease(cachedPassword); - return res; -} - - - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCredentials.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCredentials.m new file mode 100644 index 00000000..794e4f85 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountCredentials.m @@ -0,0 +1,471 @@ +/* + * 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 +#include +#include "SOSAccountPriv.h" +#include "SOSPeerInfoCollections.h" +#include "SOSTransport.h" +#import +#import + +#define kPublicKeyAvailable "com.apple.security.publickeyavailable" +// +// MARK: User Credential management +// + + +// List of things to do +// Update myFullPeerInfo in circle if needed +// Fix iCloud Identity if needed +// Gen sign if private key changed + +bool SOSAccountGenerationSignatureUpdate(SOSAccount* account, CFErrorRef *error) { + bool result = false; + SecKeyRef priv_key = SOSAccountGetPrivateCredential(account, error); + require_quiet(priv_key, bail); + + [account.trust generationSignatureUpdateWith:account key:priv_key]; + + result = true; +bail: + return result; +} + +/* this one is meant to be local - not published over KVS. */ +static bool SOSAccountPeerSignatureUpdate(SOSAccount* account, SecKeyRef privKey, CFErrorRef *error) { + SOSFullPeerInfoRef identity = NULL; + SOSAccountTrustClassic *trust = account.trust; + identity = trust.fullPeerInfo; + + return identity && SOSFullPeerInfoUpgradeSignatures(identity, privKey, error); +} + + +void SOSAccountPurgePrivateCredential(SOSAccount* account) +{ + secnotice("keygen", "Purging private account credential"); + + if(account.accountPrivateKey) + { + account.accountPrivateKey = NULL; + } + if(account._password_tmp) + { + account._password_tmp = NULL; + } + if (account.user_private_timer) { + dispatch_source_cancel(account.user_private_timer); + account.user_private_timer = NULL; + xpc_transaction_end(); + } + if (account.lock_notification_token != NOTIFY_TOKEN_INVALID) { + notify_cancel(account.lock_notification_token); + account.lock_notification_token = NOTIFY_TOKEN_INVALID; + } +} + + +static void SOSAccountSetTrustedUserPublicKey(SOSAccount* account, bool public_was_trusted, SecKeyRef privKey) +{ + if (!privKey) return; + SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey); + + if (account.accountKey && account.accountKeyIsTrusted && CFEqual(publicKey, account.accountKey)) { + CFReleaseNull(publicKey); + return; + } + + if(public_was_trusted && account.accountKey) { + account.previousAccountKey = account.accountKey; + } + + account.accountKey = publicKey; + account.accountKeyIsTrusted = true; + + if(!account.previousAccountKey) { + account.previousAccountKey = account.accountKey; + } + + CFReleaseNull(publicKey); + + secnotice("keygen", "trusting new public key: %@", account.accountKey); + notify_post(kPublicKeyAvailable); +} + +void SOSAccountSetUnTrustedUserPublicKey(SOSAccount* account, SecKeyRef publicKey) { + if(account.accountKeyIsTrusted && account.accountKey) { + secnotice("keygen", "Moving : %@ to previousAccountKey", account.accountKey); + account.previousAccountKey = account.accountKey; + } + + account.accountKey = publicKey; + account.accountKeyIsTrusted = false; + + if(!account.previousAccountKey) { + account.previousAccountKey = account.accountKey; + } + + secnotice("keygen", "not trusting new public key: %@", account.accountKey); +} + + +static void SOSAccountSetPrivateCredential(SOSAccount* account, SecKeyRef private, CFDataRef password) { + if (!private) + return SOSAccountPurgePrivateCredential(account); + + secnotice("keygen", "setting new private credential"); + + account.accountPrivateKey = private; + + if (password) { + account._password_tmp = [[NSData alloc] initWithData:(__bridge NSData * _Nonnull)(password)]; + } else { + account._password_tmp = NULL; + } + + bool resume_timer = false; + if (!account.user_private_timer) { + xpc_transaction_begin(); + resume_timer = true; + account.user_private_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, account.queue); + dispatch_source_set_event_handler(account.user_private_timer, ^{ + secnotice("keygen", "Timing out, purging private account credential"); + SOSAccountPurgePrivateCredential(account); + }); + int lockNotification; + + notify_register_dispatch(kUserKeybagStateChangeNotification, &lockNotification, account.queue, ^(int token) { + bool locked = false; + CFErrorRef lockCheckError = NULL; + + if (!SecAKSGetIsLocked(&locked, &lockCheckError)) { + secerror("Checking for locked after change failed: %@", lockCheckError); + } + + if (locked) { + SOSAccountPurgePrivateCredential(account); + } + }); + [account setLock_notification_token:lockNotification]; + } + + SOSAccountRestartPrivateCredentialTimer(account); + + if (resume_timer) + dispatch_resume(account.user_private_timer); +} + +void SOSAccountRestartPrivateCredentialTimer(SOSAccount* account) +{ + if (account.user_private_timer) { + // (Re)set the timer's fire time to now + 10 minutes with a 5 second fuzz factor. + dispatch_time_t purgeTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * 60 * NSEC_PER_SEC)); + dispatch_source_set_timer(account.user_private_timer, purgeTime, DISPATCH_TIME_FOREVER, (int64_t)(5 * NSEC_PER_SEC)); + } +} + +SecKeyRef SOSAccountGetPrivateCredential(SOSAccount* account, CFErrorRef* error) +{ + if (account.accountPrivateKey == NULL) { + SOSCreateError(kSOSErrorPrivateKeyAbsent, CFSTR("Private Key not available - failed to prompt user recently"), NULL, error); + } + return account.accountPrivateKey; +} + +CFDataRef SOSAccountGetCachedPassword(SOSAccount* account, CFErrorRef* error) +{ + if (account._password_tmp == NULL) { + secnotice("keygen", "Password cache expired"); + } + return (__bridge CFDataRef)(account._password_tmp); +} +static NSString *SOSUserCredentialAccount = @"SOSUserCredential"; +static NSString *SOSUserCredentialAccessGroup = @"com.apple.security.sos-usercredential"; + +__unused static void SOSAccountDeleteStashedAccountKey(SOSAccount* account) +{ + NSString *dsid = (__bridge NSString *)SOSAccountGetValue(account, kSOSDSIDKey, NULL); + if (dsid == NULL) + return; + + NSDictionary * attributes = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccount : SOSUserCredentialAccount, + (__bridge id)kSecAttrServer : dsid, + (__bridge id)kSecAttrAccessGroup : SOSUserCredentialAccessGroup, + }; + (void)SecItemDelete((__bridge CFDictionaryRef)attributes); +} + +void SOSAccountStashAccountKey(SOSAccount* account) +{ + OSStatus status; + SecKeyRef user_private = account.accountPrivateKey; + NSData *data = CFBridgingRelease(SecKeyCopyExternalRepresentation(user_private, NULL)); + if (data == NULL){ + return; + } + + NSDictionary *attributes = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccount : SOSUserCredentialAccount, + (__bridge id)kSecAttrIsInvisible : @YES, + (__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleWhenUnlocked, + (__bridge id)kSecAttrAccessGroup : SOSUserCredentialAccessGroup, + (__bridge id)kSecAttrSysBound : @(kSecSecAttrSysBoundPreserveDuringRestore), + (__bridge id)kSecValueData : data, + }; + + status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL); + + if (status == errSecDuplicateItem) { + attributes = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccount : SOSUserCredentialAccount, + (__bridge id)kSecAttrAccessGroup : SOSUserCredentialAccessGroup, + (__bridge id)kSecAttrNoLegacy : @YES, + }; + + status = SecItemUpdate((__bridge CFDictionaryRef)attributes, (__bridge CFDictionaryRef)@{ + (__bridge id)kSecValueData : data, + (__bridge id)kSecAttrSysBound : @(kSecSecAttrSysBoundPreserveDuringRestore) + }); + + if (status) { + secnotice("keygen", "Failed to update user private key to keychain: %d", (int)status); + } + } else if (status != 0) { + secnotice("keygen", "Failed to add user private key to keychain: %d", (int)status); + } + + if(status == 0) { + secnotice("keygen", "Stored user private key stashed local keychain"); + } + + return; +} + +SecKeyRef SOSAccountCopyStashedUserPrivateKey(SOSAccount* account, CFErrorRef *error) +{ + SecKeyRef key = NULL; + CFDataRef data = NULL; + OSStatus status; + + NSDictionary *attributes = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccount : SOSUserCredentialAccount, + (__bridge id)kSecAttrAccessGroup : SOSUserCredentialAccessGroup, + (__bridge id)kSecReturnData : @YES, + (__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitOne, + }; + + status = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, (CFTypeRef *)&data); + if (status) { + SecError(status, error, CFSTR("Failed fetching account credential: %d"), (int)status); + return NULL; + } + + NSDictionary *keyAttributes = @{ + (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, + (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC, + }; + + + key = SecKeyCreateWithData(data, (__bridge CFDictionaryRef)keyAttributes, error); + CFReleaseNull(data); + + return key; +} + +SecKeyRef SOSAccountGetTrustedPublicCredential(SOSAccount* account, CFErrorRef* error) +{ + if (account.accountKey == NULL || account.accountKeyIsTrusted == false) { + SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Public Key not available - failed to register before call"), NULL, error); + return NULL; + } + return account.accountKey; +} + +bool SOSAccountHasPublicKey(SOSAccount* account, CFErrorRef* error) +{ + return SOSAccountGetTrustedPublicCredential(account, error); +} + +static void sosAccountSetTrustedCredentials(SOSAccount* account, CFDataRef user_password, SecKeyRef user_private, bool public_was_trusted) { + if(!SOSAccountFullPeerInfoVerify(account, user_private, NULL)){ + (void) SOSAccountPeerSignatureUpdate(account, user_private, NULL); + } + SOSAccountSetTrustedUserPublicKey(account, public_was_trusted, user_private); + SOSAccountSetPrivateCredential(account, user_private, user_password); + SOSAccountCheckForAlwaysOnViews(account); +} + +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(user_private, errOut); + + require_action_quiet(SOSAccountValidateAccountCredential(account, user_private, error), errOut, CFReleaseNull(user_private)); +errOut: + return user_private; +} + +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)); + SOSCreateError(kSOSErrorWrongPassword, CFSTR("Could not create correct key with password."), NULL, error); + return false; + } + sosAccountSetTrustedCredentials(account, user_password, privKey, account.accountKeyIsTrusted); + CFReleaseNull(privKey); + return true; +} + +void SOSAccountSetParameters(SOSAccount* account, CFDataRef parameters) { + account.accountKeyDerivationParamters = (__bridge NSData *) parameters; +} + +bool SOSAccountValidateAccountCredential(SOSAccount* account, SecKeyRef accountPrivateKey, CFErrorRef *error) +{ + SecKeyRef publicCandidate = NULL; + bool res = false; + + publicCandidate = SecKeyCreatePublicFromPrivate(accountPrivateKey); + + require_action_quiet(CFEqualSafe(account.accountKey, publicCandidate), fail, + SOSCreateErrorWithFormat(kSOSErrorWrongPassword, NULL, error, NULL, CFSTR("account private key no doesn't match validated public key: candidate: %@ accountKey: %@"), publicCandidate, account.accountKey)); + + res = true; +fail: + CFReleaseNull(publicCandidate); + return res; + +} + +bool SOSAccountAssertStashedAccountCredential(SOSAccount* account, CFErrorRef *error) +{ + SecKeyRef accountPrivateKey = NULL, publicCandidate = NULL; + bool result = false; + + require_action(account.accountKey, fail, SOSCreateError(kSOSErrorWrongPassword, CFSTR("account public key missing, can't check stashed copy"), NULL, error)); + require_action(account.accountKeyIsTrusted, fail, SOSCreateError(kSOSErrorWrongPassword, CFSTR("public key no not valid, can't check stashed copy"), NULL, error)); + + + accountPrivateKey = SOSAccountCopyStashedUserPrivateKey(account, error); + require_action_quiet(accountPrivateKey, fail, secnotice("keygen", "Looked for a stashed private key, didn't find one")); + + require(SOSAccountValidateAccountCredential(account, accountPrivateKey, error), fail); + + sosAccountSetTrustedCredentials(account, NULL, accountPrivateKey, true); + + result = true; +fail: + CFReleaseSafe(publicCandidate); + CFReleaseSafe(accountPrivateKey); + + return result; +} + + + +bool SOSAccountAssertUserCredentials(SOSAccount* account, CFStringRef user_account __unused, CFDataRef user_password, CFErrorRef *error) +{ + bool public_was_trusted = account.accountKeyIsTrusted; + account.accountKeyIsTrusted = false; + SecKeyRef user_private = NULL; + CFDataRef parameters = NULL; + + // if this succeeds, skip to the end. Success will update account.accountKeyIsTrusted by side-effect. + require_quiet(!sosAccountValidatePasswordOrFail(account, user_password, error), recordCred); + + // We may or may not have parameters here. + // In any case we tried using them and they didn't match + // So forget all that and start again, assume we're the first to push anything useful. + + if (CFDataGetLength(user_password) > 20) { + secwarning("Long password (>20 byte utf8) being used to derive account key – this may be a PET by mistake!!"); + } + + parameters = SOSUserKeyCreateGenerateParameters(error); + require_quiet(user_private = SOSUserKeygen(user_password, parameters, error), errOut); + SOSAccountSetParameters(account, parameters); + sosAccountSetTrustedCredentials(account, user_password, user_private, public_was_trusted); + + CFErrorRef publishError = NULL; + if (!SOSAccountPublishCloudParameters(account, &publishError)) { + secerror("Failed to publish new cloud parameters: %@", publishError); + } + + CFReleaseNull(publishError); +recordCred: + SOSAccountStashAccountKey(account); +errOut: + CFReleaseNull(parameters); + CFReleaseNull(user_private); + account.key_interests_need_updating = true; + return account.accountKeyIsTrusted; +} + + +bool SOSAccountTryUserCredentials(SOSAccount* account, CFStringRef user_account __unused, CFDataRef user_password, CFErrorRef *error) { + bool success = sosAccountValidatePasswordOrFail(account, user_password, error); + if(success) { + SOSAccountStashAccountKey(account); + } + account.key_interests_need_updating = true; + return success; +} + +bool SOSAccountTryUserPrivateKey(SOSAccount* account, SecKeyRef user_private, CFErrorRef *error) { + bool retval = SOSAccountValidateAccountCredential(account, user_private, error); + if(!retval) { + secnotice("keygen", "Failed to accept provided user_private as credential"); + return retval; + } + sosAccountSetTrustedCredentials(account, NULL, user_private, account.accountKeyIsTrusted); + SOSAccountStashAccountKey(account); + account.key_interests_need_updating = true; + secnotice("keygen", "Accepted provided user_private as credential"); + return retval; +} + +bool SOSAccountRetryUserCredentials(SOSAccount* account) { + CFDataRef cachedPassword = SOSAccountGetCachedPassword(account, NULL); + if (cachedPassword == NULL) + return false; + /* + * SOSAccountTryUserCredentials reset the cached password internally, + * so we must have a retain of the password over SOSAccountTryUserCredentials(). + */ + CFRetain(cachedPassword); + bool res = SOSAccountTryUserCredentials(account, NULL, cachedPassword, NULL); + CFRelease(cachedPassword); + return res; +} + + + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountDer.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountDer.m similarity index 80% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountDer.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountDer.m index bf387523..4dce951a 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountDer.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountDer.m @@ -23,6 +23,7 @@ #include "SOSAccountPriv.h" +#include // // DER Encoding utilities @@ -56,43 +57,6 @@ static uint8_t* ccder_encode_null(const uint8_t *der, uint8_t *der_end) } -// -// Encodes data or a zero length data -// -size_t der_sizeof_data_or_null(CFDataRef data, CFErrorRef* error) -{ - if (data) { - return der_sizeof_data(data, error); - } else { - return der_sizeof_null(kCFNull, error); - } -} - -uint8_t* der_encode_data_or_null(CFDataRef data, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) -{ - if (data) { - return der_encode_data(data, error, der, der_end); - } else { - return der_encode_null(kCFNull, error, der, der_end); - } -} - - -const uint8_t* der_decode_data_or_null(CFAllocatorRef allocator, CFDataRef* data, - CFErrorRef* error, - const uint8_t* der, const uint8_t* der_end) -{ - CFTypeRef value = NULL; - der = der_decode_plist(allocator, 0, &value, error, der, der_end); - if (value && CFGetTypeID(value) != CFDataGetTypeID()) { - CFReleaseNull(value); - } - if (data) { - *data = value; - } - return der; -} - // // Encodes data or a zero length data // diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.m similarity index 52% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.m index ee42fe36..25e4d32e 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.m @@ -21,21 +21,27 @@ * @APPLE_LICENSE_HEADER_END@ */ +#include #include #include "SOSAccountPriv.h" #include "SOSInternal.h" #include "SOSViews.h" #include "SOSPeerInfoV2.h" +#import +#import static CFStringRef kicloud_identity_name = CFSTR("Cloud Identity"); -SecKeyRef SOSAccountCopyDeviceKey(SOSAccountRef account, CFErrorRef *error) { +SecKeyRef SOSAccountCopyDeviceKey(SOSAccount* account, CFErrorRef *error) { SecKeyRef privateKey = NULL; + SOSFullPeerInfoRef identity = NULL; - require_action_quiet(account->my_identity, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No identity to get key from"))); + 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(account->my_identity, error); + privateKey = SOSFullPeerInfoCopyDeviceKey(identity, error); fail: return privateKey; @@ -90,64 +96,24 @@ static SecKeyRef GeneratePermanentFullECKeyForCloudIdentity(int keySize, CFStrin return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlocked, kCFBooleanTrue, error); } -bool SOSAccountEnsureFullPeerAvailable(SOSAccountRef account, CFErrorRef * error) { - require_action_quiet(account->trusted_circle, fail, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("Don't have circle"))); - - if (account->my_identity == NULL) { - CFStringRef keyName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("ID for %@-%@"), SOSPeerGestaltGetName(account->gestalt), SOSCircleGetName(account->trusted_circle)); - SecKeyRef full_key = GeneratePermanentFullECKey(256, keyName, error); - CFReleaseNull(keyName); - - if (full_key) { - CFSetRef initialViews = SOSViewCopyViewSet(kViewSetInitial); - - CFReleaseNull(account->my_identity); - account->my_identity = SOSFullPeerInfoCreateWithViews(kCFAllocatorDefault, account->gestalt, account->backup_key, initialViews, - full_key, error); - CFDictionaryRef v2dictionaryTestUpdates = SOSAccountGetValue(account, kSOSTestV2Settings, NULL); - if(v2dictionaryTestUpdates) SOSFullPeerInfoUpdateV2Dictionary(account->my_identity, v2dictionaryTestUpdates, NULL); - CFReleaseNull(initialViews); - CFReleaseNull(full_key); - - CFSetRef pendingDefaultViews = SOSViewCopyViewSet(kViewSetDefault); - SOSAccountPendEnableViewSet(account, pendingDefaultViews); - CFReleaseNull(pendingDefaultViews); - - SOSAccountSetValue(account, kSOSUnsyncedViewsKey, kCFBooleanTrue, NULL); - - if (!account->my_identity) { - secerror("Can't make FullPeerInfo for %@-%@ (%@) - is AKS ok?", SOSPeerGestaltGetName(account->gestalt), SOSCircleGetName(account->trusted_circle), error ? (void*)*error : (void*)CFSTR("-")); - } - else{ - secnotice("fpi", "alert KeychainSyncingOverIDSProxy the fpi is available"); - notify_post(kSecServerPeerInfoAvailable); - if(account->deviceID) - SOSFullPeerInfoUpdateDeviceID(account->my_identity, account->deviceID, error); - } - } - else { - secerror("No full_key: %@:", error ? *error : NULL); - - } - } - -fail: - return account->my_identity != NULL; -} +bool SOSAccountHasCircle(SOSAccount* account, CFErrorRef* error) { + SOSAccountTrustClassic *trust = account.trust; + SOSCircleRef circle = trust.trustedCircle; -bool SOSAccountHasCircle(SOSAccountRef account, CFErrorRef* error) { - if (!account->trusted_circle) + if (!circle) SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No trusted circle")); - return account->trusted_circle != NULL; + return circle != NULL; } -bool SOSAccountHasFullPeerInfo(SOSAccountRef account, CFErrorRef* error) { +bool SOSAccountHasFullPeerInfo(SOSAccount* account, CFErrorRef* error) { bool hasPeer = false; + SOSAccountTrustClassic *trust = account.trust; + SOSFullPeerInfoRef identity = trust.fullPeerInfo; require(SOSAccountHasCircle(account, error), fail); - hasPeer = account->my_identity != NULL; + hasPeer = identity != NULL; if (!hasPeer) SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("No peer for circle")); @@ -156,69 +122,76 @@ fail: return hasPeer; } -bool SOSAccountIsAccountIdentity(SOSAccountRef account, SOSPeerInfoRef peer_info, CFErrorRef *error) +bool SOSAccountIsAccountIdentity(SOSAccount* account, SOSPeerInfoRef peer_info, CFErrorRef *error) { - return CFEqualSafe(peer_info, SOSFullPeerInfoGetPeerInfo(account->my_identity)); -} + SOSFullPeerInfoRef identity = NULL; -SOSPeerInfoRef SOSAccountGetMyPeerInfo(SOSAccountRef account) { - return SOSFullPeerInfoGetPeerInfo(SOSAccountGetMyFullPeerInfo(account)); + SOSAccountTrustClassic *trust = account.trust; + identity = trust.fullPeerInfo; + return CFEqualSafe(peer_info, SOSFullPeerInfoGetPeerInfo(identity)); } -CFStringRef SOSAccountGetMyPeerID(SOSAccountRef a) { - return SOSPeerInfoGetPeerID(SOSAccountGetMyPeerInfo(a)); -} +bool SOSAccountFullPeerInfoVerify(SOSAccount* account, SecKeyRef privKey, CFErrorRef *error) { + SOSFullPeerInfoRef identity = NULL; -SOSFullPeerInfoRef SOSAccountGetMyFullPeerInfo(SOSAccountRef account) { - return account->trusted_circle ? account->my_identity : NULL; -} - -bool SOSAccountFullPeerInfoVerify(SOSAccountRef account, SecKeyRef privKey, CFErrorRef *error) { - if(!account->my_identity) return false; + SOSAccountTrustClassic *trust = account.trust; + identity = trust.fullPeerInfo; + if(!identity) return false; SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey); - bool retval = SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(account->my_identity), pubKey, error); + bool retval = SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(identity), pubKey, error); CFReleaseNull(pubKey); return retval; } +static bool UpdateKeyName(SecKeyRef key, SOSPeerInfoRef peer, CFErrorRef* error) +{ + CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecClass, kSecClassKey, + kSecAttrSynchronizable,kCFBooleanTrue, + kSecUseTombstones, kCFBooleanTrue, + kSecValueRef, key, + NULL); + + CFStringRef new_name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(peer)); + + CFDictionaryRef change = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecAttrLabel, new_name, + NULL); + + bool result = SecError(SecItemUpdate(query, change), error, CFSTR("Couldn't update name")); + + CFReleaseNull(new_name); + CFReleaseNull(query); + CFReleaseNull(change); + return result; +} + SOSPeerInfoRef GenerateNewCloudIdentityPeerInfo(CFErrorRef *error) { SecKeyRef cloud_key = GeneratePermanentFullECKeyForCloudIdentity(256, kicloud_identity_name, error); + SecKeyRef octagon_key = GeneratePermanentFullECKeyForCloudIdentity(384, kicloud_identity_name, error); SOSPeerInfoRef cloud_peer = NULL; - CFDictionaryRef query = NULL; - CFDictionaryRef change = NULL; - CFStringRef new_name = NULL; - CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + CFDictionaryRef gestalt = NULL; + + require_action_quiet(cloud_key, fail, SecError(errSecAllocate, error, CFSTR("Can't generate keypair for icloud identity"))); + + gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kPIUserDefinedDeviceNameKey, CFSTR("iCloud"), NULL); require_action_quiet(gestalt, fail, SecError(errSecAllocate, error, CFSTR("Can't allocate gestalt"))); - cloud_peer = SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault, gestalt, cloud_key, error); + cloud_peer = SOSPeerInfoCreateCloudIdentity(kCFAllocatorDefault, gestalt, cloud_key, octagon_key, error); require(cloud_peer, fail); - query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecClass, kSecClassKey, - kSecAttrSynchronizable,kCFBooleanTrue, - kSecUseTombstones, kCFBooleanTrue, - kSecValueRef, cloud_key, - NULL); - - new_name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("Cloud Identity - '%@'"), SOSPeerInfoGetPeerID(cloud_peer)); - - change = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSecAttrLabel, new_name, - NULL); - - SecError(SecItemUpdate(query, change), error, CFSTR("Couldn't update name")); + UpdateKeyName(cloud_key, cloud_peer, error); + UpdateKeyName(octagon_key, cloud_peer, error); fail: - CFReleaseNull(new_name); - CFReleaseNull(query); - CFReleaseNull(change); CFReleaseNull(gestalt); CFReleaseNull(cloud_key); + CFReleaseNull(octagon_key); return cloud_peer; } diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGetSet.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGetSet.c deleted file mode 100644 index 397b5051..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGetSet.c +++ /dev/null @@ -1,105 +0,0 @@ -// -// SOSAccountGetSet.c -// Security -// -// - -#include "SOSAccountPriv.h" - -#include - -// -// MARK: Generic Value manipulation -// - -static inline bool SOSAccountEnsureExpansion(SOSAccountRef account, CFErrorRef *error) { - if (!account->expansion) { - account->expansion = CFDictionaryCreateMutableForCFTypes(NULL); - } - - return SecAllocationError(account->expansion, error, CFSTR("Can't Alloc Account Expansion dictionary")); -} - -bool SOSAccountClearValue(SOSAccountRef account, CFStringRef key, CFErrorRef *error) { - bool success = SOSAccountEnsureExpansion(account, error); - require_quiet(success, errOut); - - CFDictionaryRemoveValue(account->expansion, key); -errOut: - return success; -} - -bool SOSAccountSetValue(SOSAccountRef account, CFStringRef key, CFTypeRef value, CFErrorRef *error) { - if (value == NULL) return SOSAccountClearValue(account, key, error); - - bool success = SOSAccountEnsureExpansion(account, error); - require_quiet(success, errOut); - - CFDictionarySetValue(account->expansion, key, value); -errOut: - return success; -} - -CFTypeRef SOSAccountGetValue(SOSAccountRef account, CFStringRef key, CFErrorRef *error) { - if (!account->expansion) { - return NULL; - } - return CFDictionaryGetValue(account->expansion, key); -} - - -// -// MARK: Value as Set manipulation -// -bool SOSAccountValueSetContainsValue(SOSAccountRef account, CFStringRef key, CFTypeRef value); -void SOSAccountValueUnionWith(SOSAccountRef account, CFStringRef key, CFSetRef valuesToUnion); -void SOSAccountValueSubtractFrom(SOSAccountRef account, CFStringRef key, CFSetRef valuesToSubtract); - -bool SOSAccountValueSetContainsValue(SOSAccountRef account, CFStringRef key, CFTypeRef value) { - CFSetRef foundSet = asSet(SOSAccountGetValue(account, key, NULL), NULL); - return foundSet && CFSetContainsValue(foundSet, value); -} - -void SOSAccountValueUnionWith(SOSAccountRef account, CFStringRef key, CFSetRef valuesToUnion) { - CFMutableSetRef unionedSet = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, valuesToUnion); - CFSetRef foundSet = asSet(SOSAccountGetValue(account, key, NULL), NULL); - if (foundSet) { - CFSetUnion(unionedSet, foundSet); - } - SOSAccountSetValue(account, key, unionedSet, NULL); - CFReleaseNull(unionedSet); -} - -void SOSAccountValueSubtractFrom(SOSAccountRef account, CFStringRef key, CFSetRef valuesToSubtract) { - CFSetRef foundSet = asSet(SOSAccountGetValue(account, key, NULL), NULL); - if (foundSet) { - CFMutableSetRef subtractedSet = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, foundSet); - CFSetSubtract(subtractedSet, valuesToSubtract); - SOSAccountSetValue(account, key, subtractedSet, NULL); - CFReleaseNull(subtractedSet); - } -} - -// -// MARK: UUID -CFStringRef SOSAccountCopyUUID(SOSAccountRef account) { - CFStringRef uuid = CFRetainSafe(asString(SOSAccountGetValue(account, kSOSAccountUUID, NULL), NULL)); - if (uuid == NULL) { - CFUUIDRef newID = CFUUIDCreate(kCFAllocatorDefault); - uuid = CFUUIDCreateString(kCFAllocatorDefault, newID); - - CFErrorRef setError = NULL; - if (!SOSAccountSetValue(account, kSOSAccountUUID, uuid, &setError)) { - secerror("Failed to set UUID: %@ (%@)", uuid, setError); - } - CFReleaseNull(setError); - CFReleaseNull(newID); - } - return uuid; -} - -void SOSAccountEnsureUUID(SOSAccountRef account) { - CFStringRef uuid = SOSAccountCopyUUID(account); - CFReleaseNull(uuid); -} - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGetSet.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGetSet.m new file mode 100644 index 00000000..5fd60977 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGetSet.m @@ -0,0 +1,72 @@ +// +// SOSAccountGetSet.c +// Security +// +// + +#include "SOSAccountPriv.h" + +#include + +#import +#import + +// +// MARK: Generic Value manipulation +// + +static inline bool SOSAccountEnsureExpansion(SOSAccount* account, CFErrorRef *error) { + + if (!account.trust.expansion) { + account.trust.expansion = [NSMutableDictionary dictionary]; + } + + return SecAllocationError(((__bridge CFDictionaryRef)account.trust.expansion), error, CFSTR("Can't Alloc Account Expansion dictionary")); +} + +bool SOSAccountClearValue(SOSAccount* account, CFStringRef key, CFErrorRef *error) { + bool success = SOSAccountEnsureExpansion(account, error); + if(!success){ + return success; + } + + [account.trust.expansion removeObjectForKey: (__bridge NSString* _Nonnull)(key)]; + + return success; +} + +bool SOSAccountSetValue(SOSAccount* account, CFStringRef key, CFTypeRef value, CFErrorRef *error) { + if (value == NULL) return SOSAccountClearValue(account, key, error); + + bool success = SOSAccountEnsureExpansion(account, error); + if(!success) + return success; + + [account.trust.expansion setObject:(__bridge id _Nonnull)(value) forKey:(__bridge NSString* _Nonnull)(key)]; + + return success; +} + +// +// MARK: UUID +CFStringRef SOSAccountCopyUUID(SOSAccount* account) { + CFStringRef uuid = CFRetainSafe(asString(SOSAccountGetValue(account, kSOSAccountUUID, NULL), NULL)); + if (uuid == NULL) { + CFUUIDRef newID = CFUUIDCreate(kCFAllocatorDefault); + uuid = CFUUIDCreateString(kCFAllocatorDefault, newID); + + CFErrorRef setError = NULL; + if (!SOSAccountSetValue(account, kSOSAccountUUID, uuid, &setError)) { + secerror("Failed to set UUID: %@ (%@)", uuid, setError); + } + CFReleaseNull(setError); + CFReleaseNull(newID); + } + return uuid; +} + +void SOSAccountEnsureUUID(SOSAccount* account) { + CFStringRef uuid = SOSAccountCopyUUID(account); + CFReleaseNull(uuid); +} + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.h index 049c11a7..bab201c9 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.h @@ -11,8 +11,8 @@ #include "SOSAccount.h" -bool SOSAccountTrustedCircleHasNoGhostOfMe(SOSAccountRef account); -bool SOSAccountGhostResultsInReset(SOSAccountRef account); -SOSCircleRef SOSAccountCloneCircleWithoutMyGhosts(SOSAccountRef account, SOSCircleRef startCircle); +bool SOSAccountTrustedCircleHasNoGhostOfMe(SOSAccount* account); +bool SOSAccountGhostResultsInReset(SOSAccount* account); +SOSCircleRef SOSAccountCloneCircleWithoutMyGhosts(SOSAccount* account, SOSCircleRef startCircle); #endif /* SOSAccountGhost_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.m similarity index 80% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.m index bfcce031..9ff99218 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.m @@ -14,6 +14,7 @@ #include #include #include +#include #define DETECT_IOS_ONLY 1 @@ -70,14 +71,14 @@ errOut: } -static CFSetRef SOSTrustedCircleCreateGhostsOfPeerSet(SOSAccountRef account, SOSPeerInfoRef pi) { - return (account) ? SOSCircleCreateGhostsOfPeerSet(SOSAccountGetCircle(account, NULL), pi): NULL; +static CFSetRef SOSTrustedCircleCreateGhostsOfPeerSet(SOSAccount* account, SOSPeerInfoRef pi) { + return (account) ? SOSCircleCreateGhostsOfPeerSet([account.trust getCircle:NULL], pi): NULL; } -static CFSetRef SOSTrustedCircleCopyGhostSet(SOSAccountRef account) { +static CFSetRef SOSTrustedCircleCopyGhostSet(SOSAccount* account) { CFSetRef ghosts = NULL; require_quiet(account, errOut); - SOSPeerInfoRef me = SOSAccountGetMyPeerInfo(account); + SOSPeerInfoRef me = account.peerInfo; require_quiet(me, errOut); require_quiet(sosGhostCheckValid(me), errOut); ghosts = SOSTrustedCircleCreateGhostsOfPeerSet(account, me); @@ -86,7 +87,7 @@ errOut: } -static CFIndex SOSTrustedCircleGhostSetCount(SOSAccountRef account) { +static CFIndex SOSTrustedCircleGhostSetCount(SOSAccount* account) { CFIndex retval = 0; CFSetRef ghosts = SOSTrustedCircleCopyGhostSet(account); require_quiet(ghosts, retOut); @@ -96,26 +97,24 @@ retOut: return retval; } -bool SOSAccountTrustedCircleHasNoGhostOfMe(SOSAccountRef account) { +bool SOSAccountTrustedCircleHasNoGhostOfMe(SOSAccount* account) { return SOSTrustedCircleGhostSetCount(account) == 0; } -bool SOSAccountGhostResultsInReset(SOSAccountRef account) { - return SOSTrustedCircleGhostSetCount(account) == SOSCircleCountActivePeers(SOSAccountGetCircle(account, NULL)); +bool SOSAccountGhostResultsInReset(SOSAccount* account) { + return SOSTrustedCircleGhostSetCount(account) == SOSCircleCountActivePeers([account.trust getCircle:NULL]); } // This only works if you're in the circle and have the private key -SOSCircleRef SOSAccountCloneCircleWithoutMyGhosts(SOSAccountRef account, SOSCircleRef startCircle) { +SOSCircleRef SOSAccountCloneCircleWithoutMyGhosts(SOSAccount* account, SOSCircleRef startCircle) { SOSCircleRef newCircle = NULL; CFSetRef ghosts = NULL; require_quiet(account, retOut); SecKeyRef userPrivKey = SOSAccountGetPrivateCredential(account, NULL); require_quiet(userPrivKey, retOut); - SOSFullPeerInfoRef meFull = SOSAccountGetMyFullPeerInfo(account); - require_quiet(meFull, retOut); - SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(meFull); + SOSPeerInfoRef me = account.peerInfo; require_quiet(me, retOut); bool iAmApplicant = SOSCircleHasApplicant(startCircle, me, NULL); @@ -132,15 +131,15 @@ SOSCircleRef SOSAccountCloneCircleWithoutMyGhosts(SOSAccountRef account, SOSCirc if(iAmApplicant) { if(SOSCircleRemovePeersByIDUnsigned(newCircle, ghosts) && (SOSCircleCountPeers(newCircle) == 0)) { secnotice("resetToOffering", "Reset to offering with last ghost and me as applicant"); - if(!SOSCircleResetToOffering(newCircle, userPrivKey, meFull, NULL) || - !SOSAccountAddiCloudIdentity(account, newCircle, userPrivKey, NULL)) { + if(!SOSCircleResetToOffering(newCircle, userPrivKey, account.fullPeerInfo, NULL) || + ![account.trust addiCloudIdentity:newCircle key:userPrivKey err:NULL]){ CFReleaseNull(newCircle); } } else { CFReleaseNull(newCircle); } } else { - SOSCircleRemovePeersByID(newCircle, userPrivKey, meFull, ghosts, NULL); + SOSCircleRemovePeersByID(newCircle, userPrivKey, account.fullPeerInfo, ghosts, NULL); } retOut: CFReleaseNull(ghosts); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountHSAJoin.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountHSAJoin.c deleted file mode 100644 index ca2f9b2f..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountHSAJoin.c +++ /dev/null @@ -1,99 +0,0 @@ -// -// SOSAccountHSAJoin.c -// sec -// -// Created by Richard Murphy on 3/23/15. -// -// - -#include "SOSAccountHSAJoin.h" -#include "SOSAccountPriv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -const CFStringRef kSOSHsaPreApprovedPeerKeyInfo = CFSTR("HSAPreApprovedPeer"); - -const CFStringRef kSOSHsaCrKeyUUID = CFSTR("HSAUUID"); -const CFStringRef kSOSHsaCrKeyDescription = CFSTR("HSADESC"); - -CFMutableSetRef SOSAccountCopyPreApprovedHSA2Info(SOSAccountRef account) { - CFMutableSetRef preApprovedPeers = (CFMutableSetRef) SOSAccountGetValue(account, kSOSHsaPreApprovedPeerKeyInfo, NULL); - if(preApprovedPeers) { - preApprovedPeers = CFSetCreateMutableCopy(NULL, 0, preApprovedPeers); - } else { - preApprovedPeers = CFSetCreateMutableForCFTypes(NULL); - } - return preApprovedPeers; -} - -static bool sosAccountSetPreApprovedInfo(SOSAccountRef account, CFStringRef peerID, CFErrorRef *error) { - bool retval = false; - CFMutableSetRef preApprovedPeers = SOSAccountCopyPreApprovedHSA2Info(account); - require_action_quiet(preApprovedPeers, errOut, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("Can't Alloc Pre-Approved Peers Set"), NULL, error)); - CFSetSetValue(preApprovedPeers, peerID); - require(SOSAccountSetValue(account, kSOSHsaPreApprovedPeerKeyInfo, preApprovedPeers, error), errOut); - retval = true; -errOut: - CFReleaseNull(preApprovedPeers); - return retval; -} - -bool SOSAccountSetHSAPubKeyExpected(SOSAccountRef account, CFDataRef pubKeyBytes, CFErrorRef *error) { - bool retval = false; - SecKeyRef publicKey = SecKeyCreateFromPublicBytes(NULL, kSecECDSAAlgorithmID, CFDataGetBytePtr(pubKeyBytes), CFDataGetLength(pubKeyBytes)); - CFStringRef peerID = SOSCopyIDOfKey(publicKey, error); - require(sosAccountSetPreApprovedInfo(account, peerID, error), errOut); - retval = true; -errOut: - CFReleaseNull(publicKey); - CFReleaseNull(peerID); - return retval; -} - -bool SOSAccountVerifyAndAcceptHSAApplicants(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) { - SOSFullPeerInfoRef fpi = account->my_identity; - __block bool circleChanged = false; - CFMutableSetRef approvals = SOSAccountCopyPreApprovedHSA2Info(account); - if(approvals && CFSetGetCount(approvals) > 0) { - SOSCircleForEachApplicant(newCircle, ^(SOSPeerInfoRef peer) { - CFStringRef peerID = SOSPeerInfoGetPeerID(peer); - if(CFSetContainsValue(approvals, peerID)) { - SOSPeerInfoRef copypi = SOSPeerInfoCreateCopy(NULL, peer, NULL); - circleChanged = SOSCircleAcceptRequest(newCircle, SOSAccountGetPrivateCredential(account, NULL), fpi, copypi, error); - CFSetRemoveValue(approvals, peerID); - } - }); - } - if(circleChanged) { - bool local = SOSAccountSetValue(account, kSOSHsaPreApprovedPeerKeyInfo, approvals, error); - if(!local) secnotice("hsa2approval", "Couldn't clean pre-approved peer list"); - } - CFReleaseNull(approvals); - return circleChanged; -} - -bool SOSAccountClientPing(SOSAccountRef account) { - if (account->trusted_circle && account->my_identity - && SOSFullPeerInfoPing(account->my_identity, NULL)) { - SOSAccountModifyCircle(account, NULL, ^(SOSCircleRef circle_to_change) { - secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); - return SOSCircleUpdatePeerInfo(circle_to_change, SOSFullPeerInfoGetPeerInfo(account->my_identity)); - }); - } - - return true; -} - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountHSAJoin.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountHSAJoin.h deleted file mode 100644 index bce9f98f..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountHSAJoin.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// SOSAccountHSAJoin.h -// sec -// -// Created by Richard Murphy on 3/23/15. -// -// - -#ifndef _sec_SOSAccountHSAJoin_ -#define _sec_SOSAccountHSAJoin_ - -#include "SOSAccountPriv.h" - -CFMutableSetRef SOSAccountCopyPreApprovedHSA2Info(SOSAccountRef account); -bool SOSAccountSetHSAPubKeyExpected(SOSAccountRef account, CFDataRef pubKeyBytes, CFErrorRef *error); -bool SOSAccountVerifyAndAcceptHSAApplicants(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error); -bool SOSAccountClientPing(SOSAccountRef account); - -#endif /* defined(_sec_SOSAccountHSAJoin_) */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.h index 1fdde94d..59ee33a7 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.h @@ -10,8 +10,7 @@ #define SOSAccountLog_h #include -#include "SOSAccountPriv.h" -#include +#import #include #include #include @@ -19,9 +18,12 @@ #include #include #include +#import + //#include +@class SOSAccount; -void SOSAccountLog(SOSAccountRef account); -SOSAccountRef SOSAccountCreateFromStringRef(CFStringRef hexString); +void SOSAccountLog(SOSAccount* account); +SOSAccount* SOSAccountCreateFromStringRef(CFStringRef hexString); #endif /* SOSAccountLog_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.m similarity index 51% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.m index cd82a0b7..cc9eb52a 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountLog.m @@ -2,10 +2,7 @@ // SOSAccountLog.c // sec // -// Created by Richard Murphy on 6/1/16. -// -// - +#import #include "SOSAccountLog.h" #include #include @@ -14,38 +11,28 @@ #include "SOSAccountPriv.h" #include "SOSViews.h" #include +#import #include #include -#include +#include #include - #include #include // Keep these for later -static CFStringRef SOSAccountCreateStringRef(SOSAccountRef account) { - CFStringRef hex = NULL; - - CFDataRef derdata = SOSAccountCopyEncodedData(account, kCFAllocatorDefault, NULL); - require_quiet(derdata, errOut); - hex = CFDataCopyHexString(derdata); -errOut: - CFRelease(derdata); - return hex; -} - -void SOSAccountLog(SOSAccountRef account) { - CFStringRef hex = SOSAccountCreateStringRef(account); +void SOSAccountLog(SOSAccount* account) { + NSString* hex = [[account encodedData: nil] asHexString]; if(!hex) return; secdebug("accountLog", "Full contents: %@", hex); - CFRelease(hex); } -SOSAccountRef SOSAccountCreateFromStringRef(CFStringRef hexString) { +SOSAccount* SOSAccountCreateFromStringRef(CFStringRef hexString) { CFDataRef accountDER = CFDataCreateFromHexString(kCFAllocatorDefault, hexString); if(!accountDER) return NULL; - SOSAccountRef account = SOSAccountCreateFromData(kCFAllocatorDefault, accountDER, NULL, NULL); + SOSAccount* account = [SOSAccount accountFromData:(__bridge NSData*) accountDER + factory:NULL + error:nil]; CFReleaseNull(accountDER); return account; } diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.m similarity index 76% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.m index eefec614..17126ec0 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.m @@ -27,11 +27,20 @@ #include #include #include +#include +#import +#include +bool SOSAccountIsMyPeerActive(SOSAccount* account, CFErrorRef* error) { + SOSFullPeerInfoRef identity = NULL; + SOSCircleRef circle = NULL; -bool SOSAccountIsMyPeerActive(SOSAccountRef account, CFErrorRef* error) { - SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(account->my_identity); - return me ? SOSCircleHasActivePeer(account->trusted_circle, me, error) : false; + SOSAccountTrustClassic *trust = account.trust; + identity = trust.fullPeerInfo; + circle = trust.trustedCircle; + + SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(identity); + return me ? SOSCircleHasActivePeer(circle, me, error) : false; } // @@ -45,15 +54,18 @@ static void sosArrayAppendPeerCopy(CFMutableArrayRef appendPeersTo, SOSPeerInfoR CFRelease(peerInfo); } -static CFArrayRef SOSAccountCopySortedPeerArray(SOSAccountRef account, +static CFArrayRef SOSAccountCopySortedPeerArray(SOSAccount* account, CFErrorRef *error, void (^action)(SOSCircleRef circle, CFMutableArrayRef appendPeersTo)) { if (!SOSAccountHasPublicKey(account, error)) return NULL; CFMutableArrayRef peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - - action(account->trusted_circle, peers); + SOSCircleRef circle = NULL; + + SOSAccountTrustClassic *trust = account.trust; + circle = trust.trustedCircle; + action(circle, peers); CFArrayOfSOSPeerInfosSortByID(peers); @@ -61,10 +73,10 @@ static CFArrayRef SOSAccountCopySortedPeerArray(SOSAccountRef account, } -CFArrayRef SOSAccountCopyNotValidPeers(SOSAccountRef account, CFErrorRef *error) { +CFArrayRef SOSAccountCopyNotValidPeers(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { - if(!SOSPeerInfoApplicationVerify(peer, account->user_public, NULL)) { + if(!SOSPeerInfoApplicationVerify(peer, account.accountKey, NULL)) { sosArrayAppendPeerCopy(appendPeersTo, peer); } }); @@ -72,36 +84,29 @@ CFArrayRef SOSAccountCopyNotValidPeers(SOSAccountRef account, CFErrorRef *error) } -CFArrayRef SOSAccountCopyValidPeers(SOSAccountRef account, CFErrorRef *error) { +CFArrayRef SOSAccountCopyValidPeers(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { - if(SOSPeerInfoApplicationVerify(peer, account->user_public, NULL)) { + if(SOSPeerInfoApplicationVerify(peer, account.accountKey, NULL)) { sosArrayAppendPeerCopy(appendPeersTo, peer); } }); }); } -void SOSAccountForEachCirclePeerExceptMe(SOSAccountRef account, void (^action)(SOSPeerInfoRef peer)) { - SOSPeerInfoRef myPi = SOSAccountGetMyPeerInfo(account); - if (account->trusted_circle && myPi) { - CFStringRef myPi_id = SOSPeerInfoGetPeerID(myPi); - SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) { - CFStringRef peerID = SOSPeerInfoGetPeerID(peer); - if (peerID && !CFEqual(peerID, myPi_id)) { - action(peer); - } - }); - } -} -CFArrayRef SOSAccountCopyPeersToListenTo(SOSAccountRef account, CFErrorRef *error) { - SOSPeerInfoRef myPeerInfo = SOSFullPeerInfoGetPeerInfo(account->my_identity); + +CFArrayRef SOSAccountCopyPeersToListenTo(SOSAccount* account, CFErrorRef *error) { + SOSFullPeerInfoRef identity = NULL; + + SOSAccountTrustClassic *trust = account.trust; + identity = trust.fullPeerInfo; + SOSPeerInfoRef myPeerInfo = SOSFullPeerInfoGetPeerInfo(identity); CFStringRef myID = myPeerInfo ? SOSPeerInfoGetPeerID(myPeerInfo) : NULL; return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { if(!CFEqualSafe(myID, SOSPeerInfoGetPeerID(peer)) && - SOSPeerInfoApplicationVerify(peer, account->user_public, NULL) && + SOSPeerInfoApplicationVerify(peer, account.accountKey, NULL) && !SOSPeerInfoIsRetirementTicket(peer)) { CFArrayAppendValue(appendPeersTo, peer); } @@ -109,7 +114,7 @@ CFArrayRef SOSAccountCopyPeersToListenTo(SOSAccountRef account, CFErrorRef *erro }); } -CFArrayRef SOSAccountCopyRetired(SOSAccountRef account, CFErrorRef *error) { +CFArrayRef SOSAccountCopyRetired(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) { sosArrayAppendPeerCopy(appendPeersTo, peer); @@ -117,7 +122,7 @@ CFArrayRef SOSAccountCopyRetired(SOSAccountRef account, CFErrorRef *error) { }); } -CFArrayRef SOSAccountCopyViewUnaware(SOSAccountRef account, CFErrorRef *error) { +CFArrayRef SOSAccountCopyViewUnaware(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { if (!SOSPeerInfoVersionHasV2Data(peer) ) { @@ -135,7 +140,7 @@ CFArrayRef SOSAccountCopyViewUnaware(SOSAccountRef account, CFErrorRef *error) { }); } -CFArrayRef SOSAccountCopyApplicants(SOSAccountRef account, CFErrorRef *error) { +CFArrayRef SOSAccountCopyApplicants(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) { sosArrayAppendPeerCopy(appendPeersTo, peer); @@ -143,7 +148,7 @@ CFArrayRef SOSAccountCopyApplicants(SOSAccountRef account, CFErrorRef *error) { }); } -CFArrayRef SOSAccountCopyPeers(SOSAccountRef account, CFErrorRef *error) { +CFArrayRef SOSAccountCopyPeers(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { sosArrayAppendPeerCopy(appendPeersTo, peer); @@ -222,7 +227,7 @@ bool SOSAccountDeleteEngineStateFromKeychain(CFErrorRef *error){ } -CFArrayRef SOSAccountCopyActivePeers(SOSAccountRef account, CFErrorRef *error) { +CFArrayRef SOSAccountCopyActivePeers(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { sosArrayAppendPeerCopy(appendPeersTo, peer); @@ -230,40 +235,55 @@ CFArrayRef SOSAccountCopyActivePeers(SOSAccountRef account, CFErrorRef *error) { }); } -CFArrayRef SOSAccountCopyActiveValidPeers(SOSAccountRef account, CFErrorRef *error) { +CFArrayRef SOSAccountCopyActiveValidPeers(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { - SOSCircleForEachActiveValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) { + SOSCircleForEachActiveValidPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) { sosArrayAppendPeerCopy(appendPeersTo, peer); }); }); } -CFArrayRef SOSAccountCopyConcurringPeers(SOSAccountRef account, CFErrorRef *error) +CFArrayRef SOSAccountCopyConcurringPeers(SOSAccount* account, CFErrorRef *error) { return SOSAccountCopySortedPeerArray(account, error, ^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { SOSCircleAppendConcurringPeers(circle, appendPeersTo, NULL); }); } -SOSPeerInfoRef SOSAccountCopyPeerWithID(SOSAccountRef account, CFStringRef peerid, CFErrorRef *error) { - if(!account->trusted_circle) return NULL; - return SOSCircleCopyPeerWithID(account->trusted_circle, peerid, error); +SOSPeerInfoRef SOSAccountCopyPeerWithID(SOSAccount* account, CFStringRef peerid, CFErrorRef *error) { + SOSCircleRef circle = NULL; + + SOSAccountTrustClassic *trust = account.trust; + circle = trust.trustedCircle; + if(!circle) return NULL; + return SOSCircleCopyPeerWithID(circle, peerid, error); } -CFBooleanRef SOSAccountPeersHaveViewsEnabled(SOSAccountRef account, CFArrayRef viewNames, CFErrorRef *error) { +CFBooleanRef SOSAccountPeersHaveViewsEnabled(SOSAccount* account, CFArrayRef viewNames, CFErrorRef *error) { CFBooleanRef result = NULL; CFMutableSetRef viewsRemaining = NULL; CFSetRef viewsToLookFor = NULL; - require_quiet(SOSAccountHasPublicKey(account, error), done); - require_quiet(SOSAccountIsInCircle(account, error), done); + if(!SOSAccountHasPublicKey(account, error)) + { + CFReleaseNull(viewsToLookFor); + CFReleaseNull(viewsRemaining); + + return result; + } + if(![account.trust isInCircle:error]){ + CFReleaseNull(viewsToLookFor); + CFReleaseNull(viewsRemaining); + + return result; + } viewsToLookFor = CFSetCreateCopyOfArrayForCFTypes(viewNames); viewsRemaining = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, viewsToLookFor); CFReleaseNull(viewsToLookFor); SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { - if (SOSPeerInfoApplicationVerify(peer, account->user_public, NULL)) { + if (SOSPeerInfoApplicationVerify(peer, account.accountKey, NULL)) { CFSetRef peerViews = SOSPeerInfoCopyEnabledViews(peer); CFSetSubtract(viewsRemaining, peerViews); CFReleaseNull(peerViews); @@ -272,7 +292,6 @@ CFBooleanRef SOSAccountPeersHaveViewsEnabled(SOSAccountRef account, CFArrayRef v result = CFSetIsEmpty(viewsRemaining) ? kCFBooleanTrue : kCFBooleanFalse; -done: CFReleaseNull(viewsToLookFor); CFReleaseNull(viewsRemaining); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c deleted file mode 100644 index c0b7ea45..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c +++ /dev/null @@ -1,426 +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 -#include -#include -#include -#include "SOSAccountPriv.h" -#include "SOSViews.h" - -#include -#include -#include - -#include -#include - -#include - -#include -#include - - -static SOSAccountRef SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator, - SOSDataSourceFactoryRef factory, - CFErrorRef* error, - const uint8_t** der_p, const uint8_t *der_end) -{ - SOSAccountRef result = NULL; - SOSAccountRef account = NULL; - CFArrayRef array = NULL; - CFDictionaryRef retiredPeers = NULL; - CFStringRef circle_name = factory->copy_name(factory); - - { - CFDictionaryRef decoded_gestalt = NULL; - *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error, - *der_p, der_end); - - if (*der_p == 0) - return NULL; - - account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory); - CFReleaseNull(decoded_gestalt); - } - - *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, der_end); - - uint64_t tmp_departure_code = kSOSNeverAppliedToCircle; - *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end); - *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, der_end); - *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, der_end); - *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->previous_public, error, *der_p, der_end); - *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, der_end); - - *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &retiredPeers, error, *der_p, der_end); - require_action_quiet(*der_p == der_end, fail, *der_p = NULL); - - account->departure_code = (enum DepartureReason) tmp_departure_code; - - CFDictionaryForEach(retiredPeers, ^(const void *key, const void *value) { - if (isData(value)) { - SOSPeerInfoRef retiree = SOSPeerInfoCreateFromData(kCFAllocatorDefault, NULL, (CFDataRef) value); - - CFSetAddValue(account->retirees, retiree); - - CFReleaseNull(retiree); - } - }); - - require_quiet(array && *der_p, fail); - - CFArrayForEach(array, ^(const void *value) { - CFDataRef circleData = NULL; - CFDataRef fullPeerInfoData = NULL; - - if (isData(value)) { - circleData = (CFDataRef) value; - } else if (isArray(value)) { - CFArrayRef pair = (CFArrayRef) value; - - CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0); - CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1); - - if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) { - circleData = (CFDataRef) circleObject; - fullPeerInfoData = (CFDataRef) fullPeerInfoObject; - } - } - - if (circleData) { - SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error); - require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail); - - account->trusted_circle = CFRetainSafe(circle); - - if(fullPeerInfoData) { - account->my_identity = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, NULL); - } - - fail: - CFReleaseNull(circle); - } - }); - CFReleaseNull(array); - - require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail, - SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error)); - - result = CFRetainSafe(account); - -fail: - CFReleaseNull(account); - return result; -} - -static size_t der_sizeof_data_optional(CFDataRef data) -{ - return data ? der_sizeof_data(data, NULL) : 0; - -} - -static uint8_t* der_encode_data_optional(CFDataRef data, CFErrorRef *error, - const uint8_t *der, uint8_t *der_end) -{ - return data ? der_encode_data(data, error, der, der_end) : der_end; - -} - -static const uint8_t* der_decode_data_optional(CFAllocatorRef allocator, CFOptionFlags mutability, - 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); - - return dt_end ? dt_end : der; -} - -static SOSAccountRef SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator, - SOSDataSourceFactoryRef factory, - CFErrorRef* error, - const uint8_t** der_p, const uint8_t *der_end) -{ - SOSAccountRef account = NULL; - SOSAccountRef result = NULL; - - { - CFDictionaryRef decoded_gestalt = NULL; - *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error, - *der_p, der_end); - - if (*der_p == 0) - return NULL; - - account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory); - CFReleaseNull(decoded_gestalt); - } - - account->trusted_circle = SOSCircleCreateFromDER(kCFAllocatorDefault, error, der_p, der_end); - *der_p = der_decode_fullpeer_or_null(kCFAllocatorDefault, &account->my_identity, error, *der_p, der_end); - - uint64_t tmp_departure_code = kSOSNeverAppliedToCircle; - *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end); - *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, der_end); - *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, der_end); - *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->previous_public, error, *der_p, der_end); - *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, der_end); - account->retirees = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, der_p, der_end); - *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &account->backup_key, error, *der_p, der_end); - - account->departure_code = (enum DepartureReason) tmp_departure_code; - - require_action_quiet(*der_p && *der_p == der_end, fail, - SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes v7"), (error != NULL) ? *error : NULL, error)); - - result = CFRetainSafe(account); - -fail: - CFReleaseNull(account); - return result; -} - - -static SOSAccountRef SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator, - SOSDataSourceFactoryRef factory, - CFErrorRef* error, - const uint8_t** der_p, const uint8_t *der_end) -{ - SOSAccountRef account = NULL; - SOSAccountRef result = NULL; - - { - CFDictionaryRef decoded_gestalt = NULL; - *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error, - *der_p, der_end); - - if (*der_p == 0) - return NULL; - - account = SOSAccountCreateBasic(allocator, decoded_gestalt, factory); - CFReleaseNull(decoded_gestalt); - } - CFReleaseNull(account->trusted_circle); - account->trusted_circle = SOSCircleCreateFromDER(kCFAllocatorDefault, error, der_p, der_end); - CFReleaseNull(account->my_identity); - *der_p = der_decode_fullpeer_or_null(kCFAllocatorDefault, &account->my_identity, error, *der_p, der_end); - - uint64_t tmp_departure_code = kSOSNeverAppliedToCircle; - *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end); - *der_p = ccder_decode_bool(&account->user_public_trusted, *der_p, der_end); - *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->user_public, error, *der_p, der_end); - *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &account->previous_public, error, *der_p, der_end); - *der_p = der_decode_data_or_null(kCFAllocatorDefault, &account->user_key_parameters, error, *der_p, der_end); - CFReleaseNull(account->retirees); - account->retirees = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, der_p, der_end); - *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &account->backup_key, error, *der_p, der_end); - { - CFDictionaryRef expansion = NULL; - *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &expansion, error, - *der_p, der_end); - - if (*der_p == 0) - return NULL; - - CFReleaseNull(account->expansion); - account->expansion = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, expansion); - CFReleaseNull(expansion); - } - - account->departure_code = (enum DepartureReason) tmp_departure_code; - - require_action_quiet(*der_p && *der_p == der_end, fail, - SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes v7"), (error != NULL) ? *error : NULL, error)); - - result = CFRetainSafe(account); - -fail: - CFReleaseNull(account); - return result; -} - -// -// Version History for Account -// -// 1-5 - InnsbruckTaos/Cab; Never supported even for upgrading. -// 6 - First version used in the field. -// 7 - One Circle version -// 8 - Adding expansion dictionary -// - -#define CURRENT_ACCOUNT_PERSISTENT_VERSION 8 - -SOSAccountRef SOSAccountCreateFromDER(CFAllocatorRef allocator, - SOSDataSourceFactoryRef factory, - CFErrorRef* error, - const uint8_t** der_p, const uint8_t *der_end) -{ - SOSAccountRef account = NULL; - SOSAccountRef result = NULL; - uint64_t version = 0; - - const uint8_t *sequence_end; - *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end); - *der_p = ccder_decode_uint64(&version, *der_p, sequence_end); - require_action_quiet(*der_p, errOut, - SOSCreateError(kSOSErrorBadFormat, CFSTR("Version parsing failed"), (error != NULL) ? *error : NULL, error)); - - switch (version) { - case CURRENT_ACCOUNT_PERSISTENT_VERSION: - account = SOSAccountCreateFromRemainingDER_v8(allocator, factory, error, der_p, sequence_end); - break; - - case 7: - account = SOSAccountCreateFromRemainingDER_v7(allocator, factory, error, der_p, sequence_end); - break; - - case 6: - account = SOSAccountCreateFromRemainingDER_v6(allocator, factory, error, der_p, sequence_end); - break; - - default: - SOSCreateErrorWithFormat(kSOSErrorBadFormat, (error != NULL) ? *error : NULL, error, - NULL, CFSTR("Unsupported version (%llu)"), version); - break; - } - - require_quiet(account, errOut); - - require_quiet(*der_p && *der_p == sequence_end, errOut); - - /* I may not always have an identity, but when I do, it has a private key */ - if(account->my_identity) { - require_action_quiet(SOSFullPeerInfoPrivKeyExists(account->my_identity), errOut, secnotice("account", "No private key associated with my_identity, resetting")); - notify_post(kSecServerPeerInfoAvailable); - if(account->deviceID) - SOSFullPeerInfoUpdateDeviceID(account->my_identity, account->deviceID, error); - } - - require_action_quiet(SOSAccountEnsureFactoryCircles(account), errOut, - SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error)); - - SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account); - if (myPI) { - SOSAccountCheckForAlwaysOnViews(account); - SOSPeerInfoRef oldPI = myPI; - // if UpdateFullPeerInfo did something - we need to make sure we have the right Ref - myPI = SOSAccountGetMyPeerInfo(account); - if(oldPI != myPI) secnotice("canary", "Caught spot where PIs differ in account setup"); - CFStringRef transportTypeInflatedFromDER = SOSPeerInfoCopyTransportType(myPI); - if (CFStringCompare(transportTypeInflatedFromDER, CFSTR("IDS"), 0) == 0 || CFStringCompare(transportTypeInflatedFromDER, CFSTR("KVS"), 0) == 0) - SOSFullPeerInfoUpdateTransportType(account->my_identity, SOSTransportMessageTypeIDSV2, NULL); //update the transport type to the current IDS V2 type - - CFReleaseNull(transportTypeInflatedFromDER); - } - - SOSAccountEnsureRecoveryRing(account); - - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { - account->key_interests_need_updating = true; - }); - - SOSAccountEnsureUUID(account); - - result = CFRetainSafe(account); - -errOut: - CFReleaseNull(account); - return result; -} - -SOSAccountRef SOSAccountCreateFromData(CFAllocatorRef allocator, CFDataRef circleData, - SOSDataSourceFactoryRef factory, - CFErrorRef* error) -{ - size_t size = CFDataGetLength(circleData); - const uint8_t *der = CFDataGetBytePtr(circleData); - SOSAccountRef account = SOSAccountCreateFromDER(allocator, factory, - error, - &der, der + size); - return account; -} - -CFMutableSetRef SOSPeerInfoSetCreateFromArrayDER(CFAllocatorRef allocator, const CFSetCallBacks *callbacks, CFErrorRef* error, - const uint8_t** der_p, const uint8_t *der_end); -size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia, CFErrorRef *error); -uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pia, CFErrorRef* error, const uint8_t* der, uint8_t* der_end); - -size_t SOSAccountGetDEREncodedSize(SOSAccountRef account, CFErrorRef *error) -{ - size_t sequence_size = 0; - uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION; - - require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(version)), fail); - require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->gestalt, error)), fail); - require_quiet(accumulate_size(&sequence_size, SOSCircleGetDEREncodedSize(account->trusted_circle, error)), fail); - require_quiet(accumulate_size(&sequence_size, der_sizeof_fullpeer_or_null(account->my_identity, error)), fail); - require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(account->departure_code)), fail); - require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account->user_public_trusted, error)), fail); - require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->user_public, error)), fail); - require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account->previous_public, error)), fail); - require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null(account->user_key_parameters, error)), fail); - require_quiet(accumulate_size(&sequence_size, SOSPeerInfoSetGetDEREncodedArraySize(account->retirees, error)), fail); - accumulate_size(&sequence_size, der_sizeof_data_optional(account->backup_key)); - require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary(account->expansion, error)), fail); - - return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size); - -fail: - SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error); - return 0; -} - -uint8_t* SOSAccountEncodeToDER(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) -{ - uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION; - der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, - ccder_encode_uint64(version, der, - der_encode_dictionary(account->gestalt, error, der, - SOSCircleEncodeToDER(account->trusted_circle, error, der, - der_encode_fullpeer_or_null(account->my_identity, error, der, - ccder_encode_uint64(account->departure_code, der, - ccder_encode_bool(account->user_public_trusted, der, - der_encode_public_bytes(account->user_public, error, der, - der_encode_public_bytes(account->previous_public, error, der, - der_encode_data_or_null(account->user_key_parameters, error, der, - SOSPeerInfoSetEncodeToArrayDER(account->retirees, error, der, - der_encode_data_optional(account->backup_key, error, der, - der_encode_dictionary(account->expansion, error, der, - - - der_end))))))))))))); - - return der_end; -} - -/************************/ - -CFDataRef SOSAccountCopyEncodedData(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef *error) -{ - return CFDataCreateWithDER(kCFAllocatorDefault, SOSAccountGetDEREncodedSize(account, error), ^uint8_t*(size_t size, uint8_t *buffer) { - return SOSAccountEncodeToDER(account, error, buffer, (uint8_t *) buffer + size); - }); -} - - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.m new file mode 100644 index 00000000..916c62a5 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.m @@ -0,0 +1,530 @@ +/* + * 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 +#include +#include +#include +#include "SOSViews.h" + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#import +#import +#import +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" + +#define kSecServerPeerInfoAvailable "com.apple.security.fpiAvailable" + +@implementation SOSAccount (Persistence) + + +static SOSAccount* SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator, + SOSDataSourceFactoryRef factory, + CFErrorRef* error, + const uint8_t** der_p, const uint8_t *der_end) +{ + SOSAccount* result = NULL; + SOSAccount* account = NULL; + + CFArrayRef array = NULL; + CFDictionaryRef retiredPeers = NULL; + + CFStringRef circle_name = factory->copy_name(factory); + + { + CFDictionaryRef decoded_gestalt = NULL; + *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error, + *der_p, der_end); + + if (*der_p == 0) + return NULL; + + account = SOSAccountCreate(allocator, decoded_gestalt, factory); + + CFReleaseNull(decoded_gestalt); + } + SOSAccountTrustClassic *trust = account.trust; + + *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, der_end); + + uint64_t tmp_departure_code = kSOSNeverAppliedToCircle; + *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end); + [trust setDepartureCode:(enum DepartureReason)tmp_departure_code]; + + bool userPublicTrusted; + *der_p = ccder_decode_bool(&userPublicTrusted, *der_p, der_end); + account.accountKeyIsTrusted = userPublicTrusted; + + SecKeyRef userPublic = NULL; + SecKeyRef previousUserPublic = NULL; + *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &userPublic, error, *der_p, der_end); + *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &previousUserPublic, error, *der_p, der_end); + account.accountKey = userPublic; + account.previousAccountKey = previousUserPublic; + CFReleaseNull(userPublic); + CFReleaseNull(previousUserPublic); + + { + CFDataRef parms = NULL; + *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end); + [account setAccountKeyDerivationParamters:(__bridge_transfer NSData*) parms]; + } + + *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &retiredPeers, error, *der_p, der_end); + + if(*der_p != der_end) { + *der_p = NULL; + return result; + } + + { + CFMutableSetRef retirees = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + + CFDictionaryForEach(retiredPeers, ^(const void *key, const void *value) { + if (isData(value)) { + SOSPeerInfoRef retiree = SOSPeerInfoCreateFromData(kCFAllocatorDefault, NULL, (CFDataRef) value); + + CFSetAddValue(retirees, retiree); + + CFReleaseNull(retiree); + } + }); + + [trust setRetirees:(__bridge NSMutableSet *)retirees]; + CFReleaseNull(retirees); + } + + if(!array || !*der_p) + return result; + + CFArrayForEach(array, ^(const void *value) { + CFDataRef circleData = NULL; + CFDataRef fullPeerInfoData = NULL; + + if (isData(value)) { + circleData = (CFDataRef) value; + } else if (isArray(value)) { + CFArrayRef pair = (CFArrayRef) value; + + CFTypeRef circleObject = CFArrayGetValueAtIndex(pair, 0); + CFTypeRef fullPeerInfoObject = CFArrayGetValueAtIndex(pair, 1); + + if (CFArrayGetCount(pair) == 2 && isData(circleObject) && isData(fullPeerInfoObject)) { + circleData = (CFDataRef) circleObject; + fullPeerInfoData = (CFDataRef) fullPeerInfoObject; + } + } + + if (circleData) { + SOSCircleRef circle = SOSCircleCreateFromData(kCFAllocatorDefault, circleData, error); + require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail); + [trust setTrustedCircle:circle]; + CFReleaseNull(circle); + + if(fullPeerInfoData) { + SOSFullPeerInfoRef identity = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, NULL); + trust.fullPeerInfo = identity; + CFReleaseNull(identity); + } + + fail: + CFReleaseNull(circle); + } + }); + CFReleaseNull(array); + require_action_quiet([account ensureFactoryCircles], fail, + SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error)); + result = account; + +fail: + + return result; +} + +static const uint8_t* der_decode_data_optional(CFAllocatorRef allocator, CFOptionFlags mutability, + 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); + + return dt_end ? dt_end : der; +} + +static SOSAccount* SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator, + SOSDataSourceFactoryRef factory, + CFErrorRef* error, + const uint8_t** der_p, const uint8_t *der_end) +{ + SOSAccount* account = NULL; + SOSAccount* result = NULL; + + { + CFDictionaryRef decoded_gestalt = NULL; + *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error, + *der_p, der_end); + + if (*der_p == 0) + return NULL; + + account = SOSAccountCreate(kCFAllocatorDefault, decoded_gestalt, factory); + CFReleaseNull(decoded_gestalt); + } + + enum DepartureReason departure_code = 0; + SOSAccountTrustClassic *trust = account.trust; + + { + SOSCircleRef circle = SOSCircleCreateFromDER(kCFAllocatorDefault, error, der_p, der_end); + [trust setTrustedCircle:circle]; + CFReleaseNull(circle); + } + + { + SOSFullPeerInfoRef identity = NULL; + *der_p = der_decode_fullpeer_or_null(kCFAllocatorDefault, &identity, error, *der_p, der_end); + trust.fullPeerInfo = identity; + CFReleaseNull(identity); + } + + uint64_t tmp_departure_code = kSOSNeverAppliedToCircle; + *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end); + bool userPublicTrusted; + + *der_p = ccder_decode_bool(&userPublicTrusted, *der_p, der_end); + account.accountKeyIsTrusted = userPublicTrusted; + + { + SecKeyRef userPublic = NULL; + *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &userPublic, error, *der_p, der_end); + account.accountKey = userPublic; + CFReleaseNull(userPublic); + } + + { + SecKeyRef previousUserPublic = NULL; + *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &previousUserPublic, error, *der_p, der_end); + account.previousAccountKey = previousUserPublic; + CFReleaseNull(previousUserPublic); + } + + { + CFDataRef parms = NULL; + *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end); + account.accountKeyDerivationParamters = (__bridge_transfer NSData*)parms; + } + + { + CFSetRef retirees = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, der_p, der_end); + [trust setRetirees:(__bridge NSMutableSet *)retirees]; + } + + { + CFDataRef bKey = NULL; + *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &bKey, error, *der_p, der_end); + if(bKey != NULL) + [account setBackup_key:(__bridge_transfer NSData *)bKey]; + } + + departure_code = (enum DepartureReason) tmp_departure_code; + + [trust setDepartureCode:departure_code]; + require_action_quiet(*der_p && *der_p == der_end, fail, + SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes v7"), (error != NULL) ? *error : NULL, error)); + + result = account; + +fail: + return result; +} + + +static SOSAccount* SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator, + SOSDataSourceFactoryRef factory, + CFErrorRef* error, + const uint8_t** der_p, const uint8_t *der_end) +{ + SOSAccount* account = NULL; + SOSAccount* result = NULL; + + { + CFDictionaryRef decoded_gestalt = NULL; + *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error, + *der_p, der_end); + + if (*der_p == 0) { + CFReleaseNull(decoded_gestalt); + return NULL; + } + + account = SOSAccountCreate(kCFAllocatorDefault, decoded_gestalt, factory); + CFReleaseNull(decoded_gestalt); + } + + SOSAccountTrustClassic *trust = account.trust; + + { + SOSCircleRef circle = SOSCircleCreateFromDER(kCFAllocatorDefault, error, der_p, der_end); + [trust setTrustedCircle:circle]; + CFReleaseNull(circle); + } + + { + SOSFullPeerInfoRef identity = NULL; + *der_p = der_decode_fullpeer_or_null(kCFAllocatorDefault, &identity, error, *der_p, der_end); + trust.fullPeerInfo = identity; + CFReleaseNull(identity); + } + + uint64_t tmp_departure_code = kSOSNeverAppliedToCircle; + *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end); + [trust setDepartureCode:(enum DepartureReason) tmp_departure_code]; + + bool userPublicTrusted; + *der_p = ccder_decode_bool(&userPublicTrusted, *der_p, der_end); + account.accountKeyIsTrusted = userPublicTrusted; + + { + SecKeyRef userPublic = NULL; + *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &userPublic, error, *der_p, der_end); + account.accountKey = userPublic; + CFReleaseNull(userPublic); + } + + { + SecKeyRef previousUserPublic = NULL; + *der_p = der_decode_public_bytes(kCFAllocatorDefault, kSecECDSAAlgorithmID, &previousUserPublic, error, *der_p, der_end); + account.previousAccountKey = previousUserPublic; + CFReleaseNull(previousUserPublic); + } + + { + CFDataRef parms; + *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end); + account.accountKeyDerivationParamters = (__bridge_transfer NSData*)parms; + parms = NULL; + } + + { + CFMutableSetRef retirees = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error, der_p, der_end); + [trust setRetirees:(__bridge NSMutableSet *)retirees]; + CFReleaseNull(retirees); + } + + CFDataRef bKey = NULL; + *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &bKey, error, *der_p, der_end); + { + CFDictionaryRef expansion = NULL; + *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &expansion, error, + *der_p, der_end); + + if (*der_p == 0) { + CFReleaseNull(expansion); + return NULL; + } + + if(expansion) { + [trust setExpansion:(__bridge NSMutableDictionary *)(expansion)]; + } + CFReleaseNull(expansion); + } + if(bKey != NULL) + [account setBackup_key:[[NSData alloc] initWithData:(__bridge NSData * _Nonnull)(bKey)]]; + + require_action_quiet(*der_p && *der_p == der_end, fail, + SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes v7"), (error != NULL) ? *error : NULL, error)); + + result = account; + +fail: + return result; +} + +// +// Version History for Account +// +// 1-5 - InnsbruckTaos/Cab; Never supported even for upgrading. +// 6 - First version used in the field. +// 7 - One Circle version +// 8 - Adding expansion dictionary +// + +#define CURRENT_ACCOUNT_PERSISTENT_VERSION 8 + +static SOSAccount* SOSAccountCreateFromDER(CFAllocatorRef allocator, + SOSDataSourceFactoryRef factory, + CFErrorRef* error, + const uint8_t** der_p, const uint8_t *der_end) +{ + SOSAccount* account = NULL; + uint64_t version = 0; + + SOSFullPeerInfoRef identity = NULL; + + const uint8_t *sequence_end; + *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end); + *der_p = ccder_decode_uint64(&version, *der_p, sequence_end); + if (*der_p == NULL) { + SOSCreateError(kSOSErrorBadFormat, CFSTR("Version parsing failed"), (error != NULL) ? *error : NULL, error); + return nil; + } + + switch (version) { + case CURRENT_ACCOUNT_PERSISTENT_VERSION: + account = SOSAccountCreateFromRemainingDER_v8(allocator, factory, error, der_p, sequence_end); + break; + + case 7: + account = SOSAccountCreateFromRemainingDER_v7(allocator, factory, error, der_p, sequence_end); + break; + + case 6: + account = SOSAccountCreateFromRemainingDER_v6(allocator, factory, error, der_p, sequence_end); + break; + + default: + SOSCreateErrorWithFormat(kSOSErrorBadFormat, (error != NULL) ? *error : NULL, error, + NULL, CFSTR("Unsupported version (%llu)"), version); + break; + } + + if (!account) { + // Error should have been filled in above. + return nil; + } + + if (*der_p != sequence_end) { + SOSCreateError(kSOSErrorBadFormat, CFSTR("Extra data at the end of saved acount"), (error != NULL) ? *error : NULL, error); + return nil; + } + + identity = account.fullPeerInfo; + /* I may not always have an identity, but when I do, it has a private key */ + if(identity) { + if(!(SOSFullPeerInfoPrivKeyExists(identity))) + { + SOSUnregisterTransportKeyParameter(account.key_transport); + SOSUnregisterTransportCircle((SOSCircleStorageTransport*)account.circle_transport); + SOSUnregisterTransportMessage((SOSMessage*)account.ids_message_transport); + SOSUnregisterTransportMessage(account.kvs_message_transport); + + secnotice("account", "No private key associated with my_identity, resetting"); + return nil; + } + notify_post(kSecServerPeerInfoAvailable); + if(account.deviceID && [account.deviceID length] != 0){ + SOSFullPeerInfoUpdateDeviceID(identity, (__bridge CFStringRef)(account.deviceID), error); + account.trust.fullPeerInfo = identity; + } + } + + if (![account ensureFactoryCircles]) { + SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error); + return nil; + } + + SOSPeerInfoRef oldPI = CFRetainSafe(account.peerInfo); + if (oldPI) { + SOSAccountCheckForAlwaysOnViews(account); + // if UpdateFullPeerInfo did something - we need to make sure we have the right Ref + SOSPeerInfoRef myPI = account.peerInfo; + CFStringRef transportTypeInflatedFromDER = SOSPeerInfoCopyTransportType(myPI); + if (CFStringCompare(transportTypeInflatedFromDER, CFSTR("IDS"), 0) == 0 || CFStringCompare(transportTypeInflatedFromDER, CFSTR("KVS"), 0) == 0) + SOSFullPeerInfoUpdateTransportType(identity, SOSTransportMessageTypeIDSV2, NULL); //update the transport type to the current IDS V2 type + + CFReleaseNull(transportTypeInflatedFromDER); + } + CFReleaseNull(oldPI); + + SOSAccountEnsureRecoveryRing(account); + + [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + account.key_interests_need_updating = true; + }]; + + SOSAccountEnsureUUID(account); + + return account; +} + ++(instancetype) accountFromDER: (const uint8_t**) der + end: (const uint8_t*) der_end + factory: (SOSDataSourceFactoryRef) factory + error: (NSError**) error { + CFErrorRef failure = NULL; + SOSAccount* result = SOSAccountCreateFromDER(kCFAllocatorDefault, factory, &failure, der, der_end); + + if (result == nil) { + if (error) { + *error = (__bridge_transfer NSError*) failure; + failure = NULL; + } + } + CFReleaseNull(failure); + + return result; +} + ++(instancetype) accountFromData: (NSData*) data + factory: (SOSDataSourceFactoryRef) factory + error: (NSError**) error { + size_t size = [data length]; + const uint8_t *der = [data bytes]; + return [self accountFromDER: &der end: der+size factory: factory error: error]; +} + +CFMutableSetRef SOSPeerInfoSetCreateFromArrayDER(CFAllocatorRef allocator, const CFSetCallBacks *callbacks, CFErrorRef* error, + const uint8_t** der_p, const uint8_t *der_end); +size_t SOSPeerInfoSetGetDEREncodedArraySize(CFSetRef pia, CFErrorRef *error); +uint8_t* SOSPeerInfoSetEncodeToArrayDER(CFSetRef pia, CFErrorRef* error, const uint8_t* der, uint8_t* der_end); + +/************************/ + + +- (NSData*) encodedData: (NSError* __autoreleasing *) error { + NSUInteger expected = [self.trust getDEREncodedSize: self err:error]; + if (expected == 0) return nil; + + return [NSMutableData dataWithSpace:expected + DEREncode:^uint8_t *(size_t size, uint8_t *buffer) { + return [self.trust encodeToDER:self + err:error + start:buffer + end:buffer + size]; + }]; +} + +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPriv.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPriv.h index 9cff709c..7791a59d 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPriv.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountPriv.h @@ -1,12 +1,12 @@ // // SOSAccountPriv.h -// sec +// Security // -#ifndef sec_SOSAccountPriv_h -#define sec_SOSAccountPriv_h +#ifndef SOSAccountPriv_h +#define SOSAccountPriv_h -#include "SOSAccount.h" +#import #include #include @@ -14,7 +14,6 @@ #include #include - #include #include @@ -27,6 +26,7 @@ #import #include + #include #include #include @@ -39,138 +39,138 @@ #include #include #include -#include +#include + #include #include -extern const CFStringRef kSOSRecoveryRing; -struct __OpaqueSOSAccount { - CFRuntimeBase _base; - - CFDictionaryRef gestalt; - - CFDataRef backup_key; - - SOSFullPeerInfoRef my_identity; - SOSCircleRef trusted_circle; - - CFStringRef deviceID; - - CFMutableDictionaryRef backups; - - CFMutableSetRef retirees; - - bool user_public_trusted; - CFDataRef user_key_parameters; - SecKeyRef user_public; - SecKeyRef previous_public; - enum DepartureReason departure_code; - CFMutableDictionaryRef expansion; // All CFTypes and Keys - - // Non-persistent data - dispatch_queue_t queue; - - SOSDataSourceFactoryRef factory; - SecKeyRef _user_private; - CFDataRef _password_tmp; - - bool isListeningForSync; - - dispatch_source_t user_private_timer; - int lock_notification_token; - - SOSTransportKeyParameterRef key_transport; - SOSTransportCircleRef circle_transport; - SOSTransportMessageRef kvs_message_transport; - SOSTransportMessageRef ids_message_transport; - - //indicates if changes in circle, rings, or retirements need to be pushed - bool circle_rings_retirements_need_attention; - bool engine_peer_state_needs_repair; - bool key_interests_need_updating; - - // Live Notification - CFMutableArrayRef change_blocks; - CFMutableDictionaryRef waitForInitialSync_blocks; - - SOSAccountSaveBlock saveBlock; -}; +extern const CFStringRef kSOSUnsyncedViewsKey; +extern const CFStringRef kSOSPendingEnableViewsToBeSetKey; +extern const CFStringRef kSOSPendingDisableViewsToBeSetKey; +extern const CFStringRef kSOSRecoveryKey; +extern const CFStringRef kSOSAccountUUID; +extern const CFStringRef kSOSAccountPeerNegotiationTimeouts; +extern const CFStringRef kSOSRecoveryRing; extern const CFStringRef kSOSEscrowRecord; extern const CFStringRef kSOSTestV2Settings; +extern const CFStringRef kSOSRateLimitingCounters; +extern const CFStringRef kSOSAccountPeerLastSentTimestamp; +extern const CFStringRef kSOSAccountRenegotiationRetryCount; +extern const CFStringRef kOTRConfigVersion; +extern const CFStringRef kSOSInitialSyncTimeoutV0; -SOSAccountRef SOSAccountCreateBasic(CFAllocatorRef allocator, - CFDictionaryRef gestalt, - SOSDataSourceFactoryRef factory); +#define kSecServerPeerInfoAvailable "com.apple.security.fpiAvailable" -bool SOSAccountEnsureFactoryCircles(SOSAccountRef a); +typedef void (^SOSAccountSaveBlock)(CFDataRef flattenedAccount, CFErrorRef flattenFailError); -void SOSAccountSetToNew(SOSAccountRef a); +@class SOSMessageIDS; +@class SOSMessageKVS; +@class CKKeyParameter; +@class SOSAccountTrustClassic; +@class SOSKVSCircleStorageTransport; +@class SOSCircleStorageTransport; +@class SOSCKCircleStorage; -bool SOSAccountIsMyPeerActive(SOSAccountRef account, CFErrorRef* error); +@interface SOSAccount : NSObject -// MARK: Notifications +@property (nonatomic, retain) NSDictionary *gestalt; +@property (nonatomic, retain) NSData *backup_key; +@property (nonatomic, retain) NSString *deviceID; -#define kSecServerPeerInfoAvailable "com.apple.security.fpiAvailable" +@property (nonatomic, retain) SOSAccountTrustClassic *trust; +@property (nonatomic, retain) dispatch_queue_t queue; +@property (nonatomic, retain) dispatch_source_t user_private_timer; +@property (nonatomic) SecKeyRef accountPrivateKey; -// MARK: Getters and Setters +@property (nonatomic) SOSDataSourceFactoryRef factory; -// UUID, no setter just getter and ensuring value. -void SOSAccountEnsureUUID(SOSAccountRef account); -CFStringRef SOSAccountCopyUUID(SOSAccountRef account); +@property (nonatomic, retain) NSData *_password_tmp; +@property (nonatomic, assign) BOOL isListeningForSync; +@property (nonatomic, assign) int lock_notification_token; +@property (nonatomic, retain) CKKeyParameter* key_transport; +@property (nonatomic) SOSKVSCircleStorageTransport* circle_transport; +@property (nonatomic, retain) SOSMessageKVS* kvs_message_transport; +@property (nonatomic, retain) SOSMessageIDS* ids_message_transport; +@property (nonatomic, retain) SOSCKCircleStorage* ck_storage; -// MARK: Transactional +@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; -void SOSAccountWithTransaction_Locked(SOSAccountRef account, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)); +@property (nonatomic, retain) NSMutableArray *change_blocks; -void SOSAccountWithTransaction(SOSAccountRef account, bool sync, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)); -void SOSAccountWithTransactionSync(SOSAccountRef account, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)); -void SOSAccountWithTransactionAsync(SOSAccountRef account, bool sync, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)); +@property (nonatomic, retain) NSMutableDictionary *waitForInitialSync_blocks; +@property (nonatomic, assign) BOOL isInitialSyncing; -void SOSAccountRecordRetiredPeersInCircle(SOSAccountRef account); +@property (nonatomic) NSData* accountKeyDerivationParamters; -// MARK: In Sync checking +@property (nonatomic, assign) BOOL accountKeyIsTrusted; +@property (nonatomic) SecKeyRef accountKey; +@property (nonatomic) SecKeyRef previousAccountKey; -CF_RETURNS_RETAINED CFStringRef SOSAccountCallWhenInSync(SOSAccountRef account, SOSAccountWaitForInitialSyncBlock syncBlock); -bool SOSAccountUnregisterCallWhenInSync(SOSAccountRef account, CFStringRef id); +@property (copy) SOSAccountSaveBlock saveBlock; -bool SOSAccountHandleOutOfSyncUpdate(SOSAccountRef account, CFSetRef oldOOSViews, CFSetRef newOOSViews); -void SOSAccountUpdateOutOfSyncViews(SOSAccountTransactionRef aTxn, CFSetRef viewsInSync); +// Identity access properties, all delegated to the trust object +@property (readonly, nonatomic) BOOL hasPeerInfo; +@property (readonly, nonatomic) SOSPeerInfoRef peerInfo; +@property (readonly, nonatomic) SOSFullPeerInfoRef fullPeerInfo; +@property (readonly, nonatomic) NSString* peerID; -void SOSAccountEnsureSyncChecking(SOSAccountRef account); -void SOSAccountCancelSyncChecking(SOSAccountRef account); -bool SOSAccountCheckForAlwaysOnViews(SOSAccountRef account); +-(id) init; +-(id) initWithGestalt:(CFDictionaryRef)gestalt factory:(SOSDataSourceFactoryRef)factory; +- (xpc_endpoint_t)xpcControlEndpoint; -CFMutableSetRef SOSAccountCopyOutstandingViews(SOSAccountRef account); -CFMutableSetRef SOSAccountCopyIntersectionWithOustanding(SOSAccountRef account, CFSetRef inSet); -bool SOSAccountIntersectsWithOutstanding(SOSAccountRef account, CFSetRef views); -bool SOSAccountIsViewOutstanding(SOSAccountRef account, CFStringRef view); -bool SOSAccountHasOustandingViews(SOSAccountRef account); +void SOSAccountAddSyncablePeerBlock(SOSAccount* a, + CFStringRef ds_name, + SOSAccountSyncablePeersBlock changeBlock); +-(bool) ensureFactoryCircles; -// MARK: DER Stuff +-(void) flattenToSaveBlock; +void SOSAccountSetToNew(SOSAccount* a); + +bool SOSAccountIsMyPeerActive(SOSAccount* account, CFErrorRef* error); + +// MARK: In Sync checking +typedef bool (^SOSAccountWaitForInitialSyncBlock)(SOSAccount* account); -size_t der_sizeof_data_or_null(CFDataRef data, CFErrorRef* error); +CF_RETURNS_RETAINED CFStringRef SOSAccountCallWhenInSync(SOSAccount* account, SOSAccountWaitForInitialSyncBlock syncBlock); +bool SOSAccountUnregisterCallWhenInSync(SOSAccount* account, CFStringRef id); -uint8_t* der_encode_data_or_null(CFDataRef data, CFErrorRef* error, const uint8_t* der, uint8_t* der_end); +bool SOSAccountHandleOutOfSyncUpdate(SOSAccount* account, CFSetRef oldOOSViews, CFSetRef newOOSViews); + +void SOSAccountEnsureSyncChecking(SOSAccount* account); +void SOSAccountCancelSyncChecking(SOSAccount* account); + +CFMutableSetRef SOSAccountCopyOutstandingViews(SOSAccount* account); +void SOSAccountNotifyEngines(SOSAccount* account); +CFMutableSetRef SOSAccountCopyOutstandingViews(SOSAccount* account); +bool SOSAccountIsViewOutstanding(SOSAccount* account, CFStringRef view); +CFMutableSetRef SOSAccountCopyIntersectionWithOustanding(SOSAccount* account, CFSetRef inSet); +bool SOSAccountIntersectsWithOutstanding(SOSAccount* account, CFSetRef views); +bool SOSAccountHasOustandingViews(SOSAccount* account); +bool SOSAccountHasCompletedInitialSync(SOSAccount* account); +bool SOSAccountHasCompletedRequiredBackupSync(SOSAccount* account); +CFMutableSetRef SOSAccountCopyOutstandingViews(SOSAccount* account); +bool SOSAccountSyncingV0(SOSAccount* account); + +// MARK: DER Stuff -const uint8_t* der_decode_data_or_null(CFAllocatorRef allocator, CFDataRef* data, - CFErrorRef* error, - const uint8_t* der, const uint8_t* der_end); size_t der_sizeof_fullpeer_or_null(SOSFullPeerInfoRef data, CFErrorRef* error); uint8_t* der_encode_fullpeer_or_null(SOSFullPeerInfoRef data, CFErrorRef* error, const uint8_t* der, uint8_t* der_end); const uint8_t* der_decode_fullpeer_or_null(CFAllocatorRef allocator, SOSFullPeerInfoRef* data, - CFErrorRef* error, - const uint8_t* der, const uint8_t* der_end); + CFErrorRef* error, + const uint8_t* der, const uint8_t* der_end); size_t der_sizeof_public_bytes(SecKeyRef publicKey, CFErrorRef* error); @@ -180,67 +180,41 @@ uint8_t* der_encode_public_bytes(SecKeyRef publicKey, CFErrorRef* error, const u const uint8_t* der_decode_public_bytes(CFAllocatorRef allocator, CFIndex algorithmID, SecKeyRef* publicKey, CFErrorRef* error, const uint8_t* der, const uint8_t* der_end); -// Persistence - -SOSAccountRef SOSAccountCreateFromDER(CFAllocatorRef allocator, - SOSDataSourceFactoryRef factory, - CFErrorRef* error, - const uint8_t** der_p, const uint8_t *der_end); - -SOSAccountRef SOSAccountCreateFromData(CFAllocatorRef allocator, CFDataRef circleData, - SOSDataSourceFactoryRef factory, - CFErrorRef* error); - -size_t SOSAccountGetDEREncodedSize(SOSAccountRef account, CFErrorRef *error); - -uint8_t* SOSAccountEncodeToDER(SOSAccountRef account, CFErrorRef* error, const uint8_t* der, uint8_t* der_end); - -CFDataRef SOSAccountCopyEncodedData(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef *error); - // Update +-(SOSCCStatus) getCircleStatus:(CFErrorRef*) error; -bool SOSAccountHandleCircleMessage(SOSAccountRef account, +bool SOSAccountHandleCircleMessage(SOSAccount* account, CFStringRef circleName, CFDataRef encodedCircleMessage, CFErrorRef *error); CF_RETURNS_RETAINED -CFDictionaryRef SOSAccountHandleRetirementMessages(SOSAccountRef account, CFDictionaryRef circle_retirement_messages, CFErrorRef *error); +CFDictionaryRef SOSAccountHandleRetirementMessages(SOSAccount* account, CFDictionaryRef circle_retirement_messages, CFErrorRef *error); +void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account); -bool SOSAccountHandleUpdateCircle(SOSAccountRef account, +bool SOSAccountHandleUpdateCircle(SOSAccount* account, SOSCircleRef prospective_circle, bool writeUpdate, CFErrorRef *error); -void SOSAccountNotifyEngines(SOSAccountRef account); - -bool SOSAccountSyncingV0(SOSAccountRef account); // My Peer -bool SOSAccountHasFullPeerInfo(SOSAccountRef account, CFErrorRef* error); -SOSPeerInfoRef SOSAccountGetMyPeerInfo(SOSAccountRef account); -SOSFullPeerInfoRef SOSAccountGetMyFullPeerInfo(SOSAccountRef account); -CFStringRef SOSAccountGetMyPeerID(SOSAccountRef a); -bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccountRef account, CFStringRef viewname); -bool SOSAccountUpdateOurPeerInBackup(SOSAccountRef account, SOSRingRef oldRing, CFErrorRef *error); -bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccountRef account, SOSPeerInfoRef testPeer, CFStringRef viewname); +bool SOSAccountHasFullPeerInfo(SOSAccount* account, CFErrorRef* error); + +bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccount* account, CFStringRef viewname); +bool SOSAccountUpdateOurPeerInBackup(SOSAccount* account, SOSRingRef oldRing, CFErrorRef *error); +bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccount* account, SOSPeerInfoRef testPeer, CFStringRef viewname); bool SOSDeleteV0Keybag(CFErrorRef *error); -void SOSAccountForEachBackupView(SOSAccountRef account, void (^operation)(const void *value)); -bool SOSAccountUpdatePeerInfo(SOSAccountRef account, CFStringRef updateDescription, CFErrorRef *error, bool (^update)(SOSFullPeerInfoRef fpi, CFErrorRef *error)); +void SOSAccountForEachBackupView(SOSAccount* account, void (^operation)(const void *value)); +bool SOSAccountUpdatePeerInfo(SOSAccount* account, CFStringRef updateDescription, CFErrorRef *error, bool (^update)(SOSFullPeerInfoRef fpi, CFErrorRef *error)); +CFStringRef SOSAccountCreateCompactDescription(SOSAccount* a); // Currently permitted backup rings. -void SOSAccountForEachRingName(SOSAccountRef account, void (^operation)(CFStringRef value)); +void SOSAccountForEachBackupRingName(SOSAccount* account, void (^operation)(CFStringRef value)); +void SOSAccountForEachRingName(SOSAccount* account, void (^operation)(CFStringRef value)); // My Circle -bool SOSAccountHasCircle(SOSAccountRef account, CFErrorRef* error); -SOSCircleRef SOSAccountGetCircle(SOSAccountRef a, CFErrorRef *error); -SOSCircleRef SOSAccountEnsureCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error); - -bool SOSAccountUpdateCircleFromRemote(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error); -bool SOSAccountUpdateCircle(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error); -bool SOSAccountModifyCircle(SOSAccountRef account, - CFErrorRef* error, - bool (^action)(SOSCircleRef circle)); -CFSetRef SOSAccountCopyPeerSetMatching(SOSAccountRef account, bool (^action)(SOSPeerInfoRef peer)); +bool SOSAccountHasCircle(SOSAccount* account, CFErrorRef* error); +SOSCircleRef SOSAccountEnsureCircle(SOSAccount* a, CFStringRef name, CFErrorRef *error); void AppendCircleKeyName(CFMutableArrayRef array, CFStringRef name); @@ -250,89 +224,45 @@ CFStringRef SOSInterestListCopyDescription(CFArrayRef interests); // FullPeerInfos - including Cloud Identity SOSFullPeerInfoRef CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer, CFErrorRef *error); -SecKeyRef GeneratePermanentFullECKey(int keySize, CFStringRef name, CFErrorRef* error); - -bool SOSAccountEnsureFullPeerAvailable(SOSAccountRef account, CFErrorRef * error); - -bool SOSAccountIsAccountIdentity(SOSAccountRef account, SOSPeerInfoRef peer_info, CFErrorRef *error); -bool SOSAccountFullPeerInfoVerify(SOSAccountRef account, SecKeyRef privKey, CFErrorRef *error); +bool SOSAccountIsAccountIdentity(SOSAccount* account, SOSPeerInfoRef peer_info, CFErrorRef *error); +bool SOSAccountFullPeerInfoVerify(SOSAccount* account, SecKeyRef privKey, CFErrorRef *error); SOSPeerInfoRef GenerateNewCloudIdentityPeerInfo(CFErrorRef *error); // Credentials -bool SOSAccountHasPublicKey(SOSAccountRef account, CFErrorRef* error); -void SOSAccountSetPreviousPublic(SOSAccountRef account); -bool SOSAccountPublishCloudParameters(SOSAccountRef account, CFErrorRef* error); -bool SOSAccountRetrieveCloudParameters(SOSAccountRef account, SecKeyRef *newKey, +bool SOSAccountHasPublicKey(SOSAccount* account, CFErrorRef* error); +bool SOSAccountPublishCloudParameters(SOSAccount* account, CFErrorRef* error); +bool SOSAccountRetrieveCloudParameters(SOSAccount* account, SecKeyRef *newKey, CFDataRef derparms, CFDataRef *newParameters, CFErrorRef* error); //DSID -void SOSAccountAssertDSID(SOSAccountRef account, CFStringRef dsid); +void SOSAccountAssertDSID(SOSAccount* account, CFStringRef dsid); // // Key extraction // -SecKeyRef SOSAccountCopyDeviceKey(SOSAccountRef account, CFErrorRef *error); -SecKeyRef SOSAccountCopyPublicKeyForPeer(SOSAccountRef account, CFStringRef peer_id, CFErrorRef *error); +SecKeyRef SOSAccountCopyDeviceKey(SOSAccount* account, CFErrorRef *error); +SecKeyRef GeneratePermanentFullECKey(int keySize, CFStringRef name, CFErrorRef* error); // Testing -void SOSAccountSetLastDepartureReason(SOSAccountRef account, enum DepartureReason reason); -void SOSAccountSetUserPublicTrustedForTesting(SOSAccountRef account); -void SOSAccountPeerGotInSync(SOSAccountTransactionRef aTxn, CFStringRef peerID, CFSetRef views); - -static inline void CFArrayAppendValueIfNot(CFMutableArrayRef array, CFTypeRef value, CFTypeRef excludedValue) -{ - if (!CFEqualSafe(value, excludedValue)) - CFArrayAppendValue(array, value); -} - -static inline CFMutableDictionaryRef CFDictionaryEnsureCFDictionaryAndGetCurrentValue(CFMutableDictionaryRef dict, CFTypeRef key) -{ - CFMutableDictionaryRef result = (CFMutableDictionaryRef) CFDictionaryGetValue(dict, key); - - if (!isDictionary(result)) { - result = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionarySetValue(dict, key, result); - CFReleaseSafe(result); - } - - return result; -} - -static inline CFMutableArrayRef CFDictionaryEnsureCFArrayAndGetCurrentValue(CFMutableDictionaryRef dict, CFTypeRef key) -{ - CFMutableArrayRef result = (CFMutableArrayRef) CFDictionaryGetValue(dict, key); - - if (!isArray(result)) { - result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionarySetValue(dict, key, result); - CFReleaseSafe(result); - } - - return result; -} - -void SOSAccountPurgeIdentity(SOSAccountRef account); -bool sosAccountLeaveCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error); -bool sosAccountLeaveRing(SOSAccountRef account, SOSRingRef ring, CFErrorRef* error); -void SOSAccountAddRingDictionary(SOSAccountRef a); -bool SOSAccountForEachRing(SOSAccountRef account, SOSRingRef (^action)(CFStringRef name, SOSRingRef ring)); -CFMutableDictionaryRef SOSAccountGetBackups(SOSAccountRef a, CFErrorRef *error); -bool SOSAccountUpdateBackUp(SOSAccountRef account, CFStringRef viewname, CFErrorRef *error); -bool SOSAccountEnsureInBackupRings(SOSAccountRef account); - -bool SOSAccountEnsurePeerRegistration(SOSAccountRef account, CFErrorRef *error); - -extern const CFStringRef kSOSDSIDKey; -extern const CFStringRef SOSTransportMessageTypeIDSV2; -extern const CFStringRef SOSTransportMessageTypeKVS; +void SOSAccountSetLastDepartureReason(SOSAccount* account, enum DepartureReason reason); +void SOSAccountSetUserPublicTrustedForTesting(SOSAccount* account); + +void SOSAccountPurgeIdentity(SOSAccount*); +bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, CFErrorRef* error); +bool sosAccountLeaveRing(SOSAccount* account, SOSRingRef ring, 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); extern const CFStringRef kSOSUnsyncedViewsKey; extern const CFStringRef kSOSPendingEnableViewsToBeSetKey; extern const CFStringRef kSOSPendingDisableViewsToBeSetKey; extern const CFStringRef kSOSRecoveryKey; -extern const CFStringRef kSOSAccountUUID; typedef enum{ kSOSTransportNone = 0, @@ -342,40 +272,23 @@ typedef enum{ kSOSTransportPresent = 4 }TransportType; -SOSPeerInfoRef SOSAccountCopyPeerWithID(SOSAccountRef account, CFStringRef peerid, CFErrorRef *error); - -// MARK: Value setting/clearing -bool SOSAccountSetValue(SOSAccountRef account, CFStringRef key, CFTypeRef value, CFErrorRef *error); -bool SOSAccountClearValue(SOSAccountRef account, CFStringRef key, CFErrorRef *error); -CFTypeRef SOSAccountGetValue(SOSAccountRef account, CFStringRef key, CFErrorRef *error); - -// MARK: Value as Set -bool SOSAccountValueSetContainsValue(SOSAccountRef account, CFStringRef key, CFTypeRef value); -void SOSAccountValueUnionWith(SOSAccountRef account, CFStringRef key, CFSetRef valuesToUnion); -void SOSAccountValueSubtractFrom(SOSAccountRef account, CFStringRef key, CFSetRef valuesToSubtract); - - -bool SOSAccountAddEscrowToPeerInfo(SOSAccountRef account, SOSFullPeerInfoRef myPeer, CFErrorRef *error); -bool SOSAccountAddEscrowRecords(SOSAccountRef account, CFStringRef dsid, CFDictionaryRef record, CFErrorRef *error); -bool SOSAccountCheckForRings(SOSAccountRef a, CFErrorRef *error); -bool SOSAccountHandleUpdateRing(SOSAccountRef account, SOSRingRef prospective_ring, bool writeUpdate, CFErrorRef *error); -SOSRingRef SOSAccountCopyRing(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error); -bool SOSAccountSetRing(SOSAccountRef a, SOSRingRef ring, CFStringRef ringName, CFErrorRef *error); -void SOSAccountRemoveRing(SOSAccountRef a, CFStringRef ringName); -SOSRingRef SOSAccountCopyRingNamed(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error); -SOSRingRef SOSAccountRingCreateForName(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error); -bool SOSAccountUpdateRingFromRemote(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error); -bool SOSAccountUpdateRing(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error); -bool SOSAccountModifyRing(SOSAccountRef account, CFStringRef ringName, - CFErrorRef* error, - bool (^action)(SOSRingRef ring)); -CFDataRef SOSAccountRingCopyPayload(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error); -SOSRingRef SOSAccountRingCopyWithPayload(SOSAccountRef account, CFStringRef ringName, CFDataRef payload, CFErrorRef *error); -bool SOSAccountRemoveBackupPeers(SOSAccountRef account, CFArrayRef peerIDs, CFErrorRef *error); -bool SOSAccountResetRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error); -bool SOSAccountResetAllRings(SOSAccountRef account, CFErrorRef *error); -bool SOSAccountCheckPeerAvailability(SOSAccountRef account, CFErrorRef *error); -bool SOSAccountUpdateNamedRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error, +SOSPeerInfoRef SOSAccountCopyPeerWithID(SOSAccount* account, CFStringRef peerid, CFErrorRef *error); + +bool SOSAccountSetValue(SOSAccount* account, CFStringRef key, CFTypeRef value, CFErrorRef *error); +bool SOSAccountClearValue(SOSAccount* account, CFStringRef key, CFErrorRef *error); +CFTypeRef SOSAccountGetValue(SOSAccount* account, CFStringRef key, CFErrorRef *error); + +bool SOSAccountAddEscrowToPeerInfo(SOSAccount* account, SOSFullPeerInfoRef myPeer, CFErrorRef *error); +bool SOSAccountAddEscrowRecords(SOSAccount* account, CFStringRef dsid, CFDictionaryRef record, CFErrorRef *error); +void SOSAccountRemoveRing(SOSAccount* a, CFStringRef ringName); +SOSRingRef SOSAccountCopyRingNamed(SOSAccount* a, CFStringRef ringName, CFErrorRef *error); +SOSRingRef SOSAccountRingCreateForName(SOSAccount* a, CFStringRef ringName, CFErrorRef *error); +bool SOSAccountUpdateRingFromRemote(SOSAccount* account, SOSRingRef newRing, CFErrorRef *error); +bool SOSAccountUpdateRing(SOSAccount* account, SOSRingRef newRing, CFErrorRef *error); +bool SOSAccountRemoveBackupPeers(SOSAccount* account, CFArrayRef peerIDs, CFErrorRef *error); +bool SOSAccountResetRing(SOSAccount* account, CFStringRef ringName, CFErrorRef *error); +bool SOSAccountCheckPeerAvailability(SOSAccount* account, CFErrorRef *error); +bool SOSAccountUpdateNamedRing(SOSAccount* account, CFStringRef ringName, CFErrorRef *error, SOSRingRef (^create)(CFStringRef ringName, CFErrorRef *error), SOSRingRef (^copyModified)(SOSRingRef existing, CFErrorRef *error)); @@ -388,13 +301,51 @@ CFStringRef SOSBackupCopyRingNameForView(CFStringRef viewName); // // Security tool test/debug functions // - +bool SOSAccountPostDebugScope(SOSAccount* account, CFTypeRef scope, CFErrorRef *error); CFDataRef SOSAccountCopyAccountStateFromKeychain(CFErrorRef *error); bool SOSAccountDeleteAccountStateFromKeychain(CFErrorRef *error); CFDataRef SOSAccountCopyEngineStateFromKeychain(CFErrorRef *error); bool SOSAccountDeleteEngineStateFromKeychain(CFErrorRef *error); -bool SOSAccountIsNew(SOSAccountRef account, CFErrorRef *error); +bool SOSAccountIsNew(SOSAccount* account, CFErrorRef *error); +bool SOSAccountCheckForAlwaysOnViews(SOSAccount* account); +// UUID, no setter just getter and ensuring value. +void SOSAccountEnsureUUID(SOSAccount* account); +CFStringRef SOSAccountCopyUUID(SOSAccount* account); +const uint8_t* der_decode_cloud_parameters(CFAllocatorRef allocator, + CFIndex algorithmID, SecKeyRef* publicKey, + CFDataRef *parameters, + CFErrorRef* error, + const uint8_t* der, const uint8_t* der_end); + +/* + * HSA2/piggybacking + */ + +CFDataRef SOSPiggyBackBlobCopyEncodedData(SOSGenCountRef gencount, SecKeyRef pubKey, CFDataRef signature, CFErrorRef *error); + +#if __OBJC__ +NSData *SOSPiggyCreateInitialSyncData(NSArray *identities, NSArray* tlks); +NSDictionary * SOSPiggyCopyInitialSyncData(const uint8_t** der, const uint8_t *der_end); +NSArray* SOSAccountSortTLKS(NSArray* tlks); +#endif +bool SOSAccountCleanupAllKVSKeys(SOSAccount* account, CFErrorRef* error); +bool SOSAccountPopulateKVSWithBadKeys(SOSAccount* account, CFErrorRef* error); -#endif +@end + +@interface SOSAccount (Persistence) + ++(instancetype) accountFromData: (NSData*) data + factory: (SOSDataSourceFactoryRef) factory + error: (NSError**) error; ++(instancetype) accountFromDER: (const uint8_t**) der + end: (const uint8_t*) der_end + factory: (SOSDataSourceFactoryRef) factory + error: (NSError**) error; + +-(NSData*) encodedData: (NSError**) error; +@end + +#endif /* SOSAccount_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRecovery.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRecovery.m similarity index 74% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRecovery.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRecovery.m index 1d6cf242..56b76d7b 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRecovery.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRecovery.m @@ -30,21 +30,20 @@ #include "SOSAccountPriv.h" #include "SOSCloudKeychainClient.h" -// #include #include #include +#include +#include #include "SOSInternal.h" #include "SecADWrapper.h" - - #include #include CFStringRef kRecoveryRingKey = CFSTR("recoveryKeyBag"); -bool SOSAccountSetRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccountRef account, SOSRecoveryKeyBagRef rkbg, CFErrorRef *error) { +bool SOSAccountSetRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccount* account, SOSRecoveryKeyBagRef rkbg, CFErrorRef *error) { CFDataRef rkbg_as_data = NULL; bool result = false; rkbg_as_data = SOSRecoveryKeyBagCopyEncoded(rkbg, error); @@ -53,7 +52,7 @@ bool SOSAccountSetRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccountRef ac return result; } -SOSRecoveryKeyBagRef SOSAccountCopyRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccountRef account, CFErrorRef *error) { +SOSRecoveryKeyBagRef SOSAccountCopyRecoveryKeyBagEntry(CFAllocatorRef allocator, SOSAccount* account, CFErrorRef *error) { SOSRecoveryKeyBagRef retval = NULL; CFDataRef rkbg_as_data = asData(SOSAccountGetValue(account, kRecoveryRingKey, error), error); require_quiet(rkbg_as_data, errOut); @@ -62,7 +61,7 @@ errOut: return retval; } -SOSRecoveryKeyBagRef SOSAccountCopyRecoveryKeyBag(CFAllocatorRef allocator, SOSAccountRef account, CFErrorRef *error) { +SOSRecoveryKeyBagRef SOSAccountCopyRecoveryKeyBag(CFAllocatorRef allocator, SOSAccount* account, CFErrorRef *error) { SOSRingRef recRing = NULL; SOSRecoveryKeyBagRef rkbg = NULL; require_action_quiet(account, errOut, SOSCreateError(kSOSErrorParam, CFSTR("No Account Object"), NULL, error)); @@ -74,38 +73,53 @@ errOut: return rkbg; } -CFDataRef SOSAccountCopyRecoveryPublic(CFAllocatorRef allocator, SOSAccountRef account, CFErrorRef *error) { + +static CFDataRef SOSRKNullKey(void) { + static CFDataRef localNullKey = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + localNullKey = CFDataCreate(kCFAllocatorDefault, (const UInt8*) "nullkey", 8); + }); + return localNullKey; +} + +CFDataRef SOSAccountCopyRecoveryPublic(CFAllocatorRef allocator, SOSAccount* account, CFErrorRef *error) { SOSRecoveryKeyBagRef rkbg = SOSAccountCopyRecoveryKeyBag(allocator, account, error); CFDataRef recKey = NULL; require_quiet(rkbg, errOut); CFDataRef tmpKey = SOSRecoveryKeyBagGetKeyData(rkbg, error); - if(tmpKey) recKey = CFDataCreateCopy(kCFAllocatorDefault, tmpKey); + require_quiet(tmpKey, errOut); + require_quiet(!CFEqualSafe(tmpKey, SOSRKNullKey()), errOut); + recKey = CFDataCreateCopy(kCFAllocatorDefault, tmpKey); errOut: CFReleaseNull(rkbg); + if(!recKey) { + if(error && !(*error)) SOSErrorCreate(kSOSErrorNoKey, error, NULL, CFSTR("No recovery key available")); + } return recKey; } -static bool SOSAccountUpdateRecoveryRing(SOSAccountRef account, CFErrorRef *error, +static bool SOSAccountUpdateRecoveryRing(SOSAccount* account, CFErrorRef *error, SOSRingRef (^modify)(SOSRingRef existing, CFErrorRef *error)) { bool result = SOSAccountUpdateNamedRing(account, kSOSRecoveryRing, error, ^SOSRingRef(CFStringRef ringName, CFErrorRef *error) { - return SOSRingCreate(ringName, SOSAccountGetMyPeerID(account), kSOSRingRecovery, error); + return SOSRingCreate(ringName, (__bridge CFStringRef)(account.peerID), kSOSRingRecovery, error); }, modify); return result; } -static bool SOSAccountSetKeybagForRecoveryRing(SOSAccountRef account, SOSRecoveryKeyBagRef keyBag, CFErrorRef *error) { +static bool SOSAccountSetKeybagForRecoveryRing(SOSAccount* account, SOSRecoveryKeyBagRef keyBag, CFErrorRef *error) { bool result = SOSAccountUpdateRecoveryRing(account, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) { SOSRingRef newRing = NULL; - CFSetRef peerSet = SOSAccountCopyPeerSetMatching(account, ^bool(SOSPeerInfoRef peer) { + CFSetRef peerSet = [account.trust copyPeerSetMatching:^bool(SOSPeerInfoRef peer) { return true; - }); + }]; CFMutableSetRef cleared = CFSetCreateMutableForCFTypes(NULL); SOSRingSetPeerIDs(existing, cleared); SOSRingAddAll(existing, peerSet); - require_quiet(SOSRingSetRecoveryKeyBag(existing, SOSAccountGetMyFullPeerInfo(account), keyBag, error), exit); + require_quiet(SOSRingSetRecoveryKeyBag(existing, account.fullPeerInfo, keyBag, error), exit); newRing = CFRetainSafe(existing); exit: @@ -121,20 +135,16 @@ static bool SOSAccountSetKeybagForRecoveryRing(SOSAccountRef account, SOSRecover return result; } - -bool SOSAccountRemoveRecoveryKey(SOSAccountRef account, CFErrorRef *error) { - bool result = SOSAccountSetKeybagForRecoveryRing(account, NULL, error); - SOSAccountSetRecoveryKeyBagEntry(kCFAllocatorDefault, account, NULL, NULL); - account->circle_rings_retirements_need_attention = true; - return result; +bool SOSAccountRemoveRecoveryKey(SOSAccount* account, CFErrorRef *error) { + return SOSAccountSetRecoveryKey(account, SOSRKNullKey(), error); } -bool SOSAccountSetRecoveryKey(SOSAccountRef account, CFDataRef pubData, CFErrorRef *error) { +bool SOSAccountSetRecoveryKey(SOSAccount* account, CFDataRef pubData, CFErrorRef *error) { __block bool result = false; CFDataRef oldRecoveryKey = NULL; SOSRecoveryKeyBagRef rkbg = NULL; - - require_quiet(SOSAccountIsInCircle(account, error), exit); + + require_quiet([account.trust isInCircle:error], exit); oldRecoveryKey = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL); // ok to fail here. don't collect error require_action_quiet(!CFEqualSafe(pubData, oldRecoveryKey), exit, result = true); @@ -144,25 +154,33 @@ bool SOSAccountSetRecoveryKey(SOSAccountRef account, CFDataRef pubData, CFErrorR }); }); - rkbg = SOSRecoveryKeyBagCreateForAccount(kCFAllocatorDefault, account, pubData, error); + rkbg = SOSRecoveryKeyBagCreateForAccount(kCFAllocatorDefault, (__bridge CFTypeRef)account, pubData, error); require_quiet(rkbg, exit); result = SOSAccountSetKeybagForRecoveryRing(account, rkbg, error); SOSAccountSetRecoveryKeyBagEntry(kCFAllocatorDefault, account, rkbg, NULL); + { + SOSAccountForEachBackupView(account, ^(const void *value) { + CFStringRef viewName = (CFStringRef)value; + SOSAccountNewBKSBForView(account, viewName, error); + }); + } - account->circle_rings_retirements_need_attention = true; + account.circle_rings_retirements_need_attention = true; exit: CFReleaseNull(oldRecoveryKey); CFReleaseNull(rkbg); SOSClearErrorIfTrue(result, error); if (!result) { + // if we're failing and something above failed to give an error - make a generic one. + if(error && !(*error)) SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("Failed to set Recovery Key")); secnotice("recovery", "SetRecoveryPublic Failed: %@", error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space")); } return result; } -bool SOSAccountRecoveryKeyIsInBackupAndCurrentInView(SOSAccountRef account, CFStringRef viewname) { +bool SOSAccountRecoveryKeyIsInBackupAndCurrentInView(SOSAccount* account, CFStringRef viewname) { bool result = false; CFErrorRef bsError = NULL; CFDataRef backupSliceData = NULL; @@ -173,7 +191,7 @@ bool SOSAccountRecoveryKeyIsInBackupAndCurrentInView(SOSAccountRef account, CFSt require_quiet(rkbg, errOut); CFStringRef ringName = SOSBackupCopyRingNameForView(viewname); - ring = SOSAccountCopyRing(account, ringName, &bsError); + ring = [account.trust copyRing:ringName err:&bsError]; CFReleaseNull(ringName); require_quiet(ring, errOut); @@ -199,14 +217,14 @@ errOut: } -static void sosRecoveryAlertAndNotify(SOSAccountRef account, SOSRecoveryKeyBagRef oldRingRKBG, SOSRecoveryKeyBagRef ringRKBG) { +static void sosRecoveryAlertAndNotify(SOSAccount* account, SOSRecoveryKeyBagRef oldRingRKBG, SOSRecoveryKeyBagRef ringRKBG) { secnotice("recovery", "Recovery Key changed: old %@ new %@", oldRingRKBG, ringRKBG); notify_post(kSOSCCRecoveryKeyChanged); } -void SOSAccountEnsureRecoveryRing(SOSAccountRef account) { +void SOSAccountEnsureRecoveryRing(SOSAccount* account) { static SOSRecoveryKeyBagRef oldRingRKBG = NULL; - bool inCircle = SOSAccountIsInCircle(account, NULL); + bool inCircle = [account.trust isInCircle:NULL]; CFStringRef accountDSID = SOSAccountGetValue(account, kSOSDSIDKey, NULL); // murfxxx this needs to be consulted still SOSRecoveryKeyBagRef acctRKBG = SOSAccountCopyRecoveryKeyBagEntry(kCFAllocatorDefault, account, NULL); SOSRecoveryKeyBagRef ringRKBG = SOSAccountCopyRecoveryKeyBag(kCFAllocatorDefault, account, NULL); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.c deleted file mode 100644 index 0e6fe98c..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.c +++ /dev/null @@ -1,374 +0,0 @@ -// -// SOSAccountRingUpdate.c -// sec -// -// - -#include - -#include "SOSAccountPriv.h" -#include -#include -#include -#include -#include -#include - -#if 0 -static inline bool SOSAccountHasLeft(SOSAccountRef account) { - switch(account->departure_code) { - case kSOSWithdrewMembership: /* Fallthrough */ - case kSOSMembershipRevoked: /* Fallthrough */ - case kSOSLeftUntrustedCircle: - return true; - case kSOSNeverAppliedToCircle: /* Fallthrough */ - case kSOSNeverLeftCircle: /* Fallthrough */ - default: - return false; - } -} -#endif - -static const char * __unused concordstring[] = { - "kSOSConcordanceTrusted", - "kSOSConcordanceGenOld", // kSOSErrorReplay - "kSOSConcordanceNoUserSig", // kSOSErrorBadSignature - "kSOSConcordanceNoUserKey", // kSOSErrorNoKey - "kSOSConcordanceNoPeer", // kSOSErrorPeerNotFound - "kSOSConcordanceBadUserSig", // kSOSErrorBadSignature - "kSOSConcordanceBadPeerSig", // kSOSErrorBadSignature - "kSOSConcordanceNoPeerSig", - "kSOSConcordanceWeSigned", - "kSOSConcordanceInvalidMembership", - "kSOSConcordanceMissingMe", - "kSOSConcordanceImNotWorthy", -}; - - -static bool SOSAccountIsPeerRetired(SOSAccountRef account, CFSetRef peers){ - CFMutableArrayRef peerInfos = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - bool result = false; - - CFSetForEach(peers, ^(const void *value) { - SOSPeerInfoRef peer = (SOSPeerInfoRef)value; - if(SOSPeerInfoIsRetirementTicket(peer)) - CFArrayAppendValue(peerInfos, peer); - }); - if(CFArrayGetCount(peerInfos) > 0){ - if(!SOSAccountRemoveBackupPeers(account, peerInfos, NULL)) - secerror("Could not remove peers: %@, from the backup", peerInfos); - else - return true; - } - else - result = true; - - CFReleaseNull(peerInfos); - - return result; -} - -static bool SOSAccountBackupSliceKeyBagNeedsFix(SOSAccountRef account, SOSBackupSliceKeyBagRef bskb) { - - if (SOSBSKBIsDirect(bskb) || account->backup_key == NULL) - return false; - - CFSetRef peers = SOSBSKBGetPeers(bskb); - - /* first scan for retired peers, and kick'em out!*/ - SOSAccountIsPeerRetired(account, peers); - - SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account); - bool needsFix = true; - - if (myPeer) { - SOSPeerInfoRef meInBag = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer); - CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer); - CFDataRef meInBagBK = SOSPeerInfoCopyBackupKey(meInBag); - needsFix = !(meInBag && CFEqualSafe(myBK, - meInBagBK)); - CFReleaseNull(myBK); - CFReleaseNull(meInBagBK); - } - - CFDataRef rkbg = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL); - if(rkbg) needsFix |= !SOSBKSBPrefixedKeyIsInKeyBag(bskb, bskbRkbgPrefix, rkbg); - else needsFix |= SOSBSKBHasRecoveryKey(bskb); // if we don't have a recovery key - the bskb shouldn't - CFReleaseNull(rkbg); - - return needsFix; -} - - -typedef enum { - accept, - countersign, - leave, - revert, - modify, - ignore -} ringAction_t; - -static const char * __unused actionstring[] = { - "accept", "countersign", "leave", "revert", "modify", "ignore", -}; - -bool SOSAccountHandleUpdateRing(SOSAccountRef account, SOSRingRef prospectiveRing, bool writeUpdate, CFErrorRef *error) { - bool success = true; - bool haveOldRing = true; - const char * __unused localRemote = writeUpdate ? "local": "remote"; - SOSFullPeerInfoRef fpi = account->my_identity; - SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); - CFStringRef peerID = SOSPeerInfoGetPeerID(pi); - bool peerActive = (fpi && pi && peerID && SOSAccountIsInCircle(account, NULL)); - - - secdebug("ringSigning", "start:[%s] %@", localRemote, prospectiveRing); - - require_quiet(SOSAccountHasPublicKey(account, error), errOut); - - require_action_quiet(prospectiveRing, errOut, - SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("No Ring to work with"), NULL, error)); - - require_action_quiet(SOSRingIsStable(prospectiveRing), errOut, SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("You give rings a bad name"), NULL, error)); - - // We should at least have a sane ring system in the account object - require_quiet(SOSAccountCheckForRings(account, error), errOut); - - CFStringRef ringName = SOSRingGetName(prospectiveRing); - SOSRingRef oldRing = SOSAccountCopyRing(account, ringName, NULL); - - SOSTransportCircleRef transport = account->circle_transport; - - SOSRingRef newRing = CFRetainSafe(prospectiveRing); // TODO: SOSAccountCloneRingWithRetirement(account, prospectiveRing, error); - - ringAction_t ringAction = ignore; - - bool userTrustedoldRing = true; - - SOSCircleRef circle = SOSAccountGetCircle(account, NULL); - CFSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault); - - SecKeyRef oldKey = account->user_public; - -#if 0 - // for now user keys aren't explored. - // we should ask the ring if it cares about it and then do the magic to find the right user keys. - SecKeyRef oldKey = account->user_public; - - if(SOSRingPKTrusted(oldRing, account->user_public, NULL)) oldKey = account->user_public; - else if(account->previous_public && SOSRingPKTrusted(oldRing, account->previous_public, NULL)) oldKey = account->previous_public; - bool userTrustedoldRing = (oldKey != NULL) && haveOldRing; - -#endif - - if (!oldRing) { - oldRing = CFRetainSafe(newRing); - } - - SOSConcordanceStatus concstat = SOSRingConcordanceTrust(fpi, peers, oldRing, newRing, oldKey, account->user_public, peerID, error); - CFReleaseNull(peers); - - CFStringRef concStr = NULL; - switch(concstat) { - case kSOSConcordanceTrusted: - ringAction = countersign; - concStr = CFSTR("Trusted"); - break; - case kSOSConcordanceGenOld: - ringAction = userTrustedoldRing ? revert : ignore; - concStr = CFSTR("Generation Old"); - break; - case kSOSConcordanceBadUserSig: - case kSOSConcordanceBadPeerSig: - ringAction = userTrustedoldRing ? revert : accept; - concStr = CFSTR("Bad Signature"); - break; - case kSOSConcordanceNoUserSig: - ringAction = userTrustedoldRing ? revert : accept; - concStr = CFSTR("No User Signature"); - break; - case kSOSConcordanceNoPeerSig: - ringAction = accept; // We might like this one eventually but don't countersign. - concStr = CFSTR("No trusted peer signature"); - secnotice("signing", "##### No trusted peer signature found, accepting hoping for concordance later %@", newRing); - break; - case kSOSConcordanceNoPeer: - ringAction = leave; - concStr = CFSTR("No trusted peer left"); - break; - case kSOSConcordanceNoUserKey: - secerror("##### No User Public Key Available, this shouldn't ever happen!!!"); - ringAction = ignore; - break; - - case kSOSConcordanceMissingMe: - case kSOSConcordanceImNotWorthy: - ringAction = modify; - concStr = CFSTR("Incorrect membership for me"); - break; - case kSOSConcordanceInvalidMembership: - ringAction = userTrustedoldRing ? revert : ignore; - concStr = CFSTR("Invalid Ring Membership"); - break; - default: - secerror("##### Bad Error Return from ConcordanceTrust"); - ringAction = ignore; - break; - } - - (void)concStr; - - secdebug("ringSigning", "Decided on action [%s] based on concordance state [%s] and [%s] circle.", actionstring[ringAction], concordstring[concstat], userTrustedoldRing ? "trusted" : "untrusted"); - - SOSRingRef ringToPush = NULL; - bool iWasInOldRing = peerID && SOSRingHasPeerID(oldRing, peerID); - bool iAmInNewRing = peerID && SOSRingHasPeerID(newRing, peerID); - bool ringIsBackup = SOSRingGetType(newRing) == kSOSRingBackup; - bool ringIsRecovery = SOSRingGetType(newRing) == kSOSRingRecovery; - - if (ringIsBackup && peerActive) { - if (ringAction == accept || ringAction == countersign) { - CFErrorRef localError = NULL; - SOSBackupSliceKeyBagRef bskb = SOSRingCopyBackupSliceKeyBag(newRing, &localError); - - if(!bskb) { - secnotice("ringSigning", "Backup ring with no backup slice keybag (%@)", localError); - } else if (SOSAccountBackupSliceKeyBagNeedsFix(account, bskb)) { - ringAction = modify; - } - CFReleaseSafe(localError); - CFReleaseSafe(bskb); - } - - if (ringAction == modify) { - CFErrorRef updateError = NULL; - SOSAccountSetRing(account, newRing, ringName, error); - - if(SOSAccountUpdateOurPeerInBackup(account, newRing, &updateError)) { - secdebug("signing", "Modified backup ring to include us"); - } else { - secerror("Could not add ourselves to the backup: (%@)", updateError); - } - CFReleaseSafe(updateError); - - // Fall through to normal modify handling. - } - } - - if (ringIsRecovery && peerActive && (ringAction == modify)) { - SOSAccountSetRing(account, newRing, ringName, error); - } - - - if (ringAction == modify) { - ringAction = ignore; - } - - if (ringAction == leave) { - if (iWasInOldRing) { - if (sosAccountLeaveRing(account, newRing, error)) { - ringToPush = newRing; - } else { - secdebug("ringSigning", "Can't leave ring %@", oldRing); - success = false; - } - ringAction = accept; - } else { - // We are not in this ring, but we need to update account with it, since we got it from cloud - ringAction = accept; - } - } - - if (ringAction == countersign) { - if (iAmInNewRing) { - if (SOSRingPeerTrusted(newRing, fpi, NULL)) { - secdebug("ringSigning", "Already concur with: %@", newRing); - } else { - CFErrorRef signingError = NULL; - - if (fpi && SOSRingConcordanceSign(newRing, fpi, &signingError)) { - ringToPush = newRing; - } else { - secerror("Failed to concordance sign, error: %@ Old: %@ New: %@", signingError, oldRing, newRing); - success = false; - } - CFReleaseSafe(signingError); - } - } else { - secdebug("ringSigning", "Not countersigning, not in ring: %@", newRing); - } - ringAction = accept; - } - - if (ringAction == accept) { - if (iWasInOldRing && !iAmInNewRing) { - - // Don't destroy evidence of other code determining reason for leaving. - //if(!SOSAccountHasLeft(account)) account->departure_code = kSOSMembershipRevoked; - // TODO: LeaveReason for rings - } - - if (pi && SOSRingHasRejection(newRing, peerID)) { - // TODO: ReasonForLeaving for rings - SOSRingRemoveRejection(newRing, peerID); - } - - SOSAccountSetRing(account, newRing, ringName, error); - - if (pi && account->user_public_trusted - && SOSRingHasApplicant(oldRing, peerID) - && SOSRingCountPeers(newRing) > 0 - && !iAmInNewRing && !SOSRingHasApplicant(newRing, peerID)) { - // We weren't rejected (above would have set me to NULL. - // We were applying and we weren't accepted. - // Our application is declared lost, let us reapply. - - if (SOSRingApply(newRing, account->user_public, fpi, NULL)) - if(peerActive) writeUpdate = true; - } - - if (pi && SOSRingHasPeerID(oldRing, peerID)) { - SOSAccountCleanupRetirementTickets(account, RETIREMENT_FINALIZATION_SECONDS, NULL); - } - - - account->circle_rings_retirements_need_attention = true; - - if (writeUpdate) - ringToPush = newRing; - account->key_interests_need_updating = true; - } - - /* - * In the revert section we'll guard the KVS idea of circles by rejecting "bad" new rings - * and pushing our current view of the ring (oldRing). We'll only do this if we actually - * are a member of oldRing - never for an empty ring. - */ - - if (ringAction == revert) { - if(haveOldRing && peerActive && SOSRingHasPeerID(oldRing, peerID)) { - secdebug("ringSigning", "%@, Rejecting: %@ re-publishing %@", concStr, newRing, oldRing); - ringToPush = oldRing; - } else { - secdebug("ringSigning", "%@, Rejecting: %@ Have no old circle - would reset", concStr, newRing); - } - } - - - if (ringToPush != NULL) { - secdebug("ringSigning", "Pushing:[%s] %@", localRemote, ringToPush); - CFDataRef ringData = SOSRingCopyEncodedData(ringToPush, error); - if (ringData) { - success &= SOSTransportCircleRingPostRing(transport, SOSRingGetName(ringToPush), ringData, error); - } else { - success = false; - } - CFReleaseNull(ringData); - } - CFReleaseNull(oldRing); - CFReleaseSafe(newRing); - return success; -errOut: - return false; -} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.m new file mode 100644 index 00000000..b50d0bf8 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRingUpdate.m @@ -0,0 +1,55 @@ +// +// SOSAccountRingUpdate.c +// sec +// +// + +#include + +#include "SOSAccountPriv.h" +#include +#include +#include +#include +#include +#include +#import + +static const char * __unused concordstring[] = { + "kSOSConcordanceTrusted", + "kSOSConcordanceGenOld", // kSOSErrorReplay + "kSOSConcordanceNoUserSig", // kSOSErrorBadSignature + "kSOSConcordanceNoUserKey", // kSOSErrorNoKey + "kSOSConcordanceNoPeer", // kSOSErrorPeerNotFound + "kSOSConcordanceBadUserSig", // kSOSErrorBadSignature + "kSOSConcordanceBadPeerSig", // kSOSErrorBadSignature + "kSOSConcordanceNoPeerSig", + "kSOSConcordanceWeSigned", + "kSOSConcordanceInvalidMembership", + "kSOSConcordanceMissingMe", + "kSOSConcordanceImNotWorthy", +}; + + +bool SOSAccountIsPeerRetired(SOSAccount* account, CFSetRef peers){ + CFMutableArrayRef peerInfos = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + bool result = false; + + CFSetForEach(peers, ^(const void *value) { + SOSPeerInfoRef peer = (SOSPeerInfoRef)value; + if(SOSPeerInfoIsRetirementTicket(peer)) + CFArrayAppendValue(peerInfos, peer); + }); + if(CFArrayGetCount(peerInfos) > 0){ + if(!SOSAccountRemoveBackupPeers(account, peerInfos, NULL)) + secerror("Could not remove peers: %@, from the backup", peerInfos); + else + return true; + } + else + result = true; + + CFReleaseNull(peerInfos); + + return result; +} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.c deleted file mode 100644 index 6f75a8da..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.c +++ /dev/null @@ -1,331 +0,0 @@ -// -// SOSAccountRings.c -// sec -// - -#include "SOSAccountPriv.h" -#include -#include - -// -// MARK: Ring management -// - -const CFStringRef kSOSRingCircleV2 = CFSTR("Ring-CircleV2"); -const CFStringRef kSOSRingKeychainV0 = CFSTR("Ring-KeychainV0"); -const CFStringRef kSOSRingPCSHyperion = CFSTR("Ring-PCS-Photos"); -const CFStringRef kSOSRingPCSBladerunner = CFSTR("Ring-PCS-iCloudDrive"); -const CFStringRef kSOSRingPCSLiverpool = CFSTR("Ring-PCS-CloudKit"); -const CFStringRef kSOSRingPCSEscrow = CFSTR("Ring-PCS-Escrow"); -const CFStringRef kSOSRingPCSPianoMover = CFSTR("Ring-PCS-Maildrop"); -const CFStringRef kSOSRingPCSNotes = CFSTR("Ring-PCS-Notes"); -const CFStringRef kSOSRingPCSFeldspar = CFSTR("Ring-PCS-Feldspar"); -const CFStringRef kSOSRingAppleTV = CFSTR("Ring-AppleTV"); -const CFStringRef kSOSRingHomeKit = CFSTR("Ring-HomeKit"); -const CFStringRef kSOSRingWifi = CFSTR("Ring-WiFi"); -const CFStringRef kSOSRingPasswords = CFSTR("Ring-Passwords"); -const CFStringRef kSOSRingCreditCards = CFSTR("Ring-CreditCards"); -const CFStringRef kSOSRingiCloudIdentity = CFSTR("Ring-iCloudIdentity"); -const CFStringRef kSOSRingOtherSyncable = CFSTR("Ring-OtherSyncable"); - -const CFStringRef kSOSRingKey = CFSTR("trusted_rings"); - -static CFSetRef allCurrentRings(void) { - static dispatch_once_t dot; - static CFMutableSetRef allRings = NULL; - dispatch_once(&dot, ^{ - allRings = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); - CFSetAddValue(allRings, kSOSRingCircleV2); - CFSetAddValue(allRings, kSOSRingKeychainV0); - CFSetAddValue(allRings, kSOSRingPCSHyperion); - CFSetAddValue(allRings, kSOSRingPCSBladerunner); - CFSetAddValue(allRings, kSOSRingPCSLiverpool); - CFSetAddValue(allRings, kSOSRingPCSEscrow); - CFSetAddValue(allRings, kSOSRingPCSPianoMover); - CFSetAddValue(allRings, kSOSRingPCSNotes); - CFSetAddValue(allRings, kSOSRingPCSFeldspar); - CFSetAddValue(allRings, kSOSRingAppleTV); - CFSetAddValue(allRings, kSOSRingHomeKit); - CFSetAddValue(allRings, kSOSRingWifi); - CFSetAddValue(allRings, kSOSRingPasswords); - CFSetAddValue(allRings, kSOSRingCreditCards); - CFSetAddValue(allRings, kSOSRingiCloudIdentity); - CFSetAddValue(allRings, kSOSRingOtherSyncable); - }); - return allRings; -} - -typedef struct ringDef_t { - CFStringRef name; - SOSRingType ringType; - bool dropWhenLeaving; -} ringDef, *ringDefPtr; - -static ringDefPtr getRingDef(CFStringRef ringName) { - static ringDef retval; - - // Defaults - retval.name = ringName; - retval.dropWhenLeaving = true; - retval.ringType = kSOSRingEntropyKeyed; - - - if(CFSetContainsValue(allCurrentRings(), ringName)) { - retval.ringType = kSOSRingBase; - retval.dropWhenLeaving = false; - } else { - retval.ringType = kSOSRingBackup; - retval.dropWhenLeaving = false; - } - return &retval; -} - -__unused static inline void SOSAccountRingForEachRingMatching(SOSAccountRef a, void (^action)(SOSRingRef ring), bool (^condition)(SOSRingRef ring)) { - CFSetRef allRings = allCurrentRings(); - CFSetForEach(allRings, ^(const void *value) { - CFStringRef ringName = (CFStringRef) value; - SOSRingRef ring = SOSAccountCopyRing(a, ringName, NULL); - if (condition(ring)) { - action(ring); - } - CFReleaseNull(ring); - }); -} - -void SOSAccountAddRingDictionary(SOSAccountRef a) { - if(a->expansion) { - if(!CFDictionaryGetValue(a->expansion, kSOSRingKey)) { - CFMutableDictionaryRef rings = CFDictionaryCreateMutableForCFTypes(NULL); - CFDictionarySetValue(a->expansion, kSOSRingKey, rings); - CFReleaseNull(rings); - } - } -} - -static CFMutableDictionaryRef SOSAccountGetRings(SOSAccountRef a, CFErrorRef *error){ - CFMutableDictionaryRef rings = (CFMutableDictionaryRef) CFDictionaryGetValue(a->expansion, kSOSRingKey); - if(!rings) { - SOSAccountAddRingDictionary(a); - rings = SOSAccountGetRings(a, error); - } - return rings; -} - -static void SOSAccountSetRings(SOSAccountRef a, CFMutableDictionaryRef newrings){ - CFDictionarySetValue(a->expansion, newrings, kSOSRingKey); -} - -bool SOSAccountForEachRing(SOSAccountRef account, SOSRingRef (^action)(CFStringRef name, SOSRingRef ring)) { - bool retval = false; - __block bool changed = false; - CFMutableDictionaryRef rings = SOSAccountGetRings(account, NULL); - CFMutableDictionaryRef ringscopy = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - require_quiet(rings, errOut); - require_quiet(ringscopy, errOut); - CFDictionaryForEach(rings, ^(const void *key, const void *value) { - CFStringRef ringname = (CFStringRef) key; - CFDataRef ringder = CFDataCreateCopy(kCFAllocatorDefault, (CFDataRef) value); - CFDictionaryAddValue(ringscopy, key, ringder); - SOSRingRef ring = SOSRingCreateFromData(NULL, ringder); - SOSRingRef newring = action(ringname, ring); - if(newring) { - CFDataRef newringder = SOSRingCopyEncodedData(newring, NULL); - CFDictionaryReplaceValue(ringscopy, key, newringder); - CFReleaseNull(newringder); - changed = true; - } - CFReleaseNull(ring); - CFReleaseNull(ringder); - CFReleaseNull(newring); - }); - if(changed) { - SOSAccountSetRings(account, ringscopy); - } - retval = true; -errOut: - CFReleaseNull(ringscopy); - return retval; -} - -CFMutableDictionaryRef SOSAccountGetBackups(SOSAccountRef a, CFErrorRef *error){ - return a->backups; -} - -SOSRingRef SOSAccountCopyRing(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error) { - CFMutableDictionaryRef rings = SOSAccountGetRings(a, error); - require_action_quiet(rings, errOut, SOSCreateError(kSOSErrorNoRing, CFSTR("No Rings found"), NULL, error)); - CFTypeRef ringder = CFDictionaryGetValue(rings, ringName); - require_action_quiet(ringder, errOut, SOSCreateError(kSOSErrorNoRing, CFSTR("No Ring found"), NULL, error)); - SOSRingRef ring = SOSRingCreateFromData(NULL, ringder); - return (SOSRingRef) ring; - -errOut: - return NULL; -} - -bool SOSAccountSetRing(SOSAccountRef a, SOSRingRef addRing, CFStringRef ringName, CFErrorRef *error) { - require_quiet(addRing, errOut); - CFMutableDictionaryRef rings = SOSAccountGetRings(a, error); - require_action_quiet(rings, errOut, SOSCreateError(kSOSErrorNoRing, CFSTR("No Rings found"), NULL, error)); - CFDataRef ringder = SOSRingCopyEncodedData(addRing, error); - require_quiet(ringder, errOut); - CFDictionarySetValue(rings, ringName, ringder); - CFReleaseNull(ringder); - return true; -errOut: - return false; -} - -void SOSAccountRemoveRing(SOSAccountRef a, CFStringRef ringName) { - CFMutableDictionaryRef rings = SOSAccountGetRings(a, NULL); - require_quiet(rings, fail); - CFDictionaryRemoveValue(rings, ringName); -fail: - return; -} - - -SOSRingRef SOSAccountCopyRingNamed(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error) { - SOSRingRef found = SOSAccountCopyRing(a, ringName, error); - if (isSOSRing(found)) return found; - if (found) { - secerror("Non ring in ring table: %@, purging!", found); - SOSAccountRemoveRing(a, ringName); - } - found = NULL; - return found; -} - -/* Unused? */ -SOSRingRef SOSAccountRingCreateForName(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error) { - ringDefPtr rdef = getRingDef(ringName); - if(!rdef) return NULL; - SOSRingRef retval = SOSRingCreate(rdef->name, SOSAccountGetMyPeerID(a), rdef->ringType, error); - return retval; -} - -bool SOSAccountCheckForRings(SOSAccountRef a, CFErrorRef *error) { - __block bool retval = true; - CFMutableDictionaryRef rings = SOSAccountGetRings(a, error); - if(rings && isDictionary(rings)) { - SOSAccountForEachRing(a, ^SOSRingRef(CFStringRef ringname, SOSRingRef ring) { - if(retval == true) { - if(!SOSRingIsStable(ring)) { - retval = false; - secnotice("ring", "Ring %@ not stable", ringname); - } - } - return NULL; - }); - } else { - SOSCreateError(kSOSErrorNotReady, CFSTR("Rings not present"), NULL, error); - retval = false; - } - return retval; -} - -bool SOSAccountUpdateRingFromRemote(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error) { - return SOSAccountHandleUpdateRing(account, newRing, false, error); -} - -bool SOSAccountUpdateRing(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error) { - return SOSAccountHandleUpdateRing(account, newRing, true, error); -} - - -/* Unused? */ -bool SOSAccountModifyRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef* error, bool (^action)(SOSRingRef ring)) { - bool success = false; - - SOSRingRef ring = SOSAccountCopyRing(account, ringName, error); - require_action_quiet(ring, fail, SOSErrorCreate(kSOSErrorNoRing, error, NULL, CFSTR("No Ring to get peer key from"))); - - success = true; - require_quiet(action(ring), fail); - - success = SOSAccountUpdateRing(account, ring, error); - -fail: - CFReleaseSafe(ring); - return success; -} - -/* Unused? */ -CFDataRef SOSAccountRingCopyPayload(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error) { - SOSRingRef ring = SOSAccountCopyRing(account, ringName, error); - CFDataRef payload = SOSRingGetPayload(ring, error); - CFDataRef retval = CFDataCreateCopy(kCFAllocatorDefault, payload); - CFReleaseNull(ring); - return retval; -} - -/* Unused? */ -SOSRingRef SOSAccountRingCopyWithPayload(SOSAccountRef account, CFStringRef ringName, CFDataRef payload, CFErrorRef *error) { - SOSRingRef ring = SOSAccountCopyRing(account, ringName, error); - require_quiet(ring, errOut); - CFDataRef oldpayload = SOSRingGetPayload(ring, error); - require_quiet(!CFEqualSafe(oldpayload, payload), errOut); - require_quiet(SOSRingSetPayload(ring, NULL, payload, account->my_identity, error), errOut); -errOut: - return ring; -} - -bool SOSAccountResetRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error) { - bool retval = false; - SOSRingRef ring = SOSAccountCopyRing(account, ringName, error); - SOSRingRef newring = SOSRingCreate(ringName, NULL, SOSRingGetType(ring), error); - SOSRingGenerationCreateWithBaseline(newring, ring); - SOSBackupRingSetViews(newring, account->my_identity, SOSBackupRingGetViews(ring, NULL), error); - require_quiet(newring, errOut); - CFReleaseNull(ring); - retval = SOSAccountUpdateRing(account, newring, error); -errOut: - CFReleaseNull(newring); - return retval; -} - -bool SOSAccountResetAllRings(SOSAccountRef account, CFErrorRef *error) { - __block bool retval = true; - CFMutableSetRef ringList = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - require_quiet(ringList, errOut); - - SOSAccountForEachRing(account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) { - CFSetAddValue(ringList, name); - return NULL; // just using this to grab names. - }); - - CFSetForEach(ringList, ^(const void *value) { - CFStringRef ringName = (CFStringRef) value; - retval = retval && SOSAccountResetRing(account, ringName, error); - }); - -errOut: - CFReleaseNull(ringList); - return retval; -} - - -bool SOSAccountUpdateNamedRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error, - SOSRingRef (^create)(CFStringRef ringName, CFErrorRef *error), - SOSRingRef (^copyModified)(SOSRingRef existing, CFErrorRef *error)) { - bool result = false; - SOSRingRef found = SOSAccountCopyRing(account, ringName, error); - SOSRingRef newRing = NULL; - if(!found) { - found = create(ringName, error); - } - require_quiet(found, errOut); - newRing = copyModified(found, error); - CFReleaseNull(found); - - require_quiet(newRing, errOut); - - result = SOSAccountHandleUpdateRing(account, newRing, true, error); - -errOut: - CFReleaseNull(found); - CFReleaseNull(newRing); - return result; -} - - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.m new file mode 100644 index 00000000..83551638 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.m @@ -0,0 +1,228 @@ +// +// SOSAccountRings.c +// sec +// + +#include "SOSAccountPriv.h" +#include +#include +#import +#import + +#include "AssertMacros.h" + +// +// MARK: Ring management +// + +const CFStringRef kSOSRingCircleV2 = CFSTR("Ring-CircleV2"); +const CFStringRef kSOSRingKeychainV0 = CFSTR("Ring-KeychainV0"); +const CFStringRef kSOSRingPCSHyperion = CFSTR("Ring-PCS-Photos"); +const CFStringRef kSOSRingPCSBladerunner = CFSTR("Ring-PCS-iCloudDrive"); +const CFStringRef kSOSRingPCSLiverpool = CFSTR("Ring-PCS-CloudKit"); +const CFStringRef kSOSRingPCSEscrow = CFSTR("Ring-PCS-Escrow"); +const CFStringRef kSOSRingPCSPianoMover = CFSTR("Ring-PCS-Maildrop"); +const CFStringRef kSOSRingPCSNotes = CFSTR("Ring-PCS-Notes"); +const CFStringRef kSOSRingPCSFeldspar = CFSTR("Ring-PCS-Feldspar"); +const CFStringRef kSOSRingAppleTV = CFSTR("Ring-AppleTV"); +const CFStringRef kSOSRingHomeKit = CFSTR("Ring-HomeKit"); +const CFStringRef kSOSRingWifi = CFSTR("Ring-WiFi"); +const CFStringRef kSOSRingPasswords = CFSTR("Ring-Passwords"); +const CFStringRef kSOSRingCreditCards = CFSTR("Ring-CreditCards"); +const CFStringRef kSOSRingiCloudIdentity = CFSTR("Ring-iCloudIdentity"); +const CFStringRef kSOSRingOtherSyncable = CFSTR("Ring-OtherSyncable"); + +const CFStringRef kSOSRingKey = CFSTR("trusted_rings"); + +static CFSetRef allCurrentRings(void) { + static dispatch_once_t dot; + static CFMutableSetRef allRings = NULL; + dispatch_once(&dot, ^{ + allRings = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + CFSetAddValue(allRings, kSOSRingCircleV2); + CFSetAddValue(allRings, kSOSRingKeychainV0); + CFSetAddValue(allRings, kSOSRingPCSHyperion); + CFSetAddValue(allRings, kSOSRingPCSBladerunner); + CFSetAddValue(allRings, kSOSRingPCSLiverpool); + CFSetAddValue(allRings, kSOSRingPCSEscrow); + CFSetAddValue(allRings, kSOSRingPCSPianoMover); + CFSetAddValue(allRings, kSOSRingPCSNotes); + CFSetAddValue(allRings, kSOSRingPCSFeldspar); + CFSetAddValue(allRings, kSOSRingAppleTV); + CFSetAddValue(allRings, kSOSRingHomeKit); + CFSetAddValue(allRings, kSOSRingWifi); + CFSetAddValue(allRings, kSOSRingPasswords); + CFSetAddValue(allRings, kSOSRingCreditCards); + CFSetAddValue(allRings, kSOSRingiCloudIdentity); + CFSetAddValue(allRings, kSOSRingOtherSyncable); + }); + return allRings; +} + +typedef struct ringDef_t { + CFStringRef name; + SOSRingType ringType; + bool dropWhenLeaving; +} ringDef, *ringDefPtr; + +static ringDefPtr getRingDef(CFStringRef ringName) { + static ringDef retval; + + // Defaults + retval.name = ringName; + retval.dropWhenLeaving = true; + retval.ringType = kSOSRingEntropyKeyed; + + + if(CFSetContainsValue(allCurrentRings(), ringName)) { + retval.ringType = kSOSRingBase; + retval.dropWhenLeaving = false; + } else { + retval.ringType = kSOSRingBackup; + retval.dropWhenLeaving = false; + } + return &retval; +} + +__unused static inline void SOSAccountRingForEachRingMatching(SOSAccount* a, void (^action)(SOSRingRef ring), bool (^condition)(SOSRingRef ring)) { + CFSetRef allRings = allCurrentRings(); + CFSetForEach(allRings, ^(const void *value) { + CFStringRef ringName = (CFStringRef) value; + SOSRingRef ring = [a.trust copyRing:ringName err:NULL]; + if (condition(ring)) { + action(ring); + } + CFReleaseNull(ring); + }); +} + + + + + +static void SOSAccountSetRings(SOSAccount* a, CFMutableDictionaryRef newrings){ + SOSAccountTrustClassic *trust = a.trust; + [trust.expansion setObject:(__bridge NSMutableDictionary*)newrings forKey:(__bridge NSString* _Nonnull)(kSOSRingKey)]; +} + +bool SOSAccountForEachRing(SOSAccount* account, SOSRingRef (^action)(CFStringRef name, SOSRingRef ring)) { + bool retval = false; + __block bool changed = false; + __block CFStringRef ringname = NULL; + __block CFDataRef ringder = NULL; + __block SOSRingRef ring = NULL; + __block SOSRingRef newring = NULL; + __block CFDataRef newringder = NULL; + + CFMutableDictionaryRef rings = [account.trust getRings:NULL]; + CFMutableDictionaryRef ringscopy = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + if(!rings){ + CFReleaseNull(ringscopy); + return retval; + } + if(!ringscopy){ + CFReleaseNull(ringscopy); + return retval; + } + CFDictionaryForEach(rings, ^(const void *key, const void *value) { + ringname = (CFStringRef) key; + ringder = CFDataCreateCopy(kCFAllocatorDefault, (CFDataRef) value); + CFDictionaryAddValue(ringscopy, key, ringder); + ring = SOSRingCreateFromData(NULL, ringder); + newring = action(ringname, ring); + if(newring) { + newringder = SOSRingCopyEncodedData(newring, NULL); + CFDictionaryReplaceValue(ringscopy, key, newringder); + CFReleaseNull(newringder); + changed = true; + } + CFReleaseNull(ring); + CFReleaseNull(ringder); + CFReleaseNull(newring); + }); + if(changed) { + SOSAccountSetRings(account, ringscopy); + } + retval = true; + + CFReleaseNull(ringscopy); + return retval; +} + +void SOSAccountRemoveRing(SOSAccount* a, CFStringRef ringName) { + CFMutableDictionaryRef rings = [a.trust getRings:NULL]; + require_quiet(rings, fail); + CFDictionaryRemoveValue(rings, ringName); +fail: + return; +} + + +SOSRingRef SOSAccountCopyRingNamed(SOSAccount* a, CFStringRef ringName, CFErrorRef *error) { + if(!a.trust) + { + return NULL; + } + SOSRingRef found = [a.trust copyRing:ringName err:error]; + + if (isSOSRing(found)) return found; + if (found) { + secerror("Non ring in ring table: %@, purging!", found); + SOSAccountRemoveRing(a, ringName); + } + found = NULL; + return found; +} + +/* Unused? */ +SOSRingRef SOSAccountRingCreateForName(SOSAccount* a, CFStringRef ringName, CFErrorRef *error) { + ringDefPtr rdef = getRingDef(ringName); + if(!rdef) return NULL; + SOSRingRef retval = SOSRingCreate(rdef->name, (__bridge CFStringRef) a.peerID, rdef->ringType, error); + return retval; +} + +bool SOSAccountUpdateRingFromRemote(SOSAccount* account, SOSRingRef newRing, CFErrorRef *error) { + require_quiet(SOSAccountHasPublicKey(account, error), errOut); + + return [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:false err:error]; +errOut: + return false; +} + +bool SOSAccountUpdateRing(SOSAccount* account, SOSRingRef newRing, CFErrorRef *error) { + require_quiet(SOSAccountHasPublicKey(account, error), errOut); + + return [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:true err:error]; + +errOut: + return false; +} + +bool SOSAccountUpdateNamedRing(SOSAccount* account, CFStringRef ringName, CFErrorRef *error, + SOSRingRef (^create)(CFStringRef ringName, CFErrorRef *error), + SOSRingRef (^copyModified)(SOSRingRef existing, CFErrorRef *error)) { + bool result = false; + SOSRingRef found = [account.trust copyRing:ringName err:error]; + + SOSRingRef newRing = NULL; + 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); + + result = [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:true err:error]; + +errOut: + CFReleaseNull(found); + CFReleaseNull(newRing); + return result; +} + + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountSync.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountSync.m similarity index 54% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountSync.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountSync.m index e7907c79..993d7db8 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountSync.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountSync.m @@ -1,15 +1,25 @@ #include "SOSAccountPriv.h" +#include "SOSAccount.h" +#include #include +#include #include #include #include #include #include -#include +#include +#import +#import +#import +#import +#import "Security/SecureObjectSync/SOSTransportMessageIDS.h" +#import #include +#include #include @@ -18,45 +28,88 @@ // MARK: Engine Logging #define LOG_ENGINE_STATE_INTERVAL 20 -static void SOSAccountConsiderLoggingEngineState(SOSAccountTransactionRef txn) { +void SOSAccountConsiderLoggingEngineState(SOSAccountTransaction* txn) { static int engineLogCountDown = 0; if(engineLogCountDown <= 0) { - SOSEngineRef engine = SOSTransportMessageGetEngine(txn->account->kvs_message_transport); + SOSAccount* acct = txn.account; + CFTypeRef engine = [acct.kvs_message_transport SOSTransportMessageGetEngine]; - SOSEngineLogState(engine); + SOSEngineLogState((SOSEngineRef)engine); engineLogCountDown = LOG_ENGINE_STATE_INTERVAL; } else { engineLogCountDown--; } } -static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account, CFStringRef peerID) { - SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(account->my_identity); - CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi); +bool SOSAccountInflateTransports(SOSAccount* account, CFStringRef circleName, CFErrorRef *error){ + bool success = false; + + if(account.key_transport) + SOSUnregisterTransportKeyParameter(account.key_transport); + if(account.circle_transport) + SOSUnregisterTransportCircle(account.circle_transport); + if(account.ids_message_transport) + SOSUnregisterTransportMessage((SOSMessage*)account.ids_message_transport); + if(account.kvs_message_transport) + SOSUnregisterTransportMessage((SOSMessage*)account.kvs_message_transport); + + account.key_transport = [[CKKeyParameter alloc] initWithAccount:account]; + account.circle_transport = [[SOSKVSCircleStorageTransport alloc]initWithAccount:account andCircleName:(__bridge NSString *)(circleName)]; - return myPeerID && CFEqualSafe(myPeerID, peerID); + require_quiet(account.key_transport, fail); + require_quiet(account.circle_transport, fail); + + account.ids_message_transport = [[SOSMessageIDS alloc] initWithAccount:account andName:(__bridge NSString *)(circleName)]; + require_quiet(account.ids_message_transport, fail); + + account.kvs_message_transport = [[SOSMessageKVS alloc] initWithAccount:account andName:(__bridge NSString*)circleName]; + require_quiet(account.kvs_message_transport, fail); + + success = true; + +fail: + return success; +} + +static bool SOSAccountIsThisPeerIDMe(SOSAccount* account, CFStringRef peerID) { + NSString* myPeerID = account.peerID; + + return myPeerID && [myPeerID isEqualToString: (__bridge NSString*) peerID]; } -bool SOSAccountSendIKSPSyncList(SOSAccountRef account, CFErrorRef *error){ +bool SOSAccountSendIKSPSyncList(SOSAccount* account, CFErrorRef *error){ bool result = true; __block CFErrorRef localError = NULL; __block CFMutableArrayRef ids = NULL; SOSCircleRef circle = NULL; - - require_action_quiet(SOSAccountIsInCircle(account, NULL), xit, - SOSCreateError(kSOSErrorNoCircle, CFSTR("This device is not in circle"), - NULL, &localError)); - - circle = SOSAccountGetCircle(account, error); + SOSFullPeerInfoRef identity = NULL; + + if(![account.trust isInCircle:NULL]) + { + SOSCreateError(kSOSErrorNoCircle, CFSTR("This device is not in circle"), NULL, &localError); + if(error && *error != NULL) + secerror("SOSAccountSendIKSPSyncList had an error: %@", *error); + + if(localError) + secerror("SOSAccountSendIKSPSyncList had an error: %@", localError); + + CFReleaseNull(ids); + CFReleaseNull(localError); + + return result; + } + + circle = account.trust.trustedCircle; + identity = account.fullPeerInfo; ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - SOSCircleForEachValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) { + SOSCircleForEachValidPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) { if (!SOSAccountIsThisPeerIDMe(account, SOSPeerInfoGetPeerID(peer))) { - if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer) && - SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer) && - !SOSPeerInfoShouldUseACKModel(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer)){ - SOSTransportMessageIDSSetFragmentationPreference(account->ids_message_transport, kCFBooleanTrue); + if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(identity), peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(identity), peer) && + !SOSPeerInfoShouldUseACKModel(SOSFullPeerInfoGetPeerInfo(identity), peer)){ + [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref:kCFBooleanTrue]; CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); if(deviceID != NULL){ CFArrayAppendValue(ids, deviceID); @@ -68,7 +121,7 @@ bool SOSAccountSendIKSPSyncList(SOSAccountRef account, CFErrorRef *error){ require_quiet(CFArrayGetCount(ids) != 0, xit); secnotice("IDS Transport", "List of IDS Peers to ping: %@", ids); - SOSCloudKeychainGetIDSDeviceAvailability(ids, SOSAccountGetMyPeerID(account), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { + SOSCloudKeychainGetIDSDeviceAvailability(ids, (__bridge CFStringRef)(account.peerID), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { bool success = (sync_error == NULL); if(!success) secerror("Failed to send list of IDS peers to IDSKSP: %@", sync_error); @@ -89,14 +142,14 @@ xit: // MARK: KVS Syncing // -static bool SOSAccountSyncWithKVSPeers(SOSAccountTransactionRef txn, CFSetRef peerIDs, CFErrorRef *error) { - SOSAccountRef account = txn->account; +static bool SOSAccountSyncWithKVSPeers(SOSAccountTransaction* txn, CFSetRef peerIDs, CFErrorRef *error) { + SOSAccount* account = txn.account; CFErrorRef localError = NULL; bool result = false; - require_quiet(SOSAccountIsInCircle(account, &localError), xit); + require_quiet([account.trust isInCircle:error], xit); - result = SOSTransportMessageSyncWithPeers(account->kvs_message_transport, peerIDs, &localError); + result =[account.kvs_message_transport SOSTransportMessageSyncWithPeers:account.kvs_message_transport p:peerIDs err:&localError]; if (result) SetCloudKeychainTraceValueForKey(kCloudKeychainNumberOfTimesSyncedWithPeers, 1); @@ -106,7 +159,7 @@ xit: // Tell account to update SOSEngine with current trusted peers if (isSOSErrorCoded(localError, kSOSErrorPeerNotFound)) { secnotice("Account", "Arming account to update SOSEngine with current trusted peers"); - account->engine_peer_state_needs_repair = true; + account.engine_peer_state_needs_repair = true; } CFErrorPropagate(localError, error); localError = NULL; @@ -115,8 +168,8 @@ xit: } -bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransactionRef txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error) { - SOSAccountRef account = txn->account; +bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransaction* txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error) { + SOSAccount* account = txn.account; bool result = false; CFErrorRef localError = NULL; CFDictionaryRef encapsulatedMessage = NULL; @@ -129,7 +182,7 @@ bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransactionRef txn, CFString encapsulatedMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerid, message, NULL); - result = SOSTransportMessageSendMessages(account->kvs_message_transport, encapsulatedMessage, &localError); + result = [account.kvs_message_transport SOSTransportMessageSendMessages:account.kvs_message_transport pm:encapsulatedMessage err:&localError]; secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError); SOSAccountConsiderLoggingEngineState(txn); @@ -142,7 +195,7 @@ xit: } -static bool SOSAccountSyncWithKVSPeer(SOSAccountTransactionRef txn, CFStringRef peerID, CFErrorRef *error) +static bool SOSAccountSyncWithKVSPeer(SOSAccountTransaction* txn, CFStringRef peerID, CFErrorRef *error) { bool result = false; CFErrorRef localError = NULL; @@ -161,63 +214,62 @@ static bool SOSAccountSyncWithKVSPeer(SOSAccountTransactionRef txn, CFStringRef return result; } - -static CFMutableArrayRef SOSAccountCopyPeerIDsForDSID(SOSAccountRef account, CFStringRef deviceID, CFErrorRef* error) { +static CFMutableArrayRef SOSAccountCopyPeerIDsForDSID(SOSAccount* account, CFStringRef deviceID, CFErrorRef* error) { CFMutableArrayRef peerIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSCircleForEachValidPeer(account->trusted_circle, account->user_public, ^(SOSPeerInfoRef peer) { + + SOSCircleForEachValidPeer(account.trust.trustedCircle, account.accountKey, ^(SOSPeerInfoRef peer) { CFStringRef peerDeviceID = SOSPeerInfoCopyDeviceID(peer); if(peerDeviceID != NULL && CFStringCompare(peerDeviceID, deviceID, 0) == 0){ CFArrayAppendValue(peerIDs, SOSPeerInfoGetPeerID(peer)); } CFReleaseNull(peerDeviceID); }); - + if (peerIDs == NULL || CFArrayGetCount(peerIDs) == 0) { CFReleaseNull(peerIDs); SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No peer with DSID: %@"), deviceID); } - + return peerIDs; } -static bool SOSAccountSyncWithKVSPeerFromPing(SOSAccountRef account, CFArrayRef peerIDs, CFErrorRef *error) { - +static bool SOSAccountSyncWithKVSPeerFromPing(SOSAccount* account, CFArrayRef peerIDs, CFErrorRef *error) { + CFErrorRef localError = NULL; bool result = false; - + CFSetRef peerSet = CFSetCreateCopyOfArrayForCFTypes(peerIDs); - result = SOSTransportMessageSyncWithPeers(account->kvs_message_transport, peerSet, &localError); - + result = [account.kvs_message_transport SOSTransportMessageSyncWithPeers:account.kvs_message_transport p:peerSet err:&localError]; + CFReleaseNull(peerSet); - + return result; } -bool SOSAccountSyncWithKVSUsingIDSID(SOSAccountRef account, CFStringRef deviceID, CFErrorRef *error) { +bool SOSAccountSyncWithKVSUsingIDSID(SOSAccount* account, CFStringRef deviceID, CFErrorRef *error) { bool result = false; CFErrorRef localError = NULL; - + secnotice("KVS Transport","Syncing with KVS capable peer via DSID: %@", deviceID); - + CFArrayRef peerIDs = SOSAccountCopyPeerIDsForDSID(account, deviceID, &localError); require_quiet(peerIDs, xit); - + CFStringArrayPerfromWithDescription(peerIDs, ^(CFStringRef peerIDList) { secnotice("KVS Transport", "Syncing with KVS capable peers: %@", peerIDList); }); - + result = SOSAccountSyncWithKVSPeerFromPing(account, peerIDs, &localError); secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError); - + xit: CFReleaseNull(peerIDs); CFErrorPropagate(localError, error); - + return result; } -static __nonnull CF_RETURNS_RETAINED CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransactionRef txn, CFSetRef peers) { +CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransaction* txn, CFSetRef peers) { CFMutableSetRef handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); CFSetForEach(peers, ^(const void *value) { @@ -234,41 +286,54 @@ static __nonnull CF_RETURNS_RETAINED CFSetRef SOSAccountSyncWithPeersOverKVS(SOS return handled; } -static __nonnull CF_RETURNS_RETAINED CFSetRef SOSAccountSyncWithPeersOverIDS(SOSAccountTransactionRef txn, __nonnull CFSetRef peers) { +CF_RETURNS_RETAINED CFSetRef SOSAccountSyncWithPeersOverIDS(SOSAccountTransaction* txn, CFSetRef peers) { CFErrorRef localError = NULL; + SOSAccount* account = txn.account; CFStringSetPerformWithDescription(peers, ^(CFStringRef peerDescription) { secnotice("IDS Transport","Syncing with IDS capable peers: %@", peerDescription); }); // We should change this to return a set of peers we succeeded with, but for now assume they all worked. - bool result = SOSTransportMessageSyncWithPeers(txn->account->ids_message_transport, peers, &localError); + bool result = [account.ids_message_transport SOSTransportMessageSyncWithPeers:account.ids_message_transport p:peers err:&localError]; secnotice("IDS Transport", "IDS Sync result: %d", result); - return CFRetainSafe(peers); + return CFSetCreateCopy(kCFAllocatorDefault, peers); } -static CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransactionRef txn, CFSetRef /* CFStringRef */ peerIDs, CFErrorRef *error) { +CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peerIDs, CFErrorRef *error) { CFMutableSetRef notMePeers = NULL; CFMutableSetRef handledPeerIDs = NULL; CFMutableSetRef peersForIDS = NULL; CFMutableSetRef peersForKVS = NULL; - SOSAccountRef account = txn->account; - - require_action_quiet(SOSAccountIsInCircle(account, error), done, - handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs)); + SOSAccount* account = txn.account; // Kick getting our device ID if we don't have it, and find out if we're setup to use IDS. - bool canUseIDS = SOSTransportMessageIDSGetIDSDeviceID(account); + bool canUseIDS = [account.ids_message_transport SOSTransportMessageIDSGetIDSDeviceID:account]; + + if(![account.trust isInCircle:error]) + { + handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs); + CFReleaseNull(notMePeers); + CFReleaseNull(peersForIDS); + CFReleaseNull(peersForKVS); + return handledPeerIDs; + } handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); peersForIDS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - SOSPeerInfoRef myPeerInfo = SOSAccountGetMyPeerInfo(account); - require(myPeerInfo, done); + SOSPeerInfoRef myPeerInfo = account.peerInfo; + if(!myPeerInfo) + { + CFReleaseNull(notMePeers); + CFReleaseNull(peersForIDS); + CFReleaseNull(peersForKVS); + return handledPeerIDs; + } CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo); notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs); @@ -283,11 +348,13 @@ static CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTra CFErrorRef localError = NULL; CFStringRef peerID = asString(value, &localError); SOSPeerInfoRef peerInfo = NULL; - + SOSCircleRef circle = NULL; + SOSAccountTrustClassic *trust = account.trust; + circle = trust.trustedCircle; require_quiet(peerID, skip); - peerInfo = SOSCircleCopyPeerWithID(account->trusted_circle, peerID, NULL); - if (peerInfo && SOSCircleHasValidSyncingPeer(account->trusted_circle, peerInfo, account->user_public, NULL)) { + peerInfo = SOSCircleCopyPeerWithID(circle, peerID, NULL); + if (peerInfo && SOSCircleHasValidSyncingPeer(circle, peerInfo, account.accountKey, NULL)) { if (canUseIDS && SOSPeerInfoShouldUseIDSTransport(myPeerInfo, peerInfo) && SOSPeerInfoShouldUseACKModel(myPeerInfo, peerInfo)) { CFSetAddValue(peersForIDS, peerID); } else { @@ -315,16 +382,15 @@ static CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTra SOSAccountConsiderLoggingEngineState(txn); -done: CFReleaseNull(notMePeers); CFReleaseNull(peersForIDS); CFReleaseNull(peersForKVS); return handledPeerIDs; } -bool SOSAccountClearPeerMessageKey(SOSAccountTransactionRef txn, CFStringRef peerID, CFErrorRef *error) +bool SOSAccountClearPeerMessageKey(SOSAccountTransaction* txn, CFStringRef peerID, CFErrorRef *error) { - SOSAccountRef account = txn->account; + SOSAccount* account = txn.account; secnotice("IDS Transport", "clearing peer message for %@", peerID); CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error); @@ -332,7 +398,8 @@ bool SOSAccountClearPeerMessageKey(SOSAccountTransactionRef txn, CFStringRef pee if(dsid == NULL) dsid = kCFNull; - CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(account->kvs_message_transport, peerID); + CFStringRef myID = (__bridge CFStringRef)(account.peerID); + CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(account.kvs_message_transport, myID, peerID); CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, kCFNull, kSOSKVSRequiredKey, dsid, NULL); CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) { @@ -349,22 +416,24 @@ bool SOSAccountClearPeerMessageKey(SOSAccountTransactionRef txn, CFStringRef pee return true; } -CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransactionRef txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error) +CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error) { CFErrorRef localError = NULL; + SOSAccount* account = txn.account; + CFMutableSetRef handled = SOSAccountSyncWithPeers(txn, peers, &localError); - SOSTransportMessageIDSGetIDSDeviceID(txn->account); + [account.ids_message_transport SOSTransportMessageIDSGetIDSDeviceID:account]; if (!handled) { secnotice("account-sync", "Peer Sync failed: %@", localError); handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); } CFReleaseNull(localError); - - SOSEngineRef engine = SOSTransportMessageGetEngine(txn->account->kvs_message_transport); - CFSetRef engineHandled = SOSEngineSyncWithBackupPeers(engine, backupPeers, error); - + + CFTypeRef engine = [account.kvs_message_transport SOSTransportMessageGetEngine]; + CFSetRef engineHandled = SOSEngineSyncWithBackupPeers((SOSEngineRef)engine, backupPeers, false, error); + if (engineHandled) { CFSetUnion(handled, engineHandled); } else { @@ -376,49 +445,60 @@ CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransactio return handled; } -bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransactionRef txn, CFErrorRef *error) +CF_RETURNS_RETAINED CFSetRef SOSAccountCopyBackupPeersAndForceSync(SOSAccountTransaction* txn, CFErrorRef *error) { - bool success = false; - CFMutableSetRef allSyncingPeers = NULL; + SOSEngineRef engine = (SOSEngineRef) [txn.account.kvs_message_transport SOSTransportMessageGetEngine]; - require_quiet(SOSAccountIsInCircle(txn->account, error), xit); + NSArray* backupPeersArray = (NSArray*) CFBridgingRelease(SOSEngineCopyBackupPeerNames(engine, error)); + NSSet* backupPeers = [[NSSet alloc] initWithArray: backupPeersArray]; + return SOSEngineSyncWithBackupPeers(engine, (__bridge CFSetRef) backupPeers, true, error); +} - SOSTransportMessageIDSGetIDSDeviceID(txn->account); +bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransaction* txn, CFErrorRef *error) +{ + SOSAccount* account = txn.account; + SOSAccountTrustClassic *trust = account.trust; - allSyncingPeers = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + if (![account.trust isInCircle:error]) + return false; - SOSCircleForEachValidSyncingPeer(txn->account->trusted_circle, txn->account->user_public, ^(SOSPeerInfoRef peer) { - CFSetAddValue(allSyncingPeers, SOSPeerInfoGetPeerID(peer)); - }); + NSMutableSet* allSyncingPeers = [NSMutableSet set]; + SOSCircleRef circle = trust.trustedCircle; - SOSAccountTransactionAddSyncRequestForAllPeerIDs(txn, allSyncingPeers); + // Tickle IDS in case we haven't even tried when we're syncing. + [account.ids_message_transport SOSTransportMessageIDSGetIDSDeviceID:account]; - success = true; + SOSCircleForEachValidSyncingPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) { + [allSyncingPeers addObject: (__bridge NSString*) SOSPeerInfoGetPeerID(peer)]; + }); -xit: - CFReleaseNull(allSyncingPeers); - return success; + [txn requestSyncWithPeers:allSyncingPeers]; + + return true; } // // MARK: Syncing status functions // -bool SOSAccountMessageFromPeerIsPending(SOSAccountTransactionRef txn, SOSPeerInfoRef peer, CFErrorRef *error) { +bool SOSAccountMessageFromPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) { bool success = false; - require_quiet(SOSAccountIsInCircle(txn->account, error), xit); + SOSAccount* account = txn.account; + require_quiet([account.trust isInCircle:error], xit); // This translation belongs inside KVS..way down in CKD, but for now we reach over and do it here. - CFStringRef peerMessage = SOSMessageKeyCreateFromPeerToTransport(txn->account->kvs_message_transport, SOSPeerInfoGetPeerID(peer)); + CFStringRef peerMessage = SOSMessageKeyCreateFromPeerToTransport([account kvs_message_transport], (__bridge CFStringRef)(account.peerID), SOSPeerInfoGetPeerID(peer)); success = SOSCloudKeychainHasPendingKey(peerMessage, error); + CFReleaseNull(peerMessage); xit: return success; } -bool SOSAccountSendToPeerIsPending(SOSAccountTransactionRef txn, SOSPeerInfoRef peer, CFErrorRef *error) { +bool SOSAccountSendToPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) { bool success = false; - require_quiet(SOSAccountIsInCircle(txn->account, error), xit); + SOSAccount* account = txn.account; + require_quiet([account.trust isInCircle:error], xit); success = SOSCCIsSyncPendingFor(SOSPeerInfoGetPeerID(peer), error); xit: @@ -426,3 +506,4 @@ xit: } + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.c deleted file mode 100644 index cd074040..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.c +++ /dev/null @@ -1,226 +0,0 @@ -// -// SOSAccountTransaction.c -// sec -// -// - -#include "SOSAccountTransaction.h" - -#include -#include - -#include -#include -#include -#include -#include - -#define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable" - -CFGiblisFor(SOSAccountTransaction); - -static void SOSAccountTransactionDestroy(CFTypeRef aObj) { - SOSAccountTransactionRef at = (SOSAccountTransactionRef) aObj; - - CFReleaseNull(at->initialUnsyncedViews); - CFReleaseNull(at->initialID); - CFReleaseNull(at->account); - CFReleaseNull(at->initialViews); - CFReleaseNull(at->initialKeyParameters); - CFReleaseNull(at->peersToRequestSync); -} - -static CFStringRef SOSAccountTransactionCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) { - SOSAccountTransactionRef at = (SOSAccountTransactionRef) aObj; - - CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0); - - CFStringAppendFormat(description, NULL, CFSTR(""), - at, at->initialViews ? CFSetGetCount(at->initialViews) : 0); - - return description; -} - -static void SOSAccountTransactionRestart(SOSAccountTransactionRef txn) { - txn->initialInCircle = SOSAccountIsInCircle(txn->account, NULL); - - if(txn->account) - txn->initialTrusted = (txn->account)->user_public_trusted; - - if (txn->initialInCircle) { - SOSAccountEnsureSyncChecking(txn->account); - } - - CFAssignRetained(txn->initialUnsyncedViews, SOSAccountCopyOutstandingViews(txn->account)); - - CFReleaseNull(txn->initialKeyParameters); - - if(txn->account && txn->account->user_key_parameters){ - CFReleaseNull(txn->initialKeyParameters); - txn->initialKeyParameters = CFDataCreateCopy(kCFAllocatorDefault, txn->account->user_key_parameters); - } - SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(txn->account); - CFAssignRetained(txn->initialViews, mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL); - - CFRetainAssign(txn->initialID, SOSPeerInfoGetPeerID(mpi)); - - CFReleaseNull(txn->peersToRequestSync); - - CFStringSetPerformWithDescription(txn->initialViews, ^(CFStringRef description) { - secnotice("acct-txn", "Starting as:%s v:%@", txn->initialInCircle ? "member" : "non-member", description); - }); -} - - -SOSAccountTransactionRef SOSAccountTransactionCreate(SOSAccountRef account) { - SOSAccountTransactionRef at = CFTypeAllocate(SOSAccountTransaction, struct __OpaqueSOSAccountTransaction, kCFAllocatorDefault); - - at->account = CFRetainSafe(account); - - at->initialInCircle = false; - at->initialViews = NULL; - at->initialKeyParameters = NULL; - at->initialTrusted = false; - at->initialUnsyncedViews = NULL; - at->initialID = NULL; - at->peersToRequestSync = NULL; - - SOSAccountTransactionRestart(at); - - return at; -} - -#define ACCOUNT_STATE_INTERVAL 20 - -void SOSAccountTransactionFinish(SOSAccountTransactionRef txn) { - CFErrorRef localError = NULL; - bool notifyEngines = false; - static int do_account_state_at_zero = 0; - - SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(txn->account); - - bool isInCircle = SOSAccountIsInCircle(txn->account, NULL); - - if (isInCircle && txn->peersToRequestSync) { - SOSCCRequestSyncWithPeers(txn->peersToRequestSync); - } - CFReleaseNull(txn->peersToRequestSync); - - if (isInCircle) { - SOSAccountEnsureSyncChecking(txn->account); - } else { - SOSAccountCancelSyncChecking(txn->account); - } - - // If our identity changed our inital set should be everything. - if (!CFEqualSafe(txn->initialID, SOSPeerInfoGetPeerID(mpi))) { - CFAssignRetained(txn->initialUnsyncedViews, SOSViewCopyViewSet(kViewSetAll)); - } - - CFSetRef finalUnsyncedViews = SOSAccountCopyOutstandingViews(txn->account); - if (!CFEqualSafe(txn->initialUnsyncedViews, finalUnsyncedViews)) { - if (SOSAccountHandleOutOfSyncUpdate(txn->account, txn->initialUnsyncedViews, finalUnsyncedViews)) { - notifyEngines = true; - } - - CFStringSetPerformWithDescription(txn->initialUnsyncedViews, ^(CFStringRef newUnsyncedDescripion) { - CFStringSetPerformWithDescription(finalUnsyncedViews, ^(CFStringRef unsyncedDescription) { - secnotice("initial-sync", "Unsynced was: %@", unsyncedDescription); - secnotice("initial-sync", "Unsynced is: %@", newUnsyncedDescripion); - }); - }); - } - CFReleaseNull(finalUnsyncedViews); - - if (txn->account->engine_peer_state_needs_repair) { - // We currently only get here from a failed syncwithallpeers, so - // that will retry. If this logic changes, force a syncwithallpeers - if (!SOSAccountEnsurePeerRegistration(txn->account, &localError)) { - secerror("Ensure peer registration while repairing failed: %@", localError); - } - CFReleaseNull(localError); - - notifyEngines = true; - } - - if(txn->account->circle_rings_retirements_need_attention){ - SOSAccountRecordRetiredPeersInCircle(txn->account); - - SOSAccountEnsureRecoveryRing(txn->account); - SOSAccountEnsureInBackupRings(txn->account); - - CFErrorRef localError = NULL; - if(!SOSTransportCircleFlushChanges(txn->account->circle_transport, &localError)) { - secerror("flush circle failed %@", localError); - } - CFReleaseSafe(localError); - - notifyEngines = true; - } - - if (notifyEngines) { - SOSAccountNotifyEngines(txn->account); - } - - if(txn->account->key_interests_need_updating){ - SOSUpdateKeyInterest(txn->account); - } - - txn->account->key_interests_need_updating = false; - txn->account->circle_rings_retirements_need_attention = false; - txn->account->engine_peer_state_needs_repair = false; - - SOSAccountFlattenToSaveBlock(txn->account); - - // Refresh isInCircle since we could have changed our mind - isInCircle = SOSAccountIsInCircle(txn->account, NULL); - - mpi = SOSAccountGetMyPeerInfo(txn->account); - CFSetRef views = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL; - - CFStringSetPerformWithDescription(views, ^(CFStringRef description) { - secnotice("acct-txn", "Finished as:%s v:%@", isInCircle ? "member" : "non-member", description); - }); - if(!CFEqualSafe(txn->initialViews, views) || txn->initialInCircle != isInCircle) { - notify_post(kSOSCCViewMembershipChangedNotification); - do_account_state_at_zero = 0; - } - - if((txn->initialTrusted != (txn->account)->user_public_trusted) || (!CFEqualSafe(txn->initialKeyParameters, txn->account->user_key_parameters))){ - notify_post(kPublicKeyNotAvailable); - do_account_state_at_zero = 0; - } - - if(do_account_state_at_zero <= 0) { - SOSAccountLogState(txn->account); - SOSAccountLogViewState(txn->account); - do_account_state_at_zero = ACCOUNT_STATE_INTERVAL; - } - do_account_state_at_zero--; - - CFReleaseNull(views); - -} - -void SOSAccountTransactionFinishAndRestart(SOSAccountTransactionRef txn) { - SOSAccountTransactionFinish(txn); - SOSAccountTransactionRestart(txn); -} - -void SOSAccountTransactionAddSyncRequestForPeerID(SOSAccountTransactionRef txn, CFStringRef peerID) { - if (!txn->peersToRequestSync) { - txn->peersToRequestSync = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - } - - CFSetAddValue(txn->peersToRequestSync, peerID); -} - -void SOSAccountTransactionAddSyncRequestForAllPeerIDs(SOSAccountTransactionRef txn, CFSetRef /* CFStringRef */ peerIDs) { - if (!txn->peersToRequestSync) { - txn->peersToRequestSync = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - } - - CFSetUnion(txn->peersToRequestSync, peerIDs); -} - - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.h index 667e53be..061c17ea 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.h @@ -8,39 +8,43 @@ #ifndef SOSAccountTransaction_h #define SOSAccountTransaction_h -typedef struct __OpaqueSOSAccountTransaction *SOSAccountTransactionRef; - #include -#include +#import #include -CF_ASSUME_NONNULL_BEGIN +NS_ASSUME_NONNULL_BEGIN + +@class SOSAccountTransaction; + +@interface SOSAccount (Transaction) + ++ (void)performOnAccountQueue:(void (^)(void))action; ++ (void)performWhileHoldingAccountQueue:(void (^)(void))action; + +- (void) performTransaction: (void (^)(SOSAccountTransaction* txn)) action; +- (void) performTransaction_Locked: (void (^)(SOSAccountTransaction* txn)) action; -struct __OpaqueSOSAccountTransaction { - CFRuntimeBase _base; +@end - _Nonnull SOSAccountRef account; +@interface SOSAccountTransaction : NSObject - bool initialInCircle; - _Nullable CFSetRef initialViews; ++ (instancetype) transactionWithAccount: (SOSAccount*) account; - _Nullable CFSetRef initialUnsyncedViews; - _Nullable CFStringRef initialID; +- (instancetype) init NS_UNAVAILABLE; +- (instancetype) initWithAccount: (SOSAccount*) account NS_DESIGNATED_INITIALIZER; - bool initialTrusted; - _Nullable CFDataRef initialKeyParameters; +- (void) finish; +- (void) restart; - _Nullable CFMutableSetRef peersToRequestSync; -}; +- (void) requestSyncWith: (NSString*) peerID; +- (void) requestSyncWithPeers: (NSSet*) peerList; +@property SOSAccount *account; -SOSAccountTransactionRef SOSAccountTransactionCreate(SOSAccountRef account); -void SOSAccountTransactionFinish(SOSAccountTransactionRef txn); -void SOSAccountTransactionFinishAndRestart(SOSAccountTransactionRef txn); +@property (readonly) NSString* description; -void SOSAccountTransactionAddSyncRequestForPeerID(SOSAccountTransactionRef txn, CFStringRef peerID); -void SOSAccountTransactionAddSyncRequestForAllPeerIDs(SOSAccountTransactionRef txn, CFSetRef /* CFStringRef */ peerIDs); +@end -CF_ASSUME_NONNULL_END +NS_ASSUME_NONNULL_END #endif /* SOSAccountTransaction_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.m new file mode 100644 index 00000000..b54350b3 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.m @@ -0,0 +1,298 @@ +// +// SOSAccountTransaction.c +// sec +// +// + +#include "SOSAccountTransaction.h" + +#include +#import +#include + +#include +#include +#include +#import +#import +#import +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" +#import "Security/SecureObjectSync/SOSTransportMessageKVS.h" + +#include +#define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable" + +// Account dumping state stuff + +#define ACCOUNT_STATE_INTERVAL 200 + + +@interface SOSAccountTransaction () + +@property BOOL initialInCircle; +@property NSSet* initialViews; +@property NSSet* initialUnsyncedViews; +@property NSString* initialID; + +@property BOOL initialTrusted; +@property NSData* initialKeyParameters; + +@property NSMutableSet* peersToRequestSync; + +- (void) start; + +@end + + + +@implementation SOSAccountTransaction + ++ (instancetype) transactionWithAccount: (SOSAccount*) account { + return [[SOSAccountTransaction new] initWithAccount: account]; +} + +- (NSString*) description { + return [NSString stringWithFormat:@"", + self, (unsigned long)(self.initialViews ? [self.initialViews count] : 0)]; +} + +- (instancetype) initWithAccount:(SOSAccount *)account { + if (self = [super init]) { + self.account = account; + [self start]; + } + return self; +} + +- (void) start { + self.initialInCircle = [self.account.trust isInCircle:NULL]; + self.initialTrusted = self.account.accountKeyIsTrusted; + + if (self.initialInCircle) { + SOSAccountEnsureSyncChecking(self.account); + } + + self.initialUnsyncedViews = (__bridge_transfer NSMutableSet*)SOSAccountCopyOutstandingViews(self.account); + self.initialKeyParameters = self.account.accountKeyDerivationParamters ? [NSData dataWithData:self.account.accountKeyDerivationParamters] : nil; + + SOSPeerInfoRef mpi = self.account.peerInfo; + self.initialViews = mpi ? (__bridge_transfer NSSet*) SOSPeerInfoCopyEnabledViews(mpi) : nil; + + self.peersToRequestSync = nil; + + CFStringSetPerformWithDescription((__bridge CFSetRef) self.initialViews, ^(CFStringRef description) { + secnotice("acct-txn", "Starting as:%s v:%@", self.initialInCircle ? "member" : "non-member", description); + }); +} + +- (void) restart { + [self finish]; + [self start]; +} + + +- (void) finish { + static int do_account_state_at_zero = 0; + + CFErrorRef localError = NULL; + bool notifyEngines = false; + + SOSPeerInfoRef mpi = self.account.peerInfo; + + bool isInCircle = [self.account.trust isInCircle:NULL]; + + if (isInCircle && self.peersToRequestSync) { + SOSCCRequestSyncWithPeers((__bridge CFSetRef)(self.peersToRequestSync)); + } + self.peersToRequestSync = nil; + + if (isInCircle) { + SOSAccountEnsureSyncChecking(self.account); + } else { + SOSAccountCancelSyncChecking(self.account); + } + + // If our identity changed our inital set should be everything. + if ([self.initialID isEqualToString: (__bridge NSString *)(SOSPeerInfoGetPeerID(mpi))]) { + self.initialUnsyncedViews = (__bridge_transfer NSSet*) SOSViewCopyViewSet(kViewSetAll); + } + + NSSet* finalUnsyncedViews = (__bridge_transfer NSSet*) SOSAccountCopyOutstandingViews(self.account); + if (!NSIsEqualSafe(self.initialUnsyncedViews, finalUnsyncedViews)) { + if (SOSAccountHandleOutOfSyncUpdate(self.account, + (__bridge CFSetRef)(self.initialUnsyncedViews), + (__bridge CFSetRef)(finalUnsyncedViews))) { + notifyEngines = true; + } + + secnotice("initial-sync", "Unsynced was: %@", [self.initialUnsyncedViews shortDescription]); + secnotice("initial-sync", "Unsynced is: %@", [finalUnsyncedViews shortDescription]); + } + + if (self.account.engine_peer_state_needs_repair) { + // We currently only get here from a failed syncwithallpeers, so + // that will retry. If this logic changes, force a syncwithallpeers + if (!SOSAccountEnsurePeerRegistration(self.account, &localError)) { + secerror("Ensure peer registration while repairing failed: %@", localError); + } + CFReleaseNull(localError); + + notifyEngines = true; + } + + if(self.account.circle_rings_retirements_need_attention){ + SOSAccountRecordRetiredPeersInCircle(self.account); + + SOSAccountEnsureRecoveryRing(self.account); + SOSAccountEnsureInBackupRings(self.account); + + CFErrorRef localError = NULL; + if(![self.account.circle_transport flushChanges:&localError]){ + secerror("flush circle failed %@", localError); + } + CFReleaseSafe(localError); + + notifyEngines = true; + } + + if (notifyEngines) { +#if OCTAGON + if(!SecCKKSTestDisableSOS()) { +#endif + SOSAccountNotifyEngines(self.account); +#if OCTAGON + } +#endif + } + + if(self.account.key_interests_need_updating){ + SOSUpdateKeyInterest(self.account); + } + + self.account.key_interests_need_updating = false; + self.account.circle_rings_retirements_need_attention = false; + self.account.engine_peer_state_needs_repair = false; + + [self.account flattenToSaveBlock]; + + // Refresh isInCircle since we could have changed our mind + isInCircle = [self.account.trust isInCircle:NULL]; + + mpi = self.account.peerInfo; + CFSetRef views = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL; + + CFStringSetPerformWithDescription(views, ^(CFStringRef description) { + secnotice("acct-txn", "Finished as:%s v:%@", isInCircle ? "member" : "non-member", description); + }); + + // This is the logic to detect a new userKey: + bool userKeyChanged = !NSIsEqualSafe(self.initialKeyParameters, self.account.accountKeyDerivationParamters); + + // This indicates we initiated a password change. + bool weInitiatedKeyChange = (self.initialTrusted && + self.initialInCircle && + userKeyChanged && isInCircle && + self.account.accountKeyIsTrusted); + + if(self.initialInCircle != isInCircle) { + notify_post(kSOSCCCircleChangedNotification); + notify_post(kSOSCCViewMembershipChangedNotification); + do_account_state_at_zero = 0; + secnotice("secdNotify", "Notified clients of kSOSCCCircleChangedNotification && kSOSCCViewMembershipChangedNotification for circle/view change"); + } else if(isInCircle && !NSIsEqualSafe(self.initialViews, (__bridge NSSet*)views)) { + notify_post(kSOSCCViewMembershipChangedNotification); + do_account_state_at_zero = 0; + secnotice("secdNotify", "Notified clients of kSOSCCViewMembershipChangedNotification for viewchange(only)"); + } else if(weInitiatedKeyChange) { // We consider this a circleChange so (PCS) can tell the userkey trust changed. + notify_post(kSOSCCCircleChangedNotification); + do_account_state_at_zero = 0; + secnotice("secdNotify", "Notified clients of kSOSCCCircleChangedNotification for userKey change"); + } + + // This is the case of we used to trust the key, were in the circle, the key changed, we don't trust it now. + bool fellOutOfTrust = (self.initialTrusted && + self.initialInCircle && + userKeyChanged && + !self.account.accountKeyIsTrusted); + + if(fellOutOfTrust) { + secnotice("userKeyTrust", "No longer trust user public key - prompting for password."); + notify_post(kPublicKeyNotAvailable); + do_account_state_at_zero = 0; + } + + if(do_account_state_at_zero <= 0) { + SOSAccountLogState(self.account); + SOSAccountLogViewState(self.account); + do_account_state_at_zero = ACCOUNT_STATE_INTERVAL; + } + do_account_state_at_zero--; + + CFReleaseNull(views); +} + +- (void) requestSyncWith: (NSString*) peerID { + if (self.peersToRequestSync == nil) { + self.peersToRequestSync = [NSMutableSet set]; + } + [self.peersToRequestSync addObject: peerID]; +} + +- (void) requestSyncWithPeers: (NSSet*) peerList { + if (self.peersToRequestSync == nil) { + self.peersToRequestSync = [NSMutableSet set]; + } + [self.peersToRequestSync unionSet: peerList]; +} + +@end + + + + +// +// MARK: Transactional +// + +@implementation SOSAccount (Transaction) + +__thread bool __hasAccountQueue = false; + ++ (void)performWhileHoldingAccountQueue:(void (^)(void))action +{ + bool hadAccountQueue = __hasAccountQueue; + __hasAccountQueue = true; + action(); + __hasAccountQueue = hadAccountQueue; +} + ++ (void)performOnAccountQueue:(void (^)(void))action +{ + SOSAccount* account = (__bridge SOSAccount*)GetSharedAccountRef(); + [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + action(); + }]; +} + +- (void) performTransaction_Locked: (void (^)(SOSAccountTransaction* txn)) action { + SOSAccountTransaction* transaction = [SOSAccountTransaction transactionWithAccount:self]; + action(transaction); + [transaction finish]; +} + +- (void) performTransaction: (void (^)(SOSAccountTransaction* txn)) action { + if (__hasAccountQueue) { + [self performTransaction_Locked:action]; + } + else { + dispatch_sync(self.queue, ^{ + __hasAccountQueue = true; + [self performTransaction_Locked:action]; + __hasAccountQueue = false; + }); + } +} + + +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrust.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrust.h new file mode 100644 index 00000000..fcd013be --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrust.h @@ -0,0 +1,54 @@ +// +// SOSAccountTrust_h +// Security + +#ifndef SOSAccountTrust_h +#define SOSAccountTrust_h + +#import +#import +#import +#import + +typedef bool (^SOSModifyCircleBlock)(SOSCircleRef circle); +typedef void (^SOSIteratePeerBlock)(SOSPeerInfoRef peerInfo); +typedef bool (^SOSModifyPeerBlock)(SOSPeerInfoRef peerInfo); +typedef bool (^SOSModifyPeerInfoBlock)(SOSFullPeerInfoRef fpi, CFErrorRef *error); +typedef SOSRingRef(^RingNameBlock)(CFStringRef name, SOSRingRef ring); +typedef void (^SOSModifyPeersInCircleBlock)(SOSCircleRef circle, CFMutableArrayRef appendPeersTo); + +@interface SOSAccountTrust : NSObject +{ + NSMutableDictionary * expansion; + + SOSFullPeerInfoRef fullPeerInfo; + SOSPeerInfoRef peerInfo; + NSString* peerID; + + SOSCircleRef trustedCircle; + NSMutableSet * retirees; + enum DepartureReason departureCode; +} +@property (strong, nonatomic) NSMutableDictionary * expansion; + +@property (nonatomic) SOSFullPeerInfoRef fullPeerInfo; + +// Convenince getters +@property (nonatomic, readonly) SOSPeerInfoRef peerInfo; +@property (nonatomic, readonly) NSString* peerID; + + +@property (nonatomic) SOSCircleRef trustedCircle; +@property (strong, nonatomic) NSMutableSet * retirees; +@property (nonatomic) enum DepartureReason departureCode; + ++(instancetype)trust; + +-(id)init; +-(id)initWithRetirees:(NSMutableSet*)retirees fpi:(SOSFullPeerInfoRef)identity circle:(SOSCircleRef) trusted_circle + departureCode:(enum DepartureReason)code peerExpansion:(NSMutableDictionary*)expansion; + + +@end + +#endif /* Trust_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrust.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrust.m new file mode 100644 index 00000000..00ef816f --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrust.m @@ -0,0 +1,87 @@ +// +// SOSAccountTrust.c +// Security +// +#import "Security/SecureObjectSync/SOSAccountPriv.h" +#import "Security/SecureObjectSync/SOSAccountTrust.h" + +@implementation SOSAccountTrust + ++(instancetype)trust +{ + return [[SOSAccountTrust alloc]init]; +} + +-(id)init +{ + self = [super init]; + if(self) + { + self.retirees = [NSMutableSet set]; + self.fullPeerInfo = NULL; + self.trustedCircle = NULL; + self.departureCode = kSOSDepartureReasonError; + self.expansion = [NSMutableDictionary dictionary]; + } + return self; +} + +-(id)initWithRetirees:(NSMutableSet*)r fpi:(SOSFullPeerInfoRef)fpi circle:(SOSCircleRef) trusted_circle + departureCode:(enum DepartureReason)code peerExpansion:(NSMutableDictionary*)e +{ + + self = [super init]; + if(self) + { + self.retirees = r; + self.fullPeerInfo = fpi; + self.trustedCircle = trusted_circle; + self.departureCode = code; + self.expansion = e; + } + return self; +} + +- (SOSPeerInfoRef) peerInfo { + return SOSFullPeerInfoGetPeerInfo(self.fullPeerInfo); +} + +- (NSString*) peerID { + return (__bridge_transfer NSString*) CFRetainSafe(SOSPeerInfoGetPeerID(self.peerInfo)); +} + +@synthesize trustedCircle = trustedCircle; + +- (void) setTrustedCircle:(SOSCircleRef) circle { + CFRetainAssign(self->trustedCircle, circle); +} + +@synthesize retirees = retirees; + +-(void) setRetirees:(NSSet *)newRetirees +{ + self->retirees = newRetirees.mutableCopy; +} + +@synthesize fullPeerInfo = fullPeerInfo; + +- (void) setFullPeerInfo:(SOSFullPeerInfoRef) newIdentity { + CFRetainAssign(self->fullPeerInfo, newIdentity); +} + +@synthesize expansion = expansion; + +-(void)setExpansion:(NSDictionary*) newExpansion +{ + self->expansion = newExpansion.mutableCopy; +} + +@synthesize departureCode = departureCode; + +-(void)setDepartureCode:(enum DepartureReason)newDepartureCode +{ + self->departureCode = newDepartureCode; +} + +@end + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Circle.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Circle.h new file mode 100644 index 00000000..9b45a2c0 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Circle.h @@ -0,0 +1,36 @@ +// +// SOSAccountTrustClassic+Circle.h +// Security +// + +#ifndef SOSAccountTrustClassic_Circle_h +#define SOSAccountTrustClassic_Circle_h + +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" +#import "Security/SecureObjectSync/SOSTransportCircleKVS.h" + +@interface SOSAccountTrustClassic (Circle) +//Circle +-(SOSCCStatus) getCircleStatus:(CFErrorRef*) error; +-(SOSCircleRef) ensureCircle:(SOSAccount*)account name:(CFStringRef)name err:(CFErrorRef *)error; +-(bool) modifyCircle:(SOSCircleStorageTransport*)circleTransport err:(CFErrorRef*)error action:(SOSModifyCircleBlock)block; +-(SOSCircleRef) getCircle:(CFErrorRef *)error; +-(bool) hasCircle:(CFErrorRef*) error; +-(void) generationSignatureUpdateWith:(SOSAccount*)account key:(SecKeyRef) privKey; +-(bool) isInCircle:(CFErrorRef *)error; +-(void) forEachCirclePeerExceptMe:(SOSIteratePeerBlock)block; +-(bool) leaveCircle:(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) updateCircleFromRemote:(SOSCircleStorageTransport*)circleTransport newCircle:(SOSCircleRef)newCircle err:(CFErrorRef*)error; + +-(CFArrayRef) copySortedPeerArray:(CFErrorRef *)error + action:(SOSModifyPeersInCircleBlock)block; +-(bool) handleUpdateCircle:(SOSCircleRef) prospective_circle transport:(SOSCircleStorageTransport*)circleTransport update:(bool) writeUpdate err:(CFErrorRef*)error; +-(bool) joinCircle:(SOSAccountTransaction*) aTxn userKey:(SecKeyRef)user_key useCloudPeer:(bool)use_cloud_peer err:(CFErrorRef*) error; + +@end + +#endif /* SOSAccountTrustClassic_Circle_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Circle.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Circle.m new file mode 100644 index 00000000..770135fd --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Circle.m @@ -0,0 +1,686 @@ +// +// SOSAccountTrustClassicCircle.m +// Security +// + +#import +#include + +#import "Security/SecureObjectSync/SOSAccount.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" +#import "Security/SecureObjectSync/SOSTransportCircle.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Identity.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" + +#import "Security/SecureObjectSync/SOSAccountGhost.h" +#import "Security/SecureObjectSync/SOSViews.h" + +static const char *concordstring[] = { + "kSOSConcordanceTrusted", + "kSOSConcordanceGenOld", // kSOSErrorReplay + "kSOSConcordanceNoUserSig", // kSOSErrorBadSignature + "kSOSConcordanceNoUserKey", // kSOSErrorNoKey + "kSOSConcordanceNoPeer", // kSOSErrorPeerNotFound + "kSOSConcordanceBadUserSig", // kSOSErrorBadSignature + "kSOSConcordanceBadPeerSig", // kSOSErrorBadSignature + "kSOSConcordanceNoPeerSig", + "kSOSConcordanceWeSigned", +}; + +@implementation SOSAccountTrustClassic (Circle) + +-(bool) isInCircle:(CFErrorRef *)error +{ + SOSCCStatus result = [self getCircleStatus:error]; + + if (result != kSOSCCInCircle) { + SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("Not in circle")); + return false; + } + + return true; +} + +-(bool) hasCircle:(CFErrorRef*) error +{ + if (!self.trustedCircle) + SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No trusted circle")); + + return self.trustedCircle != NULL; +} + +-(SOSCCStatus) thisDeviceStatusInCircle:(SOSCircleRef) circle peer:(SOSPeerInfoRef) this_peer +{ + if (!circle) + return kSOSCCNotInCircle; + + if (circle && SOSCircleCountPeers(circle) == 0) + return kSOSCCCircleAbsent; + + if (this_peer) { + + if(SOSPeerInfoIsRetirementTicket(this_peer)) + return kSOSCCNotInCircle; + + if (SOSCircleHasPeer(circle, this_peer, NULL)) + return kSOSCCInCircle; + + if (SOSCircleHasApplicant(circle, this_peer, NULL)) + return kSOSCCRequestPending; + } + + return kSOSCCNotInCircle; +} +-(SOSCCStatus) getCircleStatus:(CFErrorRef*) error +{ + return [self thisDeviceStatusInCircle:self.trustedCircle peer:self.peerInfo]; +} + + +-(SOSCircleRef) getCircle:(CFErrorRef *)error +{ + CFTypeRef entry = self.trustedCircle; + require_action_quiet(!isNull(entry), fail, + SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Incompatible circle in KVS"), NULL, error)); + return (SOSCircleRef) entry; + +fail: + return NULL; +} + + +//Circle + +-(SOSCircleRef) ensureCircle:(SOSAccount*)a name:(CFStringRef)name err:(CFErrorRef *)error +{ + CFErrorRef localError = NULL; + if (self.trustedCircle == NULL) { + self.trustedCircle = SOSCircleCreate(NULL, name, NULL); + a.key_interests_need_updating = true; + } + + require_action_quiet(self.trustedCircle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail, + if (error) { *error = localError; localError = NULL; }); + +fail: + CFReleaseNull(localError); + return self.trustedCircle; +} + +-(bool) hasLeft +{ + switch(self.departureCode) { + case kSOSDiscoveredRetirement: /* Fallthrough */ + case kSOSLostPrivateKey: /* Fallthrough */ + case kSOSWithdrewMembership: /* Fallthrough */ + case kSOSMembershipRevoked: /* Fallthrough */ + case kSOSLeftUntrustedCircle: + return true; + case kSOSNeverAppliedToCircle: /* Fallthrough */ + case kSOSNeverLeftCircle: /* Fallthrough */ + default: + return false; + } +} + +/* This check is new to protect piggybacking by the current peer - in that case we have a remote peer signature that + can't have ghost cleanup changing the circle hash. + */ + +-(bool) ghostBustingOK:(SOSCircleRef) oldCircle updatingTo:(SOSCircleRef) newCircle { + bool retval = false; + SOSFullPeerInfoRef me_full = self.fullPeerInfo; + if(!me_full) return false; + SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(me_full); + CFStringRef myPid = SOSPeerInfoGetPeerID(me); + CFDictionaryRef newSigs = SOSCircleCopyAllSignatures(newCircle); + bool iSignedNew = CFDictionaryGetCountOfKey(newSigs, myPid); + long otherPeerSigCount = CFDictionaryGetCount(newSigs) - ((iSignedNew) ? 2: 1); + + if (me && SOSCircleHasPeer(oldCircle, me, NULL) && SOSCircleHasPeer(newCircle, me, NULL)) { // If we're already in the old one we're not PBing + retval = true; + } else if (!iSignedNew) { // Piggybacking peers always have signed as part of genSigning - so this indicates we're safe to bust. + retval = true; + } else if(iSignedNew && otherPeerSigCount > 1) { // if others have seen this we're good to bust. + retval = true; + } + CFReleaseNull(newSigs); + return retval; +} + +// If this circle bears a signature from us and a newer gencount and it isn't our "current" circle, we're +// going to trust it. That's the signature of a piggybacked circle where we were the sponsor. + +-(bool) checkForSponsorshipTrust:(SOSCircleRef) prospective_circle { + if(CFEqualSafe(self.trustedCircle, prospective_circle)) return false; + SecKeyRef myPubKey = SOSFullPeerInfoCopyPubKey(self.fullPeerInfo, NULL); + if(!myPubKey) return false; + if(SOSCircleVerify(prospective_circle, myPubKey, NULL) && SOSCircleIsOlderGeneration(self.trustedCircle, prospective_circle)) { + [self setTrustedCircle:prospective_circle]; + return true; + } + return false; +} + +-(bool) handleUpdateCircle:(SOSCircleRef) prospective_circle transport:(SOSKVSCircleStorageTransport*)circleTransport update:(bool) writeUpdate err:(CFErrorRef*)error +{ + bool success = true; + bool haveOldCircle = true; + const char *local_remote = writeUpdate ? "local": "remote"; + + SOSAccount* account = [circleTransport getAccount]; + + secnotice("signing", "start:[%s]", local_remote); + if (!account.accountKey || !account.accountKeyIsTrusted) { + SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Can't handle updates with no trusted public key here"), NULL, error); + return false; + } + + if (!prospective_circle) { + secerror("##### Can't update to a NULL circle ######"); + return false; // Can't update one we don't have. + } + + // If this is a remote circle, check to see if this is our first opportunity to trust a circle where we + // sponsored the only signer. + if(!writeUpdate && [ self checkForSponsorshipTrust: prospective_circle ]){ + SOSCCEnsurePeerRegistration(); + account.key_interests_need_updating = true; + return true; + + } + + CFStringRef newCircleName = SOSCircleGetName(prospective_circle); + + SOSCircleRef oldCircle = self.trustedCircle; + SOSCircleRef emptyCircle = NULL; + + if(oldCircle == NULL) { + SOSCreateErrorWithFormat(kSOSErrorIncompatibleCircle, NULL, error, NULL, CFSTR("Current Entry is NULL; rejecting %@"), prospective_circle); + secerror("##### Can't replace circle - we don't care about it ######"); + return false; + } + if (CFGetTypeID(oldCircle) != SOSCircleGetTypeID()) { + secdebug("signing", ">>>>>>>>>>>>>>> Non-Circle Circle found <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); + // We don't know what is in our table, likely it was kCFNull indicating we didn't + // understand a circle that came by. We seem to like this one lets make our entry be empty circle + emptyCircle = SOSCircleCreate(kCFAllocatorDefault, newCircleName, NULL); + oldCircle = emptyCircle; + haveOldCircle = false; + // And we're paranoid, drop our old peer info if for some reason we didn't before. + // SOSAccountDestroyCirclePeerInfo(account, oldCircle, NULL); + } + + + SOSAccountScanForRetired(account, prospective_circle, error); + SOSCircleRef newCircle = SOSAccountCloneCircleWithRetirement(account, prospective_circle, error); + if(!newCircle) return false; + if([self ghostBustingOK: oldCircle updatingTo:newCircle]) { + SOSCircleRef ghostCleaned = SOSAccountCloneCircleWithoutMyGhosts(account, newCircle); + if(ghostCleaned) { + CFRetainAssign(newCircle, ghostCleaned); + writeUpdate = true; + } + } + + SOSFullPeerInfoRef me_full = self.fullPeerInfo; + SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(me_full); + CFStringRef myPeerID = SOSPeerInfoGetPeerID(me); + myPeerID = (myPeerID) ? myPeerID: CFSTR("No Peer"); + + if (me && SOSCircleUpdatePeerInfo(newCircle, me)) { + writeUpdate = true; // If we update our peer in the new circle we should write it if we accept it. + } + + typedef enum { + accept, + countersign, + leave, + revert, + ignore + } circle_action_t; + + static const char *actionstring[] = { + "accept", "countersign", "leave", "revert", "ignore", + }; + + circle_action_t circle_action = ignore; + enum DepartureReason leave_reason = kSOSNeverLeftCircle; + + SecKeyRef old_circle_key = NULL; + if(SOSCircleVerify(oldCircle, account.accountKey, NULL)){ + old_circle_key = account.accountKey; + } + else if(account.previousAccountKey && SOSCircleVerify(oldCircle, account.previousAccountKey, NULL)){ + old_circle_key = account.previousAccountKey; + } + + bool userTrustedOldCircle = (old_circle_key != NULL) && haveOldCircle; + + SOSConcordanceStatus concstat = + SOSCircleConcordanceTrust(oldCircle, newCircle, + 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; + } + + secnotice("signing", "Decided on action [%s] based on concordance state [%s] and [%s] circle. My PeerID is %@", actionstring[circle_action], concordstring[concstat], userTrustedOldCircle ? "trusted" : "untrusted", myPeerID); + + SOSCircleRef circleToPush = NULL; + + if (circle_action == leave) { + circle_action = ignore; (void) circle_action; // Acknowledge this is a dead store. + + if (me && SOSCircleHasPeer(oldCircle, me, NULL)) { + secnotice("account", "Leaving circle with peer %@", me); + debugDumpCircle(CFSTR("oldCircle"), oldCircle); + debugDumpCircle(CFSTR("newCircle"), newCircle); + debugDumpCircle(CFSTR("prospective_circle"), prospective_circle); + secnotice("account", "Key state: accountKey %@, previousAccountKey %@, old_circle_key %@", + account.accountKey, account.previousAccountKey, old_circle_key); + + if (sosAccountLeaveCircle(account, newCircle, error)) { + secnotice("leaveCircle", "Leaving circle by newcircle state"); + circleToPush = newCircle; + } else { + secnotice("signing", "Can't leave circle, but dumping identities"); + success = false; + } + self.departureCode = leave_reason; + circle_action = accept; + me = NULL; + me_full = NULL; + } else { + // We are not in this circle, but we need to update account with it, since we got it from cloud + secnotice("signing", "We are not in this circle, but we need to update account with it"); + debugDumpCircle(CFSTR("oldCircle"), oldCircle); + debugDumpCircle(CFSTR("newCircle"), newCircle); + debugDumpCircle(CFSTR("prospective_circle"), prospective_circle); + circle_action = accept; + } + } + + if (circle_action == countersign) { + if (me && SOSCircleHasPeer(newCircle, me, NULL)) { + if (SOSCircleVerifyPeerSigned(newCircle, me, NULL)) { + secnotice("signing", "Already concur with the new circle"); + } else { + CFErrorRef signing_error = NULL; + + if (me_full && SOSCircleConcordanceSign(newCircle, me_full, &signing_error)) { + circleToPush = newCircle; + secnotice("signing", "Concurred with new circle"); + } else { + secerror("Failed to concurrence sign, error: %@", signing_error); + success = false; + } + CFReleaseSafe(signing_error); + } + } else { + secnotice("signing", "Not countersigning, not in new circle"); + debugDumpCircle(CFSTR("circle to countersign"), newCircle); + } + circle_action = accept; + } + + if (circle_action == accept) { + if (me && SOSCircleHasActivePeer(oldCircle, me, NULL) && !SOSCircleHasPeer(newCircle, me, NULL)) { + // Don't destroy evidence of other code determining reason for leaving. + if(![self hasLeft]) self.departureCode = kSOSMembershipRevoked; + secnotice("account", "Member of old circle but not of new circle"); + debugDumpCircle(CFSTR("oldCircle"), oldCircle); + debugDumpCircle(CFSTR("newCircle"), newCircle); + } + + if (me + && SOSCircleHasActivePeer(oldCircle, me, NULL) + && !(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); + me = NULL; + me_full = NULL; + } + + if (me && SOSCircleHasRejectedApplicant(newCircle, me, NULL)) { + SOSPeerInfoRef reject = SOSCircleCopyRejectedApplicant(newCircle, me, NULL); + if(CFEqualSafe(reject, me) && SOSPeerInfoApplicationVerify(me, account.accountKey, NULL)) { + 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); + me = NULL; + me_full = NULL; + } else { + secnotice("circle", "Rejected, Reapplying (ID: %@) for circle '%@'", SOSPeerInfoGetPeerID(me), SOSCircleGetName(oldCircle)); + debugDumpCircle(CFSTR("oldCircle"), oldCircle); + debugDumpCircle(CFSTR("newCircle"), newCircle); + SOSCircleRequestReadmission(newCircle, account.accountKey, me, NULL); + writeUpdate = true; + } + } + + CFRetainSafe(oldCircle); + account.previousAccountKey = account.accountKey; + + secnotice("signing", "%@, Accepting new circle", concStr); + if (circle_action == accept) { + [self setTrustedCircle:newCircle]; + } + + if (me && account.accountKeyIsTrusted + && SOSCircleHasApplicant(oldCircle, me, NULL) + && SOSCircleCountPeers(newCircle) > 0 + && !SOSCircleHasPeer(newCircle, me, NULL) && !SOSCircleHasApplicant(newCircle, me, NULL)) { + // We weren't rejected (above would have set me to NULL. + // We were applying and we weren't accepted. + // Our application is declared lost, let us reapply. + + secnotice("signing", "requesting readmission to new circle"); + if (SOSCircleRequestReadmission(newCircle, account.accountKey, me, NULL)) + writeUpdate = true; + } + + if (me && SOSCircleHasActivePeer(oldCircle, me, NULL)) { + [account.trust cleanupRetirementTickets:account circle:oldCircle time:RETIREMENT_FINALIZATION_SECONDS err:NULL]; + } + + SOSAccountNotifyOfChange(account, oldCircle, newCircle); + + CFReleaseNull(oldCircle); + + if (writeUpdate) + circleToPush = newCircle; + account.key_interests_need_updating = true; + } + + /* + * In the revert section we'll guard the KVS idea of circles by rejecting "bad" new circles + * and pushing our current view of the circle (oldCircle). We'll only do this if we actually + * are a member of oldCircle - never for an empty circle. + */ + + if (circle_action == revert) { + if(haveOldCircle && me && SOSCircleHasActivePeer(oldCircle, me, NULL)) { + secnotice("signing", "%@, Rejecting new circle, re-publishing old circle", concStr); + debugDumpCircle(CFSTR("oldCircle"), oldCircle); + debugDumpCircle(CFSTR("newCircle"), newCircle); + circleToPush = oldCircle; + [self setTrustedCircle:oldCircle]; + } else { + secnotice("canary", "%@, Rejecting: new circle Have no old circle - would reset", concStr); + } + } + + + if (circleToPush != NULL) { + secnotice("signing", "Pushing:[%s]", local_remote); + CFDataRef circle_data = SOSCircleCopyEncodedData(circleToPush, kCFAllocatorDefault, error); + + if (circle_data) { + // Ensure we flush changes + account.circle_rings_retirements_need_attention = true; + + //posting new circle to peers + success &= [circleTransport postCircle:SOSCircleGetName(circleToPush) circleData:circle_data err:error]; + //cleanup old KVS keys + SOSAccountCleanupAllKVSKeys(account, error); + } else { + success = false; + } + CFReleaseNull(circle_data); + } + CFReleaseSafe(newCircle); + CFReleaseNull(emptyCircle); + + return success; +} + +-(bool) updateCircleFromRemote:(SOSKVSCircleStorageTransport*)circleTransport newCircle:(SOSCircleRef)newCircle err:(CFErrorRef*)error +{ + return [self handleUpdateCircle:newCircle transport:circleTransport update:false err:error]; +} + +-(bool) updateCircle:(SOSKVSCircleStorageTransport*)circleTransport newCircle:(SOSCircleRef) newCircle err:(CFErrorRef*)error +{ + return [self handleUpdateCircle:newCircle transport:circleTransport update:true err:error]; +} + +-(bool) modifyCircle:(SOSKVSCircleStorageTransport*)circleTransport err:(CFErrorRef*)error action:(SOSModifyCircleBlock)block +{ + bool success = false; + SOSCircleRef circleCopy = NULL; + require_action_quiet(self.trustedCircle, fail, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to get peer key from"))); + + circleCopy = SOSCircleCopyCircle(kCFAllocatorDefault, self.trustedCircle, error); + require_quiet(circleCopy, fail); + + success = true; + require_quiet(block(circleCopy), fail); + + success = [self updateCircle:circleTransport newCircle:circleCopy err:error]; + +fail: + CFReleaseSafe(circleCopy); + return success; + +} + +-(void) generationSignatureUpdateWith:(SOSAccount*)account key:(SecKeyRef) privKey +{ + if (self.trustedCircle && self.fullPeerInfo) { + [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle) { + SOSPeerInfoRef myPI = account.peerInfo; + bool iAmPeer = SOSCircleHasPeer(circle, myPI, NULL); + bool change = SOSCircleUpdatePeerInfo(circle, myPI); + if(iAmPeer && !SOSCircleVerify(circle, account.accountKey, NULL)) { + change |= [self upgradeiCloudIdentity:circle privKey:privKey]; + [self removeInvalidApplications:circle userPublic:account.accountKey]; + change |= SOSCircleGenerationSign(circle, privKey, self.fullPeerInfo, NULL); + [self setDepartureCode:kSOSNeverLeftCircle]; + } else if(iAmPeer) { + SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL); + if(!icfpi) { + SOSAccountRemoveIncompleteiCloudIdentities(account, circle, privKey, NULL); + change |= [self addiCloudIdentity:circle key:privKey err:NULL]; + } else { + CFReleaseNull(icfpi); + } + } + secnotice("updatingGenSignature", "we changed the circle? %@", change ? CFSTR("YES") : CFSTR("NO")); + return change; + }]; + } +} + +-(void) forEachCirclePeerExceptMe:(SOSIteratePeerBlock)block +{ + if (self.trustedCircle && self.peerInfo) { + NSString* myPi_id = self.peerID; + SOSCircleForEachPeer(self.trustedCircle, ^(SOSPeerInfoRef peer) { + CFStringRef peerID = SOSPeerInfoGetPeerID(peer); + if (peerID && ![myPi_id isEqualToString:(__bridge NSString*) peerID]) { + block(peer); + } + }); + } +} +-(bool) leaveCircle:(SOSAccount*)account err:(CFErrorRef*) error +{ + bool result = true; + secnotice("leaveCircle", "Leaving circle by client request"); + result &= [self modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { + return sosAccountLeaveCircle(account, circle, error); + }]; + + self.departureCode = kSOSWithdrewMembership; + + return result; +} + +-(bool) resetToOffering:(SOSAccountTransaction*) aTxn key:(SecKeyRef)userKey err:(CFErrorRef*) error +{ + SOSFullPeerInfoPurgePersistentKey(self.fullPeerInfo, NULL); + self.fullPeerInfo = nil; + + secnotice("resetToOffering", "Resetting circle to offering by request from client"); + + return userKey && [self resetCircleToOffering:aTxn userKey:userKey err:error]; +} + + +-(bool) resetCircleToOffering:(SOSAccountTransaction*) aTxn userKey:(SecKeyRef)user_key err:(CFErrorRef *)error +{ + bool result = false; + + SOSAccount* account = aTxn.account; + 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]) + return result; + + (void)[self resetAllRings:account err:error]; + + [self modifyCircle:account.circle_transport err:error action:^bool(SOSCircleRef circle) { + bool result = false; + SOSFullPeerInfoRef cloud_identity = NULL; + CFErrorRef localError = NULL; + + require_quiet(SOSCircleResetToOffering(circle, user_key, self.fullPeerInfo, &localError), err_out); + + self.departureCode = kSOSNeverLeftCircle; + + require_quiet([self addEscrowToPeerInfo:self.fullPeerInfo err:error], err_out); + + require_quiet([self addiCloudIdentity:circle key:user_key err:error], err_out); + result = true; + SOSAccountPublishCloudParameters(account, NULL); + + err_out: + if (result == false) + secerror("error resetting circle (%@) to offering: %@", circle, localError); + if (localError && error && *error == NULL) { + *error = localError; + localError = NULL; + } + CFReleaseNull(localError); + CFReleaseNull(cloud_identity); + return result; + }]; + + [self setValueInExpansion:kSOSUnsyncedViewsKey value:kCFBooleanTrue err:NULL]; + SOSAccountUpdateOutOfSyncViews(aTxn, SOSViewsGetAllCurrent()); + + result = true; + + return result; +} + +void SOSAccountForEachCirclePeerExceptMe(SOSAccount* account, void (^action)(SOSPeerInfoRef peer)) { + SOSPeerInfoRef myPi = account.peerInfo; + SOSCircleRef circle = NULL; + + SOSAccountTrustClassic *trust = account.trust; + circle = trust.trustedCircle; + if (circle && myPi) { + CFStringRef myPi_id = SOSPeerInfoGetPeerID(myPi); + SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { + CFStringRef peerID = SOSPeerInfoGetPeerID(peer); + if (peerID && !CFEqual(peerID, myPi_id)) { + action(peer); + } + }); + } +} + +-(bool) joinCircle:(SOSAccountTransaction*) aTxn userKey:(SecKeyRef) user_key useCloudPeer:(bool) use_cloud_peer err:(CFErrorRef*) error +{ + __block bool result = false; + __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); + + if (SOSCircleCountPeers(self.trustedCircle) == 0 || SOSAccountGhostResultsInReset(account)) { + secnotice("resetToOffering", "Resetting circle to offering since there are no peers"); + // this also clears initial sync data + result = [self resetCircleToOffering:aTxn userKey:user_key err:error]; + } else { + [self setValueInExpansion:kSOSUnsyncedViewsKey value:kCFBooleanTrue err:NULL]; + + if (use_cloud_peer) { + cloud_full_peer = SOSCircleCopyiCloudFullPeerInfoRef(self.trustedCircle, NULL); + } + + [self modifyCircle: account.circle_transport err:error action:^(SOSCircleRef circle) { + result = SOSAccountAddEscrowToPeerInfo(account, self.fullPeerInfo, error); + result &= SOSCircleRequestAdmission(circle, user_key, self.fullPeerInfo, error); + self.departureCode = kSOSNeverLeftCircle; + if(result && cloud_full_peer) { + CFErrorRef localError = NULL; + CFStringRef cloudid = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(cloud_full_peer)); + require_quiet(cloudid, finish); + require_quiet(SOSCircleHasActivePeerWithID(circle, cloudid, &localError), finish); + require_quiet(SOSCircleAcceptRequest(circle, user_key, cloud_full_peer, self.peerInfo, &localError), finish); + + finish: + if (localError){ + secerror("Failed to join with cloud identity: %@", localError); + CFReleaseNull(localError); + } + } + return result; + }]; + + if (use_cloud_peer) { + SOSAccountUpdateOutOfSyncViews(aTxn, SOSViewsGetAllCurrent()); + } + } + +fail: + CFReleaseNull(cloud_full_peer); + return result; +} + +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Expansion.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Expansion.h new file mode 100644 index 00000000..9a2e38d1 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Expansion.h @@ -0,0 +1,44 @@ +// +// SOSAccountTrustClassic+Expansion_h +// Security +// +// + +#ifndef SOSAccountTrustClassic_Expansion_h +#define SOSAccountTrustClassic_Expansion_h + + +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" + +#include +#import "Security/SecureObjectSync/SOSTransportCircleKVS.h" + +@interface SOSAccountTrustClassic (Expansion) + +//Expansion Dictionary +//ring handling +-(bool) updateV2Dictionary:(SOSAccount*)account v2:(CFDictionaryRef) newV2Dict; +-(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) leaveRing:(SOSKVSCircleStorageTransport*)circle_transport ring:(SOSRingRef) ring err:(CFErrorRef*) error; +-(bool) resetAccountToEmpty:(SOSAccount*)account transport: (SOSCircleStorageTransport*)circleTransport err:(CFErrorRef*) error; +-(SOSRingRef) copyRing:(CFStringRef) ringName err:(CFErrorRef *)error; +-(CFMutableDictionaryRef) getRings:(CFErrorRef *)error; +-(bool) forEachRing:(RingNameBlock)block; +-(bool) setRing:(SOSRingRef) addRing ringName:(CFStringRef) ringName err:(CFErrorRef*)error; +//generic expansion +-(bool) ensureExpansion:(CFErrorRef *)error; +-(bool) clearValueFromExpansion:(CFStringRef) key err:(CFErrorRef *)error; +-(bool) setValueInExpansion:(CFStringRef) key value:(CFTypeRef) value err:(CFErrorRef *)error; +-(CFTypeRef) getValueFromExpansion:(CFStringRef)key err:(CFErrorRef*)error; +-(void) setRings:(CFMutableDictionaryRef) newrings; +-(bool) valueSetContainsValue:(CFStringRef) key value:(CFTypeRef) value; +-(void) valueUnionWith:(CFStringRef) key valuesToUnion:(CFSetRef) valuesToUnion; +-(void) valueSubtractFrom:(CFStringRef) key valuesToSubtract:(CFSetRef) valuesToSubtract; +-(void) pendEnableViewSet:(CFSetRef) enabledViews; +-(bool) resetAllRings:(SOSAccount*)account err:(CFErrorRef *)error; +-(bool) checkForRings:(CFErrorRef*)error; + +@end + +#endif /* SOSAccountTrustClassic_Expansion_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Expansion.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Expansion.m new file mode 100644 index 00000000..08ce8cc4 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Expansion.m @@ -0,0 +1,635 @@ +// +// SOSAccountTrustClassicExpansion.m +// Security +// + + +#import +#import "Security/SecureObjectSync/SOSAccount.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#import "Security/SecureObjectSync/SOSViews.h" +#import "Security/SecureObjectSync/SOSPeerInfoV2.h" +#import "Security/SecureObjectSync/SOSTransportCircleKVS.h" + +@implementation SOSAccountTrustClassic (Expansion) +typedef enum { + accept, + countersign, + leave, + revert, + modify, + ignore +} ringAction_t; + +#if !defined(NDEBUG) +static const char *concordstring[] = { + "kSOSConcordanceTrusted", + "kSOSConcordanceGenOld", // kSOSErrorReplay + "kSOSConcordanceNoUserSig", // kSOSErrorBadSignature + "kSOSConcordanceNoUserKey", // kSOSErrorNoKey + "kSOSConcordanceNoPeer", // kSOSErrorPeerNotFound + "kSOSConcordanceBadUserSig", // kSOSErrorBadSignature + "kSOSConcordanceBadPeerSig", // kSOSErrorBadSignature + "kSOSConcordanceNoPeerSig", + "kSOSConcordanceWeSigned", +}; + +static const char * __unused actionstring[] = { + "accept", "countersign", "leave", "revert", "modify", "ignore", +}; +#endif +static NSString* kSOSRingKey = @"trusted_rings"; + +// +// Generic Calls to Expansion Dictionary +// +-(CFTypeRef) getValueFromExpansion:(CFStringRef)key err:(CFErrorRef*)error +{ + if (!self.expansion) { + return NULL; + } + return (__bridge CFTypeRef)([self.expansion objectForKey:(__bridge NSString*)key]); +} + +-(bool) ensureExpansion:(CFErrorRef *)error +{ + if (!self.expansion) { + self.expansion = [NSMutableDictionary dictionary]; + } + + return SecAllocationError((__bridge CFTypeRef)(self.expansion), error, CFSTR("Can't Alloc Account Expansion dictionary")); +} + +-(bool) clearValueFromExpansion:(CFStringRef) key err:(CFErrorRef *)error +{ + bool success = [self ensureExpansion:error]; + + require_quiet(success, errOut); + + [self.expansion removeObjectForKey: (__bridge NSString*)(key)]; +errOut: + return success; +} + +-(bool) setValueInExpansion:(CFStringRef) key value:(CFTypeRef) value err:(CFErrorRef *)error { + if (value == NULL) return [self clearValueFromExpansion:key err:error]; + + bool success = [self ensureExpansion:error]; + require_quiet(success, errOut); + + [self.expansion setObject:(__bridge id _Nonnull)(value) forKey:(__bridge NSString*)key]; + +errOut: + return success; +} + +-(bool) valueSetContainsValue:(CFStringRef) key value:(CFTypeRef) value +{ + CFSetRef foundSet = asSet([self getValueFromExpansion:key err:NULL], NULL); + return foundSet && CFSetContainsValue(foundSet, value); +} + +-(void) valueUnionWith:(CFStringRef) key valuesToUnion:(CFSetRef) valuesToUnion +{ + CFMutableSetRef unionedSet = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, valuesToUnion); + CFSetRef foundSet = asSet([self getValueFromExpansion:key err:NULL], NULL); + if (foundSet) { + CFSetUnion(unionedSet, foundSet); + } + [self setValueInExpansion:key value:unionedSet err:NULL]; + CFReleaseNull(unionedSet); +} + +-(void) valueSubtractFrom:(CFStringRef) key valuesToSubtract:(CFSetRef) valuesToSubtract +{ + CFSetRef foundSet = asSet([self getValueFromExpansion:key err:NULL], NULL); + if (foundSet) { + CFMutableSetRef subtractedSet = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, foundSet); + CFSetSubtract(subtractedSet, valuesToSubtract); + [self setValueInExpansion:key value:subtractedSet err:NULL]; + CFReleaseNull(subtractedSet); + } +} + +//Views +-(void) pendEnableViewSet:(CFSetRef) enabledViews +{ + if(CFSetGetValue(enabledViews, kSOSViewKeychainV0) != NULL) secnotice("viewChange", "Warning, attempting to Add KeychainV0"); + + [self valueUnionWith:kSOSPendingEnableViewsToBeSetKey valuesToUnion:enabledViews]; + [self valueSubtractFrom:kSOSPendingDisableViewsToBeSetKey valuesToSubtract:enabledViews]; +} + +// V2 Dictionary +-(bool) updateV2Dictionary:(SOSAccount*)account v2:(CFDictionaryRef) newV2Dict +{ + if(!newV2Dict) return true; + + [self setValueInExpansion:kSOSTestV2Settings value:newV2Dict err:NULL]; + + if (self.trustedCircle && self.fullPeerInfo + && SOSFullPeerInfoUpdateV2Dictionary(self.fullPeerInfo, newV2Dict, NULL)) { + [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) { + secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); + return SOSCircleUpdatePeerInfo(circle_to_change, account.peerInfo); + }]; + } + return true; +} + +// +// Rings +// + +-(bool) forEachRing:(RingNameBlock)block +{ + bool retval = false; + __block bool changed = false; + __block CFStringRef ringname = NULL; + __block CFDataRef ringder = NULL; + __block SOSRingRef ring = NULL; + __block SOSRingRef newring = NULL; + __block CFDataRef newringder = NULL; + + CFMutableDictionaryRef rings = [self getRings:NULL]; + CFMutableDictionaryRef ringscopy = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + if(!rings){ + CFReleaseNull(ringscopy); + return retval; + } + if(!ringscopy){ + CFReleaseNull(ringscopy); + return retval; + } + CFDictionaryForEach(rings, ^(const void *key, const void *value) { + ringname = (CFStringRef) key; + ringder = CFDataCreateCopy(kCFAllocatorDefault, (CFDataRef) value); + CFDictionaryAddValue(ringscopy, key, ringder); + ring = SOSRingCreateFromData(NULL, ringder); + newring = block(ringname, ring); + if(newring) { + newringder = SOSRingCopyEncodedData(newring, NULL); + CFDictionaryReplaceValue(ringscopy, key, newringder); + CFReleaseNull(newringder); + changed = true; + } + CFReleaseNull(ring); + CFReleaseNull(ringder); + CFReleaseNull(newring); + }); + if(changed) { + [self setRings:ringscopy]; + } + retval = true; + + CFReleaseNull(ringscopy); + return retval; +} + +-(bool) resetAllRings:(SOSAccount*)account err:(CFErrorRef *)error +{ + __block bool retval = true; + CFMutableSetRef ringList = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + if(!ringList){ + CFReleaseNull(ringList); + return retval; + } + + [self forEachRing: ^SOSRingRef(CFStringRef name, SOSRingRef ring) { + CFSetAddValue(ringList, name); + return NULL; // just using this to grab names. + }]; + + CFSetForEach(ringList, ^(const void *value) { + CFStringRef ringName = (CFStringRef) value; + retval = retval && [self resetRing:account ringName:ringName err:error]; + }); + + CFReleaseNull(ringList); + return retval; +} + +-(bool) resetAccountToEmpty:(SOSAccount*)account transport: (SOSCircleStorageTransport*)circleTransport err:(CFErrorRef*) error +{ + + __block bool result = true; + + result &= [self resetAllRings:account err:error]; + + self.fullPeerInfo = nil; + + self.departureCode = kSOSWithdrewMembership; + secnotice("resetToEmpty", "Reset Circle to empty by client request"); + + result &= [self modifyCircle:circleTransport err:error action:^bool(SOSCircleRef circle) { + result = SOSCircleResetToEmpty(circle, error); + return result; + }]; + + if (!result) { + secerror("error: %@", error ? *error : NULL); + } + return result; +} + +-(void) setRings:(CFMutableDictionaryRef) newrings +{ + [self.expansion setObject:(__bridge NSMutableDictionary*)newrings forKey:(kSOSRingKey)]; +} + +-(bool) checkForRings:(CFErrorRef*)error +{ + __block bool retval = true; + CFMutableDictionaryRef rings = [self getRings:NULL]; + if(rings && isDictionary(rings)) { + [self forEachRing:^SOSRingRef(CFStringRef ringname, SOSRingRef ring) { + if(retval == true) { + if(!SOSRingIsStable(ring)) { + retval = false; + secnotice("ring", "Ring %@ not stable", ringname); + } + } + return NULL; + }]; + } else { + SOSCreateError(kSOSErrorNotReady, CFSTR("Rings not present"), NULL, error); + retval = false; + } + return retval; +} + +-(bool) setRing:(SOSRingRef) addRing ringName:(CFStringRef) ringName err:(CFErrorRef*)error +{ + require_quiet(addRing, errOut); + CFMutableDictionaryRef rings = [self getRings:NULL]; + require_action_quiet(rings, errOut, SOSCreateError(kSOSErrorNoRing, CFSTR("No Rings found"), NULL, error)); + CFDataRef ringder = SOSRingCopyEncodedData(addRing, error); + require_quiet(ringder, errOut); + CFDictionarySetValue(rings, ringName, ringder); + CFReleaseNull(ringder); + return true; +errOut: + return false; +} + +static bool SOSAccountBackupSliceKeyBagNeedsFix(SOSAccount* account, SOSBackupSliceKeyBagRef bskb) { + + if (SOSBSKBIsDirect(bskb) || account.backup_key == NULL) + return false; + + CFSetRef peers = SOSBSKBGetPeers(bskb); + + /* first scan for retired peers, and kick'em out!*/ + SOSAccountIsPeerRetired(account, peers); + + bool needsFix = true; + + SOSPeerInfoRef myPeer = account.peerInfo; + if (myPeer) { + SOSPeerInfoRef meInBag = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer); + CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer); + CFDataRef meInBagBK = SOSPeerInfoCopyBackupKey(meInBag); + needsFix = !(meInBag && CFEqualSafe(myBK, + meInBagBK)); + CFReleaseNull(myBK); + CFReleaseNull(meInBagBK); + } + + CFDataRef rkbg = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL); + if(rkbg) needsFix |= !SOSBKSBPrefixedKeyIsInKeyBag(bskb, bskbRkbgPrefix, rkbg); + else needsFix |= SOSBSKBHasRecoveryKey(bskb); // if we don't have a recovery key - the bskb shouldn't + CFReleaseNull(rkbg); + + return needsFix; +} + +-(bool) handleUpdateRing:(SOSAccount*)account prospectiveRing:(SOSRingRef)prospectiveRing transport:(SOSKVSCircleStorageTransport*)circleTransport userPublicKey:(SecKeyRef)userPublic writeUpdate:(bool)writeUpdate err:(CFErrorRef *)error +{ + bool success = true; + bool haveOldRing = true; + + const char * __unused localRemote = writeUpdate ? "local": "remote"; + SOSFullPeerInfoRef fpi = self.fullPeerInfo; + SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); + CFStringRef peerID = SOSPeerInfoGetPeerID(pi); + bool peerActive = (fpi && pi && peerID && [self isInCircle:NULL]); + SOSRingRef newRing = NULL; + SOSRingRef oldRing = NULL; + + secdebug("ringSigning", "start:[%s] %@", localRemote, prospectiveRing); + + require_quiet(SOSAccountHasPublicKey(account, error), errOut); + + require_action_quiet(prospectiveRing, errOut, + SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("No Ring to work with"), NULL, error)); + + require_action_quiet(SOSRingIsStable(prospectiveRing), errOut, SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("You give rings a bad name"), NULL, error)); + + // We should at least have a sane ring system in the account object + require_quiet([self checkForRings:error], errOut); + + CFStringRef ringName = SOSRingGetName(prospectiveRing); + oldRing = [self copyRing:ringName err:NULL]; + + newRing = CFRetainSafe(prospectiveRing); // TODO: SOSAccountCloneRingWithRetirement(account, prospectiveRing, error); + + ringAction_t ringAction = ignore; + + bool userTrustedoldRing = true; + + CFSetRef peers = SOSCircleCopyPeers(self.trustedCircle, kCFAllocatorDefault); + + SecKeyRef oldKey = userPublic; + + if (!oldRing) { + oldRing = CFRetainSafe(newRing); + } + + SOSConcordanceStatus concstat = SOSRingConcordanceTrust(fpi, peers, oldRing, newRing, oldKey, userPublic, peerID, error); + CFReleaseNull(peers); + + CFStringRef concStr = NULL; + switch(concstat) { + case kSOSConcordanceTrusted: + ringAction = countersign; + concStr = CFSTR("Trusted"); + break; + case kSOSConcordanceGenOld: + ringAction = userTrustedoldRing ? revert : ignore; + concStr = CFSTR("Generation Old"); + break; + case kSOSConcordanceBadUserSig: + case kSOSConcordanceBadPeerSig: + ringAction = userTrustedoldRing ? revert : accept; + concStr = CFSTR("Bad Signature"); + break; + case kSOSConcordanceNoUserSig: + ringAction = userTrustedoldRing ? revert : accept; + concStr = CFSTR("No User Signature"); + break; + case kSOSConcordanceNoPeerSig: + ringAction = accept; // We might like this one eventually but don't countersign. + concStr = CFSTR("No trusted peer signature"); + secnotice("signing", "##### No trusted peer signature found, accepting hoping for concordance later %@", newRing); + break; + case kSOSConcordanceNoPeer: + ringAction = leave; + concStr = CFSTR("No trusted peer left"); + break; + case kSOSConcordanceNoUserKey: + secerror("##### No User Public Key Available, this shouldn't ever happen!!!"); + ringAction = ignore; + break; + + case kSOSConcordanceMissingMe: + case kSOSConcordanceImNotWorthy: + ringAction = modify; + concStr = CFSTR("Incorrect membership for me"); + break; + case kSOSConcordanceInvalidMembership: + ringAction = userTrustedoldRing ? revert : ignore; + concStr = CFSTR("Invalid Ring Membership"); + break; + default: + secerror("##### Bad Error Return from ConcordanceTrust"); + ringAction = ignore; + break; + } + + (void)concStr; + + secdebug("ringSigning", "Decided on action [%s] based on concordance state [%s] and [%s] circle.", actionstring[ringAction], concordstring[concstat], userTrustedoldRing ? "trusted" : "untrusted"); + + SOSRingRef ringToPush = NULL; + bool iWasInOldRing = peerID && SOSRingHasPeerID(oldRing, peerID); + bool iAmInNewRing = peerID && SOSRingHasPeerID(newRing, peerID); + bool ringIsBackup = SOSRingGetType(newRing) == kSOSRingBackup; + bool ringIsRecovery = SOSRingGetType(newRing) == kSOSRingRecovery; + + if (ringIsBackup && peerActive) { + if (ringAction == accept || ringAction == countersign) { + CFErrorRef localError = NULL; + SOSBackupSliceKeyBagRef bskb = SOSRingCopyBackupSliceKeyBag(newRing, &localError); + + if(!bskb) { + secnotice("ringSigning", "Backup ring with no backup slice keybag (%@)", localError); + } else if (SOSAccountBackupSliceKeyBagNeedsFix(account, bskb)) { + ringAction = modify; + } + CFReleaseSafe(localError); + CFReleaseSafe(bskb); + } + + if (ringAction == modify) { + CFErrorRef updateError = NULL; + [self setRing:newRing ringName:ringName err:error]; + + if(SOSAccountUpdateOurPeerInBackup(account, newRing, &updateError)) { + secdebug("signing", "Modified backup ring to include us"); + } else { + secerror("Could not add ourselves to the backup: (%@)", updateError); + } + CFReleaseSafe(updateError); + + // Fall through to normal modify handling. + } + } + + if (ringIsRecovery && peerActive && (ringAction == modify)) { + [self setRing:newRing ringName:ringName err:error]; + } + + + if (ringAction == modify) { + ringAction = ignore; + } + + if (ringAction == leave) { + if (iWasInOldRing) { + if ([self leaveRing:circleTransport ring:newRing err:error]){ + ringToPush = newRing; + } else { + secdebug("ringSigning", "Can't leave ring %@", oldRing); + success = false; + } + ringAction = accept; + } else { + // We are not in this ring, but we need to update account with it, since we got it from cloud + ringAction = accept; + } + } + + if (ringAction == countersign) { + if (iAmInNewRing) { + if (SOSRingPeerTrusted(newRing, fpi, NULL)) { + secdebug("ringSigning", "Already concur with: %@", newRing); + } else { + CFErrorRef signingError = NULL; + + if (fpi && SOSRingConcordanceSign(newRing, fpi, &signingError)) { + ringToPush = newRing; + } else { + secerror("Failed to concordance sign, error: %@ Old: %@ New: %@", signingError, oldRing, newRing); + success = false; + } + CFReleaseSafe(signingError); + } + } else { + secdebug("ringSigning", "Not countersigning, not in ring: %@", newRing); + } + ringAction = accept; + } + + if (ringAction == accept) { + if (iWasInOldRing && !iAmInNewRing) { + + // Don't destroy evidence of other code determining reason for leaving. + //if(!SOSAccountHasLeft(account)) account.departure_code = kSOSMembershipRevoked; + // TODO: LeaveReason for rings + } + + if (pi && SOSRingHasRejection(newRing, peerID)) { + // TODO: ReasonForLeaving for rings + SOSRingRemoveRejection(newRing, peerID); + } + + [self setRing:newRing ringName:ringName err:error]; + + if (pi && account.accountKeyIsTrusted + && SOSRingHasApplicant(oldRing, peerID) + && SOSRingCountPeers(newRing) > 0 + && !iAmInNewRing && !SOSRingHasApplicant(newRing, peerID)) { + // We weren't rejected (above would have set me to NULL. + // We were applying and we weren't accepted. + // Our application is declared lost, let us reapply. + + if (SOSRingApply(newRing, userPublic, fpi, NULL)) + if(peerActive) writeUpdate = true; + } + + if (pi && SOSRingHasPeerID(oldRing, peerID)) { + [self cleanupRetirementTickets:account circle:self.trustedCircle time:RETIREMENT_FINALIZATION_SECONDS err:NULL]; + } + + + account.circle_rings_retirements_need_attention = true; + + if (writeUpdate) + ringToPush = newRing; + account.key_interests_need_updating = true; + } + + /* + * In the revert section we'll guard the KVS idea of circles by rejecting "bad" new rings + * and pushing our current view of the ring (oldRing). We'll only do this if we actually + * are a member of oldRing - never for an empty ring. + */ + + if (ringAction == revert) { + if(haveOldRing && peerActive && SOSRingHasPeerID(oldRing, peerID)) { + secdebug("ringSigning", "%@, Rejecting: %@ re-publishing %@", concStr, newRing, oldRing); + ringToPush = oldRing; + } else { + secdebug("ringSigning", "%@, Rejecting: %@ Have no old circle - would reset", concStr, newRing); + } + } + + + if (ringToPush != NULL) { + secdebug("ringSigning", "Pushing:[%s] %@", localRemote, ringToPush); + CFDataRef ringData = SOSRingCopyEncodedData(ringToPush, error); + if (ringData) { + success &= [circleTransport kvsRingPostRing:SOSRingGetName(ringToPush) ring:ringData err:error]; + } else { + success = false; + } + CFReleaseNull(ringData); + } + CFReleaseNull(oldRing); + CFReleaseNull(newRing); + return success; +errOut: + CFReleaseNull(oldRing); + CFReleaseNull(newRing); + return false; + +} + +-(SOSRingRef) copyRing:(CFStringRef)ringName err:(CFErrorRef *)error +{ + CFMutableDictionaryRef rings = [self getRings:error]; + require_action_quiet(rings, errOut, SOSCreateError(kSOSErrorNoRing, CFSTR("No Rings found"), NULL, error)); + CFTypeRef ringder = CFDictionaryGetValue(rings, ringName); + require_action_quiet(ringder, errOut, SOSCreateError(kSOSErrorNoRing, CFSTR("No Ring found"), NULL, error)); + SOSRingRef ring = SOSRingCreateFromData(NULL, ringder); + return (SOSRingRef) ring; + +errOut: + return NULL; +} + +-(CFMutableDictionaryRef) getRings:(CFErrorRef *)error +{ + CFMutableDictionaryRef rings = (__bridge CFMutableDictionaryRef) [self.expansion objectForKey:kSOSRingKey]; + if(!rings) { + [self addRingDictionary]; + rings = [self getRings:error]; + } + + return rings; +} + +-(bool) resetRing:(SOSAccount*)account ringName:(CFStringRef) ringName err:(CFErrorRef *)error +{ + bool retval = false; + + SOSRingRef ring = [self copyRing:ringName err:error]; + SOSRingRef newring = SOSRingCreate(ringName, NULL, SOSRingGetType(ring), error); + SOSRingGenerationCreateWithBaseline(newring, ring); + SOSBackupRingSetViews(newring, self.fullPeerInfo, SOSBackupRingGetViews(ring, NULL), error); + require_quiet(newring, errOut); + CFReleaseNull(ring); + retval = SOSAccountUpdateRing(account, newring, error); +errOut: + CFReleaseNull(newring); + return retval; +} + +-(bool) leaveRing:(SOSKVSCircleStorageTransport*)circle_transport ring:(SOSRingRef) ring err:(CFErrorRef*) error +{ + SOSFullPeerInfoRef fpi = self.fullPeerInfo; + if(!fpi) return false; + SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); + CFStringRef peerID = SOSPeerInfoGetPeerID(pi); + + CFErrorRef localError = NULL; + + bool retval = false; + bool writeRing = false; + bool writePeerInfo = false; + + if(SOSRingHasPeerID(ring, peerID)) { + writePeerInfo = true; + } + + if(writePeerInfo || writeRing) { + SOSRingWithdraw(ring, NULL, fpi, error); + } + + if (writeRing) { + CFDataRef ring_data = SOSRingCopyEncodedData(ring, error); + + if (ring_data) { + [circle_transport kvsRingPostRing:SOSRingGetName(ring) ring:ring_data err:NULL]; + } + CFReleaseNull(ring_data); + } + retval = true; + CFReleaseNull(localError); + return retval; +} + +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Identity.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Identity.h new file mode 100644 index 00000000..de6856c0 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Identity.h @@ -0,0 +1,26 @@ +// +// SOSAccountTrustClassic+Identity.h +// Security +// + +#ifndef SOSAccountTrustClassic_Identity_h +#define SOSAccountTrustClassic_Identity_h + +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" + +@class SOSAccountTrustClassic; + +@interface SOSAccountTrustClassic (Identity) +//FullPeerInfo +-(bool) updateFullPeerInfo:(SOSAccount*)account minimum:(CFSetRef)minimumViews excluded:(CFSetRef)excludedViews; +-(SOSFullPeerInfoRef) getMyFullPeerInfo; +-(bool) fullPeerInfoVerify:(SecKeyRef) privKey err:(CFErrorRef *)error; +-(bool) hasFullPeerInfo:(CFErrorRef*) error; +-(SOSFullPeerInfoRef) CopyAccountIdentityPeerInfo; +-(bool) ensureFullPeerAvailable:(CFDictionaryRef)gestalt deviceID:(CFStringRef)deviceID backupKey:(CFDataRef)backup err:(CFErrorRef *) error; +-(bool) isMyPeerActive:(CFErrorRef*) error; +-(void) purgeIdentity; +@end + + +#endif /* SOSAccountTrustClassic_Identity_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Identity.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Identity.m new file mode 100644 index 00000000..fb446c1f --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Identity.m @@ -0,0 +1,131 @@ + // +// SOSAccountTrustClassicIdentity.m +// Security +// + + +#import +#include +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Identity.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h" + +#import "Security/SecureObjectSync/SOSViews.h" + +@implementation SOSAccountTrustClassic (Identity) + +-(bool) updateFullPeerInfo:(SOSAccount*)account minimum:(CFSetRef)minimumViews excluded:(CFSetRef)excludedViews +{ + if (self.trustedCircle && self.fullPeerInfo) { + if(SOSFullPeerInfoUpdateToCurrent(self.fullPeerInfo, minimumViews, excludedViews)) { + [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) { + secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); + return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo); + }]; + } + } + + return true; +} + +-(SOSFullPeerInfoRef) getMyFullPeerInfo +{ + return self.trustedCircle ? self.fullPeerInfo : NULL; +} + +-(bool) fullPeerInfoVerify:(SecKeyRef) privKey err:(CFErrorRef *)error +{ + if(!self.fullPeerInfo) return false; + SecKeyRef pubKey = SecKeyCreatePublicFromPrivate(privKey); + bool retval = SOSPeerInfoApplicationVerify(self.peerInfo, pubKey, error); + CFReleaseNull(pubKey); + return retval; +} + +-(bool) hasFullPeerInfo:(CFErrorRef*) error +{ + bool hasPeer = false; + if(![self hasCircle:error]){ + return hasPeer; + } + hasPeer = self.fullPeerInfo != NULL; + + if (!hasPeer) + SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("No peer for circle")); + + return hasPeer; +} + +-(SOSFullPeerInfoRef) CopyAccountIdentityPeerInfo +{ + return SOSFullPeerInfoCopyFullPeerInfo(self.fullPeerInfo); +} + +-(bool) ensureFullPeerAvailable:(CFDictionaryRef)gestalt deviceID:(CFStringRef)deviceID backupKey:(CFDataRef)backup err:(CFErrorRef *) error +{ + require_action_quiet(self.trustedCircle, fail, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("Don't have circle"))); + + if (self.fullPeerInfo == NULL) { + CFStringRef keyName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("ID for %@-%@"), SOSPeerGestaltGetName(gestalt), SOSCircleGetName(self.trustedCircle)); + SecKeyRef full_key = GeneratePermanentFullECKey(256, keyName, error); + + NSString* octagonKeyName = [@"Octagon " stringByAppendingString:(__bridge NSString*)keyName]; + SecKeyRef octagonFullKey = GeneratePermanentFullECKey(384, (__bridge CFStringRef)octagonKeyName, error); + + if (full_key && octagonFullKey) { + CFSetRef initialViews = SOSViewCopyViewSet(kViewSetInitial); + + self.fullPeerInfo = nil; + self.fullPeerInfo = SOSFullPeerInfoCreateWithViews(kCFAllocatorDefault, gestalt, backup, initialViews, full_key,octagonFullKey, error); + CFDictionaryRef v2dictionaryTestUpdates = [self getValueFromExpansion:kSOSTestV2Settings err:NULL]; + if(v2dictionaryTestUpdates) SOSFullPeerInfoUpdateV2Dictionary(self.fullPeerInfo, v2dictionaryTestUpdates, NULL); + CFReleaseNull(initialViews); + CFReleaseNull(full_key); + + CFSetRef pendingDefaultViews = SOSViewCopyViewSet(kViewSetDefault); + [self pendEnableViewSet:pendingDefaultViews]; + CFReleaseNull(pendingDefaultViews); + + [self setValueInExpansion:kSOSUnsyncedViewsKey value:kCFBooleanTrue err:NULL]; + + if (!self.fullPeerInfo) { + secerror("Can't make FullPeerInfo for %@-%@ (%@) - is AKS ok?", SOSPeerGestaltGetName(gestalt), SOSCircleGetName(self.trustedCircle), error ? (void*)*error : (void*)CFSTR("-")); + } + else{ + secnotice("fpi", "alert KeychainSyncingOverIDSProxy the fpi is available"); + notify_post(kSecServerPeerInfoAvailable); + if(deviceID) + SOSFullPeerInfoUpdateDeviceID(self.fullPeerInfo, deviceID, error); + } + } + else { + secerror("No full_key: %@:", error ? *error : NULL); + + } + + CFReleaseNull(keyName); + } + +fail: + return self.fullPeerInfo != NULL; +} +-(bool) isMyPeerActive:(CFErrorRef*) error +{ + return (self.peerInfo ? SOSCircleHasActivePeer(self.trustedCircle, self.peerInfo, error) : false); +} + +-(void) purgeIdentity +{ + if (self.fullPeerInfo) { + // 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); + } + CFReleaseNull(purgeError); + + self.fullPeerInfo=nil; + } +} +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Retirement.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Retirement.h new file mode 100644 index 00000000..f2ee2dcf --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Retirement.h @@ -0,0 +1,17 @@ +// +// SOSAccountTrustClassic+Retirement.h +// Security +// + +#ifndef SOSAccountTrustClassic_Retirement_h +#define SOSAccountTrustClassic_Retirement_h + +#import "Security/SecureObjectSync/SOSTransportCircleKVS.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" + +@interface SOSAccountTrustClassic (Retirement) +//Retirement +-(bool) cleanupAfterPeer:(SOSMessageKVS*)kvsTransport circleTransport:(SOSCircleStorageTransport*)circleTransport seconds:(size_t) seconds circle:(SOSCircleRef) circle cleanupPeer:(SOSPeerInfoRef) cleanupPeer err:(CFErrorRef*) error; +-(bool) cleanupRetirementTickets:(SOSAccount*)account circle:(SOSCircleRef)circle time:(size_t) seconds err:(CFErrorRef*) error; +@end +#endif /* SOSAccountTrustClassic_Retirement_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Retirement.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Retirement.m new file mode 100644 index 00000000..fbdde2e6 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic+Retirement.m @@ -0,0 +1,106 @@ +// +// SOSAccountTrustClassicRetirement.m +// Security +// +// Created by Michelle Auricchio on 12/27/16. +// +// + +#import +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" +#import "Security/SecureObjectSync/SOSPeerInfoCollections.h" +#import "Security/SecureObjectSync/SOSTransportMessageKVS.h" + +@implementation SOSAccountTrustClassic (Retirement) + +-(bool) cleanupRetirementTickets:(SOSAccount*)account circle:(SOSCircleRef)circle time:(size_t) seconds err:(CFErrorRef*) error +{ + CFMutableSetRef retirees_to_remove = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); + + __block bool success = true; + + CFSetForEach((__bridge CFSetRef)(self.retirees), ^(const void *value) { + SOSPeerInfoRef retiree = (SOSPeerInfoRef) value; + + if (retiree) { + // Remove the entry if it's not a retired peer or if it's retirment ticket has expired AND he's no longer in the circle. + if (!SOSPeerInfoIsRetirementTicket(retiree) || + (SOSPeerInfoRetireRetirementTicket(seconds, retiree) && !SOSCircleHasActivePeer(circle, retiree, NULL))) { + CFSetAddValue(retirees_to_remove, retiree); + }; + } + }); + + CFMutableArrayRef retirees_to_cleanup = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetForEach(retirees_to_remove, ^(const void *value) { + CFArrayAppendValue(retirees_to_cleanup, value); + CFSetRemoveValue((__bridge CFMutableSetRef)self.retirees, value); + }); + + CFReleaseNull(retirees_to_remove); + + CFDictionaryRef retirements_to_remove = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + SOSCircleGetName(circle), retirees_to_cleanup, + NULL); + + CFReleaseNull(retirees_to_cleanup); + + success = [account.circle_transport expireRetirementRecords:retirements_to_remove err:error]; + + CFReleaseNull(retirements_to_remove); + + return success; +} + +static inline CFMutableArrayRef CFDictionaryEnsureCFArrayAndGetCurrentValue(CFMutableDictionaryRef dict, CFTypeRef key) +{ + CFMutableArrayRef result = (CFMutableArrayRef) CFDictionaryGetValue(dict, key); + + if (!isArray(result)) { + result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionarySetValue(dict, key, result); + CFReleaseSafe(result); + } + + return result; +} + + +-(bool) cleanupAfterPeer:(SOSMessageKVS*)kvsTransport circleTransport:(SOSCircleStorageTransport*)circleTransport seconds:(size_t) seconds circle:(SOSCircleRef) circle cleanupPeer:(SOSPeerInfoRef) cleanupPeer err:(CFErrorRef*) error +{ + bool success = true; + + SOSPeerInfoRef myPeerInfo = self.peerInfo; + require_action_quiet(self.fullPeerInfo && myPeerInfo, xit, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("I have no peer"))); + require_quiet(SOSCircleHasActivePeer(circle, self.peerInfo, error), xit); + + CFStringRef cleanupPeerID = SOSPeerInfoGetPeerID(cleanupPeer); + + CFStringRef circle_name = SOSCircleGetName(circle); + + CFMutableDictionaryRef circleToPeerIDs = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFArrayAppendValue(CFDictionaryEnsureCFArrayAndGetCurrentValue(circleToPeerIDs, circle_name), cleanupPeerID); + + CFErrorRef localError = NULL; + + if (!(success &= [kvsTransport SOSTransportMessageCleanupAfterPeerMessages:kvsTransport peers:circleToPeerIDs err:&localError])) { + secnotice("account", "Failed to cleanup after peer %@ messages: %@", cleanupPeerID, localError); + } + + CFReleaseNull(localError); + + if((success &= SOSPeerInfoRetireRetirementTicket(seconds, cleanupPeer))) { + + if (!(success &= [circleTransport expireRetirementRecords:circleToPeerIDs err:&localError])) { + secnotice("account", "Failed to cleanup after peer %@ retirement: %@", cleanupPeerID, localError); + } + } + CFReleaseNull(localError); + CFReleaseNull(circleToPeerIDs); + +xit: + return success; +} + +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic.h new file mode 100644 index 00000000..28c0cfb7 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic.h @@ -0,0 +1,68 @@ +// +// SOSAccountTrustClassic.h +// Security +// + +#ifndef SOSAccountTrustClassic_h +#define SOSAccountTrustClassic_h + +#import +#import "Security/SecureObjectSync/SOSAccountTrust.h" +#import "Security/SecureObjectSync/SOSTypes.h" +#import "Security/SecureObjectSync/SOSTransportCircleKVS.h" +@class SOSAccount; + +@interface SOSAccountTrustClassic : SOSAccountTrust + ++(instancetype)trustClassic; + + +//Security Properties +-(SOSSecurityPropertyResultCode) UpdateSecurityProperty:(SOSAccount*)account property:(CFStringRef)property code:(SOSSecurityPropertyActionCode)actionCode err:(CFErrorRef*)error; +-(SOSSecurityPropertyResultCode) SecurityPropertyStatus:(CFStringRef)property err:(CFErrorRef *)error; + +//Gestalt Dictionary +-(bool) updateGestalt:(SOSAccount*)account newGestalt:(CFDictionaryRef) new_gestalt; + +//Peers +-(SOSPeerInfoRef) copyPeerWithID:(CFStringRef) peerid err:(CFErrorRef *)error; +-(bool) isAccountIdentity:(SOSPeerInfoRef)peerInfo err:(CFErrorRef *)error; +-(SecKeyRef) copyPublicKeyForPeer:(CFStringRef) peer_id err:(CFErrorRef *)error; +-(CFSetRef) copyPeerSetMatching:(SOSModifyPeerBlock)block; +-(CFArrayRef) copyPeersToListenTo:(SecKeyRef)userPublic err:(CFErrorRef *)error; +-(bool) peerSignatureUpdate:(SecKeyRef)privKey err:(CFErrorRef *)error; +-(bool) updatePeerInfo:(SOSKVSCircleStorageTransport*)circleTransport description:(CFStringRef)updateDescription err:(CFErrorRef *)error update:(SOSModifyPeerInfoBlock)block; +-(bool) addEscrowToPeerInfo:(SOSFullPeerInfoRef) myPeer err:(CFErrorRef *)error; + +//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) updateViewSets:(SOSAccount*)account enabled:(CFSetRef) origEnabledViews disabled:(CFSetRef) origDisabledViews; +-(CFSetRef) copyPeerSetForView:(CFStringRef) viewName; +-(void) peerGotInSync:(SOSAccountTransaction*) aTxn peerID:(CFStringRef) peerID views:(CFSetRef) views; + +//DER +-(size_t) getDEREncodedSize:(SOSAccount*)account err:(NSError**)error; +-(uint8_t*) encodeToDER:(SOSAccount*)account err:(NSError**) error start:(const uint8_t*) der end:(uint8_t*)der_end; + +//Syncing +-(CFMutableSetRef) CF_RETURNS_RETAINED syncWithPeers:(SOSAccountTransaction*) txn peerIDs:(CFSetRef) /* CFStringRef */ peerIDs err:(CFErrorRef *)error; +-(bool) requestSyncWithAllPeers:(SOSAccountTransaction*) txn key:(SecKeyRef)userPublic err:(CFErrorRef *)error; +-(SOSEngineRef) getDataSourceEngine:(SOSDataSourceFactoryRef)factory; + + +-(bool) postDebugScope:(SOSCircleStorageTransport*) circle_transport scope:(CFTypeRef) scope err:(CFErrorRef*)error; +-(SecKeyRef) copyDeviceKey:(CFErrorRef *)error; +-(void) addSyncablePeerBlock:(SOSAccountTransaction*)a dsName:(CFStringRef) ds_name change:(SOSAccountSyncablePeersBlock) changeBlock; +-(bool) clientPing:(SOSAccount*)account; +-(void) removeInvalidApplications:(SOSCircleRef) circle userPublic:(SecKeyRef)userPublic; + +-(bool) addiCloudIdentity:(SOSCircleRef) circle key:(SecKeyRef) userKey err:(CFErrorRef*)error; +-(bool) removeIncompleteiCloudIdentities:(SOSCircleRef) circle privKey:(SecKeyRef) privKey err:(CFErrorRef *)error; +-(bool) upgradeiCloudIdentity:(SOSCircleRef) circle privKey:(SecKeyRef) privKey; +-(CFMutableSetRef) copyPreApprovedHSA2Info; + +-(void) addRingDictionary; + +@end +#endif /* SOSAccountTrustClassic_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic.m new file mode 100644 index 00000000..7c401525 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustClassic.m @@ -0,0 +1,820 @@ +// +// SOSAccountTrustClassic.m +// Security +// + +#import +#import "Security/SecureObjectSync/SOSAccount.h" +#import "Security/SecureObjectSync/SOSViews.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Identity.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" + +#import "Security/SecureObjectSync/SOSPeerInfoV2.h" +#import "Security/SecureObjectSync/SOSPeerInfoCollections.h" +#import "Security/SecureObjectSync/SOSTransportMessageKVS.h" +#import "Security/SecureObjectSync/SOSTransportMessageIDS.h" + +#include +#include +#include +#include + +#include +#include +#include + +@implementation SOSAccountTrustClassic +extern CFStringRef kSOSAccountDebugScope; + ++(instancetype)trustClassic +{ + return [[self alloc] init]; +} + +-(id)init +{ + self = [super init]; + if(self) + { + self.retirees = [NSMutableSet set]; + self.fullPeerInfo = NULL; + self.trustedCircle = NULL; + self.departureCode = kSOSDepartureReasonError; + self.expansion = [NSMutableDictionary dictionary]; + [self addRingDictionary]; + } + return self; +} + +-(id)initWithRetirees:(NSMutableSet*)r fpi:(SOSFullPeerInfoRef)fpi circle:(SOSCircleRef) trusted_circle + departureCode:(enum DepartureReason)code peerExpansion:(NSMutableDictionary*)e +{ + self = [super init]; + if(self) + { + self.retirees = [[NSMutableSet alloc] initWithSet:r] ; + self.fullPeerInfo = CFRetainSafe(fpi); + self.trustedCircle = CFRetainSafe(trusted_circle); + self.departureCode = code; + self.expansion = [[NSMutableDictionary alloc]initWithDictionary:e]; + + [self addRingDictionary]; + } + return self; + + +} +-(SOSSecurityPropertyResultCode) UpdateSecurityProperty:(SOSAccount*)account property:(CFStringRef)property code:(SOSSecurityPropertyActionCode)actionCode err:(CFErrorRef*)error +{ + SOSSecurityPropertyResultCode retval = kSOSCCGeneralSecurityPropertyError; + bool updateCircle = false; + + require_action_quiet(self.trustedCircle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error)); + require_action_quiet(self.fullPeerInfo, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error)); + retval = SOSFullPeerInfoUpdateSecurityProperty(self.fullPeerInfo, actionCode, property, error); + + if(actionCode == kSOSCCSecurityPropertyEnable && retval == kSOSCCSecurityPropertyValid) { + updateCircle = true; + } else if(actionCode == kSOSCCSecurityPropertyDisable && retval == kSOSCCSecurityPropertyNotValid) { + updateCircle = true; + } else if(actionCode == kSOSCCSecurityPropertyPending) { + updateCircle = true; + } + + if (updateCircle) { + [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) { + secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for security property change"); + return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo); + }]; + } + +errOut: + return retval; +} + +-(SOSSecurityPropertyResultCode) SecurityPropertyStatus:(CFStringRef)property err:(CFErrorRef *)error +{ + SOSSecurityPropertyResultCode retval = kSOSCCGeneralViewError; + require_action_quiet(self.trustedCircle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error)); + require_action_quiet(self.fullPeerInfo, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error)); + retval = SOSFullPeerInfoSecurityPropertyStatus(self.fullPeerInfo, property, error); +errOut: + return retval; +} + + +-(bool) updateGestalt:(SOSAccount*)account newGestalt:(CFDictionaryRef)new_gestalt +{ + if (CFEqualSafe(new_gestalt, (__bridge CFDictionaryRef)(account.gestalt))) + return false; + + if (self.trustedCircle && self.fullPeerInfo + && SOSFullPeerInfoUpdateGestalt(self.fullPeerInfo, new_gestalt, NULL)) { + [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) { + secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); + return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo); + }]; + } + + account.gestalt = [[NSDictionary alloc] initWithDictionary:(__bridge NSDictionary * _Nonnull)(new_gestalt)]; + return true; +} + +-(SOSViewResultCode) updateView:(SOSAccount*)account name:(CFStringRef) viewname code:(SOSViewActionCode) actionCode err:(CFErrorRef *)error +{ + SOSViewResultCode retval = kSOSCCGeneralViewError; + SOSViewResultCode currentStatus = kSOSCCGeneralViewError; + bool alreadyInSync = SOSAccountHasCompletedInitialSync(account); + + bool updateCircle = false; + require_action_quiet(self.trustedCircle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error)); + require_action_quiet(self.fullPeerInfo, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error)); + require_action_quiet((actionCode == kSOSCCViewEnable) || (actionCode == kSOSCCViewDisable), errOut, CFSTR("Invalid View Action")); + currentStatus = [account.trust viewStatus:account name:viewname err:error]; + require_action_quiet((currentStatus == kSOSCCViewNotMember) || (currentStatus == kSOSCCViewMember), errOut, CFSTR("View Membership Not Actionable")); + + if (CFEqualSafe(viewname, kSOSViewKeychainV0)) { + retval = SOSAccountVirtualV0Behavior(account, actionCode); + } else if ([account.trust isSyncingV0] && SOSViewsIsV0Subview(viewname)) { + // Subviews of V0 syncing can't be turned off if V0 is on. + require_action_quiet(actionCode = kSOSCCViewDisable, errOut, CFSTR("Have V0 peer can't disable")); + retval = kSOSCCViewMember; + } else { + CFMutableSetRef pendingSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(pendingSet, viewname); + + if(actionCode == kSOSCCViewEnable && currentStatus == kSOSCCViewNotMember) { + if(alreadyInSync) { + retval = SOSFullPeerInfoUpdateViews(self.fullPeerInfo, actionCode, viewname, error); + if(retval == kSOSCCViewMember) updateCircle = true; + } else { + [self pendEnableViewSet:pendingSet]; + retval = kSOSCCViewMember; + updateCircle = false; + } + } else if(actionCode == kSOSCCViewDisable && currentStatus == kSOSCCViewMember) { + if(alreadyInSync) { + retval = SOSFullPeerInfoUpdateViews(self.fullPeerInfo, actionCode, viewname, error); + if(retval == kSOSCCViewNotMember) updateCircle = true; + } else { + SOSAccountPendDisableViewSet(account, pendingSet); + retval = kSOSCCViewNotMember; + updateCircle = false; + } + } else { + retval = currentStatus; + } + CFReleaseNull(pendingSet); + + if (updateCircle) { + [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) { + secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for views change"); + return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo); + }]; + } + } + +errOut: + return retval; +} + +-(bool) activeValidInCircle:(SOSAccount*) account err:(CFErrorRef *)error { + return SOSCircleHasActiveValidPeer(self.trustedCircle, SOSFullPeerInfoGetPeerInfo(self.fullPeerInfo), SOSAccountGetTrustedPublicCredential(account, error), error); +} + +-(SOSViewResultCode) viewStatus:(SOSAccount*)account name:(CFStringRef) viewname err:(CFErrorRef *)error +{ + SOSViewResultCode retval = kSOSCCGeneralViewError; + + require_action_quiet(self.trustedCircle, errOut, SOSCreateError(kSOSErrorNoCircle, CFSTR("No Trusted Circle"), NULL, error)); + require_action_quiet(self.fullPeerInfo, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, error)); + require_action_quiet([self activeValidInCircle: account err: error ], + errOut, SOSCreateError(kSOSErrorNotInCircle, CFSTR("Not in Circle"), NULL, error)); + + if ([self valueSetContainsValue:kSOSPendingEnableViewsToBeSetKey value:viewname]) { + retval = kSOSCCViewMember; + } else if ([self valueSetContainsValue:kSOSPendingDisableViewsToBeSetKey value:viewname]) { + retval = kSOSCCViewNotMember; + } else { + retval = SOSFullPeerInfoViewStatus(self.fullPeerInfo, viewname, error); + } + + // If that doesn't say we're a member and this view is a V0 subview, and we're syncing V0 views we are a member + if (retval != kSOSCCViewMember) { + if ((CFEqualSafe(viewname, kSOSViewKeychainV0) || SOSViewsIsV0Subview(viewname)) + && [account.trust isSyncingV0]) { + retval = kSOSCCViewMember; + } + } + + // If we're only an applicant we report pending if we would be a view member + if (retval == kSOSCCViewMember) { + bool isApplicant = SOSCircleHasApplicant(self.trustedCircle, self.peerInfo, error); + if (isApplicant) { + retval = kSOSCCViewPending; + } + } + +errOut: + return retval; +} + +static void dumpViewSet(CFStringRef label, CFSetRef views) { + if(views) { + CFStringSetPerformWithDescription(views, ^(CFStringRef description) { + secnotice("circleChange", "%@ list: %@", label, description); + }); + } else { + secnotice("circleChange", "No %@ list provided.", label); + } +} + +static bool SOSAccountScreenViewListForValidV0(SOSAccount* account, CFMutableSetRef viewSet, SOSViewActionCode actionCode) { + bool retval = true; + if(viewSet && CFSetContainsValue(viewSet, kSOSViewKeychainV0)) { + retval = SOSAccountVirtualV0Behavior(account, actionCode) != kSOSCCGeneralViewError; + CFSetRemoveValue(viewSet, kSOSViewKeychainV0); + } + return retval; +} + +-(bool) updateViewSets:(SOSAccount*)account enabled:(CFSetRef) origEnabledViews disabled:(CFSetRef) origDisabledViews +{ + bool retval = false; + bool updateCircle = false; + SOSPeerInfoRef pi = NULL; + CFMutableSetRef enabledViews = NULL; + CFMutableSetRef disabledViews = NULL; + if(origEnabledViews) enabledViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, origEnabledViews); + if(origDisabledViews) disabledViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, origDisabledViews); + dumpViewSet(CFSTR("Enabled"), enabledViews); + dumpViewSet(CFSTR("Disabled"), disabledViews); + + require_action_quiet(self.trustedCircle, errOut, secnotice("views", "Attempt to set viewsets with no trusted circle")); + + // Make sure we have a peerInfo capable of supporting views. + SOSFullPeerInfoRef fpi = self.fullPeerInfo; + require_action_quiet(fpi, errOut, secnotice("views", "Attempt to set viewsets with no fullPeerInfo")); + require_action_quiet(enabledViews || disabledViews, errOut, secnotice("views", "No work to do")); + + pi = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSFullPeerInfoGetPeerInfo(fpi), NULL); + + require_action_quiet(pi, errOut, secnotice("views", "Couldn't copy PeerInfoRef")); + + if(!SOSPeerInfoVersionIsCurrent(pi)) { + CFErrorRef updateFailure = NULL; + require_action_quiet(SOSPeerInfoUpdateToV2(pi, &updateFailure), errOut, + (secnotice("views", "Unable to update peer to V2- can't update views: %@", updateFailure), (void) CFReleaseNull(updateFailure))); + secnotice("V2update", "Updating PeerInfo to V2 within SOSAccountUpdateViewSets"); + updateCircle = true; + } + + CFStringSetPerformWithDescription(enabledViews, ^(CFStringRef description) { + secnotice("viewChange", "Enabling %@", description); + }); + + CFStringSetPerformWithDescription(disabledViews, ^(CFStringRef description) { + secnotice("viewChange", "Disabling %@", description); + }); + + 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(SOSAccountHasCompletedInitialSync(account)) { + if(enabledViews) updateCircle |= SOSViewSetEnable(pi, enabledViews); + if(disabledViews) updateCircle |= SOSViewSetDisable(pi, disabledViews); + retval = true; + } else { + //hold on to the views and enable them later + if(enabledViews) [self pendEnableViewSet:enabledViews]; + if(disabledViews) SOSAccountPendDisableViewSet(account, disabledViews); + retval = true; + } + + if(updateCircle) { + /* UPDATE FULLPEERINFO VIEWS */ + require_quiet(SOSFullPeerInfoUpdateToThisPeer(fpi, pi, NULL), errOut); + + 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); + + // Make sure we update the engine + account.circle_rings_retirements_need_attention = true; + } + +errOut: + CFReleaseNull(enabledViews); + CFReleaseNull(disabledViews); + CFReleaseNull(pi); + return retval; +} + + +static inline void CFArrayAppendValueIfNot(CFMutableArrayRef array, CFTypeRef value, CFTypeRef excludedValue) +{ + if (!CFEqualSafe(value, excludedValue)) + CFArrayAppendValue(array, value); +} + +-(void) addSyncablePeerBlock:(SOSAccountTransaction*)txn dsName:(CFStringRef) ds_name change:(SOSAccountSyncablePeersBlock) changeBlock +{ + if (!changeBlock) return; + SOSAccount* account = txn.account; + CFRetainSafe(ds_name); + SOSAccountCircleMembershipChangeBlock block_to_register = ^void (SOSCircleRef new_circle, + CFSetRef added_peers, CFSetRef removed_peers, + CFSetRef added_applicants, CFSetRef removed_applicants) { + + if (!CFEqualSafe(SOSCircleGetName(new_circle), ds_name)) + return; + + SOSPeerInfoRef myPi = self.peerInfo; + CFStringRef myPi_id = myPi ? SOSPeerInfoGetPeerID(myPi) : NULL; + + CFMutableArrayRef peer_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFMutableArrayRef added_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFMutableArrayRef removed_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + if (SOSCircleHasPeer(new_circle, myPi, NULL)) { + SOSCircleForEachPeer(new_circle, ^(SOSPeerInfoRef peer) { + CFArrayAppendValueIfNot(peer_ids, SOSPeerInfoGetPeerID(peer), myPi_id); + }); + + CFSetForEach(added_peers, ^(const void *value) { + CFArrayAppendValueIfNot(added_ids, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value), myPi_id); + }); + + CFSetForEach(removed_peers, ^(const void *value) { + CFArrayAppendValueIfNot(removed_ids, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value), myPi_id); + }); + } + + if (CFArrayGetCount(peer_ids) || CFSetContainsValue(removed_peers, myPi)) + changeBlock(peer_ids, added_ids, removed_ids); + + CFReleaseSafe(peer_ids); + CFReleaseSafe(added_ids); + CFReleaseSafe(removed_ids); + }; + + SOSAccountAddChangeBlock(account, block_to_register); + + CFSetRef empty = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); + if (self.trustedCircle && CFEqualSafe(ds_name, SOSCircleGetName(self.trustedCircle))) { + block_to_register(self.trustedCircle, empty, empty, empty, empty); + } + CFReleaseSafe(empty); +} + + +-(CFSetRef) copyPeerSetForView:(CFStringRef) viewName +{ + CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); + + if (self.trustedCircle) { + SOSCircleForEachPeer(self.trustedCircle, ^(SOSPeerInfoRef peer) { + if (CFSetContainsValue(SOSPeerInfoGetPermittedViews(peer), viewName)) { + CFSetAddValue(result, peer); + } + }); + } + + return result; +} + +-(SecKeyRef) copyPublicKeyForPeer:(CFStringRef) peer_id err:(CFErrorRef *)error +{ + SecKeyRef publicKey = NULL; + SOSPeerInfoRef peer = NULL; + + require_action_quiet(self.trustedCircle, fail, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to get peer key from"))); + + peer = SOSCircleCopyPeerWithID(self.trustedCircle, peer_id, error); + require_quiet(peer, fail); + + publicKey = SOSPeerInfoCopyPubKey(peer, error); + +fail: + CFReleaseSafe(peer); + return publicKey; +} + +//Peers +-(SOSPeerInfoRef) copyPeerWithID:(CFStringRef) peerid err:(CFErrorRef *)error +{ + if(!self.trustedCircle) return NULL; + return SOSCircleCopyPeerWithID(self.trustedCircle, peerid, error); +} +-(bool) isAccountIdentity:(SOSPeerInfoRef)peerInfo err:(CFErrorRef *)error +{ + return CFEqualSafe(peerInfo, self.peerInfo); +} + +-(CFSetRef) copyPeerSetMatching:(SOSModifyPeerBlock)block +{ + CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); + if (self.trustedCircle) { + SOSCircleForEachPeer(self.trustedCircle, ^(SOSPeerInfoRef peer) { + if (block(peer)) { + CFSetAddValue(result, peer); + } + }); + } + + return result; +} +-(CFArrayRef) copyPeersToListenTo:(SecKeyRef)userPublic err:(CFErrorRef *)error +{ + SOSPeerInfoRef myPeerInfo = self.peerInfo; + CFStringRef myID = myPeerInfo ? SOSPeerInfoGetPeerID(myPeerInfo) : NULL; + return [self copySortedPeerArray:error action:^(SOSCircleRef circle, CFMutableArrayRef appendPeersTo) { + SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) { + if(!CFEqualSafe(myID, SOSPeerInfoGetPeerID(peer)) && + SOSPeerInfoApplicationVerify(peer, userPublic, NULL) && + !SOSPeerInfoIsRetirementTicket(peer)) { + CFArrayAppendValue(appendPeersTo, peer); + } + }); + }]; +} +-(bool) peerSignatureUpdate:(SecKeyRef)privKey err:(CFErrorRef *)error +{ + return self.fullPeerInfo && SOSFullPeerInfoUpgradeSignatures(self.fullPeerInfo, privKey, error); +} +-(bool) updatePeerInfo:(SOSKVSCircleStorageTransport*)circleTransport description:(CFStringRef)updateDescription err:(CFErrorRef *)error update:(SOSModifyPeerInfoBlock)block +{ + if (self.fullPeerInfo == NULL) + return true; + + bool result = block(self.fullPeerInfo, error); + + if (result && [self hasCircle:NULL]) { + return [self modifyCircle:circleTransport err:error action:^(SOSCircleRef circle_to_change) { + secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for %@", updateDescription); + return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo); + }]; + } + + return result; +} + +//Views +-(void) peerGotInSync:(SOSAccountTransaction*) aTxn peerID:(CFStringRef) peerID views:(CFSetRef) views +{ + secnotice("initial-sync", "Peer %@ synced views: %@", peerID, views); + if (self.trustedCircle && [self isInCircle:NULL] && SOSCircleHasActivePeerWithID(self.trustedCircle, peerID, NULL)) { + SOSAccountUpdateOutOfSyncViews(aTxn, views); + } +} +-(void) removeInvalidApplications:(SOSCircleRef) circle userPublic:(SecKeyRef)userPublic +{ + CFMutableSetRef peersToRemove = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); + SOSCircleForEachApplicant(circle, ^(SOSPeerInfoRef peer) { + if (!SOSPeerInfoApplicationVerify(peer, userPublic, NULL)) + CFSetAddValue(peersToRemove, peer); + }); + + CFSetForEach(peersToRemove, ^(const void *value) { + SOSPeerInfoRef peer = (SOSPeerInfoRef) value; + + SOSCircleWithdrawRequest(circle, peer, NULL); + }); +} + +-(bool) upgradeiCloudIdentity:(SOSCircleRef) circle privKey:(SecKeyRef) privKey +{ + bool retval = false; + SOSFullPeerInfoRef cloud_fpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL); + require_quiet(cloud_fpi != NULL, errOut); + require_quiet(SOSFullPeerInfoUpgradeSignatures(cloud_fpi, privKey, NULL), errOut); + retval = SOSCircleUpdatePeerInfo(circle, SOSFullPeerInfoGetPeerInfo(cloud_fpi)); +errOut: + return retval; +} +const CFStringRef kSOSHsaPreApprovedPeerKeyInfo = CFSTR("HSAPreApprovedPeer"); + +-(CFMutableSetRef) copyPreApprovedHSA2Info +{ + CFMutableSetRef preApprovedPeers = (CFMutableSetRef) [self getValueFromExpansion:kSOSHsaPreApprovedPeerKeyInfo err:NULL]; + + if(preApprovedPeers) { + preApprovedPeers = CFSetCreateMutableCopy(NULL, 0, preApprovedPeers); + } else { + preApprovedPeers = CFSetCreateMutableForCFTypes(NULL); + } + return preApprovedPeers; +} + + +-(bool) addiCloudIdentity:(SOSCircleRef) circle key:(SecKeyRef) userKey err:(CFErrorRef*)error +{ + bool result = false; + SOSFullPeerInfoRef cloud_identity = NULL; + SOSPeerInfoRef cloud_peer = GenerateNewCloudIdentityPeerInfo(error); + if(!cloud_peer) + return result; + cloud_identity = CopyCloudKeychainIdentity(cloud_peer, error); + CFReleaseNull(cloud_peer); + if(!cloud_identity) + return result; + if(!SOSCircleRequestAdmission(circle, userKey, cloud_identity, error)) + return result; + + require_quiet(SOSCircleAcceptRequest(circle, userKey, self.fullPeerInfo, SOSFullPeerInfoGetPeerInfo(cloud_identity), error), err_out); + result = true; +err_out: + return result; +} +-(bool) addEscrowToPeerInfo:(SOSFullPeerInfoRef) myPeer err:(CFErrorRef *)error +{ + bool success = false; + + CFDictionaryRef escrowRecords = [self getValueFromExpansion:kSOSEscrowRecord err:error]; + success = SOSFullPeerInfoReplaceEscrowRecords(myPeer, escrowRecords, error); + + return success; +} + +-(CFArrayRef) copySortedPeerArray:(CFErrorRef *)error + action:(SOSModifyPeersInCircleBlock)block +{ + CFMutableArrayRef peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + block(self.trustedCircle, peers); + + CFArrayOfSOSPeerInfosSortByID(peers); + + return peers; + +} + +#define CURRENT_ACCOUNT_PERSISTENT_VERSION 8 + +static size_t der_sizeof_data_optional(CFDataRef data) +{ + return data ? der_sizeof_data(data, NULL) : 0; + +} +-(size_t) getDEREncodedSize:(SOSAccount*)account err:(NSError**)error +{ + size_t sequence_size = 0; + uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION; + CFErrorRef failure = NULL; + + require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(version)), fail); + require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary((__bridge CFDictionaryRef)account.gestalt, &failure)), fail); + require_quiet(accumulate_size(&sequence_size, SOSCircleGetDEREncodedSize(self.trustedCircle, &failure)), fail); + require_quiet(accumulate_size(&sequence_size, der_sizeof_fullpeer_or_null(self.fullPeerInfo, &failure)), fail); + require_quiet(accumulate_size(&sequence_size, ccder_sizeof_uint64(self.departureCode)), fail); + 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, SOSPeerInfoSetGetDEREncodedArraySize((__bridge CFSetRef)self.retirees, &failure)), fail); + 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); + + return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, sequence_size); + +fail: + // Ensure some error is made, maybe not this one, tho. + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, &failure); + if (error) { + if (failure != NULL) { + *error = (__bridge_transfer NSError*) failure; + failure = NULL; + } + } + CFReleaseNull(failure); + + return 0; +} + +static uint8_t* der_encode_data_optional(CFDataRef data, CFErrorRef *error, + const uint8_t *der, uint8_t *der_end) +{ + return data ? der_encode_data(data, error, der, der_end) : der_end; + +} + +-(uint8_t*) encodeToDER:(SOSAccount*)account err:(NSError**) error start:(const uint8_t*) der end:(uint8_t*)der_end +{ + CFErrorRef failure = NULL; + uint64_t version = CURRENT_ACCOUNT_PERSISTENT_VERSION; + der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, + ccder_encode_uint64(version, der, + der_encode_dictionary((__bridge CFDictionaryRef)account.gestalt, &failure, der, + SOSCircleEncodeToDER(self.trustedCircle, &failure, der, + der_encode_fullpeer_or_null(self.fullPeerInfo, &failure, der, + ccder_encode_uint64(self.departureCode, der, + 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, + 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, + der_end))))))))))))); + + if (error) { + if (failure != NULL) { + *error = (__bridge_transfer NSError*) failure; + failure = NULL; + } + } + CFReleaseNull(failure); + + return der_end; +} + +-(CFMutableSetRef) CF_RETURNS_RETAINED syncWithPeers:(SOSAccountTransaction*) txn peerIDs:(CFSetRef) /* CFStringRef */ peerIDs err:(CFErrorRef *)error +{ + CFMutableSetRef notMePeers = NULL; + CFMutableSetRef handledPeerIDs = NULL; + CFMutableSetRef peersForIDS = NULL; + CFMutableSetRef peersForKVS = NULL; + + SOSAccount* account = txn.account; + + // Kick getting our device ID if we don't have it, and find out if we're setup to use IDS. + bool canUseIDS = [account.ids_message_transport SOSTransportMessageIDSGetIDSDeviceID:account]; + + if(![self isInCircle:error]) + { + handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs); + CFReleaseNull(notMePeers); + CFReleaseNull(peersForIDS); + CFReleaseNull(peersForKVS); + return handledPeerIDs; + } + + handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + peersForIDS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSPeerInfoRef myPeerInfo = account.peerInfo; + if(!myPeerInfo) + { + CFReleaseNull(notMePeers); + CFReleaseNull(peersForIDS); + CFReleaseNull(peersForKVS); + return handledPeerIDs; + + } + CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo); + + notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs); + CFSetRemoveValue(notMePeers, myPeerID); + + CFSetForEach(notMePeers, ^(const void *value) { + CFErrorRef localError = NULL; + CFStringRef peerID = asString(value, &localError); + SOSPeerInfoRef peerInfo = NULL; + require_quiet(peerID, skip); + + peerInfo = SOSCircleCopyPeerWithID(self.trustedCircle, peerID, NULL); + if (peerInfo && SOSCircleHasValidSyncingPeer(self.trustedCircle, peerInfo, account.accountKey, NULL)) { + if (canUseIDS && SOSPeerInfoShouldUseIDSTransport(myPeerInfo, peerInfo)) { + CFSetAddValue(peersForIDS, peerID); + } else { + CFSetAddValue(peersForKVS, peerID); + } + } else { + CFSetAddValue(handledPeerIDs, peerID); + } + + skip: + CFReleaseNull(peerInfo); + if (localError) { + secnotice("sync-with-peers", "Skipped peer ID: %@ due to %@", peerID, localError); + } + CFReleaseNull(localError); + }); + + CFSetRef handledIDSPeerIDs = SOSAccountSyncWithPeersOverIDS(txn, peersForIDS); + CFSetUnion(handledPeerIDs, handledIDSPeerIDs); + CFReleaseNull(handledIDSPeerIDs); + + CFSetRef handledKVSPeerIDs = SOSAccountSyncWithPeersOverKVS(txn, peersForKVS); + CFSetUnion(handledPeerIDs, handledKVSPeerIDs); + CFReleaseNull(handledKVSPeerIDs); + + SOSAccountConsiderLoggingEngineState(txn); + + CFReleaseNull(notMePeers); + CFReleaseNull(peersForIDS); + CFReleaseNull(peersForKVS); + return handledPeerIDs; +} + +-(bool) requestSyncWithAllPeers:(SOSAccountTransaction*) txn key:(SecKeyRef)userPublic err:(CFErrorRef *)error +{ + if (![self isInCircle: error]) { + return false; + } + + NSMutableSet* allSyncingPeerIDs = [NSMutableSet set]; + + SOSCircleForEachValidSyncingPeer(self.trustedCircle, userPublic, ^(SOSPeerInfoRef peer) { + [allSyncingPeerIDs addObject: (__bridge NSString*) SOSPeerInfoGetPeerID(peer)]; + }); + + [txn requestSyncWithPeers: allSyncingPeerIDs]; + + return true; +} + +-(bool) isSyncingV0{ + __block bool syncingV0 = false; + + [self forEachCirclePeerExceptMe:^(SOSPeerInfoRef peer){ + if (SOSPeerInfoIsEnabledView(peer, kSOSViewKeychainV0)) { + syncingV0 = true; + } + }]; + + return syncingV0; +} + +-(SOSEngineRef) getDataSourceEngine:(SOSDataSourceFactoryRef)factory +{ + return SOSDataSourceFactoryGetEngineForDataSourceName(factory, SOSCircleGetName(self.trustedCircle), NULL); +} + +-(bool) postDebugScope:(SOSKVSCircleStorageTransport*) circle_transport scope:(CFTypeRef) scope err:(CFErrorRef*)error +{ + bool result = false; + if (circle_transport) { + result = [circle_transport kvssendDebugInfo:kSOSAccountDebugScope debug:scope err:error]; + } + return result; +} + +-(SecKeyRef) copyDeviceKey:(CFErrorRef *)error +{ + SecKeyRef privateKey = NULL; + + require_action_quiet(self.fullPeerInfo, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No identity to get key from"))); + + privateKey = SOSFullPeerInfoCopyDeviceKey(self.fullPeerInfo, error); + +fail: + return privateKey; + +} +-(bool) removeIncompleteiCloudIdentities:(SOSCircleRef) circle privKey:(SecKeyRef) privKey err:(CFErrorRef *)error +{ + bool retval = false; + + CFMutableSetRef iCloud2Remove = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSCircleForEachActivePeer(self.trustedCircle, ^(SOSPeerInfoRef peer) { + if(SOSPeerInfoIsCloudIdentity(peer)) { + SOSFullPeerInfoRef icfpi = SOSFullPeerInfoCreateCloudIdentity(kCFAllocatorDefault, peer, NULL); + if(!icfpi) { + CFSetAddValue(iCloud2Remove, peer); + } + CFReleaseNull(icfpi); + } + }); + + if(CFSetGetCount(iCloud2Remove) > 0) { + retval = true; + SOSCircleRemovePeers(self.trustedCircle, privKey, self.fullPeerInfo, iCloud2Remove, error); + } + CFReleaseNull(iCloud2Remove); + return retval; +} + +-(bool) clientPing:(SOSAccount*)account +{ + if (self.trustedCircle && self.fullPeerInfo + && SOSFullPeerInfoPing(self.fullPeerInfo, NULL)) { + [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) { + secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); + return SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo); + }]; + } + + return true; +} +static NSString* kSOSRingKey = @"trusted_rings"; + +-(void) addRingDictionary { + + if(self.expansion) { + if(![self.expansion valueForKey:kSOSRingKey]) { + NSMutableDictionary *rings = [NSMutableDictionary dictionary]; + [self.expansion setObject:rings forKey:kSOSRingKey]; + } + } +} + +@end + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustOctagon.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustOctagon.h new file mode 100644 index 00000000..82b0ae5c --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustOctagon.h @@ -0,0 +1,11 @@ +// +// SOSAccountTrustOctagon_h +// Security +// + +#ifndef SOSAccountTrustOctagon_h +#define SOSAccountTrustOctagon_h + +#import "Security/SecureObjectSync/SOSAccountTrust.h" + +#endif /* SOSAccountTrustOctagon_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustOctagon.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustOctagon.m new file mode 100644 index 00000000..81cc3883 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTrustOctagon.m @@ -0,0 +1,6 @@ +// +// SOSAccountTrustOctagon.m +// Security +// + +#import diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c deleted file mode 100644 index 2f8091bf..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c +++ /dev/null @@ -1,734 +0,0 @@ -// -// SOSAccountUpdate.c -// sec -// - -#include "SOSAccountPriv.h" -#include "SOSAccountLog.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static void DifferenceAndCall(CFSetRef old_members, CFSetRef new_members, void (^updatedCircle)(CFSetRef additions, CFSetRef removals)) -{ - CFMutableSetRef additions = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, new_members); - CFMutableSetRef removals = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, old_members); - - - CFSetForEach(old_members, ^(const void * value) { - CFSetRemoveValue(additions, value); - }); - - CFSetForEach(new_members, ^(const void * value) { - CFSetRemoveValue(removals, value); - }); - - updatedCircle(additions, removals); - - CFReleaseSafe(additions); - CFReleaseSafe(removals); -} - -static CFMutableSetRef SOSAccountCopyIntersectedViews(CFSetRef peerViews, CFSetRef myViews) { - __block CFMutableSetRef views = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); - if (peerViews && myViews) CFSetForEach(peerViews, ^(const void *view) { - if (CFSetContainsValue(myViews, view)) { - CFSetAddValue(views, view); - } - }); - return views; -} - -static inline bool isSyncing(SOSPeerInfoRef peer, SecKeyRef upub) { - if(!SOSPeerInfoApplicationVerify(peer, upub, NULL)) return false; - if(SOSPeerInfoIsRetirementTicket(peer)) return false; - return true; -} - -static bool isBackupSOSRing(SOSRingRef ring) -{ - return isSOSRing(ring) && (kSOSRingBackup == SOSRingGetType(ring)); -} - -static void SOSAccountAppendPeerMetasForViewBackups(SOSAccountRef account, CFSetRef views, CFMutableArrayRef appendTo) -{ - CFMutableDictionaryRef ringToViewTable = NULL; - - require_quiet(SOSAccountIsInCircle(account, NULL), done); - - require_action_quiet(SOSAccountHasCompletedRequiredBackupSync(account), done, - secnotice("backup", "Haven't finished initial backup syncing, not registering backup metas with engine")); - - require_action_quiet(SOSPeerInfoV2DictionaryHasData(SOSAccountGetMyPeerInfo(account), sBackupKeyKey), done, - secnotice("backup", "No key to backup to, we don't enable individual view backups")); - - ringToViewTable = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFSetForEach(views, ^(const void *value) { - CFStringRef viewName = value; - if (isString(viewName) && !CFEqualSafe(viewName, kSOSViewKeychainV0)) { - CFStringRef ringName = SOSBackupCopyRingNameForView(viewName); - viewName = ringName; - SOSRingRef ring = SOSAccountCopyRing(account, ringName, NULL); - if (ring && isBackupSOSRing(ring)) { - CFTypeRef currentValue = (CFTypeRef) CFDictionaryGetValue(ringToViewTable, ring); - - if (isSet(currentValue)) { - CFSetAddValue((CFMutableSetRef)currentValue, viewName); - } else { - CFMutableSetRef viewNameSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); - CFSetAddValue(viewNameSet, viewName); - - CFDictionarySetValue(ringToViewTable, ring, viewNameSet); - CFReleaseNull(viewNameSet); - } - } else { - secwarning("View '%@' not being backed up – ring %@:%@ not backup ring.", viewName, ringName, ring); - } - CFReleaseNull(ringName); - CFReleaseNull(ring); - } - }); - - CFDictionaryForEach(ringToViewTable, ^(const void *key, const void *value) { - SOSRingRef ring = (SOSRingRef) key; - CFSetRef viewNames = asSet(value, NULL); - if (isSOSRing(ring) && viewNames) { - if (SOSAccountIntersectsWithOutstanding(account, viewNames)) { - CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { - secnotice("engine-notify", "Not ready, no peer meta: R: %@ Vs: %@", SOSRingGetName(ring), ringViews); - }); - } else { - bool meta_added = false; - CFErrorRef create_error = NULL; - SOSBackupSliceKeyBagRef key_bag = NULL; - SOSPeerMetaRef newMeta = NULL; - - CFDataRef ring_payload = SOSRingGetPayload(ring, NULL); - require_quiet(isData(ring_payload), skip); - - key_bag = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, ring_payload, &create_error); - require_quiet(key_bag, skip); - - newMeta = SOSPeerMetaCreateWithComponents(SOSRingGetName(ring), viewNames, ring_payload); - require_quiet(SecAllocationError(newMeta, &create_error, CFSTR("Didn't make peer meta for: %@"), ring), skip); - CFArrayAppendValue(appendTo, newMeta); - - CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { - secnotice("engine-notify", "Backup peer meta: R: %@ Vs: %@ VD: %@", SOSRingGetName(ring), ringViews, ring_payload); - }); - - meta_added = true; - - skip: - if (!meta_added) { - CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { - secerror("Failed to register backup meta from %@ for views %@. Error (%@)", ring, ringViews, create_error); - }); - } - CFReleaseNull(newMeta); - CFReleaseNull(key_bag); - CFReleaseNull(create_error); - } - } - }); - -done: - CFReleaseNull(ringToViewTable); -} - -bool SOSAccountSyncingV0(SOSAccountRef account) { - __block bool syncingV0 = false; - SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { - if (SOSPeerInfoIsEnabledView(peer, kSOSViewKeychainV0)) { - syncingV0 = true; - } - }); - - return syncingV0; -} - -void SOSAccountNotifyEngines(SOSAccountRef account) -{ - SOSPeerInfoRef myPi = SOSFullPeerInfoGetPeerInfo(account->my_identity); - CFStringRef myPi_id = SOSPeerInfoGetPeerID(myPi); - CFMutableArrayRef syncing_peer_metas = NULL; - CFMutableArrayRef zombie_peer_metas = NULL; - CFErrorRef localError = NULL; - SOSPeerMetaRef myMeta = NULL; - - if (myPi_id && isSyncing(myPi, account->user_public) && SOSCircleHasPeer(account->trusted_circle, myPi, NULL)) { - CFMutableSetRef myViews = SOSPeerInfoCopyEnabledViews(myPi); - - // 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); - - syncing_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - zombie_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { - CFMutableArrayRef arrayToAddTo = isSyncing(peer, account->user_public) ? syncing_peer_metas : zombie_peer_metas; - - // Compute views each peer is in that we are also in ourselves - CFMutableSetRef peerEnabledViews = SOSPeerInfoCopyEnabledViews(peer); - CFMutableSetRef views = SOSAccountCopyIntersectedViews(peerEnabledViews, myViews); - CFReleaseNull(peerEnabledViews); - - if(addV0Views) { - CFSetAddValue(views, kSOSViewKeychainV0); - } - - CFStringSetPerformWithDescription(views, ^(CFStringRef viewsDescription) { - secnotice("engine-notify", "Meta: %@: %@", SOSPeerInfoGetPeerID(peer), viewsDescription); - }); - - SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(SOSPeerInfoGetPeerID(peer), views, NULL); - CFReleaseNull(views); - - CFArrayAppendValue(arrayToAddTo, peerMeta); - CFReleaseNull(peerMeta); - }); - - // We don't make a backup peer meta for the magic V0 peer - // Set up all the rest before we munge the set - SOSAccountAppendPeerMetasForViewBackups(account, myViews, syncing_peer_metas); - - // If we saw someone else needing V0, we sync V0, too! - if (addV0Views) { - CFSetAddValue(myViews, kSOSViewKeychainV0); - } - - CFStringSetPerformWithDescription(myViews, ^(CFStringRef viewsDescription) { - secnotice("engine-notify", "My Meta: %@: %@", myPi_id, viewsDescription); - }); - myMeta = SOSPeerMetaCreateWithComponents(myPi_id, myViews, NULL); - CFReleaseSafe(myViews); - } - - SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, SOSCircleGetName(account->trusted_circle), NULL); - if (engine) { - SOSEngineCircleChanged(engine, myMeta, syncing_peer_metas, zombie_peer_metas); - } - - CFReleaseNull(myMeta); - CFReleaseSafe(localError); - CFReleaseNull(syncing_peer_metas); - CFReleaseNull(zombie_peer_metas); -} - -// Upcoming call to View Changes Here -static void SOSAccountNotifyOfChange(SOSAccountRef account, SOSCircleRef oldCircle, SOSCircleRef newCircle) -{ - account->circle_rings_retirements_need_attention = true; - - CFMutableSetRef old_members = SOSCircleCopyPeers(oldCircle, kCFAllocatorDefault); - CFMutableSetRef new_members = SOSCircleCopyPeers(newCircle, kCFAllocatorDefault); - - CFMutableSetRef old_applicants = SOSCircleCopyApplicants(oldCircle, kCFAllocatorDefault); - CFMutableSetRef new_applicants = SOSCircleCopyApplicants(newCircle, kCFAllocatorDefault); - - SOSPeerInfoRef me = SOSAccountGetMyPeerInfo(account); - if(me && CFSetContainsValue(new_members, me)) - SOSAccountSetValue(account, kSOSEscrowRecord, kCFNull, NULL); //removing the escrow records from the account object - - DifferenceAndCall(old_members, new_members, ^(CFSetRef added_members, CFSetRef removed_members) { - DifferenceAndCall(old_applicants, new_applicants, ^(CFSetRef added_applicants, CFSetRef removed_applicants) { - CFArrayForEach(account->change_blocks, ^(const void * notificationBlock) { - secnotice("updates", "calling change block"); - ((SOSAccountCircleMembershipChangeBlock) notificationBlock)(newCircle, added_members, removed_members, added_applicants, removed_applicants); - }); - }); - }); - - CFReleaseNull(old_applicants); - CFReleaseNull(new_applicants); - - CFReleaseNull(old_members); - CFReleaseNull(new_members); -} - -CF_RETURNS_RETAINED -CFDictionaryRef SOSAccountHandleRetirementMessages(SOSAccountRef account, CFDictionaryRef circle_retirement_messages, CFErrorRef *error) { - CFStringRef circle_name = SOSCircleGetName(account->trusted_circle); - CFMutableArrayRef handledRetirementIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - // We only handle one circle, look it up: - - require_quiet(account->trusted_circle, finish); // We don't fail, we intentionally handle nothing. - CFDictionaryRef retirement_dictionary = asDictionary(CFDictionaryGetValue(circle_retirement_messages, circle_name), error); - require_quiet(retirement_dictionary, finish); - CFDictionaryForEach(retirement_dictionary, ^(const void *key, const void *value) { - if(isData(value)) { - SOSPeerInfoRef pi = SOSPeerInfoCreateFromData(NULL, error, (CFDataRef) value); - if(pi && CFEqual(key, SOSPeerInfoGetPeerID(pi)) && SOSPeerInfoInspectRetirementTicket(pi, error)) { - CFSetAddValue(account->retirees, pi); - - account->circle_rings_retirements_need_attention = true; // Have to handle retirements. - - CFArrayAppendValue(handledRetirementIDs, key); - } - CFReleaseNull(pi); - } - }); - - // If we are in the retiree list, we somehow got resurrected - // clearly we took care of proper departure before so leave - // and delcare that we withdrew this time. - SOSPeerInfoRef me = SOSAccountGetMyPeerInfo(account); - if (me && CFSetContainsValue(account->retirees, me)) { - SOSAccountPurgeIdentity(account); - account->departure_code = kSOSDiscoveredRetirement; - } - -finish: - { - CFDictionaryRef result = (CFArrayGetCount(handledRetirementIDs) == 0) ? CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL) - : CFDictionaryCreateForCFTypes(kCFAllocatorDefault, circle_name, handledRetirementIDs, NULL); - - CFReleaseNull(handledRetirementIDs); - return result; - } -} - -static SOSCircleRef SOSAccountCreateCircleFrom(CFStringRef circleName, CFTypeRef value, CFErrorRef *error) { - if (value && !isData(value) && !isNull(value)) { - secnotice("circleCreat", "Value provided not appropriate for a circle"); - CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(value)); - SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL, - CFSTR("Expected data or NULL got %@"), description); - CFReleaseSafe(description); - return NULL; - } - - SOSCircleRef circle = NULL; - if (!value || isNull(value)) { - secnotice("circleCreat", "No circle found in data: %@", value); - circle = NULL; - } else { - circle = SOSCircleCreateFromData(NULL, (CFDataRef) value, error); - if (circle) { - CFStringRef name = SOSCircleGetName(circle); - if (!CFEqualSafe(name, circleName)) { - secnotice("circleCreat", "Expected circle named %@, got %@", circleName, name); - SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL, - CFSTR("Expected circle named %@, got %@"), circleName, name); - CFReleaseNull(circle); - } - } else { - secnotice("circleCreat", "SOSCircleCreateFromData returned NULL."); - } - } - return circle; -} - -bool SOSAccountHandleCircleMessage(SOSAccountRef account, - CFStringRef circleName, CFDataRef encodedCircleMessage, CFErrorRef *error) { - bool success = false; - CFErrorRef localError = NULL; - SOSCircleRef circle = SOSAccountCreateCircleFrom(circleName, encodedCircleMessage, &localError); - if (circle) { - success = SOSAccountUpdateCircleFromRemote(account, circle, &localError); - CFReleaseSafe(circle); - } else { - secerror("NULL circle found, ignoring ..."); - success = true; // don't pend this NULL thing. - } - - if (!success) { - if (isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)) { - secerror("Incompatible circle found, abandoning membership: %@", circleName); - CFReleaseNull(account->my_identity); - CFReleaseNull(account->trusted_circle); - } - - if (error) { - *error = localError; - localError = NULL; - } - - } - - CFReleaseNull(localError); - - return success; -} - -bool SOSAccountHandleParametersChange(SOSAccountRef account, CFDataRef parameters, CFErrorRef *error){ - - SecKeyRef newKey = NULL; - CFDataRef newParameters = NULL; - bool success = false; - - if(SOSAccountRetrieveCloudParameters(account, &newKey, parameters, &newParameters, error)) { - debugDumpUserParameters(CFSTR("SOSAccountHandleParametersChange got new user key parameters:"), parameters); - secnotice("keygen", "SOSAccountHandleParametersChange got new public key: %@", newKey); - - if (CFEqualSafe(account->user_public, newKey)) { - secnotice("updates", "Got same public key sent our way. Ignoring."); - success = true; - } else if (CFEqualSafe(account->previous_public, newKey)) { - secnotice("updates", "Got previous public key repeated. Ignoring."); - success = true; - } else { - SOSAccountSetUnTrustedUserPublicKey(account, newKey); - SOSAccountSetParameters(account, newParameters); - newKey = NULL; - - if(SOSAccountRetryUserCredentials(account)) { - secnotice("keygen", "Successfully used cached password with new parameters"); - SOSAccountGenerationSignatureUpdate(account, error); - } else { - SOSAccountPurgePrivateCredential(account); - secnotice("keygen", "Got new parameters for public key - could not find or use cached password"); - } - - account->circle_rings_retirements_need_attention = true; - account->key_interests_need_updating = true; - - success = true; - } - } - - CFReleaseNull(newKey); - CFReleaseNull(newParameters); - - return success; -} - -static inline bool SOSAccountHasLeft(SOSAccountRef account) { - switch(account->departure_code) { - case kSOSDiscoveredRetirement: /* Fallthrough */ - case kSOSLostPrivateKey: /* Fallthrough */ - case kSOSWithdrewMembership: /* Fallthrough */ - case kSOSMembershipRevoked: /* Fallthrough */ - case kSOSLeftUntrustedCircle: - return true; - case kSOSNeverAppliedToCircle: /* Fallthrough */ - case kSOSNeverLeftCircle: /* Fallthrough */ - default: - return false; - } -} - -static const char *concordstring[] = { - "kSOSConcordanceTrusted", - "kSOSConcordanceGenOld", // kSOSErrorReplay - "kSOSConcordanceNoUserSig", // kSOSErrorBadSignature - "kSOSConcordanceNoUserKey", // kSOSErrorNoKey - "kSOSConcordanceNoPeer", // kSOSErrorPeerNotFound - "kSOSConcordanceBadUserSig", // kSOSErrorBadSignature - "kSOSConcordanceBadPeerSig", // kSOSErrorBadSignature - "kSOSConcordanceNoPeerSig", - "kSOSConcordanceWeSigned", -}; - - -bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospective_circle, bool writeUpdate, CFErrorRef *error) -{ - bool success = true; - bool haveOldCircle = true; - const char *local_remote = writeUpdate ? "local": "remote"; - - secnotice("signing", "start:[%s]", local_remote); - if (!account->user_public || !account->user_public_trusted) { - SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Can't handle updates with no trusted public key here"), NULL, error); - return false; - } - - if (!prospective_circle) { - secerror("##### Can't update to a NULL circle ######"); - return false; // Can't update one we don't have. - } - - CFStringRef newCircleName = SOSCircleGetName(prospective_circle); - SOSCircleRef oldCircle = account->trusted_circle; - SOSCircleRef emptyCircle = NULL; - - if(oldCircle == NULL) { - SOSCreateErrorWithFormat(kSOSErrorIncompatibleCircle, NULL, error, NULL, CFSTR("Current Entry is NULL; rejecting %@"), prospective_circle); - secerror("##### Can't replace circle - we don't care about it ######"); - return false; - } - if (CFGetTypeID(oldCircle) != SOSCircleGetTypeID()) { - secdebug("signing", ">>>>>>>>>>>>>>> Non-Circle Circle found <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); - // We don't know what is in our table, likely it was kCFNull indicating we didn't - // understand a circle that came by. We seem to like this one lets make our entry be empty circle - emptyCircle = SOSCircleCreate(kCFAllocatorDefault, newCircleName, NULL); - oldCircle = emptyCircle; - haveOldCircle = false; - // And we're paranoid, drop our old peer info if for some reason we didn't before. - // SOSAccountDestroyCirclePeerInfo(account, oldCircle, NULL); - } - - - SOSTransportCircleRef transport = account->circle_transport; - - SOSAccountScanForRetired(account, prospective_circle, error); - SOSCircleRef newCircle = SOSAccountCloneCircleWithRetirement(account, prospective_circle, error); - if(!newCircle) return false; - - SOSCircleRef ghostCleaned = SOSAccountCloneCircleWithoutMyGhosts(account, newCircle); - if(ghostCleaned) { - CFRetainAssign(newCircle, ghostCleaned); - writeUpdate = true; - } - - SOSFullPeerInfoRef me_full = account->my_identity; - SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(me_full); - CFStringRef myPeerID = SOSPeerInfoGetPeerID(me); - myPeerID = (myPeerID) ? myPeerID: CFSTR("No Peer"); - - if (me && SOSCircleUpdatePeerInfo(newCircle, me)) { - writeUpdate = true; // If we update our peer in the new circle we should write it if we accept it. - } - - typedef enum { - accept, - countersign, - leave, - revert, - ignore - } circle_action_t; - - static const char *actionstring[] = { - "accept", "countersign", "leave", "revert", "ignore", - }; - - circle_action_t circle_action = ignore; - enum DepartureReason leave_reason = kSOSNeverLeftCircle; - - SecKeyRef old_circle_key = NULL; - if(SOSCircleVerify(oldCircle, account->user_public, NULL)) old_circle_key = account->user_public; - else if(account->previous_public && SOSCircleVerify(oldCircle, account->previous_public, NULL)) old_circle_key = account->previous_public; - bool userTrustedOldCircle = (old_circle_key != NULL) && haveOldCircle; - - SOSConcordanceStatus concstat = - SOSCircleConcordanceTrust(oldCircle, newCircle, - old_circle_key, account->user_public, - 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; - } - - secnotice("signing", "Decided on action [%s] based on concordance state [%s] and [%s] circle. My PeerID is %@", actionstring[circle_action], concordstring[concstat], userTrustedOldCircle ? "trusted" : "untrusted", myPeerID); - - SOSCircleRef circleToPush = NULL; - - if (circle_action == leave) { - circle_action = ignore; (void) circle_action; // Acknowledge this is a dead store. - - if (me && SOSCircleHasPeer(oldCircle, me, NULL)) { - secnotice("account", "Leaving circle with peer %@", me); - debugDumpCircle(CFSTR("oldCircle"), oldCircle); - debugDumpCircle(CFSTR("newCircle"), newCircle); - debugDumpCircle(CFSTR("prospective_circle"), prospective_circle); - secnotice("account", "Key state: user_public %@, previous_public %@, old_circle_key %@", - account->user_public, account->previous_public, old_circle_key); - - if (sosAccountLeaveCircle(account, newCircle, error)) { - secnotice("leaveCircle", "Leaving circle by newcircle state"); - circleToPush = newCircle; - } else { - secnotice("signing", "Can't leave circle, but dumping identities"); - success = false; - } - account->departure_code = leave_reason; - circle_action = accept; - me = NULL; - me_full = NULL; - } else { - // We are not in this circle, but we need to update account with it, since we got it from cloud - secnotice("signing", "We are not in this circle, but we need to update account with it"); - debugDumpCircle(CFSTR("oldCircle"), oldCircle); - debugDumpCircle(CFSTR("newCircle"), newCircle); - debugDumpCircle(CFSTR("prospective_circle"), prospective_circle); - circle_action = accept; - } - } - - if (circle_action == countersign) { - if (me && SOSCircleHasPeer(newCircle, me, NULL)) { - if (SOSCircleVerifyPeerSigned(newCircle, me, NULL)) { - secnotice("signing", "Already concur with the new circle"); - } else { - CFErrorRef signing_error = NULL; - - if (me_full && SOSCircleConcordanceSign(newCircle, me_full, &signing_error)) { - circleToPush = newCircle; - secnotice("signing", "Concurred with new circle"); - } else { - secerror("Failed to concurrence sign, error: %@", signing_error); - success = false; - } - CFReleaseSafe(signing_error); - } - - if(SOSAccountVerifyAndAcceptHSAApplicants(account, newCircle, error)) { - circleToPush = newCircle; - writeUpdate = true; - } - } else { - secnotice("signing", "Not countersigning, not in new circle"); - debugDumpCircle(CFSTR("circle to countersign"), newCircle); - } - circle_action = accept; - } - - if (circle_action == accept) { - if (me && SOSCircleHasActivePeer(oldCircle, me, NULL) && !SOSCircleHasPeer(newCircle, me, NULL)) { - // Don't destroy evidence of other code determining reason for leaving. - if(!SOSAccountHasLeft(account)) account->departure_code = kSOSMembershipRevoked; - secnotice("account", "Member of old circle but not of new circle"); - debugDumpCircle(CFSTR("oldCircle"), oldCircle); - debugDumpCircle(CFSTR("newCircle"), newCircle); - } - - if (me - && SOSCircleHasActivePeer(oldCircle, me, NULL) - && !(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 (account->my_identity) - SOSFullPeerInfoPurgePersistentKey(account->my_identity, NULL); - CFReleaseNull(account->my_identity); - me = NULL; - me_full = NULL; - } - - if (me && SOSCircleHasRejectedApplicant(newCircle, me, NULL)) { - SOSPeerInfoRef reject = SOSCircleCopyRejectedApplicant(newCircle, me, NULL); - if(CFEqualSafe(reject, me) && SOSPeerInfoApplicationVerify(me, account->user_public, NULL)) { - secnotice("circle", "Rejected, Purging my applicant peer (ID: %@) for circle '%@'", SOSPeerInfoGetPeerID(me), SOSCircleGetName(oldCircle)); - debugDumpCircle(CFSTR("oldCircle"), oldCircle); - debugDumpCircle(CFSTR("newCircle"), newCircle); - if (account->my_identity) - SOSFullPeerInfoPurgePersistentKey(account->my_identity, NULL); - CFReleaseNull(account->my_identity); - me = NULL; - me_full = NULL; - } else { - secnotice("circle", "Rejected, Reapplying (ID: %@) for circle '%@'", SOSPeerInfoGetPeerID(me), SOSCircleGetName(oldCircle)); - debugDumpCircle(CFSTR("oldCircle"), oldCircle); - debugDumpCircle(CFSTR("newCircle"), newCircle); - SOSCircleRequestReadmission(newCircle, account->user_public, me, NULL); - writeUpdate = true; - } - } - - CFRetainSafe(oldCircle); - CFRetainAssign(account->trusted_circle, newCircle); - SOSAccountSetPreviousPublic(account); - - secnotice("signing", "%@, Accepting new circle", concStr); - - if (me && account->user_public_trusted - && SOSCircleHasApplicant(oldCircle, me, NULL) - && SOSCircleCountPeers(newCircle) > 0 - && !SOSCircleHasPeer(newCircle, me, NULL) && !SOSCircleHasApplicant(newCircle, me, NULL)) { - // We weren't rejected (above would have set me to NULL. - // We were applying and we weren't accepted. - // Our application is declared lost, let us reapply. - - secnotice("signing", "requesting readmission to new circle"); - if (SOSCircleRequestReadmission(newCircle, account->user_public, me, NULL)) - writeUpdate = true; - } - - if (me && SOSCircleHasActivePeer(oldCircle, me, NULL)) { - SOSAccountCleanupRetirementTickets(account, RETIREMENT_FINALIZATION_SECONDS, NULL); - } - - SOSAccountNotifyOfChange(account, oldCircle, newCircle); - - CFReleaseNull(oldCircle); - - if (writeUpdate) - circleToPush = newCircle; - account->key_interests_need_updating = true; - } - - /* - * In the revert section we'll guard the KVS idea of circles by rejecting "bad" new circles - * and pushing our current view of the circle (oldCircle). We'll only do this if we actually - * are a member of oldCircle - never for an empty circle. - */ - - if (circle_action == revert) { - if(haveOldCircle && me && SOSCircleHasActivePeer(oldCircle, me, NULL)) { - secnotice("signing", "%@, Rejecting new circle, re-publishing old circle", concStr); - debugDumpCircle(CFSTR("oldCircle"), oldCircle); - debugDumpCircle(CFSTR("newCircle"), newCircle); - circleToPush = oldCircle; - } else { - secnotice("canary", "%@, Rejecting: new circle Have no old circle - would reset", concStr); - } - } - - - if (circleToPush != NULL) { - secnotice("signing", "Pushing:[%s]", local_remote); - CFDataRef circle_data = SOSCircleCopyEncodedData(circleToPush, kCFAllocatorDefault, error); - - if (circle_data) { - // Ensure we flush changes - account->circle_rings_retirements_need_attention = true; - - //recording circle we are pushing in KVS - success &= SOSTransportCircleRecordLastCirclePushedInKVS(transport, SOSCircleGetName(circleToPush), circle_data); - //posting new circle to peers - success &= SOSTransportCirclePostCircle(transport, SOSCircleGetName(circleToPush), circle_data, error); - } else { - success = false; - } - CFReleaseNull(circle_data); - } - - CFReleaseSafe(newCircle); - CFReleaseNull(emptyCircle); - - return success; -} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.m new file mode 100644 index 00000000..9978c662 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.m @@ -0,0 +1,415 @@ +// +// SOSAccountUpdate.c +// sec +// + +#include "SOSAccountPriv.h" +#include "SOSAccountLog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#import +#import +#import + +static void DifferenceAndCall(CFSetRef old_members, CFSetRef new_members, void (^updatedCircle)(CFSetRef additions, CFSetRef removals)) +{ + CFMutableSetRef additions = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, new_members); + CFMutableSetRef removals = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, old_members); + + + CFSetForEach(old_members, ^(const void * value) { + CFSetRemoveValue(additions, value); + }); + + CFSetForEach(new_members, ^(const void * value) { + CFSetRemoveValue(removals, value); + }); + + updatedCircle(additions, removals); + + CFReleaseSafe(additions); + CFReleaseSafe(removals); +} +static CFMutableSetRef SOSAccountCopyIntersectedViews(CFSetRef peerViews, CFSetRef myViews) { + __block CFMutableSetRef views = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + if (peerViews && myViews) CFSetForEach(peerViews, ^(const void *view) { + if (CFSetContainsValue(myViews, view)) { + CFSetAddValue(views, view); + } + }); + return views; +} + +static inline bool isSyncing(SOSPeerInfoRef peer, SecKeyRef upub) { + if(!SOSPeerInfoApplicationVerify(peer, upub, NULL)) return false; + if(SOSPeerInfoIsRetirementTicket(peer)) return false; + return true; +} + +static bool isBackupSOSRing(SOSRingRef ring) +{ + return isSOSRing(ring) && (kSOSRingBackup == SOSRingGetType(ring)); +} + +static void SOSAccountAppendPeerMetasForViewBackups(SOSAccount* account, CFSetRef views, CFMutableArrayRef appendTo) +{ + CFMutableDictionaryRef ringToViewTable = NULL; + + if([account getCircleStatus:NULL] != kSOSCCInCircle) + return; + + if(!(SOSAccountHasCompletedInitialSync(account))){ + secnotice("backup", "Haven't finished initial backup syncing, not registering backup metas with engine"); + return; + } + if(!SOSPeerInfoV2DictionaryHasData(account.peerInfo, sBackupKeyKey)){ + secnotice("backup", "No key to backup to, we don't enable individual view backups"); + return; + } + ringToViewTable = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFSetForEach(views, ^(const void *value) { + CFStringRef viewName = value; + if (isString(viewName) && !CFEqualSafe(viewName, kSOSViewKeychainV0)) { + CFStringRef ringName = SOSBackupCopyRingNameForView(viewName); + viewName = ringName; + SOSRingRef ring = [account.trust copyRing:ringName err:NULL]; + if (ring && isBackupSOSRing(ring)) { + CFTypeRef currentValue = (CFTypeRef) CFDictionaryGetValue(ringToViewTable, ring); + + if (isSet(currentValue)) { + CFSetAddValue((CFMutableSetRef)currentValue, viewName); + } else { + CFMutableSetRef viewNameSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(viewNameSet, viewName); + + CFDictionarySetValue(ringToViewTable, ring, viewNameSet); + CFReleaseNull(viewNameSet); + } + } else { + secwarning("View '%@' not being backed up – ring %@:%@ not backup ring.", viewName, ringName, ring); + } + CFReleaseNull(ringName); + CFReleaseNull(ring); + } + }); + + CFDictionaryForEach(ringToViewTable, ^(const void *key, const void *value) { + SOSRingRef ring = (SOSRingRef) key; + CFSetRef viewNames = asSet(value, NULL); + if (isSOSRing(ring) && viewNames) { + if (SOSAccountIntersectsWithOutstanding(account, viewNames)) { + CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { + secnotice("engine-notify", "Not ready, no peer meta: R: %@ Vs: %@", SOSRingGetName(ring), ringViews); + }); + } else { + bool meta_added = false; + CFErrorRef create_error = NULL; + SOSBackupSliceKeyBagRef key_bag = NULL; + SOSPeerMetaRef newMeta = NULL; + + CFDataRef ring_payload = SOSRingGetPayload(ring, NULL); + require_quiet(isData(ring_payload), skip); + + key_bag = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, ring_payload, &create_error); + require_quiet(key_bag, skip); + + newMeta = SOSPeerMetaCreateWithComponents(SOSRingGetName(ring), viewNames, ring_payload); + require_quiet(SecAllocationError(newMeta, &create_error, CFSTR("Didn't make peer meta for: %@"), ring), skip); + CFArrayAppendValue(appendTo, newMeta); + + CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { + secnotice("engine-notify", "Backup peer meta: R: %@ Vs: %@ VD: %@", SOSRingGetName(ring), ringViews, ring_payload); + }); + + meta_added = true; + + skip: + if (!meta_added) { + CFStringSetPerformWithDescription(viewNames, ^(CFStringRef ringViews) { + secerror("Failed to register backup meta from %@ for views %@. Error (%@)", ring, ringViews, create_error); + }); + } + CFReleaseNull(newMeta); + CFReleaseNull(key_bag); + CFReleaseNull(create_error); + } + } + }); + + CFReleaseNull(ringToViewTable); +} + +bool SOSAccountSyncingV0(SOSAccount* account) { + __block bool syncingV0 = false; + SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { + if (SOSPeerInfoIsEnabledView(peer, kSOSViewKeychainV0)) { + syncingV0 = true; + } + }); + + return syncingV0; +} + +void SOSAccountNotifyEngines(SOSAccount* account) +{ + SOSAccountTrustClassic *trust = account.trust; + SOSFullPeerInfoRef identity = trust.fullPeerInfo; + SOSCircleRef circle = trust.trustedCircle; + + SOSPeerInfoRef myPi = SOSFullPeerInfoGetPeerInfo(identity); + CFStringRef myPi_id = SOSPeerInfoGetPeerID(myPi); + CFMutableArrayRef syncing_peer_metas = NULL; + CFMutableArrayRef zombie_peer_metas = NULL; + CFErrorRef localError = NULL; + SOSPeerMetaRef myMeta = NULL; + + if (myPi_id && isSyncing(myPi, account.accountKey) && SOSCircleHasPeer(circle, myPi, NULL)) { + CFMutableSetRef myViews = SOSPeerInfoCopyEnabledViews(myPi); + + // 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); + + syncing_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + zombie_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { + CFMutableArrayRef arrayToAddTo = isSyncing(peer, account.accountKey) ? syncing_peer_metas : zombie_peer_metas; + + // Compute views each peer is in that we are also in ourselves + CFMutableSetRef peerEnabledViews = SOSPeerInfoCopyEnabledViews(peer); + CFMutableSetRef views = SOSAccountCopyIntersectedViews(peerEnabledViews, myViews); + CFReleaseNull(peerEnabledViews); + + if(addV0Views) { + CFSetAddValue(views, kSOSViewKeychainV0); + } + + CFStringSetPerformWithDescription(views, ^(CFStringRef viewsDescription) { + secnotice("engine-notify", "Meta: %@: %@", SOSPeerInfoGetPeerID(peer), viewsDescription); + }); + + SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(SOSPeerInfoGetPeerID(peer), views, NULL); + CFReleaseNull(views); + + CFArrayAppendValue(arrayToAddTo, peerMeta); + CFReleaseNull(peerMeta); + }); + + // We don't make a backup peer meta for the magic V0 peer + // Set up all the rest before we munge the set + SOSAccountAppendPeerMetasForViewBackups(account, myViews, syncing_peer_metas); + + // If we saw someone else needing V0, we sync V0, too! + if (addV0Views) { + CFSetAddValue(myViews, kSOSViewKeychainV0); + } + + CFStringSetPerformWithDescription(myViews, ^(CFStringRef viewsDescription) { + secnotice("engine-notify", "My Meta: %@: %@", myPi_id, viewsDescription); + }); + myMeta = SOSPeerMetaCreateWithComponents(myPi_id, myViews, NULL); + CFReleaseSafe(myViews); + } + + SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account.factory, SOSCircleGetName(circle), NULL); + if (engine) { + SOSEngineCircleChanged(engine, myMeta, syncing_peer_metas, zombie_peer_metas); + } + + CFReleaseNull(myMeta); + CFReleaseSafe(localError); + + CFReleaseNull(syncing_peer_metas); + CFReleaseNull(zombie_peer_metas); +} + + +// Upcoming call to View Changes Here +void SOSAccountNotifyOfChange(SOSAccount* account, SOSCircleRef oldCircle, SOSCircleRef newCircle) +{ + account.circle_rings_retirements_need_attention = true; + + CFMutableSetRef old_members = SOSCircleCopyPeers(oldCircle, kCFAllocatorDefault); + CFMutableSetRef new_members = SOSCircleCopyPeers(newCircle, kCFAllocatorDefault); + + CFMutableSetRef old_applicants = SOSCircleCopyApplicants(oldCircle, kCFAllocatorDefault); + CFMutableSetRef new_applicants = SOSCircleCopyApplicants(newCircle, kCFAllocatorDefault); + + SOSPeerInfoRef me = account.peerInfo; + if(me && CFSetContainsValue(new_members, me)) + SOSAccountSetValue(account, kSOSEscrowRecord, kCFNull, NULL); //removing the escrow records from the account object + + DifferenceAndCall(old_members, new_members, ^(CFSetRef added_members, CFSetRef removed_members) { + DifferenceAndCall(old_applicants, new_applicants, ^(CFSetRef added_applicants, CFSetRef removed_applicants) { + CFArrayForEach((__bridge CFArrayRef)(account.change_blocks), ^(const void * notificationBlock) { + secnotice("updates", "calling change block"); + ((__bridge SOSAccountCircleMembershipChangeBlock) notificationBlock)(newCircle, added_members, removed_members, added_applicants, removed_applicants); + }); + }); + }); + + CFReleaseNull(old_applicants); + CFReleaseNull(new_applicants); + + CFReleaseNull(old_members); + CFReleaseNull(new_members); +} + +CF_RETURNS_RETAINED +CFDictionaryRef SOSAccountHandleRetirementMessages(SOSAccount* account, CFDictionaryRef circle_retirement_messages, CFErrorRef *error) { + SOSAccountTrustClassic* trust = account.trust; + CFStringRef circle_name = SOSCircleGetName(trust.trustedCircle); + CFMutableArrayRef handledRetirementIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + // We only handle one circle, look it up: + + if(!trust.trustedCircle) // We don't fail, we intentionally handle nothing. + return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); + + CFDictionaryRef retirement_dictionary = asDictionary(CFDictionaryGetValue(circle_retirement_messages, circle_name), error); + if(!retirement_dictionary) + return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); + + CFDictionaryForEach(retirement_dictionary, ^(const void *key, const void *value) { + if(isData(value)) { + SOSPeerInfoRef pi = SOSPeerInfoCreateFromData(NULL, error, (CFDataRef) value); + if(pi && CFEqual(key, SOSPeerInfoGetPeerID(pi)) && SOSPeerInfoInspectRetirementTicket(pi, error)) { + [trust.retirees addObject: (__bridge id _Nonnull)(pi)]; + + account.circle_rings_retirements_need_attention = true; // Have to handle retirements. + + CFArrayAppendValue(handledRetirementIDs, key); + } + CFReleaseNull(pi); + } + }); + + // If we are in the retiree list, we somehow got resurrected + // clearly we took care of proper departure before so leave + // and delcare that we withdrew this time. + SOSPeerInfoRef me = account.peerInfo; + + if (me && [trust.retirees containsObject:(__bridge id _Nonnull)(me)]) { + SOSAccountPurgeIdentity(account); + trust.departureCode = kSOSDiscoveredRetirement; + } + + CFDictionaryRef result = (CFArrayGetCount(handledRetirementIDs) == 0) ? CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL) + : CFDictionaryCreateForCFTypes(kCFAllocatorDefault, circle_name, handledRetirementIDs, NULL); + + CFReleaseNull(handledRetirementIDs); + return result; +} + +static SOSCircleRef SOSAccountCreateCircleFrom(CFStringRef circleName, CFTypeRef value, CFErrorRef *error) { + if (value && !isData(value) && !isNull(value)) { + secnotice("circleCreat", "Value provided not appropriate for a circle"); + CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(value)); + SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL, + CFSTR("Expected data or NULL got %@"), description); + CFReleaseSafe(description); + return NULL; + } + + SOSCircleRef circle = NULL; + if (!value || isNull(value)) { + secnotice("circleCreat", "No circle found in data: %@", value); + circle = NULL; + } else { + circle = SOSCircleCreateFromData(NULL, (CFDataRef) value, error); + if (circle) { + CFStringRef name = SOSCircleGetName(circle); + if (!CFEqualSafe(name, circleName)) { + secnotice("circleCreat", "Expected circle named %@, got %@", circleName, name); + SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL, + CFSTR("Expected circle named %@, got %@"), circleName, name); + CFReleaseNull(circle); + } + } else { + secnotice("circleCreat", "SOSCircleCreateFromData returned NULL."); + } + } + return circle; +} + +bool SOSAccountHandleCircleMessage(SOSAccount* account, + CFStringRef circleName, CFDataRef encodedCircleMessage, CFErrorRef *error) { + bool success = false; + CFErrorRef localError = NULL; + SOSCircleRef circle = SOSAccountCreateCircleFrom(circleName, encodedCircleMessage, &localError); + if (circle) { + success = [account.trust updateCircleFromRemote:account.circle_transport newCircle:circle err:&localError]; + CFReleaseSafe(circle); + } else { + secerror("NULL circle found, ignoring ..."); + success = true; // don't pend this NULL thing. + } + + if (!success) { + if (isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)) { + secerror("Incompatible circle found, abandoning membership: %@", circleName); + } + + if (error) { + *error = localError; + localError = NULL; + } + + } + + CFReleaseNull(localError); + + return success; +} + +bool SOSAccountHandleParametersChange(SOSAccount* account, CFDataRef parameters, CFErrorRef *error){ + + SecKeyRef newKey = NULL; + CFDataRef newParameters = NULL; + bool success = false; + + if(SOSAccountRetrieveCloudParameters(account, &newKey, parameters, &newParameters, error)) { + debugDumpUserParameters(CFSTR("SOSAccountHandleParametersChange got new user key parameters:"), parameters); + secnotice("keygen", "SOSAccountHandleParametersChange got new public key: %@", newKey); + + if (CFEqualSafe(account.accountKey, newKey)) { + secnotice("updates", "Got same public key sent our way. Ignoring."); + success = true; + } else if (CFEqualSafe(account.previousAccountKey, newKey)) { + secnotice("updates", "Got previous public key repeated. Ignoring."); + success = true; + } else { + SOSAccountSetUnTrustedUserPublicKey(account, newKey); + SOSAccountSetParameters(account, newParameters); + newKey = NULL; + + if(SOSAccountRetryUserCredentials(account)) { + secnotice("keygen", "Successfully used cached password with new parameters"); + SOSAccountGenerationSignatureUpdate(account, error); + } else { + secnotice("keygen", "Got new parameters for public key - could not find or use cached password"); + SOSAccountPurgePrivateCredential(account); + } + + account.circle_rings_retirements_need_attention = true; + account.key_interests_need_updating = true; + + success = true; + } + } + + CFReleaseNull(newKey); + CFReleaseNull(newParameters); + + return success; +} + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountViewSync.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountViewSync.m similarity index 71% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSAccountViewSync.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSAccountViewSync.m index 820f550b..1eba28b7 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountViewSync.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountViewSync.m @@ -14,12 +14,16 @@ #include "SOSAccountPriv.h" #include +#import +#import +#import +#import // // MARK: Helpers // -static CFMutableSetRef SOSAccountCopyOtherPeersViews(SOSAccountRef account) { +static CFMutableSetRef SOSAccountCopyOtherPeersViews(SOSAccount* account) { __block CFMutableSetRef otherPeersViews = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) { SOSPeerInfoWithEnabledViewSet(peer, ^(CFSetRef enabled) { @@ -33,23 +37,17 @@ static CFMutableSetRef SOSAccountCopyOtherPeersViews(SOSAccountRef account) { // // MARK: Outstanding tracking // - -CFMutableSetRef SOSAccountCopyOutstandingViews(SOSAccountRef account) { +CFMutableSetRef SOSAccountCopyOutstandingViews(SOSAccount* account) { CFSetRef initialSyncViews = SOSViewCopyViewSet(kViewSetAll); CFMutableSetRef result = SOSAccountCopyIntersectionWithOustanding(account, initialSyncViews); CFReleaseNull(initialSyncViews); return result; } - - -bool SOSAccountIsViewOutstanding(SOSAccountRef account, CFStringRef view) { +bool SOSAccountIsViewOutstanding(SOSAccount* account, CFStringRef view) { bool isOutstandingView; - - require_action_quiet(SOSAccountIsInCircle(account, NULL), done, isOutstandingView = true); - + require_action_quiet([account getCircleStatus:NULL] == kSOSCCInCircle, done, isOutstandingView = true); CFTypeRef unsyncedObject = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, NULL); require_action_quiet(unsyncedObject, done, isOutstandingView = false); - CFBooleanRef unsyncedBool = asBoolean(unsyncedObject, NULL); if (unsyncedBool) { isOutstandingView = CFBooleanGetValue(unsyncedBool); @@ -57,17 +55,13 @@ bool SOSAccountIsViewOutstanding(SOSAccountRef account, CFStringRef view) { CFSetRef unsyncedSet = asSet(unsyncedObject, NULL); isOutstandingView = unsyncedSet && CFSetContainsValue(unsyncedSet, view); } - done: return isOutstandingView; } - -CFMutableSetRef SOSAccountCopyIntersectionWithOustanding(SOSAccountRef account, CFSetRef inSet) { +CFMutableSetRef SOSAccountCopyIntersectionWithOustanding(SOSAccount* account, CFSetRef inSet) { CFTypeRef unsyncedObject = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, NULL); CFMutableSetRef result = NULL; - - require_quiet(SOSAccountIsInCircle(account, NULL), done); - + require_quiet([account getCircleStatus:NULL] == kSOSCCInCircle, done); CFBooleanRef unsyncedBool = asBoolean(unsyncedObject, NULL); if (unsyncedBool) { if (!CFBooleanGetValue(unsyncedBool)) { @@ -81,73 +75,55 @@ CFMutableSetRef SOSAccountCopyIntersectionWithOustanding(SOSAccountRef account, result = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); } } - done: if (result == NULL) { result = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, inSet); } - return result; } - -bool SOSAccountIntersectsWithOutstanding(SOSAccountRef account, CFSetRef views) { +bool SOSAccountIntersectsWithOutstanding(SOSAccount* account, CFSetRef views) { CFSetRef nonInitiallySyncedViews = SOSAccountCopyIntersectionWithOustanding(account, views); bool intersects = !CFSetIsEmpty(nonInitiallySyncedViews); CFReleaseNull(nonInitiallySyncedViews); return intersects; } - -bool SOSAccountHasOustandingViews(SOSAccountRef account) { +bool SOSAccountHasOustandingViews(SOSAccount* account) { bool hasOutstandingViews; - - require_action_quiet(SOSAccountIsInCircle(account, NULL), done, hasOutstandingViews = true); - + require_action_quiet([account getCircleStatus:NULL] == kSOSCCInCircle, done, hasOutstandingViews = true); CFTypeRef unsyncedObject = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, NULL); require_action_quiet(unsyncedObject, done, hasOutstandingViews = false); - CFBooleanRef unsyncedBool = asBoolean(unsyncedObject, NULL); if (unsyncedBool) { hasOutstandingViews = CFBooleanGetValue(unsyncedBool); } else { hasOutstandingViews = isSet(unsyncedBool); } - done: return hasOutstandingViews; } - - // // MARK: Initial sync functions // - -static bool SOSAccountHasCompletedInitialySyncWithSetKind(SOSAccountRef account, ViewSetKind setKind) { +static bool SOSAccountHasCompletedInitialySyncWithSetKind(SOSAccount* account, ViewSetKind setKind) { CFSetRef viewSet = SOSViewCopyViewSet(setKind); bool completedSync = !SOSAccountIntersectsWithOutstanding(account, viewSet); CFReleaseNull(viewSet); - return completedSync; } - -bool SOSAccountHasCompletedInitialSync(SOSAccountRef account) { +bool SOSAccountHasCompletedInitialSync(SOSAccount* account) { return SOSAccountHasCompletedInitialySyncWithSetKind(account, kViewSetInitial); } - -bool SOSAccountHasCompletedRequiredBackupSync(SOSAccountRef account) { +bool SOSAccountHasCompletedRequiredBackupSync(SOSAccount* account) { return SOSAccountHasCompletedInitialySyncWithSetKind(account, kViewSetRequiredForBackup); } - - // // MARK: Handling initial sync being done // -static bool SOSAccountResolvePendingViewSets(SOSAccountRef account, CFErrorRef *error) { - bool status = SOSAccountUpdateViewSets(account, - asSet(SOSAccountGetValue(account, kSOSPendingEnableViewsToBeSetKey, NULL), NULL), - asSet(SOSAccountGetValue(account, kSOSPendingDisableViewsToBeSetKey, NULL), NULL)); +static bool SOSAccountResolvePendingViewSets(SOSAccount* account, CFErrorRef *error) { + bool status = [account.trust updateViewSets:account enabled:asSet(SOSAccountGetValue(account, kSOSPendingEnableViewsToBeSetKey, NULL), NULL) disabled:asSet(SOSAccountGetValue(account, kSOSPendingDisableViewsToBeSetKey, NULL), NULL)]; if(status){ SOSAccountClearValue(account, kSOSPendingEnableViewsToBeSetKey, NULL); SOSAccountClearValue(account, kSOSPendingDisableViewsToBeSetKey, NULL); @@ -160,25 +136,26 @@ static bool SOSAccountResolvePendingViewSets(SOSAccountRef account, CFErrorRef * return status; } -static void SOSAccountCallInitialSyncBlocks(SOSAccountRef account) { +static void SOSAccountCallInitialSyncBlocks(SOSAccount* account) { CFDictionaryRef syncBlocks = NULL; - CFTransferRetained(syncBlocks, account->waitForInitialSync_blocks); + syncBlocks = CFBridgingRetain(account.waitForInitialSync_blocks); + account.waitForInitialSync_blocks = nil; if (syncBlocks) { CFDictionaryForEach(syncBlocks, ^(const void *key, const void *value) { secnotice("updates", "calling in sync block [%@]", key); - ((SOSAccountWaitForInitialSyncBlock)value)(account); + ((__bridge SOSAccountWaitForInitialSyncBlock)value)(account); }); } CFReleaseNull(syncBlocks); } -static void SOSAccountHandleRequiredBackupSyncDone(SOSAccountRef account) { +static void SOSAccountHandleRequiredBackupSyncDone(SOSAccount* account) { secnotice("initial-sync", "Handling Required Backup Sync done"); } -static void SOSAccountHandleInitialSyncDone(SOSAccountRef account) { +static void SOSAccountHandleInitialSyncDone(SOSAccount* account) { secnotice("initial-sync", "Handling initial sync done."); if(!SOSAccountResolvePendingViewSets(account, NULL)) @@ -199,19 +176,18 @@ static CFStringRef CreateUUIDString() { return result; } -CFStringRef SOSAccountCallWhenInSync(SOSAccountRef account, SOSAccountWaitForInitialSyncBlock syncBlock) { +CFStringRef SOSAccountCallWhenInSync(SOSAccount* account, SOSAccountWaitForInitialSyncBlock syncBlock) { //if we are not initially synced CFStringRef id = NULL; CFTypeRef unSyncedViews = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, NULL); if (unSyncedViews != NULL) { id = CreateUUIDString(); secnotice("initial-sync", "adding sync block [%@] to array!", id); - SOSAccountWaitForInitialSyncBlock copy = Block_copy(syncBlock); - if (account->waitForInitialSync_blocks == NULL) { - account->waitForInitialSync_blocks = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSAccountWaitForInitialSyncBlock copy = syncBlock; + if (account.waitForInitialSync_blocks == NULL) { + account.waitForInitialSync_blocks = [NSMutableDictionary dictionary]; } - CFDictionarySetValue(account->waitForInitialSync_blocks, id, copy); - Block_release(copy); + [account.waitForInitialSync_blocks setObject:copy forKey:(__bridge NSString*)id]; } else { syncBlock(account); } @@ -219,12 +195,11 @@ CFStringRef SOSAccountCallWhenInSync(SOSAccountRef account, SOSAccountWaitForIni return id; } -bool SOSAccountUnregisterCallWhenInSync(SOSAccountRef account, CFStringRef id) { - if (account->waitForInitialSync_blocks == NULL) return false; +bool SOSAccountUnregisterCallWhenInSync(SOSAccount* account, CFStringRef id) { + if (account.waitForInitialSync_blocks == NULL) return false; - bool removed = CFDictionaryGetValueIfPresent(account->waitForInitialSync_blocks, id, NULL); - CFDictionaryRemoveValue(account->waitForInitialSync_blocks, id); - return removed; + [account.waitForInitialSync_blocks removeObjectForKey: (__bridge NSString*)id]; + return true; } static void performWithInitialSyncDescription(CFTypeRef object, void (^action)(CFStringRef description)) { @@ -250,7 +225,7 @@ static bool SOSViewIntersectionWentEmpty(ViewSetKind kind, CFSetRef before, CFSe return result; } -bool SOSAccountHandleOutOfSyncUpdate(SOSAccountRef account, CFSetRef oldOOSViews, CFSetRef newOOSViews) { +bool SOSAccountHandleOutOfSyncUpdate(SOSAccount* account, CFSetRef oldOOSViews, CFSetRef newOOSViews) { bool actionTaken = false; if (SOSViewIntersectionWentEmpty(kViewSetInitial, oldOOSViews, newOOSViews)) { @@ -265,9 +240,10 @@ bool SOSAccountHandleOutOfSyncUpdate(SOSAccountRef account, CFSetRef oldOOSViews return actionTaken; } -void SOSAccountUpdateOutOfSyncViews(SOSAccountTransactionRef aTxn, CFSetRef viewsInSync) { - SOSAccountRef account = aTxn->account; - SOSCCStatus circleStatus = SOSAccountGetCircleStatus(account, NULL); +void SOSAccountUpdateOutOfSyncViews(SOSAccountTransaction* aTxn, CFSetRef viewsInSync) { + SOSAccount* account = aTxn.account; + SOSCCStatus circleStatus = [account getCircleStatus:NULL]; + bool inOrApplying = (circleStatus == kSOSCCInCircle) || (circleStatus == kSOSCCRequestPending); CFTypeRef unsyncedObject = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, NULL); @@ -331,40 +307,39 @@ void SOSAccountUpdateOutOfSyncViews(SOSAccountTransactionRef aTxn, CFSetRef view CFReleaseNull(unsyncedSet); } -void SOSAccountPeerGotInSync(SOSAccountTransactionRef aTxn, CFStringRef peerID, CFSetRef views) { - SOSAccountRef account = aTxn->account; +void SOSAccountPeerGotInSync(SOSAccountTransaction* aTxn, CFStringRef peerID, CFSetRef views) { + SOSAccount* account = aTxn.account; secnotice("initial-sync", "Peer %@ synced views: %@", peerID, views); - if (account->trusted_circle && SOSAccountIsInCircle(account, NULL) && SOSCircleHasActivePeerWithID(account->trusted_circle, peerID, NULL)) { + SOSCircleRef circle = NULL; + SOSAccountTrustClassic* trust = account.trust; + circle = trust.trustedCircle; + if (circle && [account.trust isInCircle:NULL] && SOSCircleHasActivePeerWithID(circle, peerID, NULL)) { SOSAccountUpdateOutOfSyncViews(aTxn, views); } } -static SOSEngineRef SOSAccountGetDataSourceEngine(SOSAccountRef account) { - return SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, SOSCircleGetName(account->trusted_circle), NULL); -} - -void SOSAccountEnsureSyncChecking(SOSAccountRef account) { - if (!account->isListeningForSync) { - SOSEngineRef engine = SOSAccountGetDataSourceEngine(account); +void SOSAccountEnsureSyncChecking(SOSAccount* account) { + if (!account.isListeningForSync) { + SOSEngineRef engine = [account.trust getDataSourceEngine:account.factory]; if (engine) { secnotice("initial-sync", "Setting up notifications to monitor in-sync"); - SOSEngineSetSyncCompleteListenerQueue(engine, account->queue); + SOSEngineSetSyncCompleteListenerQueue(engine, account.queue); SOSEngineSetSyncCompleteListener(engine, ^(CFStringRef peerID, CFSetRef views) { - SOSAccountWithTransaction_Locked(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { + [account performTransaction_Locked:^(SOSAccountTransaction * _Nonnull txn) { SOSAccountPeerGotInSync(txn, peerID, views); - }); + }]; }); - account->isListeningForSync = true; + account.isListeningForSync = true; } else { secerror("Couldn't find engine to setup notifications!!!"); } } } -void SOSAccountCancelSyncChecking(SOSAccountRef account) { - if (account->isListeningForSync) { - SOSEngineRef engine = SOSAccountGetDataSourceEngine(account); +void SOSAccountCancelSyncChecking(SOSAccount* account) { + if (account.isListeningForSync) { + SOSEngineRef engine = [account.trust getDataSourceEngine:account.factory]; if (engine) { secnotice("initial-sync", "Cancelling notifications to monitor in-sync"); @@ -373,15 +348,15 @@ void SOSAccountCancelSyncChecking(SOSAccountRef account) { } else { secnotice("initial-sync", "No engine to cancel notification from."); } - account->isListeningForSync = false; + account.isListeningForSync = false; } } -bool SOSAccountCheckForAlwaysOnViews(SOSAccountRef account) { +bool SOSAccountCheckForAlwaysOnViews(SOSAccount* account) { bool changed = false; - SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account); + SOSPeerInfoRef myPI = account.peerInfo; require_quiet(myPI, done); - require_quiet(SOSAccountIsInCircle(account, NULL), done); + require_quiet([account.trust isInCircle:NULL], done); require_quiet(SOSAccountHasCompletedInitialSync(account), done); CFMutableSetRef viewsToEnsure = SOSViewCopyViewSet(kViewSetAlwaysOn); // Previous version PeerInfo if we were syncing legacy keychain, ensure we include those legacy views. @@ -390,7 +365,7 @@ bool SOSAccountCheckForAlwaysOnViews(SOSAccountRef account) { CFSetUnion(viewsToEnsure, V0toAdd); CFReleaseNull(V0toAdd); } - changed = SOSAccountUpdateFullPeerInfo(account, viewsToEnsure, SOSViewsGetV0ViewSet()); // We don't permit V0 view proper, only sub-views + changed = [account.trust updateFullPeerInfo:account minimum:viewsToEnsure excluded:SOSViewsGetV0ViewSet()]; // We don't permit V0 view proper, only sub-views CFReleaseNull(viewsToEnsure); done: return changed; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupEvent.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupEvent.c index 3954b4b2..10ecd658 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupEvent.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupEvent.c @@ -125,9 +125,9 @@ static bool SOSBackupEventWrite(FILE *journalFile, CFErrorRef *error, der_end += len; require(der_end = encode(der, der_end), xit); - require_action(der == der_end, xit, SecError(-1, error, CFSTR("size mismatch der: %zu der_end: %zu"))); + require_action(der == der_end, xit, SecError(-1, error, CFSTR("size mismatch der_end - der: %td"), der_end - der)); - ok = SecCheckErrno(1 != fwrite(der, len, 1, journalFile), error, CFSTR("fwrite %s"), journalFile); + ok = SecCheckErrno(1 != fwrite(der, len, 1, journalFile), error, CFSTR("fwrite SOSBackupEventWrite")); xit: CFReleaseSafe(derObject); return ok; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.h index 6c24be26..a89ad1ff 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.h @@ -44,6 +44,6 @@ extern const CFStringRef kSOSBkpInfoStatus; extern const CFStringRef kSOSBkpInfoBSKB; extern const CFStringRef kSOSBkpInfoRKBG; -CFDictionaryRef SOSBackupInformation(SOSAccountTransactionRef txn, CFErrorRef *error); +CFDictionaryRef SOSBackupInformation(SOSAccountTransaction* txn, CFErrorRef *error); #endif /* SOSBackupInformation_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.m similarity index 86% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.m index 7f4e28a8..8b9b9177 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupInformation.m @@ -35,18 +35,20 @@ const CFStringRef kSOSBkpInfoStatus = CFSTR("BkpInfoStatus"); const CFStringRef kSOSBkpInfoBSKB = CFSTR("BkpInfoBSKB"); const CFStringRef kSOSBkpInfoRKBG = CFSTR("BkpInfoRKBG"); -CFDictionaryRef SOSBackupInformation(SOSAccountTransactionRef txn, CFErrorRef *error) { +CFDictionaryRef SOSBackupInformation(SOSAccountTransaction* txn, CFErrorRef *error) { CFNumberRef status = NULL; int ibkpInfoStatus; __block bool havebskbcontent = false; + SOSAccount *a = txn.account; + CFMutableDictionaryRef retval = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - require_action_quiet(txn && txn->account, errOut, ibkpInfoStatus = noTxnorAcct); + require_action_quiet(txn && a, errOut, ibkpInfoStatus = noTxnorAcct); require_action_quiet(retval, errOut, ibkpInfoStatus = noAlloc); require_action_quiet(txn, errOut, ibkpInfoStatus = noTxnorAcct); - SOSAccountRef account = txn->account; - require_action_quiet(account->user_public && account->user_public_trusted, errOut, ibkpInfoStatus = noTrustedPubKey); + + require_action_quiet(a.accountKey && a.accountKeyIsTrusted, errOut, ibkpInfoStatus = noTrustedPubKey); CFMutableDictionaryRef bskbders = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountForEachRing(account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) { + SOSAccountForEachRing(a, ^SOSRingRef(CFStringRef name, SOSRingRef ring) { if(SOSRingGetType(ring) == kSOSRingBackup) { CFDataRef bskbder = SOSRingGetPayload(ring, NULL); if(bskbder) CFDictionaryAddValue(bskbders, name, bskbder); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.h index 79ec67e3..0376e096 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.h @@ -37,7 +37,7 @@ extern CFStringRef bskbRkbgPrefix; // This should be fixed when we get a portable AKS interface. typedef int32_t bskb_keybag_handle_t; -typedef struct __OpaqueSOSBackupSliceKeyBag *SOSBackupSliceKeyBagRef; +typedef struct CF_BRIDGED_TYPE(id) __OpaqueSOSBackupSliceKeyBag *SOSBackupSliceKeyBagRef; CFTypeRef SOSBackupSliceKeyBageGetTypeID(void); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.m similarity index 95% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.m index 62013882..bfd2686a 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSBackupSliceKeyBag.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2015-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -50,6 +50,7 @@ #include "SOSKeyedPubKeyIdentifier.h" #include "SOSInternal.h" #include "SecADWrapper.h" +#include "SecCFAllocator.h" CFStringRef bskbRkbgPrefix = CFSTR("RK"); @@ -602,23 +603,32 @@ static bool SOSPerformWithRecoveryKeyFullKey(CFDataRef wrappingSecret, CFErrorRe bool result = false; CFStringRef keyID = NULL; + NSError *nserror = NULL; SecRecoveryKey *sRecKey = NULL; - CFDataRef fullKeyBytes = NULL; - CFDataRef pubKeyBytes = NULL; - CFStringRef restoreKeySecret = CFStringCreateWithBytes(kCFAllocatorDefault, CFDataGetBytePtr(wrappingSecret), CFDataGetLength(wrappingSecret), kCFStringEncodingUTF8, false); + NSData* fullKeyBytes = NULL; + NSData* pubKeyBytes = NULL; + CFStringRef restoreKeySecret = CFStringCreateWithBytes(SecCFAllocatorZeroize(), CFDataGetBytePtr(wrappingSecret), CFDataGetLength(wrappingSecret), kCFStringEncodingUTF8, false); require_action_quiet(restoreKeySecret, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to create key string from data."))); - sRecKey = SecRKCreateRecoveryKey(restoreKeySecret); + + sRecKey = SecRKCreateRecoveryKeyWithError((__bridge NSString *)(restoreKeySecret), &nserror); + if(!sRecKey) { + if (error) + *error = (CFErrorRef)CFBridgingRetain(nserror); + goto errOut; + } + require_action_quiet(sRecKey, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to create recovery key from string."))); + fullKeyBytes = SecRKCopyBackupFullKey(sRecKey); pubKeyBytes = SecRKCopyBackupPublicKey(sRecKey); - require_action_quiet(fullKeyBytes && pubKeyBytes, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to create recovery key public and private keys."))); - keyID = SOSCopyIDOfDataBuffer(pubKeyBytes, error); + require_action_quiet(fullKeyBytes && pubKeyBytes, errOut, SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("Unable to get recovery key public and private keys."))); + keyID = SOSCopyIDOfDataBuffer(((__bridge CFDataRef) pubKeyBytes), error); require_quiet(keyID, errOut); { - size_t keysize = ccec_compact_import_priv_size(CFDataGetLength(fullKeyBytes)); + size_t keysize = ccec_compact_import_priv_size(CFDataGetLength((__bridge CFDataRef)fullKeyBytes)); ccec_const_cp_t cp = ccec_curve_for_length_lookup(keysize, ccec_cp_256(), ccec_cp_384(), ccec_cp_521()); ccec_full_ctx_decl_cp(cp, fullKey); - int res = ccec_compact_import_priv(cp, CFDataGetLength(fullKeyBytes), CFDataGetBytePtr(fullKeyBytes), fullKey); + int res = ccec_compact_import_priv(cp, CFDataGetLength((__bridge CFDataRef)fullKeyBytes), CFDataGetBytePtr((__bridge CFDataRef)fullKeyBytes), fullKey); if(res == 0) { operation(fullKey, keyID); result = true; @@ -629,9 +639,6 @@ static bool SOSPerformWithRecoveryKeyFullKey(CFDataRef wrappingSecret, CFErrorRe errOut: CFReleaseNull(keyID); - CFReleaseNull(sRecKey); - CFReleaseNull(fullKeyBytes); - CFReleaseNull(pubKeyBytes); CFReleaseNull(restoreKeySecret); return result; } @@ -655,7 +662,9 @@ errOut: return result; } +// fixed for CrashTracer: secdtests at secdtests: SOSBSKBCopyAdditionalKeysWithPrefix static CFDictionaryRef SOSBSKBCopyAdditionalKeysWithPrefix(CFAllocatorRef allocator, SOSBackupSliceKeyBagRef bskb, CFStringRef prefix) { + if(!bskb || !bskb->wrapped_keys) return NULL; CFMutableDictionaryRef retval = CFDictionaryCreateMutableForCFTypes(allocator); if(!retval) return NULL; CFDictionaryForEach(bskb->wrapped_keys, ^(const void *key, const void *value) { @@ -674,13 +683,14 @@ static CFDictionaryRef SOSBSKBCopyAdditionalKeysWithPrefix(CFAllocatorRef alloca static bool SOSBSKBHasPrefixedKey(SOSBackupSliceKeyBagRef bskb, CFStringRef prefix) { CFDictionaryRef keyDict = SOSBSKBCopyAdditionalKeysWithPrefix(kCFAllocatorDefault, bskb, prefix); - bool haveKeys = CFDictionaryGetCount(keyDict) > 0; + bool haveKeys = keyDict && CFDictionaryGetCount(keyDict) > 0; CFReleaseNull(keyDict); return haveKeys; } CFDataRef SOSBSKBCopyRecoveryKey(SOSBackupSliceKeyBagRef bskb) { CFDictionaryRef keyDict = SOSBSKBCopyAdditionalKeysWithPrefix(kCFAllocatorDefault, bskb, bskbRkbgPrefix); + if(!keyDict) return NULL; if(CFDictionaryGetCount(keyDict) == 1) { __block CFDataRef keyData = NULL; CFDictionaryForEach(keyDict, ^(const void *key, const void *value) { diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSChangeTracker.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSChangeTracker.c index 6d68036b..cda061ef 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSChangeTracker.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSChangeTracker.c @@ -210,7 +210,12 @@ bool SOSChangeTrackerTrackChanges(SOSChangeTrackerRef ct, SOSEngineRef engine, S bool ok = true; if (changes && CFArrayGetCount(changes)) { CFStringRef changesDesc = SOSChangesCopyDescription(changes); - secnotice("tracker", "%@ %s %s changes: %@", ct, phase == kSOSDataSourceTransactionWillCommit ? "will-commit" : phase == kSOSDataSourceTransactionDidCommit ? "did-commit" : "did-rollback", source == kSOSDataSourceSOSTransaction ? "sos" : "api", changesDesc); + secnotice("tracker", "%@ %s %s changes: %@", ct, phase == kSOSDataSourceTransactionWillCommit ? "will-commit" : phase == kSOSDataSourceTransactionDidCommit ? "did-commit" : "did-rollback", + source == kSOSDataSourceSOSTransaction ? "sos" : + source == kSOSDataSourceCKKSTransaction ? "ckks" : + source == kSOSDataSourceAPITransaction ? "api" : + "unknown", + changesDesc); CFReleaseSafe(changesDesc); if (ct->manifest || ct->manifestChildren) { SOSManifestRef additions = NULL; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.c index 2dc787bd..98b3db56 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.c @@ -146,7 +146,7 @@ static bool SOSCircleDigestArray(const struct ccdigest_info *di, CFMutableArrayR { __block bool success = true; ccdigest_di_decl(di, array_digest); - const void * a_digest = array_digest; + void * a_digest = (void * )array_digest; ccdigest_init(di, array_digest); CFArraySortValues(array, CFRangeMake(0, CFArrayGetCount(array)), SOSPeerInfoCompareByID, SOSPeerCmpPubKeyHash); @@ -227,6 +227,10 @@ fail: return result; } +CFDictionaryRef SOSCircleCopyAllSignatures(SOSCircleRef circle) { + return CFDictionaryCreateCopy(kCFAllocatorDefault, circle->signatures); +} + #define circle_signature_di() ccsha256_di() static CFDataRef SecKeyCopyRawHashSignature(const struct ccdigest_info *di, const uint8_t* hashToSign, SecKeyRef privKey, CFErrorRef *error) { @@ -236,7 +240,7 @@ static CFDataRef SecKeyCopyRawHashSignature(const struct ccdigest_info *di, cons size_t signatureSpace = CFDataGetLength(signature); OSStatus status = SecKeyRawSign(privKey, kSecPaddingNone, hashToSign, di->output_size, CFDataGetMutableBytePtr(signature), &signatureSpace); - require_quiet(SecError(status, error, CFSTR("Signing failed: %d"), status), fail); + require_quiet(SecError(status, error, CFSTR("Signing failed: %d"), (int)status), fail); if (signatureSpace < (size_t)CFDataGetLength(signature)) { CFDataSetLength(signature, signatureSpace); @@ -1422,9 +1426,29 @@ void debugDumpCircle(CFStringRef message, SOSCircleRef circle) { bool SOSCircleAcceptPeerFromHSA2(SOSCircleRef circle, SecKeyRef userKey, SOSGenCountRef gencount, SecKeyRef pPubKey, CFDataRef signature, SOSFullPeerInfoRef fpi, CFErrorRef *error) { SOSPeerInfoRef peerInfo = SOSFullPeerInfoGetPeerInfo(fpi); - CFSetAddValue(circle->peers, peerInfo); + bool res; + + CFSetAddValue(circle->peers, peerInfo); + // Gen sign first, then add signature from our approver - remember gensign removes all existing sigs. - return SOSCircleGenerationSignWithGenCount(circle, userKey, fpi, gencount, error) && SOSCircleSetSignature(circle, pPubKey, signature, error) && SOSCircleVerify(circle, pPubKey, error); + res = SOSCircleGenerationSignWithGenCount(circle, userKey, fpi, gencount, error); + if (!res) { + secnotice("circleJoin", "Failed to regenerate circle with new gen count: %@", error ? *error : NULL); + return res; + } + res = SOSCircleSetSignature(circle, pPubKey, signature, error); + if (!res) { + secnotice("circleJoin", "Failed to set signature: %@", error ? *error : NULL); + return res; + } + res = SOSCircleVerify(circle, pPubKey, error); + if (!res) { + secnotice("circleJoin", "Circle failed to validate after peer signature: %@", error ? *error : NULL); + return res; + } + secnotice("circleJoin", "Circle accepted successfullyed"); + + return true; } diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.h index b5271ab8..e43c0adb 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCircle.h @@ -37,6 +37,7 @@ #include #include #include +#include __BEGIN_DECLS @@ -53,6 +54,7 @@ SOSCircleRef SOSCircleCopyCircle(CFAllocatorRef allocator, SOSCircleRef otherCir bool SOSCircleSetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFDataRef signature, CFErrorRef *error); CFDataRef SOSCircleGetSignature(SOSCircleRef circle, SecKeyRef pubkey, CFErrorRef *error); +CFDictionaryRef SOSCircleCopyAllSignatures(SOSCircleRef circle); bool SOSCircleSign(SOSCircleRef circle, SecKeyRef privkey, CFErrorRef *error); bool SOSCircleVerifySignatureExists(SOSCircleRef circle, SecKeyRef pubKey, CFErrorRef *error); bool SOSCircleVerify(SOSCircleRef circle, SecKeyRef pubkey, CFErrorRef *error); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCircleDer.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSCircleDer.c index fb0ae75b..1985c876 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCircleDer.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCircleDer.c @@ -164,3 +164,41 @@ CFDataRef SOSCircleCopyEncodedData(SOSCircleRef circle, CFAllocatorRef allocator return SOSCircleEncodeToDER(circle, error, buffer, (uint8_t *) buffer + size); }); } + +// +// Encodes data or a zero length data +// +size_t der_sizeof_data_or_null(CFDataRef data, CFErrorRef* error) +{ + if (data) { + return der_sizeof_data(data, error); + } else { + return der_sizeof_null(kCFNull, error); + } +} + +uint8_t* der_encode_data_or_null(CFDataRef data, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) +{ + if (data) { + return der_encode_data(data, error, der, der_end); + } else { + return der_encode_null(kCFNull, error, der, der_end); + } +} + + +const uint8_t* der_decode_data_or_null(CFAllocatorRef allocator, CFDataRef* data, + CFErrorRef* error, + const uint8_t* der, const uint8_t* der_end) +{ + CFTypeRef value = NULL; + der = der_decode_plist(allocator, 0, &value, error, der, der_end); + if (value && CFGetTypeID(value) != CFDataGetTypeID()) { + CFReleaseNull(value); + } + if (data) { + *data = value; + } + return der; +} + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCircleDer.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSCircleDer.h index e689cf68..48dbb678 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCircleDer.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCircleDer.h @@ -11,4 +11,12 @@ #include +size_t der_sizeof_data_or_null(CFDataRef data, CFErrorRef* error); + +uint8_t* der_encode_data_or_null(CFDataRef data, CFErrorRef* error, const uint8_t* der, uint8_t* der_end); + +const uint8_t* der_decode_data_or_null(CFAllocatorRef allocator, CFDataRef* data, + CFErrorRef* error, + const uint8_t* der, const uint8_t* der_end); + #endif /* defined(_sec_SOSCircleDer_) */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.h index 8ab0f274..ef9002aa 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.h @@ -28,6 +28,10 @@ #ifndef _SECURITY_SOSCLOUDCIRCLE_H_ #define _SECURITY_SOSCLOUDCIRCLE_H_ +#if __OBJC__ +#import +#endif + #include #include #include @@ -54,7 +58,8 @@ enum { kSOSErrorNotReady = 4, // System not yet ready (before first unlock) kSOSErrorIncompatibleCircle = 5, // We saw an incompatible circle out there. - kSOSInitialSyncFailed =6, //we timed out when syncing during approving from another device + kSOSInitialSyncFailed = 6, //we timed out when syncing during approving from another device + kSOSEntitlementMissing = 7, }; // @@ -77,6 +82,7 @@ extern const char * kSOSCCInitialSyncChangedNotification; extern const char * kSOSCCHoldLockForInitialSync; extern const char * kSOSCCPeerAvailable; extern const char * kSOSCCRecoveryKeyChanged; + /*! @function SOSCCSetUserCredentials @abstract Uses the user authentication credential (password) to create an internal EC Key Pair for authenticating Circle changes. @@ -432,14 +438,6 @@ bool SOSCCRejectApplicants(CFArrayRef applicants, CFErrorRef *error); */ CFArrayRef SOSCCCopyPeerPeerInfo(CFErrorRef* error); -/*! - @function SOSCCSetAutoAcceptInfo - @abstract Arms auto-acceptance for the HSA2 data given. - @param error What went wrong. - @result true if the operation succeeded, otherwise false. - */ -bool SOSCCSetAutoAcceptInfo(CFDataRef autoaccept, CFErrorRef *error); - /*! @function SOSCCCheckPeerAvailability @abstract Prompts KeychainSyncingOverIDSProxy to query all devices in the circle with the same view. @@ -553,6 +551,13 @@ extern const CFStringRef kSOSViewAppleTV; extern const CFStringRef kSOSViewHomeKit; extern const CFStringRef kSOSViewContinuityUnlock; extern const CFStringRef kSOSViewAccessoryPairing; +extern const CFStringRef kSOSViewNanoRegistry; +extern const CFStringRef kSOSViewWatchMigration; +extern const CFStringRef kCKKSViewEngram; +extern const CFStringRef kCKKSViewManatee; +extern const CFStringRef kCKKSViewAutoUnlock; +extern const CFStringRef kCKKSViewHealth; + /*! @function SOSCCView @@ -708,7 +713,7 @@ CFDataRef SOSCCCopyCircleJoiningBlob(SOSPeerInfoRef applicant, CFErrorRef *error @result true if this succeeded. */ -bool SOSCCJoinWithCircleJoiningBlob(CFDataRef joiningBlob, CFErrorRef *error); +bool SOSCCJoinWithCircleJoiningBlob(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); /*! @function: bool SOSCCPeersHaveViewsEnabled(CFSetRef viewNames) @@ -733,7 +738,7 @@ bool SOSCCRegisterRecoveryPublicKey(CFDataRef recovery_key, CFErrorRef *error); @function: bool SOSCCMessageFromPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error) @param peer PeerInfo for the peer to ask about @param error failure if we fail - @reulst true if we have a message pending that we haven't processed, false if we don't have one queued right now or an error occurred. + @result true if we have a message pending that we haven't processed, false if we don't have one queued right now or an error occurred. */ bool SOSCCMessageFromPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error); @@ -741,10 +746,28 @@ bool SOSCCMessageFromPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error); @function: bool SOSCCSendToPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error) @param peer PeerInfo for the peer to ask about @param error failure if we fail - @reulst true if we have an attempt to sync pending that we haven't processed, false if we don't have one queued right now or an error occurred. + @result true if we have an attempt to sync pending that we haven't processed, false if we don't have one queued right now or an error occurred. */ bool SOSCCSendToPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error); +#if __OBJC__ +/* + @function: SOSCCAccountGetPublicKey + @param reply fetch the current user public key as SubjectPublicKeyInfoi + */ +void SOSCCAccountGetPublicKey(void (^reply)(BOOL trusted, NSData *data, NSError *error)); + +/* + @function: SOSCCAccountGetAccountPrivateCredential + @param reply fetch the current user public key as SubjectPublicKeyInfoi + */ +void SOSCCAccountGetAccountPrivateCredential(void (^complete)(NSData *data, NSError *error)); + +void SOSCCAccountGetKeyCircleGeneration(void (^reply)(NSData *data, NSError *error)); + +CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error); + +#endif __END_DECLS diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.m similarity index 89% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.m index 15824158..77c15ccf 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircle.m @@ -25,18 +25,22 @@ // SOSCloudCircle.m // +#import +#import + #include #include #include #include #include #include -#include #include #include #include #include #include +#include +#include #include #include @@ -49,6 +53,8 @@ #include #include +#include + #include #include @@ -67,7 +73,6 @@ const char * kSOSCCInitialSyncChangedNotification = "com.apple.security.secureob const char * kSOSCCHoldLockForInitialSync = "com.apple.security.secureobjectsync.holdlock"; const char * kSOSCCPeerAvailable = "com.apple.security.secureobjectsync.peeravailable"; const char * kSOSCCRecoveryKeyChanged = "com.apple.security.secureobjectsync.recoverykeychanged"; -const CFStringRef kSOSErrorDomain = CFSTR("com.apple.security.sos.error"); #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); } @@ -104,13 +109,8 @@ SOSCCStatus SOSCCThisDeviceIsInCircle(CFErrorRef *error) free((void *)desc); } } - if(response) - xpc_release(response); - if(message) - xpc_release(message); } - return result; }, CFSTR("SOSCCStatus=%d")) } @@ -126,7 +126,7 @@ static bool cfstring_to_error_request(enum SecXPCOperation op, CFStringRef strin if (xString){ xpc_dictionary_set_value(message, kSecXPCKeyString, xString); success = true; - xpc_release(xString); + xString = nil; } return success; }, ^bool(xpc_object_t response, __unused CFErrorRef *error) { @@ -166,7 +166,7 @@ static SOSRingStatus cfstring_to_uint64_request(enum SecXPCOperation op, CFStrin if (xString){ xpc_dictionary_set_value(message, kSecXPCKeyString, xString); success = true; - xpc_release(xString); + xString = nil; } return success; }, ^bool(xpc_object_t response, __unused CFErrorRef *error) { @@ -274,7 +274,7 @@ static bool escrow_to_bool_error_request(enum SecXPCOperation op, CFStringRef es if (xEscrowLabel){ xpc_dictionary_set_value(message, kSecXPCKeyEscrowLabel, xEscrowLabel); success = true; - xpc_release(xEscrowLabel); + xEscrowLabel = nil; } if(tries){ xpc_dictionary_set_int64(message, kSecXPCKeyTriesLabel, tries); @@ -378,13 +378,12 @@ static SOSPeerInfoRef peer_info_error_request(enum SecXPCOperation op, CFErrorRe return data != NULL; }); - if (!isData(data)) { - SOSErrorCreate(kSOSErrorUnexpectedType, error, NULL, CFSTR("Expected CFData, got: %@"), result); - } - - if (data) { + if (isData(data)) { result = SOSPeerInfoCreateFromData(kCFAllocatorDefault, error, data); + } else { + SOSErrorCreate(kSOSErrorUnexpectedType, error, NULL, CFSTR("Expected CFData, got: %@"), data); } + CFReleaseNull(data); return result; } @@ -442,7 +441,7 @@ static CF_RETURNS_RETAINED SOSPeerInfoRef data_to_peer_info_error_request(enum S if (xsecretData){ xpc_dictionary_set_value(message, kSecXPCKeyNewPublicBackupKey, xsecretData); success = true; - xpc_release(xsecretData); + xsecretData = nil; } return success; }, ^bool(xpc_object_t response, __unused CFErrorRef *error) { @@ -450,16 +449,15 @@ static CF_RETURNS_RETAINED SOSPeerInfoRef data_to_peer_info_error_request(enum S if (response && (NULL != temp_result)) { data = _CFXPCCreateCFObjectFromXPCObject(temp_result); } - return result != NULL; + return data != NULL; }); - if (!isData(data)) { - SOSErrorCreate(kSOSErrorUnexpectedType, error, NULL, CFSTR("Expected CFData, got: %@"), result); - } - - if (data) { + if (isData(data)) { result = SOSPeerInfoCreateFromData(kCFAllocatorDefault, error, data); + } else { + SOSErrorCreate(kSOSErrorUnexpectedType, error, NULL, CFSTR("Expected CFData, got: %@"), data); } + CFReleaseNull(data); return result; } @@ -472,7 +470,7 @@ static bool keybag_and_bool_to_bool_error_request(enum SecXPCOperation op, CFDat bool success = false; if (xData){ xpc_dictionary_set_value(message, kSecXPCKeyKeybag, xData); - xpc_release(xData); + xData = nil; success = true; } xpc_dictionary_set_bool(message, kSecXPCKeyIncludeV0, include); @@ -490,7 +488,7 @@ static bool recovery_and_bool_to_bool_error_request(enum SecXPCOperation op, CFD bool success = false; if (xData){ xpc_dictionary_set_value(message, kSecXPCKeyRecoveryPublicKey, xData); - xpc_release(xData); + xData = nil; success = true; } return success; @@ -544,8 +542,8 @@ static bool cfstring_and_cfdata_to_cfdata_cfdata_error_request(enum SecXPCOperat xpc_dictionary_set_value(message, kSecXPCKeyViewName, xviewname); xpc_dictionary_set_value(message, kSecXPCData, xinput); success = true; - xpc_release(xviewname); - xpc_release(xinput); + xviewname = nil; + xinput = nil; } return success; }, ^bool(xpc_object_t response, __unused CFErrorRef *error) { @@ -573,34 +571,8 @@ static bool cfstring_and_cfdata_to_cfdata_cfdata_error_request(enum SecXPCOperat return result; } -static bool set_hsa2_autoaccept_error_request(enum SecXPCOperation op, CFDataRef pubKey, CFErrorRef *error) -{ - __block bool result = false; - - sec_trace_enter_api(NULL); - securityd_send_sync_and_do(op, error, ^(xpc_object_t message, - CFErrorRef *error) { - xpc_object_t xpubkey = _CFXPCCreateXPCObjectFromCFObject(pubKey); - bool success = false; - if (xpubkey) { - xpc_dictionary_set_value(message, - kSecXPCKeyHSA2AutoAcceptInfo, xpubkey); - success = true; - xpc_release(xpubkey); - } - - return success; - }, ^(xpc_object_t response, __unused CFErrorRef *error) { - result = xpc_dictionary_get_bool(response, kSecXPCKeyResult); - return (bool)true; - }); - - return result; -} - - - -static bool cfdata_error_request_returns_bool(enum SecXPCOperation op, CFDataRef thedata, CFErrorRef *error) { +static bool cfdata_and_int_error_request_returns_bool(enum SecXPCOperation op, CFDataRef thedata, + PiggyBackProtocolVersion version, CFErrorRef *error) { __block bool result = false; sec_trace_enter_api(NULL); @@ -609,8 +581,9 @@ static bool cfdata_error_request_returns_bool(enum SecXPCOperation op, CFDataRef bool success = false; if (xdata) { xpc_dictionary_set_value(message, kSecXPCData, xdata); + xpc_dictionary_set_uint64(message, kSecXPCVersion, version); success = true; - xpc_release(xdata); + xdata = nil; } return success; @@ -622,7 +595,6 @@ static bool cfdata_error_request_returns_bool(enum SecXPCOperation op, CFDataRef return result; } - static CFDataRef cfdata_error_request_returns_cfdata(enum SecXPCOperation op, CFDataRef thedata, CFErrorRef *error) { __block CFDataRef result = NULL; @@ -633,7 +605,7 @@ static CFDataRef cfdata_error_request_returns_cfdata(enum SecXPCOperation op, CF if (xdata) { xpc_dictionary_set_value(message, kSecXPCData, xdata); success = true; - xpc_release(xdata); + xdata = nil; } return success; }, ^(xpc_object_t response, __unused CFErrorRef *error) { @@ -863,15 +835,6 @@ CFArrayRef SOSCCCopyPeerPeerInfo(CFErrorRef* error) }, CFSTR("return=%@")); } -bool SOSCCSetAutoAcceptInfo(CFDataRef autoaccept, CFErrorRef *error) -{ - sec_trace_return_bool_api(^{ - do_if_registered(soscc_SetHSA2AutoAcceptInfo, autoaccept, error); - - return set_hsa2_autoaccept_error_request(kSecXPCOpSetHSA2AutoAcceptInfo, autoaccept, error); - }, NULL) -} - CFArrayRef SOSCCCopyConcurringPeerPeerInfo(CFErrorRef* error) { sec_trace_enter_api(NULL); @@ -1104,11 +1067,8 @@ static CF_RETURNS_RETAINED SOSPeerInfoRef SOSSetNewPublicBackupKey(CFDataRef pub SOSPeerInfoRef SOSCCCopyMyPeerWithNewDeviceRecoverySecret(CFDataRef secret, CFErrorRef *error){ CFDataRef publicKeyData = SOSCopyDeviceBackupPublicKey(secret, error); - SOSPeerInfoRef copiedPeer = publicKeyData ? SOSSetNewPublicBackupKey(publicKeyData, error) : NULL; - CFReleaseNull(publicKeyData); - return copiedPeer; } @@ -1124,8 +1084,16 @@ bool SOSCCRegisterSingleRecoverySecret(CFDataRef aks_bag, bool forV0Only, CFErro bool SOSCCRegisterRecoveryPublicKey(CFDataRef recovery_key, CFErrorRef *error){ sec_trace_enter_api(NULL); sec_trace_return_bool_api(^{ + bool retval = false; do_if_registered(soscc_RegisterRecoveryPublicKey, recovery_key, error); - return recovery_and_bool_to_bool_error_request(kSecXPCOpRegisterRecoveryPublicKey, recovery_key, error); + if(!recovery_key) { // this is used to clear the rk + CFDataRef empty = CFDataCreate(kCFAllocatorDefault, 0, 0); + retval = recovery_and_bool_to_bool_error_request(kSecXPCOpRegisterRecoveryPublicKey, empty, error); + CFReleaseNull(empty); + } else { + retval = recovery_and_bool_to_bool_error_request(kSecXPCOpRegisterRecoveryPublicKey, recovery_key, error); + } + return retval; }, NULL); } @@ -1494,7 +1462,7 @@ CFStringRef SOSCCGetStatusDescription(SOSCCStatus status) case kSOSCCError: return CFSTR("InternalError"); default: - return CFSTR("Unknown Status (%d)"); + return CFSTR("Unknown Status"); }; } @@ -1506,6 +1474,26 @@ CFStringRef SOSCCGetStatusDescription(SOSCCStatus status) kSOSCCNoSuchView = 3, #endif + +CFStringRef SOSCCGetViewResultDescription(SOSViewResultCode vrc) +{ + switch (vrc) { + case kSOSCCGeneralViewError: + return CFSTR("GeneralViewError"); + case kSOSCCViewMember: + return CFSTR("ViewMember"); + case kSOSCCViewNotMember: + return CFSTR("ViewNotMember"); + case kSOSCCViewNotQualified: + return CFSTR("ViewNotQualified"); + case kSOSCCNoSuchView: + return CFSTR("ViewUndefined"); + default: + return CFSTR("Unknown View Status"); + }; +} + + static int64_t name_action_to_code_request(enum SecXPCOperation op, uint16_t error_result, CFStringRef name, uint64_t action, CFErrorRef *error) { __block int64_t result = error_result; @@ -1581,28 +1569,54 @@ SOSSecurityPropertyResultCode SOSCCSecurityProperty(CFStringRef property, SOSSec } } if(response) - xpc_release(response); + response = nil; if(message) - xpc_release(message); + message = nil; } return result; }, CFSTR("SOSSecurityPropertyResultCode=%d")) } +static CFStringRef copyViewNames(size_t n, CFStringRef *views) { + CFMutableStringRef retval = CFStringCreateMutable(kCFAllocatorDefault, 0); + CFStringAppend(retval, CFSTR("|")); + for(size_t i = 0; i < n; i++) { + CFStringAppend(retval, views[i]); + CFStringAppend(retval, CFSTR("|")); + } + return retval; +} static bool sosIsViewSetSyncing(size_t n, CFStringRef *views) { __block bool retval = true; + CFErrorRef error = NULL; - SOSCCStatus cstatus = SOSCCThisDeviceIsInCircle(NULL); - if(cstatus == kSOSCCInCircle) { + if(n == 0 || views == NULL) return false; + CFStringRef viewString = copyViewNames(n, views); + + SOSCCStatus cstatus = SOSCCThisDeviceIsInCircle(&error); + if(cstatus != kSOSCCInCircle) { + secnotice("viewCheck", "Checking view / circle status for %@: SOSCCStatus: (%@) Error: (%@)", viewString, SOSCCGetStatusDescription(cstatus), error); + retval = false; + } + + if(retval == true) { for(size_t i = 0; i < n; i++) { - SOSViewResultCode vstatus = SOSCCView(views[i], kSOSCCViewQuery, NULL); - if(vstatus != kSOSCCViewMember) retval = false; + SOSViewResultCode vstatus = SOSCCView(views[i], kSOSCCViewQuery, &error); + if(vstatus != kSOSCCViewMember) { + secnotice("viewCheck", "Checking view / circle status for %@: SOSCCStatus: (%@) SOSViewResultCode(%@) Error: (%@)", views[i], + SOSCCGetStatusDescription(cstatus), SOSCCGetViewResultDescription(vstatus), error); + retval = false; + } } - } else { - retval = false; } + + if(retval == true) { + secnotice("viewCheck", "Checking view / circle status for %@: ENABLED", viewString); + } + CFReleaseNull(error); + CFReleaseNull(viewString); return retval; } @@ -1699,6 +1713,30 @@ SOSPeerInfoRef SOSCCCopyApplication(CFErrorRef *error) { }, CFSTR("return=%@")); } +bool SOSCCCleanupKVSKeys(CFErrorRef *error) { + secnotice("cleanup-keys", "enter SOSCCCleanupKVSKeys"); + sec_trace_enter_api(NULL); + sec_trace_return_bool_api(^{ + do_if_registered(soscc_SOSCCCleanupKVSKeys, error); + + return simple_bool_error_request(kSecXPCOpKVSKeyCleanup, error); + }, NULL) + + return false; +} + +bool SOSCCTestPopulateKVSWithBadKeys(CFErrorRef *error) { + secnotice("cleanup-keys", "enter SOSCCPopulateKVSWithBadKeys"); + sec_trace_enter_api(NULL); + sec_trace_return_bool_api(^{ + do_if_registered(soscc_SOSCCTestPopulateKVSWithBadKeys, error); + + return simple_bool_error_request(kSecXPCOpPopulateKVS, error); + }, NULL) + + return false; +} + CFDataRef SOSCCCopyCircleJoiningBlob(SOSPeerInfoRef applicant, CFErrorRef *error) { secnotice("hsa2PB", "enter SOSCCCopyCircleJoiningBlob approver"); sec_trace_enter_api(NULL); @@ -1713,13 +1751,23 @@ CFDataRef SOSCCCopyCircleJoiningBlob(SOSPeerInfoRef applicant, CFErrorRef *error }, CFSTR("return=%@")); } -bool SOSCCJoinWithCircleJoiningBlob(CFDataRef joiningBlob, CFErrorRef *error) { +CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error) { + secnotice("circleJoin", "enter SOSCCCopyInitialSyncData approver"); + sec_trace_enter_api(NULL); + + sec_trace_return_api(CFDataRef, ^{ + do_if_registered(soscc_CopyInitialSyncData, error); + return data_to_error_request(kSecXPCOpCopyInitialSyncBlob, error); + }, CFSTR("return=%@")); +} + +bool SOSCCJoinWithCircleJoiningBlob(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) { secnotice("hsa2PB", "enter SOSCCJoinWithCircleJoiningBlob applicant"); sec_trace_enter_api(NULL); sec_trace_return_bool_api(^{ - do_if_registered(soscc_JoinWithCircleJoiningBlob, joiningBlob, error); + do_if_registered(soscc_JoinWithCircleJoiningBlob, joiningBlob, version, error); - return cfdata_error_request_returns_bool(kSecXPCOpJoinWithCircleJoiningBlob, joiningBlob, error); + return cfdata_and_int_error_request_returns_bool(kSecXPCOpJoinWithCircleJoiningBlob, joiningBlob, version, error); }, NULL) return false; @@ -1762,5 +1810,103 @@ bool SOSCCSendToPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error) { return peer_info_to_bool_error_request(kSecXPCOpSendToPeerIsPending, peer, error); }, NULL) +} + +/* + * SecSOSStatus interfaces + */ + +@interface SecSOSStatus : NSObject { + NSXPCConnection* _connection; +} +@property NSXPCConnection *connection; +@end + +@implementation SecSOSStatus +@synthesize connection = _connection; + +- (instancetype) initWithEndpoint:(xpc_endpoint_t)endpoint +{ + if ((self = [super init]) == NULL) + return NULL; + NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SOSControlProtocol)]; + _SOSControlSetupInterface(interface); + NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; + + [listenerEndpoint _setEndpoint:endpoint]; + + self.connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; + if (self.connection == NULL) + return NULL; + + self.connection.remoteObjectInterface = interface; + + [self.connection resume]; + + return self; +} + +@end + +static id +SOSCCGetStatusObject(CFErrorRef *error) +{ + if (gSecurityd && gSecurityd->soscc_status) + return (__bridge id)gSecurityd->soscc_status(); + + static SecSOSStatus *control; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + xpc_endpoint_t endpoint = _SecSecuritydCopySOSStatusEndpoint(error); + if (endpoint == NULL) + return; + + control = [[SecSOSStatus alloc] initWithEndpoint:endpoint]; + }); + return control.connection.remoteObjectProxy; +} + +void +SOSCCAccountGetPublicKey(void (^reply)(BOOL trusted, NSData *data, NSError *error)) +{ + CFErrorRef error = NULL; + id status = SOSCCGetStatusObject(&error); + if (status == NULL) { + reply(false, NULL, (__bridge NSError *)error); + CFReleaseNull(error); + return; + } + + [status userPublicKey:reply]; +} + +void +SOSCCAccountGetAccountPrivateCredential(void (^complete)(NSData *data, NSError *error)) +{ + CFErrorRef error = NULL; + id status = SOSCCGetStatusObject(&error); + if (status == NULL) { + complete(NULL, (__bridge NSError *)error); + CFReleaseNull(error); + return; + } + + [status validatedStashedAccountCredential:complete]; } + +void +SOSCCAccountGetKeyCircleGeneration(void (^reply)(NSData *data, NSError *error)) +{ + SOSCCAccountGetPublicKey(^(BOOL __unused trusted, NSData *data, NSError *error){ + if (data == NULL) { + reply(data, error); + } else { + NSMutableData *digest = [NSMutableData dataWithLength:CCSHA256_OUTPUT_SIZE]; + ccdigest(ccsha256_di(), [data length], [data bytes], [digest mutableBytes]); + reply(digest, error); + } + }); +} + + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircleInternal.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircleInternal.h index 82e2a4e4..c901d102 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircleInternal.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCloudCircleInternal.h @@ -30,7 +30,6 @@ #include #include -//#include // only included for SOSRingStatus, see rdar://problem/20831215 before uncommenting __BEGIN_DECLS @@ -55,6 +54,7 @@ CFArrayRef SOSCCCopyConcurringPeerPeerInfo(CFErrorRef* error); bool SOSCCPurgeUserCredentials(CFErrorRef* error); CFStringRef SOSCCGetStatusDescription(SOSCCStatus status); +CFStringRef SOSCCGetViewResultDescription(SOSViewResultCode vrc); bool SOSCCAccountHasPublicKey(CFErrorRef *error); bool SOSCCAccountIsNew(CFErrorRef *error); @@ -91,6 +91,7 @@ bool SOSCCWithdrawlFromARing(CFStringRef ringName, CFErrorRef* error); int SOSCCRingStatus(CFStringRef ringName, CFErrorRef* error); // TODO: this returns SOSRingStatus bool SOSCCEnableRing(CFStringRef ringName, CFErrorRef* error); +bool SOSCCCleanupKVSKeys(CFErrorRef *error); /*! @@ -146,7 +147,9 @@ bool SOSCCClearPeerMessageKeyInKVS(CFStringRef peerID, CFErrorRef *error); CFDataRef SOSCCCopyRecoveryPublicKey(CFErrorRef *error); CFDictionaryRef SOSCCCopyBackupInformation(CFErrorRef *error); bool SOSCCRequestSyncWithPeerOverKVSUsingIDOnly(CFStringRef peerID, CFErrorRef *error); - +bool SOSCCTestPopulateKVSWithBadKeys(CFErrorRef *error); +CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error); + char *SOSCCSysdiagnose(const char *directoryname); void SOSCCForEachEngineStateAsStringFromArray(CFArrayRef states, void (^block)(CFStringRef oneStateString)); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.c index 1a57d845..44cecd77 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -104,23 +105,6 @@ static const char *SOSCoderString(SOSCoderStatus coderStatus) { } } -/* - static void logRawCoderMessage(const uint8_t* der, uint8_t* der_end, bool encoding) -{ -#ifndef NDEBUG - CFStringRef hexMessage = NULL; - if (der && der_end) { - CFIndex length = der_end - der; - CFDataRef message = CFDataCreate(kCFAllocatorDefault, der, length); - hexMessage = CFDataCopyHexString(message); - secnoticeq("coder", "%s RAW [%ld] %@", encoding ? "encode" : "decode", length, hexMessage); - CFReleaseSafe(message); - } - CFReleaseSafe(hexMessage); -#endif -} -*/ - static CFMutableDataRef sessSerializedCreate(SOSCoderRef coder, CFErrorRef *error) { CFMutableDataRef otr_state = NULL; @@ -188,6 +172,9 @@ static uint8_t* SOSCoderEncodeToDER(SOSCoderRef coder, CFErrorRef* error, const return result; } +bool SOSCoderIsCoderInAwaitingState(SOSCoderRef coder){ + return SecOTRSessionIsSessionInAwaitingState(coder->sessRef); +} CFDataRef SOSCoderCopyDER(SOSCoderRef coder, CFErrorRef* error) { CFMutableDataRef encoded = NULL; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.h index c6e831b5..862d398a 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSCoder.h @@ -41,6 +41,7 @@ enum { kSOSCoderTooNew = 5, kSOSCoderForceMessage = 6, }; + typedef uint32_t SOSCoderStatus; CFTypeID SOSCoderGetTypeID(void); @@ -73,6 +74,6 @@ void SOSCoderReset(SOSCoderRef coder); CFDataRef SOSCoderCopyPendingResponse(SOSCoderRef coder); void SOSCoderConsumeResponse(SOSCoderRef coder); - - +bool SOSCoderIsCoderInAwaitingState(SOSCoderRef coder); + #endif // _SEC_SOSCODER_H_ diff --git a/OSX/libsecurity_codesigning/lib/SecIntegrity.cpp b/OSX/sec/SOSCircle/SecureObjectSync/SOSControlHelper.h similarity index 85% rename from OSX/libsecurity_codesigning/lib/SecIntegrity.cpp rename to OSX/sec/SOSCircle/SecureObjectSync/SOSControlHelper.h index dc266a02..34508f30 100644 --- a/OSX/libsecurity_codesigning/lib/SecIntegrity.cpp +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSControlHelper.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2007,2011 Apple Inc. All Rights Reserved. - * + * 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, @@ -17,10 +17,11 @@ * 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 -#include "SecIntegrity.h" +#import +void +_SOSControlSetupInterface(NSXPCInterface *interface); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSControlHelper.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSControlHelper.m new file mode 100644 index 00000000..4ff588d1 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSControlHelper.m @@ -0,0 +1,66 @@ +/* + * 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 +#import +#import +#import +#import + +void +_SOSControlSetupInterface(NSXPCInterface *interface) +{ + static NSMutableSet *errClasses; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + errClasses = [NSMutableSet set]; + + char *classes[] = { + "NSURL", + "NSURLError", + "NSError" + }; + + 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(userPublicKey:) argumentIndex:2 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(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]; +} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSDataSource.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSDataSource.h index c434c5af..84a34ce4 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSDataSource.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSDataSource.h @@ -110,9 +110,11 @@ enum SOSDataSourceTransactionPhase { }; typedef CFOptionFlags SOSDataSourceTransactionPhase; +// These must match the values in SecDbTransactionSource enum SOSDataSourceTransactionSource { - kSOSDataSourceSOSTransaction, // A remotely initated transaction. - kSOSDataSourceAPITransaction, // A user initated transaction. + kSOSDataSourceSOSTransaction = 0, // A remotely initated transaction. + kSOSDataSourceCKKSTransaction = 3, // A transaction initiated by CKKS. + kSOSDataSourceAPITransaction = 1, // A user initated transaction. }; typedef CFOptionFlags SOSDataSourceTransactionSource; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSECWrapUnwrap.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSECWrapUnwrap.c index f23285c9..6b84d445 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSECWrapUnwrap.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSECWrapUnwrap.c @@ -27,7 +27,7 @@ const char fingerprint[20] = "fingerprint"; const uint8_t kAlgorithmID = 1; CFMutableDataRef -SOSCopyECWrappedData(ccec_pub_ctx *ec_ctx, CFDataRef data, CFErrorRef *error) +SOSCopyECWrappedData(ccec_pub_ctx_t ec_ctx, CFDataRef data, CFErrorRef *error) { CFMutableDataRef result = NULL; CFMutableDataRef output = NULL; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSEngine.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSEngine.c index 05313501..29c6464d 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSEngine.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSEngine.c @@ -35,6 +35,7 @@ #include #include #include + #include #include #include @@ -52,6 +53,7 @@ #include #include + #include #include @@ -62,6 +64,8 @@ #include #include +#include + #include // @@ -560,8 +564,8 @@ static bool SOSEngineSaveCoders(SOSEngineRef engine, SOSTransactionRef txn, CFEr return ok; } -bool SOSTestEngineSaveCoders(SOSEngineRef engine, SOSTransactionRef txn, CFErrorRef *error){ - return SOSEngineSaveCoders(engine, txn, error); +bool SOSTestEngineSaveCoders(CFTypeRef engine, SOSTransactionRef txn, CFErrorRef *error){ + return SOSEngineSaveCoders((SOSEngineRef)engine, txn, error); } #if !TARGET_IPHONE_SIMULATOR @@ -700,9 +704,9 @@ CFMutableDictionaryRef derStateToDictionaryCopy(CFDataRef state, CFErrorRef *err } return stateDict; } -bool TestSOSEngineLoadCoders(SOSEngineRef engine, SOSTransactionRef txn, CFErrorRef *error) +bool TestSOSEngineLoadCoders(CFTypeRef engine, SOSTransactionRef txn, CFErrorRef *error) { - return SOSEngineLoadCoders(engine, txn, error); + return SOSEngineLoadCoders((SOSEngineRef)engine, txn, error); } static bool SOSEngineLoadCoders(SOSEngineRef engine, SOSTransactionRef txn, CFErrorRef *error) { @@ -891,7 +895,7 @@ static void SOSEngineObjectWithView(SOSEngineRef engine, SOSObjectRef object, vo } else if (SecDbItemIsSyncableOrCorrupted(item)) { const SecDbClass *iclass = SecDbItemGetClass(item); CFTypeRef pdmn = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible); - if ((iclass == &genp_class || iclass == &inet_class || iclass == &keys_class || iclass == &cert_class) + if ((iclass == genp_class() || iclass == inet_class() || iclass == keys_class() || iclass == cert_class()) && isString(pdmn) && (CFEqual(pdmn, kSecAttrAccessibleWhenUnlocked) || CFEqual(pdmn, kSecAttrAccessibleAfterFirstUnlock) @@ -904,21 +908,27 @@ static void SOSEngineObjectWithView(SOSEngineRef engine, SOSObjectRef object, vo char cvalue = 0; bool isTomb = (isNumber(tomb) && CFNumberGetValue(tomb, kCFNumberCharType, &cvalue) && cvalue == 1); CFTypeRef viewHint = SecDbItemGetCachedValueWithName(item, kSecAttrSyncViewHint); + + // Intecept CKKS-handled items here and short-circuit function + if(SOSViewHintInCKKSSystem(viewHint)) { + return; + } + if (viewHint == NULL) { - if (iclass == &cert_class) { + if (iclass == cert_class()) { withViewAndBackup(kSOSViewOtherSyncable); } else { if (!SecDbItemGetCachedValueWithName(item, kSecAttrTokenID)) { withViewAndBackup(kSOSViewKeychainV0); } CFTypeRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup); - if (iclass == &keys_class && CFEqualSafe(agrp, CFSTR("com.apple.security.sos"))) { + if (iclass == keys_class() && CFEqualSafe(agrp, CFSTR("com.apple.security.sos"))) { withViewAndBackup(kSOSViewiCloudIdentity); } else if (CFEqualSafe(agrp, CFSTR("com.apple.cfnetwork"))) { withViewAndBackup(kSOSViewAutofillPasswords); } else if (CFEqualSafe(agrp, CFSTR("com.apple.safari.credit-cards"))) { withViewAndBackup(kSOSViewSafariCreditCards); - } else if (iclass == &genp_class) { + } else if (iclass == genp_class()) { if (CFEqualSafe(agrp, CFSTR("apple")) && CFEqualSafe(SecDbItemGetCachedValueWithName(item, kSecAttrService), CFSTR("AirPort"))) { withViewAndBackup(kSOSViewWiFi); @@ -1126,7 +1136,12 @@ static bool SOSChangeMapperSend(struct SOSChangeMapper *cm, CFErrorRef *error) { static bool SOSEngineUpdateChanges_locked(SOSEngineRef engine, SOSTransactionRef txn, SOSDataSourceTransactionPhase phase, SOSDataSourceTransactionSource source, CFArrayRef changes, CFErrorRef *error) { - secnoticeq("engine", "%@: %s %s %ld changes, txn=%@, %p", engine->myID, phase == kSOSDataSourceTransactionWillCommit ? "will-commit" : phase == kSOSDataSourceTransactionDidCommit ? "did-commit" : "did-rollback", source == kSOSDataSourceSOSTransaction ? "sos" : "api", CFArrayGetCount(changes), txn, txn); + secnoticeq("engine", "%@: %s %s %ld changes, txn=%@, %p", engine->myID, phase == kSOSDataSourceTransactionWillCommit ? "will-commit" : phase == kSOSDataSourceTransactionDidCommit ? "did-commit" : "did-rollback", + source == kSOSDataSourceSOSTransaction ? "sos" : + source == kSOSDataSourceCKKSTransaction ? "ckks" : + source == kSOSDataSourceAPITransaction ? "api" : + "unknown", + CFArrayGetCount(changes), txn, txn); bool ok = true; switch (phase) { case kSOSDataSourceTransactionDidRollback: @@ -1187,16 +1202,22 @@ static bool SOSEngineUpdateChanges_locked(SOSEngineRef engine, SOSTransactionRef // writing to the DBConn will cause deadlocks. if (mappedItemChanged || source == kSOSDataSourceSOSTransaction) { // Write SOSEngine and SOSPeer state to disk - secnotice("engine", "saving engine state"); - ok &= SOSEngineSave(engine, txn, error); - - if (kSOSDataSourceAPITransaction == source) - SOSCCRequestSyncWithPeersList(engine->peerIDs); +#if OCTAGON + if(!SecCKKSTestDisableSOS()) { +#endif + secnotice("engine", "saving engine state"); + ok &= SOSEngineSave(engine, txn, error); + + if (kSOSDataSourceAPITransaction == source || kSOSDataSourceCKKSTransaction == source) + SOSCCRequestSyncWithPeersList(engine->peerIDs); +#if OCTAGON + } +#endif } else { - secnotice("engine", "Not saving engine state, nothing changed."); + secinfo("engine", "Not saving engine state, nothing changed."); } } - + break; } } @@ -1653,9 +1674,9 @@ static void SOSEngineCloudKeychainTrace(SOSEngineRef engine, CFAbsoluteTime now) struct _SecServerKeyStats inetStats = { }; struct _SecServerKeyStats keysStats = { }; - _SecServerGetKeyStats(&genp_class, &genpStats); - _SecServerGetKeyStats(&inet_class, &inetStats); - _SecServerGetKeyStats(&keys_class, &keysStats); + _SecServerGetKeyStats(genp_class(), &genpStats); + _SecServerGetKeyStats(inet_class(), &inetStats); + _SecServerGetKeyStats(keys_class(), &keysStats); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ CloudKeychainTrace(num_peers, num_items, &genpStats, &inetStats, &keysStats); @@ -1782,11 +1803,8 @@ static void SOSEngineForEachBackupPeer(SOSEngineRef engine, void (^with)(SOSPeer }); } -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR static const CFStringRef kSecADSecurityNewItemSyncTimeKey = CFSTR("com.apple.security.secureobjectsync.itemtime.new"); static const CFStringRef kSecADSecurityKnownItemSyncTimeKey = CFSTR("com.apple.security.secureobjectsync.itemtime.known"); -#else -#endif static void ReportItemSyncTime(SOSDataSourceRef ds, bool known, SOSObjectRef object) @@ -1801,11 +1819,8 @@ static void ReportItemSyncTime(SOSDataSourceRef ds, bool known, SOSObjectRef obj syncTime = now - peerModificationAbsoluteTime; } -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR SecADClientPushValueForDistributionKey(known ? kSecADSecurityKnownItemSyncTimeKey : kSecADSecurityNewItemSyncTimeKey, SecBucket2Significant(syncTime)); -#else -#endif } } @@ -2228,7 +2243,7 @@ static void SOSEngineCompletedSyncWithPeer(SOSEngineRef engine, SOSPeerRef peer) CFDataRef SOSEngineCreateMessage_locked(SOSEngineRef engine, SOSTransactionRef txn, SOSPeerRef peer, - CFErrorRef *error, SOSEnginePeerMessageSentBlock *sent) { + CFMutableArrayRef *attributeList, CFErrorRef *error, SOSEnginePeerMessageSentBlock *sent) { SOSManifestRef local = SOSEngineCopyLocalPeerManifest_locked(engine, peer, error); __block SOSMessageRef message = SOSMessageCreate(kCFAllocatorDefault, SOSPeerGetMessageVersion(peer), error); SOSManifestRef confirmed = SOSPeerGetConfirmedManifest(peer); @@ -2345,7 +2360,7 @@ CFDataRef SOSEngineCreateMessage_locked(SOSEngineRef engine, SOSTransactionRef t if (!object) { const uint8_t *d = CFDataGetBytePtr(key); secerror("%@:%@ object %02X%02X%02X%02X dropping from manifest: not found in datasource: %@", - engine->myID, SOSPeerGetID(peer), d[0], d[1], d[2], d[3], dsfeError); + engine->myID, SOSPeerGetID(peer), d[0], d[1], d[2], d[3], dsfeError); SOSChangesAppendDelete(changes, key); } else if (!(der = SOSEngineCopyObjectDER(engine, object, &localError)) || !(digest = SOSObjectCopyDigest(engine->dataSource, object, &localError))) { @@ -2353,14 +2368,14 @@ CFDataRef SOSEngineCreateMessage_locked(SOSEngineRef engine, SOSTransactionRef t // Decode error, we need to drop these objects from our manifests const uint8_t *d = CFDataGetBytePtr(key); secnoticeq("engine", "%@:%@ object %02X%02X%02X%02X dropping from manifest: %@", - engine->myID, SOSPeerGetID(peer), d[0], d[1], d[2], d[3], localError); + engine->myID, SOSPeerGetID(peer), d[0], d[1], d[2], d[3], localError); SOSChangesAppendDelete(changes, key); CFRelease(localError); } else { // Stop iterating and propagate out all other errors. const uint8_t *d = CFDataGetBytePtr(key); secnoticeq("engine", "%@:%@ object %02X%02X%02X%02X in SOSDataSourceForEachObject: %@", - engine->myID, SOSPeerGetID(peer), d[0], d[1], d[2], d[3], localError); + engine->myID, SOSPeerGetID(peer), d[0], d[1], d[2], d[3], localError); *stop = true; CFErrorPropagate(localError, error); CFReleaseNull(message); @@ -2374,20 +2389,27 @@ CFDataRef SOSEngineCreateMessage_locked(SOSEngineRef engine, SOSTransactionRef t SOSChangesAppendDelete(changes, key); SOSChangesAppendAdd(changes, object); // This is new behaviour but we think it's more correct } - + size_t objectLen = (size_t)CFDataGetLength(der); if (SOSMessageAppendObject(message, der, &localError)) { SOSDigestVectorAppend(&dv, CFDataGetBytePtr(digest)); + if(!*attributeList) + *attributeList = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryRef itemPlist = SOSObjectCopyPropertyList(engine->dataSource, object, &localError); + if(itemPlist && !CFArrayContainsValue(*attributeList, CFRangeMake(0, CFArrayGetCount(*attributeList)), (CFStringRef)CFDictionaryGetValue(itemPlist, kSecAttrAccessGroup))){ + CFArrayAppendValue(*attributeList, (CFStringRef)CFDictionaryGetValue(itemPlist, kSecAttrAccessGroup)); + }//copy access group to array } else { const uint8_t *d = CFDataGetBytePtr(digest); CFStringRef hexder = CFDataCopyHexString(der); secnoticeq("engine", "%@:%@ object %02X%02X%02X%02X der: %@ dropping from manifest: %@", - engine->myID, SOSPeerGetID(peer), d[0], d[1], d[2], d[3], hexder, localError); + engine->myID, SOSPeerGetID(peer), d[0], d[1], d[2], d[3], hexder, localError); CFReleaseNull(hexder); CFReleaseNull(message); // Since we can't send these objects let's assume they are bad too? SOSChangesAppendDelete(changes, digest); } + objectsSize += objectLen; if (objectsSize > kSOSMessageMaxObjectsSize) *stop = true; @@ -2646,7 +2668,7 @@ done: return ok; } -CF_RETURNS_RETAINED CFSetRef SOSEngineSyncWithBackupPeers(SOSEngineRef engine, CFSetRef /* CFStringRef */ peers, CFErrorRef *error) +CF_RETURNS_RETAINED CFSetRef SOSEngineSyncWithBackupPeers(SOSEngineRef engine, CFSetRef /* CFStringRef */ peers, bool forceReset, CFErrorRef *error) { __block bool incomplete = false; CFMutableSetRef handledSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); @@ -2664,6 +2686,10 @@ CF_RETURNS_RETAINED CFSetRef SOSEngineSyncWithBackupPeers(SOSEngineRef engine, C require_quiet(peerID, done); if (SOSPeerMapEntryIsBackup(peer)) { + if(forceReset) { + SOSPeerSetMustSendMessage(peer, true); + } + report_handled = SOSEngineWriteToBackup_locked(engine, peer, false, &dirty, &incomplete, &localError); } @@ -2818,10 +2844,10 @@ bool SOSEngineWithPeerID(SOSEngineRef engine, CFStringRef peerID, CFErrorRef *er return result; } -CFDataRef SOSEngineCreateMessageToSyncToPeer(SOSEngineRef engine, CFStringRef peerID, SOSEnginePeerMessageSentBlock *sentBlock, CFErrorRef *error) { - __block CFDataRef message = NULL; +CFDataRef SOSEngineCreateMessageToSyncToPeer(SOSEngineRef engine, CFStringRef peerID, CFMutableArrayRef *attributeList, SOSEnginePeerMessageSentBlock *sentBlock, CFErrorRef *error){ +__block CFDataRef message = NULL; SOSEngineForPeerID(engine, peerID, error, ^(SOSTransactionRef txn, SOSPeerRef peer) { - message = SOSEngineCreateMessage_locked(engine, txn, peer, error, sentBlock); + message = SOSEngineCreateMessage_locked(engine, txn, peer, attributeList, error, sentBlock); }); return message; } @@ -2949,3 +2975,27 @@ retOut: return; } + +//For Testing +void TestSOSEngineDoOnQueue(CFTypeRef engine, dispatch_block_t action) +{ + dispatch_sync(((SOSEngineRef)engine)->queue, action); +} +CFMutableDictionaryRef TestSOSEngineGetCoders(CFTypeRef engine){ + return ((SOSEngineRef)engine)->coders; +} + +bool TestSOSEngineDoTxnOnQueue(CFTypeRef engine, CFErrorRef *error, void(^transaction)(SOSTransactionRef txn, bool *commit)) +{ + return SOSDataSourceWithCommitQueue(((SOSEngineRef)engine)->dataSource, error, ^(SOSTransactionRef txn, bool *commit) { + TestSOSEngineDoOnQueue((SOSEngineRef)engine, ^{ transaction(txn, commit); }); + }); +} +bool SOSEngineGetCodersNeedSaving(SOSEngineRef engine){ + return engine->codersNeedSaving; +} + +void SOSEngineSetCodersNeedSaving(SOSEngineRef engine, bool saved){ + engine->codersNeedSaving = saved; +} + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSEngine.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSEngine.h index 8ad3f48d..1325e5fb 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSEngine.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSEngine.h @@ -86,14 +86,14 @@ void SOSEngineCircleChanged(SOSEngineRef engine, CFStringRef myPeerID, CFArrayRe // Iterate over all peers. void SOSEngineForEachPeer(SOSEngineRef engine, void (^with)(SOSPeerRef peer)); -CF_RETURNS_RETAINED CFSetRef SOSEngineSyncWithBackupPeers(SOSEngineRef engine, CFSetRef /* CFStringRef */ peers, CFErrorRef *error); +CF_RETURNS_RETAINED CFSetRef SOSEngineSyncWithBackupPeers(SOSEngineRef engine, CFSetRef /* CFStringRef */ peers, bool forceReset, CFErrorRef *error); // Don't call this unless you know what you are doing. If you do then still don't call it. bool SOSEngineHandleMessage_locked(SOSEngineRef engine, CFStringRef peerID, SOSMessageRef message, SOSTransactionRef txn, bool *commit, bool *somethingChanged, CFErrorRef *error); CFDataRef SOSEngineCreateMessage_locked(SOSEngineRef engine, SOSTransactionRef txn, SOSPeerRef peer, - CFErrorRef *error, SOSEnginePeerMessageSentBlock *sent); + CFMutableArrayRef *attributeList, CFErrorRef *error, SOSEnginePeerMessageSentBlock *sent); // Return a SOSPeerRef for a given peer_id. SOSPeerRef SOSEngineCopyPeerWithID(SOSEngineRef engine, CFStringRef peer_id, CFErrorRef *error); @@ -110,7 +110,7 @@ bool SOSEngineInitializePeerCoder(SOSEngineRef engine, SOSFullPeerInfoRef myPeer // return a zero length CFDataRef if there is nothing to send. // If *ProposedManifest is set the caller is responsible for updating their // proposed manifest upon successful transmission of the message. -CFDataRef SOSEngineCreateMessageToSyncToPeer(SOSEngineRef engine, CFStringRef peerID, SOSEnginePeerMessageSentBlock *sentBlock, CFErrorRef *error); +CFDataRef SOSEngineCreateMessageToSyncToPeer(SOSEngineRef engine, CFStringRef peerID, CFMutableArrayRef *attributeList, SOSEnginePeerMessageSentBlock *sentBlock, CFErrorRef *error); CFStringRef SOSEngineGetMyID(SOSEngineRef engine); bool SOSEnginePeerDidConnect(SOSEngineRef engine, CFStringRef peerID, CFErrorRef *error); @@ -131,8 +131,11 @@ bool SOSTestEngineSaveWithDER(SOSEngineRef engine, CFDataRef derState, CFErrorRe bool SOSTestEngineSave(SOSEngineRef engine, SOSTransactionRef txn, CFErrorRef *error); bool SOSTestEngineLoad(SOSEngineRef engine, SOSTransactionRef txn, CFErrorRef *error); CFMutableDictionaryRef derStateToDictionaryCopy(CFDataRef state, CFErrorRef *error); -bool SOSTestEngineSaveCoders(SOSEngineRef engine, SOSTransactionRef txn, CFErrorRef *error); -bool TestSOSEngineLoadCoders(SOSEngineRef engine, SOSTransactionRef txn, CFErrorRef *error); +bool SOSTestEngineSaveCoders(CFTypeRef engine, SOSTransactionRef txn, CFErrorRef *error); +bool TestSOSEngineLoadCoders(CFTypeRef engine, SOSTransactionRef txn, CFErrorRef *error); +void TestSOSEngineDoOnQueue(CFTypeRef engine, dispatch_block_t action); +bool TestSOSEngineDoTxnOnQueue(CFTypeRef engine, CFErrorRef *error, void(^transaction)(SOSTransactionRef txn, bool *commit)); +CFMutableDictionaryRef TestSOSEngineGetCoders(CFTypeRef engine); // MARK: Sync completion notification registration @@ -153,6 +156,8 @@ extern CFStringRef kSOSEngineManifestCache; // Class A [kSecAttrAccessibleWhenUnlockedThisDeviceOnly] extern CFStringRef kSOSEngineCoders; #define kSOSEngineProtectionDomainClassA kSecAttrAccessibleWhenUnlockedThisDeviceOnly +bool SOSEngineGetCodersNeedSaving(SOSEngineRef engine); +void SOSEngineSetCodersNeedSaving(SOSEngineRef engine, bool saved); extern CFStringRef kSOSEngineStateVersionKey; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSEnginePriv.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSEnginePriv.h index f66de33a..b8166650 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSEnginePriv.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSEnginePriv.h @@ -35,14 +35,14 @@ struct __OpaqueSOSEngine { bool haveLoadedCoders; bool codersNeedSaving; - dispatch_queue_t queue; // Engine queue dispatch_source_t save_timer; // Engine state save timer - bool save_timer_pending; // Engine state timer running, read/modify on engine queue - dispatch_queue_t syncCompleteQueue; // Non-retained queue for async notificaion SOSEnginePeerInSyncBlock syncCompleteListener; // Block to call to notify the listener. + + bool save_timer_pending; // Engine state timer running, read/modify on engine queue + }; #endif /* SOSEnginePriv_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSExports.exp-in b/OSX/sec/SOSCircle/SecureObjectSync/SOSExports.exp-in index ad40ac35..6269f69a 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSExports.exp-in +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSExports.exp-in @@ -6,6 +6,8 @@ // _SOSCCAcceptApplicants +_SOSCCAccountGetPublicKey +_SOSCCAccountGetKeyCircleGeneration _SOSCCAccountHasPublicKey _SOSCCAccountIsNew _SOSCCAccountSetToNew @@ -35,10 +37,13 @@ _SOSCCCopyViewUnawarePeerInfo _SOSCCCopyYetToSyncViewsList _SOSCCDeleteAccountState _SOSCCDeleteEngineState +_SOSCCCleanupKVSKeys +_SOSCCTestPopulateKVSWithBadKeys _SOSCCForEachEngineStateAsString _SOSCCForEachEngineStateAsStringFromArray _SOSCCGetLastDepartureReason _SOSCCGetStatusDescription +_SOSCCGetViewResultDescription _SOSCCHandleIDSMessage _SOSCCRequestSyncWithPeerOverKVS _SOSCCRequestSyncWithPeerOverKVSUsingIDOnly @@ -73,7 +78,6 @@ _SOSCCResetToEmpty _SOSCCResetToOffering _SOSCCSecurityProperty _SOSCCSendToPeerIsPending -_SOSCCSetAutoAcceptInfo _SOSCCSetDeviceID _SOSCCSetEscrowRecord _SOSCCSetLastDepartureReason @@ -87,6 +91,7 @@ _SOSCCValidateUserPublic _SOSCCView _SOSCCViewSet _SOSCCWaitForInitialSync +_SOSCCCopyInitialSyncData _kSOSCCEngineStateCoderKey _kSOSCCEngineStateManifestCountKey @@ -125,6 +130,9 @@ _SOSPeerInfoCopyWithEscrowRecordUpdate _SOSPeerInfoCopyWithGestaltUpdate _SOSPeerInfoCopyWithSecurityPropertyChange _SOSPeerInfoCopyWithViewsChange +_SOSPeerInfoCopyTransportType +_SOSPeerInfoCopySerialNumber +_SOSPeerInfoCopyOSVersion _SOSPeerInfoCreate _SOSPeerInfoCreateCloudIdentity _SOSPeerInfoCreateCopy @@ -145,7 +153,6 @@ _SOSPeerInfoGetPeerName _SOSPeerInfoGetPeerProtocolVersion _SOSPeerInfoGetPermittedViews _SOSPeerInfoGetRetirementDate -_SOSPeerInfoCopyTransportType _SOSPeerInfoGetTypeID _SOSPeerInfoGetVersion _SOSPeerInfoHasBackupKey @@ -167,6 +174,12 @@ _SOSPeerInfoUpgradeSignatures _SOSPeerInfoViewStatus _SOSPeerInfoExpandV2Data + +_SOSFullPeerInfoCreate +_SOSFullPeerInfoPromoteToApplication +_SOSFullPeerInfoGetPeerInfo +_SOSCircleAcceptPeerFromHSA2 + _SOSCCSetDeviceID _SOSCCHandleIDSMessage @@ -220,7 +233,6 @@ _der_encode_BackupSliceKeyBag _der_sizeof_BackupSliceKeyBag _SOSWrapToBackupSliceKeyBagForView -_SOSAccountRecoveryKeyIsInBackupAndCurrentInView _SOSBSKBHasRecoveryKey // @@ -247,9 +259,26 @@ _SOSCircleCreateFromData _SOSCircleGenerationIncrement _SOSCircleGenerationSetValue _SOSCircleGetGenerationSint -_SOSAccountPeerGotInSync -_SOSCloudKeychainRetrievePendingMessageFromProxy +_SOSCircleCreate +_SOSCircleCopyCircle +_SOSCirclePreGenerationSign +_SOSCircleGetGeneration +_SOSGenerationIncrementAndCreate +_SOSCircleCopyNextGenSignatureWithPeerAdded +_SOSCircleGenerationSetValue +_SOSCircleGenerationIncrement +_SOSCircleGenerationSetValue +_SOSCircleGenerationIncrement +_SOSCircleGetGenerationSint +_SOSCircleRequestAdmission +_SOSCircleAcceptRequest +_SOSCircleHasPeer + + +_SOSPiggyBackBlobCreateFromData +_SOSPiggyBackBlobCopyEncodedData +_SOSCloudKeychainRetrievePendingMessageFromProxy _SOSCloudKeychainClearAll _SOSCloudKeychainGetAllObjectsFromCloud _SOSCloudKeychainGetObjectsFromCloud @@ -275,14 +304,9 @@ _kSOSKVSAccountChangedKey _kSOSKVSInitialSyncKey _kSOSKVSRequiredKey _kSOSKVSOfficialDSIDKey - -_SOSCircleGenerationSetValue -_SOSCircleGenerationIncrement - - -_SOSCircleGenerationSetValue -_SOSCircleGenerationIncrement -_SOSCircleGetGenerationSint +_kSOSKVSLastCleanupTimestampKey +_kSOSKVSOTRConfigVersion +_kSOSKVSWroteLastKeyParams _SOSKVSKeyGetKeyType @@ -313,6 +337,11 @@ _SOSGenerationCountCopyDescription _SOSLogSetOutputTo +_der_sizeof_data_or_null +_der_encode_data_or_null +_der_decode_data_or_null + + #if !(TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) // Symbols only for embedded, typically for tests diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.h index 25f2c9eb..324ccde7 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.h @@ -39,13 +39,13 @@ enum { kSOSFullPeerVersion = 1, }; -SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backupKey, SecKeyRef signingKey, CFErrorRef *error); +SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backupKey, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef *error); bool SOSFullPeerInfoUpdateToThisPeer(SOSFullPeerInfoRef peer, SOSPeerInfoRef pi, CFErrorRef *error); SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backupKey, CFSetRef enabledViews, - SecKeyRef signingKey, CFErrorRef *error); + SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef *error); SOSFullPeerInfoRef SOSFullPeerInfoCopyFullPeerInfo(SOSFullPeerInfoRef toCopy); @@ -53,6 +53,8 @@ SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer); SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error); +SecKeyRef SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi, CFErrorRef *error); +SecKeyRef SOSFullPeerInfoCopyOctagonSigningKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error); bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef peer, CFErrorRef* error); @@ -64,6 +66,8 @@ bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error); bool SOSFullPeerInfoPrivKeyExists(SOSFullPeerInfoRef peer); +bool SOSFullPeerInfoOctagonPrivKeyExists(SOSFullPeerInfoRef peer); + bool SOSFullPeerInfoUpdateGestalt(SOSFullPeerInfoRef peer, CFDictionaryRef gestalt, CFErrorRef* error); bool SOSFullPeerInfoUpdateV2Dictionary(SOSFullPeerInfoRef peer, CFDictionaryRef newv2dict, CFErrorRef* error); @@ -106,7 +110,7 @@ bool SOSFullPeerInfoUpdateTransportAckModelPreference(SOSFullPeerInfoRef peer, C SOSSecurityPropertyResultCode SOSFullPeerInfoUpdateSecurityProperty(SOSFullPeerInfoRef peer, SOSViewActionCode action, CFStringRef property, CFErrorRef* error); SOSSecurityPropertyResultCode SOSFullPeerInfoSecurityPropertyStatus(SOSFullPeerInfoRef peer, CFStringRef property, CFErrorRef *error); - +CFDataRef SOSPeerInfoCopyData(SOSPeerInfoRef fpi, CFErrorRef *error); __END_DECLS diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m similarity index 87% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m index 4d1b3205..ce803c32 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m @@ -27,11 +27,11 @@ #include #include #include +#include #include #include -#include #include #include @@ -80,6 +80,7 @@ struct __OpaqueSOSFullPeerInfo { SOSPeerInfoRef peer_info; CFDataRef key_ref; + CFDataRef octagon_sync_signing_key_ref; }; CFGiblisWithHashFor(SOSFullPeerInfo); @@ -118,20 +119,20 @@ bool SOSFullPeerInfoUpdateToThisPeer(SOSFullPeerInfoRef peer, SOSPeerInfoRef pi, } SOSFullPeerInfoRef SOSFullPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, - CFDataRef backupKey, SecKeyRef signingKey, + CFDataRef backupKey, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) { - return SOSFullPeerInfoCreateWithViews(allocator, gestalt, backupKey, NULL, signingKey, error); + return SOSFullPeerInfoCreateWithViews(allocator, gestalt, backupKey, NULL, signingKey, octagonSigningKey, error); } SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backupKey, CFSetRef initialViews, - SecKeyRef signingKey, CFErrorRef* error) { + SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) { SOSFullPeerInfoRef result = NULL; SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator); CFStringRef IDSID = CFSTR(""); - CFStringRef transportType =SOSTransportMessageTypeIDSV2; + CFStringRef transportType = SOSTransportMessageTypeIDSV2; CFBooleanRef preferIDS = kCFBooleanFalse; CFBooleanRef preferIDSFragmentation = kCFBooleanTrue; CFBooleanRef preferACKModel = kCFBooleanTrue; @@ -139,11 +140,14 @@ SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator, fpi->peer_info = SOSPeerInfoCreateWithTransportAndViews(allocator, gestalt, backupKey, IDSID, transportType, preferIDS, preferIDSFragmentation, preferACKModel, initialViews, - signingKey, error); + signingKey, octagonSigningKey, 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(octagonSigningKey, &fpi->octagon_sync_signing_key_ref); + require_quiet(SecError(status, error, CFSTR("Inflating octagon persistent ref")), exit); CFTransferRetained(result, fpi); @@ -200,6 +204,35 @@ bool SOSFullPeerInfoUpdateTransportAckModelPreference(SOSFullPeerInfoRef peer, C }); } +CFDataRef SOSPeerInfoCopyData(SOSPeerInfoRef pi, CFErrorRef *error) +{ + CFTypeRef vData = NULL; + SecKeyRef pubKey = SOSPeerInfoCopyPubKey(pi, error); + CFDictionaryRef query = NULL; + require_quiet(pubKey, exit); + + + CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(pubKey); + + query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecClass, kSecClassKey, + kSecAttrKeyClass, kSecAttrKeyClassPrivate, + kSecAttrSynchronizable, kSecAttrSynchronizableAny, + kSecAttrApplicationLabel, public_key_hash, + kSecReturnData, kCFBooleanTrue, + NULL); + CFReleaseNull(public_key_hash); + + require_quiet(SecError(SecItemCopyMatching(query, &vData),error , + CFSTR("Error finding persistent ref to key from public: %@"), pubKey), exit); + +exit: + CFReleaseNull(query); + + secnotice("fpi","no private key found"); + return (CFDataRef)vData; +} + SOSFullPeerInfoRef SOSFullPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, SOSPeerInfoRef peer, CFErrorRef* error) { SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator); @@ -463,7 +496,7 @@ SOSPeerInfoRef SOSFullPeerInfoGetPeerInfo(SOSFullPeerInfoRef fullPeer) { // MARK: Private Key Retrieval and Existence -static SecKeyRef SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) { +SecKeyRef SOSFullPeerInfoCopyPubKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) { SecKeyRef retval = NULL; require_quiet(fpi, errOut); SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); @@ -474,6 +507,18 @@ errOut: return retval; } +static SecKeyRef SOSFullPeerInfoCopyOctagonPubKey(SOSFullPeerInfoRef fpi, CFErrorRef* error) +{ + SecKeyRef retval = NULL; + require_quiet(fpi, errOut); + SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); + require_quiet(pi, errOut); + retval = SOSPeerInfoCopyOctagonPubKey(pi, error); + +errOut: + return retval; +} + static SecKeyRef SOSFullPeerInfoCopyMatchingPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) { SecKeyRef retval = NULL; @@ -485,6 +530,18 @@ exit: return retval; } +static SecKeyRef SOSFullPeerInfoCopyMatchingOctagonPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef* error) +{ + SecKeyRef retval = NULL; + SecKeyRef pub = SOSFullPeerInfoCopyOctagonPubKey(fpi, error); + require_quiet(pub, exit); + retval = SecKeyCopyMatchingPrivateKey(pub, error); + +exit: + CFReleaseNull(pub); + return retval; +} + static OSStatus SOSFullPeerInfoGetMatchingPrivateKeyStatus(SOSFullPeerInfoRef fpi, CFErrorRef *error) { OSStatus retval = errSecParam; SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error); @@ -512,20 +569,35 @@ bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fpi, CFErrorRef* error bool result = false; CFDictionaryRef privQuery = NULL; CFMutableDictionaryRef query = NULL; + CFDictionaryRef octagonPrivQuery = NULL; + CFMutableDictionaryRef octagonQuery = NULL; SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error); + SecKeyRef octagonPub = SOSFullPeerInfoCopyOctagonPubKey(fpi, error); require_quiet(pub, fail); + require_quiet(octagonPub, fail); privQuery = CreatePrivateKeyMatchingQuery(pub, false); query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, privQuery); CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanFalse); result = SecError(SecItemDelete(query), error, CFSTR("Deleting while purging")); + + // do the same thing to also purge the octagon sync signing key + + octagonPrivQuery = CreatePrivateKeyMatchingQuery(octagonPub, false); + octagonQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, octagonPrivQuery); + CFDictionaryAddValue(octagonQuery, kSecUseTombstones, kCFBooleanFalse); + + result &= SecError(SecItemDelete(octagonQuery), error, CFSTR("Deleting while purging")); fail: CFReleaseNull(privQuery); CFReleaseNull(query); CFReleaseNull(pub); + CFReleaseNull(octagonPrivQuery); + CFReleaseNull(octagonQuery); + CFReleaseNull(octagonPub); return result; } @@ -533,6 +605,11 @@ SecKeyRef SOSFullPeerInfoCopyDeviceKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* return SOSFullPeerInfoCopyMatchingPrivateKey(fullPeer, error); } +SecKeyRef SOSFullPeerInfoCopyOctagonSigningKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) +{ + return SOSFullPeerInfoCopyMatchingOctagonPrivateKey(fullPeer, error); +} + // // MARK: Encode and decode // diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.h index 5fb74418..e1722f56 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.h @@ -69,8 +69,24 @@ enum { kSOSErrorNoiCloudPeer = 1044, kSOSErrorParam = 1045, + kSOSErrorNotInCircle = 1046, }; +typedef enum { + kSecIDSErrorNoDeviceID = -1, //default case + kSecIDSErrorNotRegistered = -2, + kSecIDSErrorFailedToSend=-3, + kSecIDSErrorCouldNotFindMatchingAuthToken = -4, + kSecIDSErrorDeviceIsLocked = -5, + kSecIDSErrorNoPeersAvailable = -6 + +} idsError; + + +extern const CFStringRef SOSTransportMessageTypeIDSV2; +extern const CFStringRef SOSTransportMessageTypeKVS; +extern const CFStringRef SOSTransportMessageTypeIDS; +extern const CFStringRef kSOSDSIDKey; // Returns false unless errorCode is 0. bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef descriptionString, ...); @@ -111,7 +127,7 @@ CFDataRef SOSCopyDeviceBackupPublicKey(CFDataRef entropy, CFErrorRef *error); // Wrapping and Unwrapping // -CFMutableDataRef SOSCopyECWrappedData(ccec_pub_ctx *ec_ctx, CFDataRef data, CFErrorRef *error); +CFMutableDataRef SOSCopyECWrappedData(ccec_pub_ctx_t ec_ctx, CFDataRef data, CFErrorRef *error); bool SOSPerformWithUnwrappedData(ccec_full_ctx_t ec_ctx, CFDataRef data, CFErrorRef *error, void (^operation)(size_t size, uint8_t *buffer)); CFMutableDataRef SOSCopyECUnwrappedData(ccec_full_ctx_t ec_ctx, CFDataRef data, CFErrorRef *error); @@ -150,8 +166,6 @@ extern const CFStringRef kIDSMessageRecipientPeerID; extern const CFStringRef kIDSMessageRecipientDeviceID; extern const CFStringRef kIDSMessageUsesAckModel; - - __END_DECLS #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.m similarity index 96% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.m index cc6b0837..4aac04d1 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSInternal.m @@ -59,6 +59,13 @@ const CFStringRef kIDSMessageUniqueID = CFSTR("MessageID"); const CFStringRef kIDSMessageRecipientPeerID = CFSTR("RecipientPeerID"); const CFStringRef kIDSMessageRecipientDeviceID = CFSTR("RecipientDeviceID"); const CFStringRef kIDSMessageUsesAckModel = CFSTR("UsesAckModel"); +const CFStringRef kSOSErrorDomain = CFSTR("com.apple.security.sos.error"); +const CFStringRef SOSTransportMessageTypeIDSV2 = CFSTR("IDS2.0"); +const CFStringRef SOSTransportMessageTypeKVS = CFSTR("KVS"); + +bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef format, ...) + CF_FORMAT_FUNCTION(4, 5); + bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef format, ...) { if (!errorCode) return true; @@ -277,7 +284,7 @@ CFDataRef SOSCopyDeviceBackupPublicKey(CFDataRef entropy, CFErrorRef *error) require_quiet(SOSGenerateDeviceBackupFullKey(fullKey, SOSGetBackupKeyCurveParameters(), entropy, error), exit); - size_t space = ccec_compact_export_size(false, fullKey); + size_t space = ccec_compact_export_size(false, ccec_ctx_pub(fullKey)); publicKeyData = CFDataCreateMutableWithScratch(kCFAllocatorDefault, space); require_quiet(SecAllocationError(publicKeyData, error, CFSTR("Mutable data allocation")), exit); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.h index 35b6f3af..7dd56944 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.h @@ -4,9 +4,8 @@ #define SOSKVSKEYS_H #include "SOSCircle.h" -#include #include - +#include // // MARK: Key formation // @@ -20,9 +19,9 @@ typedef enum { kAccountChangedKey, kDebugInfoKey, kRingKey, - kPeerInfoKey, kLastCircleKey, kLastKeyParameterKey, + kOTRConfig, kUnknownKey, } SOSKVSKeyType; @@ -31,13 +30,12 @@ extern const CFStringRef kSOSKVSInitialSyncKey; extern const CFStringRef kSOSKVSAccountChangedKey; extern const CFStringRef kSOSKVSRequiredKey; extern const CFStringRef kSOSKVSOfficialDSIDKey; - -//extern const CFStringRef kSOSKVSDebugInfo; +extern const CFStringRef kSOSKVSLastCleanupTimestampKey; +extern const CFStringRef kSOSKVSOTRConfigVersion; +extern const CFStringRef kSOSKVSWroteLastKeyParams; extern const CFStringRef sCirclePrefix; extern const CFStringRef sRetirementPrefix; -extern const CFStringRef sLastCirclePushedPrefix; -extern const CFStringRef sLastKeyParametersPushedPrefix; extern const CFStringRef sDebugInfoPrefix; SOSKVSKeyType SOSKVSKeyGetKeyType(CFStringRef key); @@ -45,7 +43,6 @@ bool SOSKVSKeyParse(SOSKVSKeyType keyType, CFStringRef key, CFStringRef *circle, SOSKVSKeyType SOSKVSKeyGetKeyTypeAndParse(CFStringRef key, CFStringRef *circle, CFStringRef *peerInfo, CFStringRef *ring, CFStringRef *backupName, CFStringRef *from, CFStringRef *to); CFStringRef SOSCircleKeyCreateWithCircle(SOSCircleRef circle, CFErrorRef *error); -CFStringRef SOSPeerInfoKeyCreateWithName(CFStringRef peer_info_name, CFErrorRef *error); CFStringRef SOSRingKeyCreateWithName(CFStringRef ring_name, CFErrorRef *error); @@ -61,16 +58,13 @@ CFStringRef SOSMessageKeyCreateWithCircleAndPeerInfos(SOSCircleRef circle, SOSPe CFStringRef SOSRetirementKeyCreateWithCircleNameAndPeer(CFStringRef circle_name, CFStringRef retirement_peer_name); CFStringRef SOSRetirementKeyCreateWithCircleAndPeer(SOSCircleRef circle, CFStringRef retirement_peer_name); -CFStringRef SOSMessageKeyCreateFromTransportToPeer(SOSTransportMessageRef transport, CFStringRef peer_name); -CFStringRef SOSMessageKeyCreateFromPeerToTransport(SOSTransportMessageRef transport, CFStringRef peer_name); +CFStringRef SOSMessageKeyCreateFromTransportToPeer(SOSMessage* transport, CFStringRef myID, CFStringRef peer_name); +CFStringRef SOSMessageKeyCreateFromPeerToTransport(SOSMessage* transport, CFStringRef myID, CFStringRef peer_name); +CFStringRef SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(SOSAccount* account); CFStringRef SOSMessageKeyCreateWithCircleNameAndTransportType(CFStringRef circleName, CFStringRef transportType); -CFStringRef SOSPeerInfoV2KeyCreateWithPeerName(CFStringRef peer_name); CFStringRef SOSRingKeyCreateWithRingName(CFStringRef ring_name); -CFStringRef SOSLastCirclePushedKeyCreateWithCircleNameAndPeerID(CFStringRef circleName, CFStringRef peerID); -CFStringRef SOSLastCirclePushedKeyCreateWithAccountGestalt(SOSAccountRef account); CFStringRef SOSLastKeyParametersPushedKeyCreateWithPeerID(CFStringRef peerID); -CFStringRef SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(SOSAccountRef account); CFStringRef SOSDebugInfoKeyCreateWithTypeName(CFStringRef type_name); #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.m similarity index 83% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.m index c384c8b4..2699dfd4 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSKVSKeys.m @@ -42,18 +42,17 @@ const CFStringRef kSOSKVSInitialSyncKey = CFSTR("^InitialSync"); const CFStringRef kSOSKVSAccountChangedKey = CFSTR("^AccountChanged"); const CFStringRef kSOSKVSRequiredKey = CFSTR("^Required"); const CFStringRef kSOSKVSOfficialDSIDKey = CFSTR("^OfficialDSID"); - +const CFStringRef kSOSKVSLastCleanupTimestampKey = CFSTR("tLastKVSKeyCleanup"); +const CFStringRef kSOSKVSOTRConfigVersion = CFSTR("OTRConfigVersion"); +const CFStringRef kSOSKVSWroteLastKeyParams = CFSTR("WroteLastKeyParams"); const CFStringRef kSOSKVSDebugScope = CFSTR("^DebugScope"); -const CFStringRef sPeerInfoPrefix = CFSTR("+"); const CFStringRef sRingPrefix = CFSTR("~"); const CFStringRef sDebugInfoPrefix = CFSTR("dbg-"); const CFStringRef sWarningPrefix = CFSTR("!"); -const CFStringRef sAncientCirclePrefix = CFSTR("@"); const CFStringRef sCirclePrefix = CFSTR("o"); const CFStringRef sRetirementPrefix = CFSTR("-"); -const CFStringRef sLastCirclePushedPrefix = CFSTR("p"); const CFStringRef sLastKeyParametersPushedPrefix = CFSTR("k"); const CFStringRef sCircleSeparator = CFSTR("|"); const CFStringRef sFromToSeparator = CFSTR(":"); @@ -72,14 +71,13 @@ SOSKVSKeyType SOSKVSKeyGetKeyType(CFStringRef key) { if(CFStringHasPrefix(key, sCirclePrefix)) retval = kCircleKey; else if (CFStringHasPrefix(key, sRingPrefix)) retval = kRingKey; - else if(CFStringHasPrefix(key, sPeerInfoPrefix)) retval = kPeerInfoKey; else if(CFStringHasPrefix(key, sRetirementPrefix)) retval = kRetirementKey; else if(CFStringHasPrefix(key, kSOSKVSKeyParametersKey)) retval = kParametersKey; else if(CFStringHasPrefix(key, kSOSKVSInitialSyncKey)) retval = kInitialSyncKey; else if(CFStringHasPrefix(key, kSOSKVSAccountChangedKey)) retval = kAccountChangedKey; else if(CFStringHasPrefix(key, sDebugInfoPrefix)) retval = kDebugInfoKey; - else if(CFStringHasPrefix(key, sLastCirclePushedPrefix)) retval = kLastCircleKey; else if(CFStringHasPrefix(key, sLastKeyParametersPushedPrefix)) retval = kLastKeyParameterKey; + else if(CFStringHasPrefix(key, kSOSKVSOTRConfigVersion)) retval = kOTRConfig; else retval = kMessageKey; return retval; @@ -140,12 +138,6 @@ bool SOSKVSKeyParse(SOSKVSKeyType keyType, CFStringRef key, CFStringRef *circle, *ring = CFStringCreateWithSubstring(NULL, key, fromRange); } break; - case kPeerInfoKey: - if (peerInfo) { - CFRange fromRange = CFRangeMake(1, CFStringGetLength(key)-1); - *peerInfo = CFStringCreateWithSubstring(NULL, key, fromRange); - } - break; case kDebugInfoKey: /* piggybacking on peerinfo */ if (peerInfo) { @@ -158,6 +150,7 @@ bool SOSKVSKeyParse(SOSKVSKeyType keyType, CFStringRef key, CFStringRef *circle, case kParametersKey: case kInitialSyncKey: case kUnknownKey: + case kOTRConfig: break; case kLastKeyParameterKey: if(from) { @@ -221,12 +214,6 @@ CFStringRef SOSCircleKeyCreateWithName(CFStringRef circleName, CFErrorRef *error return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), sCirclePrefix, circleName); } -CFStringRef SOSPeerInfoKeyCreateWithName(CFStringRef peer_info_name, CFErrorRef *error) -{ - if(!peer_info_name) return NULL; - return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), sPeerInfoPrefix, peer_info_name); -} - CFStringRef SOSRingKeyCreateWithName(CFStringRef ring_name, CFErrorRef *error) { if(!ring_name) return NULL; @@ -292,30 +279,21 @@ CFStringRef SOSMessageKeyCreateWithCircleAndPeerInfos(SOSCircleRef circle, SOSPe return SOSMessageKeyCreateWithCircleAndPeerNames(circle, SOSPeerInfoGetPeerID(from_peer), SOSPeerInfoGetPeerID(to_peer)); } -CFStringRef SOSMessageKeyCreateFromPeerToTransport(SOSTransportMessageRef transport, CFStringRef peer_name) { +CFStringRef SOSMessageKeyCreateFromPeerToTransport(SOSMessage* transport, CFStringRef myName, CFStringRef peer_name){ CFErrorRef error = NULL; - SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport); - - CFStringRef circleName = SOSTransportMessageGetCircleName((SOSTransportMessageRef)transport); - CFStringRef my_id = SOSEngineGetMyID(engine); - if(my_id == NULL) - { - secerror("cannot create message keys, SOSEngineGetMyID returned NULL"); - return NULL; - } - CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, peer_name, my_id); + + CFStringRef circleName = [transport SOSTransportMessageGetCircleName]; + CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, peer_name, myName); CFReleaseSafe(error); return result; } -CFStringRef SOSMessageKeyCreateFromTransportToPeer(SOSTransportMessageRef transport, CFStringRef peer_name) { +CFStringRef SOSMessageKeyCreateFromTransportToPeer(SOSMessage* transport, CFStringRef myID, CFStringRef peer_name) { CFErrorRef error = NULL; - SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport); - - CFStringRef circleName = SOSTransportMessageGetCircleName((SOSTransportMessageRef)transport); - CFStringRef my_id = SOSEngineGetMyID(engine); - - CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, my_id, peer_name); + + CFStringRef circleName = [transport SOSTransportMessageGetCircleName]; + + CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, myID, peer_name); CFReleaseSafe(error); return result; } @@ -326,12 +304,6 @@ CFStringRef SOSRetirementKeyCreateWithCircleNameAndPeer(CFStringRef circle_name, sRetirementPrefix, circle_name, sCircleSeparator, retirement_peer_name); } -CFStringRef SOSPeerInfoV2KeyCreateWithPeerName(CFStringRef peer_name) -{ - return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), - sPeerInfoPrefix, peer_name); -} - CFStringRef SOSRingKeyCreateWithRingName(CFStringRef ring_name) { return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), @@ -343,21 +315,6 @@ CFStringRef SOSRetirementKeyCreateWithCircleAndPeer(SOSCircleRef circle, CFStrin return SOSRetirementKeyCreateWithCircleNameAndPeer(SOSCircleGetName(circle), retirement_peer_name); } -//should be poak|ourPeerID -CFStringRef SOSLastCirclePushedKeyCreateWithCircleNameAndPeerID(CFStringRef circleName, CFStringRef peerID){ - - return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@%@"), - sLastCirclePushedPrefix, sCirclePrefix, circleName, sCircleSeparator, peerID); -} - -CFStringRef SOSLastCirclePushedKeyCreateWithAccountGestalt(SOSAccountRef account){ - CFStringRef gestaltInfo = SOSAccountCreateCompactDescription(account); - CFStringRef key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@"), - sLastCirclePushedPrefix, sCirclePrefix, gestaltInfo); - CFReleaseNull(gestaltInfo); - return key; -} - //should be >KeyParameters|ourPeerID CFStringRef SOSLastKeyParametersPushedKeyCreateWithPeerID(CFStringRef peerID){ @@ -367,7 +324,7 @@ CFStringRef SOSLastKeyParametersPushedKeyCreateWithPeerID(CFStringRef peerID){ //should be >KeyParameters|ourPeerID -CFStringRef SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(SOSAccountRef account){ +CFStringRef SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(SOSAccount* account){ CFStringRef gestaltInfo = SOSAccountCreateCompactDescription(account); CFStringRef key= CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@"), diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.h index 418b5737..3771023f 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.h @@ -75,7 +75,11 @@ CFDictionaryRef SOSPeerCopyState(SOSPeerRef peer, CFErrorRef *error); // (Re)initialize from a peerState dictionary bool SOSPeerSetState(SOSPeerRef peer, SOSEngineRef engine, CFDictionaryRef state, CFErrorRef *error); - +void SOSPeerSetOTRTimer(SOSPeerRef peer, dispatch_source_t timer); +dispatch_source_t SOSPeerGetOTRTimer(SOSPeerRef peer); +void SOSPeerRemoveOTRTimerEntry(SOSPeerRef peer); +bool SOSPeerTimerForPeerExist(SOSPeerRef peer); + // // // @@ -134,6 +138,13 @@ int SOSPeerHandoffFD(SOSPeerRef peer, CFErrorRef *error); void SOSBackupPeerPostNotification(const char *reason); +// +// MARK: RateLimiting +// +void SOSPeerSetRateLimiter(SOSPeerRef peer, CFTypeRef limiter); +CFTypeRef SOSPeerGetRateLimiter(SOSPeerRef peer); +bool SOSPeerShouldRateLimit(CFArrayRef attributes, SOSPeerRef peer); + __END_DECLS #endif /* !_SOSPEER_H_ */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.m similarity index 96% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.m index 470c7869..0251c73e 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeer.m @@ -26,10 +26,11 @@ * SOSPeer.c - Implementation of a secure object syncing peer */ #include - +#include #include #include #include +#include #include #include #include @@ -329,6 +330,10 @@ struct __OpaqueSOSPeer { CFMutableArrayRef proposedManifests; CFMutableArrayRef localManifests; + CFTypeRef limiter; + + CFMutableDictionaryRef otrTimers; + // Only backup peers have these: CFDataRef _keyBag; FILE *journalFile; @@ -540,6 +545,8 @@ static SOSPeerRef SOSPeerCreate_Internal(SOSEngineRef engine, CFDictionaryRef st SOSPeerRef p = CFTypeAllocate(SOSPeer, struct __OpaqueSOSPeer, kCFAllocatorDefault); p->peer_id = CFRetainSafe(theirPeerID); p->version = version; + p->otrTimers = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryRef empty = NULL; if (!state) { empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -640,6 +647,8 @@ static void SOSPeerDestroy(CFTypeRef cf) { CFReleaseNull(peer->confirmedManifest); CFReleaseNull(peer->proposedManifests); CFReleaseNull(peer->localManifests); + CFReleaseNull(peer->otrTimers); + CFReleaseNull(peer->limiter); } bool SOSPeerDidConnect(SOSPeerRef peer) { @@ -655,6 +664,16 @@ CFIndex SOSPeerGetVersion(SOSPeerRef peer) { return peer->version; } +void SOSPeerSetRateLimiter(SOSPeerRef peer, CFTypeRef limiter) +{ + peer->limiter = CFRetainSafe(limiter); +} + +CFTypeRef SOSPeerGetRateLimiter(SOSPeerRef peer) +{ + return (peer->limiter ? peer->limiter : NULL); +} + CFStringRef SOSPeerGetID(SOSPeerRef peer) { return peer->peer_id; } @@ -822,6 +841,26 @@ SOSManifestRef SOSPeerGetUnwantedManifest(SOSPeerRef peer) { void SOSPeerSetUnwantedManifest(SOSPeerRef peer, SOSManifestRef unwantedManifest) { CFRetainAssign(peer->unwantedManifest, unwantedManifest); } +bool SOSPeerTimerForPeerExist(SOSPeerRef peer){ + dispatch_source_t timer = SOSPeerGetOTRTimer(peer); + return timer ? true : false; +} +void SOSPeerSetOTRTimer(SOSPeerRef peer, dispatch_source_t timer){ + NSMutableDictionary* timers = (__bridge NSMutableDictionary*)peer->otrTimers; + if(!timers) + timers = [[NSMutableDictionary alloc]init]; + + [timers setObject:timer forKey:(__bridge NSString*)SOSPeerGetID(peer)]; + peer->otrTimers = (CFMutableDictionaryRef)CFBridgingRetain(timers); +} + +dispatch_source_t SOSPeerGetOTRTimer(SOSPeerRef peer){ + return (dispatch_source_t)CFDictionaryGetValue(peer->otrTimers, SOSPeerGetID(peer)); +} + +void SOSPeerRemoveOTRTimerEntry(SOSPeerRef peer){ + CFDictionaryRemoveValue(peer->otrTimers, SOSPeerGetID(peer)); +} SOSManifestRef SOSPeerCopyManifestForDigest(SOSPeerRef peer, CFDataRef digest) { if (!digest) return NULL; @@ -929,8 +968,9 @@ bool SOSPeerDidReceiveRemovalsAndAdditions(SOSPeerRef peer, SOSManifestRef absen // Called for a normal syncing peer. Only updates pendingObjects currently. bool SOSPeerDataSourceWillCommit(SOSPeerRef peer, SOSDataSourceTransactionSource source, SOSManifestRef removals, SOSManifestRef additions, CFErrorRef *error) { bool isAPITransaction = source == kSOSDataSourceAPITransaction; + bool isCKKSTransaction = source == kSOSDataSourceCKKSTransaction; SOSManifestRef unconfirmedAdditions = NULL; - if (isAPITransaction && SOSManifestGetCount(additions)) { + if ((isAPITransaction || isCKKSTransaction) && SOSManifestGetCount(additions)) { // Remove confirmed from additions, leaving us with additions to the local db that the remote peer doesn't have yet unconfirmedAdditions = SOSManifestCreateComplement(SOSPeerGetConfirmedManifest(peer), additions, error); } @@ -947,7 +987,7 @@ bool SOSPeerDataSourceWillCommit(SOSPeerRef peer, SOSDataSourceTransactionSource SOSManifestDiff(peer->pendingObjects, pendingObjectsManifest, &unpended, &pended, error); secinfo("peer", "%@: willCommit R:%@ A:%@ UA:%@ %s O%s%@%s%@", SOSPeerGetID(peer), removals, additions, unconfirmedAdditions, - (isAPITransaction ? "api": "sos"), + (isAPITransaction ? "api": isCKKSTransaction ? "ckks" : "sos"), (SOSManifestGetCount(unpended) ? "-" : ""), (SOSManifestGetCount(unpended) ? (CFStringRef)unpended : CFSTR("")), (SOSManifestGetCount(pended) ? "+" : SOSManifestGetCount(unpended) ? "" : "="), @@ -1026,3 +1066,4 @@ bool SOSPeerDataSourceWillChange(SOSPeerRef peer, SOSDataSourceRef dataSource, S } return ok; } + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.h index e2a998e4..20654ffd 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.h @@ -26,14 +26,14 @@ #define SOSPeerCoder_h #include #include - +#include enum SOSCoderUnwrapStatus{ SOSCoderUnwrapError = 0, SOSCoderUnwrapDecoded = 1, SOSCoderUnwrapHandled = 2 }; -bool SOSPeerCoderSendMessageIfNeeded(SOSEngineRef engine, SOSTransactionRef txn, SOSPeerRef peer, SOSCoderRef coder, CFDataRef *message_to_send, CFStringRef peer_id, SOSEnginePeerMessageSentBlock *sent, CFErrorRef *error); +bool SOSPeerCoderSendMessageIfNeeded(SOSAccount* account, SOSEngineRef engine, SOSTransactionRef txn, SOSPeerRef peer, SOSCoderRef coder, CFDataRef *message_to_send, CFStringRef peer_id, CFMutableArrayRef *attributeList, SOSEnginePeerMessageSentBlock *sent, CFErrorRef *error); enum SOSCoderUnwrapStatus SOSPeerHandleCoderMessage(SOSPeerRef peer, SOSCoderRef coder, CFStringRef peer_id, CFDataRef codedMessage, CFDataRef *decodedMessage, bool *forceSave, CFErrorRef *error); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.m similarity index 74% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.m index a7aa186f..421f9262 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerCoder.m @@ -24,10 +24,15 @@ #include #include #include -#include #include +#include #include -#include +#include +#include +#include +#include + +#include #include #include @@ -50,10 +55,15 @@ enum SOSCoderUnwrapStatus SOSPeerHandleCoderMessage(SOSPeerRef peer, SOSCoderRef CFErrorRef localError = NULL; if (coder) { coderStatus = SOSCoderUnwrap(coder, codedMessage, &localDecodedMessage, peer_id, error); - + dispatch_source_t timer = SOSPeerGetOTRTimer(peer); + if(timer){ + secnotice("otrtimer","removing timer for peer: %@", peer); + SOSPeerRemoveOTRTimerEntry(peer); + dispatch_cancel(timer); + } switch(coderStatus) { case kSOSCoderDataReturned: { - logRawMessage(localDecodedMessage, false, 0); + //logRawMessage(localDecodedMessage, false, 0); result = SOSCoderUnwrapDecoded; break; } @@ -102,9 +112,7 @@ enum SOSCoderUnwrapStatus SOSPeerHandleCoderMessage(SOSPeerRef peer, SOSCoderRef xit: return result; } - - -bool SOSPeerCoderSendMessageIfNeeded(SOSEngineRef engine, SOSTransactionRef txn, SOSPeerRef peer, SOSCoderRef coder, CFDataRef *message_to_send, CFStringRef peer_id, SOSEnginePeerMessageSentBlock *sent, CFErrorRef *error) { +bool SOSPeerCoderSendMessageIfNeeded(SOSAccount* account, SOSEngineRef engine, SOSTransactionRef txn, SOSPeerRef peer, SOSCoderRef coder, CFDataRef *message_to_send, CFStringRef peer_id, CFMutableArrayRef *attributeList, SOSEnginePeerMessageSentBlock *sent, CFErrorRef *error) { bool ok = false; secnotice("transport", "coder state: %@", coder); require_action_quiet(coder, xit, secerror("%@ getCoder: %@", peer_id, error ? *error : NULL)); @@ -112,9 +120,9 @@ bool SOSPeerCoderSendMessageIfNeeded(SOSEngineRef engine, SOSTransactionRef txn, if (SOSCoderCanWrap(coder)) { secinfo("transport", "%@ Coder can wrap, getting message from engine", peer_id); CFMutableDataRef codedMessage = NULL; - CFDataRef message = SOSEngineCreateMessage_locked(engine, txn, peer, error, sent); + CFDataRef message = SOSEngineCreateMessage_locked(engine, txn, peer, attributeList, error, sent); if (!message) { - secnotice("transport", "%@ SOSEngineCreateMessageToSyncToPeer failed: %@", peer_id, *error); + secnotice("transport", "%@ SOSEngineCreateMessage_locked failed: %@", peer_id, *error); } else if (CFDataGetLength(message) || SOSPeerMustSendMessage(peer)) { // TODO: Remove SOSPeerMustSendMessage from peer and move into coder/transport instead ok = message && (SOSCoderWrap(coder, message, &codedMessage, peer_id, error) == kSOSCoderDataReturned); @@ -122,7 +130,7 @@ bool SOSPeerCoderSendMessageIfNeeded(SOSEngineRef engine, SOSTransactionRef txn, secnotice("transport", "%@ SOSCoderWrap failed: %@", peer_id, *error); } else { CFRetainAssign(*message_to_send, codedMessage); - engine->codersNeedSaving = true; + SOSEngineSetCodersNeedSaving(engine, true); } CFReleaseNull(codedMessage); } else { @@ -130,17 +138,30 @@ bool SOSPeerCoderSendMessageIfNeeded(SOSEngineRef engine, SOSTransactionRef txn, ok = true; } CFReleaseNull(message); + } else { *message_to_send = SOSCoderCopyPendingResponse(coder); - engine->codersNeedSaving = true; + SOSEngineSetCodersNeedSaving(engine, true); secinfo("transport", "%@ negotiating, %@", peer_id, (message_to_send && *message_to_send) ? CFSTR("sending negotiation message.") : CFSTR("waiting for negotiation message.")); - *sent = Block_copy(^(bool wasSent){ + *sent = ^(bool wasSent){ if (wasSent) SOSCoderConsumeResponse(coder); - }); + }; ok = true; } - + /*if coder state is in awaiting for message, then set a timer and restart if failure*/ + if(*message_to_send != NULL && account.isInitialSyncing && !SOSPeerOTRTimerHaveReachedMaxRetryAllowance(account, (__bridge NSString*)peer_id)){ + if(SOSCoderIsCoderInAwaitingState(coder) && !SOSPeerTimerForPeerExist(peer) && SOSPeerOTRTimerHaveAnRTTAvailable(account, (__bridge NSString*)peer_id)){ + secnotice("otrtimer", "coder is in awaiting state"); + SOSPeerOTRTimerSetupAwaitingTimer(account, peer, engine, coder); + } + else if(!SOSCoderIsCoderInAwaitingState(coder)){ + secnotice("otrtimer", "coder not in awaiting state: %@", coder); + } + else if (SOSPeerTimerForPeerExist(peer)){ + secnotice("otrtimer", "timer for coder already set: %@", coder); + } + } xit: return ok; } diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.h index 6ab58698..86b6dc8c 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.h @@ -61,13 +61,13 @@ static inline SOSPeerInfoRef asSOSPeerInfo(CFTypeRef obj) { return isSOSPeerInfo(obj) ? (SOSPeerInfoRef) obj : NULL; } -SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, CFErrorRef* error); +SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, SecKeyRef octagonSigningKey, 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, CFErrorRef* error); + CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error); -SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error); +SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error); SOSPeerInfoRef SOSPeerInfoCreateCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFErrorRef* error); SOSPeerInfoRef SOSPeerInfoCreateCurrentCopy(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, @@ -172,6 +172,7 @@ CFStringRef SOSPeerGestaltGetName(CFDictionaryRef gestalt); CFTypeRef SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt, CFStringRef question); SecKeyRef SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFErrorRef *error); +SecKeyRef SOSPeerInfoCopyOctagonPubKey(SOSPeerInfoRef peer, CFErrorRef* error); CFDataRef SOSPeerInfoGetAutoAcceptInfo(SOSPeerInfoRef peer); @@ -219,6 +220,10 @@ bool SOSPeerInfoHasDeviceID(SOSPeerInfoRef peer); CFStringRef SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer); SOSPeerInfoRef SOSPeerInfoSetDeviceID(CFAllocatorRef allocator, SOSPeerInfoRef toCopy, CFStringRef IDS, SecKeyRef signingKey, CFErrorRef *error); +CFStringRef SOSPeerInfoCopySerialNumber(SOSPeerInfoRef pi); +CFStringRef SOSPeerInfoCopyOSVersion(SOSPeerInfoRef pi); + + bool SOSPeerInfoShouldUseIDSTransport(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer); bool SOSPeerInfoShouldUseIDSMessageFragmentation(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer); bool SOSPeerInfoShouldUseACKModel(SOSPeerInfoRef myPeer, SOSPeerInfoRef theirPeer); @@ -237,7 +242,6 @@ typedef uint32_t SOSPeerInfoDeviceClass; SOSPeerInfoDeviceClass SOSPeerInfoGetClass(SOSPeerInfoRef pi); - __END_DECLS #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.m similarity index 95% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.m index 78f932da..24d0cb0f 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfo.m @@ -29,8 +29,8 @@ #include #include #include +#include #include -#include #include #include @@ -78,6 +78,7 @@ const CFStringRef kPIOSVersionKey = CFSTR("OSVersion"); // Description Dictionary Entries static CFStringRef sPublicKeyKey = CFSTR("PublicSigningKey"); +static CFStringRef sOctagonPublicKeyKey = CFSTR("OctagonPublicSigningKey"); const CFStringRef sGestaltKey = CFSTR("DeviceGestalt"); const CFStringRef sVersionKey = CFSTR("ConflictVersion"); static CFStringRef sCloudIdentityKey = CFSTR("CloudIdentity"); @@ -103,21 +104,31 @@ SOSPeerInfoRef SOSPeerInfoAllocate(CFAllocatorRef allocator) { return CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator); } -SecKeyRef SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFErrorRef* error) { +static SecKeyRef _SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFStringRef keyDictionaryKey, CFErrorRef* error) +{ SecKeyRef result = NULL; - - CFDataRef pubKeyBytes = asData(CFDictionaryGetValue(peer->description, sPublicKeyKey), error); + + CFDataRef pubKeyBytes = asData(CFDictionaryGetValue(peer->description, keyDictionaryKey), error); require_quiet(pubKeyBytes, fail); - + CFAllocatorRef allocator = CFGetAllocator(peer); result = SecKeyCreateFromPublicData(allocator, kSecECDSAAlgorithmID, pubKeyBytes); - + require_quiet(SecAllocationError(result, error, CFSTR("Failed to create public key from data %@"), pubKeyBytes), fail); - + fail: return result; } +SecKeyRef SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFErrorRef* error) { + return _SOSPeerInfoCopyPubKey(peer, sPublicKeyKey, error); +} + +SecKeyRef SOSPeerInfoCopyOctagonPubKey(SOSPeerInfoRef peer, CFErrorRef* error) +{ + return _SOSPeerInfoCopyPubKey(peer, sOctagonPublicKeyKey, error); +} + CFDataRef SOSPeerInfoGetAutoAcceptInfo(SOSPeerInfoRef peer) { CFDataRef pubKeyBytes = NULL; @@ -210,7 +221,7 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator, CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS, CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews, - SecKeyRef signingKey, CFErrorRef* error, + SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error, void (^ description_modifier)(CFMutableDictionaryRef description)) { SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator); pi->gestalt = gestalt; @@ -218,6 +229,7 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator, pi->version = SOSPeerInfoGetPeerProtocolVersion(pi); CFDataRef publicBytes = NULL; + CFDataRef octagonPublicBytes = NULL; CFNumberRef versionNumber = NULL; SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(signingKey); @@ -235,6 +247,21 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator, goto exit; } + SecKeyRef octagonPublicKey = SecKeyCreatePublicFromPrivate(octagonSigningKey); + if (octagonPublicKey == NULL) { + SOSCreateError(kSOSErrorBadKey, CFSTR("Unable to get public key"), NULL, error); + CFReleaseNull(pi); + goto exit; + } + + result = SecKeyCopyPublicBytes(octagonPublicKey, &octagonPublicBytes); + + if (result != errSecSuccess) { + SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error); + CFReleaseNull(pi); + goto exit; + } + pi->signature = CFDataCreateMutable(allocator, 0); versionNumber = CFNumberCreateWithCFIndex(NULL, pi->version); @@ -242,6 +269,7 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator, pi->description = CFDictionaryCreateMutableForCFTypesWith(allocator, sVersionKey, versionNumber, sPublicKeyKey, publicBytes, + sOctagonPublicKeyKey, octagonPublicBytes, sGestaltKey, pi->gestalt, NULL); @@ -251,6 +279,7 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator, pi->id = SOSCopyIDOfKey(publicKey, error); CFReleaseNull(publicKey); + CFReleaseNull(octagonPublicKey); require_quiet(pi->id, exit); @@ -280,23 +309,24 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator, exit: CFReleaseNull(versionNumber); CFReleaseNull(publicBytes); + CFReleaseNull(octagonPublicBytes); return pi; } -SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, CFErrorRef* error) { - return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, error, ^(CFMutableDictionaryRef description) {}); +SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) { + return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonSigningKey, error, ^(CFMutableDictionaryRef description) {}); } SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS, - CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews, SecKeyRef signingKey, CFErrorRef* error) + CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) { - return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey, error, ^(CFMutableDictionaryRef description) {}); + return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey, octagonSigningKey, 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, error, ^(CFMutableDictionaryRef description) { +SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, SecKeyRef octagonSigningKey, CFErrorRef* error) { + return SOSPeerInfoCreate_Internal(allocator, gestalt, NULL, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonSigningKey, error, ^(CFMutableDictionaryRef description) { CFDictionarySetValue(description, sCloudIdentityKey, kCFBooleanTrue); }); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoDER.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoDER.m similarity index 100% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoDER.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoDER.m diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoRingState.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoRingState.h index a2e63945..c9971c92 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoRingState.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoRingState.h @@ -22,8 +22,6 @@ #include #include #include -#include -#include SOSRingStatus SOSPeerInfoGetRingState(SOSPeerInfoRef pi, CFStringRef ringname, CFErrorRef *error); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoRingState.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoRingState.m similarity index 100% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoRingState.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoRingState.m diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoSecurityProperties.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoSecurityProperties.m similarity index 82% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoSecurityProperties.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoSecurityProperties.m index c240ab9f..008753b8 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoSecurityProperties.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoSecurityProperties.m @@ -20,12 +20,10 @@ #include #include #include -#include -#include -CFStringRef secpropMemError = CFSTR("Failed to get memory for SecurityProperties in PeerInfo"); -CFStringRef secpropUnknownError = CFSTR("Unknown Security Property(%@) (SOSSecurityPropertyResultCode=%d)"); -CFStringRef secpropInvalidError = CFSTR("Peer is invalid for this security property(%@) (SOSSecurityPropertyResultCode=%d)"); +#define secpropMemError CFSTR("Failed to get memory for SecurityProperties in PeerInfo") +#define secpropUnknownError CFSTR("Unknown Security Property(%@) (SOSSecurityPropertyResultCode=%d)") +#define secpropInvalidError CFSTR("Peer is invalid for this security property(%@) (SOSSecurityPropertyResultCode=%d)") const CFStringRef kSOSSecPropertyHasEntropy = CFSTR("SecPropEntropy"); const CFStringRef kSOSSecPropertyScreenLock = CFSTR("SecPropScreenLock"); @@ -81,10 +79,6 @@ static bool SOSPeerInfoSecurityPropertyIsValid(SOSPeerInfoRef pi, CFStringRef pr return true; } -static bool secPropertyErrorReport(CFIndex errorCode, CFErrorRef *error, CFStringRef format, CFStringRef propertyname, int retval) { - return SOSCreateErrorWithFormat(errorCode, NULL, error, NULL, format, propertyname, retval); -} - CFMutableSetRef SOSSecurityPropertiesCreateDefault(SOSPeerInfoRef pi, CFErrorRef *error) { return CFSetCreateMutableForSOSSecurityProperties(NULL); } @@ -96,9 +90,9 @@ SOSSecurityPropertyResultCode SOSSecurityPropertyEnable(SOSPeerInfoRef pi, CFStr require_action_quiet(newSecurityProperties, fail, SOSCreateError(kSOSErrorAllocationFailure, secpropMemError, NULL, error)); require_action_quiet(SOSSecurityPropertyIsKnownProperty(propertyname), fail, - secPropertyErrorReport(kSOSErrorNameMismatch, error, secpropUnknownError, propertyname, retval = kSOSCCNoSuchSecurityProperty)); + SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL, secpropUnknownError, propertyname, retval = kSOSCCNoSuchSecurityProperty)); require_action_quiet(SOSPeerInfoSecurityPropertyIsValid(pi, propertyname), fail, - secPropertyErrorReport(kSOSErrorNameMismatch, error, secpropInvalidError, propertyname, retval = kSOSCCSecurityPropertyNotQualified)); + SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL, secpropInvalidError, propertyname, retval = kSOSCCSecurityPropertyNotQualified)); CFSetAddValue(newSecurityProperties, propertyname); SOSPeerInfoSetSecurityProperty(pi, newSecurityProperties); CFReleaseSafe(newSecurityProperties); @@ -116,7 +110,7 @@ SOSSecurityPropertyResultCode SOSSecurityPropertyDisable(SOSPeerInfoRef pi, CFSt require_action_quiet(newSecurityProperties, fail, SOSCreateError(kSOSErrorAllocationFailure, secpropMemError, NULL, error)); require_action_quiet(SOSSecurityPropertyIsKnownProperty(propertyname), fail, - secPropertyErrorReport(kSOSErrorNameMismatch, error, secpropUnknownError, propertyname, retval = kSOSCCNoSuchSecurityProperty)); + SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL, secpropUnknownError, propertyname, retval = kSOSCCNoSuchSecurityProperty)); CFSetRemoveValue(newSecurityProperties, propertyname); SOSPeerInfoSetSecurityProperty(pi, newSecurityProperties); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.h index ef9cd5b3..2a2b1de7 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.h @@ -12,9 +12,7 @@ #include #include #include -#include #include -#include // Description Dictionary Entries Added for V2 extern CFStringRef sV2DictionaryKey; // CFData wrapper for V2 extensions @@ -60,6 +58,5 @@ void SOSPeerInfoV2DictionaryWithSet(SOSPeerInfoRef pi, const void *key, void(^op bool SOSPeerInfoSerialNumberIsSet(SOSPeerInfoRef pi); void SOSPeerInfoSetSerialNumber(SOSPeerInfoRef pi); void SOSPeerInfoSetTestSerialNumber(SOSPeerInfoRef pi, CFStringRef serialNumber); -CFStringRef SOSPeerInfoCopySerialNumber(SOSPeerInfoRef pi); #endif /* defined(_sec_SOSPeerInfoV2_) */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.m similarity index 98% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.m index b4450b97..4dd77fdc 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerInfoV2.m @@ -9,8 +9,9 @@ #include #include "SOSPeerInfoV2.h" #include -#include #include +#include +#include #include #include #include @@ -88,6 +89,11 @@ CFStringRef SOSPeerInfoCopySerialNumber(SOSPeerInfoRef pi) { return (retval ? retval : CFRetain(SOSSerialUnknown)); } +CFStringRef SOSPeerInfoCopyOSVersion(SOSPeerInfoRef pi) { + return SOSPeerInfoV2DictionaryCopyString(pi, kPIOSVersionKey); +} + + static bool SOSPeerInfoV2SanityCheck(SOSPeerInfoRef pi) { if(!pi) { return false; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerOTRTimer.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerOTRTimer.h new file mode 100644 index 00000000..8dc9a775 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerOTRTimer.h @@ -0,0 +1,24 @@ +// +// SOSPeerOTRTimer.h +// + +#ifndef SOSPeerOTRTimer_h +#define SOSPeerOTRTimer_h + +void SOSPeerOTRTimerFired(SOSAccount* account, SOSPeerRef peer, SOSEngineRef engine, SOSCoderRef coder); +int SOSPeerOTRTimerTimeoutValue(SOSAccount* account, SOSPeerRef peer); +void SOSPeerOTRTimerSetupAwaitingTimer(SOSAccount* account, SOSPeerRef peer, SOSEngineRef engine, SOSCoderRef coder); + +//KVS global config +void SOSPeerOTRTimerCreateKVSConfigDict(SOSAccount* account, CFNumberRef timeout, CFStringRef peerid); + + +//functions to handle max retry counter +void SOSPeerOTRTimerIncreaseOTRNegotiationRetryCount(SOSAccount* account, NSString* peerid); +bool SOSPeerOTRTimerHaveReachedMaxRetryAllowance(SOSAccount* account, NSString* peerid); +void SOSPeerOTRTimerClearMaxRetryCount(SOSAccount* account, NSString* peerid); +bool SOSPeerOTRTimerHaveAnRTTAvailable(SOSAccount* account, NSString* peerid); +void SOSPeerOTRTimerRemoveRTTTimeoutForPeer(SOSAccount* account, NSString* peerid); +void SOSPeerOTRTimerRemoveLastSentMessageTimestamp(SOSAccount* account, NSString* peerid); + +#endif /* SOSPeerOTRTimer_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerOTRTimer.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerOTRTimer.m new file mode 100644 index 00000000..0cbb885b --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerOTRTimer.m @@ -0,0 +1,393 @@ +// +// SOSPeerOTRTimer.m +// + +#import +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "SOSInternal.h" + +//AGGD +NSString* const SecSOSAggdMaxRenegotiation = @"com.apple.security.sos.otrrenegotiationmaxretries"; + + +static const CFStringRef OTRTimeoutsPerPeer = CFSTR("OTRTimeoutsPerPeer"); +static const CFStringRef OTRConfigVersion = CFSTR("OTRConfigVersion"); + +__unused static int initialOTRTimeoutValue = 60; //best round trip time in KVS plus extra for good measure +static int maxRetryCount = 7; //max number of times to attempt restarting OTR negotiation + +bool SOSPeerOTRTimerHaveReachedMaxRetryAllowance(SOSAccount* account, NSString* peerid){ + bool reachedMax = false; + NSMutableDictionary* attemptsPerPeer = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountRenegotiationRetryCount, NULL); + if(!attemptsPerPeer){ + attemptsPerPeer = [NSMutableDictionary dictionary]; + } + NSNumber* attempt = [attemptsPerPeer objectForKey:peerid]; + if(attempt && [attempt intValue] >= maxRetryCount) + { + reachedMax = true; + SecADAddValueForScalarKey((__bridge CFStringRef) SecSOSAggdMaxRenegotiation,1); + } + return reachedMax; +} + +//used when evaluating whether or not securityd should start a timer for negotiation +bool SOSPeerOTRTimerHaveAnRTTAvailable(SOSAccount* account, NSString* peerid) +{ + CFErrorRef error = NULL; + CFNumberRef timeout = NULL; + bool doesRTTExist = false; + + CFMutableDictionaryRef timeouts = (CFMutableDictionaryRef)asDictionary(SOSAccountGetValue(account, kSOSAccountPeerNegotiationTimeouts, &error), NULL); + require_action_quiet(timeouts, exit, secnotice("otrtimer", "do not have an rtt yet")); + + timeout = CFDictionaryGetValue(timeouts, (__bridge CFStringRef)peerid); + require_action_quiet(timeout, exit, secnotice("otrtimer", "do not have an rtt yet")); + + doesRTTExist = true; +exit: + return doesRTTExist; +} + +//call when a timer has fired, remove the current rtt entry as the existing one isn't working +void SOSPeerOTRTimerRemoveRTTTimeoutForPeer(SOSAccount* account, NSString* peerid) +{ + CFNumberRef timeout = NULL; + CFErrorRef error = NULL; + + CFMutableDictionaryRef timeouts = (CFMutableDictionaryRef)asDictionary(SOSAccountGetValue(account, kSOSAccountPeerNegotiationTimeouts, &error), NULL); + require_action_quiet(timeouts && (error == NULL), exit, secnotice("otrtimer","timeout dictionary doesn't exist")); + + timeout = CFDictionaryGetValue(timeouts, (__bridge CFStringRef)peerid); + require_action_quiet(timeout, exit, secnotice("otrtimer","timeout for peerid: %@, doesn't exist", (__bridge CFStringRef)peerid)); + + CFDictionaryRemoveValue(timeouts, (__bridge CFStringRef)peerid); + SOSAccountSetValue(account, kSOSAccountPeerNegotiationTimeouts, timeouts, &error); + if(error){ + secnotice("otrtimer","SOSAccountSetValue threw an error for key kSOSAccountPeerNegotiationTimeouts: %@", error); + } +exit: + CFReleaseNull(error); +} + +void SOSPeerOTRTimerRemoveLastSentMessageTimestamp(SOSAccount* account, NSString* peerid) +{ + NSMutableDictionary *peerToTimeLastSentDict = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountPeerLastSentTimestamp, NULL); + + if(peerToTimeLastSentDict){ + NSDate* storedDate = [peerToTimeLastSentDict objectForKey:peerid]; + if(storedDate){ + [peerToTimeLastSentDict removeObjectForKey:peerid]; + SOSAccountSetValue(account, kSOSAccountPeerLastSentTimestamp, (__bridge CFMutableDictionaryRef)peerToTimeLastSentDict, NULL); + } + } +} + +void SOSPeerOTRTimerIncreaseOTRNegotiationRetryCount(SOSAccount* account, NSString* peerid) +{ + NSMutableDictionary* attemptsPerPeer = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountRenegotiationRetryCount, NULL); + if(!attemptsPerPeer){ + attemptsPerPeer = [NSMutableDictionary dictionary]; + } + NSNumber* attempt = [attemptsPerPeer objectForKey:peerid]; + if(!attempt){ + attempt = [[NSNumber alloc] initWithInt:1]; + [attemptsPerPeer setObject:attempt forKey:peerid]; + } + else{ + NSNumber* newCount = [[NSNumber alloc]initWithInt:([attempt intValue]+1)]; + [attemptsPerPeer setObject:newCount forKey:peerid]; + secnotice("otr","OTR negotiation retry count: %d", [newCount intValue]); + } + SOSAccountSetValue(account, kSOSAccountRenegotiationRetryCount, (__bridge CFMutableDictionaryRef)attemptsPerPeer, NULL); +} + +static CFNumberRef SOSPeerOTRTimerCopyConfigVersion(SOSAccount* account) +{ + uint64_t v = 0; + CFNumberRef versionFromAccount = NULL; + CFNumberRef version = (CFNumberRef)SOSAccountGetValue(account, OTRConfigVersion, NULL); + + if(!version){ + versionFromAccount = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &v); + SOSAccountSetValue(account, OTRConfigVersion, versionFromAccount, NULL); + } + else{ + versionFromAccount = CFRetainSafe(version); + } + return versionFromAccount; +} + +void SOSPeerOTRTimerCreateKVSConfigDict(SOSAccount* account, CFNumberRef timeout, CFStringRef peerid) +{ + CFMutableDictionaryRef peerToTimeout = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(peerToTimeout, peerid, timeout); + + CFNumberRef versionFromAccount = SOSPeerOTRTimerCopyConfigVersion(account); + + CFMutableDictionaryRef peerTimeOutsAndVersion = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(peerTimeOutsAndVersion, OTRTimeoutsPerPeer, peerToTimeout); + CFDictionaryAddValue(peerTimeOutsAndVersion, OTRConfigVersion, versionFromAccount); + + CFMutableDictionaryRef myPeerChanges = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFStringRef myPeerID = (__bridge CFStringRef) account.peerID; + CFDictionaryAddValue(myPeerChanges, myPeerID, peerTimeOutsAndVersion); + + CFMutableDictionaryRef otrConfig = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(otrConfig, kSOSKVSOTRConfigVersion, myPeerChanges); + + SOSCloudKeychainPutObjectsInCloud(otrConfig, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) { + if (block_error) { + secerror("Error putting: %@", block_error); + } + }); + secnotice("kvsconfig", "submitting config to KVS: %@", otrConfig); + CFReleaseNull(myPeerChanges); + CFReleaseNull(peerToTimeout); + CFReleaseNull(versionFromAccount); + CFReleaseNull(otrConfig); +} + +//grab existing key from KVS +__unused __unused static CFDictionaryRef SOSPeerOTRTimerCopyConfigFromKVS() +{ + CFErrorRef error = NULL; + __block CFTypeRef object = NULL; + + dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); + const uint64_t maxTimeToWaitInSeconds = 5ull * NSEC_PER_SEC; + + dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds); + + SOSCloudKeychainGetAllObjectsFromCloud(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef block_error) { + secnotice("otrtimer", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues); + object = returnedValues; + if (object) + CFRetain(object); + if (error) + { + secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error); + } + secnotice("otrtimer", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object); + dispatch_semaphore_signal(waitSemaphore); + }); + + dispatch_semaphore_wait(waitSemaphore, finishTime); + if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull + { + CFRelease(object); + object = NULL; + return NULL; + } + if(isDictionary(object)) + { + return CFRetainSafe((CFDictionaryRef)object); + } + return NULL; +} + +__unused static bool SOSPeerOTRTimerShouldWriteConfig(CFDictionaryRef config, CFStringRef myID, CFStringRef peerid, CFNumberRef currentConfigVersion, CFNumberRef localTimeout) +{ + bool result = true; + secnotice("otrtimer", "grabbed config from KVS: %@", config); + CFDictionaryRef myPeerConfigSettings = NULL; + CFNumberRef versionFromKVS = NULL; + CFDictionaryRef peerToTimeouts = NULL; + CFNumberRef timeoutInKVS = NULL; + CFDictionaryRef otrConfig = NULL; + + require_action_quiet(currentConfigVersion, fail, secnotice("otrtimer","current config version is null")); + require_action_quiet(localTimeout, fail, secnotice("otrtimer", "local timeout is null")); + + otrConfig = CFDictionaryGetValue(config, kSOSKVSOTRConfigVersion); + require_action_quiet(otrConfig, fail, secnotice("otrtimer","otr config does not exist")); + + myPeerConfigSettings = CFDictionaryGetValue(otrConfig, myID); + require_action_quiet(myPeerConfigSettings, fail, secnotice("otrtimer","my peer config settings dictionary is null")); + + versionFromKVS = CFDictionaryGetValue(myPeerConfigSettings, OTRConfigVersion); + require_action_quiet(versionFromKVS, fail, secnotice("otrtimer", "version from KVS is null")); + + peerToTimeouts = CFDictionaryGetValue(myPeerConfigSettings, OTRTimeoutsPerPeer); + require_action_quiet(peerToTimeouts, fail, secnotice("otrtimer", "dictionary of peerids and timeout values is null")); + + timeoutInKVS = CFDictionaryGetValue(peerToTimeouts, peerid); + require_action_quiet(timeoutInKVS, fail, secnotice("otrtimer", "timeout value from kvs is null")); + + if(kCFCompareEqualTo == CFNumberCompare(currentConfigVersion, versionFromKVS, NULL) && + (CFNumberCompare(timeoutInKVS, localTimeout, NULL) == kCFCompareEqualTo)){ + secnotice("otrtimer", "versions match, can write new config"); + }else if(CFNumberCompare(versionFromKVS, currentConfigVersion, NULL) == kCFCompareGreaterThan){ + result = false; + secnotice("otrtimer", "versions do not match, cannot write a new config"); + }else{ + secnotice("otrtimer", "config versions match, going to write current configuration of peerids to timeouts to KVS"); + } + +fail: + return result; + +} + +__unused static CFNumberRef SOSPeerOTRTimerCopyOTRConfigVersionFromAccount(SOSAccount* account) +{ + CFNumberRef version = SOSAccountGetValue(account, OTRConfigVersion, NULL); + if(!version){ + uint64_t v = 0; + version = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &v); + SOSAccountSetValue(account, OTRConfigVersion, version, NULL); + }else{ + return CFRetainSafe(version); + } + + return version; +} + +__unused static bool SOSPeerOTRTimerShouldUseTimeoutValueFromKVS(CFDictionaryRef otrConfigFromKVS, CFStringRef myID, CFNumberRef localConfigVersion){ + bool shouldUseTimeoutFromKVS = false; + CFDictionaryRef otrConfig = NULL; + CFDictionaryRef myPeerConfigSettings = NULL; + CFNumberRef versionFromKVS = NULL; + + require_action_quiet(otrConfigFromKVS, xit, secnotice("otrtimer", "configuration file from kvs does not exist")); + + otrConfig = CFDictionaryGetValue(otrConfigFromKVS, kSOSKVSOTRConfigVersion); + require_action_quiet(otrConfig, xit, secnotice("otrtimer", "configuration file from kvs does not exist")); + + myPeerConfigSettings = CFDictionaryGetValue(otrConfig, myID); + require_action_quiet(myPeerConfigSettings, xit, secnotice("otrtimer", "configuration file from kvs does not exist")); + + versionFromKVS = CFDictionaryGetValue(myPeerConfigSettings, OTRConfigVersion); + require_action_quiet(versionFromKVS && (CFGetTypeID(versionFromKVS) != CFNullGetTypeID()), xit, secnotice("otrtimer", "configuration file from kvs does not exist")); + + if(CFNumberCompare(versionFromKVS, localConfigVersion, NULL) == kCFCompareGreaterThan){ + secnotice("otrtimer", "should use timeout from kvs"); + shouldUseTimeoutFromKVS = true; + } + +xit: + return shouldUseTimeoutFromKVS; +} + +__unused static CFNumberRef SOSPeerOTRTimerTimeoutFromKVS(CFDictionaryRef otrConfigFromKVS, CFStringRef myID, CFStringRef peerID) +{ + CFNumberRef timeout = NULL; + CFDictionaryRef otrConfig = NULL; + CFDictionaryRef myPeerConfigSettings = NULL; + CFDictionaryRef peerToTimeoutDictionary = NULL; + + require_action_quiet(otrConfigFromKVS, xit, secnotice("otrtimer", "configuration file from kvs does not exist")); + + otrConfig = CFDictionaryGetValue(otrConfigFromKVS, kSOSKVSOTRConfigVersion); + require_action_quiet(otrConfig, xit, secnotice("otrtimer", "configuration file from kvs does not exist")); + + myPeerConfigSettings = CFDictionaryGetValue(otrConfig, myID); + require_action_quiet(myPeerConfigSettings, xit, secnotice("otrtimer", "configuration file from kvs does not exist")); + + peerToTimeoutDictionary = CFDictionaryGetValue(myPeerConfigSettings, OTRTimeoutsPerPeer); + require_action_quiet(peerToTimeoutDictionary, xit, secnotice("otrtimer", "configuration file from kvs does not exist")); + + timeout = CFDictionaryGetValue(peerToTimeoutDictionary, peerID); +xit: + return timeout; +} + +int SOSPeerOTRTimerTimeoutValue(SOSAccount* account, SOSPeerRef peer) +{ + CFErrorRef error = NULL; + //bool shouldWriteConfig = true; + //bool shouldUseTimeoutFromKVS = false; + int timeoutIntValue = 0; + + //CFDictionaryRef configFromKVS = SOSPeerOTRTimerCopyConfigFromKVS(); + + //CFNumberRef configVersion = SOSPeerOTRTimerCopyOTRConfigVersionFromAccount(account); + //shouldUseTimeoutFromKVS = SOSPeerOTRTimerShouldUseTimeoutValueFromKVS(configFromKVS, (__bridge CFStringRef)account.peerID,configVersion); + //CFReleaseNull(configVersion); + + //if(shouldUseTimeoutFromKVS){ + // secnotice("otrtimer", "using timeout from kvs"); + //CFNumberRef timeoutFromKVS = SOSPeerOTRTimerTimeoutFromKVS(configFromKVS, (__bridge CFStringRef)account.peerID, //SOSPeerGetID(peer)); + //CFReleaseNull(configFromKVS); + //return [(__bridge NSNumber*)timeoutFromKVS intValue]; + // } + + CFMutableDictionaryRef timeouts = (CFMutableDictionaryRef)asDictionary(SOSAccountGetValue(account, kSOSAccountPeerNegotiationTimeouts, &error), NULL); + require_action_quiet(timeouts, xit, secnotice("otrtimer","deadline value not available yet")); + + CFNumberRef timeout = CFDictionaryGetValue(timeouts, SOSPeerGetID(peer)); + require_action_quiet(timeout, xit, secnotice("otrtimer","deadline value not available yet")); + + secnotice("otrtimer", "decided to wait %d before restarting negotiation", [(__bridge NSNumber*)timeout intValue]); + timeoutIntValue = [(__bridge NSNumber*)timeout intValue]; + + //CFNumberRef localConfigVersion = SOSPeerOTRTimerCopyOTRConfigVersionFromAccount(account); + /* + if(localConfigVersion){ + shouldWriteConfig = SOSPeerOTRTimerShouldWriteConfig(configFromKVS, (__bridge CFStringRef)account.peerID, SOSPeerGetID(peer), localConfigVersion, timeout); + } + + if(shouldWriteConfig) + SOSPeerOTRTimerCreateKVSConfigDict(account, timeout, SOSPeerGetID(peer)); + */ + +xit: + // CFReleaseNull(configVersion); + //CFReleaseNull(localConfigVersion); + //CFReleaseNull(configFromKVS); + + return timeoutIntValue; +} + +void SOSPeerOTRTimerSetupAwaitingTimer(SOSAccount* account, SOSPeerRef peer, SOSEngineRef engine, SOSCoderRef coder) +{ + //check which timeout value to use + int timeoutValue = SOSPeerOTRTimerTimeoutValue(account, peer); + CFStringRef peerid = CFRetainSafe(SOSPeerGetID(peer)); + + secnotice("otrtimer", "setting timer for peer: %@", peer); + __block dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); + dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, timeoutValue * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); + dispatch_source_set_event_handler(timer, ^{ + secnotice("otrtimer","otrTimerFired fired"); + SOSCCResetOTRNegotiation_Server(peerid); + + }); + + dispatch_source_set_cancel_handler(timer, ^{ + CFReleaseSafe(peerid); + }); + + dispatch_resume(timer); + + SOSPeerSetOTRTimer(peer, timer); +} + +//clear the max retry counter in the account object +void SOSPeerOTRTimerClearMaxRetryCount(SOSAccount* account, NSString* peerid) +{ + secnotice("otrtimer", "negotiation finished! clearing max retry counter"); + NSMutableDictionary* attemptsPerPeer = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountRenegotiationRetryCount, NULL); + if(!attemptsPerPeer){ + attemptsPerPeer = [NSMutableDictionary dictionary]; + } + [attemptsPerPeer removeObjectForKey:peerid]; + SOSAccountSetValue(account, kSOSAccountRenegotiationRetryCount, (__bridge CFMutableDictionaryRef)attemptsPerPeer, NULL); +} + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerRateLimiter.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerRateLimiter.h new file mode 100644 index 00000000..9690c0ae --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerRateLimiter.h @@ -0,0 +1,36 @@ +// +// SOSPeerRateLimiter.h +// Security +// +#import "keychain/ckks/RateLimiter.h" +#include "Security/SecureObjectSync/SOSPeer.h" + +#ifndef SOSPeerRateLimiter_h +#define SOSPeerRateLimiter_h + +enum RateLimitState{ + RateLimitStateCanSend = 1, + RateLimitStateHoldMessage = 2 +}; + +@interface PeerRateLimiter : RateLimiter +{ + NSString *peerID; +} + +@property (retain) NSString *peerID; +@property (retain) NSMutableDictionary *accessGroupRateLimitState; +@property (retain) NSMutableDictionary *accessGroupToTimer; +@property (retain) NSMutableDictionary *accessGroupToNextMessageToSend; + +-(instancetype)initWithPeer:(SOSPeerRef)peer; +-(NSDictionary *) setUpConfigForPeer; +-(enum RateLimitState) stateForAccessGroup:(NSString*) accessGroup; +@end + +@interface KeychainItem : NSObject +@property (atomic, retain) NSString* accessGroup; +-(instancetype) initWithAccessGroup:(NSString*)accessGroup; +@end + +#endif /* SOSPeerRateLimiter_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerRateLimiter.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerRateLimiter.m new file mode 100644 index 00000000..22f4bba7 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPeerRateLimiter.m @@ -0,0 +1,112 @@ +// +// SOSPeerRateLimiter.m +// SecureObjectSyncServer +// + +#import +#import +#import "Security/SecureObjectSync/SOSPeerRateLimiter.h" + +#include +#include +#include +#include + +// +// RateLimiting Code per Peer + +@implementation PeerRateLimiter + +@synthesize peerID = peerID; + +-(NSDictionary*) setUpConfigForPeer +{ + NSData *configData = [@"\ + \ + \ + \ + general\ + \ + maxStateSize\ + 250\ + maxItemAge\ + 3600\ + overloadDuration\ + 1800\ + name\ + SOS\ + MAType\ + \ + \ + groups\ + \ + \ + property\ + global\ + capacity\ + 1000\ + rate\ + 10\ + badness\ + 1\ + \ + \ + property\ + accessGroup\ + capacity\ + 20\ + rate\ + 900\ + badness\ + 3\ + \ + \ + \ + \ + " dataUsingEncoding:NSUTF8StringEncoding]; + + NSError *err = nil; + return ([NSPropertyListSerialization propertyListWithData:configData options:NSPropertyListImmutable format:nil error:&err]); +} + +-(instancetype)initWithPeer:(SOSPeerRef)peer +{ + self = [super initWithConfig:[self setUpConfigForPeer]]; + if(self){ + self.peerID = (__bridge NSString *)(SOSPeerGetID(peer)); + self.accessGroupRateLimitState = [[NSMutableDictionary alloc] init]; + self.accessGroupToTimer = [[NSMutableDictionary alloc]init]; + self.accessGroupToNextMessageToSend = [[NSMutableDictionary alloc]init]; + } + return self; +} + +-(enum RateLimitState) stateForAccessGroup:(NSString*) accessGroup +{ + enum RateLimitState stateForAccessGroup; + NSNumber *state = [self.accessGroupRateLimitState objectForKey:accessGroup]; + if(state == nil) + { + //initialize access group state + stateForAccessGroup = RateLimitStateCanSend; + NSNumber *initialize = [[NSNumber alloc] initWithLong:stateForAccessGroup]; + [self.accessGroupRateLimitState setObject:initialize forKey:accessGroup]; + }else{ + stateForAccessGroup = [state intValue]; + } + return stateForAccessGroup; +} +@end + +@implementation KeychainItem + +-(instancetype)initWithAccessGroup:(NSString *)accessGroup +{ + self = [super init]; + if(self){ + _accessGroup = accessGroup; + } + return self; +} + +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPiggyback.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSPiggyback.h new file mode 100644 index 00000000..3257cdb4 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPiggyback.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 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 SOSCIRCLE_PIGGIGGYBACK_H +#define SOSCIRCLE_PIGGIGGYBACK_H 1 + +#include +#include +#include + +__BEGIN_DECLS + +bool SOSPiggyBackBlobCreateFromData(SOSGenCountRef *gencount, SecKeyRef *pubKey, CFDataRef *signature, + CFDataRef blobData, PiggyBackProtocolVersion version, bool *setInitialSyncTimeoutToV0, CFErrorRef *error); +bool SOSPiggyBackBlobCreateFromDER(SOSGenCountRef *retGencount, SecKeyRef *retPubKey, CFDataRef *retSignature, + const uint8_t** der_p, const uint8_t *der_end, PiggyBackProtocolVersion version, bool *setInitialSyncTimeoutToV0, CFErrorRef *error); +CFDataRef SOSPiggyBackBlobCopyEncodedData(SOSGenCountRef gencount, SecKeyRef pubKey, CFDataRef signature, CFErrorRef *error); + +#if __OBJC__ +bool SOSPiggyBackAddToKeychain(NSArray* identity, NSArray* tlk); +#endif + +__END_DECLS + +#endif /* SOSCIRCLE_PIGGIGGYBACK_H */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSPiggyback.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSPiggyback.m new file mode 100644 index 00000000..23377ed9 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSPiggyback.m @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2015 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "SOSPiggyback.h" + +#include "utilities/der_date.h" +#include "utilities/der_plist.h" +#include +#include + +static size_t SOSPiggyBackBlobGetDEREncodedSize(SOSGenCountRef gencount, SecKeyRef pubKey, CFDataRef signature, CFErrorRef *error) { + size_t total_payload = 0; + + CFDataRef publicBytes = NULL; + OSStatus result = SecKeyCopyPublicBytes(pubKey, &publicBytes); + + if (result != errSecSuccess) { + SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error); + return 0; + } + + require_quiet(accumulate_size(&total_payload, der_sizeof_number(gencount, error)), errOut); + require_quiet(accumulate_size(&total_payload, der_sizeof_data_or_null(publicBytes, error)), errOut); + require_quiet(accumulate_size(&total_payload, der_sizeof_data_or_null(signature, error)), errOut); + return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, total_payload); + +errOut: + SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("don't know how to encode"), NULL, error); + return 0; +} + + +static uint8_t* SOSPiggyBackBlobEncodeToDER(SOSGenCountRef gencount, SecKeyRef pubKey, CFDataRef signature, CFErrorRef* error, const uint8_t* der, uint8_t* der_end) { + CFDataRef publicBytes = NULL; + + OSStatus result = SecKeyCopyPublicBytes(pubKey, &publicBytes); + + if (result != errSecSuccess) { + SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to export public bytes"), NULL, error); + return NULL; + } + + + der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, + der_encode_number(gencount, error, der, + der_encode_data_or_null(publicBytes, error, der, + der_encode_data_or_null(signature, error, der, der_end)))); + return der_end; +} + +CFDataRef SOSPiggyBackBlobCopyEncodedData(SOSGenCountRef gencount, SecKeyRef pubKey, CFDataRef signature, CFErrorRef *error) +{ + return CFDataCreateWithDER(kCFAllocatorDefault, SOSPiggyBackBlobGetDEREncodedSize(gencount, pubKey, signature, error), ^uint8_t*(size_t size, uint8_t *buffer) { + return SOSPiggyBackBlobEncodeToDER(gencount, pubKey, signature, error, buffer, (uint8_t *) buffer + size); + }); +} + +bool SOSPiggyBackAddToKeychain(NSArray* identities, NSArray* tlks) +{ + [tlks enumerateObjectsUsingBlock:^(NSDictionary* item, NSUInteger idx, BOOL * _Nonnull stop) { + + NSData* v_data = item[(__bridge NSString*)kSecValueData]; + NSString *acct = item[(__bridge NSString*)kSecAttrAccount]; + NSString *srvr = item[(__bridge NSString*)kSecAttrServer]; + + NSData* base64EncodedVData = [v_data base64EncodedDataWithOptions:0]; + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup: @"com.apple.security.ckks", + (id)kSecAttrDescription: @"tlk-piggy", + (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, + (id)kSecAttrSyncViewHint : (id)kSecAttrViewHintPCSMasterKey, + (id)kSecAttrServer: srvr, + (id)kSecAttrAccount: [NSString stringWithFormat: @"%@-piggy", acct], + (id)kSecAttrPath: acct, + (id)kSecAttrIsInvisible: @YES, + (id)kSecValueData : base64EncodedVData, + } mutableCopy]; + + OSStatus status = SecItemAdd((__bridge CFDictionaryRef) query, NULL); + + if(status == errSecDuplicateItem) { + // Sure, okay, fine, we'll update. + NSMutableDictionary* update = [@{(id)kSecValueData: v_data, + } mutableCopy]; + + status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef)update); + } + + if(status) { + secerror("Couldn't save tlks to keychain %d", (int)status); + } + }]; + [identities enumerateObjectsUsingBlock:^(NSData *v_data, NSUInteger idx, BOOL *stop) { + SecKeyRef publicKey = NULL; + SecKeyRef privKey = NULL; + CFDataRef public_key_hash = NULL; + NSMutableDictionary* query = NULL; + CFStringRef peerid = NULL; + OSStatus status; + + NSDictionary *keyAttributes = @{ + (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, + (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC, + }; + //create private key + privKey = SecKeyCreateWithData((__bridge CFDataRef)v_data, (__bridge CFDictionaryRef)keyAttributes, NULL); + require_action_quiet(privKey, exit, secnotice("piggy","privKey failed to be created")); + //create public key + publicKey = SecKeyCreatePublicFromPrivate(privKey); + require_action_quiet(privKey, exit, secnotice("piggy","public key failed to be created")); + + //create public_key_hash + public_key_hash = SecKeyCopyPublicKeyHash(publicKey); + require_action_quiet(privKey, exit, secnotice("piggy","can't create public key hash")); + + peerid = SOSCopyIDOfKey(publicKey, NULL); + + query = [@{ + (id)kSecClass : (id)kSecClassKey, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup: @"com.apple.security.sos", + (id)kSecAttrApplicationLabel : (__bridge NSData*)public_key_hash, + (id)kSecAttrLabel : [NSString stringWithFormat: @"Cloud Identity-piggy-%@", peerid], + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecUseTombstones : (id)kCFBooleanTrue, + (id)kSecValueData : v_data, + } mutableCopy]; + + status = SecItemAdd((__bridge CFDictionaryRef) query, NULL); + + if(status == errSecDuplicateItem) { + // Sure, okay, fine, we'll update. + NSMutableDictionary* update = [@{ + (id)kSecValueData: v_data, + } mutableCopy]; + query[(id)kSecValueData] = nil; + status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef)update); + } + + if(status) { + secerror("Couldn't save backupV0 to keychain %d", (int)status); + } + + exit: + CFReleaseNull(publicKey); + CFReleaseNull(privKey); + CFReleaseNull(peerid); + CFReleaseNull(public_key_hash); + secnotice("piggy","key not available"); + }]; + + return true; +} + +static const uint8_t * +piggy_decode_data(const uint8_t *der, const uint8_t *der_end, NSData **data) +{ + size_t body_length = 0; + const uint8_t *body = ccder_decode_tl(CCDER_OCTET_STRING, &body_length, der, der_end); + if(body == NULL) + return NULL; + *data = [NSData dataWithBytes:body length:body_length]; + return body + body_length; + +} + +static NSMutableArray * +parse_identies(const uint8_t *der, const uint8_t *der_end) +{ + NSMutableArray* array = [NSMutableArray array]; + + while (der != der_end) { + NSData *data = NULL; + + der = piggy_decode_data(der, der_end, &data); + if (der == NULL) + return NULL; + if (data) + [array addObject:data]; + } + + return array; +} + +static NSMutableArray * +SOSPiggyCreateDecodedTLKs(const uint8_t *der, const uint8_t *der_end) +{ + NSMutableArray *array = [NSMutableArray array]; + + while (der != der_end) { + NSMutableDictionary *item = [NSMutableDictionary dictionary]; + NSData *data = NULL; + size_t item_size = 0; + + const uint8_t *item_der = ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &item_size, der, der_end); + if (item_der == NULL) + return NULL; + const uint8_t *end_item_der = item_der + item_size; + + item_der = piggy_decode_data(item_der, end_item_der, &data); + if (der == NULL) + return NULL; + + item[(__bridge id)kSecValueData] = data; + data = NULL; + + item_der = piggy_decode_data(item_der, end_item_der, &data); + if (item_der == NULL) + return NULL; + if ([data length] != sizeof(uuid_t)) { + return NULL; + } + + NSString *uuidString = [[[NSUUID alloc] initWithUUIDBytes:[data bytes]] UUIDString]; + item[(__bridge id)kSecAttrAccount] = uuidString; + + NSString *view = NULL; + uint64_t r = 0; + const uint8_t *choice_der = NULL; + choice_der = ccder_decode_uint64(&r, item_der, end_item_der); + if (choice_der == NULL) { + /* try other branch of CHOICE, a string */ + CFErrorRef localError = NULL; + CFStringRef string = NULL; + + choice_der = der_decode_string(NULL, 0, &string, &localError, item_der, end_item_der); + if (choice_der == NULL || string == NULL) { + CFReleaseNull(string); + secnotice("piggy", "Failed to parse view name"); + return NULL; + } + CFReleaseNull(localError); + item_der = choice_der; + view = CFBridgingRelease(string); + } else { + if (r == kTLKManatee) + view = @"Manatee"; + else if (r == kTLKEngram) + view = @"Engram"; + else if (r == kTLKAutoUnlock) + view = @"AutoUnlock"; + else if (r == kTLKHealth) + view = @"Health"; + else { + secnotice("piggy", "unexpected view number: %d", (int)r); + return NULL; + } + item_der = choice_der; + } + item[(__bridge id)kSecAttrServer] = view; + + if (item_der != end_item_der) { + return NULL; + } + secnotice("piggy", "Adding %@ %@", view, uuidString); + + [array addObject:item]; + + der = end_item_der; + } + return array; +} + +NSDictionary * +SOSPiggyCopyInitialSyncData(const uint8_t** der, const uint8_t *der_end) +{ + NSMutableDictionary *results = [NSMutableDictionary dictionary]; + size_t seq_size; + + const uint8_t *topSeq = ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &seq_size, *der, der_end); + if(topSeq == NULL){ + secnotice("piggy", "Failed to parse CONS SEQ"); + return NULL; + } + + /* parse idents */ + const uint8_t *ider = ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &seq_size, topSeq, der_end); + if (ider == NULL){ + secnotice("piggy", "Failed to parse CONS SEQ of ident"); + return NULL; + } + NSArray *idents = parse_identies(ider, ider + seq_size); + if (idents) + results[@"idents"] = idents; + topSeq = ider + seq_size; + + /* parse tlks */ + const uint8_t *tder = ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &seq_size, topSeq, der_end); + if (tder == NULL){ + secnotice("piggy", "Failed to parse CONS SEQ of TLKs"); + return NULL; + } + NSMutableArray *tlks = SOSPiggyCreateDecodedTLKs(tder, tder + seq_size); + if (tlks) + results[@"tlks"] = tlks; + *der = tder + seq_size; + + /* Don't check length here so we can add more data */ + + if(results.count == 0 || tlks.count == 0){ + secnotice("piggy","NO DATA, falling back to waiting 5 minutes for initial sync to finish"); + results = NULL; + } + + return results; +} + +bool +SOSPiggyBackBlobCreateFromDER(SOSGenCountRef *retGencount, + SecKeyRef *retPubKey, + CFDataRef *retSignature, + const uint8_t** der_p, const uint8_t *der_end, + PiggyBackProtocolVersion version, + bool *setInitialSyncTimeoutToV0, + CFErrorRef *error) +{ + const uint8_t *sequence_end; + SOSGenCountRef gencount = NULL; + CFDataRef signature = NULL; + CFDataRef publicBytes = NULL; + + bool res = true; + + *setInitialSyncTimeoutToV0 = true; + + *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_data_or_null(kCFAllocatorDefault, &publicBytes, error, *der_p, sequence_end); + *der_p = der_decode_data_or_null(kCFAllocatorDefault, &signature, error, *der_p, sequence_end); + + if(version == kPiggyV1){ + NSDictionary* initialSyncDict = SOSPiggyCopyInitialSyncData(der_p, der_end); + if (initialSyncDict) { + NSArray* idents = initialSyncDict[@"idents"]; + NSArray* tlks = initialSyncDict[@"tlks"]; + SOSPiggyBackAddToKeychain(idents, tlks); + *setInitialSyncTimeoutToV0 = false; + } + /* Don't check length here so we can add more data */ + } + else{ //V0 + secnotice("piggy","Piggybacking version 0, setting initial sync timeout to 5 minutes"); + *setInitialSyncTimeoutToV0 = true; + require_action_quiet(*der_p && *der_p == der_end, errOut, + SOSCreateError(kSOSErrorBadFormat, CFSTR("Didn't consume all bytes for pbblob"), (error != NULL) ? *error : NULL, error)); + } + + *retPubKey = SecKeyCreateFromPublicData(kCFAllocatorDefault, kSecECDSAAlgorithmID, publicBytes); + require_quiet(*retPubKey, errOut); + *retGencount = gencount; + *retSignature = signature; + + res = true; + +errOut: + if(!res) { + CFReleaseNull(gencount); + CFReleaseNull(publicBytes); + CFReleaseNull(signature); + } + + return res; +} + +bool +SOSPiggyBackBlobCreateFromData(SOSGenCountRef *gencount, + SecKeyRef *pubKey, + CFDataRef *signature, + CFDataRef blobData, + PiggyBackProtocolVersion version, + bool *setInitialSyncTimeoutToV0, + CFErrorRef *error) +{ + size_t size = CFDataGetLength(blobData); + const uint8_t *der = CFDataGetBytePtr(blobData); + return SOSPiggyBackBlobCreateFromDER(gencount, pubKey, signature, &der, der + size, version, setInitialSyncTimeoutToV0, error); +} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.h index d9d0fb2f..71c2620a 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.h @@ -31,13 +31,12 @@ #include #include -#include +typedef struct __OpaqueSOSRecoveryKeyBag *SOSRecoveryKeyBagRef; CFTypeRef SOSRecoveryKeyBageGetTypeID(void); - -SOSRecoveryKeyBagRef SOSRecoveryKeyBagCreateForAccount(CFAllocatorRef allocator, SOSAccountRef account, CFDataRef pubData, CFErrorRef *error); -CFDataRef SOSRecoveryKeyCopyKeyForAccount(CFAllocatorRef allocator, SOSAccountRef account, SOSRecoveryKeyBagRef recoveryKeyBag, CFErrorRef *error); +SOSRecoveryKeyBagRef SOSRecoveryKeyBagCreateForAccount(CFAllocatorRef allocator, CFTypeRef account, CFDataRef pubData, CFErrorRef *error); +CFDataRef SOSRecoveryKeyCopyKeyForAccount(CFAllocatorRef allocator, CFTypeRef account, SOSRecoveryKeyBagRef recoveryKeyBag, CFErrorRef *error); CFDataRef SOSRecoveryKeyBagCopyEncoded(SOSRecoveryKeyBagRef RecoveryKeyBag, CFErrorRef* error); SOSRecoveryKeyBagRef SOSRecoveryKeyBagCreateFromData(CFAllocatorRef allocator, CFDataRef data, CFErrorRef *error); @@ -53,5 +52,4 @@ const uint8_t* der_decode_RecoveryKeyBag(CFAllocatorRef allocator, size_t der_sizeof_RecoveryKeyBag(SOSRecoveryKeyBagRef RecoveryKeyBag, CFErrorRef *error); uint8_t* der_encode_RecoveryKeyBag(SOSRecoveryKeyBagRef RecoveryKeyBag, CFErrorRef *error, const uint8_t *der, uint8_t *der_end); - #endif /* SOSRecoveryKeyBag_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.m similarity index 86% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.m index 8d07b18c..6883a312 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSRecoveryKeyBag.m @@ -30,7 +30,7 @@ #include "AssertMacros.h" #include #include - +#include #include #include #include @@ -52,7 +52,6 @@ // MARK: Type creation // - struct __OpaqueSOSRecoveryKeyBag { CFRuntimeBase _base; CFStringRef accountDSID; @@ -115,16 +114,35 @@ fail: return result; } +static bool SOSRecoveryKeyBagIsComplete(SOSRecoveryKeyBagRef RecoveryKeyBag, CFErrorRef *error) { + if(!RecoveryKeyBag) { + SOSCreateError(kSOSErrorEncodeFailure, CFSTR("NULL RecoveryKeyBag"), NULL, error); + return false; + } + bool retval = true; + if(!RecoveryKeyBag->recoveryKeyBag) { + SOSCreateError(kSOSErrorEncodeFailure, CFSTR("RecoveryKeyBag has no public key"), NULL, error); + retval = false; + } + if(!RecoveryKeyBag->accountDSID) { + SOSCreateError(kSOSErrorEncodeFailure, CFSTR("RecoveryKeyBag has no DSID"), NULL, error); + retval = false; + } + if(!RecoveryKeyBag->generation) { + SOSCreateError(kSOSErrorEncodeFailure, CFSTR("RecoveryKeyBag has no generation"), NULL, error); + retval = false; + } + return retval; +} + size_t der_sizeof_RecoveryKeyBag(SOSRecoveryKeyBagRef RecoveryKeyBag, CFErrorRef *error) { size_t result = 0; - if(RecoveryKeyBag && RecoveryKeyBag->recoveryKeyBag && RecoveryKeyBag->accountDSID && RecoveryKeyBag->generation) { + if(SOSRecoveryKeyBagIsComplete(RecoveryKeyBag, error)) { size_t partSize = der_sizeof_string(RecoveryKeyBag->accountDSID, NULL); partSize += SOSGenCountGetDEREncodedSize(RecoveryKeyBag->generation, NULL); partSize += ccder_sizeof_uint64(RecoveryKeyBag->rkbVersion); partSize += der_sizeof_data(RecoveryKeyBag->recoveryKeyBag, NULL); result = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, partSize); - } else { - SOSCreateError(kSOSErrorEncodeFailure, CFSTR("Null RecoveryKeyBag"), NULL, error); } return result; } @@ -133,7 +151,7 @@ uint8_t* der_encode_RecoveryKeyBag(SOSRecoveryKeyBagRef RecoveryKeyBag, CFErrorR const uint8_t *der, uint8_t *der_end) { uint8_t *result = NULL; if (der_end == NULL) return der_end; - if(RecoveryKeyBag && RecoveryKeyBag->recoveryKeyBag && RecoveryKeyBag->accountDSID && RecoveryKeyBag->generation) { + if(SOSRecoveryKeyBagIsComplete(RecoveryKeyBag, error)) { der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der, der_encode_string(RecoveryKeyBag->accountDSID, error, der, SOSGenCountEncodeToDER(RecoveryKeyBag->generation, error, der, @@ -142,19 +160,17 @@ uint8_t* der_encode_RecoveryKeyBag(SOSRecoveryKeyBagRef RecoveryKeyBag, CFErrorR require_quiet(der_end == der, errOut); result = der_end; - } else { - SOSCreateError(kSOSErrorEncodeFailure, CFSTR("Null RecoveryKeyBag"), NULL, error); } - errOut: return result; } -SOSRecoveryKeyBagRef SOSRecoveryKeyBagCreateForAccount(CFAllocatorRef allocator, SOSAccountRef account, CFDataRef pubData, CFErrorRef *error) { +SOSRecoveryKeyBagRef SOSRecoveryKeyBagCreateForAccount(CFAllocatorRef allocator, CFTypeRef account, CFDataRef pubData, CFErrorRef *error) { SOSRecoveryKeyBagRef retval = NULL; SOSGenCountRef gencount = NULL; require_action_quiet(account, errOut, SOSCreateError(kSOSErrorEncodeFailure, CFSTR("Null Account Object"), NULL, error)); - CFStringRef dsid = asString(SOSAccountGetValue(account, kSOSDSIDKey, NULL), error); + CFStringRef dsid = NULL; + dsid = asString(SOSAccountGetValue((__bridge SOSAccount*)account, kSOSDSIDKey, NULL), error); gencount = SOSGenerationCreate(); require_action_quiet(pubData && dsid && gencount, errOut, SOSCreateError(kSOSErrorEncodeFailure, CFSTR("Couldn't get recovery keybag components"), NULL, error)); @@ -169,11 +185,13 @@ errOut: return retval; } -CFDataRef SOSRecoveryKeyCopyKeyForAccount(CFAllocatorRef allocator, SOSAccountRef account, SOSRecoveryKeyBagRef recoveryKeyBag, CFErrorRef *error) { +CFDataRef SOSRecoveryKeyCopyKeyForAccount(CFAllocatorRef allocator, CFTypeRef account, SOSRecoveryKeyBagRef recoveryKeyBag, CFErrorRef *error) { CFDataRef retval = NULL; require_action_quiet(recoveryKeyBag && recoveryKeyBag->recoveryKeyBag && recoveryKeyBag->accountDSID, errOut, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("Null recoveryKeyBag Object"), NULL, error)); - CFStringRef dsid = asString(SOSAccountGetValue(account, kSOSDSIDKey, NULL), error); + CFStringRef dsid = NULL; + dsid = asString(SOSAccountGetValue((__bridge SOSAccount *)(account), kSOSDSIDKey, NULL), error); + require_action_quiet(dsid, errOut, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("No DSID in Account"), NULL, error)); require_action_quiet(CFEqual(dsid, recoveryKeyBag->accountDSID), errOut, SOSCreateError(kSOSErrorDecodeFailure, CFSTR("Account/RecoveryKeybag DSID miss-match"), NULL, error)); retval = CFDataCreateCopy(allocator, recoveryKeyBag->recoveryKeyBag); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingBackup.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingBackup.m similarity index 100% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSRingBackup.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSRingBackup.m diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingBasic.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingBasic.m similarity index 100% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSRingBasic.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSRingBasic.m diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingRecovery.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingRecovery.m similarity index 99% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSRingRecovery.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSRingRecovery.m index 4faf03d6..01241476 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingRecovery.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingRecovery.m @@ -118,5 +118,3 @@ SOSRecoveryKeyBagRef SOSRingCopyRecoveryKeyBag(SOSRingRef ring, CFErrorRef *erro errOut: return result; } - - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.h index cb9e46d3..8149b23f 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.h @@ -55,23 +55,6 @@ typedef struct ringfuncs_t { CFDataRef (*sosRingGetPayload)(SOSRingRef ring, CFErrorRef *error); } ringFuncStruct, *ringFuncs; -// ViewRequirements -bool SOSRingRequirementKnown(SOSAccountRef account, CFStringRef name, CFErrorRef *error); -bool SOSRingRequirementCreate(SOSAccountRef account, CFStringRef name, SOSRingType type, CFErrorRef *error); - -// Admins -bool SOSRingRequirementResetToOffering(SOSAccountRef account, CFStringRef name, CFErrorRef* error); -bool SOSRingRequirementResetToEmpty(SOSAccountRef account, CFStringRef name, CFErrorRef* error); - -// Clients -bool SOSRingRequirementRequestToJoin(SOSAccountRef account, CFStringRef name, CFErrorRef* error); -bool SOSRingRequirementRemoveThisDevice(SOSAccountRef account, CFStringRef name, CFErrorRef* error); - -// Approvers -CFArrayRef SOSRingRequirementGetApplicants(SOSAccountRef account, CFStringRef name, CFErrorRef* error); -bool SOSRingRequirementAcceptApplicants(SOSAccountRef account, CFStringRef name, CFArrayRef applicants, CFErrorRef* error); -bool SOSRingRequirementRejectApplicants(SOSAccountRef account, CFStringRef name, CFArrayRef applicants, CFErrorRef *error); - static inline SOSRingRef SOSRingCreate_ForType(CFStringRef name, SOSRingType type, CFStringRef myPeerID, CFErrorRef *error) { SOSRingRef retval = NULL; retval = SOSRingCreate_Internal(name, type, error); diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.m similarity index 62% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.m index 845ea54b..2259dd5a 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingTypes.m @@ -31,7 +31,9 @@ #include "SOSRingBackup.h" #include "SOSRingRecovery.h" #include +#include #include +#include // These need to track the ring type enums in SOSRingTypes.h static ringFuncs ringTypes[] = { @@ -53,101 +55,112 @@ static bool SOSRingValidType(SOSRingType type) { SOSRingRef SOSRingCreate(CFStringRef name, CFStringRef myPeerID, SOSRingType type, CFErrorRef *error) { - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingCreate, errOut); + if(!SOSRingValidType(type)){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return NULL; + } + if(!(ringTypes[type]->sosRingCreate)){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return NULL; + } return ringTypes[type]->sosRingCreate(name, myPeerID, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return NULL; } bool SOSRingResetToEmpty(SOSRingRef ring, CFStringRef myPeerID, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingResetToEmpty, errOut); + if(!SOSRingValidType(type)){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!ringTypes[type]->sosRingResetToEmpty){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } return ringTypes[type]->sosRingResetToEmpty(ring, myPeerID, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; } bool SOSRingResetToOffering(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingResetToOffering, errOut); + if(!SOSRingValidType(type)){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!ringTypes[type]->sosRingResetToOffering){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } return ringTypes[type]->sosRingResetToOffering(ring, user_privkey, requestor, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; } SOSRingStatus SOSRingDeviceIsInRing(SOSRingRef ring, CFStringRef peerID) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingDeviceIsInRing, errOut); + if(!(SOSRingValidType(type))){ + return kSOSRingError; + } + if(!(ringTypes[type]->sosRingDeviceIsInRing)){ + return kSOSRingError; + } return ringTypes[type]->sosRingDeviceIsInRing(ring, peerID); -errOut: - return kSOSRingError; } bool SOSRingApply(SOSRingRef ring, SecKeyRef user_pubkey, SOSFullPeerInfoRef fpi, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingApply, shortCircuit); - require_quiet(SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(fpi), user_pubkey, error), errOut2); + if(!(SOSRingValidType(type))){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!(ringTypes[type]->sosRingApply)){ + return true; + } + if(!(SOSPeerInfoApplicationVerify(SOSFullPeerInfoGetPeerInfo(fpi), user_pubkey, error))){ + SOSCreateError(kSOSErrorBadSignature, CFSTR("FullPeerInfo fails userkey signature check"), NULL, error); + return false; + } return ringTypes[type]->sosRingApply(ring, user_pubkey, fpi, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; -errOut2: - SOSCreateError(kSOSErrorBadSignature, CFSTR("FullPeerInfo fails userkey signature check"), NULL, error); - return false; -shortCircuit: - return true; } bool SOSRingWithdraw(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingWithdraw, shortCircuit); + if(!SOSRingValidType(type)){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!ringTypes[type]->sosRingWithdraw) + return true; + return ringTypes[type]->sosRingWithdraw(ring, user_privkey, requestor, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; -shortCircuit: - return true; } bool SOSRingGenerationSign(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingGenerationSign, shortCircuit); + if(!(SOSRingValidType(type))){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!(ringTypes[type]->sosRingGenerationSign)){ + return true; + } return ringTypes[type]->sosRingGenerationSign(ring, user_privkey, requestor, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; -shortCircuit: - return true; } bool SOSRingConcordanceSign(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingConcordanceSign, shortCircuit); + if(!(SOSRingValidType(type))){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!(ringTypes[type]->sosRingConcordanceSign)){ + return true; + } return ringTypes[type]->sosRingConcordanceSign(ring, requestor, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; -shortCircuit: - return true; } SOSConcordanceStatus SOSRingConcordanceTrust(SOSFullPeerInfoRef me, CFSetRef peers, @@ -158,97 +171,111 @@ SOSConcordanceStatus SOSRingConcordanceTrust(SOSFullPeerInfoRef me, CFSetRef pee SOSRingAssertStable(proposedRing); SOSRingType type1 = SOSRingGetType(knownRing); SOSRingType type2 = SOSRingGetType(proposedRing); - require(SOSRingValidType(type1), errOut); - require(SOSRingValidType(type2), errOut); - require(type1 == type2, errOut); + if(!(SOSRingValidType(type1))){ + return kSOSConcordanceError; + } + if(!(SOSRingValidType(type2))){ + return kSOSConcordanceError; + } + if((type1 != type2)){ + return kSOSConcordanceError; + } secnotice("ring", "concordance trust (%s) knownRing: %@ proposedRing: %@ knownkey: %@ userkey: %@ excluded: %@", ringTypes[type1]->typeName, knownRing, proposedRing, knownPubkey, userPubkey, excludePeerID); - require(ringTypes[type1]->sosRingConcordanceTrust, errOut); + if(!(ringTypes[type1]->sosRingConcordanceTrust)){ + return kSOSConcordanceError; + } return ringTypes[type1]->sosRingConcordanceTrust(me, peers, knownRing, proposedRing, knownPubkey, userPubkey, excludePeerID, error); -errOut: - return kSOSConcordanceError; } bool SOSRingAccept(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingAccept, shortCircuit); + if(!(SOSRingValidType(type))){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!(ringTypes[type]->sosRingAccept)){ + return true; + } return ringTypes[type]->sosRingAccept(ring, user_privkey, requestor, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; -shortCircuit: - return true; } bool SOSRingReject(SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingReject, shortCircuit); + if(!(SOSRingValidType(type))){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!(ringTypes[type]->sosRingReject)){ + return true; + } return ringTypes[type]->sosRingReject(ring, user_privkey, requestor, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; -shortCircuit: - return true; } bool SOSRingSetPayload(SOSRingRef ring, SecKeyRef user_privkey, CFDataRef payload, SOSFullPeerInfoRef requestor, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingSetPayload, errOut); + if(!(SOSRingValidType(type))){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } + if(!(ringTypes[type]->sosRingSetPayload)){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + } return ringTypes[type]->sosRingSetPayload(ring, user_privkey, payload, requestor, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; } CFDataRef SOSRingGetPayload(SOSRingRef ring, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); - require(ringTypes[type]->sosRingGetPayload, errOut); + if(!SOSRingValidType(type)){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return NULL; + } + if(!ringTypes[type]->sosRingGetPayload){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return NULL; + }; return ringTypes[type]->sosRingGetPayload(ring, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return NULL; } CFSetRef SOSRingGetBackupViewset(SOSRingRef ring, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(kSOSRingBackup == type, errOut); + if(kSOSRingBackup != type){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not backup ring type"), NULL, error); + return NULL; + } return SOSRingGetBackupViewset_Internal(ring); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not backup ring type"), NULL, error); - return NULL; } static bool isBackupRing(SOSRingRef ring, CFErrorRef *error) { SOSRingType type = SOSRingGetType(ring); - require_quiet(kSOSRingBackup == type, errOut); + if(kSOSRingBackup != type){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not backup ring type"), NULL, error); + return false; + } return true; -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not backup ring type"), NULL, error); - return false; } bool SOSRingSetBackupKeyBag(SOSRingRef ring, SOSFullPeerInfoRef fpi, CFSetRef viewSet, SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) { SOSRingAssertStable(ring); CFDataRef bskb_as_data = NULL; bool result = false; - require_quiet(isBackupRing(ring, error), errOut); + if(!isBackupRing(ring, error)){ + CFReleaseNull(bskb_as_data); + return result; + } bskb_as_data = SOSBSKBCopyEncoded(bskb, error); result = bskb_as_data && SOSRingSetBackupViewset_Internal(ring, viewSet) && SOSRingSetPayload(ring, NULL, bskb_as_data, fpi, error); -errOut: CFReleaseNull(bskb_as_data); return result; } @@ -258,26 +285,26 @@ SOSBackupSliceKeyBagRef SOSRingCopyBackupSliceKeyBag(SOSRingRef ring, CFErrorRef CFDataRef bskb_as_data = NULL; SOSBackupSliceKeyBagRef result = NULL; - require_quiet(isBackupRing(ring, error), errOut); + if(!isBackupRing(ring, error)){ + return result; + } bskb_as_data = SOSRingGetPayload(ring, error); - require_quiet(bskb_as_data, errOut); - + if(!bskb_as_data){ + return result; + } result = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, bskb_as_data, error); - -errOut: return result; } - bool SOSRingPKTrusted(SOSRingRef ring, SecKeyRef pubkey, CFErrorRef *error) { SOSRingAssertStable(ring); SOSRingType type = SOSRingGetType(ring); - require(SOSRingValidType(type), errOut); + if(!(SOSRingValidType(type))){ + SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); + return false; + }; return SOSRingVerify(ring, pubkey, error); -errOut: - SOSCreateError(kSOSErrorUnexpectedType, CFSTR("Not valid ring type"), NULL, error); - return false; } bool SOSRingPeerTrusted(SOSRingRef ring, SOSFullPeerInfoRef requestor, CFErrorRef *error) { diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSRingV0.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSRingV0.m similarity index 100% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSRingV0.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSRingV0.m diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSSysdiagnose.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSSysdiagnose.m similarity index 100% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSSysdiagnose.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSSysdiagnose.m diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.h index cbdeb5dc..2d03c55f 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.h @@ -7,22 +7,22 @@ #include #include -CF_RETURNS_RETAINED CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFDictionaryRef updates, CFErrorRef *error); +CF_RETURNS_RETAINED CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransaction* txn, CFDictionaryRef updates, CFErrorRef *error); -void SOSRegisterTransportMessage(SOSTransportMessageRef additional); -void SOSUnregisterTransportMessage(SOSTransportMessageRef removal); +void SOSRegisterTransportMessage(SOSMessage* additional); +void SOSUnregisterTransportMessage(SOSMessage* removal); -void SOSRegisterTransportCircle(SOSTransportCircleRef additional); -void SOSUnregisterTransportCircle(SOSTransportCircleRef removal); +void SOSRegisterTransportCircle(SOSCircleStorageTransport* additional); +void SOSUnregisterTransportCircle(SOSCircleStorageTransport* removal); -void SOSRegisterTransportKeyParameter(SOSTransportKeyParameterRef additional); -void SOSUnregisterTransportKeyParameter(SOSTransportKeyParameterRef removal); +void SOSRegisterTransportKeyParameter(CKKeyParameter* additional); +void SOSUnregisterTransportKeyParameter(CKKeyParameter* removal); void SOSUnregisterAllTransportMessages(void); void SOSUnregisterAllTransportCircles(void); void SOSUnregisterAllTransportKeyParameters(void); -void SOSUpdateKeyInterest(SOSAccountRef account); +void SOSUpdateKeyInterest(SOSAccount* account); enum TransportType{ kUnknown = 0, @@ -30,7 +30,21 @@ enum TransportType{ kIDS = 2, kBackupPeer = 3, kIDSTest = 4, - kKVSTest = 5 + kKVSTest = 5, + kCK = 6 }; +static inline CFMutableDictionaryRef CFDictionaryEnsureCFDictionaryAndGetCurrentValue(CFMutableDictionaryRef dict, CFTypeRef key) +{ + CFMutableDictionaryRef result = (CFMutableDictionaryRef) CFDictionaryGetValue(dict, key); + + if (!isDictionary(result)) { + result = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionarySetValue(dict, key, result); + CFReleaseSafe(result); + } + + return result; +} + #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.m similarity index 73% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.m index 4783d877..127bd0a1 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.m @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -60,36 +60,39 @@ CFGiblisGetSingleton(CFMutableArrayRef, SOSGetTransportCircles, sTransportCircle }); -void SOSRegisterTransportMessage(SOSTransportMessageRef additional) { - CFArrayAppendValue(SOSGetTransportMessages(), additional); +void SOSRegisterTransportMessage(SOSMessage* additional) { + if(additional != nil) + CFArrayAppendValue(SOSGetTransportMessages(), (__bridge CFTypeRef)(additional)); } -void SOSUnregisterTransportMessage(SOSTransportMessageRef removal) { - CFArrayRemoveAllValue(SOSGetTransportMessages(), removal); +void SOSUnregisterTransportMessage(SOSMessage* removal) { + CFArrayRemoveAllValue(SOSGetTransportMessages(), (__bridge CFTypeRef)(removal)); } void SOSUnregisterAllTransportMessages() { CFArrayRemoveAllValues(SOSGetTransportMessages()); } -void SOSRegisterTransportCircle(SOSTransportCircleRef additional) { - CFArrayAppendValue(SOSGetTransportCircles(), additional); +void SOSRegisterTransportCircle(SOSCircleStorageTransport* additional) { + if(additional != nil) + CFArrayAppendValue(SOSGetTransportCircles(), (__bridge CFTypeRef)(additional)); } -void SOSUnregisterTransportCircle(SOSTransportCircleRef removal) { - CFArrayRemoveAllValue(SOSGetTransportCircles(), removal); +void SOSUnregisterTransportCircle(SOSCircleStorageTransport* removal) { + CFArrayRemoveAllValue(SOSGetTransportCircles(), (__bridge CFTypeRef)removal); } void SOSUnregisterAllTransportCircles() { CFArrayRemoveAllValues(SOSGetTransportCircles()); } -void SOSRegisterTransportKeyParameter(SOSTransportKeyParameterRef additional) { - CFArrayAppendValue(SOSGetTransportKeyParameters(), additional); +void SOSRegisterTransportKeyParameter(CKKeyParameter* additional) { + if(additional != nil) + CFArrayAppendValue(SOSGetTransportKeyParameters(), (__bridge CFTypeRef)(additional)); } -void SOSUnregisterTransportKeyParameter(SOSTransportKeyParameterRef removal) { - CFArrayRemoveAllValue(SOSGetTransportKeyParameters(), removal); +void SOSUnregisterTransportKeyParameter(CKKeyParameter* removal) { + CFArrayRemoveAllValue(SOSGetTransportKeyParameters(), (__bridge CFTypeRef)(removal)); } void SOSUnregisterAllTransportKeyParameters() { @@ -99,25 +102,29 @@ void SOSUnregisterAllTransportKeyParameters() { // // Should we be dispatching back to our queue to handle later // -void SOSUpdateKeyInterest(SOSAccountRef account) +void SOSUpdateKeyInterest(SOSAccount* account) { CFMutableArrayRef alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFMutableArrayRef afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFMutableArrayRef whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFMutableDictionaryRef keyDict = CFDictionaryCreateMutableForCFTypes (kCFAllocatorDefault); - - CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) { - SOSTransportKeyParameterRef tKP = (SOSTransportKeyParameterRef) value; - if (SOSTransportKeyParameterGetAccount(tKP) == account && SOSTransportKeyParameterGetTransportType(tKP, NULL) == kKVS) { - SOSTransportKeyParameterKVSRef tkvs = (SOSTransportKeyParameterKVSRef) value; + + NSMutableArray *temp = (__bridge NSMutableArray *)(SOSGetTransportKeyParameters()); + + [temp enumerateObjectsUsingBlock:^(CKKeyParameter *value, NSUInteger idx, BOOL * _Nonnull stop) { + CKKeyParameter* tKP = (CKKeyParameter*) value; + if ([tKP SOSTransportKeyParameterGetAccount:tKP] == account && [tKP SOSTransportKeyParameterGetTransportType:tKP err:NULL] == kKVS) { + CKKeyParameter* tkvs = (CKKeyParameter*) value; CFErrorRef localError = NULL; - - if (!SOSTransportKeyParameterKVSAppendKeyInterests(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)) { + + if (![tkvs SOSTransportKeyParameterKVSAppendKeyInterests:tkvs ak:alwaysKeys firstUnLock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]) { secerror("Error getting key parameters interests %@", localError); } CFReleaseNull(localError); } - }); + + }]; + CFMutableDictionaryRef keyParamsDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFDictionarySetValue(keyParamsDict, kAlwaysKeys, alwaysKeys); CFDictionarySetValue(keyParamsDict, kFirstUnlocked, afterFirstUnlockKeys); @@ -132,22 +139,24 @@ void SOSUpdateKeyInterest(SOSAccountRef account) whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) { - if (SOSTransportCircleGetAccount((SOSTransportCircleRef)value) == account && SOSTransportCircleGetTransportType((SOSTransportCircleRef)value, NULL) == kKVS) { - SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef) value; + SOSKVSCircleStorageTransport *transport = (__bridge SOSKVSCircleStorageTransport*)value; + if ( [[transport getAccount] isEqual: account] ) { + SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value; CFErrorRef localError = NULL; - if(!SOSTransportCircleKVSAppendKeyInterest(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)){ + if(! [tkvs kvsAppendKeyInterest:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]){ secerror("Error getting circle interests %@", localError); } - if(!SOSTransportCircleKVSAppendPeerInfoKeyInterest(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)){ - secerror("Error getting peer info interests %@", localError); - } - if(!SOSTransportCircleKVSAppendRingKeyInterest(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)){ + if(![tkvs kvsAppendRingKeyInterest:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]){ secerror("Error getting ring interests %@", localError); } - if(!SOSTransportCircleKVSAppendDebugKeyInterest(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)){ + if(![tkvs kvsAppendDebugKeyInterest:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]) { secerror("Error getting debug key interests %@", localError); } + + if(![tkvs kvsAppendConfigKeyInterest:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]) { + secerror("Error getting config key interests %@", localError); + } CFReleaseNull(localError); } @@ -166,11 +175,11 @@ void SOSUpdateKeyInterest(SOSAccountRef account) whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) { - if (SOSTransportMessageGetAccount((SOSTransportMessageRef) value) == account && SOSTransportMessageGetTransportType((SOSTransportMessageRef) value, NULL) == kKVS) { - SOSTransportMessageKVSRef tkvs = (SOSTransportMessageKVSRef) value; + SOSMessage* transport = (__bridge SOSMessage*)value; + if ([transport SOSTransportMessageGetAccount] == account && [transport SOSTransportMessageGetTransportType] == kKVS) { CFErrorRef localError = NULL; - - if(!SOSTransportMessageKVSAppendKeyInterest(tkvs, alwaysKeys, afterFirstUnlockKeys, whenUnlockedKeys, &localError)){ + SOSMessageKVS* tks = (__bridge SOSMessageKVS*)value; + if(![tks SOSTransportMessageKVSAppendKeyInterest:tks ak:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]){ secerror("Error getting message interests %@", localError); } CFReleaseNull(localError); @@ -186,7 +195,18 @@ void SOSUpdateKeyInterest(SOSAccountRef account) // // Log what we are about to do. // - secnotice("key-interests", "Updating interests: %@", keyDict); + NSUInteger itemCount = 0; + for (NSString *subsystem in @[(__bridge id)kMessage, (__bridge id)kCircle, (__bridge id)kKeyParameter]) { + secnotice("key-interests", "Updating interests: %@", subsystem); + for (NSString *lockState in @[(__bridge id)kAlwaysKeys, (__bridge id)kFirstUnlocked, (__bridge id)kUnlocked]) { + NSArray *items = ((__bridge NSDictionary *)keyDict)[subsystem][lockState]; + itemCount += items.count; + for (NSString *item in items) { + secnotice("key-interests", " key-intrest: %@->%@: %@", subsystem, lockState, item); + } + } + } + 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) { @@ -231,38 +251,37 @@ static void showWhatWasHandled(CFDictionaryRef updates, CFMutableArrayRef handle #define KVS_STATE_INTERVAL 50 CF_RETURNS_RETAINED -CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFDictionaryRef updates, CFErrorRef *error){ - SOSAccountRef account = txn->account; +CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransaction* txn, CFDictionaryRef updates, CFErrorRef *error){ + __block SOSAccount* account = txn.account; CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFStringRef dsid = NULL; if(CFDictionaryGetValueIfPresent(updates, kSOSKVSAccountChangedKey, (const void**)&dsid)){ secnotice("accountChange", "SOSTransportDispatchMessages received kSOSKVSAccountChangedKey"); - // While changing accounts we may modify the key params array. To avoid stepping on ourselves we // copy the list for iteration. Now modifying the transport outside of the list iteration. CFMutableArrayRef transportsToUse = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) { - SOSTransportKeyParameterRef transport = (SOSTransportKeyParameterRef) value; - if(CFEqualSafe(SOSTransportKeyParameterGetAccount(transport), account)){ - CFArrayAppendValue(transportsToUse, transport); - } + CKKeyParameter* transport = (__bridge CKKeyParameter*) value; + if(CFEqualSafe((__bridge CFTypeRef)([transport SOSTransportKeyParameterGetAccount:transport]), (__bridge CFTypeRef)(account))){ + CFArrayAppendValue(transportsToUse, (__bridge const void *)(transport)); + } }); CFArrayForEach(transportsToUse, ^(const void *value) { - SOSTransportKeyParameterRef tempTransport = (SOSTransportKeyParameterRef) value; + CKKeyParameter* tempTransport = (__bridge CKKeyParameter*) value; CFStringRef accountDSID = (CFStringRef)SOSAccountGetValue(account, kSOSDSIDKey, error); if(accountDSID == NULL){ - SOSTransportKeyParameterHandleNewAccount(tempTransport, account); + [tempTransport SOSTransportKeyParameterHandleNewAccount:tempTransport acct:account]; SOSAccountSetValue(account, kSOSDSIDKey, dsid, error); secdebug("dsid", "Assigning new DSID: %@", dsid); } else if(accountDSID != NULL && CFStringCompare(accountDSID, dsid, 0) != 0 ) { - SOSTransportKeyParameterHandleNewAccount(tempTransport, account); + [tempTransport SOSTransportKeyParameterHandleNewAccount:tempTransport acct:account]; SOSAccountSetValue(account, kSOSDSIDKey, dsid, error); secdebug("dsid", "Assigning new DSID: %@", dsid); } else { @@ -283,8 +302,8 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD CFMutableDictionaryRef circle_circle_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFMutableDictionaryRef circle_retirement_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFMutableDictionaryRef ring_update_message_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFMutableDictionaryRef peer_info_message_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFMutableDictionaryRef debug_info_message_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + __block CFMutableDictionaryRef config_message_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); __block CFDataRef newParameters = NULL; __block bool initial_sync = false; @@ -325,9 +344,6 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD case kAccountChangedKey: new_account = true; break; - case kPeerInfoKey: - CFDictionarySetValue(peer_info_message_table, peer_info_name, value); - break; case kRingKey: if(isString(ring_name)) CFDictionarySetValue(ring_update_message_table, ring_name, value); @@ -335,12 +351,16 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD case kDebugInfoKey: CFDictionarySetValue(debug_info_message_table, peer_info_name, value); break; + case kOTRConfig: + if(isDictionary(value)){ + config_message_table = CFRetainSafe((CFMutableDictionaryRef)(value)); + } + break; case kLastCircleKey: case kLastKeyParameterKey: case kUnknownKey: secnotice("updates", "Unknown key '%@', ignoring", key); break; - } errOut: @@ -362,10 +382,10 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD if (newParameters) { CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) { - SOSTransportKeyParameterRef tkvs = (SOSTransportKeyParameterRef) value; + CKKeyParameter* tkvs = (__bridge CKKeyParameter*) value; CFErrorRef localError = NULL; - if(CFEqualSafe(SOSTransportKeyParameterGetAccount(tkvs), account)){ - if(!SOSTransportKeyParameterHandleKeyParameterChanges(tkvs, newParameters, localError)) + if([[tkvs SOSTransportKeyParameterGetAccount:tkvs] isEqual:account]){ + if(![tkvs SOSTransportKeyParameterHandleKeyParameterChanges:tkvs data:newParameters err:localError]) secerror("Transport failed to handle new key parameters: %@", localError); } }); @@ -377,6 +397,11 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD CFArrayAppendValue(handledKeys, kSOSKVSInitialSyncKey); } + if(CFDictionaryGetCount(config_message_table)){ + secnotice("otrtimer","got the config table: %@", config_message_table); + CFArrayAppendValue(handledKeys, kOTRConfigVersion); + } + if(CFDictionaryGetCount(debug_info_message_table)) { /* check for a newly set circle debug scope */ CFTypeRef debugScope = CFDictionaryGetValue(debug_info_message_table, kSOSAccountDebugScope); @@ -394,10 +419,10 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD if(CFDictionaryGetCount(circle_retirement_messages_table)) { CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) { - SOSTransportCircleRef tkvs = (SOSTransportCircleRef) value; - if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef)value), account)){ + SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value; + if([[tkvs getAccount] isEqual:account]){ CFErrorRef localError = NULL; - CFDictionaryRef handledRetirementKeys = SOSTransportCircleHandleRetirementMessages(tkvs, circle_retirement_messages_table, error); + CFDictionaryRef handledRetirementKeys = [tkvs handleRetirementMessages:circle_retirement_messages_table err:error]; if(handledRetirementKeys == NULL){ secerror("Transport failed to handle retirement messages: %@", localError); } else { @@ -417,47 +442,34 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD } }); } - if(CFDictionaryGetCount(peer_info_message_table)){ - CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) { - SOSTransportCircleRef tkvs = (SOSTransportCircleRef) value; - if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef)value), account)){ - CFErrorRef localError = NULL; - CFArrayRef handledPeerInfoMessages = SOSTransportCircleKVSHandlePeerInfoV2Messages(tkvs, peer_info_message_table, error); - if(handledPeerInfoMessages == NULL){ - secerror("Transport failed to handle peer info messages: %@", localError); - } else { - CFArrayForEach(handledPeerInfoMessages, ^(const void *value) { - CFStringRef peer_id = (CFStringRef)value; - CFStringRef keyHandled = SOSPeerInfoV2KeyCreateWithPeerName(peer_id); - CFArrayAppendValue(handledKeys, keyHandled); - CFReleaseNull(keyHandled); - }); - } - CFReleaseNull(handledPeerInfoMessages); - CFReleaseNull(localError); - } - }); - } if(CFDictionaryGetCount(circle_peer_messages_table)) { CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) { - SOSTransportMessageRef tmsg = (SOSTransportMessageRef) value; + SOSMessage* tmsg = (__bridge SOSMessage*) value; CFDictionaryRef circleToPeersHandled = NULL; CFErrorRef handleMessagesError = NULL; CFErrorRef flushError = NULL; - require_quiet(CFEqualSafe(SOSTransportMessageGetAccount(tmsg), account), done); - - circleToPeersHandled = SOSTransportMessageHandleMessages(tmsg, circle_peer_messages_table, &handleMessagesError); - require_action_quiet(circleToPeersHandled, done, secnotice("msg", "No messages handled: %@", handleMessagesError)); - - CFArrayRef handledPeers = asArray(CFDictionaryGetValue(circleToPeersHandled, SOSTransportMessageGetCircleName(tmsg)), NULL); + if(!([([tmsg SOSTransportMessageGetAccount]) isEqual:account])){ + CFReleaseNull(flushError); + CFReleaseNull(circleToPeersHandled); + CFReleaseNull(handleMessagesError); + return; + } + circleToPeersHandled = [tmsg SOSTransportMessageHandlePeerMessageReturnsHandledCopy:tmsg peerMessages:circle_peer_messages_table err:&handleMessagesError]; + if(!circleToPeersHandled){ + secnotice("msg", "No messages handled: %@", handleMessagesError); + CFReleaseNull(flushError); + CFReleaseNull(circleToPeersHandled); + CFReleaseNull(handleMessagesError); + return; + } + CFArrayRef handledPeers = asArray(CFDictionaryGetValue(circleToPeersHandled, [tmsg SOSTransportMessageGetCircleName]), NULL); if (handledPeers) { CFArrayForEach(handledPeers, ^(const void *value) { CFStringRef peerID = asString(value, NULL); if (peerID) { - - CFStringRef kvsHandledKey = SOSMessageKeyCreateFromPeerToTransport(tmsg, peerID); + CFStringRef kvsHandledKey = SOSMessageKeyCreateFromPeerToTransport(tmsg, (__bridge CFStringRef) account.peerID, peerID); if (kvsHandledKey) { CFArrayAppendValue(handledKeys, kvsHandledKey); } @@ -466,9 +478,9 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD }); } - require_action_quiet(SOSTransportMessageFlushChanges(tmsg, &flushError), done, secnotice("msg", "Flush failed: %@", flushError);); + if(![tmsg SOSTransportMessageFlushChanges:tmsg err:&flushError]) + secnotice("msg", "Flush failed: %@", flushError); - done: CFReleaseNull(flushError); CFReleaseNull(circleToPeersHandled); CFReleaseNull(handleMessagesError); @@ -476,9 +488,9 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD } if(CFDictionaryGetCount(circle_circle_messages_table)) { CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) { - SOSTransportCircleRef tkvs = (SOSTransportCircleRef) value; - if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef)value), account)){ - CFArrayRef handleCircleMessages = SOSTransportCircleHandleCircleMessages(tkvs, circle_circle_messages_table, error); + SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value; + if([[tkvs getAccount] isEqual: account]){ + CFArrayRef handleCircleMessages = [tkvs handleCircleMessagesAndReturnHandledCopy:circle_circle_messages_table err:error]; CFErrorRef localError = NULL; if(handleCircleMessages == NULL){ secerror("Transport failed to handle circle messages: %@", localError); @@ -499,14 +511,14 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD } CFReleaseNull(localError); - CFReleaseNull(handleCircleMessages); } }); } if(CFDictionaryGetCount(ring_update_message_table)){ CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) { - if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef)value), account)){ + SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value; + if([[tkvs getAccount] isEqual:account]){ CFErrorRef localError = NULL; CFMutableArrayRef handledRingMessages = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); @@ -540,9 +552,8 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransactionRef txn, CFD CFReleaseNull(circle_peer_messages_table); CFReleaseNull(debug_info_message_table); CFReleaseNull(ring_update_message_table); - CFReleaseNull(peer_info_message_table); CFReleaseNull(debug_info_message_table); - + CFReleaseNull(config_message_table); showWhatWasHandled(updates, handledKeys); return handledKeys; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportBackupPeer.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportBackupPeer.m similarity index 88% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSTransportBackupPeer.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSTransportBackupPeer.m index cb4ee13f..d4bf019d 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportBackupPeer.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportBackupPeer.m @@ -1,9 +1,5 @@ #include -#include #include -#include -#include - #include #include @@ -29,7 +25,7 @@ static void SOSTransportBackupPeerDestroy(CFTypeRef aObj){ } CFIndex SOSTransportBackupPeerGetTransportType(SOSTransportBackupPeerRef transport, CFErrorRef *error){ - return kBackupPeer; + return 3; } static CFHashCode SOSTransportBackupPeerHash(CFTypeRef obj){ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c deleted file mode 100644 index 8a90b1ac..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.c +++ /dev/null @@ -1,112 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -CFGiblisWithCompareFor(SOSTransportCircle); - -SOSTransportCircleRef SOSTransportCircleCreateForSubclass(size_t size, SOSAccountRef account, CFErrorRef *error) -{ - SOSTransportCircleRef tpt = CFTypeAllocateWithSpace(SOSTransportCircle, size, kCFAllocatorDefault); - tpt->account = CFRetainSafe(account); - return tpt; -} - -static CFStringRef SOSTransportCircleCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) { - SOSTransportCircleRef t = (SOSTransportCircleRef) aObj; - - return CFStringCreateWithFormat(NULL, NULL, CFSTR(""), t); -} - -static void SOSTransportCircleDestroy(CFTypeRef aObj) { - SOSTransportCircleRef transport = (SOSTransportCircleRef) aObj; - if(transport->destroy) - transport->destroy(transport); - CFReleaseNull(transport->account); -} - -static CFHashCode SOSTransportCircleHash(CFTypeRef obj) -{ - return (intptr_t) obj; -} - -static Boolean SOSTransportCircleCompare(CFTypeRef lhs, CFTypeRef rhs) -{ - return SOSTransportCircleHash(lhs) == SOSTransportCircleHash(rhs); -} - -SOSAccountRef SOSTransportCircleGetAccount(SOSTransportCircleRef transport){ - return transport->account; -} - -bool SOSTransportCircleFlushChanges(SOSTransportCircleRef transport, CFErrorRef *error) { - return transport->flushChanges(transport, error); -} - -bool SOSTransportCirclePostCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error) { - return transport->postCircle(transport, circleName, circle_data, error); -} -CF_RETURNS_RETAINED -CFDictionaryRef SOSTransportCircleHandleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error) { - return transport->handleRetirementMessages(transport, circle_retirement_messages_table, error); -} - -CF_RETURNS_RETAINED -CFArrayRef SOSTransportCircleHandleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error) { - return transport->handleCircleMessages(transport, circle_circle_messages_table, error); -} - -bool SOSTransportCirclePostRetirement(SOSTransportCircleRef transport, CFStringRef circleName, SOSPeerInfoRef peer, CFErrorRef *error) { - bool success = false; - CFDataRef retirement_data = NULL; - - retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error); - - require_quiet(retirement_data, fail); - - success = transport->postRetirement(transport, circleName, SOSPeerInfoGetPeerID(peer), retirement_data, error); - -fail: - CFReleaseNull(retirement_data); - return success; -} - -bool SOSTransportCircleExpireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error){ - return transport->expireRetirementRecords(transport, retirements, error); -} - -CFIndex SOSTransportCircleGetTransportType(SOSTransportCircleRef transport, CFErrorRef *error){ - return transport->getTransportType ? transport->getTransportType(transport, error) : kUnknown; -} - -bool SOSTransportCircleSendPeerInfo(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error){ - return transport->sendPeerInfo(transport, peerID, peerInfoData, error); -} - -bool SOSTransportCircleRingFlushChanges(SOSTransportCircleRef transport, CFErrorRef* error){ - return transport->flushRingChanges(transport, error); -} - -bool SOSTransportCircleRingPostRing(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error){ - return transport->postRing(transport, ringName, ring, error); -} - -bool SOSTransportCircleSendDebugInfo(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error){ - return transport->sendDebugInfo(transport, type, debugInfo, error); -} - -bool SOSTransportCircleSendAccountChangedWithDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error){ - return transport->sendAccountChangedWithDSID(transport, dsid, error); -} - - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.h index f7ad3acb..efba0f77 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.h @@ -1,68 +1,32 @@ #ifndef SOSTransportCircle_h #define SOSTransportCircle_h +#import "Security/SecureObjectSync/SOSPeerInfo.h" -#include -#include -#include +@class SOSAccount; -typedef struct __OpaqueSOSTransportCircle * SOSTransportCircleRef; +@interface SOSCircleStorageTransport : NSObject +{ + SOSAccount* account; +} -struct __OpaqueSOSTransportCircle { - CFRuntimeBase _base; - SOSAccountRef account; - - CFStringRef (*copyDescription)(SOSTransportCircleRef transport); - void (*destroy)(SOSTransportCircleRef transport); - - bool (*postRetirement)(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error); - bool (*expireRetirementRecords)(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error); - bool (*flushChanges)(SOSTransportCircleRef transport, CFErrorRef *error); - bool (*postCircle)(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error); - CFIndex (*getTransportType)(SOSTransportCircleRef transport, CFErrorRef *error); - - CFDictionaryRef (*handleRetirementMessages)(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error); - CFArrayRef (*handleCircleMessages)(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error); - - bool (*sendPeerInfo)(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error); - bool (*flushRingChanges)(SOSTransportCircleRef transport, CFErrorRef* error); - bool (*postRing)(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error); - bool (*sendDebugInfo)(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error); - bool (*sendAccountChangedWithDSID)(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error); -}; +@property (retain, nonatomic) SOSAccount* account; -SOSTransportCircleRef SOSTransportCircleCreateForSubclass(size_t size, SOSAccountRef account, CFErrorRef *error); +-(id) init; +-(SOSCircleStorageTransport*) initWithAccount:(SOSAccount*)account; -bool SOSTransportCirclePostCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error); +-(CFIndex)circleGetTypeID; +-(CFIndex)getTransportType; +-(SOSAccount*)getAccount; -bool SOSTransportCirclePostRetirement(SOSTransportCircleRef transport, CFStringRef circleName, SOSPeerInfoRef peer, CFErrorRef *error); +-(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error; -bool SOSTransportCircleExpireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error); +-(bool) flushChanges:(CFErrorRef *)error; +-(bool) postCircle:(CFStringRef)circleName circleData:(CFDataRef)circle_data err:(CFErrorRef *)error; +-(bool) postRetirement:(CFStringRef) circleName peer:(SOSPeerInfoRef) peer err:(CFErrorRef *)error; -bool SOSTransportCircleFlushChanges(SOSTransportCircleRef transport, CFErrorRef *error); - -CFTypeID SOSTransportCircleGetTypeID(void); - -CFIndex SOSTransportCircleGetTransportType(SOSTransportCircleRef transport, CFErrorRef *error); - -SOSAccountRef SOSTransportCircleGetAccount(SOSTransportCircleRef transport); -CF_RETURNS_RETAINED CFDictionaryRef SOSTransportCircleHandleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error); - - -CF_RETURNS_RETAINED CFArrayRef SOSTransportCircleHandleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error); - -bool SOSTransportCircleSendPeerInfo(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error); - -bool SOSTransportCircleRingFlushChanges(SOSTransportCircleRef transport, CFErrorRef* error); - -bool SOSTransportCircleRingPostRing(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error); - -bool SOSTransportCircleSendDebugInfo(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error); - -bool SOSTransportCircleSendAccountChangedWithDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error); - -bool SOSTransportCircleSendOfficialDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error); - -bool SOSTransportCircleRecordLastCirclePushedInKVS(SOSTransportCircleRef transport, CFStringRef circle_name, CFDataRef circleData); +-(CFDictionaryRef) CF_RETURNS_RETAINED handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error; +-(CFArrayRef) handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error; +@end #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.m new file mode 100644 index 00000000..fe9349e4 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircle.m @@ -0,0 +1,65 @@ +#import "Security/SecureObjectSync/SOSAccountPriv.h" +#include + +@implementation SOSCircleStorageTransport + +@synthesize account = account; + +-(id)init +{ + return [super init]; + +} +-(SOSCircleStorageTransport*) initWithAccount:(SOSAccount*)acct +{ + self = [super init]; + if(self){ + self.account = acct; + } + return self; +} + +-(SOSAccount*)getAccount +{ + return self.account; +} + +-(CFIndex)circleGetTypeID +{ + return kUnknown; +} +-(CFIndex)getTransportType +{ + return kUnknown; +} + +-(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error +{ + return true; +} + +-(bool) flushChanges:(CFErrorRef *)error +{ + return true; +} +-(bool) postCircle:(CFStringRef)circleName circleData:(CFDataRef)circle_data err:(CFErrorRef *)error +{ + return true; +} + +-(bool) postRetirement:(CFStringRef) circleName peer:(SOSPeerInfoRef) peer err:(CFErrorRef *)error{ + return true; +} + +-(CFDictionaryRef)handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error +{ + return CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); +} + +-(CFArrayRef) handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error +{ + return CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); +} + +@end + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleCK.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleCK.h new file mode 100644 index 00000000..c92b0b51 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleCK.h @@ -0,0 +1,23 @@ +// +// SOSTransportCircleCK.h +// Security +// + +#ifndef SOSTransportCircleCK_h +#define SOSTransportCircleCK_h + +#import "SOSTransportCircle.h" +@class SOSCircleStorageTransport; + +@interface SOSCKCircleStorage : SOSCircleStorageTransport +{ + +} + +-(id)init; +-(id)initWithAccount:(SOSAccount*)acct; + +@end; + + +#endif /* SOSTransportCircleCK_h */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleCK.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleCK.m new file mode 100644 index 00000000..99f352cb --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleCK.m @@ -0,0 +1,71 @@ +// +// SOSTransportCircleCK.m +// Security +// +// Created by Michelle Auricchio on 12/23/16. +// +// + +#import +#import "Security/SecureObjectSync/SOSTransport.h" +#import "Security/SecureObjectSync/SOSAccountPriv.h" +#import "SOSTransportCircleCK.h" + +@implementation SOSCKCircleStorage + +-(id) init +{ + self = [super init]; + if(self){ + SOSRegisterTransportCircle(self); + } + return self; +} + +-(id) initWithAccount:(SOSAccount*)acct +{ + self = [super init]; + if(self) + { + self.account = acct; + } + return self; +} + +-(CFIndex) getTransportType +{ + return kCK; +} +-(SOSAccount*) getAccount +{ + return self.account; +} + +-(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error +{ + return true; +} + +-(bool) flushChanges:(CFErrorRef *)error +{ + return true; +} +-(bool) postCircle:(CFStringRef)circleName circleData:(CFDataRef)circle_data err:(CFErrorRef *)error +{ + return true; +} +-(bool) postRetirement:(CFStringRef) circleName peer:(SOSPeerInfoRef) peer err:(CFErrorRef *)error +{ + return true; +} + +-(CFDictionaryRef)handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error +{ + return NULL; +} +-(CFArrayRef) handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error +{ + return NULL; +} + +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.c deleted file mode 100644 index 70ea45ab..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.c +++ /dev/null @@ -1,435 +0,0 @@ -// -// SOSTransportCircleKVS.c -// sec -// -#include -#include -#include -#include -#include -#include -#include -#include - -static bool SOSTransportCircleKVSUpdateRetirementRecords(SOSTransportCircleKVSRef transport, CFDictionaryRef updates, CFErrorRef* error); -static bool SOSTransportCircleKVSUpdateKVS(SOSTransportCircleRef transport, CFDictionaryRef changes, CFErrorRef *error); -static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error); -static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error); -static void destroy(SOSTransportCircleRef transport); -static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error); -static CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error); -static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error); -static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error); -static inline CFIndex getTransportType(SOSTransportCircleRef transport, CFErrorRef *error); -static bool sendPeerInfo(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error); -static bool flushRingChanges(SOSTransportCircleRef transport, CFErrorRef* error); -static bool postRing(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error); -static bool sendAccountChangedWithDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error); -static bool sendDebugInfo(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error); - -struct __OpaqueSOSTransportCircleKVS{ - struct __OpaqueSOSTransportCircle c; - CFMutableDictionaryRef pending_changes; - CFStringRef circleName; -}; - - -SOSTransportCircleKVSRef SOSTransportCircleKVSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){ - SOSTransportCircleKVSRef t = (SOSTransportCircleKVSRef) SOSTransportCircleCreateForSubclass(sizeof(struct __OpaqueSOSTransportCircleKVS) - sizeof(CFRuntimeBase), account, error); - if(t){ - t->circleName = CFRetainSafe(circleName); - t->c.expireRetirementRecords = expireRetirementRecords; - t->c.postCircle = postCircle; - t->c.postRetirement = postRetirement; - t->c.flushChanges = flushChanges; - t->pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - t->c.handleRetirementMessages = handleRetirementMessages; - t->c.handleCircleMessages = handleCircleMessages; - t->c.destroy = destroy; - t->c.getTransportType = getTransportType; - t->c.sendDebugInfo = sendDebugInfo; - t->c.postRing = postRing; - t->c.sendPeerInfo = sendPeerInfo; - t->c.flushRingChanges = flushRingChanges; - t->c.sendAccountChangedWithDSID = sendAccountChangedWithDSID; - SOSRegisterTransportCircle((SOSTransportCircleRef)t); - } - return t; -} - -static CFStringRef SOSTransportCircleKVSGetCircleName(SOSTransportCircleKVSRef transport){ - return transport->circleName; -} - -static inline CFIndex getTransportType(SOSTransportCircleRef transport, CFErrorRef *error){ - return kKVS; -} - - -static void destroy(SOSTransportCircleRef transport){ - SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef)transport; - CFReleaseNull(tkvs->pending_changes); - CFReleaseNull(tkvs->circleName); - - SOSUnregisterTransportCircle((SOSTransportCircleRef)tkvs); -} - -static bool SOSTransportCircleKVSUpdateKVS(SOSTransportCircleRef transport, CFDictionaryRef changes, CFErrorRef *error){ - 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); - return true; -} - -bool SOSTransportCircleKVSSendPendingChanges(SOSTransportCircleKVSRef transport, CFErrorRef *error) { - CFErrorRef changeError = NULL; - SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport); - - if (transport->pending_changes == NULL || CFDictionaryGetCount(transport->pending_changes) == 0) { - CFReleaseNull(transport->pending_changes); - return true; - } - - CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error); - if(dsid == NULL) - dsid = kCFNull; - - CFDictionaryAddValue(transport->pending_changes, kSOSKVSRequiredKey, dsid); - - bool success = SOSTransportCircleKVSUpdateKVS((SOSTransportCircleRef)transport, transport->pending_changes, &changeError); - if (success) { - CFDictionaryRemoveAllValues(transport->pending_changes); - } else { - SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL, - CFSTR("Send changes block failed [%@]"), transport->pending_changes); - } - - return success; -} - -void SOSTransportCircleKVSAddToPendingChanges(SOSTransportCircleKVSRef transport, CFStringRef message_key, CFDataRef message_data){ - - if (transport->pending_changes == NULL) { - transport->pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - } - if (message_data == NULL) { - CFDictionarySetValue(transport->pending_changes, message_key, kCFNull); - } else { - CFDictionarySetValue(transport->pending_changes, message_key, message_data); - } -} - -static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error) { - - bool success = true; - CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFDictionaryForEach(retirements, ^(const void *key, const void *value) { - if (isString(key) && isArray(value)) { - CFStringRef circle_name = (CFStringRef) key; - CFArrayRef retirees = (CFArrayRef) value; - - CFArrayForEach(retirees, ^(const void *value) { - if (isString(value)) { - CFStringRef retiree_id = (CFStringRef) value; - - CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id); - - CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull); - - CFReleaseSafe(kvsKey); - } - }); - } - }); - - if(CFDictionaryGetCount(keysToWrite)) { - success = SOSTransportCircleKVSUpdateRetirementRecords((SOSTransportCircleKVSRef)transport, keysToWrite, error); - } - CFReleaseNull(keysToWrite); - - return success; -} - -static bool SOSTransportCircleKVSUpdateRetirementRecords(SOSTransportCircleKVSRef transport, CFDictionaryRef updates, CFErrorRef* error){ - CFErrorRef updateError = NULL; - bool success = false; - if (SOSTransportCircleKVSUpdateKVS((SOSTransportCircleRef)transport, updates, &updateError)){ - success = true; - } else { - SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL, - CFSTR("update parameters key failed [%@]"), updates); - } - return success; -} - -static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error) -{ - CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circleName, peer_id); - if (retirement_key) - SOSTransportCircleKVSAddToPendingChanges((SOSTransportCircleKVSRef)transport, retirement_key, retirement_data); - - CFReleaseNull(retirement_key); - return true; -} - -static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error) -{ - SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef) transport; - - return SOSTransportCircleKVSSendPendingChanges(tkvs, error); -} - -static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error){ - SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef)transport; - CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error); - if (circle_key) - SOSTransportCircleKVSAddToPendingChanges(tkvs, circle_key, circle_data); - CFReleaseNull(circle_key); - - return true; -} - -static CF_RETURNS_RETAINED CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error){ - SOSAccountRef account = SOSTransportCircleGetAccount(transport); - - return SOSAccountHandleRetirementMessages(account, circle_retirement_messages_table, error); -} - - -bool SOSTransportCircleRecordLastCirclePushedInKVS(SOSTransportCircleRef transport, CFStringRef circle_name, CFDataRef circleData){ - - SOSAccountRef a = SOSTransportCircleGetAccount(transport); - SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef)transport; - CFStringRef myPeerID = SOSAccountGetMyPeerID(a); - CFDataRef timeData = NULL; - - CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); - CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); - - withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) { - CFStringAppend(timeDescription, decription); - }); - CFStringAppend(timeDescription, CFSTR("]")); - - timeData = CFStringCreateExternalRepresentation(NULL,timeDescription, - kCFStringEncodingUTF8, '?'); - - CFMutableDataRef timeAndCircleMutable = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(timeData) + CFDataGetLength(circleData)); - CFDataAppend(timeAndCircleMutable, timeData); - - CFDataAppend(timeAndCircleMutable, circleData); - CFDataRef timeAndCircle = CFDataCreateCopy(kCFAllocatorDefault, timeAndCircleMutable); - - if(myPeerID){ - CFStringRef lastPushedCircleKey = SOSLastCirclePushedKeyCreateWithCircleNameAndPeerID(circle_name, SOSAccountGetMyPeerID(a)); - SOSTransportCircleKVSAddToPendingChanges(tkvs, lastPushedCircleKey,timeAndCircle); - CFReleaseSafe(lastPushedCircleKey); - } - else{ - //if we don't have a peerID (we could be retired or its too early in the system, let's use other gestalt information instead - CFStringRef lastPushedCircleKeyWithAccount = SOSLastCirclePushedKeyCreateWithAccountGestalt(SOSTransportCircleGetAccount(transport)); - SOSTransportCircleKVSAddToPendingChanges(tkvs, lastPushedCircleKeyWithAccount, timeAndCircle); - CFReleaseNull(lastPushedCircleKeyWithAccount); - } - CFReleaseNull(timeDescription); - CFReleaseNull(timeAndCircleMutable); - CFReleaseNull(timeAndCircle); - CFReleaseNull(timeData); - return true; -} - -CFArrayRef SOSTransportCircleKVSHandlePeerInfoV2Messages(SOSTransportCircleRef transport, CFMutableDictionaryRef peer_info_message_table, CFErrorRef *error){ - //SOSTransportCircleKVSRef kvs_transport = (SOSTransportCircleKVSRef)transport; - /* TODO Handle peer info messages! */ - - /* assuming array of peer ids or peer infos that were handled as the return value */ - return NULL; -} - -static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error){ - CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) { - CFErrorRef circleMessageError = NULL; - if(!isString(key) || !isData(value)) { - secerror("Error, Key-Value for CircleMessage was not CFString/CFData"); - } if (!SOSAccountHandleCircleMessage(SOSTransportCircleGetAccount(transport), key, value, &circleMessageError)) { - secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError); - } else{ - CFStringRef circle_id = (CFStringRef) key; - CFArrayAppendValue(handledKeys, circle_id); - } - CFReleaseNull(circleMessageError); - }); - - return handledKeys; -} - -bool SOSTransportCircleKVSAppendKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){ - - CFStringRef circle_name = NULL; - CFStringRef circle_key = NULL; - - if(SOSAccountHasPublicKey(SOSTransportCircleGetAccount((SOSTransportCircleRef)transport), NULL)){ - require_quiet(circle_name = SOSTransportCircleKVSGetCircleName(transport), fail); - require_quiet(circle_key = SOSCircleKeyCreateWithName(circle_name, error), fail); - - SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport); - require_quiet(account, fail); - SOSCircleRef circle = account->trusted_circle; - require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail); - - SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { - CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, SOSPeerInfoGetPeerID(peer)); - CFArrayAppendValue(alwaysKeys, retirement_key); - CFReleaseNull(retirement_key); - }); - - CFArrayAppendValue(alwaysKeys, circle_key); - - CFReleaseNull(circle_key); - } - return true; - -fail: - CFReleaseNull(circle_key); - return false; -} - -//register peer infos key -bool SOSTransportCircleKVSAppendPeerInfoKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){ - - if(SOSAccountHasPublicKey(SOSTransportCircleGetAccount((SOSTransportCircleRef)transport), NULL)){ - - SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport); - require_quiet(account, fail); - SOSCircleRef circle = account->trusted_circle; - require_quiet(circle, fail); - - SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { - CFStringRef peer_info_key = SOSPeerInfoV2KeyCreateWithPeerName(SOSPeerInfoGetPeerID(peer)); - CFArrayAppendValue(alwaysKeys, peer_info_key); - CFReleaseNull(peer_info_key); - }); - } - return true; - -fail: - return false; -} - -//register ring key -bool SOSTransportCircleKVSAppendRingKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){ - - if(SOSAccountHasPublicKey(SOSTransportCircleGetAccount((SOSTransportCircleRef)transport), NULL)){ - SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport); - require_quiet(account, fail); - SOSCircleRef circle = account->trusted_circle; - require_quiet(circle, fail); - - // Always interested in backup rings: - SOSAccountForEachRingName(account, ^(CFStringRef ringName) { - CFStringRef ring_key = SOSRingKeyCreateWithRingName(ringName); - CFArrayAppendValue(unlockedKeys, ring_key); - CFReleaseNull(ring_key); - }); - } - return true; -fail: - return false; -} - -extern CFStringRef kSOSAccountDebugScope; -//register debug scope key -bool SOSTransportCircleKVSAppendDebugKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){ - - CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope); - CFArrayAppendValue(alwaysKeys, key); - CFRelease(key); - return true; -} - -//send debug info over KVS -bool sendDebugInfo(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error) -{ - CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(type); - CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - key, - debugInfo, - NULL); - - CFReleaseNull(key); - bool success = SOSTransportCircleKVSUpdateKVS(transport, changes, error); - - CFReleaseNull(changes); - - return success; -} - -static bool sendAccountChangedWithDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error){ - - CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSOSKVSAccountChangedKey, dsid, - NULL); - - bool success = SOSTransportCircleKVSUpdateKVS((SOSTransportCircleRef)transport, changes, error); - - CFReleaseNull(changes); - - return success; -} - -//send the Ring over KVS -bool postRing(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error) -{ - CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error); - - if(ringKey) - SOSTransportCircleKVSAddToPendingChanges((SOSTransportCircleKVSRef)transport, ringKey, ring); - - CFReleaseNull(ringKey); - - return true; -} - -bool flushRingChanges(SOSTransportCircleRef transport, CFErrorRef* error){ - - SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef) transport; - - return SOSTransportCircleKVSSendPendingChanges(tkvs, error); -} - -//send the PeerInfo Data over KVS -bool sendPeerInfo(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error) -{ - CFStringRef peerName = SOSPeerInfoV2KeyCreateWithPeerName(peerID); - - CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - peerName, peerInfoData, - NULL); - - CFReleaseNull(peerName); - bool success = SOSTransportCircleKVSUpdateKVS(transport, changes, error); - - CFReleaseNull(changes); - - return success; -} - -bool SOSTransportCircleSendOfficialDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error) -{ - CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSOSKVSOfficialDSIDKey, dsid, - NULL); - bool success = SOSTransportCircleKVSUpdateKVS(transport, changes, error); - CFReleaseNull(changes); - - return success; -} - - - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.h index 1be07825..998bd928 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.h @@ -3,25 +3,40 @@ #ifndef sec_SOSTransportCircleKVS_h #define sec_SOSTransportCircleKVS_h -#include +#import "SOSTransportCircle.h" +@class SOSCircleStorageTransport; -typedef struct __OpaqueSOSTransportCircleKVS * SOSTransportCircleKVSRef; +@interface SOSKVSCircleStorageTransport : SOSCircleStorageTransport +{ + NSMutableDictionary *pending_changes; + NSString *circleName; +} -SOSTransportCircleKVSRef SOSTransportCircleKVSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error); -SOSTransportKeyParameterRef SOSTransportKeyParameterCreateForSubclass(size_t size, SOSAccountRef account, CFErrorRef *error); +@property (retain, nonatomic) NSMutableDictionary *pending_changes; +@property (retain, nonatomic) NSString *circleName; -bool SOSTransportCircleKVSAppendKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error); -void SOSTransportCircleKVSAddToPendingChanges(SOSTransportCircleKVSRef transport, CFStringRef message_key, CFDataRef message_data); -bool SOSTransportCircleKVSSendPendingChanges(SOSTransportCircleKVSRef transport, CFErrorRef *error); -bool SOSTransportCircleKVSAppendPeerInfoKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error); -bool SOSTransportCircleKVSAppendRingKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error); +-(id)init; +-(id)initWithAccount:(SOSAccount*)acct andCircleName:(NSString*)name; +-(NSString*) getCircleName; +-(bool) flushChanges:(CFErrorRef *)error; -bool SOSTransportCircleKVSAppendDebugKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error); +-(void)kvsAddToPendingChanges:(CFStringRef) message_key data:(CFDataRef)message_data; +-(bool)kvsSendPendingChanges:(CFErrorRef *)error; -CFArrayRef SOSTransportCircleKVSHandlePeerInfoV2Messages(SOSTransportCircleRef transport, CFMutableDictionaryRef peer_info_message_table, CFErrorRef *error); +-(bool)kvsAppendKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef) afterFirstUnlockKeys unlocked:(CFMutableArrayRef)unlockedKeys err:(CFErrorRef *)error; +-(bool)kvsAppendRingKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error; +-(bool)kvsAppendDebugKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error; +-(bool)kvsAppendConfigKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error; +-(bool) kvsRingFlushChanges:(CFErrorRef*) error; +-(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error; +-(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error; +-(bool) kvsSendOfficialDSID:(CFStringRef) dsid err:(CFErrorRef *)error; +-(bool) kvsSendAccountChangedWithDSID:(CFStringRef) dsid err:(CFErrorRef *)error; + +@end; #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.m new file mode 100644 index 00000000..e253420c --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.m @@ -0,0 +1,313 @@ +// +// SOSTransportCircleKVS.c +// sec +// +#include +#include +#include +#include +#include +#include +#include +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" + + +@implementation SOSKVSCircleStorageTransport + +@synthesize pending_changes = pending_changes; +@synthesize circleName = circleName; +extern CFStringRef kSOSAccountDebugScope; + +-(id)init +{ + return [super init]; +} + +-(id)initWithAccount:(SOSAccount*)acct andCircleName:(NSString*)name +{ + self = [super init]; + if(self){ + self.pending_changes = [NSMutableDictionary dictionary]; + self.circleName = [[NSString alloc] initWithString:name]; + self.account = acct; + SOSRegisterTransportCircle(self); + } + return self; +} + +-(NSString*) getCircleName +{ + return self.circleName; +} + +-(CFIndex) getTransportType{ + return kKVS; +} + +static bool SOSTransportCircleKVSUpdateKVS(NSDictionary *changes, CFErrorRef *error) +{ + CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) { + if (block_error) { + secerror("Error putting: %@", block_error); + } + }; + + SOSCloudKeychainPutObjectsInCloud((__bridge CFDictionaryRef)(changes), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error); + return true; +} + +-(bool)kvsSendPendingChanges:(CFErrorRef *)error +{ + CFErrorRef changeError = NULL; + + if (self.pending_changes == NULL || [self.pending_changes count] == 0) { + return true; + } + + CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error); + if(dsid == NULL) + dsid = kCFNull; + + [self.pending_changes setObject:(__bridge id _Nonnull)((void*)(dsid)) forKey:(__bridge NSString*)kSOSKVSRequiredKey]; + + bool success = SOSTransportCircleKVSUpdateKVS(self.pending_changes, &changeError); + if (success) { + [self.pending_changes removeAllObjects]; + } else { + SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL, + CFSTR("Send changes block failed [%@]"), self.pending_changes); + } + + return success; +} + +-(void)kvsAddToPendingChanges:(CFStringRef) message_key data:(CFDataRef)message_data +{ + if (self.pending_changes == NULL) { + self.pending_changes = [NSMutableDictionary dictionary]; + } + if (message_data == NULL) { + [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)message_key]; + } else { + [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key]; + } +} + +static bool SOSTransportCircleKVSUpdateRetirementRecords(CFDictionaryRef updates, CFErrorRef* error){ + CFErrorRef updateError = NULL; + bool success = false; + if (SOSTransportCircleKVSUpdateKVS((__bridge NSDictionary*)updates, &updateError)){ + success = true; + } else { + SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL, + CFSTR("update parameters key failed [%@]"), updates); + } + return success; +} +-(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error +{ + bool success = true; + CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFDictionaryForEach(retirements, ^(const void *key, const void *value) { + if (isString(key) && isArray(value)) { + CFStringRef circle_name = (CFStringRef) key; + CFArrayRef retirees = (CFArrayRef) value; + + CFArrayForEach(retirees, ^(const void *value) { + if (isString(value)) { + CFStringRef retiree_id = (CFStringRef) value; + + CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id); + + CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull); + + CFReleaseSafe(kvsKey); + } + }); + } + }); + + if(CFDictionaryGetCount(keysToWrite)) { + success = SOSTransportCircleKVSUpdateRetirementRecords(keysToWrite, error); + } + CFReleaseNull(keysToWrite); + + return success; +} + +-(bool) flushChanges:(CFErrorRef *)error +{ + return [self kvsSendPendingChanges:error]; + +} + +-(bool) postCircle:(CFStringRef)name circleData:(CFDataRef)circle_data err:(CFErrorRef *)error +{ + CFStringRef circle_key = SOSCircleKeyCreateWithName(name, error); + if (circle_key) + [self kvsAddToPendingChanges:circle_key data:circle_data]; + + CFReleaseNull(circle_key); + + return true; +} + +-(CFDictionaryRef)CF_RETURNS_RETAINED handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error +{ + return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error); +} + +-(CFArrayRef) handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error +{ + CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) { + CFErrorRef circleMessageError = NULL; + if(!isString(key) || !isData(value)) { + secerror("Error, Key-Value for CircleMessage was not CFString/CFData"); + } if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) { + secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError); + } else{ + CFStringRef circle_id = (CFStringRef) key; + CFArrayAppendValue(handledKeys, circle_id); + } + CFReleaseNull(circleMessageError); + }); + + return handledKeys; +} + +-(bool)kvsAppendKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef) afterFirstUnlockKeys unlocked:(CFMutableArrayRef)unlockedKeys err:(CFErrorRef *)error +{ + CFStringRef circle_name = NULL; + CFStringRef circle_key = NULL; + + if(SOSAccountHasPublicKey(self.account, NULL)){ + require_quiet(circle_name = (__bridge CFStringRef)self.circleName, fail); + require_quiet(circle_key = SOSCircleKeyCreateWithName(circle_name, error), fail); + + require_quiet(account, fail); + SOSAccountTrustClassic *trust = account.trust; + SOSCircleRef circle = trust.trustedCircle; + require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail); + + SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { + CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, SOSPeerInfoGetPeerID(peer)); + CFArrayAppendValue(alwaysKeys, retirement_key); + CFReleaseNull(retirement_key); + }); + + CFArrayAppendValue(alwaysKeys, circle_key); + + CFReleaseNull(circle_key); + } + return true; + +fail: + CFReleaseNull(circle_key); + return false; +} + +//register ring key +-(bool)kvsAppendRingKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error +{ + if(SOSAccountHasPublicKey(self.account, NULL)){ + require_quiet(account, fail); + SOSAccountTrustClassic *trust = account.trust; + SOSCircleRef circle = trust.trustedCircle; + require_quiet(circle, fail); + + // Always interested in backup rings: + SOSAccountForEachRingName(account, ^(CFStringRef ringName) { + CFStringRef ring_key = SOSRingKeyCreateWithRingName(ringName); + CFArrayAppendValue(unlockedKeys, ring_key); + CFReleaseNull(ring_key); + }); + } + return true; +fail: + return false; +} + +//register debug scope key +-(bool)kvsAppendDebugKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error +{ + CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope); + CFArrayAppendValue(alwaysKeys, key); + CFReleaseNull(key); + return true; +} + +//register otr config +-(bool)kvsAppendConfigKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error +{ + CFArrayAppendValue(alwaysKeys, kSOSKVSOTRConfigVersion); + return true; +} + +//send debug info over KVS +-(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error +{ + CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(type); + NSDictionary *changes = @{(__bridge NSString*)key:(__bridge id _Nonnull)debugInfo}; + + CFReleaseNull(key); + bool success = SOSTransportCircleKVSUpdateKVS(changes, error); + + return success; +} + +-(bool) kvsSendAccountChangedWithDSID:(CFStringRef) dsid err:(CFErrorRef *)error +{ + NSDictionary *changes = @{(__bridge NSString*)kSOSKVSAccountChangedKey:(__bridge NSString*)dsid}; + + bool success = SOSTransportCircleKVSUpdateKVS(changes, error); + + + return success; +} + +//send the Ring over KVS +-(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error +{ + CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error); + + if(ringKey) + [self kvsAddToPendingChanges:ringKey data:ring]; + + CFReleaseNull(ringKey); + + return true; +} + +-(bool) kvsRingFlushChanges:(CFErrorRef*) error +{ + return [self kvsSendPendingChanges:error]; +} + +-(bool) kvsSendOfficialDSID:(CFStringRef) dsid err:(CFErrorRef *)error +{ + NSDictionary *changes = @{(__bridge NSString*)kSOSKVSOfficialDSIDKey : (__bridge NSString*)dsid}; + bool success = SOSTransportCircleKVSUpdateKVS(changes, error); + return success; +} + +-(bool) postRetirement:(CFStringRef)circleName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error +{ + CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error); + + require_quiet(retirement_data, fail); + + CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer((__bridge CFStringRef)(self.circleName), SOSPeerInfoGetPeerID(peer)); + if (retirement_key) + [self kvsAddToPendingChanges:retirement_key data:retirement_data]; + + CFReleaseNull(retirement_key); + CFReleaseNull(retirement_data); + return true; +fail: + CFReleaseNull(retirement_data); + return true; +} +@end + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c deleted file mode 100644 index 7fa0ff23..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.c +++ /dev/null @@ -1,67 +0,0 @@ - -#include -#include -#include -#include - -#include -#include -#include - -CFGiblisWithCompareFor(SOSTransportKeyParameter); - -SOSTransportKeyParameterRef SOSTransportKeyParameterCreateForSubclass(size_t size, SOSAccountRef account, CFErrorRef *error) -{ - SOSTransportKeyParameterRef tpt = CFTypeAllocateWithSpace(SOSTransportKeyParameter, size, kCFAllocatorDefault); - tpt->account = CFRetainSafe(account); - return tpt; -} - -bool SOSTransportKeyParameterHandleNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef account){ - return transport->setToNewAccount(transport, account); -} - -static CFStringRef SOSTransportKeyParameterCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) { - SOSTransportKeyParameterRef t = (SOSTransportKeyParameterRef) aObj; - - return CFStringCreateWithFormat(NULL, NULL, CFSTR(""), t); -} - -static void SOSTransportKeyParameterDestroy(CFTypeRef aObj) { - SOSTransportKeyParameterRef transport = (SOSTransportKeyParameterRef) aObj; - - if(transport->destroy) - transport->destroy(transport); - - CFReleaseNull(transport->account); - -} - -bool SOSTransportKeyParameterHandleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error){ - return transport->handleKeyParameterChanges(transport, data, error); -} - - -static CFHashCode SOSTransportKeyParameterHash(CFTypeRef obj) -{ - return (intptr_t) obj; -} - -static Boolean SOSTransportKeyParameterCompare(CFTypeRef lhs, CFTypeRef rhs) -{ - return SOSTransportKeyParameterHash(lhs) == SOSTransportKeyParameterHash(rhs); -} - - -bool SOSTransportKeyParameterPublishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error) { - return transport->publishCloudParameters(transport, data, error); -} - -SOSAccountRef SOSTransportKeyParameterGetAccount(SOSTransportKeyParameterRef transport){ - return transport->account; -} - - -CFIndex SOSTransportKeyParameterGetTransportType(SOSTransportKeyParameterRef transport, CFErrorRef *error){ - return transport->getTransportType ? transport->getTransportType(transport, error) : kUnknown; -} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.h index 0f1c4af8..6df1521e 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.h @@ -2,36 +2,28 @@ #ifndef SOSTransportKeyParameter_h #define SOSTransportKeyParameter_h -#include -#include -#include - -typedef struct __OpaqueSOSTransportKeyParameter * SOSTransportKeyParameterRef; - -struct __OpaqueSOSTransportKeyParameter { - CFRuntimeBase _base; - SOSAccountRef account; - /* Connections from CF land to vtable land */ - CFStringRef (*copyDescription)(SOSTransportKeyParameterRef object); - void (*destroy)(SOSTransportKeyParameterRef object); - - - // TODO: Make this take broader parameters and assemble the key parameters blob? - bool (*publishCloudParameters)(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error); - bool (*handleKeyParameterChanges)(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error); - bool (*setToNewAccount)(SOSTransportKeyParameterRef transport, SOSAccountRef account); - CFIndex (*getTransportType)(SOSTransportKeyParameterRef transport, CFErrorRef *error); -}; - -bool SOSTransportKeyParameterPublishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error); - -SOSTransportKeyParameterRef SOSTransportKeyParameterCreateForSubclass(size_t size, SOSAccountRef account, CFErrorRef *error); -bool SOSTransportKeyParameterHandleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error); -bool SOSTransportKeyParameterHandleNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef account); -CFTypeID SOSTransportKeyParameterGetTypeID(void); - -SOSAccountRef SOSTransportKeyParameterGetAccount(SOSTransportKeyParameterRef transport); -CFIndex SOSTransportKeyParameterGetTransportType(SOSTransportKeyParameterRef transport, CFErrorRef *error); -bool SOSTransportKeyParameterPublishLastKeyParameters(SOSTransportKeyParameterRef transport, CFDataRef Parameters, CFErrorRef *error); +#import + +@interface CKKeyParameter : NSObject +{ + SOSAccount* account; +} + +@property (atomic) SOSAccount* account; + +-(id) initWithAccount:(SOSAccount*) account; + +-(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameter*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error; + +-(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameter*) transport data:(CFDataRef) data err:(CFErrorRef) error; +-(void) SOSTransportKeyParameterHandleNewAccount:(CKKeyParameter*) transport acct:(SOSAccount*) account; + +-(SOSAccount*) SOSTransportKeyParameterGetAccount:(CKKeyParameter*) transport; +-(CFIndex) SOSTransportKeyParameterGetTransportType:(CKKeyParameter*) transport err:(CFErrorRef *)error; + +-(bool) SOSTransportKeyParameterKVSAppendKeyInterests:(CKKeyParameter*)transport ak:(CFMutableArrayRef)alwaysKeys firstUnLock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error; + +@end + #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.m new file mode 100644 index 00000000..6f6816cc --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameter.m @@ -0,0 +1,119 @@ + +#include +#include +#include +#include +#include +#include +#include + +@implementation CKKeyParameter + +@synthesize account = account; + +-(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameter*) transport data:(CFDataRef) data err:(CFErrorRef) error +{ + return SOSAccountHandleParametersChange(account, data, &error); +} + +-(SOSAccount*) SOSTransportKeyParameterGetAccount:(CKKeyParameter*) transport +{ + return account; +} + + +-(CFIndex) SOSTransportKeyParameterGetTransportType:(CKKeyParameter*) transport err:(CFErrorRef *)error +{ + return kKVS; +} + + +-(void) SOSTransportKeyParameterHandleNewAccount:(CKKeyParameter*) transport acct:(SOSAccount*) acct +{ + SOSAccountSetToNew(acct); +} + +-(id) initWithAccount:(SOSAccount*) acct +{ + self = [super init]; + if(self){ + self.account = acct; + SOSRegisterTransportKeyParameter(self); + } + return self; +} + +-(bool) SOSTransportKeyParameterKVSAppendKeyInterests:(CKKeyParameter*)transport ak:(CFMutableArrayRef)alwaysKeys firstUnLock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error +{ + CFArrayAppendValue(alwaysKeys, kSOSKVSKeyParametersKey); + + return true; +} + +static bool SOSTransportKeyParameterKVSUpdateKVS(CFDictionaryRef changes, CFErrorRef *error){ + 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); + return true; +} + +-(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameter*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error +{ + + bool waitForeverForSynchronization = true; + CFDictionaryRef changes = NULL; + CFDataRef timeData = NULL; + CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); + CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); + + withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) { + CFStringAppend(timeDescription, decription); + }); + CFStringAppend(timeDescription, CFSTR("]")); + + timeData = CFStringCreateExternalRepresentation(NULL,timeDescription, + kCFStringEncodingUTF8, '?'); + + CFMutableDataRef timeAndKeyParametersMutable = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(timeData) + CFDataGetLength(newParameters)); + CFDataAppend(timeAndKeyParametersMutable, timeData); + CFDataAppend(timeAndKeyParametersMutable, newParameters); + CFDataRef timeAndKeyParameters = CFDataCreateCopy(kCFAllocatorDefault, timeAndKeyParametersMutable); + + CFStringRef ourPeerID = (__bridge CFStringRef)account.peerID; + + if(ourPeerID != NULL){ + CFStringRef keyParamKey = SOSLastKeyParametersPushedKeyCreateWithPeerID(ourPeerID); + + changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSOSKVSKeyParametersKey, newParameters, + keyParamKey, timeAndKeyParameters, + NULL); + CFReleaseNull(keyParamKey); + } + else + { + CFStringRef keyParamKeyWithAccount = SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(account); + changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSOSKVSKeyParametersKey, newParameters, + keyParamKeyWithAccount, timeAndKeyParameters, + NULL); + CFReleaseNull(keyParamKeyWithAccount); + } + bool success = SOSTransportKeyParameterKVSUpdateKVS(changes, error); + + sync_the_last_data_to_kvs((__bridge CFTypeRef)(account), waitForeverForSynchronization); + CFReleaseNull(changes); + CFReleaseNull(timeData); + CFReleaseNull(timeAndKeyParameters); + CFReleaseNull(timeAndKeyParametersMutable); + CFReleaseNull(timeDescription); + + return success; +} + +@end + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameterKVS.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameterKVS.c deleted file mode 100644 index ce921e49..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameterKVS.c +++ /dev/null @@ -1,137 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -static bool SOSTransportKeyParameterKVSPublishCloudParameters(SOSTransportKeyParameterKVSRef transport, CFDataRef newParameters, CFErrorRef *error); -static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error); -static bool SOSTransportKeyParameterKVSUpdateKVS(CFDictionaryRef changes, CFErrorRef *error); -static void destroy(SOSTransportKeyParameterRef transport); -static inline CFIndex getTransportType(SOSTransportKeyParameterRef transport, CFErrorRef *error); - -struct __OpaqueSOSTransportKeyParameterKVS{ - struct __OpaqueSOSTransportKeyParameter k; -}; - -static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error){ - SOSAccountRef account = transport->account; - return SOSAccountHandleParametersChange(account, data, &error); - -} - -static inline CFIndex getTransportType(SOSTransportKeyParameterRef transport, CFErrorRef *error){ - return kKVS; -} - - -static bool setToNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef account){ - SOSAccountSetToNew(account); - return true; -} - -SOSTransportKeyParameterKVSRef SOSTransportKeyParameterKVSCreate(SOSAccountRef account, CFErrorRef *error) { - SOSTransportKeyParameterKVSRef tkvs = (SOSTransportKeyParameterKVSRef) SOSTransportKeyParameterCreateForSubclass(sizeof(struct __OpaqueSOSTransportKeyParameterKVS) - sizeof(CFRuntimeBase), account, error); - if(tkvs){ - tkvs->k.publishCloudParameters = publishCloudParameters; - tkvs->k.handleKeyParameterChanges = handleKeyParameterChanges; - tkvs->k.setToNewAccount = setToNewAccount; - tkvs->k.destroy = destroy; - tkvs->k.getTransportType = getTransportType; - SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef)tkvs); - } - return tkvs; -} - -static void destroy(SOSTransportKeyParameterRef transport){ - SOSUnregisterTransportKeyParameter(transport); -} - -bool SOSTransportKeyParameterKVSHandleCloudParameterChange(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error){ - SOSTransportKeyParameterKVSRef tkvs = (SOSTransportKeyParameterKVSRef)transport; - SOSAccountRef account = tkvs->k.account; - - return SOSAccountHandleParametersChange(account, data, error); -} - - -bool SOSTransportKeyParameterKVSAppendKeyInterests(SOSTransportKeyParameterKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef*error){ - CFArrayAppendValue(alwaysKeys, kSOSKVSKeyParametersKey); - - return true; -} - -static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error) -{ - return SOSTransportKeyParameterKVSPublishCloudParameters((SOSTransportKeyParameterKVSRef)transport, data, error); -} - -static bool SOSTransportKeyParameterKVSUpdateKVS(CFDictionaryRef changes, CFErrorRef *error){ - 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); - return true; -} - -static bool SOSTransportKeyParameterKVSPublishCloudParameters(SOSTransportKeyParameterKVSRef transport, CFDataRef newParameters, CFErrorRef *error) -{ - SOSAccountRef a = SOSTransportKeyParameterGetAccount((SOSTransportKeyParameterRef)transport); - CFDictionaryRef changes = NULL; - CFDataRef timeData = NULL; - bool waitForeverForSynchronization = true; - - CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); - CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); - - withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) { - CFStringAppend(timeDescription, decription); - }); - CFStringAppend(timeDescription, CFSTR("]")); - - timeData = CFStringCreateExternalRepresentation(NULL,timeDescription, - kCFStringEncodingUTF8, '?'); - - CFMutableDataRef timeAndKeyParametersMutable = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(timeData) + CFDataGetLength(newParameters)); - CFDataAppend(timeAndKeyParametersMutable, timeData); - CFDataAppend(timeAndKeyParametersMutable, newParameters); - CFDataRef timeAndKeyParameters = CFDataCreateCopy(kCFAllocatorDefault, timeAndKeyParametersMutable); - - CFStringRef ourPeerID = SOSAccountGetMyPeerID(a); - - if(ourPeerID != NULL){ - CFStringRef keyParamKey = SOSLastKeyParametersPushedKeyCreateWithPeerID(ourPeerID); - - changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSOSKVSKeyParametersKey, newParameters, - keyParamKey, timeAndKeyParameters, - NULL); - CFReleaseNull(keyParamKey); - } - else - { - CFStringRef keyParamKeyWithAccount = SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(a); - changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, - kSOSKVSKeyParametersKey, newParameters, - keyParamKeyWithAccount, timeAndKeyParameters, - NULL); - CFReleaseNull(keyParamKeyWithAccount); - - } - bool success = SOSTransportKeyParameterKVSUpdateKVS(changes, error); - - sync_the_last_data_to_kvs(a, waitForeverForSynchronization); - - CFReleaseNull(changes); - CFReleaseNull(timeAndKeyParametersMutable); - CFReleaseNull(timeAndKeyParameters); - CFReleaseNull(timeData); - CFReleaseNull(timeDescription); - return success; -} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameterKVS.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameterKVS.h deleted file mode 100644 index 62f0d390..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportKeyParameterKVS.h +++ /dev/null @@ -1,16 +0,0 @@ - -#ifndef sec_SOSTransportKeyParameterKVS_h -#define sec_SOSTransportKeyParameterKVS_h - - -typedef struct __OpaqueSOSTransportKeyParameterKVS *SOSTransportKeyParameterKVSRef; - -bool SOSTransportKeyParameterKVSHandleCloudParameterChange(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error); -bool SOSTransportKeyParameterKVSAppendKeyInterests(SOSTransportKeyParameterKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error); -SOSTransportKeyParameterKVSRef SOSTransportKeyParameterKVSCreate(SOSAccountRef account, CFErrorRef *error); -bool SOSTransportKeyParameterHandleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error); - -bool SOSTransportKeyParameterHandleNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef account); - -#endif - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c deleted file mode 100644 index 870015ef..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c +++ /dev/null @@ -1,172 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // TODO: Remove this layer violation. - -CFGiblisWithHashFor(SOSTransportMessage); - -SOSTransportMessageRef SOSTransportMessageCreateForSubclass(size_t size, - SOSAccountRef account, CFStringRef circleName, - CFErrorRef *error) -{ - SOSTransportMessageRef tpt = CFTypeAllocateWithSpace(SOSTransportMessage, size, kCFAllocatorDefault); - - SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, circleName, error); - - tpt->engine = CFRetainSafe(engine); - tpt->account = CFRetainSafe(account); - tpt->circleName = CFRetainSafe(circleName); - return tpt; -} - - -static CFStringRef SOSTransportMessageCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions){ - SOSTransportMessageRef t = (SOSTransportMessageRef) aObj; - - return t->copyDescription ? t->copyDescription(t) - : CFStringCreateWithFormat(NULL, NULL, CFSTR(""), t); -} - -static void SOSTransportMessageDestroy(CFTypeRef aObj){ - SOSTransportMessageRef transport = (SOSTransportMessageRef) aObj; - - if (transport->destroy) - transport->destroy(transport); - - CFReleaseSafe(transport->account); -} - -CFStringRef SOSTransportMessageGetCircleName(SOSTransportMessageRef transport){ - return transport->circleName; -} - -CFIndex SOSTransportMessageGetTransportType(SOSTransportMessageRef transport, CFErrorRef *error){ - return transport->getTransportType ? transport->getTransportType(transport, error) : kUnknown; -} - - -SOSAccountRef SOSTransportMessageGetAccount(SOSTransportMessageRef transport){ - return transport->account; -} - -static CFHashCode SOSTransportMessageHash(CFTypeRef obj){ - return (intptr_t) obj; -} - -static Boolean SOSTransportMessageCompare(CFTypeRef lhs, CFTypeRef rhs){ - return SOSTransportMessageHash(lhs) == SOSTransportMessageHash(rhs); -} - -bool SOSTransportMessageSendMessage(SOSTransportMessageRef transport, CFStringRef peerID, CFDataRef message, CFErrorRef *error) { - CFDictionaryRef peerMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message, NULL); - - bool result = SOSTransportMessageSendMessages(transport, peerMessage, error); - - CFReleaseNull(peerMessage); - return result; -} - -bool SOSTransportMessageSendMessages(SOSTransportMessageRef transport, CFDictionaryRef peer_messages, CFErrorRef *error) { - return transport->sendMessages(transport, peer_messages, error); -} - -bool SOSTransportMessageFlushChanges(SOSTransportMessageRef transport, CFErrorRef *error){ - return transport->flushChanges(transport, error); -} - -bool SOSTransportMessageSyncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error){ - return transport->syncWithPeers(transport, peers, error); -} - -bool SOSTransportMessageCleanupAfterPeerMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef* error){ - return transport->cleanupAfterPeerMessages(transport, circleToPeerIDs, error); -} - -CF_RETURNS_RETAINED -CFDictionaryRef SOSTransportMessageHandleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error){ - return transport->handleMessages(transport, circle_peer_messages_table, error); -} - -SOSEngineRef SOSTransportMessageGetEngine(SOSTransportMessageRef transport) { - return transport->engine; -} - -static bool SOSEngineHandleCodedMessage(SOSEngineRef engine, CFStringRef peerID, CFDataRef codedMessage, CFErrorRef*error) { - __block bool result = true; - __block bool somethingChanged = false; - - 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); - if (uwstatus == SOSCoderUnwrapDecoded) { - SOSMessageRef message = NULL; - if (decodedMessage && CFDataGetLength(decodedMessage)) { - // Only hand non empty messages to the engine, empty messages are an artifact - // of coder startup. - message = SOSMessageCreateWithData(kCFAllocatorDefault, decodedMessage, error); - } - if (message) { - bool engineHandleMessageDoesNotGetToRollbackTransactions = true; - result = SOSEngineHandleMessage_locked(engine, peerID, message, txn, &engineHandleMessageDoesNotGetToRollbackTransactions, &somethingChanged, error); - CFReleaseSafe(message); - } - } else { - result = uwstatus != SOSCoderUnwrapError; - } - CFReleaseNull(decodedMessage); - }); - - if (somethingChanged) { - SecKeychainChanged(); - } - - if (result) { - SOSCCRequestSyncWithPeer(peerID); - } - - return result; -} - -bool SOSTransportMessageHandlePeerMessage(SOSTransportMessageRef transport, CFStringRef peerID, CFDataRef codedMessage, CFErrorRef *error) { - bool result = false; - SOSEngineRef engine = SOSTransportMessageGetEngine(transport); - require_quiet(SecRequirementError(engine != NULL, error, CFSTR("Missing engine")), done); - - result = SOSEngineHandleCodedMessage(engine, peerID, codedMessage, error); - -done: - return result; -} - -bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) { - __block bool ok = true; - SOSEngineRef engine = SOSTransportMessageGetEngine(transport); - - ok &= SOSEngineWithPeerID(engine, peer_id, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { - // Now under engine lock do stuff - CFDataRef message_to_send = NULL; - SOSEnginePeerMessageSentBlock sent = NULL; - ok = SOSPeerCoderSendMessageIfNeeded(engine, txn, peer, coder, &message_to_send, peer_id, &sent, error); - if (message_to_send) { - ok = ok && SOSTransportMessageSendMessage(transport, peer_id, message_to_send, error); - - SOSPeerCoderConsume(&sent, ok); - }else{ - secnotice("transport", "no message to send to peer: %@", peer_id); - } - - Block_release(sent); - CFReleaseSafe(message_to_send); - - *forceSaveState = ok; - }); - - return ok; -} diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.h index f9cf47c9..2c583688 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.h @@ -2,61 +2,41 @@ #ifndef SOSTransportMessage_h #define SOSTransportMessage_h -#include -#include -#include -#include - -typedef struct __OpaqueSOSTransportMessage *SOSTransportMessageRef; - - -struct __OpaqueSOSTransportMessage { - CFRuntimeBase _base; - SOSEngineRef engine; - SOSAccountRef account; - CFStringRef circleName; - /* Connections from CF land to vtable land */ - CFStringRef (*copyDescription)(SOSTransportMessageRef object); - void (*destroy)(SOSTransportMessageRef object); - CFStringRef (*getName)(SOSTransportMessageRef object); - - /* send message operations */ - bool (*syncWithPeers)(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error); - bool (*cleanupAfterPeerMessages)(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef* error); - bool (*sendMessages)(SOSTransportMessageRef transport, CFDictionaryRef circle_messages, CFErrorRef *error); - bool (*flushChanges)(SOSTransportMessageRef transport, CFErrorRef *error); - CFIndex (*getTransportType)(SOSTransportMessageRef transport, CFErrorRef *error); - CFDictionaryRef (*handleMessages)(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error); - -}; - -CFStringRef SOSTransportMessageGetCircleName(SOSTransportMessageRef transport); +#import +#import -SOSTransportMessageRef SOSTransportMessageCreateForSubclass(size_t size,SOSAccountRef account, CFStringRef circleName, CFErrorRef *error); -bool SOSTransportMessageHandlePeerMessage(SOSTransportMessageRef transport, CFStringRef peer_id, CFDataRef codedMessage, CFErrorRef *error); +@interface SOSMessage : NSObject +{ + CFTypeRef engine; + SOSAccount *account; + NSString *circleName; +} +@property (atomic) CFTypeRef engine; +@property (atomic) SOSAccount* account; +@property (strong, atomic) NSString *circleName; -typedef bool (^SOSTransportSendToPeerBlock)(SOSTransportMessageRef transport, CFStringRef peerID, CFDataRef message, SOSEnginePeerMessageSentBlock sentBlock); +-(id) initWithAccount:(SOSAccount*)acct andName:(NSString*)name; -SOSEngineRef SOSTransportMessageGetEngine(SOSTransportMessageRef transport); +-(CFIndex) SOSTransportMessageGetTransportType; +-(CFStringRef) SOSTransportMessageGetCircleName; +-(CFTypeRef) SOSTransportMessageGetEngine; +-(SOSAccount*) SOSTransportMessageGetAccount; -SOSAccountRef SOSTransportMessageGetAccount(SOSTransportMessageRef transport); - -bool SOSTransportMessageCleanupAfterPeerMessages(SOSTransportMessageRef transport, CFDictionaryRef peers, CFErrorRef* error); - -bool SOSTransportMessageSendMessage(SOSTransportMessageRef transport, CFStringRef peerID, CFDataRef message, CFErrorRef *error); -bool SOSTransportMessageSendMessages(SOSTransportMessageRef transport, CFDictionaryRef peer_messages, CFErrorRef *error); -bool SOSTransportMessageFlushChanges(SOSTransportMessageRef transport, CFErrorRef *error); +-(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessage*) transport peers:(CFDictionaryRef) peers err:(CFErrorRef*) error; -bool SOSTransportMessageSyncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error); +-(bool) SOSTransportMessageSendMessage:(SOSMessage*) transport id:(CFStringRef) peerID messageToSend:(CFDataRef) message err:(CFErrorRef *)error; +-(bool) SOSTransportMessageSendMessages:(SOSMessage*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error; +-(bool) SOSTransportMessageFlushChanges:(SOSMessage*) transport err:(CFErrorRef *)error; -SOSTransportMessageRef SOSTransportMessageCreateForSubclass(size_t size, - SOSAccountRef account, CFStringRef circleName, - CFErrorRef *error); -CF_RETURNS_RETAINED -CFDictionaryRef SOSTransportMessageHandleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error); +-(bool) SOSTransportMessageSyncWithPeers:(SOSMessage*) transport p:(CFSetRef) peers err:(CFErrorRef *)error; -CFTypeID SOSTransportMessageGetTypeID(void); +-(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessage*) transport peerMessages:(CFMutableDictionaryRef) circle_peer_messages_table err:(CFErrorRef *)error; -CFIndex SOSTransportMessageGetTransportType(SOSTransportMessageRef transport, CFErrorRef *error); +-(bool) SOSTransportMessageHandlePeerMessage:(SOSMessage*) transport id:(CFStringRef) peer_id cm:(CFDataRef) codedMessage err:(CFErrorRef *)error; +-(bool) SOSTransportMessageSendMessageIfNeeded:(SOSMessage*) transport id:(CFStringRef) circle_id pID:(CFStringRef) peer_id err:(CFErrorRef *)error; +//for testing +bool SOSEngineHandleCodedMessage(SOSAccount* account, SOSEngineRef engine, CFStringRef peerID, CFDataRef codedMessage, CFErrorRef*error); + +@end #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.m new file mode 100644 index 00000000..f94eeca5 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.m @@ -0,0 +1,408 @@ +#include +#include +#include +#include +#include +#include +#import "Security/SecureObjectSync/SOSPeerRateLimiter.h" +#import "Security/SecureObjectSync/SOSPeerOTRTimer.h" +#include + +#include +#include +#include +#include +#include +#include // TODO: Remove this layer violation. + +NSString* const SecSOSMessageRTT = @"com.apple.security.sos.messagertt"; + +@class SOSMessage; + +@implementation SOSMessage + +@synthesize engine = engine; +@synthesize account = account; +@synthesize circleName = circleName; + +-(id) initWithAccount:(SOSAccount*)acct andName:(NSString*)name +{ + self = [super init]; + if(self){ + SOSEngineRef e = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, (__bridge CFStringRef)name, NULL); + engine = e; + account = acct; + circleName = [[NSString alloc]initWithString:name]; + } + return self; +} + +-(CFTypeRef) SOSTransportMessageGetEngine +{ + return engine; +} + +-(CFStringRef) SOSTransportMessageGetCircleName +{ + return (__bridge CFStringRef)(circleName); +} + +-(CFIndex) SOSTransportMessageGetTransportType +{ + return kUnknown; +} + +-(SOSAccount*) SOSTransportMessageGetAccount +{ + return account; +} + +-(bool) SOSTransportMessageSendMessages:(SOSMessage*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error +{ + return true; +} + +-(bool) SOSTransportMessageFlushChanges:(SOSMessage*) transport err:(CFErrorRef *)error +{ + return true; +} + +-(bool) SOSTransportMessageSyncWithPeers:(SOSMessage*) transport p:(CFSetRef) peers err:(CFErrorRef *)error{ + return true; +} +-(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessage*) transport peers:(CFDictionaryRef) peers err:(CFErrorRef*) error{ + return true; +} + +-(bool) SOSTransportMessageSendMessage:(SOSMessage*) transport id:(CFStringRef) peerID messageToSend:(CFDataRef) message err:(CFErrorRef *)error +{ + CFDictionaryRef peerMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message, NULL); + + bool result = [self SOSTransportMessageSendMessages:transport pm:peerMessage err:error]; + + CFReleaseNull(peerMessage); + return result; +} + +bool SOSEngineHandleCodedMessage(SOSAccount* account, SOSEngineRef engine, CFStringRef peerID, CFDataRef codedMessage, CFErrorRef*error) { + __block bool result = true; + __block bool somethingChanged = false; + 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); + NSMutableDictionary* attemptsPerPeer = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountRenegotiationRetryCount, NULL); + //clear the max retry only if negotiation has finished and a counter exists + if(coder != NULL && attemptsPerPeer != nil && !SOSCoderIsCoderInAwaitingState(coder) && ([attemptsPerPeer objectForKey:(__bridge NSString*)peerID] != NULL)){ + secnotice("otrtimer", "otr negotiation completed! clearing max retry counter"); + SOSPeerOTRTimerClearMaxRetryCount(account, (__bridge NSString*)peerID); + } + if (uwstatus == SOSCoderUnwrapDecoded) { + SOSMessageRef message = NULL; + if (decodedMessage && CFDataGetLength(decodedMessage)) { + // Only hand non empty messages to the engine, empty messages are an artifact + // of coder startup. + message = SOSMessageCreateWithData(kCFAllocatorDefault, decodedMessage, error); + } + if (message) { + bool engineHandleMessageDoesNotGetToRollbackTransactions = true; + result = SOSEngineHandleMessage_locked(engine, peerID, message, txn, &engineHandleMessageDoesNotGetToRollbackTransactions, &somethingChanged, error); + CFReleaseSafe(message); + } + } else { + result = uwstatus != SOSCoderUnwrapError; + } + CFReleaseNull(decodedMessage); + }); + + if (somethingChanged) { + SecKeychainChanged(); + } + + if (result) { + SOSCCRequestSyncWithPeer(peerID); + } + + return result; +} +-(CFDictionaryRef) SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessage*) transport peerMessages:(CFMutableDictionaryRef) circle_peer_messages_table err:(CFErrorRef *)error +{ + return CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); +} + +-(void) SOSTransportMessageCalculateNextTimer:(SOSAccount*)account rtt:(int)rtt peerid:(NSString*)peerid +{ + NSMutableDictionary *peerRTTs = (__bridge NSMutableDictionary*)SOSAccountGetValue(account,kSOSAccountPeerNegotiationTimeouts, NULL); + if(!peerRTTs){ + peerRTTs = [NSMutableDictionary dictionary]; + } + else{ + NSNumber *timeout = [peerRTTs objectForKey:peerid]; + if(timeout){ + if(timeout.intValue < (rtt * 2)){ + NSNumber* newTimeout = [[NSNumber alloc] initWithInt: (rtt * 2)]; + [peerRTTs setObject:newTimeout forKey:peerid]; + secnotice("otrtimer", "New OTR RTT: %d", [newTimeout intValue]); + } + } + else{ + if(rtt < 15){ + timeout = [[NSNumber alloc]initWithInt:(30 * 2)]; + } + else{ + timeout = [[NSNumber alloc]initWithInt:(rtt * 2)]; + } + [peerRTTs setObject:timeout forKey:peerid]; + secnotice("otrtimer", "setting initial timeout value to rtt*2: %d", [timeout intValue]); + } + } + SOSAccountSetValue(account,kSOSAccountPeerNegotiationTimeouts, (__bridge CFMutableDictionaryRef)peerRTTs, NULL); +} + +-(void) SOSTransportMessageUpdateRTTs:(NSString*)peerid +{ + SOSAccount* account = [self SOSTransportMessageGetAccount]; + NSMutableDictionary *peerToTimeLastSentDict = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountPeerLastSentTimestamp, NULL); + if(peerToTimeLastSentDict){ + NSDate* storedDate = [peerToTimeLastSentDict objectForKey:peerid]; + if(storedDate){ + NSDate* currentDate = [NSDate date]; + int rtt = [currentDate timeIntervalSinceDate:storedDate]; + secnotice("otrtimer","current date: %@, stored date: %@", currentDate, storedDate); + secnotice("otrtimer", "rtt: %d", rtt); + [self SOSTransportMessageCalculateNextTimer:account rtt:rtt peerid:peerid]; + + SecADClientPushValueForDistributionKey((__bridge CFStringRef) SecSOSMessageRTT, rtt); + [peerToTimeLastSentDict removeObjectForKey:peerid]; //remove last sent message date + SOSAccountSetValue(account, kSOSAccountPeerLastSentTimestamp, (__bridge CFMutableDictionaryRef)peerToTimeLastSentDict, NULL); + } + } +} + +-(bool) SOSTransportMessageHandlePeerMessage:(SOSMessage*) transport id:(CFStringRef) peer_id cm:(CFDataRef) codedMessage err:(CFErrorRef *)error +{ + [self SOSTransportMessageUpdateRTTs:(__bridge NSString*)peer_id]; + bool result = false; + require_quiet(SecRequirementError(transport.engine != NULL, error, CFSTR("Missing engine")), done); + result = SOSEngineHandleCodedMessage([transport SOSTransportMessageGetAccount], (SOSEngineRef)transport.engine, peer_id, codedMessage, error); +done: + return result; +} + +static PeerRateLimiter* getRateLimiter(SOSPeerRef peer) +{ + PeerRateLimiter *limiter = nil; + + if(!(limiter = (__bridge PeerRateLimiter*)SOSPeerGetRateLimiter(peer))){ + limiter = [[PeerRateLimiter alloc] initWithPeer:peer]; + SOSPeerSetRateLimiter(peer, (__bridge void*)limiter); + } + return limiter; +} + +static void SOSPeerSetNextTimeToSend(PeerRateLimiter* limiter, int nextTimeToSync, NSString *accessGroup, SOSPeerRef peer, SOSMessage* transport, CFDataRef message_to_send) +{ + secnotice("ratelimit", "SOSPeerSetNextTimeToSend next time: %d", nextTimeToSync); + + __block dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); + dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, nextTimeToSync * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); + secnotice("ratelimit", "SOSPeerSetNextTimeToSend next time to sync: %llu", (nextTimeToSync * NSEC_PER_SEC)); + + [limiter.accessGroupToNextMessageToSend setObject:(__bridge NSData*)message_to_send forKey:accessGroup]; + + CFStringRef peerid = CFRetainSafe(SOSPeerGetID(peer)); + CFStringRef accessGroupRetained = CFRetainSafe((__bridge CFStringRef)accessGroup); + + dispatch_source_set_event_handler(timer, ^{ + SOSCCPeerRateLimiterSendNextMessage_Server(peerid, accessGroupRetained); + }); + + dispatch_source_set_cancel_handler(timer, ^{ + CFReleaseSafe(peerid); + CFReleaseSafe(accessGroupRetained); + }); + + dispatch_resume(timer); + [limiter.accessGroupToTimer setObject:timer forKey:accessGroup]; +} + +static void setRateLimitingCounters(SOSAccount* account, PeerRateLimiter* limiter, NSString* attribute) +{ + CFErrorRef error = NULL; + + NSMutableDictionary* counters = (__bridge NSMutableDictionary*) SOSAccountGetValue(account, kSOSRateLimitingCounters, &error); + + if(!counters){ + counters = [[NSMutableDictionary alloc]init]; + } + + [counters setObject:[limiter diagnostics] forKey:attribute]; + SOSAccountSetValue(account, kSOSRateLimitingCounters, (__bridge CFDictionaryRef)counters, &error); +} +//figure out whether or not an access group should be judged, held back, or sent +static bool SOSPeerShouldSend(CFArrayRef attributes, SOSPeerRef peer, SOSMessage* transport, CFDataRef message_to_send) +{ + NSDate *date = [NSDate date]; + __block bool peerShouldSend = false; + PeerRateLimiter *limiter = getRateLimiter(peer); + __block NSMutableDictionary *powerlogPayload = nil; + static NSMutableDictionary* attributeRateLimiting = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + attributeRateLimiting = [[NSMutableDictionary alloc] init]; + }); + + if(!attributes){ + peerShouldSend = true; + } + else{ + secnotice("ratelimit", "number of attributes to review: %lu", CFArrayGetCount(attributes)); + [(__bridge NSArray*)attributes enumerateObjectsUsingBlock:^(NSString* attribute, NSUInteger idx, BOOL * _Nonnull stop) { + enum RateLimitState state = [limiter stateForAccessGroup:attribute]; + + switch(state){ + case RateLimitStateCanSend: + { + NSDate *limit = nil; + KeychainItem *item = [[KeychainItem alloc] initWithAccessGroup: attribute]; + NSInteger badness = [limiter judge:item at:date limitTime:&limit]; + secnotice("ratelimit","accessGroup: %@, judged: %lu", attribute, (long)badness); + + NSNumber *currentBadness = attributeRateLimiting[attribute]; + NSNumber *newBadness = @(badness); + + if (![currentBadness isEqual:newBadness]) { + attributeRateLimiting[attribute] = newBadness; + if (powerlogPayload == NULL) { + powerlogPayload = [[NSMutableDictionary alloc] init]; + } + powerlogPayload[attribute] = newBadness; + } + + double delta = [limit timeIntervalSinceDate:date]; + + if(delta > 0){ + //setting counters for attribute being rate limited + setRateLimitingCounters([transport SOSTransportMessageGetAccount],limiter, attribute); + + secnotice("ratelimit", "setting a timer for next sync: %@", limit); + + SOSPeerSetNextTimeToSend(limiter, delta, attribute, peer, transport, message_to_send); + //set rate limit state to hold + [limiter.accessGroupRateLimitState setObject:[[NSNumber alloc]initWithLong:RateLimitStateHoldMessage] forKey:attribute]; + }else{ + peerShouldSend = true; + } + } + break; + case RateLimitStateHoldMessage: + { + secnotice("ratelimit","access group: %@ is being rate limited", attribute); + } + break; + default: + { + secnotice("ratelimit","no state for limiter for peer: %@", peer); + } + }; + }]; + } + if ([powerlogPayload count]) { + SecPLLogRegisteredEvent(@"SOSKVSRateLimitingEvent", + @{ + @"timestamp" : @([date timeIntervalSince1970]), + @"peerShouldSend" : @(peerShouldSend), + @"attributeBadness" : powerlogPayload + }); + } + return peerShouldSend; +} + +//if a separate message containing a rate limited access group is going to be sent, make sure to send any pending messages first otherwise the OTR ordering will be wrong! +static void SOSTransportSendPendingMessage(CFArrayRef attributes, SOSMessage* transport, SOSPeerRef peer){ + PeerRateLimiter *limiter = getRateLimiter(peer); + + [(__bridge NSArray*)attributes enumerateObjectsUsingBlock:^(NSString* attribute, NSUInteger idx, BOOL * _Nonnull stop) { + NSData* message = [limiter.accessGroupToNextMessageToSend objectForKey:attribute]; + if(message){ + CFErrorRef error = NULL; + bool sendResult = [transport SOSTransportMessageSendMessage:transport id:SOSPeerGetID(peer) messageToSend:(__bridge CFDataRef)message err:&error]; + + if(!sendResult || error){ + secnotice("ratelimit", "SOSTransportSendPendingMessage: could not send message: %@", error); + } + else{ + secnotice("ratelimit", "SOSTransportSendPendingMessage: sent pending message: %@ for access group: %@", message, attribute); + } + [limiter.accessGroupToNextMessageToSend removeObjectForKey:attribute]; + //cancel dispatch timer + dispatch_source_t timer = [limiter.accessGroupToTimer objectForKey:attribute]; + if(timer) + dispatch_cancel(timer); + [limiter.accessGroupToTimer removeObjectForKey:attribute]; + [limiter.accessGroupRateLimitState setObject:[[NSNumber alloc]initWithLong:RateLimitStateCanSend] forKey:attribute]; + } + }]; +} + +//update last time message sent for this peer +-(void) SOSTransportMessageUpdateLastMessageSentTimetstamp:(SOSAccount*)account peer:(SOSPeerRef)peer +{ + NSMutableDictionary *peerRTTs = (__bridge NSMutableDictionary*)SOSAccountGetValue(account, kSOSAccountPeerLastSentTimestamp, NULL); + if(!peerRTTs){ + peerRTTs = [NSMutableDictionary dictionary]; + } + if([peerRTTs objectForKey:(__bridge NSString*)SOSPeerGetID(peer) ] == nil){ + [peerRTTs setObject:[NSDate date] forKey:(__bridge NSString*)SOSPeerGetID(peer)]; + SOSAccountSetValue(account, kSOSAccountPeerLastSentTimestamp, (__bridge CFMutableDictionaryRef)peerRTTs, NULL); + } +} +-(bool) SOSTransportMessageSendMessageIfNeeded:(SOSMessage*) transport id:(CFStringRef) circle_id pID:(CFStringRef) peer_id err:(CFErrorRef *)error +{ + __block bool ok = true; + SOSAccount* account = transport.account; + + BOOL initialSync = account.isInitialSyncing; + ok &= SOSEngineWithPeerID((SOSEngineRef)transport.engine, peer_id, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + // Now under engine lock do stuff + CFDataRef message_to_send = NULL; + SOSEnginePeerMessageSentBlock sent = NULL; + CFMutableArrayRef attributes = NULL; + ok = SOSPeerCoderSendMessageIfNeeded([transport SOSTransportMessageGetAccount],(SOSEngineRef)transport.engine, txn, peer, coder, &message_to_send, peer_id, &attributes, &sent, error); + secnotice("ratelimit","attribute list: %@", attributes); + bool shouldSend = true; + + if(attributes == NULL){ //no attribute but still should be rate limited + attributes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFArrayAppendValue(attributes, CFSTR("NoAttribute")); + } + if(initialSync){ + secnotice("ratelimit","not going to rate limit, currently in initial sync"); + } + if(!initialSync && message_to_send){ //need to judge the message if not in initial sync + secnotice("ratelimit","not in initial sync!"); + shouldSend = SOSPeerShouldSend(attributes, peer, transport, message_to_send); + secnotice("ratelimit","should send? : %d", shouldSend); + } + if (shouldSend && message_to_send) { + SOSTransportSendPendingMessage(attributes, transport, peer); + ok = ok && [transport SOSTransportMessageSendMessage:transport id:peer_id messageToSend:message_to_send err:error]; + SOSPeerCoderConsume(&sent, ok); + [transport SOSTransportMessageUpdateLastMessageSentTimetstamp:account peer:peer]; + + }else if(!shouldSend){ + secnotice("ratelimit", "peer is rate limited: %@", peer_id); + }else{ + secnotice("transport", "no message to send to peer: %@", peer_id); + } + sent = NULL; + CFReleaseSafe(message_to_send); + + *forceSaveState = ok; + }); + + return ok; +} + +@end + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.h index 21e68271..97506591 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.h @@ -3,7 +3,10 @@ // sec // // -#include +#ifndef sec_SOSTransportMessageIDS_h +#define sec_SOSTransportMessageIDS_h + +@class SOSMessage; typedef enum { kIDSStartPingTestMessage = 1, @@ -16,26 +19,30 @@ typedef enum { kIDSPeerUsesACK = 9 } idsOperation; -//error handling stuff -typedef enum { - kSecIDSErrorNoDeviceID = -1, //default case - kSecIDSErrorNotRegistered = -2, - kSecIDSErrorFailedToSend=-3, - kSecIDSErrorCouldNotFindMatchingAuthToken = -4, - kSecIDSErrorDeviceIsLocked = -5, - kSecIDSErrorNoPeersAvailable = -6 - -} idsError; +extern const CFStringRef kSecIDSErrorDomain; +extern const CFStringRef kIDSOperationType; +extern const CFStringRef kIDSMessageToSendKey; +extern const CFStringRef kIDSMessageUniqueID; +extern const CFStringRef kIDSMessageRecipientPeerID; +extern const CFStringRef kIDSMessageRecipientDeviceID; +extern const CFStringRef kIDSMessageUsesAckModel; + -typedef struct __OpaqueSOSTransportMessageIDS *SOSTransportMessageIDSRef; +@interface SOSMessageIDS : SOSMessage +{ + CFBooleanRef useFragmentation; +} +@property (atomic) CFBooleanRef useFragmentation; -SOSTransportMessageIDSRef SOSTransportMessageIDSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error); +-(id) initWithAcount:(SOSAccount*)acct circleName:(CFStringRef)name; -HandleIDSMessageReason SOSTransportMessageIDSHandleMessage(SOSAccountRef account, CFDictionaryRef message, CFErrorRef *error); +-(HandleIDSMessageReason) SOSTransportMessageIDSHandleMessage:(SOSAccount*)account m:(CFDictionaryRef) message err:(CFErrorRef *)error; -bool SOSTransportMessageIDSGetIDSDeviceID(SOSAccountRef account); +-(bool) SOSTransportMessageIDSGetIDSDeviceID:(SOSAccount*)acct; -void SOSTransportMessageIDSSetFragmentationPreference(SOSTransportMessageRef transport, CFBooleanRef preference); -CFBooleanRef SOSTransportMessageIDSGetFragmentationPreference(SOSTransportMessageRef transport); +-(void) SOSTransportMessageIDSSetFragmentationPreference:(SOSMessage*) transport pref:(CFBooleanRef) preference; +-(CFBooleanRef) SOSTransportMessageIDSGetFragmentationPreference:(SOSMessage*) transport; +@end +#endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.m similarity index 59% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.m index 2841b08f..96dce491 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.m @@ -5,7 +5,8 @@ // #include #include -#include +#import +#import #include #include @@ -20,74 +21,54 @@ #include #include #include +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" #define IDS "IDS transport" -struct __OpaqueSOSTransportMessageIDS { - struct __OpaqueSOSTransportMessage m; - CFBooleanRef useFragmentation; -}; +@implementation SOSMessageIDS -// -// V-table implementation forward declarations -// -static bool sendToPeer(SOSTransportMessageRef transport, bool shouldUseAckModel, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID,CFDictionaryRef message, CFErrorRef *error); -static bool syncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error); -static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error); -static void destroy(SOSTransportMessageRef transport); -static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error); -static bool flushChanges(SOSTransportMessageRef transport, CFErrorRef *error); -static CF_RETURNS_RETAINED CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error); - -static inline CFIndex getTransportType(SOSTransportMessageRef transport, CFErrorRef *error){ +@synthesize useFragmentation = useFragmentation; + +-(CFIndex) SOSTransportMessageGetTransportType +{ return kIDS; } -void SOSTransportMessageIDSSetFragmentationPreference(SOSTransportMessageRef transport, CFBooleanRef preference){ - SOSTransportMessageIDSRef t = (SOSTransportMessageIDSRef)transport; - t->useFragmentation = preference; +-(void) SOSTransportMessageIDSSetFragmentationPreference:(SOSMessageIDS*) transport pref:(CFBooleanRef) preference +{ + useFragmentation = preference; } -CFBooleanRef SOSTransportMessageIDSGetFragmentationPreference(SOSTransportMessageRef transport){ - SOSTransportMessageIDSRef t = (SOSTransportMessageIDSRef)transport; - return t->useFragmentation; - } +-(CFBooleanRef) SOSTransportMessageIDSGetFragmentationPreference:(SOSMessageIDS*) transport +{ + return useFragmentation; +} -SOSTransportMessageIDSRef SOSTransportMessageIDSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error) +-(id) initWithAcount:(SOSAccount*)acct circleName:(CFStringRef)name { - SOSTransportMessageIDSRef ids = (SOSTransportMessageIDSRef) SOSTransportMessageCreateForSubclass(sizeof(struct __OpaqueSOSTransportMessageIDS) - sizeof(CFRuntimeBase), account, circleName, error); + self = [super init]; - if (ids) { - // Fill in vtable: - ids->m.sendMessages = sendMessages; - ids->m.syncWithPeers = syncWithPeers; - ids->m.flushChanges = flushChanges; - ids->m.cleanupAfterPeerMessages = cleanupAfterPeer; - ids->m.destroy = destroy; - ids->m.handleMessages = handleMessages; - ids->m.getTransportType = getTransportType; - - // Initialize ourselves - - SOSTransportMessageIDSGetIDSDeviceID(account); - SOSRegisterTransportMessage((SOSTransportMessageRef)ids); + if (self) { + self.useFragmentation = kCFBooleanTrue; + self.account = acct; + self.circleName = [[NSString alloc]initWithString:(__bridge NSString*)name]; + [self SOSTransportMessageIDSGetIDSDeviceID:account]; + SOSRegisterTransportMessage((SOSMessage*)self); } - return ids; -} -static void destroy(SOSTransportMessageRef transport){ - SOSUnregisterTransportMessage(transport); + return self; } -static CF_RETURNS_RETAINED CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error) { - return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL); +-(CFDictionaryRef) CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessage*) transport peerMessages:(CFMutableDictionaryRef) circle_peer_messages_table err:(CFErrorRef *)error +{ + return CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); } -static HandleIDSMessageReason checkMessageValidity(SOSAccountRef account, CFStringRef fromDeviceID, CFStringRef fromPeerID, CFStringRef *peerID, SOSPeerInfoRef *theirPeerInfo){ - +static HandleIDSMessageReason checkMessageValidity(SOSAccount* account, CFStringRef fromDeviceID, CFStringRef fromPeerID, CFStringRef *peerID, SOSPeerInfoRef *theirPeerInfo){ + SOSAccountTrustClassic *trust = account.trust; __block HandleIDSMessageReason reason = kHandleIDSMessageDontHandle; - SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) { + SOSCircleForEachPeer(trust.trustedCircle, ^(SOSPeerInfoRef peer) { CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); CFStringRef pID = SOSPeerInfoGetPeerID(peer); @@ -119,8 +100,8 @@ static HandleIDSMessageReason checkMessageValidity(SOSAccountRef account, CFStri return reason; } -HandleIDSMessageReason SOSTransportMessageIDSHandleMessage(SOSAccountRef account, CFDictionaryRef message, CFErrorRef *error) { - +-(HandleIDSMessageReason) SOSTransportMessageIDSHandleMessage:(SOSAccount*)acct m:(CFDictionaryRef) message err:(CFErrorRef *)error +{ secnotice("IDS Transport", "SOSTransportMessageIDSHandleMessage!"); CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII); @@ -142,25 +123,25 @@ HandleIDSMessageReason SOSTransportMessageIDSHandleMessage(SOSAccountRef account require_action_quiet(fromPeerID, exit, result = kHandleIDSMessageDontHandle); require_action_quiet(messageData && CFDataGetLength(messageData) != 0, exit, result = kHandleIDSMessageDontHandle); require_action_quiet(SOSAccountHasFullPeerInfo(account, error), exit, result = kHandleIDSMessageNotReady); - require_action_quiet(ourPeerID && CFEqualSafe(ourPeerID, SOSAccountGetMyPeerID(account)), exit, result = kHandleIDSMessageDontHandle; secnotice("IDS Transport","ignoring message for: %@", ourPeerID)); + require_action_quiet(ourPeerID && [account.peerID isEqual: (__bridge NSString*) ourPeerID], exit, result = kHandleIDSMessageDontHandle; secnotice("IDS Transport","ignoring message for: %@", ourPeerID)); require_quiet((result = checkMessageValidity( account, fromDeviceID, fromPeerID, &peerID, &theirPeer)) == kHandleIDSMessageSuccess, exit); - if (SOSTransportMessageHandlePeerMessage(account->ids_message_transport, peerID, messageData, error)) { + if ([account.ids_message_transport SOSTransportMessageHandlePeerMessage:account.ids_message_transport id:peerID cm:messageData err:error]) { CFMutableDictionaryRef peersToSyncWith = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); CFSetAddValue(peerIDs, peerID); - + SOSAccountTrustClassic* trust = account.trust; //sync using fragmentation? - if(SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(account->my_identity), theirPeer)){ + if(SOSPeerInfoShouldUseIDSMessageFragmentation(trust.peerInfo, theirPeer)){ //set useFragmentation bit - SOSTransportMessageIDSSetFragmentationPreference(account->ids_message_transport, kCFBooleanTrue); + [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref: kCFBooleanTrue]; } else{ - SOSTransportMessageIDSSetFragmentationPreference(account->ids_message_transport, kCFBooleanFalse); + [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref: kCFBooleanFalse]; } - if(!SOSTransportMessageSyncWithPeers(account->ids_message_transport, peerIDs, error)){ + if(![account.ids_message_transport SOSTransportMessageSyncWithPeers:account.ids_message_transport p:peerIDs err:error]){ secerror("SOSTransportMessageIDSHandleMessage Could not sync with all peers: %@", *error); }else{ secnotice("IDS Transport", "Synced with all peers!"); @@ -196,7 +177,7 @@ exit: } -static bool sendToPeer(SOSTransportMessageRef transport, bool shouldUseAckModel, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID,CFDictionaryRef message, CFErrorRef *error) +static bool sendToPeer(SOSMessageIDS* transport, bool shouldUseAckModel, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID,CFDictionaryRef message, CFErrorRef *error) { __block bool success = false; CFStringRef errorMessage = NULL; @@ -204,15 +185,30 @@ static bool sendToPeer(SOSTransportMessageRef transport, bool shouldUseAckModel, CFStringRef operation = NULL; CFDataRef operationData = NULL; CFMutableDataRef mutableData = NULL; - SOSAccountRef account = SOSTransportMessageGetAccount(transport); - CFStringRef ourPeerID = SOSPeerInfoGetPeerID(SOSAccountGetMyPeerInfo(account)); + SOSAccount* account = [transport SOSTransportMessageGetAccount]; + CFStringRef ourPeerID = SOSPeerInfoGetPeerID(account.peerInfo); CFStringRef operationToString = NULL; CFDictionaryRef messagetoSend = NULL; - require_action_quiet((deviceID != NULL && CFStringGetLength(deviceID) >0), fail, errorMessage = CFSTR("Need an IDS Device ID to sync")); + if(deviceID == NULL || CFStringGetLength(deviceID) == 0){ + errorMessage = CFSTR("Need an IDS Device ID to sync"); + userInfo = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kCFErrorLocalizedDescriptionKey, errorMessage, NULL); + if(error != NULL){ + *error =CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoDeviceID, userInfo); + secerror("%@", *error); + } + CFReleaseNull(messagetoSend); + CFReleaseNull(operation); + CFReleaseNull(operationData); + CFReleaseNull(mutableData); + CFReleaseNull(userInfo); + CFReleaseNull(operationToString); + + return success; + } - if(CFDictionaryGetValue(message, kIDSOperationType) == NULL && SOSTransportMessageIDSGetFragmentationPreference(transport) == kCFBooleanTrue){ + if(CFDictionaryGetValue(message, kIDSOperationType) == NULL && [transport SOSTransportMessageIDSGetFragmentationPreference:transport] == kCFBooleanTrue){ //handle a keychain data blob using fragmentation! secnotice("IDS Transport","sendToPeer: using fragmentation!"); @@ -237,28 +233,27 @@ static bool sendToPeer(SOSTransportMessageRef transport, bool shouldUseAckModel, } dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); - dispatch_retain(wait_for); // Both this scope and the block own it. - - secnotice("ids transport", "Starting"); + + secnotice("IDS Transport", "Starting"); - SOSCloudKeychainSendIDSMessage(messagetoSend, deviceID, ourPeerID, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), SOSTransportMessageIDSGetFragmentationPreference(transport), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { + SOSCloudKeychainSendIDSMessage(messagetoSend, deviceID, ourPeerID, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [transport SOSTransportMessageIDSGetFragmentationPreference:transport], ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { success = (sync_error == NULL); if (sync_error && error) { CFRetainAssign(*error, sync_error); } dispatch_semaphore_signal(wait_for); - dispatch_release(wait_for); }); - dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); - dispatch_release(wait_for); - + if (dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2)) != 0) { + secerror("IDS Transport: timed out waiting for message send to complete"); + } + if(!success){ if(error != NULL) - secerror("Failed to send message to peer! %@", *error); + secerror("IDS Transport: Failed to send message to peer! %@", *error); else - secerror("Failed to send message to peer"); + secerror("IDS Transport: Failed to send message to peer"); } else{ secnotice("IDS Transport", "Sent message to peer!"); @@ -270,46 +265,33 @@ static bool sendToPeer(SOSTransportMessageRef transport, bool shouldUseAckModel, CFReleaseNull(mutableData); CFReleaseNull(operationToString); return success; - -fail: - userInfo = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kCFErrorLocalizedDescriptionKey, errorMessage, NULL); - if(error != NULL){ - *error =CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoDeviceID, userInfo); - secerror("%@", *error); - } - CFReleaseNull(messagetoSend); - CFReleaseNull(operation); - CFReleaseNull(operationData); - CFReleaseNull(mutableData); - CFReleaseNull(userInfo); - CFReleaseNull(operationToString); - - return success; } -static bool syncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error) { +-(bool) SOSTransportMessageSyncWithPeers:(SOSMessageIDS*) transport p:(CFSetRef) peers err:(CFErrorRef *)error +{ // Each entry is keyed by circle name and contains a list of peerIDs __block bool result = true; CFSetForEach(peers, ^(const void *value) { CFStringRef peerID = asString(value, NULL); - result &= SOSTransportMessageSendMessageIfNeeded(transport, transport->circleName, peerID, error); + + result &= [transport SOSTransportMessageSendMessageIfNeeded:transport id:(__bridge CFStringRef)(transport.circleName) pID:peerID err:error]; }); return result; } -static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef peersToMessage, CFErrorRef *error) { +-(bool) SOSTransportMessageSendMessages:(SOSMessageIDS*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error +{ __block bool result = true; - SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(transport->account); + SOSPeerInfoRef myPeer = transport->account.peerInfo; CFStringRef myID = SOSPeerInfoGetPeerID(myPeer); - require_quiet(myPeer, fail); + if(!myPeer) + return result; - CFStringRef circleName = transport->circleName; - - CFDictionaryForEach(peersToMessage, ^(const void *key, const void *value) { + CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) { CFErrorRef error = NULL; SOSPeerInfoRef peer = NULL; @@ -337,11 +319,11 @@ static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef peers deviceID = SOSPeerInfoCopyDeviceID(peer); require_action_quiet(deviceID, skip, SOSErrorCreate(kSOSErrorSendFailure, &error, NULL, CFSTR("No IDS ID"))); - SOSTransportMessageIDSSetFragmentationPreference(transport, - SOSPeerInfoShouldUseIDSMessageFragmentation(myPeer, peer) ? kCFBooleanTrue : kCFBooleanFalse); + [transport SOSTransportMessageIDSSetFragmentationPreference:transport + pref:SOSPeerInfoShouldUseIDSMessageFragmentation(myPeer, peer) ? kCFBooleanTrue : kCFBooleanFalse]; bool shouldUseAckModel = SOSPeerInfoShouldUseACKModel(myPeer, peer); - result &= sendToPeer(transport, shouldUseAckModel, circleName, deviceID, peerID, message, &error); + result &= sendToPeer(transport, shouldUseAckModel, (__bridge CFStringRef)(transport.circleName), deviceID, peerID, message, &error); skip: if (error) { @@ -355,23 +337,24 @@ static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef peers CFReleaseNull(error); }); -fail: return result; } -static bool flushChanges(SOSTransportMessageRef transport, CFErrorRef *error) +-(bool) SOSTransportMessageFlushChanges:(SOSMessageIDS*) transport err:(CFErrorRef *)error { return true; } -static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error) +-(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageIDS*) transport peers:(CFDictionaryRef) peers err:(CFErrorRef*) error { return true; } -bool SOSTransportMessageIDSGetIDSDeviceID(SOSAccountRef account){ - CFStringRef deviceID = SOSPeerInfoCopyDeviceID(SOSFullPeerInfoGetPeerInfo(account->my_identity)); +-(bool) SOSTransportMessageIDSGetIDSDeviceID:(SOSAccount*)acct +{ + SOSAccountTrustClassic* trust = acct.trust; + CFStringRef deviceID = SOSPeerInfoCopyDeviceID(trust.peerInfo); bool hasDeviceID = deviceID != NULL && CFStringGetLength(deviceID) != 0; CFReleaseNull(deviceID); @@ -389,3 +372,4 @@ bool SOSTransportMessageIDSGetIDSDeviceID(SOSAccountRef account){ return hasDeviceID; } +@end diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.c deleted file mode 100644 index de46ddae..00000000 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.c +++ /dev/null @@ -1,277 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct __OpaqueSOSTransportMessageKVS { - struct __OpaqueSOSTransportMessage m; - CFMutableDictionaryRef pending_changes; - -}; - -// -// V-table implementation forward declarations -// -static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error); -static bool syncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error); -static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef peersToMessage, CFErrorRef *error); -static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error); -static void destroy(SOSTransportMessageRef transport); -static inline CFIndex getTransportType(SOSTransportMessageRef transport, CFErrorRef *error); - -static CF_RETURNS_RETAINED -CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error); - -static bool flushChanges(SOSTransportMessageRef transport, CFErrorRef *error); - -SOSTransportMessageKVSRef SOSTransportMessageKVSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){ - SOSTransportMessageKVSRef tkvs = (SOSTransportMessageKVSRef) SOSTransportMessageCreateForSubclass(sizeof(struct __OpaqueSOSTransportMessageKVS) - sizeof(CFRuntimeBase), account, circleName, error); - - if (tkvs) { - // Fill in vtable: - tkvs->m.sendMessages = sendMessages; - tkvs->m.syncWithPeers = syncWithPeers; - tkvs->m.flushChanges = flushChanges; - tkvs->m.cleanupAfterPeerMessages = cleanupAfterPeer; - tkvs->m.destroy = destroy; - tkvs->m.handleMessages = handleMessages; - tkvs->m.getTransportType = getTransportType; - // Initialize ourselves - tkvs->pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSRegisterTransportMessage((SOSTransportMessageRef)tkvs); - } - - return tkvs; -} - -bool SOSTransportMessageKVSAppendKeyInterest(SOSTransportMessageKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *localError){ - SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport); - require_quiet(engine, fail); - - CFArrayRef peerInfos = SOSAccountCopyPeersToListenTo(SOSTransportMessageGetAccount((SOSTransportMessageRef) transport), localError); - - if(peerInfos){ - CFArrayForEach(peerInfos, ^(const void *value) { - SOSPeerInfoRef peer = (SOSPeerInfoRef)value; - CFStringRef peerID = SOSPeerInfoGetPeerID(peer); - CFStringRef peerMessage = SOSMessageKeyCreateFromPeerToTransport((SOSTransportMessageRef)transport, peerID); - if(peerMessage != NULL) - CFArrayAppendValue(unlockedKeys, peerMessage); - CFReleaseNull(peerMessage); - }); - CFReleaseNull(peerInfos); - } - return true; -fail: - return false; -} -static void destroy(SOSTransportMessageRef transport){ - SOSTransportMessageKVSRef tkvs = (SOSTransportMessageKVSRef)transport; - CFReleaseNull(tkvs->pending_changes); - SOSUnregisterTransportMessage((SOSTransportMessageRef)tkvs); - -} - -static inline CFIndex getTransportType(SOSTransportMessageRef transport, CFErrorRef *error){ - return kKVS; -} - -static bool SOSTransportMessageKVSUpdateKVS(SOSTransportMessageKVSRef transport, CFDictionaryRef changes, CFErrorRef *error){ - - 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); - return true; -} - -static bool SOSTransportMessageKVSSendPendingChanges(SOSTransportMessageKVSRef transport, CFErrorRef *error) { - CFErrorRef changeError = NULL; - - if (transport->pending_changes == NULL || CFDictionaryGetCount(transport->pending_changes) == 0) { - CFReleaseNull(transport->pending_changes); - return true; - } - SOSAccountRef account = SOSTransportMessageGetAccount((SOSTransportMessageRef)transport); - CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error); - - if(dsid == NULL) - dsid = kCFNull; - - CFDictionaryAddValue(transport->pending_changes, kSOSKVSRequiredKey, dsid); - - bool success = SOSTransportMessageKVSUpdateKVS(transport, transport->pending_changes, &changeError); - if (success) { - CFDictionaryRemoveAllValues(transport->pending_changes); - } else { - SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL, - CFSTR("Send changes block failed [%@]"), transport->pending_changes); - } - - return success; -} - -static void SOSTransportMessageKVSAddToPendingChanges(SOSTransportMessageKVSRef transport, CFStringRef message_key, CFDataRef message_data){ - if (transport->pending_changes == NULL) { - transport->pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - } - if (message_data == NULL) { - CFDictionarySetValue(transport->pending_changes, message_key, kCFNull); - } else { - CFDictionarySetValue(transport->pending_changes, message_key, message_data); - } -} - -static bool SOSTransportMessageKVSCleanupAfterPeerMessages(SOSTransportMessageKVSRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error) -{ - CFArrayRef enginePeers = SOSEngineGetPeerIDs(SOSTransportMessageGetEngine((SOSTransportMessageRef)transport)); - __block SOSAccountRef account = SOSTransportMessageGetAccount((SOSTransportMessageRef)transport); - - CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) { - if (isString(key) && isArray(value)) { - CFStringRef circle_name = (CFStringRef) key; - CFArrayRef peers_to_cleanup_after = (CFArrayRef) value; - - CFArrayForEach(peers_to_cleanup_after, ^(const void *value) { - if (isString(value)) { - CFStringRef cleanup_id = (CFStringRef) value; - // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers - if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) { - if (isString(value)) { - CFStringRef in_circle_id = (CFStringRef) value; - - CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id); - SOSTransportMessageKVSAddToPendingChanges(transport, kvsKey, NULL); - CFReleaseSafe(kvsKey); - - CFStringRef lastCirclePushedKey = SOSLastCirclePushedKeyCreateWithCircleNameAndPeerID(circle_name, cleanup_id); - SOSTransportMessageKVSAddToPendingChanges(transport, lastCirclePushedKey, NULL); - CFReleaseSafe(lastCirclePushedKey); - - CFStringRef lastKeyParameterPushedKey = SOSLastKeyParametersPushedKeyCreateWithPeerID(cleanup_id); - SOSTransportMessageKVSAddToPendingChanges(transport, lastKeyParameterPushedKey, NULL); - CFReleaseSafe(lastKeyParameterPushedKey); - - CFStringRef lastCirclePushedWithAccountGestaltKey = SOSLastCirclePushedKeyCreateWithAccountGestalt(account); - SOSTransportMessageKVSAddToPendingChanges(transport, lastCirclePushedKey, NULL); - CFReleaseSafe(lastCirclePushedWithAccountGestaltKey); - - CFStringRef lastKeyParameterWithAccountGestaltKey = SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(account); - SOSTransportMessageKVSAddToPendingChanges(transport, lastCirclePushedKey, NULL); - CFReleaseSafe(lastKeyParameterWithAccountGestaltKey); - - kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id); - SOSTransportMessageKVSAddToPendingChanges(transport, kvsKey, NULL); - CFReleaseSafe(kvsKey); - } - }); - - } - }); - } - }); - - return SOSTransportMessageFlushChanges((SOSTransportMessageRef)transport, error); -} - -static CF_RETURNS_RETAINED -CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error) { - - CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryRef peerToMessage = CFDictionaryGetValue(circle_peer_messages_table, transport->circleName); - CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - - if(peerToMessage){ - CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) { - CFStringRef peer_id = asString(key, NULL); - CFDataRef peer_message = asData(value, NULL); - CFErrorRef localError = NULL; - - if (peer_id && peer_message && SOSTransportMessageHandlePeerMessage(transport, peer_id, peer_message, &localError)) { - CFArrayAppendValue(handled_peers, key); - } else { - secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError); - } - CFReleaseNull(localError); - }); - } - CFDictionaryAddValue(handled, transport->circleName, handled_peers); - CFReleaseNull(handled_peers); - - return handled; -} - - -static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) { - SOSTransportMessageKVSRef kvsTransport = (SOSTransportMessageKVSRef) transport; - bool result = true; - SOSAccountRef account = SOSTransportMessageGetAccount((SOSTransportMessageRef)transport); - CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error); - - if(dsid == NULL) - dsid = kCFNull; - - CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer((SOSTransportMessageRef)kvsTransport, peerID); - - CFTypeRef messageToSend = message != NULL ? (CFTypeRef) message : (CFTypeRef) kCFNull; - CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, - message_to_peer_key, messageToSend, - kSOSKVSRequiredKey, dsid, - NULL); - - if (!SOSTransportMessageKVSUpdateKVS(kvsTransport, a_message_to_a_peer, error)) { - secerror("Sync with peers failed to send to %@ [%@], %@", peerID, a_message_to_a_peer, *error); - result = false; - } - CFReleaseNull(a_message_to_a_peer); - CFReleaseNull(message_to_peer_key); - - return result; -} - -static bool syncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error) { - // Each entry is keyed by circle name and contains a list of peerIDs - __block bool result = true; - - CFSetForEach(peers, ^(const void *value) { - CFStringRef peerID = asString(value, NULL); - result &= SOSTransportMessageSendMessageIfNeeded(transport, transport->circleName, peerID, error); - }); - - return result; -} - -static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef peersToMessage, CFErrorRef *error) { - __block bool result = true; - - CFStringRef circleName = transport->circleName; - CFDictionaryForEach(peersToMessage, ^(const void *key, const void *value) { - CFStringRef peerID = asString(key, NULL); - CFDataRef message = asData(value,NULL); - if (peerID && message) { - bool rx = sendToPeer(transport, circleName, peerID, message, error); - result &= rx; - } - }); - - return true; -} - -static bool flushChanges(SOSTransportMessageRef transport, CFErrorRef *error) -{ - return SOSTransportMessageKVSSendPendingChanges((SOSTransportMessageKVSRef) transport, error); -} - -static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error) -{ - return SOSTransportMessageKVSCleanupAfterPeerMessages((SOSTransportMessageKVSRef) transport, circle_to_peer_ids, error); -} - diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.h index 006dc559..7ebfa435 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.h @@ -2,23 +2,22 @@ #ifndef sec_SOSTransportMessageKVS_h #define sec_SOSTransportMessageKVS_h -#include - -// -// KVS Stuff -// - -typedef struct __OpaqueSOSTransportMessageKVS *SOSTransportMessageKVSRef; - -SOSTransportMessageKVSRef SOSTransportMessageKVSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error); - -// -// Key interests -// - - -bool SOSTransportMessageKVSAppendKeyInterest(SOSTransportMessageKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *localError); - -bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error); - +#include +#import +@class SOSMessage; + +@interface SOSMessageKVS : SOSMessage +{ + CFMutableDictionaryRef pending_changes; +} +@property (atomic) CFMutableDictionaryRef pending_changes; + +-(CFIndex) SOSTransportMessageGetTransportType; +-(CFStringRef) SOSTransportMessageGetCircleName; +-(CFTypeRef) SOSTransportMessageGetEngine; +-(SOSAccount*) SOSTransportMessageGetAccount; +-(bool) SOSTransportMessageKVSAppendKeyInterest:(SOSMessageKVS*) transport ak:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef) afterFirstUnlockKeys + unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)localError; + +@end #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.m new file mode 100644 index 00000000..c398e55c --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageKVS.m @@ -0,0 +1,258 @@ +#include +#import +#import +#include +#include +#include +#include +#include + +@implementation SOSMessageKVS + +@synthesize pending_changes = pending_changes; + +-(id) initWithAccount:(SOSAccount*)acct andName:(NSString*)name +{ + self = [super init]; + + if (self) { + account = acct; + circleName = [[NSString alloc]initWithString:name]; + SOSEngineRef e = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, (__bridge CFStringRef)(circleName), NULL); + engine = e; + pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + SOSRegisterTransportMessage((SOSMessage*)self); + } + + return self; +} + +-(CFIndex) SOSTransportMessageGetTransportType +{ + return kKVS; +} +-(CFStringRef) SOSTransportMessageGetCircleName +{ + return (__bridge CFStringRef)circleName; +} +-(CFTypeRef) SOSTransportMessageGetEngine +{ + return engine; +} +-(SOSAccount*) SOSTransportMessageGetAccount +{ + return account; +} + +-(bool) SOSTransportMessageKVSAppendKeyInterest:(SOSMessageKVS*) transport ak:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef) afterFirstUnlockKeys + unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)localError +{ + require_quiet(engine, fail); + + CFArrayRef peerInfos = SOSAccountCopyPeersToListenTo( [self SOSTransportMessageGetAccount], localError); + + if(peerInfos){ + NSString* myID = self.account.peerID; + + CFArrayForEach(peerInfos, ^(const void *value) { + CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value); + CFStringRef peerMessage = SOSMessageKeyCreateFromPeerToTransport(transport,(__bridge CFStringRef) myID, peerID); + if(peerMessage != NULL) + CFArrayAppendValue(unlockedKeys, peerMessage); + CFReleaseNull(peerMessage); + }); + CFReleaseNull(peerInfos); + } + return true; +fail: + return false; +} + + +-(CFIndex) SOSTransportMessageGetTransportType:(SOSMessage*) transport err:(CFErrorRef *)error +{ + return kKVS; +} + +static bool SOSTransportMessageKVSUpdateKVS(SOSMessageKVS* transport, CFDictionaryRef changes, CFErrorRef *error){ + + 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); + return true; +} + +static bool SOSTransportMessageKVSSendPendingChanges(SOSMessageKVS* transport, CFErrorRef *error) { + CFErrorRef changeError = NULL; + + if (transport->pending_changes == NULL || CFDictionaryGetCount(transport->pending_changes) == 0) { + CFReleaseNull(transport->pending_changes); + return true; + } + SOSAccount* acct = [transport SOSTransportMessageGetAccount]; + CFTypeRef dsid = SOSAccountGetValue(acct, kSOSDSIDKey, error); + + if(dsid == NULL) + dsid = kCFNull; + + CFDictionaryAddValue(transport->pending_changes, kSOSKVSRequiredKey, dsid); + + bool success = SOSTransportMessageKVSUpdateKVS(transport, transport->pending_changes, &changeError); + if (success) { + CFDictionaryRemoveAllValues(transport->pending_changes); + } else { + SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL, + CFSTR("Send changes block failed [%@]"), transport->pending_changes); + } + + return success; +} + +static void SOSTransportMessageKVSAddToPendingChanges(SOSMessageKVS* transport, CFStringRef message_key, CFDataRef message_data){ + if (transport.pending_changes == NULL) { + transport.pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + } + if (message_data == NULL) { + CFDictionarySetValue(transport.pending_changes, message_key, kCFNull); + } else { + CFDictionarySetValue(transport.pending_changes, message_key, message_data); + } +} + +static bool SOSTransportMessageKVSCleanupAfterPeerMessages(SOSMessageKVS* transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error) +{ + CFArrayRef enginePeers = SOSEngineGetPeerIDs((SOSEngineRef)[transport SOSTransportMessageGetEngine]); + + CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) { + if (isString(key) && isArray(value)) { + CFStringRef circle_name = (CFStringRef) key; + CFArrayRef peers_to_cleanup_after = (CFArrayRef) value; + + CFArrayForEach(peers_to_cleanup_after, ^(const void *value) { + if (isString(value)) { + CFStringRef cleanup_id = (CFStringRef) value; + // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers + if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) { + if (isString(value)) { + CFStringRef in_circle_id = (CFStringRef) value; + + CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id); + SOSTransportMessageKVSAddToPendingChanges(transport, kvsKey, NULL); + CFReleaseSafe(kvsKey); + + kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id); + SOSTransportMessageKVSAddToPendingChanges(transport, kvsKey, NULL); + CFReleaseSafe(kvsKey); + } + }); + + } + }); + } + }); + + return [transport SOSTransportMessageFlushChanges:(SOSMessage*)transport err:error]; +} + +-(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessage*) transport peers:(CFDictionaryRef) peers err:(CFErrorRef*) error +{ + return SOSTransportMessageKVSCleanupAfterPeerMessages((SOSMessageKVS*) transport, peers, error); +} + +-(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessage*) transport peerMessages:(CFMutableDictionaryRef) circle_peer_messages_table err:(CFErrorRef *)error +{ + CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryRef peerToMessage = CFDictionaryGetValue(circle_peer_messages_table, (__bridge CFStringRef)(transport.circleName)); + CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + if(peerToMessage){ + CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) { + CFStringRef peer_id = asString(key, NULL); + CFDataRef peer_message = asData(value, NULL); + CFErrorRef localError = NULL; + + if (peer_id && peer_message && [transport SOSTransportMessageHandlePeerMessage:transport id:peer_id cm:peer_message err:&localError ]) { + CFArrayAppendValue(handled_peers, key); + } else { + secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError); + } + CFReleaseNull(localError); + }); + } + CFDictionaryAddValue(handled, (__bridge const void *)(transport.circleName), handled_peers); + CFReleaseNull(handled_peers); + + return handled; +} + + +static bool sendToPeer(SOSMessage* transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) +{ + SOSMessageKVS* kvsTransport = (SOSMessageKVS*) transport; + bool result = true; + SOSAccount* account = [transport SOSTransportMessageGetAccount]; + CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error); + + if(dsid == NULL) + dsid = kCFNull; + NSString* myID = account.peerID; + CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(kvsTransport, (__bridge CFStringRef) myID, peerID); + + CFTypeRef messageToSend = message != NULL ? (CFTypeRef) message : (CFTypeRef) kCFNull; + CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, + message_to_peer_key, messageToSend, + kSOSKVSRequiredKey, dsid, + NULL); + + if (!SOSTransportMessageKVSUpdateKVS(kvsTransport, a_message_to_a_peer, error)) { + secerror("Sync with peers failed to send to %@ [%@], %@", peerID, a_message_to_a_peer, *error); + result = false; + } + CFReleaseNull(a_message_to_a_peer); + CFReleaseNull(message_to_peer_key); + + return result; +} + +-(bool) SOSTransportMessageSyncWithPeers:(SOSMessage*) transport p:(CFSetRef) peers err:(CFErrorRef *)error +{ + // Each entry is keyed by circle name and contains a list of peerIDs + __block bool result = true; + + CFSetForEach(peers, ^(const void *value) { + CFStringRef peerID = asString(value, NULL); + + result &= [ transport SOSTransportMessageSendMessageIfNeeded:transport id:(__bridge CFStringRef)(transport.circleName) pID:peerID err:error]; + }); + + return result; +} + +-(bool) SOSTransportMessageSendMessages:(SOSMessage*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error +{ + __block bool result = true; + + CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) { + CFStringRef peerID = asString(key, NULL); + CFDataRef message = asData(value,NULL); + if (peerID && message) { + bool rx = sendToPeer(transport, (__bridge CFStringRef)(transport.circleName), peerID, message, error); + result &= rx; + } + }); + + return true; +} + +-(bool) SOSTransportMssageFlushChanges:(SOSMessage*) transport err:(CFErrorRef *)error +{ + return SOSTransportMessageKVSSendPendingChanges((SOSMessageKVS*) transport, error); +} + +@end + + diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSTypes.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSTypes.h index e14e4cf0..3736f5ac 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSTypes.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSTypes.h @@ -46,6 +46,27 @@ typedef enum HandleIDSMessageReason { kHandleIDSmessageDeviceIDMismatch } HandleIDSMessageReason; +/* + * Piggy backing codes + */ + +typedef enum{ + kPiggyV0 = 0, + kPiggyV1 = 1, +} PiggyBackProtocolVersion; + +typedef enum{ + kPiggyTLKs = 0, + kPiggyiCloudIdentities = 1 +} PiggybackKeyTypes; + +typedef enum { + kTLKUnknown = 0, + kTLKManatee = 1, + kTLKEngram = 2, + kTLKAutoUnlock = 3, + kTLKHealth = 4, +} kTLKTypes; /* View Result Codes @@ -96,6 +117,40 @@ enum { }; typedef int SOSSecurityPropertyActionCode; +#if __OBJC__ + +#import + +#define SOSControlInitialSyncFlagTLK 1 +#define SOSControlInitialSyncFlagPCS 2 +#define SOSControlInitialSyncFlagPCSNonCurrent 4 + +@protocol SOSControlProtocol +- (void)userPublicKey:(void ((^))(BOOL trusted, NSData *spki, NSError *error))complete; +- (void)kvsPerformanceCounters:(void(^)(NSDictionary *))reply; +- (void)idsPerformanceCounters:(void(^)(NSDictionary *))reply; +- (void)rateLimitingPerformanceCounters:(void(^)(NSDictionary *))reply; + +- (void)stashedCredentialPublicKey:(void(^)(NSData *, NSError *error))complete; +- (void)assertStashedAccountCredential:(void(^)(BOOL result, NSError *error))complete; +- (void)validatedStashedAccountCredential:(void(^)(NSData *credential, NSError *error))complete; +- (void)stashAccountCredential:(NSData *)credential complete:(void(^)(bool success, NSError *error))complete; + +- (void)myPeerInfo:(void (^)(NSData *, NSError *))complete; +- (void)circleJoiningBlob:(NSData *)applicant complete:(void (^)(NSData *blob, NSError *))complete; +- (void)joinCircleWithBlob:(NSData *)blob version:(PiggyBackProtocolVersion)version complete:(void (^)(bool success, NSError *))complete; +- (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete; +- (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete; + +- (void)triggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete; + +- (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete; +- (void)setWatchdogParmeters:(NSDictionary*)parameters complete:(void (^)(NSError* error))complete; + +@end +#endif + + __END_DECLS #endif diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSUserKeygen.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSUserKeygen.m similarity index 99% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSUserKeygen.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSUserKeygen.m index 3779e516..5734221e 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSUserKeygen.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSUserKeygen.m @@ -168,7 +168,7 @@ static const uint8_t *der_decode_pbkdf2_params(size_t *saltLen, const uint8_t ** static SecKeyRef ccec2SecKey(ccec_full_ctx_t fk) { - size_t export_size = ccec_x963_export_size(1, fk); + size_t export_size = ccec_x963_export_size(1, ccec_ctx_pub(fk)); uint8_t export_keybytes[export_size]; ccec_x963_export(1, export_keybytes, fk); CFDataRef exportedkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, export_keybytes, export_size, kCFAllocatorNull); @@ -311,15 +311,14 @@ void debugDumpUserParameters(CFStringRef message, CFDataRef parameters) CF_RETURNS_RETAINED CFStringRef UserParametersDescription(CFDataRef parameters){ __block CFStringRef description = NULL; - CFErrorRef error = 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("keygen", "failed to decode cloud parameters"); return NULL; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.exp-in b/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.exp-in index 06ffa5c1..5c0b5d43 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.exp-in +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.exp-in @@ -13,14 +13,14 @@ VIEWEXPORT(KeychainV0) // Views with ViewHints #undef DOVIEWMACRO -#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) _kSOSView##VIEWNAME +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) _k##SYSTEM##View##VIEWNAME #include "Security/SecureObjectSync/ViewList.list" // V0 Subviews don't have view hints, they use queries #undef DOVIEWMACRO #define DO_EXPORT_(VIEWNAME) _kSecAttrViewHint##VIEWNAME #define DO_EXPORT_V(VIEWNAME) -#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) DO_EXPORT_##V0SETTING(VIEWNAME) +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) DO_EXPORT_##V0SETTING(VIEWNAME) #include "Security/SecureObjectSync/ViewList.list" #undef DOVIEWMACRO diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.h b/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.h index db10fa3e..0995fa31 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.h +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.h @@ -31,6 +31,7 @@ #include #include #include +#include __BEGIN_DECLS @@ -52,12 +53,13 @@ typedef struct __OpaqueSOSView { typedef enum { - kViewSetAll, + kViewSetAll, // Note that this is not All, but is All SOS views. kViewSetDefault, kViewSetInitial, kViewSetAlwaysOn, kViewSetV0, - kViewSetRequiredForBackup + kViewSetRequiredForBackup, + kViewSetCKKS, } ViewSetKind; CFMutableSetRef SOSViewCopyViewSet(ViewSetKind setKind); @@ -71,6 +73,10 @@ CFSetRef SOSViewsGetV0BackupBagViewSet(void); bool SOSViewsIsV0Subview(CFStringRef viewName); +bool SOSViewInSOSSystem(CFStringRef view); +bool SOSViewHintInSOSSystem(CFStringRef viewHint); +bool SOSViewHintInCKKSSystem(CFStringRef viewHint); + // Basic interfaces to change and query views SOSViewResultCode SOSViewsEnable(SOSPeerInfoRef pi, CFStringRef viewname, CFErrorRef *error); bool SOSViewSetEnable(SOSPeerInfoRef pi, CFSetRef viewSet); @@ -92,6 +98,9 @@ static inline bool SOSPeerInfoIsViewPermitted(SOSPeerInfoRef peerInfo, CFStringR } const char *SOSViewsXlateAction(SOSViewActionCode action); +/* CFSet <-> XPC functions */ +xpc_object_t CreateXPCObjectWithCFSetRef(CFSetRef setref, CFErrorRef *error); + __END_DECLS #endif /* defined(_sec_SOSViews_) */ diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.m similarity index 71% rename from OSX/sec/SOSCircle/SecureObjectSync/SOSViews.c rename to OSX/sec/SOSCircle/SecureObjectSync/SOSViews.m index f7478434..a3065494 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.c +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSViews.m @@ -41,12 +41,14 @@ #include #include #include + +#include #include #include -CFStringRef viewMemError = CFSTR("Failed to get memory for views in PeerInfo"); -CFStringRef viewUnknownError = CFSTR("Unknown view(%@) (ViewResultCode=%d)"); -CFStringRef viewInvalidError = CFSTR("Peer is invalid for this view(%@) (ViewResultCode=%d)"); +#define viewMemError CFSTR("Failed to get memory for views in PeerInfo") +#define viewUnknownError CFSTR("Unknown view(%@) (ViewResultCode=%d)") +#define viewInvalidError CFSTR("Peer is invalid for this view(%@) (ViewResultCode=%d)") // Internal Views: const CFStringRef kSOSViewKeychainV0_tomb = CFSTR("KeychainV0-tomb"); // iCloud Keychain backup for v0 peers (no tombstones) @@ -61,8 +63,8 @@ const CFStringRef kSOSViewOtherSyncable_tomb = CFSTR("OtherSyncable-tomb" const CFStringRef kSOSViewKeychainV0 = CFSTR("KeychainV0"); // iCloud Keychain syncing for v0 peers #undef DOVIEWMACRO -#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) \ -const CFStringRef kSOSView##VIEWNAME = CFSTR(DEFSTRING); +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) \ +const CFStringRef k##SYSTEM##View##VIEWNAME = CFSTR(DEFSTRING); #include "Security/SecureObjectSync/ViewList.list" // View Hints @@ -86,6 +88,7 @@ const CFStringRef kSOSViewHintHomeKit = CFSTR("HomeKit"); CFMutableSetRef SOSViewCopyViewSet(ViewSetKind setKind) { CFMutableSetRef result = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + // Only return views in the SOS system, unless they asked for kViewSetCKKS #undef DOVIEWMACRO #define __TYPE_MEMBER_ false #define __TYPE_MEMBER_D true @@ -93,21 +96,82 @@ CFMutableSetRef SOSViewCopyViewSet(ViewSetKind setKind) { #define __TYPE_MEMBER_A true #define __TYPE_MEMBER_V true #define __TYPE_MEMBER_B true -#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \ - if ((setKind == kViewSetAll) || \ +#define __SYSTEM_SOS true +#define __SYSTEM_CKKS false + +#define DOVIEWMACRO_SOS(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \ + if(((setKind == kViewSetAll) || \ ((setKind == kViewSetDefault) && __TYPE_MEMBER_##DEFAULT) || \ ((setKind == kViewSetInitial) && __TYPE_MEMBER_##INITIAL) || \ ((setKind == kViewSetAlwaysOn) && __TYPE_MEMBER_##ALWAYSON) || \ ((setKind == kViewSetRequiredForBackup) && __TYPE_MEMBER_##BACKUP) || \ - ((setKind == kViewSetV0) && __TYPE_MEMBER_##V0) ) { \ - CFSetAddValue(result, kSOSView##VIEWNAME); \ + ((setKind == kViewSetV0) && __TYPE_MEMBER_##V0) )) { \ + CFSetAddValue(result, k##SYSTEM##View##VIEWNAME); \ + } + +#define DOVIEWMACRO_CKKS(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \ + if(setKind == kViewSetCKKS) { \ + CFSetAddValue(result, k##SYSTEM##View##VIEWNAME); \ } +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \ +DOVIEWMACRO_##SYSTEM(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) #include "Security/SecureObjectSync/ViewList.list" return result; } +bool SOSViewInSOSSystem(CFStringRef view) { + + if(CFEqualSafe(view, kSOSViewKeychainV0)) { + return true; + } + +#undef DOVIEWMACRO +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \ + if(CFEqualSafe(view, k##SYSTEM##View##VIEWNAME)) { \ + return __SYSTEM_##SYSTEM; \ + } +#include "Security/SecureObjectSync/ViewList.list" + + return false; +} + +bool SOSViewHintInSOSSystem(CFStringRef viewHint) { +#undef DOVIEWMACRO +#define CHECK_VIEWHINT_(VIEWNAME, SYSTEM) \ + if(CFEqualSafe(viewHint, kSecAttrViewHint##VIEWNAME)) { \ + return __SYSTEM_##SYSTEM; \ + } +#define CHECK_VIEWHINT_V(VIEWNAME, SYSTEM) + +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \ +CHECK_VIEWHINT_##V0(VIEWNAME, SYSTEM) +#include "Security/SecureObjectSync/ViewList.list" + + return false; +} + +bool SOSViewHintInCKKSSystem(CFStringRef viewHint) { + +#undef DOVIEWMACRO_SOS +#undef DOVIEWMACRO_CKKS +#undef DOVIEWMACRO + +#define DOVIEWMACRO_SOS(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) +#define DOVIEWMACRO_CKKS(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \ +if(CFEqualSafe(viewHint, kSecAttrViewHint##VIEWNAME)) { \ + return true; \ +} +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) \ +DOVIEWMACRO_##SYSTEM(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULT, INITIAL, ALWAYSON, BACKUP, V0) + +#include "Security/SecureObjectSync/ViewList.list" + + return false; +} + + CFGiblisGetSingleton(CFSetRef, SOSViewsGetV0ViewSet, defaultViewSet, ^{ // Since peer->views must never be NULL, fill in with a default const void *values[] = { kSOSViewKeychainV0 }; @@ -188,12 +252,8 @@ static bool SOSViewsIsKnownView(CFStringRef viewname) { return false; } -static bool viewErrorReport(CFIndex errorCode, CFErrorRef *error, CFStringRef format, CFStringRef viewname, int retval) { - return SOSCreateErrorWithFormat(errorCode, NULL, error, NULL, format, viewname, retval); -} - static bool SOSViewsRequireIsKnownView(CFStringRef viewname, CFErrorRef* error) { - return SOSViewsIsKnownView(viewname) || viewErrorReport(kSOSErrorNameMismatch, error, viewUnknownError, viewname, kSOSCCNoSuchView); + return SOSViewsIsKnownView(viewname) || SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL, viewUnknownError, viewname, kSOSCCNoSuchView); } bool SOSPeerInfoIsEnabledView(SOSPeerInfoRef pi, CFStringRef viewName) { @@ -251,7 +311,7 @@ SOSViewResultCode SOSViewsEnable(SOSPeerInfoRef pi, CFStringRef viewname, CFErro require_action_quiet(SOSViewsRequireIsKnownView(viewname, error), fail, retval = kSOSCCNoSuchView); require_action_quiet(SOSPeerInfoViewIsValid(pi, viewname), fail, - viewErrorReport(kSOSErrorNameMismatch, error, viewInvalidError, viewname, retval = kSOSCCViewNotQualified)); + SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL, viewInvalidError, viewname, retval = kSOSCCViewNotQualified)); CFSetAddValue(newviews, viewname); SOSPeerInfoSetViews(pi, newviews); CFReleaseSafe(newviews); @@ -363,113 +423,10 @@ fail: return retval; } -static CFArrayRef SOSCreateActiveViewIntersectionArrayForPeerInfos(SOSPeerInfoRef pi1, SOSPeerInfoRef pi2) { - CFMutableArrayRef retval = NULL; - CFSetRef views1 = SOSPeerInfoCopyEnabledViews(pi1); - CFSetRef views2 = SOSPeerInfoCopyEnabledViews(pi2); - size_t count = CFSetGetCount(views1); - if(count == 0){ - CFReleaseNull(views1); - CFReleaseNull(views2); - return NULL; - } - CFStringRef pi1views[count]; - - retval = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFSetGetValues(views1, (const void **) &pi1views); - for(size_t i = 0; i < count; i++) { - if(CFSetContainsValue(views2, pi1views[i])) { - CFArrayAppendValue(retval, pi1views[i]); - } - } - CFReleaseNull(views1); - CFReleaseNull(views2); - - return retval; -} - -CFArrayRef SOSCreateActiveViewIntersectionArrayForPeerID(SOSAccountRef account, CFStringRef peerID) { - CFArrayRef retval = NULL; - SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account); - SOSPeerInfoRef theirPI = SOSAccountCopyPeerWithID(account, peerID, NULL); - require_action_quiet(myPI, errOut, retval = NULL); - require_action_quiet(theirPI, errOut, retval = NULL); - - retval = SOSCreateActiveViewIntersectionArrayForPeerInfos(myPI, theirPI); - -errOut: - CFReleaseNull(theirPI); - return retval; -} - -// This needs to create a dictionary of sets of intersected views for an account -CFDictionaryRef SOSViewsCreateActiveViewMatrixDictionary(SOSAccountRef account, SOSCircleRef circle, CFErrorRef *error) { - CFMutableDictionaryRef retval = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account); - - // For now, all views require that a valid member peer is in the circle and active/valid - CFMutableSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault); - - require_action_quiet(retval, errOut, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("Could not allocate ViewMatrix"), NULL, error)); - require_action_quiet(myPI, errOut, SOSCreateError(kSOSErrorPeerNotFound, CFSTR("Could not find our PeerInfo"), NULL, error)); - require(peers, errOut); - - CFSetRef myViews = SOSPeerInfoCopyEnabledViews(myPI); - - if (myViews) - CFSetForEach(myViews, ^(const void *value) { - CFStringRef viewname = (CFStringRef) value; - CFMutableSetRef viewset = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); - CFSetForEach(peers, ^(const void *peervalue) { - SOSPeerInfoRef pi = (SOSPeerInfoRef) peervalue; - CFSetRef piViews = SOSPeerInfoCopyEnabledViews(pi); - - if(piViews && CFSetContainsValue(piViews, viewname)) { - CFStringRef peerID = SOSPeerInfoGetPeerID(pi); - CFSetAddValue(viewset, peerID); - } - CFReleaseNull(piViews); - - }); - CFDictionaryAddValue(retval, viewname, viewset); - }); - - if(CFDictionaryGetCount(retval) == 0) goto errOut; // Not really an error - just no intersection of views with anyone - CFReleaseNull(peers); - CFReleaseNull(myViews); - return retval; - -errOut: - CFReleaseNull(retval); - CFReleaseNull(peers); - return NULL; -} - - - - /* Need XPC way to carry CFSets of views */ -CFSetRef CreateCFSetRefFromXPCObject(xpc_object_t xpcSetDER, CFErrorRef* error) { - CFSetRef retval = NULL; - require_action_quiet(xpcSetDER, errOut, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Unexpected Null Set to decode"))); - - require_action_quiet(xpc_get_type(xpcSetDER) == XPC_TYPE_DATA, errOut, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("xpcSetDER not data, got %@"), xpcSetDER)); - - 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); - if (der != der_end) { - SecError(errSecDecode, error, CFSTR("trailing garbage at end of SecAccessControl data")); - goto errOut; - } - return retval; -errOut: - CFReleaseNull(retval); - return NULL; -} xpc_object_t CreateXPCObjectWithCFSetRef(CFSetRef setref, CFErrorRef *error) { xpc_object_t result = NULL; diff --git a/OSX/sec/SOSCircle/SecureObjectSync/ViewList.list b/OSX/sec/SOSCircle/SecureObjectSync/ViewList.list index e5b7a028..619beea3 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/ViewList.list +++ b/OSX/sec/SOSCircle/SecureObjectSync/ViewList.list @@ -2,10 +2,11 @@ // This is the list of views. // To add a new view put it in this file with the DOVIEWMACRO defined: // Arguments for DOVIEWMACRO in arg order are: -// DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, V0SETTING) +// DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) // VIEWNAME - the base name used for both the view and the viewhint. This will become the constants kSOSView and kSecAttrViewHint // DEFSTRING - the string constant to be used for both the viewname and viewhint // CMDSTRING - the string used in the "security" command when refering to this view. +// SYSTEM - either "SOS" or CKKS": the syncing system to be used for this view // DEFAULTSETTING - if the view is turned on by default put a D in this column - otherwise keep it blank // INITIALSYNCSETTING - if the view is to be included in initialSync default put a I in this column - otherwise keep it blank // ALWAYSONSETTING - if the view cannot be disabled put an A in this column - otherwise keep it blank @@ -14,27 +15,34 @@ // // Once an entry is in here make the following two additional changes: // for views, add the declaration for kSOSView in SOSCloudCircle.h -// for viewhints add the declaration for kSecAttrViewHint in both versions (OSX and iOS) of SecItemPriv.h +// for viewhints add the declaration for kSecAttrViewHint in SecItemPriv.h + +DOVIEWMACRO(WiFi, "WiFi", "wifi", SOS, , , , , V) +DOVIEWMACRO(AutofillPasswords, "Passwords", "passwords", SOS, , , , , V) +DOVIEWMACRO(SafariCreditCards, "CreditCards", "creditcards", SOS, , , , , V) +DOVIEWMACRO(iCloudIdentity, "iCloudIdentity", "icloudidentity", SOS, D, I, A, B, V) +DOVIEWMACRO(BackupBagV0, "BackupBagV0", "backupv0", SOS, D, I, A, , V) +DOVIEWMACRO(OtherSyncable, "OtherSyncable", "othersyncable", SOS, , , , , V) +DOVIEWMACRO(ContinuityUnlock, "ContinuityUnlock", "continuityunlock", SOS, D, , A, , ) +DOVIEWMACRO(AppleTV, "AppleTV", "appletv", SOS, D, , A, , ) +DOVIEWMACRO(HomeKit, "HomeKit", "homekit", SOS, D, , A, , ) +DOVIEWMACRO(AccessoryPairing, "AccessoryPairing", "accessorypairing", SOS, D, , A, , ) +DOVIEWMACRO(PCSCloudKit, "PCS-CloudKit", "cloudkit", SOS, D, I, A, , ) +DOVIEWMACRO(PCSEscrow, "PCS-Escrow", "escrow", SOS, D, I, A, B, ) +DOVIEWMACRO(PCSFDE, "PCS-FDE", "fde", SOS, D, I, A, , ) +DOVIEWMACRO(PCSFeldspar, "PCS-Feldspar", "feldspar", SOS, D, I, A, , ) +DOVIEWMACRO(PCSMailDrop, "PCS-Maildrop", "maildrop", SOS, D, I, A, , ) +DOVIEWMACRO(PCSMasterKey, "PCS-MasterKey", "masterkey", SOS, D, I, A, B, ) +DOVIEWMACRO(PCSNotes, "PCS-Notes", "notes", SOS, D, I, A, , ) +DOVIEWMACRO(PCSPhotos, "PCS-Photos", "photos", SOS, D, I, A, , ) +DOVIEWMACRO(PCSSharing, "PCS-Sharing", "sharing", SOS, D, I, A, , ) +DOVIEWMACRO(PCSiCloudBackup, "PCS-Backup", "icloudbackup", SOS, D, I, A, , ) +DOVIEWMACRO(PCSiCloudDrive, "PCS-iCloudDrive", "iclouddrive", SOS, D, I, A, , ) +DOVIEWMACRO(PCSiMessage, "PCS-iMessage", "imessage", SOS, D, I, A, , ) +DOVIEWMACRO(NanoRegistry, "NanoRegistry", "nanoregistry", SOS, D, , A, , ) +DOVIEWMACRO(WatchMigration, "WatchMigration", "watchmigration", SOS, D, , A, , ) +DOVIEWMACRO(Engram, "Engram", "engram", CKKS, D, , A, , ) +DOVIEWMACRO(Manatee, "Manatee", "manatee", CKKS, D, , A, , ) +DOVIEWMACRO(AutoUnlock, "AutoUnlock", "autounlock", CKKS, D, , A, , ) +DOVIEWMACRO(Health, "Health", "health", CKKS, D, , A, , ) -DOVIEWMACRO(WiFi, "WiFi", "wifi", , , , , V) -DOVIEWMACRO(AutofillPasswords, "Passwords", "passwords", , , , , V) -DOVIEWMACRO(SafariCreditCards, "CreditCards", "creditcards", , , , , V) -DOVIEWMACRO(iCloudIdentity, "iCloudIdentity", "icloudidentity", D, I, A, B, V) -DOVIEWMACRO(BackupBagV0, "BackupBagV0", "backupv0", D, I, A, , V) -DOVIEWMACRO(OtherSyncable, "OtherSyncable", "othersyncable", , , , , V) -DOVIEWMACRO(ContinuityUnlock, "ContinuityUnlock", "continuityunlock", D, , A, , ) -DOVIEWMACRO(AppleTV, "AppleTV", "appletv", D, , A, , ) -DOVIEWMACRO(HomeKit, "HomeKit", "homekit", D, , A, , ) -DOVIEWMACRO(AccessoryPairing, "AccessoryPairing", "accessorypairing", D, , A, , ) -DOVIEWMACRO(PCSCloudKit, "PCS-CloudKit", "cloudkit", D, I, A, , ) -DOVIEWMACRO(PCSEscrow, "PCS-Escrow", "escrow", D, I, A, B, ) -DOVIEWMACRO(PCSFDE, "PCS-FDE", "fde", D, I, A, , ) -DOVIEWMACRO(PCSFeldspar, "PCS-Feldspar", "feldspar", D, I, A, , ) -DOVIEWMACRO(PCSMailDrop, "PCS-Maildrop", "maildrop", D, I, A, , ) -DOVIEWMACRO(PCSMasterKey, "PCS-MasterKey", "masterkey", D, I, A, B, ) -DOVIEWMACRO(PCSNotes, "PCS-Notes", "notes", D, I, A, , ) -DOVIEWMACRO(PCSPhotos, "PCS-Photos", "photos", D, I, A, , ) -DOVIEWMACRO(PCSSharing, "PCS-Sharing", "sharing", D, I, A, , ) -DOVIEWMACRO(PCSiCloudBackup, "PCS-Backup", "icloudbackup", D, I, A, , ) -DOVIEWMACRO(PCSiCloudDrive, "PCS-iCloudDrive", "iclouddrive", D, I, A, , ) -DOVIEWMACRO(PCSiMessage, "PCS-iMessage", "imessage", D, I, A, , ) diff --git a/OSX/sec/SOSCircle/Tool/NSFileHandle+Formatting.m b/OSX/sec/SOSCircle/Tool/NSFileHandle+Formatting.m index b9f27627..6f04ea2d 100644 --- a/OSX/sec/SOSCircle/Tool/NSFileHandle+Formatting.m +++ b/OSX/sec/SOSCircle/Tool/NSFileHandle+Formatting.m @@ -25,6 +25,10 @@ va_end(args); [self writeString: formatted]; +// Remove with Enable ARC wherever possible in Security.framework +#if !__has_feature(objc_arc) + [formatted release]; +#endif } @end diff --git a/OSX/sec/SOSCircle/Tool/accountCirclesViewsPrint.c b/OSX/sec/SOSCircle/Tool/accountCirclesViewsPrint.m similarity index 98% rename from OSX/sec/SOSCircle/Tool/accountCirclesViewsPrint.c rename to OSX/sec/SOSCircle/Tool/accountCirclesViewsPrint.m index 0bb83bed..c4fe7a2e 100644 --- a/OSX/sec/SOSCircle/Tool/accountCirclesViewsPrint.c +++ b/OSX/sec/SOSCircle/Tool/accountCirclesViewsPrint.m @@ -17,7 +17,6 @@ // -#include "SOSCloudCircleInternal.h" #include #include #include @@ -141,14 +140,14 @@ void SOSCCDumpCircleInformation() { CFErrorRef error = NULL; CFArrayRef generations = NULL; - bool is_user_public_trusted = false; + bool is_accountKeyIsTrusted = false; __block int count = 0; SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error); printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus), ccstatus); - is_user_public_trusted = SOSCCValidateUserPublic(&error); - if(is_user_public_trusted) + is_accountKeyIsTrusted = SOSCCValidateUserPublic(&error); + if(is_accountKeyIsTrusted) printmsg(CFSTR("Account user public is trusted%@"),CFSTR("\n")); else printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error); @@ -220,7 +219,6 @@ static CFTypeRef getObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t proc SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull { CFRelease(object); @@ -380,7 +378,6 @@ static void decodeForKeyType(CFTypeRef key, CFTypeRef value, SOSKVSKeyType type) case kAccountChangedKey: case kDebugInfoKey: case kRingKey: - case kPeerInfoKey: default: printmsg(CFSTR("%@: %@\n"), key, value); break; diff --git a/OSX/sec/SOSCircle/Tool/keychain_log.c b/OSX/sec/SOSCircle/Tool/keychain_log.m similarity index 99% rename from OSX/sec/SOSCircle/Tool/keychain_log.c rename to OSX/sec/SOSCircle/Tool/keychain_log.m index 89af2f74..ba5054e4 100644 --- a/OSX/sec/SOSCircle/Tool/keychain_log.c +++ b/OSX/sec/SOSCircle/Tool/keychain_log.m @@ -147,7 +147,7 @@ static void dumpCircleInfo() { CFErrorRef error = NULL; CFArrayRef generations = NULL; - bool is_user_public_trusted = false; + bool is_accountKeyIsTrusted = false; __block int count = 0; SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error); @@ -157,8 +157,8 @@ static void dumpCircleInfo() } printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus), ccstatus, error); - is_user_public_trusted = SOSCCValidateUserPublic(&error); - if(is_user_public_trusted) + is_accountKeyIsTrusted = SOSCCValidateUserPublic(&error); + if(is_accountKeyIsTrusted) printmsg(CFSTR("Account user public is trusted%@"),CFSTR("\n")); else printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error); @@ -231,7 +231,7 @@ static CFTypeRef getObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t proc SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); + if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull { CFRelease(object); @@ -391,7 +391,6 @@ static void decodeForKeyType(CFTypeRef key, CFTypeRef value, SOSKVSKeyType type) case kAccountChangedKey: case kDebugInfoKey: case kRingKey: - case kPeerInfoKey: default: printmsg(CFSTR("%@: %@\n"), key, value); break; diff --git a/OSX/sec/SOSCircle/Tool/keychain_sync.h b/OSX/sec/SOSCircle/Tool/keychain_sync.h index 8c90a82a..4ea67f28 100644 --- a/OSX/sec/SOSCircle/Tool/keychain_sync.h +++ b/OSX/sec/SOSCircle/Tool/keychain_sync.h @@ -32,7 +32,6 @@ SECURITY_COMMAND( " -e enable (join/create circle)\n" " -i info (current status)\n" " -m dump my peer\n" - " -s schedule sync with all peers\n" "\n" "Account/Circle Management\n" " -a accept all applicants\n" @@ -56,6 +55,8 @@ SECURITY_COMMAND( " -2 delete account state from the keychain\n" " -3 grab engine state from the keychain\n" " -4 delete engine state from the keychain\n" + " -5 cleanup old KVS keys in KVS\n" + " -6 [test]populate KVS with garbage KVS keys\n" "\n" "IDS\n" diff --git a/OSX/sec/SOSCircle/Tool/keychain_sync.c b/OSX/sec/SOSCircle/Tool/keychain_sync.m similarity index 97% rename from OSX/sec/SOSCircle/Tool/keychain_sync.c rename to OSX/sec/SOSCircle/Tool/keychain_sync.m index 830c9b4e..73f00ac7 100644 --- a/OSX/sec/SOSCircle/Tool/keychain_sync.c +++ b/OSX/sec/SOSCircle/Tool/keychain_sync.m @@ -83,7 +83,6 @@ static bool clearAllKVS(CFErrorRef *error) }); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); return result; } @@ -160,7 +159,7 @@ static void dumpCircleInfo() CFErrorRef error = NULL; CFArrayRef generations = NULL; CFArrayRef confirmedDigests = NULL; - bool is_user_public_trusted = false; + bool is_accountKeyIsTrusted = false; __block int count = 0; SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error); @@ -170,8 +169,8 @@ static void dumpCircleInfo() } printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus), ccstatus, error); - is_user_public_trusted = SOSCCValidateUserPublic(&error); - if(is_user_public_trusted) + is_accountKeyIsTrusted = SOSCCValidateUserPublic(&error); + if(is_accountKeyIsTrusted) printmsg(CFSTR("Account user public is trusted%@"),CFSTR("\n")); else printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error); @@ -310,7 +309,6 @@ static CFTypeRef getObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t proc SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull { CFRelease(object); @@ -470,7 +468,6 @@ static void decodeForKeyType(CFTypeRef key, CFTypeRef value, SOSKVSKeyType type) case kAccountChangedKey: case kDebugInfoKey: case kRingKey: - case kPeerInfoKey: default: printmsg(CFSTR("%@: %@\n"), key, value); break; @@ -542,7 +539,6 @@ static bool syncAndWait(CFErrorRef *err) SOSCloudKeychainSynchronizeAndWait(generalq, replyBlock); dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); dumpKVS(NULL, NULL); fprintf(outFile, "\n"); @@ -792,6 +788,8 @@ keychain_sync(int argc, char * const *argv) " -2 delete account state from the keychain" " -3 grab engine state from the keychain" " -4 delete engine state from the keychain" + " -5 cleanup old KVS keys in KVS" + " -6 [test]populate KVS with garbage KVS keys " "IDS" " -g set IDS device id" @@ -828,7 +826,7 @@ keychain_sync(int argc, char * const *argv) bool hadError = false; SOSLogSetOutputTo(NULL, NULL); - while ((ch = getopt(argc, argv, "ab:deg:hikl:mopq:rSv:w:x:zA:B:MNJCDEF:HG:ILOP:RT:UWX:VY01234")) != -1) + while ((ch = getopt(argc, argv, "ab:deg:hikl:mopq:rSv:w:x:zA:B:MNJCDEF:HG:ILOP:RT:UWX:VY0123456")) != -1) switch (ch) { case 'l': { @@ -1029,7 +1027,28 @@ keychain_sync(int argc, char * const *argv) } break; } - + case '5' : + { + bool result = SOSCCCleanupKVSKeys(&error); + if(result) + { + printmsg(CFSTR("Got all the keys from KVS %d\n"), result); + }else { + hadError = true; + } + break; + } + case '6' : + { + bool result = SOSCCTestPopulateKVSWithBadKeys(&error); + if(result) + { + printmsg(CFSTR("Populated KVS with garbage %d\n"), result); + }else { + hadError = true; + } + break; + } case 'E': { fprintf(outFile, "Ensuring Fresh Parameters\n"); diff --git a/OSX/sec/SOSCircle/Tool/keychain_sync_test.m b/OSX/sec/SOSCircle/Tool/keychain_sync_test.m index 8b4db90a..1f345865 100644 --- a/OSX/sec/SOSCircle/Tool/keychain_sync_test.m +++ b/OSX/sec/SOSCircle/Tool/keychain_sync_test.m @@ -37,7 +37,6 @@ keychain_sync_test(int argc, char * const *argv) */ int result = 0; - NSError* error = nil; __block CFErrorRef cfError = NULL; static int verbose_flag = 0; @@ -93,37 +92,35 @@ keychain_sync_test(int argc, char * const *argv) if (dump_pending) { CFArrayRef peers = SOSCCCopyPeerPeerInfo(&cfError); - [fhout writeFormat: @"Dumping state for %ld peers\n", CFArrayGetCount(peers)]; - - CFArrayForEach(peers, ^(const void *value) { - SOSPeerInfoRef thisPeer = (SOSPeerInfoRef) value; - if (thisPeer) { - CFReleaseNull(cfError); - bool message = SOSCCMessageFromPeerIsPending(thisPeer, &cfError); - if (!message && cfError != NULL) { - [fherr writeFormat: @"Error from SOSCCMessageFromPeerIsPending: %@\n", cfError]; + if (peers != NULL) { + [fhout writeFormat: @"Dumping state for %ld peers\n", CFArrayGetCount(peers)]; + + CFArrayForEach(peers, ^(const void *value) { + SOSPeerInfoRef thisPeer = (SOSPeerInfoRef) value; + if (thisPeer) { + CFReleaseNull(cfError); + bool message = SOSCCMessageFromPeerIsPending(thisPeer, &cfError); + if (!message && cfError != NULL) { + [fherr writeFormat: @"Error from SOSCCMessageFromPeerIsPending: %@\n", cfError]; + } + CFReleaseNull(cfError); + bool send = SOSCCSendToPeerIsPending(thisPeer, &cfError); + if (!message && cfError != NULL) { + [fherr writeFormat: @"Error from SOSCCSendToPeerIsPending: %@\n", cfError]; + } + CFReleaseNull(cfError); + + [fhout writeFormat: @"Peer: %c%c %@\n", boolToChars(message, 'M', 'm'), boolToChars(send, 'S', 's'), thisPeer]; + } else { + [fherr writeFormat: @"Non SOSPeerInfoRef in array: %@\n", value]; } - CFReleaseNull(cfError); - bool send = SOSCCSendToPeerIsPending(thisPeer, &cfError); - if (!message && cfError != NULL) { - [fherr writeFormat: @"Error from SOSCCSendToPeerIsPending: %@\n", cfError]; - } - CFReleaseNull(cfError); - - [fhout writeFormat: @"Peer: %c%c %@\n", boolToChars(message, 'M', 'm'), boolToChars(send, 'S', 's'), thisPeer]; - } else { - [fherr writeFormat: @"Non SOSPeerInfoRef in array: %@\n", value]; - } - }); + }); + } } if (cfError != NULL) { [fherr writeFormat: @"Error: %@\n", cfError]; } - if (error != NULL) { - [fherr writeFormat: @"Error: %@\n", error]; - } - return result; } diff --git a/OSX/sec/SOSCircle/Tool/recovery_key.h b/OSX/sec/SOSCircle/Tool/recovery_key.h index 0fe4c43a..d4d54c72 100644 --- a/OSX/sec/SOSCircle/Tool/recovery_key.h +++ b/OSX/sec/SOSCircle/Tool/recovery_key.h @@ -30,5 +30,6 @@ SECURITY_COMMAND( "Recovery Key\n" " -s //Set the recovery key\n" " -g //Get the recovery key\n" - " -c //Clear the recovery key\n", + " -c //Clear the recovery key\n" + " -V //Create Verifier Dictionary (printout)\n", "Recovery Key." ) diff --git a/OSX/sec/SOSCircle/Tool/recovery_key.m b/OSX/sec/SOSCircle/Tool/recovery_key.m index 6e5170d7..19effd74 100644 --- a/OSX/sec/SOSCircle/Tool/recovery_key.m +++ b/OSX/sec/SOSCircle/Tool/recovery_key.m @@ -58,16 +58,19 @@ recovery_key(int argc, char * const *argv) }; int option_index = 0; - while ((ch = getopt_long(argc, argv, "FG:Rs:gc", long_options, &option_index)) != -1) + while ((ch = getopt_long(argc, argv, "FG:Rs:gcV:", long_options, &option_index)) != -1) switch (ch) { case 'G': { + NSError *nserror = NULL; NSString *testString = [NSString stringWithUTF8String:optarg]; if(testString == nil) return 2; - SecRecoveryKey *rk = SecRKCreateRecoveryKey(testString); - if(rk == nil) + SecRecoveryKey *rk = SecRKCreateRecoveryKeyWithError(testString, &nserror); + if(rk == nil) { + printmsg(CFSTR("SecRKCreateRecoveryKeyWithError: %@\n"), nserror); return 2; + } NSData *publicKey = SecRKCopyBackupPublicKey(rk); if(publicKey == nil) return 2; @@ -86,13 +89,16 @@ recovery_key(int argc, char * const *argv) } case 's': { + NSError *nserror = NULL; NSString *testString = [NSString stringWithUTF8String:optarg]; if(testString == nil) return 2; - SecRecoveryKey *rk = SecRKCreateRecoveryKey(testString); - if(rk == nil) + SecRecoveryKey *rk = SecRKCreateRecoveryKeyWithError(testString, &nserror); + if(rk == nil) { + printmsg(CFSTR("SecRKCreateRecoveryKeyWithError: %@\n"), nserror); return 2; + } NSData *publicKey = SecRKCopyBackupPublicKey(rk); if(publicKey == nil) @@ -112,9 +118,7 @@ recovery_key(int argc, char * const *argv) } case 'c': { - CFDataRef empty = CFDataCreate(kCFAllocatorDefault, 0, 0); - hadError = SOSCCRegisterRecoveryPublicKey(empty, &error) != true; - CFReleaseNull(empty); + hadError = SOSCCRegisterRecoveryPublicKey(NULL, &error) != true; break; } case 'F': @@ -134,6 +138,27 @@ recovery_key(int argc, char * const *argv) } break; } + case 'V': { + NSError *localError = nil; + NSString *testString = [NSString stringWithUTF8String:optarg]; + NSString *fileName = [NSString stringWithFormat:@"%@.plist", testString]; + if(testString == nil) + return 2; + + NSDictionary *ver = SecRKCopyAccountRecoveryVerifier(testString, &localError); + if(ver == nil) { + printmsg(CFSTR("Failed to make verifier dictionary: %@\n"), localError); + return 2; + } + + printmsg(CFSTR("Verifier Dictionary: %@\n\n"), ver); + printmsg(CFSTR("Writing plist to %@\n"), (__bridge CFStringRef) fileName); + + [ver writeToFile:fileName atomically:YES]; + + } + break; + case '?': default: { diff --git a/OSX/sec/SOSCircle/Tool/secToolFileIO.c b/OSX/sec/SOSCircle/Tool/secToolFileIO.c index 6f5a0e9e..970e6df6 100644 --- a/OSX/sec/SOSCircle/Tool/secToolFileIO.c +++ b/OSX/sec/SOSCircle/Tool/secToolFileIO.c @@ -14,13 +14,15 @@ FILE *outFile = NULL; FILE *errFile = NULL; +void _printcfmsg(FILE *ff, CFDictionaryRef formatOptions, CFStringRef format, ...) CF_FORMAT_FUNCTION(3, 4); + void _printcfmsg(FILE *ff, CFDictionaryRef formatOptions, CFStringRef format, ...) { va_list args; va_start(args, format); CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, formatOptions, format, args); va_end(args); - CFStringPerformWithCString(message, ^(const char *utf8String) { fprintf(ff, utf8String, ""); }); + CFStringPerformWithCString(message, ^(const char *utf8String) { fprintf(ff, "%s", utf8String); }); CFRelease(message); } diff --git a/OSX/sec/SOSCircle/Tool/secViewDisplay.c b/OSX/sec/SOSCircle/Tool/secViewDisplay.c index 2e4a827a..ad0b02e2 100644 --- a/OSX/sec/SOSCircle/Tool/secViewDisplay.c +++ b/OSX/sec/SOSCircle/Tool/secViewDisplay.c @@ -41,7 +41,8 @@ static struct foo { } string2View[] = { { "keychain", &kSOSViewKeychainV0 }, #undef DOVIEWMACRO -#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) { CMDSTRING, &kSOSView##VIEWNAME, }, +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) \ + { CMDSTRING, &k##SYSTEM##View##VIEWNAME, }, #include "Security/SecureObjectSync/ViewList.list" }; diff --git a/OSX/sec/SOSCircle/Tool/syncbackup.c b/OSX/sec/SOSCircle/Tool/syncbackup.m similarity index 97% rename from OSX/sec/SOSCircle/Tool/syncbackup.c rename to OSX/sec/SOSCircle/Tool/syncbackup.m index acb04d92..d44a94d7 100644 --- a/OSX/sec/SOSCircle/Tool/syncbackup.c +++ b/OSX/sec/SOSCircle/Tool/syncbackup.m @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include diff --git a/OSX/sec/Security/AppleiPhoneDeviceCACertificates.h b/OSX/sec/Security/AppleiPhoneDeviceCACertificates.h new file mode 100644 index 00000000..74166246 --- /dev/null +++ b/OSX/sec/Security/AppleiPhoneDeviceCACertificates.h @@ -0,0 +1,239 @@ +/* + * 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_AppleiPhoneDeviceCACertificates_h +#define _sec_AppleiPhoneDeviceCACertificates_h + +#include + +/* subject:/C=US/O=Apple Inc./OU=Apple iPhone/CN=Apple iPhone Device CA */ +/* issuer :/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple iPhone Certification Authority */ +uint8_t _AppleiPhoneDeviceCA[877]={ + 0x30,0x82,0x03,0x69,0x30,0x82,0x02,0x51,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01, + 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,0x55,0x53,0x31,0x13, + 0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49, + 0x6E,0x63,0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,0x70, + 0x70,0x6C,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, + 0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x2D,0x30,0x2B,0x06, + 0x03,0x55,0x04,0x03,0x13,0x24,0x41,0x70,0x70,0x6C,0x65,0x20,0x69,0x50,0x68,0x6F, + 0x6E,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,0x30,0x1E,0x17,0x0D,0x30,0x37, + 0x30,0x34,0x31,0x36,0x32,0x32,0x35,0x34,0x34,0x36,0x5A,0x17,0x0D,0x31,0x34,0x30, + 0x34,0x31,0x36,0x32,0x32,0x35,0x34,0x34,0x36,0x5A,0x30,0x5A,0x31,0x0B,0x30,0x09, + 0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55, + 0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x15, + 0x30,0x13,0x06,0x03,0x55,0x04,0x0B,0x13,0x0C,0x41,0x70,0x70,0x6C,0x65,0x20,0x69, + 0x50,0x68,0x6F,0x6E,0x65,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16, + 0x41,0x70,0x70,0x6C,0x65,0x20,0x69,0x50,0x68,0x6F,0x6E,0x65,0x20,0x44,0x65,0x76, + 0x69,0x63,0x65,0x20,0x43,0x41,0x30,0x81,0x9F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, + 0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x81,0x8D,0x00,0x30,0x81,0x89,0x02, + 0x81,0x81,0x00,0xF1,0x94,0x4A,0xC9,0xEA,0xBA,0x5A,0x18,0x60,0xAD,0xCB,0xA2,0x4D, + 0x4D,0x4E,0x54,0x19,0x69,0x17,0x59,0x07,0x66,0xCB,0x97,0xE8,0x66,0x9A,0x47,0x5F, + 0x46,0xAE,0x67,0x7A,0xB5,0x4A,0x73,0x54,0xB1,0xCB,0x04,0xF6,0xBD,0x36,0xB8,0x0C, + 0x55,0x38,0x8A,0x84,0x83,0x31,0x52,0x65,0xF9,0x33,0xE1,0x97,0x77,0x9C,0x2B,0x4C, + 0x26,0xB0,0x25,0x3F,0xE9,0x32,0xAA,0x7B,0x08,0x74,0x94,0xEC,0xC1,0x4B,0x38,0x1D, + 0x67,0x4E,0x08,0x52,0x94,0x5A,0x8B,0x59,0xA3,0x5C,0xD7,0x93,0xF4,0xA0,0xFE,0x55, + 0x85,0xBB,0x4C,0x46,0x97,0x5E,0x6E,0xB2,0x77,0x45,0x2F,0x67,0x5C,0xBC,0x0B,0x18, + 0xBF,0x59,0xB9,0x6C,0x86,0xF7,0x2A,0x75,0x76,0xD2,0x19,0x71,0xF4,0x29,0x63,0xB9, + 0x25,0x0B,0xAF,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x9E,0x30,0x81,0x9B,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,0xB2,0xFE,0x21,0x23,0x44,0x86, + 0x95,0x6A,0x79,0xD5,0x81,0x26,0x8E,0x73,0x10,0xD8,0xA7,0x4C,0x8E,0x74,0x30,0x1F, + 0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xE7,0x34,0x2A,0x2E,0x22, + 0xDE,0x39,0x60,0x6B,0xB4,0x94,0xCE,0x77,0x83,0x61,0x2F,0x31,0xA0,0x7C,0x35,0x30, + 0x38,0x06,0x03,0x55,0x1D,0x1F,0x04,0x31,0x30,0x2F,0x30,0x2D,0xA0,0x2B,0xA0,0x29, + 0x86,0x27,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x61,0x70,0x70, + 0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70,0x6C,0x65,0x63,0x61,0x2F,0x69, + 0x70,0x68,0x6F,0x6E,0x65,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, + 0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x77,0x5D,0xCF, + 0x67,0x7A,0x4C,0x56,0x2B,0xA4,0x54,0x77,0xBD,0x59,0x48,0x3C,0x1E,0xE9,0xBE,0xD0, + 0x8F,0xF4,0x90,0x72,0xAF,0x8E,0x1C,0x15,0x77,0xF2,0x0C,0xC0,0x69,0x57,0xC9,0x4E, + 0xC3,0x85,0x46,0x16,0x76,0x36,0xB6,0x5F,0xFC,0xEA,0x8F,0xB5,0xB6,0xE0,0x0A,0xB9, + 0xED,0xD1,0x0A,0x9B,0x77,0xEA,0xAB,0x12,0xB9,0x5C,0x21,0x55,0x19,0x8E,0x47,0x23, + 0x47,0x11,0xB1,0xD1,0x0D,0xC9,0x33,0xFB,0x97,0x14,0xA2,0x89,0x34,0x58,0x8F,0x69, + 0xA5,0x3D,0xE7,0x61,0x78,0x29,0xFE,0x93,0xA4,0xF9,0xCB,0x45,0x38,0x5E,0xBE,0x34, + 0x15,0x7C,0x16,0x6F,0x69,0xD6,0xA8,0x21,0x75,0x02,0x02,0x2E,0x76,0x18,0x2F,0x55, + 0xBC,0x65,0xBE,0xA7,0x31,0x52,0x6F,0x19,0xCF,0xBC,0x83,0x78,0x9D,0x09,0x16,0x8B, + 0xD7,0x42,0x1C,0x8E,0xE5,0xF2,0xD4,0x1D,0x12,0xC2,0x40,0x5B,0x2C,0x01,0xB7,0xFC, + 0x07,0x88,0xBC,0xAD,0x86,0x2C,0x05,0x48,0x58,0x4E,0xCA,0x55,0x25,0xCC,0x55,0xA4, + 0x82,0x25,0xB6,0x46,0x29,0x74,0x84,0x52,0x20,0x04,0x40,0xE3,0xD1,0xCD,0xBC,0xA2, + 0xB8,0x87,0x38,0xF3,0x31,0x2F,0xCE,0x84,0xA4,0x29,0x54,0xAC,0x3E,0x38,0x21,0x19, + 0xC6,0x9B,0x42,0x55,0xE3,0x76,0xA6,0x36,0xDD,0xB7,0xDB,0xB3,0x8B,0x5E,0xF9,0xA1, + 0x5A,0x3F,0xBB,0xA0,0x76,0x02,0xB2,0x80,0x5B,0x5E,0xEE,0xE9,0x71,0x07,0x21,0xD0, + 0xCC,0x39,0xEE,0xDC,0x6F,0x7D,0xE9,0x79,0x52,0x3A,0x4C,0x3D,0x79,0x5B,0x83,0x08, + 0xA7,0x24,0x0F,0x6E,0x9F,0x28,0xAE,0x55,0xDE,0xFA,0xD0,0x3C,0x24, +}; + +/* subject:/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple iPhone Certification Authority */ +/* issuer :/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA */ +uint8_t _AppleiPhoneCA[1015]={ + 0x30,0x82,0x03,0xF3,0x30,0x82,0x02,0xDB,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x17, + 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, + 0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13, + 0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49, + 0x6E,0x63,0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,0x70, + 0x70,0x6C,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, + 0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x16,0x30,0x14,0x06, + 0x03,0x55,0x04,0x03,0x13,0x0D,0x41,0x70,0x70,0x6C,0x65,0x20,0x52,0x6F,0x6F,0x74, + 0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x37,0x30,0x34,0x31,0x32,0x31,0x37,0x34, + 0x33,0x32,0x38,0x5A,0x17,0x0D,0x32,0x32,0x30,0x34,0x31,0x32,0x31,0x37,0x34,0x33, + 0x32,0x38,0x5A,0x30,0x79,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, + 0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70, + 0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B, + 0x13,0x1D,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, + 0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31, + 0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,0x03,0x13,0x24,0x41,0x70,0x70,0x6C,0x65,0x20, + 0x69,0x50,0x68,0x6F,0x6E,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,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,0xA3, + 0x1E,0xBE,0xF0,0x47,0xC0,0xB4,0x9E,0x10,0x5B,0x46,0xA4,0xB8,0x21,0xB8,0x4F,0x86, + 0x21,0x70,0x28,0x45,0x60,0x5C,0x1C,0xC3,0xC8,0x0A,0x64,0x63,0x88,0xFB,0xFC,0x69, + 0xEE,0xF8,0x54,0xFC,0xE9,0x5B,0xB7,0x06,0x4E,0x04,0x2F,0xC3,0x6B,0x33,0xAF,0x44, + 0x4C,0xEA,0x4B,0x80,0x09,0xB4,0x87,0xF6,0x5B,0xB4,0xFD,0x64,0xDD,0xB3,0x72,0xE0, + 0x13,0xB3,0xFD,0x17,0xD9,0xBC,0xE7,0xA8,0xED,0xC2,0x8C,0x61,0xC2,0x2A,0xF9,0xEC, + 0xCE,0xA5,0x5E,0xD6,0x69,0xEB,0x64,0x0B,0x8D,0x08,0x8F,0xB8,0xA0,0x50,0x46,0x09, + 0xDC,0x19,0xE4,0xE5,0xB0,0x94,0x6D,0xBB,0xF7,0x99,0x98,0xC4,0xE8,0x9B,0x41,0x4E, + 0xD4,0xF1,0x65,0xE3,0x1B,0x52,0x7A,0xDC,0xE8,0x03,0xD9,0x6E,0x1D,0xDA,0x10,0x55, + 0x86,0xA4,0x29,0x58,0x49,0x0C,0xEA,0x47,0xD7,0x15,0x34,0x33,0xF6,0xC0,0xA0,0x44, + 0x4A,0x70,0xBE,0x2C,0xB5,0x2A,0x30,0x37,0x8C,0x2E,0x15,0xEB,0xD1,0xE4,0x6C,0x97, + 0x38,0x55,0x56,0xB1,0x35,0x2B,0x58,0xEA,0x44,0xA3,0x26,0x85,0xEE,0xC8,0x66,0x4A, + 0xE4,0xCF,0x89,0xF0,0x3D,0x63,0xAD,0x29,0xDE,0xAD,0xBA,0x5A,0xB3,0xDC,0xA5,0xA3, + 0x9A,0xA7,0x09,0x4E,0x80,0x16,0x35,0x65,0xA4,0x85,0x0D,0x63,0x7B,0x3E,0x63,0x8A, + 0xDA,0x7D,0x4A,0x46,0xEC,0xA3,0x39,0x18,0x34,0xB9,0xC6,0x28,0x65,0x18,0xBC,0x13, + 0x60,0x9C,0x7F,0x57,0xAC,0x14,0xC9,0x89,0xED,0xA1,0xB6,0x87,0x68,0x52,0xB6,0x84, + 0x4E,0xB8,0xC8,0x83,0xEC,0xF9,0x9E,0x19,0xAB,0xB3,0xC1,0x0B,0x86,0xC7,0x9F,0x02, + 0x03,0x01,0x00,0x01,0xA3,0x81,0x9C,0x30,0x81,0x99,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,0xE7,0x34,0x2A,0x2E,0x22,0xDE,0x39,0x60,0x6B,0xB4, + 0x94,0xCE,0x77,0x83,0x61,0x2F,0x31,0xA0,0x7C,0x35,0x30,0x1F,0x06,0x03,0x55,0x1D, + 0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x2B,0xD0,0x69,0x47,0x94,0x76,0x09,0xFE,0xF4, + 0x6B,0x8D,0x2E,0x40,0xA6,0xF7,0x47,0x4D,0x7F,0x08,0x5E,0x30,0x36,0x06,0x03,0x55, + 0x1D,0x1F,0x04,0x2F,0x30,0x2D,0x30,0x2B,0xA0,0x29,0xA0,0x27,0x86,0x25,0x68,0x74, + 0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63, + 0x6F,0x6D,0x2F,0x61,0x70,0x70,0x6C,0x65,0x63,0x61,0x2F,0x72,0x6F,0x6F,0x74,0x2E, + 0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, + 0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x1D,0xD1,0xD5,0x7B,0xDD,0x74,0x4E,0xD7,0x17, + 0xFC,0x82,0x2D,0x0C,0x99,0x9B,0x5E,0x42,0x72,0xF2,0x69,0xDC,0xD5,0x6B,0x5E,0x0D, + 0x0C,0x6B,0x4B,0x3E,0x7B,0x14,0x25,0xDE,0xB3,0x94,0xE8,0xA0,0xFA,0x0F,0x80,0x89, + 0xF2,0x17,0x3D,0x00,0x02,0xA2,0x91,0x91,0xBE,0x74,0x57,0xDC,0xAF,0x9A,0x9F,0xA1, + 0x0A,0x7D,0x30,0xBE,0x00,0x2A,0xCC,0x21,0x59,0xEB,0xFD,0x49,0xAC,0x6E,0x75,0x19, + 0xE8,0x9A,0x7A,0x03,0xD1,0x86,0xF6,0xE7,0xF6,0xB0,0x0E,0x4B,0x49,0xFA,0xA3,0xB7, + 0x41,0xBA,0xD7,0xD1,0xE3,0x56,0xA1,0x7D,0x83,0xAB,0x97,0xAE,0xF8,0x51,0x4A,0x26, + 0xC1,0x85,0x42,0x13,0x26,0x8D,0x03,0x54,0x66,0x10,0x5E,0x60,0x84,0x05,0x12,0x31, + 0x2B,0x6B,0x54,0xC0,0xA0,0xC8,0x41,0xBC,0x54,0x1E,0xE7,0x54,0xAD,0x13,0x00,0xD2, + 0x4A,0xC7,0xBB,0xC1,0x8A,0xAF,0x81,0x08,0x8E,0xF0,0x46,0x0A,0xBF,0x27,0xA6,0xBE, + 0xDC,0xCF,0x39,0x3A,0x80,0x70,0x19,0x23,0x32,0xA3,0x6B,0x66,0x5D,0x9E,0x4D,0xA8, + 0x47,0x49,0xB2,0x7B,0x45,0xB5,0x51,0x33,0xA7,0x74,0x67,0x09,0x4E,0xB6,0x6C,0x6F, + 0x48,0xF7,0x2C,0xB9,0x33,0x05,0x44,0x6B,0x45,0xBE,0x74,0x4B,0x6F,0xB2,0x86,0x91, + 0xB4,0x3E,0x25,0x28,0x25,0x9E,0xB3,0xC2,0x51,0x86,0xFC,0x4F,0xE5,0xAF,0x3B,0xAA, + 0xBB,0x44,0x2C,0x01,0x49,0xE2,0x74,0xB3,0x34,0xFA,0x44,0xEF,0x14,0xC2,0x11,0xF2, + 0x2D,0x19,0x1A,0x51,0x89,0xD3,0x08,0x4A,0x41,0x6C,0x58,0x56,0xDE,0x9B,0x3A,0xE1, + 0x05,0x57,0xE5,0x62,0xCF,0xD2,0x0F, +}; + +/* subject:/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA */ +/* issuer :/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA */ +uint8_t _AppleRootCA[1215]={ + 0x30,0x82,0x04,0xBB,0x30,0x82,0x03,0xA3,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x02, + 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, + 0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13, + 0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49, + 0x6E,0x63,0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,0x70, + 0x70,0x6C,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, + 0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x16,0x30,0x14,0x06, + 0x03,0x55,0x04,0x03,0x13,0x0D,0x41,0x70,0x70,0x6C,0x65,0x20,0x52,0x6F,0x6F,0x74, + 0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x34,0x32,0x35,0x32,0x31,0x34, + 0x30,0x33,0x36,0x5A,0x17,0x0D,0x33,0x35,0x30,0x32,0x30,0x39,0x32,0x31,0x34,0x30, + 0x33,0x36,0x5A,0x30,0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, + 0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70, + 0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B, + 0x13,0x1D,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, + 0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31, + 0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x03,0x13,0x0D,0x41,0x70,0x70,0x6C,0x65,0x20, + 0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A, + 0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30, + 0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xE4,0x91,0xA9,0x09,0x1F,0x91,0xDB,0x1E, + 0x47,0x50,0xEB,0x05,0xED,0x5E,0x79,0x84,0x2D,0xEB,0x36,0xA2,0x57,0x4C,0x55,0xEC, + 0x8B,0x19,0x89,0xDE,0xF9,0x4B,0x6C,0xF5,0x07,0xAB,0x22,0x30,0x02,0xE8,0x18,0x3E, + 0xF8,0x50,0x09,0xD3,0x7F,0x41,0xA8,0x98,0xF9,0xD1,0xCA,0x66,0x9C,0x24,0x6B,0x11, + 0xD0,0xA3,0xBB,0xE4,0x1B,0x2A,0xC3,0x1F,0x95,0x9E,0x7A,0x0C,0xA4,0x47,0x8B,0x5B, + 0xD4,0x16,0x37,0x33,0xCB,0xC4,0x0F,0x4D,0xCE,0x14,0x69,0xD1,0xC9,0x19,0x72,0xF5, + 0x5D,0x0E,0xD5,0x7F,0x5F,0x9B,0xF2,0x25,0x03,0xBA,0x55,0x8F,0x4D,0x5D,0x0D,0xF1, + 0x64,0x35,0x23,0x15,0x4B,0x15,0x59,0x1D,0xB3,0x94,0xF7,0xF6,0x9C,0x9E,0xCF,0x50, + 0xBA,0xC1,0x58,0x50,0x67,0x8F,0x08,0xB4,0x20,0xF7,0xCB,0xAC,0x2C,0x20,0x6F,0x70, + 0xB6,0x3F,0x01,0x30,0x8C,0xB7,0x43,0xCF,0x0F,0x9D,0x3D,0xF3,0x2B,0x49,0x28,0x1A, + 0xC8,0xFE,0xCE,0xB5,0xB9,0x0E,0xD9,0x5E,0x1C,0xD6,0xCB,0x3D,0xB5,0x3A,0xAD,0xF4, + 0x0F,0x0E,0x00,0x92,0x0B,0xB1,0x21,0x16,0x2E,0x74,0xD5,0x3C,0x0D,0xDB,0x62,0x16, + 0xAB,0xA3,0x71,0x92,0x47,0x53,0x55,0xC1,0xAF,0x2F,0x41,0xB3,0xF8,0xFB,0xE3,0x70, + 0xCD,0xE6,0xA3,0x4C,0x45,0x7E,0x1F,0x4C,0x6B,0x50,0x96,0x41,0x89,0xC4,0x74,0x62, + 0x0B,0x10,0x83,0x41,0x87,0x33,0x8A,0x81,0xB1,0x30,0x58,0xEC,0x5A,0x04,0x32,0x8C, + 0x68,0xB3,0x8F,0x1D,0xDE,0x65,0x73,0xFF,0x67,0x5E,0x65,0xBC,0x49,0xD8,0x76,0x9F, + 0x33,0x14,0x65,0xA1,0x77,0x94,0xC9,0x2D,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x01, + 0x7A,0x30,0x82,0x01,0x76,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,0x2B,0xD0,0x69,0x47,0x94,0x76,0x09,0xFE,0xF4,0x6B,0x8D,0x2E,0x40,0xA6,0xF7, + 0x47,0x4D,0x7F,0x08,0x5E,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16, + 0x80,0x14,0x2B,0xD0,0x69,0x47,0x94,0x76,0x09,0xFE,0xF4,0x6B,0x8D,0x2E,0x40,0xA6, + 0xF7,0x47,0x4D,0x7F,0x08,0x5E,0x30,0x82,0x01,0x11,0x06,0x03,0x55,0x1D,0x20,0x04, + 0x82,0x01,0x08,0x30,0x82,0x01,0x04,0x30,0x82,0x01,0x00,0x06,0x09,0x2A,0x86,0x48, + 0x86,0xF7,0x63,0x64,0x05,0x01,0x30,0x81,0xF2,0x30,0x2A,0x06,0x08,0x2B,0x06,0x01, + 0x05,0x05,0x07,0x02,0x01,0x16,0x1E,0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x77, + 0x77,0x77,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70, + 0x6C,0x65,0x63,0x61,0x2F,0x30,0x81,0xC3,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07, + 0x02,0x02,0x30,0x81,0xB6,0x1A,0x81,0xB3,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,0x74,0x68,0x65,0x20,0x74,0x68,0x65,0x6E, + 0x20,0x61,0x70,0x70,0x6C,0x69,0x63,0x61,0x62,0x6C,0x65,0x20,0x73,0x74,0x61,0x6E, + 0x64,0x61,0x72,0x64,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, + 0x2C,0x20,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x70,0x6F, + 0x6C,0x69,0x63,0x79,0x20,0x61,0x6E,0x64,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,0x0D,0x06,0x09,0x2A, + 0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x5C, + 0x36,0x99,0x4C,0x2D,0x78,0xB7,0xED,0x8C,0x9B,0xDC,0xF3,0x77,0x9B,0xF2,0x76,0xD2, + 0x77,0x30,0x4F,0xC1,0x1F,0x85,0x83,0x85,0x1B,0x99,0x3D,0x47,0x37,0xF2,0xA9,0x9B, + 0x40,0x8E,0x2C,0xD4,0xB1,0x90,0x12,0xD8,0xBE,0xF4,0x73,0x9B,0xEE,0xD2,0x64,0x0F, + 0xCB,0x79,0x4F,0x34,0xD8,0xA2,0x3E,0xF9,0x78,0xFF,0x6B,0xC8,0x07,0xEC,0x7D,0x39, + 0x83,0x8B,0x53,0x20,0xD3,0x38,0xC4,0xB1,0xBF,0x9A,0x4F,0x0A,0x6B,0xFF,0x2B,0xFC, + 0x59,0xA7,0x05,0x09,0x7C,0x17,0x40,0x56,0x11,0x1E,0x74,0xD3,0xB7,0x8B,0x23,0x3B, + 0x47,0xA3,0xD5,0x6F,0x24,0xE2,0xEB,0xD1,0xB7,0x70,0xDF,0x0F,0x45,0xE1,0x27,0xCA, + 0xF1,0x6D,0x78,0xED,0xE7,0xB5,0x17,0x17,0xA8,0xDC,0x7E,0x22,0x35,0xCA,0x25,0xD5, + 0xD9,0x0F,0xD6,0x6B,0xD4,0xA2,0x24,0x23,0x11,0xF7,0xA1,0xAC,0x8F,0x73,0x81,0x60, + 0xC6,0x1B,0x5B,0x09,0x2F,0x92,0xB2,0xF8,0x44,0x48,0xF0,0x60,0x38,0x9E,0x15,0xF5, + 0x3D,0x26,0x67,0x20,0x8A,0x33,0x6A,0xF7,0x0D,0x82,0xCF,0xDE,0xEB,0xA3,0x2F,0xF9, + 0x53,0x6A,0x5B,0x64,0xC0,0x63,0x33,0x77,0xF7,0x3A,0x07,0x2C,0x56,0xEB,0xDA,0x0F, + 0x21,0x0E,0xDA,0xBA,0x73,0x19,0x4F,0xB5,0xD9,0x36,0x7F,0xC1,0x87,0x55,0xD9,0xA7, + 0x99,0xB9,0x32,0x42,0xFB,0xD8,0xD5,0x71,0x9E,0x7E,0xA1,0x52,0xB7,0x1B,0xBD,0x93, + 0x42,0x24,0x12,0x2A,0xC7,0x0F,0x1D,0xB6,0x4D,0x9C,0x5E,0x63,0xC8,0x4B,0x80,0x17, + 0x50,0xAA,0x8A,0xD5,0xDA,0xE4,0xFC,0xD0,0x09,0x07,0x37,0xB0,0x75,0x75,0x21, +}; + +#endif /* _sec_AppleiPhoneDeviceCACertificates_h */ diff --git a/OSX/sec/Security/Regressions/Security_regressions.h b/OSX/sec/Security/Regressions/Security_regressions.h index 38dbd325..7c818088 100644 --- a/OSX/sec/Security/Regressions/Security_regressions.h +++ b/OSX/sec/Security/Regressions/Security_regressions.h @@ -6,7 +6,7 @@ This file contains iOS only tests that are built in libSecurityRegression.a For test shared between OSX and iOS, see shared_regressions.h */ -#include +#include ONE_TEST(pbkdf2_00_hmac_sha1) ONE_TEST(spbkdf_00_hmac_sha1) @@ -31,12 +31,7 @@ ONE_TEST(si_41_sececkey) ONE_TEST(si_42_identity) ONE_TEST(si_43_persistent) ONE_TEST(si_50_secrandom) -ONE_TEST(si_60_cms) -ONE_TEST(si_61_pkcs12) ONE_TEST(si_63_scep) -ONE_TEST(si_64_ossl_cms) -ONE_TEST(si_65_cms_cert_policy) -ONE_TEST(si_68_secmatchissuer) ONE_TEST(si_69_keydesc) ONE_TEST(si_72_syncableitems) ONE_TEST(si_73_secpasswordgenerate) diff --git a/OSX/sec/Security/Regressions/crypto/padding-00-mmcs.c b/OSX/sec/Security/Regressions/crypto/padding-00-mmcs.c new file mode 100644 index 00000000..fdf0f4c1 --- /dev/null +++ b/OSX/sec/Security/Regressions/crypto/padding-00-mmcs.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + */ + +#include "testmore.h" + +#include "SecPaddingConfigurationsPriv.h" +#include "shared_regressions.h" +#include "SecCFWrappers.h" + +#define kTestTestCount 67 + +struct test_vector { + SecPaddingType type; + uint32_t originalSize; + int64_t paddedSize; +}; +typedef struct test_vector test_vector_t; + +test_vector_t test_vectors[] = { + {SecPaddingTypeMMCS,0,64}, + {SecPaddingTypeMMCS,1,64}, + {SecPaddingTypeMMCS,2,64}, + {SecPaddingTypeMMCS,64,64}, + {SecPaddingTypeMMCS,65,128}, + {SecPaddingTypeMMCS,68,128}, + {SecPaddingTypeMMCS,80,128}, + {SecPaddingTypeMMCS,90,128}, + {SecPaddingTypeMMCS,100,128}, + {SecPaddingTypeMMCS,128,128}, + {SecPaddingTypeMMCS,129,256}, + {SecPaddingTypeMMCS,129,256}, + {SecPaddingTypeMMCS,150,256}, + {SecPaddingTypeMMCS,256,256}, + {SecPaddingTypeMMCS,257,512}, + {SecPaddingTypeMMCS,512,512}, + {SecPaddingTypeMMCS,612,1024}, + {SecPaddingTypeMMCS,1000,1024}, + {SecPaddingTypeMMCS,1024,1024}, + {SecPaddingTypeMMCS,1025,2048}, + {SecPaddingTypeMMCS,1800,2048}, + {SecPaddingTypeMMCS,2000,2048}, + {SecPaddingTypeMMCS,2047,2048}, + {SecPaddingTypeMMCS,2048,2048}, + {SecPaddingTypeMMCS,3072,3072}, + {SecPaddingTypeMMCS,4096,4096}, + {SecPaddingTypeMMCS,31744,31744}, + {SecPaddingTypeMMCS,31999,32768}, + {SecPaddingTypeMMCS,32000,32768}, + {SecPaddingTypeMMCS,32001,32768}, + {SecPaddingTypeMMCS,32769,40960}, + {SecPaddingTypeMMCS,4294967295,4294967296} +}; + +static void tests_negative(void) +{ + CFErrorRef testError = NULL; + + // Sanity + ok(SecPaddingCompute(SecPaddingTypeMMCS, 0, &testError) == 64 && testError==NULL); + + // Wrong type + ok(SecPaddingCompute(100, 20, &testError) == -1); + ok(testError!=NULL); + CFReleaseNull(testError); +} + +static void tests_positive(void) +{ + CFErrorRef testError = NULL; + size_t n; + + n = sizeof(test_vectors)/sizeof(test_vectors[0]); + for(size_t i=0; i #include +#include #include #include #include @@ -58,6 +59,7 @@ static void tests(void) ok_status(SecItemCopyMatching(query2, &results), "find internet password, return attributes"); CFReleaseNull(query2); query2 = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, results); + CFDictionaryRemoveValue(query2, kSecAttrSHA1), CFDictionarySetValue(query2, kSecClass, kSecClassInternetPassword); CFDictionarySetValue(query2, kSecReturnData, kCFBooleanTrue); ok_status(SecItemCopyMatching(query2, &results), "find internet password using returned attributes"); diff --git a/OSX/sec/Security/Regressions/secitem/si-15-certificate.c b/OSX/sec/Security/Regressions/secitem/si-15-certificate.c index 90b7a9e0..2407e3aa 100644 --- a/OSX/sec/Security/Regressions/secitem/si-15-certificate.c +++ b/OSX/sec/Security/Regressions/secitem/si-15-certificate.c @@ -894,12 +894,101 @@ errOut: CFReleaseSafe(cert); } +const uint8_t mail_google_com [] = { + 0x30, 0x82, 0x03, 0x22, 0x30, 0x82, 0x02, 0x8b, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x2b, 0x9f, 0x7e, 0xe5, 0xca, 0x25, 0xa6, 0x25, 0x14, + 0x20, 0x47, 0x82, 0x75, 0x3a, 0x9b, 0xb9, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x5a, + 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, + 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79, 0x29, 0x20, + 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x47, + 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x31, 0x30, + 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, + 0x33, 0x30, 0x39, 0x33, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, + 0x30, 0x69, 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, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x14, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, + 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x14, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x14, 0x0f, 0x6d, 0x61, 0x69, 0x6c, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, + 0x02, 0x81, 0x81, 0x00, 0xaf, 0x39, 0x15, 0x98, 0x68, 0xe4, 0x92, 0xfe, + 0x4f, 0x4f, 0xf1, 0xbb, 0xff, 0x0d, 0x2e, 0xb0, 0xfe, 0x25, 0xaa, 0xbd, + 0x68, 0x04, 0x67, 0x27, 0xea, 0x6c, 0x43, 0x4c, 0xa7, 0x6d, 0xcb, 0xc8, + 0x8f, 0x7e, 0x81, 0xee, 0x87, 0x26, 0x25, 0x10, 0x12, 0x54, 0x33, 0x9e, + 0xaa, 0x3d, 0x9b, 0x8f, 0x8e, 0x92, 0xb3, 0x4b, 0x01, 0xe3, 0xf9, 0x4a, + 0x29, 0xc3, 0x0f, 0xfd, 0xac, 0xb7, 0xd3, 0x4c, 0x97, 0x29, 0x3f, 0x69, + 0x55, 0xcf, 0x70, 0x83, 0x04, 0xaf, 0x2e, 0x04, 0x6e, 0x74, 0xd6, 0x0f, + 0x17, 0x09, 0xfe, 0x9e, 0x20, 0x24, 0x24, 0xe3, 0xc7, 0x68, 0x9c, 0xac, + 0x11, 0xbd, 0x92, 0xe4, 0xb2, 0x1b, 0x09, 0xf2, 0x02, 0x32, 0xbb, 0x55, + 0x1b, 0x2d, 0x16, 0x5f, 0x30, 0x12, 0x23, 0xe2, 0x4c, 0x4a, 0x8d, 0xc2, + 0xda, 0x3f, 0xe1, 0xb8, 0xbf, 0xf7, 0x3a, 0xb1, 0x86, 0xbe, 0xf0, 0xc5, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xe7, 0x30, 0x81, 0xe4, 0x30, + 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, + 0x00, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2f, 0x30, 0x2d, + 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x53, 0x47, 0x43, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x28, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, + 0x42, 0x04, 0x01, 0x30, 0x72, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x66, 0x30, 0x64, 0x30, 0x22, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, + 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3e, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x32, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, + 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, + 0x5f, 0x53, 0x47, 0x43, 0x5f, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x35, 0x80, 0x11, 0xcd, 0x52, 0x3e, + 0x84, 0x29, 0xfb, 0xc1, 0x28, 0xe1, 0x20, 0xe5, 0x02, 0x8f, 0x5f, 0x71, + 0x65, 0x58, 0x1d, 0x62, 0x72, 0x57, 0x3c, 0xe6, 0x5e, 0x25, 0x61, 0xd3, + 0xcb, 0xad, 0x22, 0xf8, 0xd8, 0x81, 0xa4, 0xe7, 0xf4, 0xae, 0x7c, 0xd9, + 0xc1, 0x6d, 0xaa, 0x93, 0x0d, 0x62, 0x07, 0x9f, 0xf2, 0x67, 0x47, 0x99, + 0x34, 0x33, 0x4f, 0x3d, 0x02, 0x74, 0xf4, 0x81, 0xd6, 0x38, 0x08, 0x21, + 0xe8, 0xe2, 0xa1, 0xfa, 0x05, 0x41, 0x9c, 0x9c, 0xc9, 0xf9, 0xf3, 0xc8, + 0xa3, 0xee, 0x0d, 0xa5, 0xd7, 0x50, 0x54, 0x5e, 0x2f, 0x7d, 0x79, 0xb7, + 0x7e, 0x0a, 0x7c, 0xb6, 0xe2, 0x2c, 0xa8, 0xae, 0xfe, 0x94, 0xd7, 0xcd, + 0x16, 0x30, 0x71, 0x04, 0xaa, 0x9e, 0x79, 0xc3, 0xd2, 0xb6, 0x24, 0xa7, + 0x25, 0xab, 0xf0, 0x48, 0x8e, 0x2f, 0xc3, 0xa7, 0xbb, 0x50, 0xdd, 0x0f, + 0xcf, 0xb0, }; + +static void test_copy_email_addresses(void) { + SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, mail_google_com, sizeof (mail_google_com)); + CFArrayRef array = NULL; + CFStringRef name = NULL; + + ok_status(SecCertificateCopyCommonName(cert, &name), "Failed to get common name from cert"); + ok(name, "Failed to get common name"); + ok(CFEqual(name, CFSTR("mail.google.com")), "Got wrong common name"); + + ok_status(SecCertificateCopyEmailAddresses (cert, &array), "Failed to get email addresses from cert"); + ok(array, "Failed to get email address array"); + is(CFArrayGetCount(array), 0, "Found unexpected email addresses"); + + CFReleaseNull(cert); + CFReleaseNull(name); + CFReleaseNull(array); +} + int si_15_certificate(int argc, char *const *argv) { - plan_tests(24); + plan_tests(30); tests(); test_common_name(); + test_copy_email_addresses(); return 0; } diff --git a/OSX/sec/Security/Regressions/secitem/si-15-delete-access-group.m b/OSX/sec/Security/Regressions/secitem/si-15-delete-access-group.m index bc846996..b4b3a5bc 100644 --- a/OSX/sec/Security/Regressions/secitem/si-15-delete-access-group.m +++ b/OSX/sec/Security/Regressions/secitem/si-15-delete-access-group.m @@ -16,7 +16,7 @@ int si_15_delete_access_group(int argc, char *const *argv) { - plan_tests(4); + plan_tests(11); @autoreleasepool { NSDictionary *query = NULL, *item = NULL; diff --git a/OSX/sec/Security/Regressions/secitem/si-17-item-system-bluetooth.m b/OSX/sec/Security/Regressions/secitem/si-17-item-system-bluetooth.m index cf8f39ff..7b956220 100644 --- a/OSX/sec/Security/Regressions/secitem/si-17-item-system-bluetooth.m +++ b/OSX/sec/Security/Regressions/secitem/si-17-item-system-bluetooth.m @@ -70,7 +70,7 @@ static void tests(void) (__bridge id)kSecAttrService : kBlueToothServiceName, }; - is(SecItemCopyMatching((CFTypeRef)query, NULL), multiUser ? errSecItemNotFound : noErr, "Blue tooth item - user keychain"); + is(SecItemCopyMatching((CFTypeRef)query, NULL), multiUser ? errSecItemNotFound : noErr, "Bluetooth item - user keychain"); query = @{ (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, @@ -78,7 +78,7 @@ static void tests(void) (__bridge id)kSecUseSystemKeychain : @YES, }; - is(SecItemCopyMatching((CFTypeRef)query, NULL), noErr, "Blue tooth item - system keychain"); + is(SecItemCopyMatching((CFTypeRef)query, NULL), noErr, "Bluetooth item - system keychain"); } } diff --git a/OSX/sec/Security/Regressions/secitem/si-18-certificate-parse.m b/OSX/sec/Security/Regressions/secitem/si-18-certificate-parse.m new file mode 100644 index 00000000..6f59d94a --- /dev/null +++ b/OSX/sec/Security/Regressions/secitem/si-18-certificate-parse.m @@ -0,0 +1,195 @@ +/* + * 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@ + */ + +#include "shared_regressions.h" + +#include +#import + +#include +#include +#include +#include +#include + +const NSString *kSecTestParseFailureResources = @"si-18-certificate-parse/ParseFailureCerts"; +const NSString *kSecTestParseSuccessResources = @"si-18-certificate-parse/ParseSuccessCerts"; +const NSString *kSecTestKeyFailureResources = @"si-18-certificate-parse/KeyFailureCerts"; +const NSString *kSecTestPathFailureResources = @"si-18-certificate-parse/PathFailureCerts"; +const NSString *kSecTestTODOFailureResources = @"si-18-certificate-parse/TODOFailureCerts"; + +static uint64_t num_certs() { + uint64_t num_certs = 0; + NSArray * certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestParseFailureResources]; + num_certs += [certURLs count]; + certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestParseSuccessResources]; + num_certs += [certURLs count]; + certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestKeyFailureResources]; + num_certs += [certURLs count]; + certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestPathFailureResources]; + num_certs += [certURLs count]; + certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestTODOFailureResources]; + num_certs += [certURLs count]; + + return num_certs; +} + +static void test_parse_failure(void) { + /* A bunch of certificates with different parsing errors */ + NSArray * certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestParseFailureResources]; + require_action([certURLs count] > 0, testOut, + fail("Unable to find parse test failure certs in bundle.")); + + [certURLs enumerateObjectsUsingBlock:^(NSURL *url, __unused NSUInteger idx, __unused BOOL *stop) { + NSData *certData = [NSData dataWithContentsOfURL:url]; + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); + is(cert, NULL, "Successfully parsed bad cert: %@", url); + CFReleaseNull(cert); + }]; + +testOut: + return; +} + +static void test_parse_success(void) { + /* A bunch of certificates with different parsing variations */ + NSArray * certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestParseSuccessResources]; + require_action([certURLs count] > 0, testOut, + fail("Unable to find parse test failure certs in bundle.")); + + [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 good cert: %@", url); + CFReleaseNull(cert); + }]; + +testOut: + return; +} + +static void test_key_failure(void) { + /* Parse failures that require public key extraction */ + NSArray * certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestKeyFailureResources]; + require_action([certURLs count] > 0, testOut, + fail("Unable to find parse test failure certs in bundle.")); + + [certURLs enumerateObjectsUsingBlock:^(NSURL *url, __unused NSUInteger idx, __unused BOOL *stop) { + NSData *certData = [NSData dataWithContentsOfURL:url]; + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); + SecKeyRef pubkey = NULL; + require_action(cert, blockOut, + fail("Failed to parse cert with SPKI error: %@", url)); +#if TARGET_OS_OSX + pubkey = SecCertificateCopyPublicKey_ios(cert); +#else + pubkey = SecCertificateCopyPublicKey(cert); +#endif + is(pubkey, NULL, "Successfully parsed bad SPKI: %@", url); + + blockOut: + CFReleaseNull(cert); + CFReleaseNull(pubkey); + }]; + +testOut: + return; +} + +static void test_path_parse_failure(void) { + NSArray * certURLs = nil; + SecCertificateRef root = nil; + + NSURL *rootURL = [[NSBundle mainBundle] URLForResource:@"root" withExtension:@".cer" subdirectory:@"si-18-certificate-parse"]; + root = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)[NSData dataWithContentsOfURL:rootURL]); + require_action(root, testOut, + fail("Unable to create root cert")); + certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestPathFailureResources]; + require_action([certURLs count] > 0, testOut, + fail("Unable to find parse test failure certs in bundle.")); + + [certURLs enumerateObjectsUsingBlock:^(NSURL *url, __unused NSUInteger idx, __unused BOOL *stop) { + NSData *certData = [NSData dataWithContentsOfURL:url]; + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateBasicX509(); + SecTrustResultType trustResult = kSecTrustResultInvalid; + + require_noerr_action(SecTrustCreateWithCertificates(cert, policy, &trust), blockOut, + fail("Unable to create trust with certificate: %@", url)); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)[NSArray arrayWithObject:(__bridge id)root]), + blockOut, fail("Unable to set trust in root cert: %@", url)); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)[NSDate dateWithTimeIntervalSinceReferenceDate:507200000.0]), + blockOut, fail("Unable to set verify date: %@", url)); + require_noerr_action(SecTrustEvaluate(trust, &trustResult), blockOut, + fail("Failed ot evaluate trust with error: %@", url)); + is(trustResult, kSecTrustResultRecoverableTrustFailure, "Got wrong trust result (%d) for %@", trustResult, url); + + require_action(cert, blockOut, + fail("Failed to parse cert with SPKI error: %@", url)); + + blockOut: + CFReleaseNull(cert); + CFReleaseNull(trust); + CFReleaseNull(policy); + }]; + + +testOut: + CFReleaseNull(root); +} + +static void test_todo_failures(void) { + /* A bunch of certificates with different parsing errors that currently succeed. */ + NSArray * certURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestTODOFailureResources]; + require_action([certURLs count] > 0, testOut, + fail("Unable to find parse test failure certs in bundle.")); + + [certURLs enumerateObjectsUsingBlock:^(NSURL *url, __unused NSUInteger idx, __unused BOOL *stop) { + NSData *certData = [NSData dataWithContentsOfURL:url]; + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); + { + NSString *reason = [NSString stringWithFormat:@"Bad cert succeeds: %@",url]; + todo([reason UTF8String]); + is(cert, NULL, "Successfully parsed bad cert: %@", url); + } + CFReleaseNull(cert); + }]; + +testOut: + return; +} + +int si_18_certificate_parse(int argc, char *const *argv) +{ + + plan_tests((int)num_certs()); + + test_parse_failure(); + test_parse_success(); + test_key_failure(); + test_path_parse_failure(); + test_todo_failures(); + + return 0; +} diff --git a/OSX/sec/Security/Regressions/secitem/si-20-sectrust.c b/OSX/sec/Security/Regressions/secitem/si-20-sectrust.c index ba421bbc..fc0dd486 100644 --- a/OSX/sec/Security/Regressions/secitem/si-20-sectrust.c +++ b/OSX/sec/Security/Regressions/secitem/si-20-sectrust.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2010,2012-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2006-2010,2012-2017 Apple Inc. All Rights Reserved. */ #include @@ -8,11 +8,13 @@ #include #include #include +#include #include #include #include #include #include +#include #if TARGET_OS_IPHONE #include @@ -82,7 +84,7 @@ SKIP: { SecKeyRef pubKey = NULL; ok(pubKey = SecTrustCopyPublicKey(trust), "copy public key without securityd running"); CFReleaseNull(pubKey); - SecServerSetMachServiceName(NULL); + SecServerSetMachServiceName("com.apple.trustd"); // End of Restore OS environment tests } #endif @@ -112,7 +114,13 @@ SKIP: { is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); is(SecTrustGetCertificateCount(trust), 2, "cert count is 2"); - +#if TARGET_OS_OSX + CFArrayRef certArray; + ok_status(SecTrustCopyAnchorCertificates(&certArray), "copy anchors"); + CFReleaseSafe(certArray); + ok_status(SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &certArray), "copy certificates"); + CFReleaseSafe(certArray); +#endif CFReleaseNull(anchors); anchors = CFArrayCreate(NULL, NULL, 0, NULL); ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set empty anchors list"); @@ -448,7 +456,7 @@ static bool test_chain_of_three(uint8_t *cert0, size_t cert0len, if (failureReason && should_succeed && !did_succeed) { *failureReason = SecTrustCopyFailureDescription(trust); } else if (failureReason && !should_succeed && did_succeed) { - *failureReason = CFSTR("expected kSecTrustResultRecoverableTrustFailure"); + *failureReason = CFSTR("expected kSecTrustResultFatalTrustFailure"); } if ((should_succeed && did_succeed) || (!should_succeed && !did_succeed)) { @@ -585,15 +593,69 @@ errOut: CFReleaseNull(date); } +static void test_expired_only() { + SecCertificateRef cert0 = NULL, cert1 = NULL, cert2 = NULL; + SecPolicyRef policy = NULL; + SecTrustRef trust = NULL; + CFArrayRef certificates = NULL, roots = NULL; + CFDateRef date = NULL; + + require(cert0 = SecCertificateCreateWithBytes(NULL, _expired_badssl, sizeof(_expired_badssl)), errOut); + require(cert1 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_dvss, sizeof(_comodo_rsa_dvss)), errOut); + require(cert2 = SecCertificateCreateWithBytes(NULL, _comodo_rsa_root, sizeof(_comodo_rsa_root)), errOut); + + const void *v_certs[] = { + cert0, + cert1 + }; + certificates = CFArrayCreate(NULL, v_certs, + array_size(v_certs), + &kCFTypeArrayCallBacks); + + const void *v_roots[] = { + cert2 + }; + roots = CFArrayCreate(NULL, v_roots, + array_size(v_roots), + &kCFTypeArrayCallBacks); + + require(policy = SecPolicyCreateSSL(true, CFSTR("expired.badssl.com")), errOut); + require_noerr(SecTrustCreateWithCertificates(certificates, policy, &trust), errOut); + require_noerr(SecTrustSetAnchorCertificates(trust, roots), errOut); + + /* Mar 21 2017 (cert expired in 2015, so this will cause a validity error.) */ + require(date = CFDateCreateForGregorianZuluMoment(NULL, 2017, 3, 21, 12, 0, 0), errOut); + require_noerr(SecTrustSetVerifyDate(trust, date), errOut); + + /* SecTrustIsExpiredOnly implicitly evaluates the trust */ + ok(SecTrustIsExpiredOnly(trust), "REGRESSION: has new error as well as expiration"); + + CFReleaseNull(policy); + require(policy = SecPolicyCreateSSL(true, CFSTR("expired.terriblessl.com")), errOut); + require_noerr(SecTrustSetPolicies(trust, policy), errOut); + /* expect a hostname mismatch as well as expiration */ + ok(!SecTrustIsExpiredOnly(trust), "REGRESSION: should have found multiple errors"); + +errOut: + CFReleaseNull(trust); + CFReleaseNull(cert0); + CFReleaseNull(cert1); + CFReleaseNull(cert2); + CFReleaseNull(policy); + CFReleaseNull(certificates); + CFReleaseNull(roots); + CFReleaseNull(date); +} + int si_20_sectrust(int argc, char *const *argv) { #if TARGET_OS_IPHONE - plan_tests(101+9+(8*13)+9+1); + plan_tests(101+9+(8*13)+9+1+2); #else - plan_tests(97+9+(8*13)+9+1); + plan_tests(97+9+(8*13)+9+1+2+2); #endif - basic_tests(); + basic_tests(); negative_integer_tests(); rsa8k_tests(); date_tests(); @@ -601,6 +663,7 @@ int si_20_sectrust(int argc, char *const *argv) ec_key_size_tests(); test_input_certificates(); test_async_trust(); + test_expired_only(); - return 0; + return 0; } diff --git a/OSX/sec/Security/Regressions/secitem/si-20-sectrust.h b/OSX/sec/Security/Regressions/secitem/si-20-sectrust.h index 7c0d2135..b61eeda2 100644 --- a/OSX/sec/Security/Regressions/secitem/si-20-sectrust.h +++ b/OSX/sec/Security/Regressions/secitem/si-20-sectrust.h @@ -1680,3 +1680,294 @@ unsigned char _root_AACA2[618]={ 0xE1,0x7D,0x22,0xD8,0x36,0xC1,0x88,0xC1,0x07,0xD9,0x4D,0x88,0x2E,0x08,0xA2,0xDD, 0x13,0xB5,0x2A,0xAE,0x3B,0x83,0x2B,0xB2,0x7E,0xB3, }; + +/* subject:/OU=Domain Control Validated/OU=PositiveSSL Wildcard/CN=*.badssl.com */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA */ +unsigned char _expired_badssl[1359]={ + 0x30,0x82,0x05,0x4B,0x30,0x82,0x04,0x33,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4A, + 0xE7,0x95,0x49,0xFA,0x9A,0xBE,0x3F,0x10,0x0F,0x17,0xA4,0x78,0xE1,0x69,0x09,0x30, + 0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81, + 0x90,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,0x36,0x30,0x34,0x06,0x03,0x55, + 0x04,0x03,0x13,0x2D,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x44, + 0x6F,0x6D,0x61,0x69,0x6E,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,0x35,0x30,0x34,0x30,0x39,0x30,0x30,0x30,0x30,0x30, + 0x30,0x5A,0x17,0x0D,0x31,0x35,0x30,0x34,0x31,0x32,0x32,0x33,0x35,0x39,0x35,0x39, + 0x5A,0x30,0x59,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x44,0x6F, + 0x6D,0x61,0x69,0x6E,0x20,0x43,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x20,0x56,0x61,0x6C, + 0x69,0x64,0x61,0x74,0x65,0x64,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13, + 0x14,0x50,0x6F,0x73,0x69,0x74,0x69,0x76,0x65,0x53,0x53,0x4C,0x20,0x57,0x69,0x6C, + 0x64,0x63,0x61,0x72,0x64,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x03,0x14,0x0C, + 0x2A,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,0xC2,0x04,0xEC, + 0xF8,0x8C,0xEE,0x04,0xC2,0xB3,0xD8,0x50,0xD5,0x70,0x58,0xCC,0x93,0x18,0xEB,0x5C, + 0xA8,0x68,0x49,0xB0,0x22,0xB5,0xF9,0x95,0x9E,0xB1,0x2B,0x2C,0x76,0x3E,0x6C,0xC0, + 0x4B,0x60,0x4C,0x4C,0xEA,0xB2,0xB4,0xC0,0x0F,0x80,0xB6,0xB0,0xF9,0x72,0xC9,0x86, + 0x02,0xF9,0x5C,0x41,0x5D,0x13,0x2B,0x7F,0x71,0xC4,0x4B,0xBC,0xE9,0x94,0x2E,0x50, + 0x37,0xA6,0x67,0x1C,0x61,0x8C,0xF6,0x41,0x42,0xC5,0x46,0xD3,0x16,0x87,0x27,0x9F, + 0x74,0xEB,0x0A,0x9D,0x11,0x52,0x26,0x21,0x73,0x6C,0x84,0x4C,0x79,0x55,0xE4,0xD1, + 0x6B,0xE8,0x06,0x3D,0x48,0x15,0x52,0xAD,0xB3,0x28,0xDB,0xAA,0xFF,0x6E,0xFF,0x60, + 0x95,0x4A,0x77,0x6B,0x39,0xF1,0x24,0xD1,0x31,0xB6,0xDD,0x4D,0xC0,0xC4,0xFC,0x53, + 0xB9,0x6D,0x42,0xAD,0xB5,0x7C,0xFE,0xAE,0xF5,0x15,0xD2,0x33,0x48,0xE7,0x22,0x71, + 0xC7,0xC2,0x14,0x7A,0x6C,0x28,0xEA,0x37,0x4A,0xDF,0xEA,0x6C,0xB5,0x72,0xB4,0x7E, + 0x5A,0xA2,0x16,0xDC,0x69,0xB1,0x57,0x44,0xDB,0x0A,0x12,0xAB,0xDE,0xC3,0x0F,0x47, + 0x74,0x5C,0x41,0x22,0xE1,0x9A,0xF9,0x1B,0x93,0xE6,0xAD,0x22,0x06,0x29,0x2E,0xB1, + 0xBA,0x49,0x1C,0x0C,0x27,0x9E,0xA3,0xFB,0x8B,0xF7,0x40,0x72,0x00,0xAC,0x92,0x08, + 0xD9,0x8C,0x57,0x84,0x53,0x81,0x05,0xCB,0xE6,0xFE,0x6B,0x54,0x98,0x40,0x27,0x85, + 0xC7,0x10,0xBB,0x73,0x70,0xEF,0x69,0x18,0x41,0x07,0x45,0x55,0x7C,0xF9,0x64,0x3F, + 0x3D,0x2C,0xC3,0xA9,0x7C,0xEB,0x93,0x1A,0x4C,0x86,0xD1,0xCA,0x85,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,0x90,0xAF,0x6A,0x3A,0x94,0x5A,0x0B,0xD8,0x90, + 0xEA,0x12,0x56,0x73,0xDF,0x43,0xB4,0x3A,0x28,0xDA,0xE7,0x30,0x1D,0x06,0x03,0x55, + 0x1D,0x0E,0x04,0x16,0x04,0x14,0x9D,0xEE,0xC1,0x7B,0x81,0x0B,0x3A,0x47,0x69,0x71, + 0x18,0x7D,0x11,0x37,0x93,0xBC,0xA5,0x1B,0x3F,0xFB,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,0x4F,0x06,0x03,0x55,0x1D,0x20,0x04,0x48, + 0x30,0x46,0x30,0x3A,0x06,0x0B,0x2B,0x06,0x01,0x04,0x01,0xB2,0x31,0x01,0x02,0x02, + 0x07,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,0x08, + 0x06,0x06,0x67,0x81,0x0C,0x01,0x02,0x01,0x30,0x54,0x06,0x03,0x55,0x1D,0x1F,0x04, + 0x4D,0x30,0x4B,0x30,0x49,0xA0,0x47,0xA0,0x45,0x86,0x43,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,0x44,0x6F,0x6D,0x61, + 0x69,0x6E,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, + 0x85,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x79,0x30,0x77,0x30, + 0x4F,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x43,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,0x44,0x6F, + 0x6D,0x61,0x69,0x6E,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,0x23,0x06,0x03,0x55,0x1D,0x11,0x04,0x1C,0x30, + 0x1A,0x82,0x0C,0x2A,0x2E,0x62,0x61,0x64,0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x82, + 0x0A,0x62,0x61,0x64,0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x06,0x09,0x2A, + 0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x6A, + 0x7A,0xF1,0xDA,0xFF,0x03,0x07,0x72,0x78,0xC5,0x66,0xA1,0x4F,0x46,0x43,0x0E,0x5F, + 0x14,0x21,0x8C,0x75,0x1A,0xEB,0x36,0xE0,0x1F,0xA4,0x10,0x15,0xEC,0xDA,0x33,0x25, + 0x7C,0x3B,0xB5,0x0A,0xC7,0x01,0x38,0x3D,0x27,0xFD,0x58,0xD9,0xCC,0xEA,0x2D,0x69, + 0x39,0x7C,0xBE,0x97,0xEF,0x0B,0xD6,0x0B,0x58,0xE7,0x8C,0x7F,0xBF,0xB3,0x4C,0x1D, + 0xF3,0xB7,0x90,0x80,0xA6,0x36,0x7C,0x14,0x5B,0xEC,0x07,0x2D,0x02,0x3E,0x1B,0x5B, + 0x63,0x5B,0x15,0xAB,0x00,0xFA,0x1F,0x3B,0x19,0x2D,0xDF,0xE2,0x23,0x10,0x11,0x07, + 0x7E,0x72,0x7F,0xE2,0xBF,0xB7,0x00,0x1B,0x98,0x2F,0x2C,0x3F,0xCE,0x85,0x9A,0x27, + 0x8C,0x10,0x22,0x08,0x41,0x2B,0x8A,0x3E,0x82,0x4E,0xFC,0xDD,0x21,0xC6,0x56,0x74, + 0x70,0xA4,0x34,0xF2,0xB1,0x40,0x9E,0x2B,0x58,0xA2,0x59,0x0F,0x1D,0x48,0xEF,0xEB, + 0x11,0x3E,0xC1,0x4A,0x9E,0xBC,0x65,0x55,0x6D,0xC6,0xA3,0xEF,0xD5,0xD4,0x96,0xCD, + 0xF1,0xAE,0x27,0xF7,0xA4,0x57,0x14,0x3C,0x94,0x41,0x05,0x7A,0x8B,0xA1,0x37,0x47, + 0xD7,0xF5,0x7D,0xDC,0xFA,0xCE,0x6F,0x31,0xA2,0xB0,0x8C,0xEA,0xCC,0x12,0x9B,0x22, + 0xF1,0x34,0x70,0xCF,0x7D,0x75,0x4A,0x8B,0x68,0x29,0x0C,0x1E,0xE9,0x96,0xA8,0xCF, + 0xB0,0x12,0x1F,0x5C,0x2A,0xEE,0x67,0x2F,0x7F,0xBD,0x73,0xF3,0x5A,0x01,0x22,0x0C, + 0x70,0xFA,0xCD,0x45,0xEF,0x78,0x5C,0xCE,0x0D,0xFA,0x4E,0xE1,0xEF,0xCE,0x65,0x9F, + 0x47,0x0C,0x4F,0xBB,0x36,0x44,0x68,0x56,0x5C,0x56,0x59,0xAD,0xAA,0x8A,0xBC, +}; + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */ +unsigned char _comodo_rsa_dvss[1548]={ + 0x30,0x82,0x06,0x08,0x30,0x82,0x03,0xF0,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x2B, + 0x2E,0x6E,0xEA,0xD9,0x75,0x36,0x6C,0x14,0x8A,0x6E,0xDB,0xA3,0x7C,0x8C,0x07,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,0x34,0x30,0x32,0x31,0x32, + 0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x39,0x30,0x32,0x31,0x31,0x32, + 0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x90,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,0x36,0x30,0x34,0x06,0x03,0x55,0x04,0x03,0x13,0x2D,0x43,0x4F,0x4D,0x4F, + 0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x44,0x6F,0x6D,0x61,0x69,0x6E,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,0x8E,0xC2,0x02,0x19,0xE1,0xA0, + 0x59,0xA4,0xEB,0x38,0x35,0x8D,0x2C,0xFD,0x01,0xD0,0xD3,0x49,0xC0,0x64,0xC7,0x0B, + 0x62,0x05,0x45,0x16,0x3A,0xA8,0xA0,0xC0,0x0C,0x02,0x7F,0x1D,0xCC,0xDB,0xC4,0xA1, + 0x6D,0x77,0x03,0xA3,0x0F,0x86,0xF9,0xE3,0x06,0x9C,0x3E,0x0B,0x81,0x8A,0x9B,0x49, + 0x1B,0xAD,0x03,0xBE,0xFA,0x4B,0xDB,0x8C,0x20,0xED,0xD5,0xCE,0x5E,0x65,0x8E,0x3E, + 0x0D,0xAF,0x4C,0xC2,0xB0,0xB7,0x45,0x5E,0x52,0x2F,0x34,0xDE,0x48,0x24,0x64,0xB4, + 0x41,0xAE,0x00,0x97,0xF7,0xBE,0x67,0xDE,0x9E,0xD0,0x7A,0xA7,0x53,0x80,0x3B,0x7C, + 0xAD,0xF5,0x96,0x55,0x6F,0x97,0x47,0x0A,0x7C,0x85,0x8B,0x22,0x97,0x8D,0xB3,0x84, + 0xE0,0x96,0x57,0xD0,0x70,0x18,0x60,0x96,0x8F,0xEE,0x2D,0x07,0x93,0x9D,0xA1,0xBA, + 0xCA,0xD1,0xCD,0x7B,0xE9,0xC4,0x2A,0x9A,0x28,0x21,0x91,0x4D,0x6F,0x92,0x4F,0x25, + 0xA5,0xF2,0x7A,0x35,0xDD,0x26,0xDC,0x46,0xA5,0xD0,0xAC,0x59,0x35,0x8C,0xFF,0x4E, + 0x91,0x43,0x50,0x3F,0x59,0x93,0x1E,0x6C,0x51,0x21,0xEE,0x58,0x14,0xAB,0xFE,0x75, + 0x50,0x78,0x3E,0x4C,0xB0,0x1C,0x86,0x13,0xFA,0x6B,0x98,0xBC,0xE0,0x3B,0x94,0x1E, + 0x85,0x52,0xDC,0x03,0x93,0x24,0x18,0x6E,0xCB,0x27,0x51,0x45,0xE6,0x70,0xDE,0x25, + 0x43,0xA4,0x0D,0xE1,0x4A,0xA5,0xED,0xB6,0x7E,0xC8,0xCD,0x6D,0xEE,0x2E,0x1D,0x27, + 0x73,0x5D,0xDC,0x45,0x30,0x80,0xAA,0xE3,0xB2,0x41,0x0B,0xAF,0xBD,0x44,0x87,0xDA, + 0xB9,0xE5,0x1B,0x9D,0x7F,0xAE,0xE5,0x85,0x82,0xA5,0x02,0x03,0x01,0x00,0x01,0xA3, + 0x82,0x01,0x65,0x30,0x82,0x01,0x61,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,0x90,0xAF,0x6A,0x3A,0x94,0x5A,0x0B,0xD8,0x90,0xEA,0x12,0x56,0x73, + 0xDF,0x43,0xB4,0x3A,0x28,0xDA,0xE7,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01, + 0xFF,0x04,0x04,0x03,0x02,0x01,0x86,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,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,0x1B,0x06,0x03,0x55,0x1D, + 0x20,0x04,0x14,0x30,0x12,0x30,0x06,0x06,0x04,0x55,0x1D,0x20,0x00,0x30,0x08,0x06, + 0x06,0x67,0x81,0x0C,0x01,0x02,0x01,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,0x4E,0x2B,0x76,0x4F, + 0x92,0x1C,0x62,0x36,0x89,0xBA,0x77,0xC1,0x27,0x05,0xF4,0x1C,0xD6,0x44,0x9D,0xA9, + 0x9A,0x3E,0xAA,0xD5,0x66,0x66,0x01,0x3E,0xEA,0x49,0xE6,0xA2,0x35,0xBC,0xFA,0xF6, + 0xDD,0x95,0x8E,0x99,0x35,0x98,0x0E,0x36,0x18,0x75,0xB1,0xDD,0xDD,0x50,0x72,0x7C, + 0xAE,0xDC,0x77,0x88,0xCE,0x0F,0xF7,0x90,0x20,0xCA,0xA3,0x67,0x2E,0x1F,0x56,0x7F, + 0x7B,0xE1,0x44,0xEA,0x42,0x95,0xC4,0x5D,0x0D,0x01,0x50,0x46,0x15,0xF2,0x81,0x89, + 0x59,0x6C,0x8A,0xDD,0x8C,0xF1,0x12,0xA1,0x8D,0x3A,0x42,0x8A,0x98,0xF8,0x4B,0x34, + 0x7B,0x27,0x3B,0x08,0xB4,0x6F,0x24,0x3B,0x72,0x9D,0x63,0x74,0x58,0x3C,0x1A,0x6C, + 0x3F,0x4F,0xC7,0x11,0x9A,0xC8,0xA8,0xF5,0xB5,0x37,0xEF,0x10,0x45,0xC6,0x6C,0xD9, + 0xE0,0x5E,0x95,0x26,0xB3,0xEB,0xAD,0xA3,0xB9,0xEE,0x7F,0x0C,0x9A,0x66,0x35,0x73, + 0x32,0x60,0x4E,0xE5,0xDD,0x8A,0x61,0x2C,0x6E,0x52,0x11,0x77,0x68,0x96,0xD3,0x18, + 0x75,0x51,0x15,0x00,0x1B,0x74,0x88,0xDD,0xE1,0xC7,0x38,0x04,0x43,0x28,0xE9,0x16, + 0xFD,0xD9,0x05,0xD4,0x5D,0x47,0x27,0x60,0xD6,0xFB,0x38,0x3B,0x6C,0x72,0xA2,0x94, + 0xF8,0x42,0x1A,0xDF,0xED,0x6F,0x06,0x8C,0x45,0xC2,0x06,0x00,0xAA,0xE4,0xE8,0xDC, + 0xD9,0xB5,0xE1,0x73,0x78,0xEC,0xF6,0x23,0xDC,0xD1,0xDD,0x6C,0x8E,0x1A,0x8F,0xA5, + 0xEA,0x54,0x7C,0x96,0xB7,0xC3,0xFE,0x55,0x8E,0x8D,0x49,0x5E,0xFC,0x64,0xBB,0xCF, + 0x3E,0xBD,0x96,0xEB,0x69,0xCD,0xBF,0xE0,0x48,0xF1,0x62,0x82,0x10,0xE5,0x0C,0x46, + 0x57,0xF2,0x33,0xDA,0xD0,0xC8,0x63,0xED,0xC6,0x1F,0x94,0x05,0x96,0x4A,0x1A,0x91, + 0xD1,0xF7,0xEB,0xCF,0x8F,0x52,0xAE,0x0D,0x08,0xD9,0x3E,0xA8,0xA0,0x51,0xE9,0xC1, + 0x87,0x74,0xD5,0xC9,0xF7,0x74,0xAB,0x2E,0x53,0xFB,0xBB,0x7A,0xFB,0x97,0xE2,0xF8, + 0x1F,0x26,0x8F,0xB3,0xD2,0xA0,0xE0,0x37,0x5B,0x28,0x3B,0x31,0xE5,0x0E,0x57,0x2D, + 0x5A,0xB8,0xAD,0x79,0xAC,0x5E,0x20,0x66,0x1A,0xA5,0xB9,0xA6,0xB5,0x39,0xC1,0xF5, + 0x98,0x43,0xFF,0xEE,0xF9,0xA7,0xA7,0xFD,0xEE,0xCA,0x24,0x3D,0x80,0x16,0xC4,0x17, + 0x8F,0x8A,0xC1,0x60,0xA1,0x0C,0xAE,0x5B,0x43,0x47,0x91,0x4B,0xD5,0x9A,0x17,0x5F, + 0xF9,0xD4,0x87,0xC1,0xC2,0x8C,0xB7,0xE7,0xE2,0x0F,0x30,0x19,0x37,0x86,0xAC,0xE0, + 0xDC,0x42,0x03,0xE6,0x94,0xA8,0x9D,0xAE,0xFD,0x0F,0x24,0x51,0x94,0xCE,0x92,0x08, + 0xD1,0xFC,0x50,0xF0,0x03,0x40,0x7B,0x88,0x59,0xED,0x0E,0xDD,0xAC,0xD2,0x77,0x82, + 0x34,0xDC,0x06,0x95,0x02,0xD8,0x90,0xF9,0x2D,0xEA,0x37,0xD5,0x1A,0x60,0xD0,0x67, + 0x20,0xD7,0xD8,0x42,0x0B,0x45,0xAF,0x82,0x68,0xDE,0xDD,0x66,0x24,0x37,0x90,0x29, + 0x94,0x19,0x46,0x19,0x25,0xB8,0x80,0xD7,0xCB,0xD4,0x86,0x28,0x6A,0x44,0x70,0x26, + 0x23,0x62,0xA9,0x9F,0x86,0x6F,0xBF,0xBA,0x90,0x70,0xD2,0x56,0x77,0x85,0x78,0xEF, + 0xEA,0x25,0xA9,0x17,0xCE,0x50,0x72,0x8C,0x00,0x3A,0xAA,0xE3,0xDB,0x63,0x34,0x9F, + 0xF8,0x06,0x71,0x01,0xE2,0x82,0x20,0xD4,0xFE,0x6F,0xBD,0xB1, +}; + +/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */ +/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */ +unsigned char _comodo_rsa_root[1500]={ + 0x30,0x82,0x05,0xD8,0x30,0x82,0x03,0xC0,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4C, + 0xAA,0xF9,0xCA,0xDB,0x63,0x6F,0xE0,0x1F,0xF7,0x4E,0xD8,0x5B,0x03,0x86,0x9D,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,0x30,0x30,0x31,0x31,0x39, + 0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,0x38,0x30,0x31,0x31,0x38,0x32, + 0x33,0x35,0x39,0x35,0x39,0x5A,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,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,0x91, + 0xE8,0x54,0x92,0xD2,0x0A,0x56,0xB1,0xAC,0x0D,0x24,0xDD,0xC5,0xCF,0x44,0x67,0x74, + 0x99,0x2B,0x37,0xA3,0x7D,0x23,0x70,0x00,0x71,0xBC,0x53,0xDF,0xC4,0xFA,0x2A,0x12, + 0x8F,0x4B,0x7F,0x10,0x56,0xBD,0x9F,0x70,0x72,0xB7,0x61,0x7F,0xC9,0x4B,0x0F,0x17, + 0xA7,0x3D,0xE3,0xB0,0x04,0x61,0xEE,0xFF,0x11,0x97,0xC7,0xF4,0x86,0x3E,0x0A,0xFA, + 0x3E,0x5C,0xF9,0x93,0xE6,0x34,0x7A,0xD9,0x14,0x6B,0xE7,0x9C,0xB3,0x85,0xA0,0x82, + 0x7A,0x76,0xAF,0x71,0x90,0xD7,0xEC,0xFD,0x0D,0xFA,0x9C,0x6C,0xFA,0xDF,0xB0,0x82, + 0xF4,0x14,0x7E,0xF9,0xBE,0xC4,0xA6,0x2F,0x4F,0x7F,0x99,0x7F,0xB5,0xFC,0x67,0x43, + 0x72,0xBD,0x0C,0x00,0xD6,0x89,0xEB,0x6B,0x2C,0xD3,0xED,0x8F,0x98,0x1C,0x14,0xAB, + 0x7E,0xE5,0xE3,0x6E,0xFC,0xD8,0xA8,0xE4,0x92,0x24,0xDA,0x43,0x6B,0x62,0xB8,0x55, + 0xFD,0xEA,0xC1,0xBC,0x6C,0xB6,0x8B,0xF3,0x0E,0x8D,0x9A,0xE4,0x9B,0x6C,0x69,0x99, + 0xF8,0x78,0x48,0x30,0x45,0xD5,0xAD,0xE1,0x0D,0x3C,0x45,0x60,0xFC,0x32,0x96,0x51, + 0x27,0xBC,0x67,0xC3,0xCA,0x2E,0xB6,0x6B,0xEA,0x46,0xC7,0xC7,0x20,0xA0,0xB1,0x1F, + 0x65,0xDE,0x48,0x08,0xBA,0xA4,0x4E,0xA9,0xF2,0x83,0x46,0x37,0x84,0xEB,0xE8,0xCC, + 0x81,0x48,0x43,0x67,0x4E,0x72,0x2A,0x9B,0x5C,0xBD,0x4C,0x1B,0x28,0x8A,0x5C,0x22, + 0x7B,0xB4,0xAB,0x98,0xD9,0xEE,0xE0,0x51,0x83,0xC3,0x09,0x46,0x4E,0x6D,0x3E,0x99, + 0xFA,0x95,0x17,0xDA,0x7C,0x33,0x57,0x41,0x3C,0x8D,0x51,0xED,0x0B,0xB6,0x5C,0xAF, + 0x2C,0x63,0x1A,0xDF,0x57,0xC8,0x3F,0xBC,0xE9,0x5D,0xC4,0x9B,0xAF,0x45,0x99,0xE2, + 0xA3,0x5A,0x24,0xB4,0xBA,0xA9,0x56,0x3D,0xCF,0x6F,0xAA,0xFF,0x49,0x58,0xBE,0xF0, + 0xA8,0xFF,0xF4,0xB8,0xAD,0xE9,0x37,0xFB,0xBA,0xB8,0xF4,0x0B,0x3A,0xF9,0xE8,0x43, + 0x42,0x1E,0x89,0xD8,0x84,0xCB,0x13,0xF1,0xD9,0xBB,0xE1,0x89,0x60,0xB8,0x8C,0x28, + 0x56,0xAC,0x14,0x1D,0x9C,0x0A,0xE7,0x71,0xEB,0xCF,0x0E,0xDD,0x3D,0xA9,0x96,0xA1, + 0x48,0xBD,0x3C,0xF7,0xAF,0xB5,0x0D,0x22,0x4C,0xC0,0x11,0x81,0xEC,0x56,0x3B,0xF6, + 0xD3,0xA2,0xE2,0x5B,0xB7,0xB2,0x04,0x22,0x52,0x95,0x80,0x93,0x69,0xE8,0x8E,0x4C, + 0x65,0xF1,0x91,0x03,0x2D,0x70,0x74,0x02,0xEA,0x8B,0x67,0x15,0x29,0x69,0x52,0x02, + 0xBB,0xD7,0xDF,0x50,0x6A,0x55,0x46,0xBF,0xA0,0xA3,0x28,0x61,0x7F,0x70,0xD0,0xC3, + 0xA2,0xAA,0x2C,0x21,0xAA,0x47,0xCE,0x28,0x9C,0x06,0x45,0x76,0xBF,0x82,0x18,0x27, + 0xB4,0xD5,0xAE,0xB4,0xCB,0x50,0xE6,0x6B,0xF4,0x4C,0x86,0x71,0x30,0xE9,0xA6,0xDF, + 0x16,0x86,0xE0,0xD8,0xFF,0x40,0xDD,0xFB,0xD0,0x42,0x88,0x7F,0xA3,0x33,0x3A,0x2E, + 0x5C,0x1E,0x41,0x11,0x81,0x63,0xCE,0x18,0x71,0x6B,0x2B,0xEC,0xA6,0x8A,0xB7,0x31, + 0x5C,0x3A,0x6A,0x47,0xE0,0xC3,0x79,0x59,0xD6,0x20,0x1A,0xAF,0xF2,0x6A,0x98,0xAA, + 0x72,0xBC,0x57,0x4A,0xD2,0x4B,0x9D,0xBB,0x10,0xFC,0xB0,0x4C,0x41,0xE5,0xED,0x1D, + 0x3D,0x5E,0x28,0x9D,0x9C,0xCC,0xBF,0xB3,0x51,0xDA,0xA7,0x47,0xE5,0x84,0x53,0x02, + 0x03,0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, + 0x16,0x04,0x14,0xBB,0xAF,0x7E,0x02,0x3D,0xFA,0xA6,0xF1,0x3C,0x84,0x8E,0xAD,0xEE, + 0x38,0x98,0xEC,0xD9,0x32,0x32,0xD4,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,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, + 0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x0A,0xF1,0xD5,0x46, + 0x84,0xB7,0xAE,0x51,0xBB,0x6C,0xB2,0x4D,0x41,0x14,0x00,0x93,0x4C,0x9C,0xCB,0xE5, + 0xC0,0x54,0xCF,0xA0,0x25,0x8E,0x02,0xF9,0xFD,0xB0,0xA2,0x0D,0xF5,0x20,0x98,0x3C, + 0x13,0x2D,0xAC,0x56,0xA2,0xB0,0xD6,0x7E,0x11,0x92,0xE9,0x2E,0xBA,0x9E,0x2E,0x9A, + 0x72,0xB1,0xBD,0x19,0x44,0x6C,0x61,0x35,0xA2,0x9A,0xB4,0x16,0x12,0x69,0x5A,0x8C, + 0xE1,0xD7,0x3E,0xA4,0x1A,0xE8,0x2F,0x03,0xF4,0xAE,0x61,0x1D,0x10,0x1B,0x2A,0xA4, + 0x8B,0x7A,0xC5,0xFE,0x05,0xA6,0xE1,0xC0,0xD6,0xC8,0xFE,0x9E,0xAE,0x8F,0x2B,0xBA, + 0x3D,0x99,0xF8,0xD8,0x73,0x09,0x58,0x46,0x6E,0xA6,0x9C,0xF4,0xD7,0x27,0xD3,0x95, + 0xDA,0x37,0x83,0x72,0x1C,0xD3,0x73,0xE0,0xA2,0x47,0x99,0x03,0x38,0x5D,0xD5,0x49, + 0x79,0x00,0x29,0x1C,0xC7,0xEC,0x9B,0x20,0x1C,0x07,0x24,0x69,0x57,0x78,0xB2,0x39, + 0xFC,0x3A,0x84,0xA0,0xB5,0x9C,0x7C,0x8D,0xBF,0x2E,0x93,0x62,0x27,0xB7,0x39,0xDA, + 0x17,0x18,0xAE,0xBD,0x3C,0x09,0x68,0xFF,0x84,0x9B,0x3C,0xD5,0xD6,0x0B,0x03,0xE3, + 0x57,0x9E,0x14,0xF7,0xD1,0xEB,0x4F,0xC8,0xBD,0x87,0x23,0xB7,0xB6,0x49,0x43,0x79, + 0x85,0x5C,0xBA,0xEB,0x92,0x0B,0xA1,0xC6,0xE8,0x68,0xA8,0x4C,0x16,0xB1,0x1A,0x99, + 0x0A,0xE8,0x53,0x2C,0x92,0xBB,0xA1,0x09,0x18,0x75,0x0C,0x65,0xA8,0x7B,0xCB,0x23, + 0xB7,0x1A,0xC2,0x28,0x85,0xC3,0x1B,0xFF,0xD0,0x2B,0x62,0xEF,0xA4,0x7B,0x09,0x91, + 0x98,0x67,0x8C,0x14,0x01,0xCD,0x68,0x06,0x6A,0x63,0x21,0x75,0x03,0x80,0x88,0x8A, + 0x6E,0x81,0xC6,0x85,0xF2,0xA9,0xA4,0x2D,0xE7,0xF4,0xA5,0x24,0x10,0x47,0x83,0xCA, + 0xCD,0xF4,0x8D,0x79,0x58,0xB1,0x06,0x9B,0xE7,0x1A,0x2A,0xD9,0x9D,0x01,0xD7,0x94, + 0x7D,0xED,0x03,0x4A,0xCA,0xF0,0xDB,0xE8,0xA9,0x01,0x3E,0xF5,0x56,0x99,0xC9,0x1E, + 0x8E,0x49,0x3D,0xBB,0xE5,0x09,0xB9,0xE0,0x4F,0x49,0x92,0x3D,0x16,0x82,0x40,0xCC, + 0xCC,0x59,0xC6,0xE6,0x3A,0xED,0x12,0x2E,0x69,0x3C,0x6C,0x95,0xB1,0xFD,0xAA,0x1D, + 0x7B,0x7F,0x86,0xBE,0x1E,0x0E,0x32,0x46,0xFB,0xFB,0x13,0x8F,0x75,0x7F,0x4C,0x8B, + 0x4B,0x46,0x63,0xFE,0x00,0x34,0x40,0x70,0xC1,0xC3,0xB9,0xA1,0xDD,0xA6,0x70,0xE2, + 0x04,0xB3,0x41,0xBC,0xE9,0x80,0x91,0xEA,0x64,0x9C,0x7A,0xE1,0x22,0x03,0xA9,0x9C, + 0x6E,0x6F,0x0E,0x65,0x4F,0x6C,0x87,0x87,0x5E,0xF3,0x6E,0xA0,0xF9,0x75,0xA5,0x9B, + 0x40,0xE8,0x53,0xB2,0x27,0x9D,0x4A,0xB9,0xC0,0x77,0x21,0x8D,0xFF,0x87,0xF2,0xDE, + 0xBC,0x8C,0xEF,0x17,0xDF,0xB7,0x49,0x0B,0xD1,0xF2,0x6E,0x30,0x0B,0x1A,0x0E,0x4E, + 0x76,0xED,0x11,0xFC,0xF5,0xE9,0x56,0xB2,0x7D,0xBF,0xC7,0x6D,0x0A,0x93,0x8C,0xA5, + 0xD0,0xC0,0xB6,0x1D,0xBE,0x3A,0x4E,0x94,0xA2,0xD7,0x6E,0x6C,0x0B,0xC2,0x8A,0x7C, + 0xFA,0x20,0xF3,0xC4,0xE4,0xE5,0xCD,0x0D,0xA8,0xCB,0x91,0x92,0xB1,0x7C,0x85,0xEC, + 0xB5,0x14,0x69,0x66,0x0E,0x82,0xE7,0xCD,0xCE,0xC8,0x2D,0xA6,0x51,0x7F,0x21,0xC1, + 0x35,0x53,0x85,0x06,0x4A,0x5D,0x9F,0xAD,0xBB,0x1B,0x5F,0x74, +}; diff --git a/OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c b/OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c index e227e08f..d9b3ce58 100644 --- a/OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c +++ b/OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c @@ -1020,17 +1020,11 @@ static void tests(void) is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); - + /* Certificates are only EV if they are also CT. These aren't CT. */ CFDictionaryRef info = SecTrustCopyInfo(trust); CFBooleanRef ev = (CFBooleanRef)CFDictionaryGetValue(info, kSecTrustInfoExtendedValidationKey); - ok(ev && CFEqual(kCFBooleanTrue, ev), "extended validation succeeded"); - - CFStringRef companyName = (CFStringRef)CFDictionaryGetValue(info, - kSecTrustInfoCompanyNameKey); - CFReleaseSafe(info); - ok(companyName && CFEqual(CFSTR("PayPal, Inc."), companyName), - "kSecTrustInfoCompanyNameKey is correct"); + ok(!ev, "extended validation succeeded"); SecPolicyRef ocspSignerPolicy; ok(ocspSignerPolicy = SecPolicyCreateOCSPSigner(), @@ -1059,7 +1053,7 @@ static void tests(void) "trust is kSecTrustResultUnspecified"); CFReleaseSafe(ocspSignerPolicy); - //CFReleaseSafe(info); + CFReleaseSafe(info); CFReleaseSafe(trust); CFReleaseSafe(policies); CFReleaseSafe(certs); @@ -1290,7 +1284,6 @@ static void test_aia(void) { CFDictionaryRef info; SecTrustRef trust; SecTrustResultType trustResult; - CFStringRef companyName; CFBooleanRef ev; /* Initialize common variables */ @@ -1319,7 +1312,7 @@ static void test_aia(void) { info = SecTrustCopyInfo(trust); ev = (CFBooleanRef)CFDictionaryGetValue(info, kSecTrustInfoExtendedValidationKey); - ok(ev, "extended validation succeeded due to caissuers fetch"); + ok(!ev, "extended validation succeeded due to caissuers fetch"); //display_anchor_digest(trust); CFReleaseSafe(info); CFReleaseSafe(trust); @@ -1337,11 +1330,7 @@ static void test_aia(void) { info = SecTrustCopyInfo(trust); ev = (CFBooleanRef)CFDictionaryGetValue(info, kSecTrustInfoExtendedValidationKey); - ok(ev && CFEqual(kCFBooleanTrue, ev), "extended validation succeeded"); - companyName = (CFStringRef)CFDictionaryGetValue(info, - kSecTrustInfoCompanyNameKey); - ok(companyName && CFEqual(CFSTR("OVH"), companyName), - "kSecTrustInfoCompanyNameKey is correct"); + ok(!ev, "extended validation succeeded"); //display_anchor_digest(trust); CFReleaseSafe(info); CFReleaseSafe(trust); @@ -1359,11 +1348,7 @@ static void test_aia(void) { info = SecTrustCopyInfo(trust); ev = (CFBooleanRef)CFDictionaryGetValue(info, kSecTrustInfoExtendedValidationKey); - ok(ev && CFEqual(kCFBooleanTrue, ev), "extended validation succeeded"); - companyName = (CFStringRef)CFDictionaryGetValue(info, - kSecTrustInfoCompanyNameKey); - ok(companyName && CFEqual(CFSTR("OVH"), companyName), - "kSecTrustInfoCompanyNameKey is correct"); + ok(!ev, "extended validation succeeded"); //display_anchor_digest(trust); CFReleaseSafe(info); CFReleaseSafe(trust); @@ -1429,7 +1414,7 @@ int si_23_sectrust_ocsp(int argc, char *const *argv) unsigned host_cnt = 0; - plan_tests(68); + plan_tests(65); for (host_cnt = 0; host_cnt < sizeof(hosts)/sizeof(hosts[0]); host_cnt ++) { if(!ping_host(hosts[host_cnt])) { diff --git a/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m b/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m index 17828427..ee2af8d5 100644 --- a/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m +++ b/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m @@ -198,7 +198,7 @@ static void cleanup_globals(void) { static void test_no_constraints(void) { /* root with the default TrustRoot result succeeds */ setTS(cert0, NULL); - check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed); removeTS(cert0); /* intermediate with the default TrustRoot result fails */ @@ -207,7 +207,7 @@ static void test_no_constraints(void) { /* root with TrustRoot result succeeds */ NSDictionary *trustRoot = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)}; setTS(cert0, (__bridge CFDictionaryRef)trustRoot); - check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed); removeTS(cert0); /* intermediate with TrustRoot fails to set */ @@ -219,7 +219,7 @@ static void test_no_constraints(void) { /* intermediate with TrustAsRoot result succeeds */ setTS(cert1, (__bridge CFDictionaryRef)trustAsRoot); - check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed); removeTS(cert1); /* trusting the root but denying the intermediate fails */ @@ -238,7 +238,7 @@ static void test_no_constraints(void) { /* trusting one leaf doesn't make other leaf trusted */ setTS(cert2, (__bridge CFDictionaryRef)trustAsRoot); - check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed); check_trust(smimeChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure); removeTS(cert2); } @@ -249,7 +249,7 @@ static void test_policy_constraints(void) { NSDictionary *sslServerAllowed = @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy, (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot) }; setTS(cert1, (__bridge CFDictionaryRef)sslServerAllowed); - check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed); /* SSL client policy fails. */ SecPolicyRef sslClient = SecPolicyCreateSSL(false, NULL); @@ -272,7 +272,7 @@ static void test_policy_string_constraints(void) { ]; setTS(cert2, (__bridge CFArrayRef)hostnameAllowed); /* evaluating against trusted hostname passes */ - check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultUnspecified); + 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")); @@ -294,7 +294,7 @@ static void test_policy_string_constraints(void) { ]; setTS(cert3, (__bridge CFArrayRef)emailAllowed); /* evaluating against trusted email passes */ - check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultUnspecified); + 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")); @@ -330,7 +330,7 @@ static void test_application_constraints(void) { /* This application Trust Setting succeeds */ setTS(cert0, (__bridge CFDictionaryRef)thisAppTS); - check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed); removeTS(cert0); /* Some other application Trust Setting fails */ @@ -349,20 +349,20 @@ static void test_key_usage_constraints(void) { NSDictionary *anyKeyUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseAny), (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)}; setTS(cert0, (__bridge CFDictionaryRef)anyKeyUse); - check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultUnspecified); + 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, kSecTrustResultUnspecified); + 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, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed); removeTS(cert1); /* intermediate without signCert key usage fails */ @@ -382,7 +382,7 @@ static void test_key_usage_constraints(void) { /* signature smime policy passes for signature use TS*/ setTS(cert3, (__bridge CFDictionaryRef)signatureUse); - check_trust(smimeChain, smimeSignature, verify_date, kSecTrustResultUnspecified); + check_trust(smimeChain, smimeSignature, verify_date, kSecTrustResultProceed); /* any use policy fails for signature use TS */ check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultRecoverableTrustFailure); @@ -395,7 +395,7 @@ static void test_key_usage_constraints(void) { NSDictionary *keyEncryptUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseEnDecryptKey), (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)}; setTS(cert3, (__bridge CFDictionaryRef)keyEncryptUse); - check_trust(smimeChain, smimeKeyEncrypt, verify_date, kSecTrustResultUnspecified); + check_trust(smimeChain, smimeKeyEncrypt, verify_date, kSecTrustResultProceed); removeTS(cert3); /* multiple use smime policy against multiple uses */ @@ -403,7 +403,7 @@ static void test_key_usage_constraints(void) { kSecTrustSettingsKeyUseSignature), (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)}; setTS(cert3, (__bridge CFDictionaryRef)multipleUse) - check_trust(smimeChain, smimeMultiple, verify_date, kSecTrustResultUnspecified); + check_trust(smimeChain, smimeMultiple, verify_date, kSecTrustResultProceed); /* signature smime policy against multiple uses */ check_trust(smimeChain, smimeSignature, verify_date, kSecTrustResultRecoverableTrustFailure); @@ -431,7 +431,7 @@ static void test_allowed_errors(void) { (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)}; setTS(cert1, (__bridge CFDictionaryRef)allowExpired) setTS(cert2, (__bridge CFDictionaryRef)allowExpired); - check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultProceed); removeTS(cert2); removeTS(cert1); @@ -444,7 +444,7 @@ static void test_allowed_errors(void) { (__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, kSecTrustResultUnspecified); + check_trust(sslChain, wrongNameSSL, verify_date, kSecTrustResultProceed); removeTS(cert2); CFReleaseNull(wrongNameSSL); @@ -457,7 +457,7 @@ static void test_allowed_errors(void) { (__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, kSecTrustResultUnspecified); + check_trust(smimeChain, wrongNameSMIME, verify_date, kSecTrustResultProceed); removeTS(cert3); CFReleaseNull(wrongNameSMIME); @@ -467,7 +467,7 @@ static void test_allowed_errors(void) { (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)}; setTS(cert1, (__bridge CFDictionaryRef)allowExpiredConstrained) setTS(cert2, (__bridge CFDictionaryRef)allowExpiredConstrained); - check_trust(sslChain, sslPolicy, expired_date, kSecTrustResultUnspecified); + check_trust(sslChain, sslPolicy, expired_date, kSecTrustResultProceed); check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultRecoverableTrustFailure); removeTS(cert2); removeTS(cert1); @@ -485,7 +485,7 @@ static void test_multiple_constraints(void) { ]; setTS(cert0, (__bridge CFArrayRef)denyAllBut); check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultDeny); - check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed); removeTS(cert0); /* allow all but */ @@ -495,7 +495,7 @@ static void test_multiple_constraints(void) { @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) } ]; setTS(cert0, (__bridge CFArrayRef)allowAllBut); - check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed); check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultRecoverableTrustFailure); removeTS(cert0); @@ -507,7 +507,7 @@ static void test_multiple_constraints(void) { (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) } ]; setTS(cert0, (__bridge CFArrayRef)specifyPolicyResult); - check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultUnspecified); + check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed); check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultDeny); check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultRecoverableTrustFailure); removeTS(cert0); @@ -525,7 +525,7 @@ static void test_multiple_constraints(void) { 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, kSecTrustSettingsResultUnspecified); + check_trust(sslChain, wrongNameSSL, verify_date, kSecTrustResultProceed); check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultRecoverableTrustFailure); removeTS(cert2); CFReleaseNull(wrongNameSSL); diff --git a/OSX/sec/Security/Regressions/secitem/si-29-sectrust-sha1-deprecation.m b/OSX/sec/Security/Regressions/secitem/si-29-sectrust-sha1-deprecation.m index 58c29a71..3a7bffdf 100644 --- a/OSX/sec/Security/Regressions/secitem/si-29-sectrust-sha1-deprecation.m +++ b/OSX/sec/Security/Regressions/secitem/si-29-sectrust-sha1-deprecation.m @@ -124,7 +124,7 @@ static void tests(void) /* SHA1 cert now passes SSL server*/ setTrust(&trust, sha1_certs, serverPolicy); require_noerr_string(SecTrustEvaluate(trust, &trustResult), cleanup, "failed to evaluate trust"); - is(trustResult, kSecTrustResultUnspecified, "accept test: user-trusted SHA-1 SSL server"); + is(trustResult, kSecTrustResultProceed, "accept test: user-trusted SHA-1 SSL server"); /* Remove trust setting for root */ #if TARGET_OS_IPHONE diff --git a/OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.h b/OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.h new file mode 100644 index 00000000..9d569b59 --- /dev/null +++ b/OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.h @@ -0,0 +1,261 @@ +/* + * 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 _SECURITY_SI_32_SECTRUST_PINNING_REQUIRED_H_ +#define _SECURITY_SI_32_SECTRUST_PINNING_REQUIRED_H_ + +/* subject:/CN=query.ess.apple.com/OU=IDS SRE/O=Apple Inc./C=US */ +/* issuer :/CN=Apple Server Authentication CA/OU=Certification Authority/O=Apple Inc./C=US */ +uint8_t _ids_prod[1241]={ + 0x30,0x82,0x04,0xD5,0x30,0x82,0x03,0xBD,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x44, + 0xA0,0x2D,0x8B,0xE1,0x7C,0x9B,0xD4,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, + 0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x6D,0x31,0x27,0x30,0x25,0x06,0x03,0x55,0x04, + 0x03,0x0C,0x1E,0x41,0x70,0x70,0x6C,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20, + 0x41,0x75,0x74,0x68,0x65,0x6E,0x74,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,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,0x37,0x30,0x31,0x33,0x31,0x32, + 0x30,0x35,0x31,0x32,0x31,0x5A,0x17,0x0D,0x31,0x38,0x30,0x33,0x30,0x32,0x32,0x30, + 0x35,0x31,0x32,0x31,0x5A,0x30,0x52,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x03, + 0x0C,0x13,0x71,0x75,0x65,0x72,0x79,0x2E,0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C, + 0x65,0x2E,0x63,0x6F,0x6D,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0B,0x0C,0x07, + 0x49,0x44,0x53,0x20,0x53,0x52,0x45,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,0xCA,0x0E,0x49,0x84,0xAD,0x81, + 0xDA,0xC9,0x9B,0xB0,0xEC,0x7B,0x63,0xC9,0xEE,0x84,0xBA,0x31,0x5C,0xB5,0xA3,0x8E, + 0xFF,0x55,0xD7,0xCD,0x49,0x61,0x11,0xB2,0x0C,0x52,0x26,0xD3,0x46,0xDA,0x33,0xF5, + 0x1B,0x86,0xDB,0x24,0x4F,0x72,0x1D,0xA3,0xD5,0x57,0x3E,0x33,0xCF,0xE9,0x0A,0x00, + 0x8A,0xB3,0x1C,0x89,0x58,0x2D,0x03,0xAC,0xD7,0x69,0xB8,0xF2,0xEC,0x9A,0x1A,0x4E, + 0xA7,0x0F,0xAA,0xE8,0xA0,0x19,0x2E,0xE0,0x18,0x2E,0xC2,0x58,0xD5,0x39,0x30,0xB1, + 0xFD,0x97,0x8C,0x75,0x91,0x20,0xBA,0x40,0xCB,0x22,0x21,0x95,0xA6,0xA3,0x37,0x26, + 0xC2,0x1D,0x97,0x53,0xE7,0x69,0x91,0x79,0xC6,0xEB,0x36,0x74,0xD3,0xE7,0x15,0x66, + 0xF2,0xCD,0x6A,0xB7,0x83,0x65,0xCC,0x57,0xCE,0x99,0x71,0x98,0x2E,0xBA,0x57,0x9B, + 0x5F,0x36,0xBB,0x2C,0x88,0xAC,0x60,0x66,0xFE,0xEC,0xF3,0x15,0xD4,0x44,0x92,0x03, + 0x52,0xA2,0x3F,0x5F,0x14,0xE3,0xBF,0x48,0xA1,0x27,0xB3,0x30,0xC2,0x80,0x18,0xFC, + 0x29,0xCD,0x2E,0xD9,0x36,0x7E,0xBA,0x87,0x1F,0x65,0xB4,0xD0,0x4E,0x99,0x60,0x78, + 0x90,0xEB,0xC0,0xB2,0xFD,0x2A,0x10,0xBA,0xA7,0x97,0x3A,0x6A,0x1C,0xC8,0x47,0xD2, + 0x37,0x7E,0x43,0x23,0xCA,0x0A,0xB9,0x78,0xF5,0x7D,0x86,0x3F,0x07,0xD8,0xA5,0x73, + 0x5C,0xAE,0x73,0x71,0x30,0xD0,0xCC,0x50,0xCF,0xD6,0x81,0x5F,0xFB,0x72,0x76,0x59, + 0x13,0x4F,0x03,0xA0,0x9F,0x16,0x8E,0x44,0xEB,0xBA,0x28,0x26,0x6A,0x96,0x50,0x0F, + 0xF6,0x5F,0x44,0xE6,0x35,0xF9,0x4F,0x80,0x5C,0xD1,0x02,0x03,0x01,0x00,0x01,0xA3, + 0x82,0x01,0x92,0x30,0x82,0x01,0x8E,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, + 0x04,0x14,0x76,0xA5,0x55,0x93,0x34,0x5E,0xAF,0x27,0x7F,0xE6,0xD7,0x51,0xC0,0x87, + 0x2A,0x76,0xCD,0xC8,0xFA,0x57,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,0x2C,0xC5,0x6D,0x52,0xDD,0x31,0xEF,0x8C,0xEC,0x08,0x81,0xED,0xDF,0xDC,0xCA, + 0x43,0x00,0x45,0x01,0xD0,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,0x73,0x65,0x72,0x76,0x65,0x72,0x61,0x75,0x74,0x68,0x63,0x61,0x31,0x2E, + 0x63,0x72,0x6C,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,0x81,0xC7,0x06,0x03,0x55,0x1D,0x11, + 0x04,0x81,0xBF,0x30,0x81,0xBC,0x82,0x13,0x71,0x75,0x65,0x72,0x79,0x2E,0x65,0x73, + 0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x82,0x11,0x73,0x6D,0x73, + 0x2E,0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x82,0x13, + 0x67,0x72,0x6F,0x75,0x70,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,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,0x15,0x70,0x72,0x6F,0x66,0x69,0x6C,0x65,0x2E,0x65, + 0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x82,0x1A,0x72,0x65, + 0x67,0x69,0x73,0x74,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2E,0x65,0x73,0x73,0x2E,0x61, + 0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x82,0x18,0x61,0x67,0x67,0x72,0x65,0x67, + 0x61,0x74,0x6F,0x72,0x2E,0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63, + 0x6F,0x6D,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,0x1D,0x08,0x72,0xD6,0x97,0xBF,0xE4, + 0x6B,0xDA,0x9D,0xC1,0x7D,0x79,0x87,0x5C,0x4D,0x6D,0xDE,0xB0,0xF2,0x99,0x4F,0x0E, + 0xB9,0x79,0x44,0x45,0x2A,0xCF,0xE9,0x7D,0xC2,0x9E,0x1C,0xB9,0x83,0x21,0x99,0xD7, + 0x7C,0x89,0x70,0x3D,0xE6,0x45,0x1A,0xAC,0x6C,0x0A,0x1C,0x06,0x8A,0xCD,0xD0,0x29, + 0xC8,0x9B,0xE5,0xDE,0x02,0x3E,0xBD,0x0B,0x87,0xEE,0xAF,0x5E,0x69,0x3D,0x1F,0xFA, + 0xE3,0xAF,0x9E,0x4B,0xC3,0x5D,0xBB,0xC1,0x2D,0x27,0x09,0x34,0x5A,0xC3,0xC4,0x25, + 0xC6,0x10,0x1A,0x6B,0xBC,0x84,0xA9,0x5B,0xE7,0x7D,0xB4,0x94,0xF7,0xDB,0xA9,0x93, + 0x67,0x9F,0xB2,0x41,0x7F,0xC5,0x9B,0x23,0xFD,0xEB,0x00,0x04,0x64,0x24,0xE3,0xE1, + 0x00,0xF1,0x57,0xF6,0x53,0x4B,0xCE,0x99,0x05,0xA1,0x5E,0x62,0xF1,0x47,0xBA,0xCA, + 0xA1,0xA3,0xFC,0x20,0xE3,0xF2,0x06,0xD9,0x30,0xFB,0x57,0xFE,0x43,0x72,0x23,0xDB, + 0x5B,0x9D,0x20,0xA5,0x86,0x49,0x2C,0x26,0xFC,0x89,0xED,0x8B,0xE5,0x19,0x59,0x16, + 0x35,0x20,0x36,0x37,0x1A,0xD7,0xC6,0xAB,0xA3,0xFC,0xF0,0xA1,0xB4,0xAF,0x18,0x57, + 0xE9,0xFE,0x0A,0xD9,0xC5,0x91,0x63,0xF3,0x1F,0x36,0xB1,0x11,0xC0,0xD9,0xE0,0x6F, + 0x8E,0x6E,0xAE,0x39,0x72,0x9A,0x88,0x19,0x8A,0xBB,0xEE,0xA2,0x1C,0x7C,0xB7,0xA6, + 0x89,0x77,0xAB,0x87,0x43,0x9D,0x74,0x99,0x86,0xC8,0x7E,0x2A,0xB9,0xCD,0x6A,0xEF, + 0xDC,0x6D,0x1A,0x1F,0x6F,0xF3,0xD3,0x8F,0x0A,0x04,0xF8,0xDA,0x8C,0x43,0x7A,0xE2, + 0xE4,0x43,0x3F,0x85,0xCD,0x5C,0x00,0x3A,0x39, +}; + +/* subject:/CN=Apple Server Authentication CA/OU=Certification Authority/O=Apple Inc./C=US */ +/* issuer :/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA */ +uint8_t _AppleServerAuth[1020]={ + 0x30,0x82,0x03,0xF8,0x30,0x82,0x02,0xE0,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x23, + 0x69,0x74,0x04,0xAD,0xCB,0x83,0x14,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, + 0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, + 0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A, + 0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x26,0x30,0x24,0x06,0x03, + 0x55,0x04,0x0B,0x13,0x1D,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x65,0x72,0x74,0x69, + 0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69, + 0x74,0x79,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x03,0x13,0x0D,0x41,0x70,0x70, + 0x6C,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x34, + 0x30,0x33,0x30,0x38,0x30,0x31,0x35,0x33,0x30,0x34,0x5A,0x17,0x0D,0x32,0x39,0x30, + 0x33,0x30,0x38,0x30,0x31,0x35,0x33,0x30,0x34,0x5A,0x30,0x6D,0x31,0x27,0x30,0x25, + 0x06,0x03,0x55,0x04,0x03,0x0C,0x1E,0x41,0x70,0x70,0x6C,0x65,0x20,0x53,0x65,0x72, + 0x76,0x65,0x72,0x20,0x41,0x75,0x74,0x68,0x65,0x6E,0x74,0x69,0x63,0x61,0x74,0x69, + 0x6F,0x6E,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,0xB9,0x26,0x16,0xB0,0xCB,0x87, + 0xAB,0x71,0x15,0x92,0x8E,0xDF,0xAA,0x3E,0xE1,0x80,0xD7,0x53,0xBA,0xA4,0x60,0xCC, + 0x7C,0x85,0x72,0xF7,0x30,0x7C,0x09,0x4F,0x57,0x0D,0x4A,0xFF,0xE1,0x5E,0xC9,0x4B, + 0x50,0x13,0x02,0x64,0xB1,0xBD,0x39,0x35,0xD1,0xD7,0x04,0x51,0xC1,0x18,0xFA,0x22, + 0xFA,0xAE,0xDF,0x98,0x18,0xD6,0xBF,0x4E,0x4D,0x43,0x10,0xFA,0x25,0x88,0x9F,0xD3, + 0x40,0x85,0x76,0xE5,0x22,0x81,0xB6,0x54,0x45,0x73,0x9A,0x8B,0xE3,0x9C,0x48,0x1A, + 0x86,0x7A,0xC3,0x51,0xE2,0xDA,0x95,0xF8,0xA4,0x7D,0xDB,0x30,0xDE,0x6C,0x0E,0xC4, + 0xC5,0xF5,0x6C,0x98,0xE7,0xA6,0xFA,0x57,0x20,0x1D,0x19,0x73,0x7A,0x0E,0xCD,0x63, + 0x0F,0xB7,0x27,0x88,0x2E,0xE1,0x9A,0x68,0x82,0xB8,0x40,0x6C,0x63,0x16,0x24,0x66, + 0x2B,0xE7,0xB2,0xE2,0x54,0x7D,0xE7,0x88,0x39,0xA2,0x1B,0x81,0x3E,0x02,0xD3,0x39, + 0xD8,0x97,0x77,0x4A,0x32,0x0C,0xD6,0x0A,0x0A,0xB3,0x04,0x9B,0xF1,0x72,0x6F,0x63, + 0xA8,0x15,0x1E,0x6C,0x37,0xE8,0x0F,0xDB,0x53,0x90,0xD6,0x29,0x5C,0xBC,0x6A,0x57, + 0x9B,0x46,0x78,0x0A,0x3E,0x24,0xEA,0x9A,0x3F,0xA1,0xD8,0x3F,0xF5,0xDB,0x6E,0xA8, + 0x6C,0x82,0xB5,0xDD,0x99,0x38,0xEC,0x92,0x56,0x94,0xA6,0xC5,0x73,0x26,0xD1,0xAE, + 0x08,0xB2,0xC6,0x52,0xE7,0x8E,0x76,0x4B,0x89,0xB8,0x54,0x0F,0x6E,0xE0,0xD9,0x42, + 0xDB,0x2A,0x65,0x87,0x46,0x14,0xBB,0x96,0xB8,0x57,0xBB,0x51,0xE6,0x84,0x13,0xF7, + 0x0D,0xA1,0xB6,0x89,0xAC,0x7C,0xD1,0x21,0x74,0xAB,0x02,0x03,0x01,0x00,0x01,0xA3, + 0x81,0xA6,0x30,0x81,0xA3,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, + 0x2C,0xC5,0x6D,0x52,0xDD,0x31,0xEF,0x8C,0xEC,0x08,0x81,0xED,0xDF,0xDC,0xCA,0x43, + 0x00,0x45,0x01,0xD0,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,0x2B,0xD0,0x69,0x47,0x94,0x76,0x09,0xFE,0xF4,0x6B,0x8D,0x2E,0x40,0xA6, + 0xF7,0x47,0x4D,0x7F,0x08,0x5E,0x30,0x2E,0x06,0x03,0x55,0x1D,0x1F,0x04,0x27,0x30, + 0x25,0x30,0x23,0xA0,0x21,0xA0,0x1F,0x86,0x1D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, + 0x63,0x72,0x6C,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,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,0x02,0x0C,0x04,0x02,0x05,0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, + 0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x23,0xF1,0x06,0x7E, + 0x50,0x41,0x81,0xA2,0x5E,0xD3,0x70,0xA4,0x49,0x91,0xAF,0xD8,0xCC,0x67,0x8C,0xA1, + 0x25,0x7D,0xC4,0x9A,0x93,0x39,0x2F,0xD8,0x69,0xFB,0x1B,0x41,0x5B,0x44,0xD7,0xD9, + 0x6B,0xCB,0x3B,0x25,0x09,0x1A,0xF2,0xF4,0xE3,0xC7,0x9C,0xE8,0xB0,0x5B,0xF0,0xDF, + 0xDD,0x22,0x25,0x11,0x15,0x93,0xB9,0x49,0x5E,0xDA,0x0C,0x66,0x7A,0x5E,0xD7,0x6F, + 0xF0,0x63,0xD4,0x65,0x8C,0xC4,0x7A,0x54,0x7D,0x56,0x4F,0x65,0x9A,0xFD,0xDA,0xC4, + 0xB2,0xC8,0xB0,0xB8,0xA1,0xCB,0x7D,0xE0,0x47,0xA8,0x40,0x15,0xB8,0x16,0x19,0xED, + 0x5B,0x61,0x8E,0xDF,0xAA,0xD0,0xCD,0xD2,0x3A,0xC0,0x7E,0x3A,0x9F,0x22,0x4E,0xDF, + 0xDF,0xF4,0x4E,0x1A,0xCD,0x93,0xFF,0xD0,0xF0,0x45,0x55,0x64,0x33,0x3E,0xD4,0xE5, + 0xDA,0x68,0xA0,0x13,0x8A,0x76,0x30,0x27,0xD4,0xBF,0xF8,0x1E,0x76,0xF6,0xF9,0xC3, + 0x00,0xEF,0xB1,0x83,0xEA,0x53,0x6D,0x5C,0x35,0xC7,0x0D,0x07,0x01,0xBA,0xF8,0x61, + 0xB9,0xFE,0xC5,0x9A,0x6B,0x43,0x61,0x81,0x03,0xEB,0xBA,0x5F,0x70,0x9D,0xE8,0x6F, + 0x94,0x24,0x4B,0xDC,0xCE,0x92,0xA8,0x2E,0xA2,0x35,0x3C,0xE3,0x49,0xE0,0x16,0x77, + 0xA2,0xDC,0x6B,0xB9,0x8D,0x18,0x42,0xB9,0x36,0x96,0x43,0x32,0xC6,0xCB,0x76,0x99, + 0x35,0x36,0xD8,0x56,0xC6,0x98,0x5D,0xC3,0x6F,0xA5,0x7E,0x95,0xC2,0xD5,0x7A,0x0A, + 0x02,0x20,0x66,0x78,0x92,0xF2,0x67,0xA4,0x23,0x0D,0xE8,0x09,0xBD,0xCC,0x21,0x31, + 0x10,0xA0,0xBD,0xBE,0xB5,0xDD,0x4C,0xDD,0x46,0x03,0x99,0x99, +}; + +/* subject:/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA */ +/* issuer :/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA */ +uint8_t _AppleRootCA[1215]={ + 0x30,0x82,0x04,0xBB,0x30,0x82,0x03,0xA3,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x02, + 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, + 0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13, + 0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49, + 0x6E,0x63,0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,0x70, + 0x70,0x6C,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F, + 0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x16,0x30,0x14,0x06, + 0x03,0x55,0x04,0x03,0x13,0x0D,0x41,0x70,0x70,0x6C,0x65,0x20,0x52,0x6F,0x6F,0x74, + 0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x34,0x32,0x35,0x32,0x31,0x34, + 0x30,0x33,0x36,0x5A,0x17,0x0D,0x33,0x35,0x30,0x32,0x30,0x39,0x32,0x31,0x34,0x30, + 0x33,0x36,0x5A,0x30,0x62,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, + 0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70, + 0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B, + 0x13,0x1D,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, + 0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31, + 0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x03,0x13,0x0D,0x41,0x70,0x70,0x6C,0x65,0x20, + 0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A, + 0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30, + 0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xE4,0x91,0xA9,0x09,0x1F,0x91,0xDB,0x1E, + 0x47,0x50,0xEB,0x05,0xED,0x5E,0x79,0x84,0x2D,0xEB,0x36,0xA2,0x57,0x4C,0x55,0xEC, + 0x8B,0x19,0x89,0xDE,0xF9,0x4B,0x6C,0xF5,0x07,0xAB,0x22,0x30,0x02,0xE8,0x18,0x3E, + 0xF8,0x50,0x09,0xD3,0x7F,0x41,0xA8,0x98,0xF9,0xD1,0xCA,0x66,0x9C,0x24,0x6B,0x11, + 0xD0,0xA3,0xBB,0xE4,0x1B,0x2A,0xC3,0x1F,0x95,0x9E,0x7A,0x0C,0xA4,0x47,0x8B,0x5B, + 0xD4,0x16,0x37,0x33,0xCB,0xC4,0x0F,0x4D,0xCE,0x14,0x69,0xD1,0xC9,0x19,0x72,0xF5, + 0x5D,0x0E,0xD5,0x7F,0x5F,0x9B,0xF2,0x25,0x03,0xBA,0x55,0x8F,0x4D,0x5D,0x0D,0xF1, + 0x64,0x35,0x23,0x15,0x4B,0x15,0x59,0x1D,0xB3,0x94,0xF7,0xF6,0x9C,0x9E,0xCF,0x50, + 0xBA,0xC1,0x58,0x50,0x67,0x8F,0x08,0xB4,0x20,0xF7,0xCB,0xAC,0x2C,0x20,0x6F,0x70, + 0xB6,0x3F,0x01,0x30,0x8C,0xB7,0x43,0xCF,0x0F,0x9D,0x3D,0xF3,0x2B,0x49,0x28,0x1A, + 0xC8,0xFE,0xCE,0xB5,0xB9,0x0E,0xD9,0x5E,0x1C,0xD6,0xCB,0x3D,0xB5,0x3A,0xAD,0xF4, + 0x0F,0x0E,0x00,0x92,0x0B,0xB1,0x21,0x16,0x2E,0x74,0xD5,0x3C,0x0D,0xDB,0x62,0x16, + 0xAB,0xA3,0x71,0x92,0x47,0x53,0x55,0xC1,0xAF,0x2F,0x41,0xB3,0xF8,0xFB,0xE3,0x70, + 0xCD,0xE6,0xA3,0x4C,0x45,0x7E,0x1F,0x4C,0x6B,0x50,0x96,0x41,0x89,0xC4,0x74,0x62, + 0x0B,0x10,0x83,0x41,0x87,0x33,0x8A,0x81,0xB1,0x30,0x58,0xEC,0x5A,0x04,0x32,0x8C, + 0x68,0xB3,0x8F,0x1D,0xDE,0x65,0x73,0xFF,0x67,0x5E,0x65,0xBC,0x49,0xD8,0x76,0x9F, + 0x33,0x14,0x65,0xA1,0x77,0x94,0xC9,0x2D,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x01, + 0x7A,0x30,0x82,0x01,0x76,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,0x2B,0xD0,0x69,0x47,0x94,0x76,0x09,0xFE,0xF4,0x6B,0x8D,0x2E,0x40,0xA6,0xF7, + 0x47,0x4D,0x7F,0x08,0x5E,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16, + 0x80,0x14,0x2B,0xD0,0x69,0x47,0x94,0x76,0x09,0xFE,0xF4,0x6B,0x8D,0x2E,0x40,0xA6, + 0xF7,0x47,0x4D,0x7F,0x08,0x5E,0x30,0x82,0x01,0x11,0x06,0x03,0x55,0x1D,0x20,0x04, + 0x82,0x01,0x08,0x30,0x82,0x01,0x04,0x30,0x82,0x01,0x00,0x06,0x09,0x2A,0x86,0x48, + 0x86,0xF7,0x63,0x64,0x05,0x01,0x30,0x81,0xF2,0x30,0x2A,0x06,0x08,0x2B,0x06,0x01, + 0x05,0x05,0x07,0x02,0x01,0x16,0x1E,0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x77, + 0x77,0x77,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70, + 0x6C,0x65,0x63,0x61,0x2F,0x30,0x81,0xC3,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07, + 0x02,0x02,0x30,0x81,0xB6,0x1A,0x81,0xB3,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,0x74,0x68,0x65,0x20,0x74,0x68,0x65,0x6E, + 0x20,0x61,0x70,0x70,0x6C,0x69,0x63,0x61,0x62,0x6C,0x65,0x20,0x73,0x74,0x61,0x6E, + 0x64,0x61,0x72,0x64,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, + 0x2C,0x20,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x70,0x6F, + 0x6C,0x69,0x63,0x79,0x20,0x61,0x6E,0x64,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,0x0D,0x06,0x09,0x2A, + 0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x5C, + 0x36,0x99,0x4C,0x2D,0x78,0xB7,0xED,0x8C,0x9B,0xDC,0xF3,0x77,0x9B,0xF2,0x76,0xD2, + 0x77,0x30,0x4F,0xC1,0x1F,0x85,0x83,0x85,0x1B,0x99,0x3D,0x47,0x37,0xF2,0xA9,0x9B, + 0x40,0x8E,0x2C,0xD4,0xB1,0x90,0x12,0xD8,0xBE,0xF4,0x73,0x9B,0xEE,0xD2,0x64,0x0F, + 0xCB,0x79,0x4F,0x34,0xD8,0xA2,0x3E,0xF9,0x78,0xFF,0x6B,0xC8,0x07,0xEC,0x7D,0x39, + 0x83,0x8B,0x53,0x20,0xD3,0x38,0xC4,0xB1,0xBF,0x9A,0x4F,0x0A,0x6B,0xFF,0x2B,0xFC, + 0x59,0xA7,0x05,0x09,0x7C,0x17,0x40,0x56,0x11,0x1E,0x74,0xD3,0xB7,0x8B,0x23,0x3B, + 0x47,0xA3,0xD5,0x6F,0x24,0xE2,0xEB,0xD1,0xB7,0x70,0xDF,0x0F,0x45,0xE1,0x27,0xCA, + 0xF1,0x6D,0x78,0xED,0xE7,0xB5,0x17,0x17,0xA8,0xDC,0x7E,0x22,0x35,0xCA,0x25,0xD5, + 0xD9,0x0F,0xD6,0x6B,0xD4,0xA2,0x24,0x23,0x11,0xF7,0xA1,0xAC,0x8F,0x73,0x81,0x60, + 0xC6,0x1B,0x5B,0x09,0x2F,0x92,0xB2,0xF8,0x44,0x48,0xF0,0x60,0x38,0x9E,0x15,0xF5, + 0x3D,0x26,0x67,0x20,0x8A,0x33,0x6A,0xF7,0x0D,0x82,0xCF,0xDE,0xEB,0xA3,0x2F,0xF9, + 0x53,0x6A,0x5B,0x64,0xC0,0x63,0x33,0x77,0xF7,0x3A,0x07,0x2C,0x56,0xEB,0xDA,0x0F, + 0x21,0x0E,0xDA,0xBA,0x73,0x19,0x4F,0xB5,0xD9,0x36,0x7F,0xC1,0x87,0x55,0xD9,0xA7, + 0x99,0xB9,0x32,0x42,0xFB,0xD8,0xD5,0x71,0x9E,0x7E,0xA1,0x52,0xB7,0x1B,0xBD,0x93, + 0x42,0x24,0x12,0x2A,0xC7,0x0F,0x1D,0xB6,0x4D,0x9C,0x5E,0x63,0xC8,0x4B,0x80,0x17, + 0x50,0xAA,0x8A,0xD5,0xDA,0xE4,0xFC,0xD0,0x09,0x07,0x37,0xB0,0x75,0x75,0x21, +}; + + +#endif /* _SECURITY_SI_32_SECTRUST_PINNING_REQUIRED_H_ */ diff --git a/OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.m b/OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.m new file mode 100644 index 00000000..e63c9d73 --- /dev/null +++ b/OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.m @@ -0,0 +1,120 @@ +/* + * 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@ + */ + +#include +#import + +#include +#include +#include +#include +#include +#include + +#include "shared_regressions.h" + +#include "si-32-sectrust-pinning-required.h" + + +static NSArray *certs = nil; +static NSArray *root = nil; +static NSDate *verifyDate = nil; + +static void setup_globals(void) { + SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _ids_prod, sizeof(_ids_prod)); + SecCertificateRef intermediate = SecCertificateCreateWithBytes(NULL, _AppleServerAuth, sizeof(_AppleServerAuth)); + SecCertificateRef rootcert = SecCertificateCreateWithBytes(NULL, _AppleRootCA, sizeof(_AppleRootCA)); + + certs = @[(__bridge id)leaf,(__bridge id)intermediate]; + root = @[(__bridge id)rootcert]; + verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:508000000.0]; //February 5, 2017 at 7:06:40 AM PST + + CFReleaseNull(leaf); + CFReleaseNull(intermediate); + CFReleaseNull(rootcert); +} + +static SecTrustResultType test_with_policy_exception(SecPolicyRef CF_CONSUMED policy, bool set_exception) +{ + SecTrustRef trust = NULL; + SecTrustResultType trustResult = kSecTrustResultInvalid; + + require_noerr_quiet(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), cleanup); + require_noerr_quiet(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)root), cleanup); + require_noerr_quiet(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), cleanup); + if (set_exception) { + SecTrustSetPinningException(trust); + } + require_noerr_quiet(SecTrustEvaluate(trust, &trustResult), cleanup); + +cleanup: + CFReleaseNull(policy); + CFReleaseNull(trust); + return trustResult; +} + +static SecTrustResultType test_with_policy(SecPolicyRef CF_CONSUMED policy) { + return test_with_policy_exception(policy, false); +} + + +/* Technically, this feature works by reading the info plist of the caller. We'll fake it here by + * setting the policy option for requiring pinning. */ +static void tests(void) +{ + SecPolicyRef policy = NULL; + + policy = SecPolicyCreateSSL(true, CFSTR("openmarket.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); + SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue); + is(test_with_policy(policy), kSecTrustResultUnspecified, "Policy pinned connection failed when pinning required"); + + policy = SecPolicyCreateSSL(true, CFSTR("profile.ess.apple.com")); + SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue); + 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 *)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")); + SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue); + is(test_with_policy_exception(policy, true), kSecTrustResultUnspecified, "Unpinned connection failed when pinning exception set"); + + /* can I write an effective test for charles?? */ +} + +int si_32_sectrust_pinning_required(int argc, char *const *argv) +{ + plan_tests(5); + setup_globals(); + tests(); + return 0; +} diff --git a/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c b/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c index 28392c45..fa2dd4e7 100644 --- a/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c +++ b/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c @@ -24,10 +24,10 @@ #include -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR -#define USE_KEYSTORE 1 -#else /* No AppleKeyStore.kext on this OS. */ +#if TARGET_IPHONE_SIMULATOR #define USE_KEYSTORE 0 +#else /* No AppleKeyStore.kext on this OS. */ +#define USE_KEYSTORE 1 #endif @@ -39,8 +39,8 @@ #include #if USE_KEYSTORE -#include -#include +#include +#include #endif #include @@ -281,10 +281,47 @@ static void test_remove_lockdown_identity_items(void) { static void test_no_find_lockdown_identity_item(void) { CFMutableDictionaryRef query = test_create_lockdown_identity_query(); is_status(SecItemCopyMatching(query, NULL), errSecItemNotFound, - "test_no_find_lockdown_identity_item"); + "test_no_find_lockdown_identity_item"); CFReleaseSafe(query); } +static CFMutableDictionaryRef test_create_sysbound_query(void) { + CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(query, kSecClass, kSecClassGenericPassword); + CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("sysbound")); + CFDictionaryAddValue(query, kSecAttrAccessGroup, CFSTR("apple")); + return query; +} + +static void test_add_sysbound_item(void) { + CFMutableDictionaryRef query = test_create_sysbound_query(); + int32_t val = kSecSecAttrSysBoundPreserveDuringRestore; + CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &val); + CFDictionaryAddValue(query, kSecAttrSysBound, num); + CFReleaseNull(num); + + const char *v_data = "sysbound identity data"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + CFDictionaryAddValue(query, kSecValueData, pwdata); + ok_status(SecItemAdd(query, NULL), "test_add_sysbound_item"); + CFReleaseSafe(pwdata); + CFReleaseSafe(query); +} + +static void test_remove_sysbound_item(void) { + CFMutableDictionaryRef query = test_create_sysbound_query(); + ok_status(SecItemDelete(query), "test_remove_sysbound_item"); + CFReleaseSafe(query); +} + +static void test_find_sysbound_item(OSStatus expectedCode) { + CFMutableDictionaryRef query = test_create_sysbound_query(); + is_status(SecItemCopyMatching(query, NULL), expectedCode, + "test_find_sysbound_item"); + CFReleaseSafe(query); +} + + static void test_add_managedconfiguration_item(void) { CFMutableDictionaryRef query = test_create_managedconfiguration_query(); const char *v_data = "public managedconfiguration password history data"; @@ -303,76 +340,20 @@ static void test_find_managedconfiguration_item(void) { } #if USE_KEYSTORE -static io_connect_t connect_to_keystore(void) -{ - io_registry_entry_t apple_key_bag_service; - kern_return_t result; - io_connect_t keystore = MACH_PORT_NULL; - - apple_key_bag_service = IOServiceGetMatchingService(kIOMasterPortDefault, - IOServiceMatching(kAppleKeyStoreServiceName)); - - if (apple_key_bag_service == IO_OBJECT_NULL) { - fprintf(stderr, "Failed to get service.\n"); - return keystore; - } - - result = IOServiceOpen(apple_key_bag_service, mach_task_self(), 0, &keystore); - if (KERN_SUCCESS != result) - fprintf(stderr, "Failed to open keystore\n"); - - if (keystore != MACH_PORT_NULL) { - IOReturn kernResult = IOConnectCallMethod(keystore, - kAppleKeyStoreUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, - NULL, NULL); - if (kernResult) { - fprintf(stderr, "Failed to open AppleKeyStore: %x\n", kernResult); - } - } - return keystore; -} #define DATA_ARG(x) (x) ? CFDataGetBytePtr((x)) : NULL, (x) ? (int)CFDataGetLength((x)) : 0 - static CFDataRef create_keybag(keybag_handle_t bag_type, CFDataRef password) { - uint64_t inputs[] = { bag_type }; - uint64_t outputs[] = {0}; - uint32_t num_inputs = array_size(inputs); - uint32_t num_outputs = array_size(outputs); - IOReturn kernResult; - - io_connect_t keystore; - - unsigned char keybagdata[4096]; //Is that big enough? - size_t keybagsize=sizeof(keybagdata); - - keystore=connect_to_keystore(); - - kernResult = IOConnectCallMethod(keystore, - kAppleKeyStoreKeyBagCreate, - inputs, num_inputs, DATA_ARG(password), - outputs, &num_outputs, NULL, 0); + CFDataRef result = NULL; + void *bag = NULL; + int bagLen = 0; - if (kernResult) { - fprintf(stderr, "kAppleKeyStoreKeyBagCreate: 0x%x\n", kernResult); - return NULL; - } - - /* Copy out keybag */ - inputs[0]=outputs[0]; - num_inputs=1; - - kernResult = IOConnectCallMethod(keystore, - kAppleKeyStoreKeyBagCopy, - inputs, num_inputs, NULL, 0, - NULL, 0, keybagdata, &keybagsize); - - if (kernResult) { - fprintf(stderr, "kAppleKeyStoreKeyBagCopy: 0x%x\n", kernResult); - return NULL; - } + keybag_handle_t handle = bad_keybag_handle; + require_noerr(aks_create_bag(DATA_ARG(password), bag_type, &handle), out); + require_noerr(aks_save_bag(handle, &bag, &bagLen), out); - return CFDataCreate(kCFAllocatorDefault, keybagdata, keybagsize); + result = CFDataCreate(kCFAllocatorDefault, bag, bagLen); +out: + return result; } #endif @@ -412,6 +393,7 @@ static void tests(void) CFDataRef backup = NULL, keybag = NULL, password = NULL; test_add_lockdown_identity_items(); + test_add_sysbound_item(); #if USE_KEYSTORE keybag = create_keybag(kAppleKeyStoreBackupBag, password); @@ -424,12 +406,14 @@ static void tests(void) test_add_managedconfiguration_item(); test_remove_lockdown_identity_items(); + test_remove_sysbound_item(); ok_status(_SecKeychainRestoreBackup(backup, keybag, password), "_SecKeychainRestoreBackup"); CFReleaseSafe(backup); test_no_find_lockdown_identity_item(); + test_find_sysbound_item(errSecItemNotFound); test_find_managedconfiguration_item(); ok_status(SecItemCopyMatching(query, NULL), diff --git a/OSX/sec/Security/Regressions/secitem/si-40-seckey.c b/OSX/sec/Security/Regressions/secitem/si-40-seckey.c index a00e17c1..9213b941 100644 --- a/OSX/sec/Security/Regressions/secitem/si-40-seckey.c +++ b/OSX/sec/Security/Regressions/secitem/si-40-seckey.c @@ -74,10 +74,11 @@ static void testdigestandsignalg(SecKeyRef privKey, SecKeyRef pubKey, const SecA ok_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, sig, sigLen), "digest and verify"); /* Invalidate the signature. */ - sig[0] ^= 0xff; + /* Tweak the least-significant bit to avoid putting the signature out of range. */ + sig[sigLen-1] ^= 1; is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, sig, sigLen), errSSLCrypto, "digest and verify bad sig"); - sig[0] ^= 0xff; + sig[sigLen-1] ^= 1; dataToDigest[0] ^= 0xff; is_status(SecKeyDigestAndVerify(pubKey, algId, dataToDigest, dataToDigestLen, sig, sigLen), errSSLCrypto, "digest and verify bad digest"); @@ -934,9 +935,45 @@ static void testsignverify(unsigned long keySizeInBits) CFReleaseNull(privKey); } + +#define kSPKITestCount 4 +static void testspki(CFStringRef keytype, size_t keySizeInBits) +{ + SecKeyRef pubKey = NULL, privKey = NULL, pubKey2 = NULL; + size_t keySizeInBytes = (keySizeInBits + 7) / 8; + CFNumberRef kzib; + int32_t keysz32 = (int32_t)keySizeInBits; + CFDataRef spki = NULL; + + kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32); + CFMutableDictionaryRef kgp = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionaryAddValue(kgp, kSecAttrKeyType, keytype); + CFDictionaryAddValue(kgp, kSecAttrKeySizeInBits, kzib); + + OSStatus status; + ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey), + "Generate %ld bit (%ld byte) keypair", keySizeInBits, keySizeInBytes); + CFRelease(kzib); + CFRelease(kgp); + + spki = SecKeyCopySubjectPublicKeyInfo(pubKey); + ok(spki, "failed to create SPKI"); + + pubKey2 = SecKeyCreateFromSubjectPublicKeyInfoData(NULL, spki); + ok(pubKey2, "failed to create key from SPKI"); + + eq_cf(pubKey, pubKey2, "public not same after going though SPKI"); + + CFReleaseNull(pubKey); + CFReleaseNull(pubKey2); + CFReleaseNull(privKey); + CFReleaseNull(spki); +} + + /* Test basic add delete update copy matching stuff. */ #define kTestCount ((3 * kKeyGenTestCount) + kKeyGen2TestCount + kTestSupportedCount + kCreateWithDataTestCount \ - + kCopyAttributesTestCount + kCopyPublicKeyTestCount + kSignAndVerifyTestCount) + + kCopyAttributesTestCount + kCopyPublicKeyTestCount + kSignAndVerifyTestCount + ((3 + 3) * kSPKITestCount)) static void tests(void) { /* Comment out lines below for testing generating all common key sizes, @@ -955,6 +992,14 @@ static void tests(void) testcopyattributes(768); testcopypublickey(768); testsignverify(768); + + testspki(kSecAttrKeyTypeRSA, 1024); + testspki(kSecAttrKeyTypeRSA, 2048); + testspki(kSecAttrKeyTypeRSA, 4096); + + testspki(kSecAttrKeyTypeEC, 256); + testspki(kSecAttrKeyTypeEC, 384); + testspki(kSecAttrKeyTypeEC, 521); } int si_40_seckey(int argc, char *const *argv) diff --git a/OSX/sec/Security/Regressions/secitem/si-60-cms.c b/OSX/sec/Security/Regressions/secitem/si-60-cms.c index d55209bd..0a3ba7d6 100644 --- a/OSX/sec/Security/Regressions/secitem/si-60-cms.c +++ b/OSX/sec/Security/Regressions/secitem/si-60-cms.c @@ -41,7 +41,7 @@ #include #include -#include "Security_regressions.h" +#include "shared_regressions.h" /* Bag Attributes @@ -1685,7 +1685,13 @@ static void tests(void) fk_cms, fk_cms_len, kCFAllocatorNull); policy = SecPolicyCreateiPhoneApplicationSigning(); is_status(SecCMSVerify(message, detached, policy, &trust, NULL), errSecAuthFailed, "get trust"); +#if TARGET_OS_IPHONE + /* iOS only returns a trust ref on signature verification success */ is(trust, NULL, "no trustref: digest was wrong"); +#else + /* macOS ALWAYS returns a trust ref */ + isnt(trust, NULL, "always return trustref"); +#endif CFReleaseNull(trust); CFReleaseNull(message); CFReleaseNull(detached); @@ -1711,11 +1717,16 @@ static void tests(void) isnt(cert = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), NULL, "create certificate"); - isnt(privKey = SecKeyCreateRSAPrivateKey(NULL, _k1, sizeof(_k1), - kSecKeyEncodingPkcs1), NULL, "create private key"); + CFDataRef keyData = CFDataCreate(NULL, _k1, sizeof(_k1)); + CFMutableDictionaryRef keyAttrs = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(keyAttrs, kSecAttrKeyType, kSecAttrKeyTypeRSA); + CFDictionaryAddValue(keyAttrs, kSecAttrKeyClass, kSecAttrKeyClassPrivate); + isnt(privKey = SecKeyCreateWithData(keyData, keyAttrs, NULL), NULL, "Create private key"); isnt(identity = SecIdentityCreate(NULL, cert, privKey), NULL, "create identity"); CFReleaseNull(privKey); + CFReleaseNull(keyData); + CFReleaseNull(keyAttrs); const uint8_t test[] = "hoi joh"; CFDataRef test_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (unsigned char *)test, sizeof(test), kCFAllocatorNull); @@ -1738,11 +1749,23 @@ static void tests(void) CFReleaseNull(message); CFDataSetLength(message_data, 0); CFDataRef empty_data = CFDataCreate(kCFAllocatorDefault, NULL, 0); +#if TARGET_OS_IPHONE + /* iOS supports empty data */ ok_status(SecCMSCreateSignedData(identity, empty_data, NULL, simple_attr, message_data), "Create signed data with no content"); +#else + /* macOS does not */ + is_status(SecCMSCreateSignedData(identity, empty_data, NULL, simple_attr, message_data), errSecParam, "Create signed data with no content"); +#endif CFRelease(empty_data); //write_data("/var/tmp/empty_msg_with_attrs", message_data); CFDataSetLength(message_data, 0); - ok_status(SecCMSCreateSignedData(identity, NULL, NULL, simple_attr, message_data), "Create signed data with no content"); +#if TARGET_OS_IPHONE + /* iOS supports empty data */ + ok_status(SecCMSCreateSignedData(identity, NULL, NULL, simple_attr, message_data), "Create signed data with no content"); +#else + /* macOS does not */ + is_status(SecCMSCreateSignedData(identity, NULL, NULL, simple_attr, message_data), errSecParam, "Create signed data with no content"); +#endif uint8_t hash_data[CC_SHA1_DIGEST_LENGTH]; CCDigest(kCCDigestSHA1, test, sizeof(test), hash_data); CFDataRef hash_cfdata = CFDataCreateWithBytesNoCopy(NULL, hash_data, sizeof(hash_data), kCFAllocatorNull); @@ -1759,9 +1782,12 @@ static void tests(void) CFReleaseNull(simple_attr); CFDataSetLength(message_data, 0); +#if TARGET_OS_IPHONE CFMutableDictionaryRef params = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(params, kSecCMSSignHashAlgorithm, kSecCMSHashingAlgorithmMD5); is(SecCMSCreateSignedData(identity, NULL, params, NULL, message_data), errSecParam, "signing md5 message should fail"); + CFReleaseNull(params); +#endif message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, mobileconfig_with_long_issuer, sizeof(mobileconfig_with_long_issuer), @@ -1804,7 +1830,13 @@ static void tests(void) array_size(keys_identity), NULL, NULL); ok_status(SecItemAdd(identity_add, NULL), "add identity ref"); +#if TARGET_OS_IPHONE ok_status(SecCMSDecryptEnvelopedData(enc_data, message_data, NULL), "decrypt message"); +#else + /* @@@ There's something about the way that SecItemAdd adds the identity to the keychain on macOS + * that means that the private key is missing. */ + is_status(SecCMSDecryptEnvelopedData(enc_data, message_data, NULL), errSecDecode, "decrypt message"); +#endif ok_status(SecItemDelete(identity_add), "delete identity ref"); @@ -1820,8 +1852,11 @@ static void tests(void) int si_60_cms(int argc, char *const *argv) { +#if TARGET_OS_IPHONE plan_tests(42); - +#else + plan_tests(41); +#endif tests(); diff --git a/OSX/sec/Security/Regressions/secitem/si-61-pkcs12.c b/OSX/sec/Security/Regressions/secitem/si-61-pkcs12.c index 88ba86dc..2c2c16e6 100644 --- a/OSX/sec/Security/Regressions/secitem/si-61-pkcs12.c +++ b/OSX/sec/Security/Regressions/secitem/si-61-pkcs12.c @@ -31,622 +31,31 @@ #include #include #include +#include #include #include #include #include -#include "Security_regressions.h" - -unsigned char _user_one_p12[] = { - 0x30, 0x82, 0x06, 0xf1, 0x02, 0x01, 0x03, 0x30, 0x82, 0x06, 0xb7, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, - 0x06, 0xa8, 0x04, 0x82, 0x06, 0xa4, 0x30, 0x82, 0x06, 0xa0, 0x30, 0x82, - 0x03, 0x9f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, - 0x06, 0xa0, 0x82, 0x03, 0x90, 0x30, 0x82, 0x03, 0x8c, 0x02, 0x01, 0x00, - 0x30, 0x82, 0x03, 0x85, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0x07, 0xfd, 0xeb, - 0x68, 0x40, 0xd8, 0x58, 0x20, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x03, - 0x58, 0x03, 0x78, 0xbd, 0x4a, 0x74, 0xb4, 0x64, 0x25, 0xcc, 0xec, 0xb7, - 0xad, 0xee, 0xc5, 0x80, 0x9b, 0xdd, 0x24, 0xab, 0x1f, 0xd8, 0xa4, 0x2d, - 0x6f, 0xbc, 0x7d, 0xba, 0xf3, 0x7c, 0xc9, 0x93, 0x9c, 0xb4, 0xb7, 0x6e, - 0x2c, 0x77, 0x8d, 0xf0, 0x64, 0x59, 0x96, 0x34, 0xfb, 0xd7, 0x95, 0x5e, - 0x2a, 0xab, 0xf4, 0x64, 0x12, 0xdf, 0x68, 0x71, 0xcb, 0xa9, 0xc1, 0xe7, - 0x36, 0x46, 0x06, 0xd7, 0xde, 0xc2, 0x00, 0x13, 0xfe, 0x9d, 0xb9, 0x43, - 0xa2, 0x57, 0xd9, 0xb8, 0x6f, 0xa7, 0x09, 0xca, 0x2e, 0xc0, 0x72, 0x03, - 0x12, 0x32, 0x4c, 0x26, 0x90, 0x6b, 0x8f, 0xc1, 0xbf, 0x2e, 0xab, 0x77, - 0x9c, 0xaf, 0x0c, 0x96, 0x77, 0xc7, 0x93, 0x02, 0xdb, 0x6f, 0x5e, 0xfd, - 0x67, 0xff, 0x48, 0x7f, 0x12, 0x69, 0x47, 0x29, 0x6a, 0xc5, 0x6d, 0xb2, - 0x3f, 0xaa, 0x26, 0x42, 0x0d, 0x84, 0x7d, 0x3b, 0x19, 0xe5, 0x7c, 0xb2, - 0x47, 0xf0, 0x9d, 0xd1, 0x06, 0x73, 0xc8, 0xd0, 0x85, 0xc5, 0xc5, 0x9f, - 0xb4, 0xcc, 0x62, 0x17, 0xed, 0x42, 0x5b, 0x0a, 0x57, 0x2c, 0xc8, 0x6b, - 0x39, 0x29, 0x83, 0x4f, 0xa0, 0xfa, 0xd0, 0x1d, 0xb3, 0x8f, 0xf0, 0x2e, - 0x72, 0x66, 0x72, 0x7a, 0xc7, 0x9c, 0x67, 0x9e, 0x1c, 0xdf, 0x7c, 0xfc, - 0x87, 0x1a, 0xcc, 0xdf, 0x6b, 0x22, 0x17, 0x4b, 0x16, 0x5a, 0x97, 0x16, - 0x22, 0xea, 0xdb, 0x02, 0xab, 0x21, 0xcd, 0xb2, 0x4b, 0x85, 0x72, 0xbb, - 0xe0, 0x98, 0xdc, 0x1a, 0xf8, 0xde, 0xd3, 0x0a, 0x2f, 0xc1, 0x2d, 0x91, - 0x45, 0x7b, 0x33, 0xe6, 0x02, 0x0a, 0x12, 0xb2, 0x27, 0x4a, 0x44, 0x6f, - 0x1b, 0x6a, 0x2f, 0x15, 0xab, 0x06, 0xcb, 0x19, 0xd4, 0x16, 0x14, 0x06, - 0x18, 0x3e, 0x6a, 0x84, 0x61, 0x9e, 0x28, 0x61, 0xa6, 0xaa, 0x51, 0x6b, - 0x3b, 0x66, 0x95, 0xd8, 0x9a, 0x2c, 0x65, 0x99, 0x58, 0xad, 0xcf, 0xdf, - 0x8a, 0x0f, 0x60, 0x20, 0xc5, 0x1a, 0x3e, 0xfc, 0x28, 0x7e, 0x8f, 0x7f, - 0xe6, 0xa5, 0x48, 0xff, 0x2b, 0x65, 0xfd, 0xa5, 0xa2, 0x9e, 0x0d, 0x1d, - 0xe3, 0xf8, 0x68, 0x02, 0xac, 0x67, 0x0e, 0x12, 0x27, 0x37, 0x06, 0x95, - 0x0a, 0x59, 0xdf, 0x42, 0x6b, 0x0c, 0xc0, 0x79, 0xc8, 0x38, 0xde, 0x0c, - 0x60, 0x36, 0x89, 0xdf, 0xd0, 0x58, 0xd9, 0x67, 0x84, 0xf0, 0x54, 0x67, - 0xd3, 0x83, 0x27, 0x13, 0x99, 0xff, 0x0e, 0x68, 0x04, 0x7e, 0x65, 0xe3, - 0x69, 0x74, 0xec, 0x0e, 0x63, 0x2c, 0x05, 0xc2, 0x64, 0x43, 0x6d, 0x78, - 0xa0, 0xe8, 0x76, 0x9c, 0x60, 0x6b, 0xad, 0x0f, 0x5e, 0x2d, 0x44, 0xc1, - 0xa1, 0x2c, 0x5c, 0x2a, 0x01, 0x7b, 0xe3, 0xba, 0xbd, 0x8b, 0xd0, 0x7b, - 0x98, 0x77, 0x5e, 0xe9, 0xb0, 0xda, 0x95, 0x97, 0x6c, 0x32, 0x60, 0x6f, - 0x76, 0xf2, 0x07, 0x05, 0xd7, 0x3a, 0x40, 0x0b, 0x3e, 0xfc, 0xae, 0x72, - 0x30, 0xa2, 0x9c, 0x2f, 0x66, 0xea, 0x84, 0x1e, 0xa1, 0xc8, 0x67, 0x2c, - 0x07, 0x46, 0x84, 0xed, 0x38, 0x74, 0x75, 0xc9, 0x68, 0x7f, 0x63, 0x08, - 0x04, 0xb8, 0xb4, 0xd3, 0x62, 0x11, 0x50, 0x32, 0x20, 0x1e, 0xce, 0xf9, - 0x43, 0xc4, 0xe8, 0xb4, 0x01, 0x28, 0x85, 0x1b, 0x1e, 0x62, 0x60, 0x9c, - 0x43, 0xa7, 0xab, 0xd2, 0x8f, 0x25, 0xa6, 0x2d, 0x09, 0x7d, 0x25, 0x05, - 0x0c, 0x9e, 0x84, 0xdc, 0xd9, 0xf7, 0xf2, 0xda, 0x87, 0xce, 0x8e, 0x23, - 0x22, 0x9c, 0x4f, 0x4a, 0x0c, 0xe2, 0x6a, 0x2b, 0x18, 0x17, 0x65, 0x08, - 0xda, 0x18, 0x57, 0xfd, 0x34, 0x97, 0xbd, 0xc5, 0xce, 0x76, 0xa8, 0x22, - 0xee, 0x60, 0x63, 0x78, 0x30, 0x04, 0xfa, 0x49, 0x63, 0x65, 0x5f, 0xe4, - 0x75, 0x9f, 0x68, 0xf6, 0x93, 0x86, 0xf2, 0x76, 0x00, 0x91, 0xd1, 0x7b, - 0xcf, 0xcc, 0x55, 0xca, 0x4a, 0x2c, 0x35, 0xe0, 0x64, 0xb2, 0xc0, 0x2c, - 0x02, 0x84, 0xa2, 0xd8, 0x54, 0x08, 0xbe, 0x93, 0xfd, 0x77, 0x5d, 0xa5, - 0x4e, 0xc7, 0x07, 0x39, 0xed, 0xa5, 0x68, 0x0b, 0x93, 0x65, 0xc0, 0xd3, - 0x42, 0x55, 0xc8, 0x61, 0x92, 0x02, 0x34, 0x67, 0x93, 0x4e, 0xcb, 0xa1, - 0x99, 0x38, 0xe6, 0x93, 0x3b, 0xe2, 0x4c, 0x7d, 0x55, 0xc4, 0xd2, 0x55, - 0x81, 0x4a, 0xe4, 0xd7, 0x1c, 0x25, 0x85, 0xd8, 0xd2, 0x3e, 0x1c, 0xe6, - 0xd6, 0xdb, 0x85, 0x02, 0x2b, 0x67, 0x07, 0x5e, 0xdc, 0x19, 0x82, 0x10, - 0xa7, 0x8d, 0x2c, 0x08, 0xad, 0x4a, 0x7c, 0x54, 0x81, 0x65, 0xb6, 0xca, - 0x4a, 0x4c, 0x5d, 0xed, 0xb4, 0x3a, 0x81, 0x0c, 0xc5, 0x65, 0x01, 0x89, - 0x51, 0x6f, 0xbc, 0xfa, 0x90, 0x78, 0x6c, 0x81, 0x42, 0x00, 0xa3, 0x45, - 0xa3, 0x58, 0xa7, 0x09, 0x84, 0xa6, 0x6e, 0xae, 0xc6, 0x01, 0x84, 0x9e, - 0x8a, 0x78, 0xa9, 0xd8, 0x48, 0x07, 0x7c, 0x02, 0x44, 0x4d, 0xcf, 0xd9, - 0x6e, 0xae, 0xbd, 0xe2, 0x8c, 0xb4, 0x92, 0x65, 0x24, 0x43, 0x67, 0xb2, - 0x92, 0x86, 0xac, 0x81, 0x95, 0x48, 0xdc, 0xdf, 0xd7, 0x7d, 0x3b, 0xf2, - 0x4c, 0x4b, 0x19, 0xb0, 0xdd, 0x87, 0x1d, 0xd9, 0xf6, 0x0f, 0x30, 0x40, - 0x60, 0x78, 0x7b, 0xf8, 0xcf, 0x84, 0x60, 0x7c, 0x2d, 0xdc, 0xd3, 0x6b, - 0xbf, 0x68, 0xd3, 0x86, 0x7e, 0x22, 0xee, 0x81, 0x25, 0xdf, 0xee, 0x2b, - 0x2b, 0x39, 0x6b, 0xfe, 0x91, 0xa9, 0x41, 0x67, 0xe4, 0x8b, 0x14, 0xd6, - 0x9f, 0x12, 0xaf, 0x4f, 0x89, 0x35, 0xd9, 0x6f, 0xd1, 0x48, 0xae, 0x89, - 0xd3, 0x13, 0x8e, 0x13, 0xa0, 0xba, 0xc8, 0xef, 0xab, 0x2e, 0xdf, 0xe4, - 0x1f, 0xbd, 0xb7, 0x26, 0x28, 0x75, 0xe4, 0x7a, 0x11, 0x29, 0x8e, 0xe6, - 0x59, 0x62, 0x67, 0x2f, 0xd8, 0x8b, 0x87, 0xee, 0xcf, 0x80, 0x46, 0x14, - 0xd5, 0x77, 0xd8, 0x6b, 0xb0, 0xa4, 0xa0, 0xce, 0x93, 0xa8, 0x2c, 0x5f, - 0x4b, 0x3c, 0x56, 0x7b, 0x4e, 0x56, 0x2e, 0x7b, 0x3b, 0xa8, 0x26, 0x3e, - 0x96, 0x57, 0x05, 0x76, 0xc4, 0xff, 0x26, 0x7a, 0xe6, 0x3b, 0x21, 0xd2, - 0x76, 0x2b, 0xd3, 0xb8, 0x2d, 0x57, 0x7b, 0x62, 0xdb, 0x80, 0x9a, 0xde, - 0xad, 0x4a, 0x1b, 0x85, 0xb7, 0xd0, 0xa6, 0x0e, 0x85, 0x0a, 0xbb, 0x43, - 0x9f, 0x5c, 0x03, 0x4f, 0x9c, 0x47, 0x11, 0xb2, 0x5c, 0xc8, 0x8f, 0xb5, - 0x8d, 0xf1, 0x28, 0x37, 0xca, 0x30, 0x82, 0x02, 0xf9, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x02, 0xea, - 0x04, 0x82, 0x02, 0xe6, 0x30, 0x82, 0x02, 0xe2, 0x30, 0x82, 0x02, 0xde, - 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, - 0x02, 0xa0, 0x82, 0x02, 0xa6, 0x30, 0x82, 0x02, 0xa2, 0x30, 0x1c, 0x06, - 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, - 0x0e, 0x04, 0x08, 0xfd, 0x54, 0x70, 0x85, 0x3f, 0x2b, 0x23, 0x6c, 0x02, - 0x02, 0x08, 0x00, 0x04, 0x82, 0x02, 0x80, 0xbc, 0x6f, 0xe7, 0x00, 0x36, - 0xd9, 0xe9, 0xba, 0x49, 0x04, 0xd5, 0x06, 0xb0, 0xbb, 0x6b, 0xe8, 0x8d, - 0x51, 0x46, 0x38, 0xdc, 0x00, 0xc6, 0xf0, 0xc7, 0xb0, 0x9d, 0xf9, 0x82, - 0xec, 0x87, 0x08, 0x6a, 0x7f, 0xce, 0xb8, 0x22, 0x55, 0xae, 0x24, 0x8f, - 0x77, 0x50, 0x40, 0xf2, 0x72, 0x9d, 0xc9, 0xc9, 0x97, 0x0d, 0x1c, 0xee, - 0x8c, 0x30, 0x0b, 0xfe, 0x8c, 0x63, 0x1e, 0x1b, 0x6a, 0x13, 0xaa, 0xf5, - 0x60, 0xf1, 0x38, 0x00, 0x5b, 0x55, 0x18, 0x43, 0xf5, 0xea, 0x9e, 0xdc, - 0x12, 0xb4, 0xfd, 0xf8, 0xee, 0x62, 0x0d, 0x67, 0x32, 0x23, 0xf5, 0x3c, - 0x43, 0x5f, 0x18, 0xea, 0x3a, 0x1b, 0x7f, 0xcb, 0x20, 0xe4, 0x80, 0xb3, - 0xd4, 0x37, 0x1a, 0x58, 0x59, 0x3b, 0x40, 0xd7, 0x8e, 0x30, 0xbe, 0xee, - 0x7b, 0x65, 0xa4, 0x39, 0xf5, 0x4c, 0xa8, 0x8c, 0x20, 0x79, 0xe3, 0x1f, - 0x72, 0x82, 0x1f, 0xe3, 0x16, 0xfd, 0x29, 0xe2, 0x90, 0xa0, 0xac, 0x54, - 0xad, 0x01, 0x18, 0x42, 0x02, 0xef, 0xae, 0x61, 0x7b, 0xf9, 0x89, 0x8c, - 0x40, 0x97, 0xfb, 0x5a, 0x4c, 0xee, 0x9a, 0xb0, 0x02, 0xc3, 0x48, 0x28, - 0x58, 0xb0, 0x9a, 0x98, 0xe8, 0x70, 0x53, 0xc7, 0x7d, 0x40, 0x2e, 0x6d, - 0x0a, 0x0c, 0xa1, 0xb6, 0xac, 0x48, 0xe0, 0xde, 0x3a, 0x37, 0x52, 0x77, - 0xc5, 0x89, 0x8f, 0xa7, 0xf8, 0xaf, 0xfc, 0x94, 0x2d, 0xb7, 0xf1, 0xff, - 0x79, 0x44, 0x29, 0x69, 0xee, 0x6f, 0xaf, 0x3e, 0xe6, 0xe4, 0x09, 0x62, - 0x45, 0x36, 0xb2, 0x11, 0x3d, 0x0a, 0xdc, 0x3a, 0xc6, 0x6b, 0x46, 0x48, - 0x42, 0x60, 0xd5, 0x92, 0x49, 0x3e, 0xd8, 0xbc, 0x4b, 0x47, 0x2b, 0x2a, - 0xe9, 0xa6, 0xe5, 0xca, 0x6a, 0x39, 0x87, 0x3b, 0xa8, 0xa4, 0xae, 0x29, - 0x36, 0xb4, 0x39, 0xe2, 0x7e, 0x9a, 0x22, 0x69, 0xc6, 0xa3, 0x95, 0xa3, - 0x20, 0xf9, 0x6e, 0xc9, 0xfd, 0x4c, 0x3a, 0xd4, 0x9d, 0x9c, 0xeb, 0x91, - 0x95, 0xdc, 0x1a, 0x3b, 0xd8, 0x0d, 0x0a, 0x87, 0x52, 0xef, 0x13, 0x77, - 0xee, 0x92, 0x25, 0xba, 0xc7, 0x7a, 0x16, 0x2d, 0x85, 0x78, 0x3e, 0xbb, - 0x0f, 0x95, 0xed, 0x60, 0xd0, 0x01, 0x60, 0xa2, 0x69, 0x3b, 0x3c, 0x63, - 0x5c, 0x10, 0x78, 0x15, 0x72, 0x40, 0xc6, 0x1e, 0x0e, 0x34, 0xee, 0x71, - 0x1d, 0xdf, 0xfb, 0x5f, 0x58, 0x3a, 0xdf, 0xb9, 0xc0, 0xa1, 0xa2, 0x02, - 0x25, 0xc7, 0x16, 0xe4, 0x50, 0x64, 0xa8, 0x84, 0x3e, 0xa0, 0xb2, 0x8a, - 0xfa, 0xbe, 0x55, 0x17, 0xf9, 0x7c, 0x64, 0x4b, 0xa6, 0xf7, 0x50, 0x52, - 0x06, 0x39, 0xb1, 0x30, 0x28, 0x32, 0xa7, 0x7b, 0xaf, 0x18, 0xbd, 0x8b, - 0x25, 0x6d, 0xde, 0x95, 0x82, 0xfb, 0x65, 0x71, 0x31, 0xca, 0x3e, 0x41, - 0xb1, 0xa9, 0xf1, 0xec, 0x3c, 0xbc, 0x24, 0x49, 0x12, 0x1a, 0x49, 0x66, - 0x90, 0xb2, 0xc4, 0x36, 0xe3, 0xd8, 0x93, 0x66, 0x6c, 0xc6, 0x81, 0xef, - 0xf3, 0x61, 0xab, 0x4c, 0xba, 0x8e, 0x39, 0x47, 0xeb, 0x9b, 0xdf, 0x59, - 0x9e, 0x45, 0xdc, 0x64, 0x51, 0xfb, 0x2d, 0x4c, 0x61, 0xbe, 0x70, 0x3a, - 0x20, 0x86, 0x09, 0x75, 0xbe, 0x03, 0xdc, 0x35, 0x00, 0xae, 0xa9, 0x3d, - 0xb4, 0xa2, 0x3a, 0xfb, 0xc5, 0x63, 0xb6, 0xf1, 0x92, 0x58, 0x84, 0x42, - 0xf3, 0x11, 0x47, 0x38, 0xd4, 0x47, 0x59, 0x7d, 0xc6, 0xb6, 0x31, 0x83, - 0x7e, 0x44, 0x41, 0xca, 0x50, 0x34, 0xf6, 0xf2, 0x23, 0x1f, 0x4d, 0x7d, - 0x4d, 0xf7, 0xe8, 0x0b, 0x58, 0x0f, 0x94, 0x1f, 0x66, 0x8b, 0xe6, 0x6d, - 0xe3, 0x91, 0xf8, 0xe7, 0xca, 0xca, 0x86, 0xdb, 0x66, 0x7e, 0x3e, 0x0c, - 0x7a, 0xa8, 0xd4, 0xd4, 0xa2, 0x98, 0xe7, 0x33, 0x09, 0x7a, 0x77, 0x0d, - 0x63, 0x48, 0x0a, 0x7e, 0x27, 0x2e, 0x59, 0x87, 0xcc, 0x47, 0xa6, 0x2d, - 0x14, 0xfc, 0x1f, 0xa7, 0x31, 0xba, 0xac, 0xef, 0x4e, 0xf2, 0x02, 0xdc, - 0x8c, 0x7b, 0x44, 0x08, 0x4a, 0xeb, 0xbe, 0x48, 0xe1, 0xf0, 0x56, 0xb1, - 0xe2, 0x1a, 0x5a, 0x39, 0x11, 0x3b, 0x56, 0x5b, 0x7f, 0x05, 0xd4, 0x99, - 0x6d, 0xa1, 0x46, 0x42, 0x9a, 0x69, 0xc8, 0x97, 0x5c, 0x3b, 0xfd, 0x18, - 0x28, 0x98, 0xaa, 0x7a, 0x66, 0xf1, 0x7d, 0xcb, 0x60, 0x38, 0xd8, 0x97, - 0xed, 0x28, 0xec, 0xbb, 0x6e, 0xf0, 0x83, 0xdc, 0x1c, 0xae, 0xc2, 0xd3, - 0xa5, 0x2b, 0xd5, 0x13, 0x22, 0xf6, 0x6c, 0x7c, 0x43, 0x74, 0xf3, 0xed, - 0xd1, 0x89, 0x0a, 0x2c, 0x93, 0xb0, 0x42, 0xa3, 0x5f, 0xda, 0xa7, 0x04, - 0x76, 0x33, 0xb8, 0x05, 0xf5, 0xaf, 0xf4, 0x91, 0x43, 0x88, 0xde, 0xfc, - 0x68, 0xd0, 0xa4, 0x1f, 0x6e, 0x47, 0xc3, 0x73, 0x96, 0xfa, 0x4d, 0x31, - 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x9e, 0x4f, 0xb2, 0x4e, 0x45, 0x98, - 0x37, 0x90, 0x63, 0x59, 0xe3, 0x7b, 0xcc, 0xca, 0x76, 0x0a, 0xaf, 0x95, - 0x35, 0x37, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, - 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x82, 0xbc, 0x96, 0xb1, 0x5d, - 0x7f, 0x5d, 0x93, 0x54, 0x42, 0x95, 0x55, 0x01, 0x6a, 0xcd, 0x65, 0x01, - 0x7a, 0x06, 0xcf, 0x04, 0x08, 0x39, 0xfd, 0x29, 0x7c, 0xbe, 0x39, 0x07, - 0xd5, 0x02, 0x02, 0x08, 0x00 -}; - -unsigned char _user_two_p12[] = { - 0x30, 0x82, 0x06, 0xf1, 0x02, 0x01, 0x03, 0x30, 0x82, 0x06, 0xb7, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, - 0x06, 0xa8, 0x04, 0x82, 0x06, 0xa4, 0x30, 0x82, 0x06, 0xa0, 0x30, 0x82, - 0x03, 0x9f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, - 0x06, 0xa0, 0x82, 0x03, 0x90, 0x30, 0x82, 0x03, 0x8c, 0x02, 0x01, 0x00, - 0x30, 0x82, 0x03, 0x85, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x59, 0x5c, 0x39, - 0x74, 0xd7, 0x82, 0x11, 0x51, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x03, - 0x58, 0xa6, 0xd1, 0xa1, 0x2f, 0x26, 0x9d, 0x85, 0x45, 0xae, 0x87, 0x8f, - 0xd4, 0x13, 0x32, 0x90, 0xba, 0x53, 0x3b, 0x65, 0x02, 0xa9, 0xa0, 0xe6, - 0x45, 0x30, 0xee, 0x1c, 0xf6, 0x24, 0x38, 0x22, 0x26, 0x37, 0x50, 0x2d, - 0x7c, 0x9b, 0x66, 0xa6, 0x13, 0xed, 0xd5, 0x9f, 0xd3, 0x6d, 0xc6, 0x2b, - 0x9c, 0x66, 0x22, 0x3f, 0x95, 0xa5, 0x99, 0xc9, 0x8b, 0xcc, 0x40, 0x4b, - 0xa8, 0xd0, 0x2a, 0x6f, 0x16, 0x9b, 0xc3, 0xec, 0xfc, 0xa4, 0x28, 0xc5, - 0xb0, 0xa8, 0xc2, 0x96, 0xb4, 0xa2, 0x9d, 0x8d, 0x33, 0xc3, 0x6d, 0xc8, - 0xac, 0x64, 0x34, 0x73, 0xda, 0x1c, 0x5b, 0x07, 0xc1, 0x45, 0xac, 0xe2, - 0x00, 0x56, 0xaf, 0x38, 0xc1, 0x30, 0xe4, 0x65, 0x24, 0x42, 0x67, 0x2d, - 0xcf, 0x19, 0xad, 0x2a, 0xe2, 0x04, 0x2d, 0x5a, 0x48, 0xd1, 0xdc, 0xbe, - 0x88, 0xb7, 0x31, 0x5b, 0x37, 0x75, 0x6e, 0xa5, 0xe2, 0x74, 0xf0, 0xba, - 0xac, 0xe2, 0x24, 0x84, 0x6d, 0x94, 0x65, 0xb4, 0x55, 0x3f, 0xf8, 0x8d, - 0xd3, 0x13, 0xa1, 0xce, 0x33, 0x4f, 0x39, 0xc7, 0x80, 0x1a, 0x0e, 0x68, - 0x0f, 0x63, 0xc6, 0x36, 0x01, 0xaa, 0xd3, 0x3b, 0x03, 0xe4, 0xa9, 0xdd, - 0x4d, 0x4a, 0xcc, 0xf8, 0x2b, 0x55, 0xa7, 0x47, 0x31, 0x39, 0x14, 0xd5, - 0x0f, 0x3f, 0x38, 0xfd, 0xc7, 0xe6, 0x99, 0x36, 0xc2, 0x1b, 0xa8, 0x99, - 0x16, 0xa8, 0x05, 0x7a, 0xc4, 0x66, 0x97, 0x13, 0x09, 0x0d, 0x15, 0x14, - 0x66, 0x3c, 0x9b, 0x39, 0x6c, 0x10, 0xc9, 0xc5, 0xbe, 0x69, 0xd7, 0x13, - 0x21, 0xb3, 0xd8, 0x29, 0x50, 0xf4, 0x40, 0x77, 0x09, 0xb3, 0x32, 0xf2, - 0x88, 0xa5, 0x05, 0x5e, 0x14, 0x77, 0x41, 0xd5, 0x31, 0x82, 0xcb, 0xea, - 0xe0, 0x56, 0xd3, 0xb0, 0x3e, 0x27, 0xd7, 0x9d, 0x46, 0x04, 0x07, 0x86, - 0x8b, 0xb2, 0x0f, 0x45, 0xc4, 0x8b, 0xff, 0xcb, 0x39, 0x54, 0x6c, 0xe0, - 0x9b, 0x6d, 0xbc, 0x5d, 0x1c, 0x0e, 0xb2, 0xba, 0xfe, 0x94, 0x2a, 0x9c, - 0x4f, 0x84, 0x44, 0x17, 0xc4, 0x07, 0x0b, 0x8d, 0x6f, 0x90, 0x23, 0xfb, - 0xf3, 0xe4, 0x0f, 0x4a, 0xf4, 0x40, 0xf5, 0xf4, 0xfe, 0xb4, 0x32, 0xde, - 0x01, 0x0c, 0x00, 0x3a, 0x0a, 0x9e, 0xa0, 0x1a, 0x95, 0x94, 0xbe, 0x3c, - 0x75, 0x32, 0x38, 0x50, 0x07, 0xd3, 0x70, 0x30, 0x47, 0x7a, 0xce, 0x74, - 0x57, 0x8f, 0x7b, 0x5c, 0x2b, 0xb8, 0xc0, 0x72, 0xbf, 0x9a, 0xab, 0xc0, - 0xe4, 0x26, 0xec, 0x91, 0x80, 0xba, 0x45, 0xa7, 0xc0, 0x18, 0xcf, 0xed, - 0x24, 0x9f, 0x1b, 0x07, 0xcb, 0x1b, 0xd2, 0x81, 0xe8, 0x4b, 0x26, 0x0a, - 0xf6, 0x4c, 0x81, 0x5f, 0x4f, 0x2a, 0x7c, 0x79, 0x25, 0xd6, 0x8b, 0xe7, - 0x00, 0x82, 0xf2, 0x6e, 0x6c, 0x63, 0x38, 0x19, 0x79, 0x05, 0x0e, 0xb8, - 0x13, 0x2b, 0x30, 0x2b, 0xd3, 0xe3, 0x85, 0x6b, 0x75, 0x32, 0xc2, 0x58, - 0xa4, 0xf0, 0xd3, 0x0a, 0xae, 0xee, 0x3e, 0x10, 0x28, 0x5d, 0xd5, 0x09, - 0x6f, 0x0f, 0xa2, 0x15, 0x6f, 0x3c, 0x40, 0xb9, 0x74, 0x7f, 0x35, 0xb1, - 0xd6, 0x58, 0x6a, 0x09, 0x2c, 0x29, 0x0d, 0x69, 0x37, 0xae, 0x17, 0xd2, - 0x98, 0xef, 0x4a, 0xbd, 0x18, 0x3f, 0x97, 0x83, 0x81, 0x63, 0x8f, 0xc5, - 0x98, 0x2a, 0xb8, 0xe9, 0x32, 0xef, 0x6b, 0x4c, 0x26, 0xd8, 0x1d, 0x8f, - 0x5c, 0x68, 0xe0, 0x68, 0x2f, 0x5e, 0x2c, 0x85, 0xa5, 0xbc, 0x88, 0x56, - 0x1b, 0xc7, 0x0e, 0x22, 0x80, 0x80, 0x36, 0x43, 0x68, 0x5d, 0xd4, 0x0e, - 0xb5, 0x08, 0x82, 0xfe, 0xae, 0xc5, 0xde, 0x61, 0x1e, 0xf8, 0xfe, 0x64, - 0x66, 0xf2, 0xda, 0x9e, 0x8e, 0xb9, 0x8e, 0xa9, 0xcd, 0xe4, 0x17, 0xe0, - 0x12, 0xd4, 0x37, 0x54, 0xd0, 0x24, 0xca, 0xcc, 0xc0, 0xa9, 0xd4, 0x98, - 0x1d, 0xe9, 0x04, 0x64, 0x50, 0x3d, 0x76, 0x0f, 0xf7, 0x75, 0xde, 0xb5, - 0x5c, 0x0a, 0x3b, 0x70, 0x3e, 0xeb, 0x0b, 0x26, 0x98, 0x0e, 0x47, 0x6b, - 0x36, 0x3d, 0x7b, 0x04, 0x20, 0x26, 0xf7, 0xe6, 0x01, 0xbf, 0xda, 0xc9, - 0x09, 0xce, 0x2f, 0xd9, 0xeb, 0x8a, 0x19, 0x68, 0x9b, 0x67, 0x5d, 0x2a, - 0xef, 0x74, 0x6f, 0xcd, 0xd2, 0x3b, 0xdc, 0x65, 0xbc, 0x79, 0x40, 0x12, - 0x52, 0x3e, 0x57, 0xc4, 0x12, 0xf2, 0x4e, 0x1a, 0x5d, 0x63, 0x55, 0x0a, - 0xb7, 0x70, 0x85, 0x09, 0x6e, 0x97, 0x2f, 0xf8, 0x7b, 0x02, 0xb6, 0x03, - 0xa3, 0x7d, 0x91, 0x06, 0xb9, 0xf4, 0xfc, 0x45, 0x03, 0x6a, 0xb2, 0xc0, - 0x8c, 0x75, 0xe3, 0x16, 0x0e, 0xa7, 0x65, 0x9a, 0xd4, 0x05, 0x7e, 0x03, - 0xe0, 0x42, 0xbd, 0x8f, 0x55, 0xac, 0xf3, 0xde, 0x70, 0x0a, 0xc6, 0xbc, - 0x0d, 0xda, 0x14, 0x87, 0x3e, 0xa2, 0x18, 0x28, 0xa7, 0x4a, 0xea, 0x21, - 0x12, 0x70, 0xd3, 0x31, 0xed, 0x22, 0x5e, 0xc6, 0xed, 0xf0, 0xc1, 0xee, - 0xe6, 0x4b, 0x34, 0x22, 0x97, 0x87, 0x37, 0x24, 0x8f, 0xe4, 0x47, 0x99, - 0x5d, 0x0a, 0x82, 0xe3, 0xca, 0x88, 0xcf, 0x35, 0xa3, 0xe5, 0xa3, 0xef, - 0x8b, 0x2c, 0x0a, 0x2c, 0x1f, 0xe4, 0x24, 0xaa, 0xf2, 0x9e, 0x85, 0x28, - 0xae, 0x60, 0xcc, 0x0a, 0xfc, 0x94, 0x5b, 0x4a, 0xe4, 0x6e, 0xeb, 0x59, - 0xa3, 0x6f, 0x86, 0xac, 0xc5, 0x2c, 0xf5, 0xaa, 0x10, 0xf4, 0x9e, 0x08, - 0xc5, 0xbe, 0x8b, 0x9e, 0xe5, 0xd7, 0x6b, 0x49, 0xde, 0x0c, 0x16, 0x38, - 0x6f, 0xa5, 0x74, 0x62, 0x93, 0x44, 0xd8, 0xf7, 0x6d, 0x40, 0x98, 0xf7, - 0xfd, 0x6b, 0xc9, 0xda, 0xc7, 0x49, 0xf5, 0x7c, 0x83, 0x9e, 0xc8, 0xe3, - 0x6e, 0x51, 0x93, 0xfe, 0xb4, 0xe6, 0xa4, 0x2c, 0x18, 0xe8, 0x96, 0xb6, - 0xb7, 0x11, 0x4d, 0xd4, 0x94, 0x34, 0xfc, 0x4f, 0x2f, 0x17, 0x58, 0x84, - 0x5a, 0xaa, 0xb7, 0x8f, 0x41, 0x65, 0x7a, 0xac, 0xbc, 0x7d, 0x77, 0x1f, - 0xf2, 0x99, 0xba, 0x60, 0xe1, 0xe0, 0x24, 0xc0, 0x24, 0x56, 0x08, 0x24, - 0x39, 0x12, 0xd3, 0xa8, 0xa3, 0x51, 0x37, 0xab, 0xd6, 0xab, 0x78, 0x3c, - 0x82, 0x91, 0xb8, 0x8e, 0xbf, 0xe6, 0xfd, 0x19, 0x05, 0x60, 0x14, 0xdf, - 0x19, 0x2f, 0x07, 0x54, 0x11, 0xea, 0x45, 0xec, 0x37, 0xaa, 0x2b, 0x9d, - 0xa4, 0xfe, 0xd4, 0x34, 0xdf, 0xcc, 0x33, 0xda, 0x09, 0xa9, 0xa9, 0x49, - 0x10, 0x48, 0xc3, 0x63, 0x49, 0x30, 0x82, 0x02, 0xf9, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x02, 0xea, - 0x04, 0x82, 0x02, 0xe6, 0x30, 0x82, 0x02, 0xe2, 0x30, 0x82, 0x02, 0xde, - 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, - 0x02, 0xa0, 0x82, 0x02, 0xa6, 0x30, 0x82, 0x02, 0xa2, 0x30, 0x1c, 0x06, - 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, - 0x0e, 0x04, 0x08, 0x8d, 0xff, 0x52, 0xa2, 0x8e, 0x75, 0xb1, 0x64, 0x02, - 0x02, 0x08, 0x00, 0x04, 0x82, 0x02, 0x80, 0x57, 0x31, 0xfa, 0x59, 0x1f, - 0xec, 0x07, 0x6b, 0xcc, 0x29, 0x14, 0x9f, 0xbe, 0x11, 0x4f, 0x1b, 0xb2, - 0x14, 0x51, 0xca, 0x2e, 0x3c, 0x53, 0xf5, 0x8f, 0xab, 0x90, 0xa0, 0xae, - 0xf1, 0xa8, 0xd8, 0xc9, 0x51, 0xae, 0x5b, 0x84, 0xc8, 0xfa, 0xfe, 0x54, - 0x33, 0xf3, 0x02, 0xb2, 0x74, 0x6c, 0x77, 0xcf, 0xe8, 0xdf, 0xab, 0x45, - 0xaf, 0xb2, 0x1e, 0x18, 0xdd, 0x57, 0xa6, 0x3a, 0xc1, 0xac, 0xab, 0x83, - 0x48, 0x91, 0x24, 0x06, 0xce, 0x58, 0x69, 0x15, 0x23, 0xf4, 0x19, 0x8f, - 0x53, 0xd5, 0x92, 0x76, 0x31, 0x35, 0x75, 0xd6, 0x5d, 0xb3, 0x87, 0xe2, - 0xb3, 0x96, 0x85, 0x30, 0xe0, 0x93, 0xff, 0x02, 0x7b, 0xba, 0x89, 0x50, - 0xa9, 0xbc, 0x9d, 0x85, 0x20, 0x17, 0x3e, 0x1c, 0xef, 0xcf, 0xf9, 0x69, - 0xdf, 0x89, 0xe8, 0x11, 0x4b, 0xcc, 0x48, 0x9a, 0x5a, 0x1a, 0x6b, 0x86, - 0xc4, 0x74, 0xc8, 0x8f, 0x34, 0x0a, 0xbf, 0xec, 0xc8, 0x9d, 0x0f, 0x52, - 0xd7, 0x0e, 0x39, 0x46, 0x42, 0xf8, 0x8d, 0x14, 0xf5, 0x44, 0x73, 0xb4, - 0x78, 0x31, 0x89, 0x02, 0xc6, 0x8d, 0xae, 0x2f, 0x9c, 0x7c, 0x7a, 0x5b, - 0x55, 0x04, 0xe7, 0x81, 0x84, 0x36, 0xee, 0xb8, 0x47, 0x81, 0x65, 0x95, - 0x8e, 0x35, 0x7f, 0x15, 0xdc, 0xeb, 0xdc, 0x28, 0xe2, 0x16, 0xe8, 0x86, - 0x1c, 0x7d, 0x1a, 0xd8, 0xe5, 0x8f, 0x4c, 0x29, 0x17, 0x1a, 0x9e, 0xe9, - 0xc2, 0xd1, 0x84, 0x78, 0x76, 0xd6, 0x93, 0x8c, 0x29, 0x62, 0x3a, 0x2d, - 0xdd, 0xc6, 0xb4, 0xab, 0x32, 0xd9, 0x18, 0x2a, 0x1d, 0x38, 0x11, 0x48, - 0x4d, 0x0b, 0xd0, 0x3c, 0xed, 0x51, 0x0f, 0x77, 0x97, 0x67, 0x40, 0x96, - 0x64, 0x99, 0x34, 0x56, 0xf5, 0x45, 0xe9, 0xfe, 0x87, 0x5b, 0xb2, 0xe9, - 0x01, 0x1a, 0xfc, 0x83, 0x7e, 0x9f, 0x8b, 0xc9, 0xb2, 0xa9, 0x99, 0x1f, - 0xb2, 0x32, 0xed, 0xb8, 0x21, 0x00, 0xf5, 0x94, 0x56, 0x15, 0x72, 0xee, - 0x84, 0x0b, 0x98, 0x9d, 0x9f, 0xc9, 0xf6, 0x4b, 0x65, 0x71, 0xdb, 0xc0, - 0x49, 0xd8, 0xf8, 0x86, 0x13, 0xc4, 0x23, 0xf7, 0xe3, 0x30, 0xb6, 0x6d, - 0x2f, 0x72, 0xdb, 0x01, 0x7b, 0x68, 0x46, 0xbe, 0xd6, 0xd5, 0xfe, 0xca, - 0xc7, 0x87, 0xec, 0x7c, 0xb6, 0x91, 0x27, 0xa4, 0xb5, 0x9f, 0x9d, 0xf7, - 0xeb, 0x93, 0xce, 0x55, 0xd8, 0x61, 0xcb, 0x2a, 0x45, 0xd4, 0xe6, 0x94, - 0x9c, 0x06, 0xb3, 0xe3, 0x7b, 0xbc, 0xc8, 0xff, 0xff, 0xbb, 0x29, 0xe8, - 0x6c, 0xb5, 0x22, 0x64, 0xa4, 0xd4, 0x7e, 0x08, 0x29, 0xae, 0x05, 0xd6, - 0xf7, 0x88, 0x8b, 0xc4, 0x12, 0x1d, 0xef, 0x38, 0x74, 0x32, 0x8d, 0x2c, - 0x59, 0x10, 0x5b, 0x9f, 0xac, 0x45, 0x5e, 0xef, 0x62, 0xc3, 0x66, 0x64, - 0xc4, 0xc7, 0xb3, 0x1d, 0xb1, 0xec, 0x76, 0x90, 0x2f, 0xc8, 0x52, 0x65, - 0x3c, 0x58, 0x02, 0x01, 0x52, 0x42, 0xbd, 0x38, 0xc4, 0xb1, 0x33, 0x5e, - 0x9d, 0x6a, 0x19, 0x4f, 0xf1, 0xee, 0x1f, 0x1c, 0x90, 0x40, 0x40, 0x9d, - 0x41, 0xec, 0x3d, 0xbe, 0xe3, 0x97, 0x70, 0x95, 0x5c, 0x16, 0x66, 0xfd, - 0xc9, 0xee, 0x29, 0x14, 0x7a, 0x9b, 0x53, 0xa7, 0x8b, 0x4e, 0xf5, 0x3b, - 0xbe, 0xb4, 0x1b, 0xab, 0x25, 0x5c, 0xcd, 0xac, 0xe0, 0x49, 0xd1, 0xbc, - 0xcb, 0x1a, 0x8a, 0x7f, 0x62, 0x67, 0xeb, 0xe2, 0x0c, 0x4f, 0x05, 0x0f, - 0x28, 0xcf, 0xe7, 0x8a, 0x4c, 0x62, 0x16, 0x56, 0x66, 0x83, 0x9e, 0x56, - 0x13, 0x9d, 0xf5, 0xc4, 0xeb, 0x69, 0xae, 0x64, 0xcd, 0xa0, 0x40, 0x5f, - 0x61, 0x2d, 0x45, 0xa6, 0x5d, 0x41, 0x88, 0x87, 0xb2, 0x49, 0x30, 0x24, - 0x95, 0x9d, 0x30, 0x77, 0x36, 0xde, 0x75, 0x54, 0x3b, 0xac, 0xc8, 0x6b, - 0xf5, 0xed, 0x54, 0xcb, 0xef, 0xa0, 0xc8, 0xdb, 0x1b, 0x80, 0x08, 0x34, - 0x91, 0xe7, 0x8b, 0xbe, 0x4e, 0x46, 0xed, 0x04, 0x64, 0x51, 0x73, 0xa2, - 0x6e, 0x52, 0xa2, 0xe4, 0xe3, 0x8a, 0x72, 0x75, 0xf8, 0xb5, 0xc4, 0xa2, - 0x4a, 0xab, 0xa4, 0x4e, 0xf1, 0x65, 0x29, 0xee, 0xe6, 0x97, 0xb8, 0xeb, - 0x18, 0x9e, 0x49, 0x08, 0x92, 0x54, 0xc9, 0x20, 0xff, 0xfa, 0xc5, 0x39, - 0x36, 0xa5, 0xc5, 0xf4, 0x53, 0x91, 0x73, 0x88, 0x94, 0xf1, 0xd9, 0x5a, - 0x5b, 0xd0, 0x6f, 0x64, 0x9e, 0x32, 0xa6, 0xbf, 0xd2, 0x8e, 0xd7, 0x01, - 0x53, 0xe2, 0xdd, 0xde, 0xf9, 0x39, 0x4f, 0x53, 0xf0, 0x38, 0x80, 0x87, - 0xb2, 0x6b, 0x6e, 0x67, 0x5e, 0x6c, 0xcb, 0x21, 0x8b, 0x9a, 0xb3, 0xfc, - 0x4b, 0x50, 0x71, 0x66, 0xdd, 0x80, 0xa8, 0x0b, 0x76, 0xa7, 0xb6, 0x78, - 0xce, 0x09, 0x16, 0x88, 0x3f, 0xbb, 0x85, 0xcc, 0x30, 0x78, 0x12, 0x31, - 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x1e, 0x0f, 0x8e, 0x8c, 0x64, 0x6c, - 0x43, 0xac, 0xd5, 0x64, 0x2c, 0xab, 0x5f, 0xa8, 0x1b, 0x09, 0x44, 0x00, - 0x32, 0x8d, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, - 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x79, 0xb8, 0x38, 0x22, 0x89, - 0x49, 0xa9, 0x7b, 0xfa, 0x75, 0xb9, 0x92, 0xd7, 0x25, 0xf4, 0x42, 0x17, - 0x1f, 0xf0, 0x19, 0x04, 0x08, 0x46, 0x09, 0xf3, 0x1a, 0x9a, 0xa5, 0xda, - 0xb3, 0x02, 0x02, 0x08, 0x00 -}; - - -unsigned char ECDSA_fails_import_p12[] = { - 0x30, 0x82, 0x07, 0xf8, 0x02, 0x01, 0x03, 0x30, 0x82, 0x07, 0xbf, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, - 0x07, 0xb0, 0x04, 0x82, 0x07, 0xac, 0x30, 0x82, 0x07, 0xa8, 0x30, 0x82, - 0x04, 0xdf, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, - 0x06, 0xa0, 0x82, 0x04, 0xd0, 0x30, 0x82, 0x04, 0xcc, 0x02, 0x01, 0x00, - 0x30, 0x82, 0x04, 0xc5, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x32, 0xb1, 0x01, - 0x77, 0xeb, 0x95, 0x02, 0xb9, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x04, - 0x98, 0x8f, 0xa0, 0x71, 0x8a, 0x9a, 0x75, 0x78, 0x29, 0x7e, 0xc9, 0x54, - 0x98, 0xba, 0x58, 0x7f, 0x65, 0x29, 0xb5, 0x9e, 0xb9, 0xc3, 0xfd, 0x9f, - 0xfc, 0x43, 0x31, 0x08, 0x73, 0x45, 0x03, 0x7d, 0xfc, 0x97, 0x20, 0x8f, - 0xb1, 0x4c, 0x85, 0xc3, 0xe9, 0xda, 0xf8, 0x73, 0xbc, 0x77, 0xe5, 0xff, - 0xc7, 0xef, 0x74, 0xc0, 0xb6, 0x18, 0xa9, 0x76, 0x2c, 0x00, 0x2c, 0x00, - 0x9f, 0xcb, 0x34, 0x16, 0x0b, 0xf0, 0x11, 0x7c, 0xc0, 0x65, 0x1c, 0x69, - 0x51, 0xbb, 0x92, 0x86, 0xbf, 0x2e, 0xdf, 0x1e, 0x15, 0xad, 0x1f, 0x66, - 0xdf, 0x5e, 0x9e, 0xb4, 0xf1, 0x9b, 0x86, 0x0d, 0x0f, 0xe6, 0xd2, 0x01, - 0x91, 0x0e, 0x37, 0x43, 0xba, 0x5a, 0xf3, 0x4e, 0x3c, 0x5d, 0xc7, 0x0d, - 0x14, 0x38, 0xc3, 0x4a, 0x10, 0x9a, 0x2d, 0xf8, 0x53, 0x2d, 0xfd, 0x00, - 0xa9, 0x2b, 0xd1, 0x3f, 0xc4, 0xf8, 0x99, 0xb6, 0xaa, 0x1f, 0x70, 0xb4, - 0x2f, 0xa4, 0xa6, 0x07, 0x1a, 0x95, 0xd1, 0x93, 0xf1, 0xd2, 0xfe, 0x3f, - 0x7c, 0xb0, 0x55, 0x18, 0xd5, 0x9f, 0x37, 0x11, 0x3d, 0x2d, 0x1f, 0xb8, - 0xc8, 0x47, 0xa5, 0x03, 0xa5, 0x2e, 0x91, 0x04, 0xe0, 0xd0, 0x15, 0x70, - 0xa2, 0x05, 0xac, 0x71, 0x4a, 0x09, 0x93, 0xbb, 0x44, 0xeb, 0x78, 0x20, - 0x7b, 0xbb, 0x0a, 0x2f, 0x0a, 0x51, 0x5c, 0x16, 0x32, 0x37, 0x82, 0x9e, - 0xc8, 0x90, 0x96, 0xee, 0x9a, 0x4e, 0x77, 0x21, 0xfd, 0x37, 0x80, 0x2f, - 0x55, 0xf2, 0x03, 0xb1, 0x31, 0x7e, 0x9b, 0x90, 0xa9, 0x7b, 0xb4, 0x19, - 0x5d, 0x10, 0xfd, 0x22, 0xa5, 0x07, 0x24, 0xc5, 0xda, 0x86, 0x1e, 0xbd, - 0x4a, 0xa6, 0xc2, 0x02, 0x71, 0xa5, 0x3d, 0xca, 0x5b, 0x19, 0x5d, 0xb6, - 0xc4, 0x7d, 0xe7, 0x74, 0xf5, 0x71, 0xd5, 0xe5, 0x9f, 0x0a, 0x4a, 0x01, - 0xa0, 0xe6, 0xa0, 0x73, 0x93, 0xaa, 0x3b, 0x6c, 0x03, 0x4c, 0xbd, 0x32, - 0xc9, 0x97, 0xaf, 0x84, 0x79, 0x3d, 0x93, 0x49, 0xc6, 0xbc, 0x2a, 0x4f, - 0xe1, 0x3e, 0x9f, 0x86, 0xe3, 0xd2, 0x16, 0xd3, 0xb3, 0xf6, 0xac, 0x3c, - 0xb4, 0x6a, 0xa6, 0x68, 0xb8, 0xf4, 0xe7, 0x68, 0x98, 0xe6, 0xf6, 0x76, - 0x40, 0x64, 0xeb, 0x95, 0xe2, 0xcc, 0x8b, 0x76, 0x4a, 0xab, 0x83, 0xa9, - 0x84, 0x08, 0xf7, 0x43, 0x92, 0xcb, 0x31, 0xd1, 0x0a, 0x90, 0x8b, 0x98, - 0x1d, 0x6a, 0x45, 0x7f, 0x83, 0x9b, 0x01, 0x8d, 0xe8, 0x25, 0x9e, 0x55, - 0xad, 0x27, 0x7e, 0x21, 0xfd, 0x8e, 0xc8, 0x26, 0x1f, 0x43, 0x44, 0x06, - 0x5f, 0x44, 0xbd, 0x5a, 0xf3, 0x15, 0xac, 0x1a, 0x8f, 0xc7, 0x5a, 0x40, - 0xa9, 0x93, 0x09, 0xdc, 0xc4, 0xc9, 0xe9, 0x42, 0xf0, 0xe4, 0xda, 0x29, - 0x90, 0x61, 0x32, 0xcb, 0x05, 0x74, 0x61, 0x71, 0x44, 0xbb, 0x3f, 0x99, - 0xc3, 0x25, 0x29, 0x8c, 0xa1, 0xe1, 0x92, 0xe6, 0xfd, 0x55, 0x8e, 0x22, - 0x37, 0x95, 0x08, 0x59, 0xdc, 0xa2, 0x7c, 0xfc, 0x12, 0x9a, 0x5e, 0x1a, - 0x58, 0x8a, 0x14, 0xa7, 0x96, 0xa2, 0x9e, 0x35, 0xe1, 0x1c, 0x7d, 0xac, - 0x86, 0x1e, 0xcf, 0x1a, 0x35, 0x7a, 0xf1, 0x31, 0x46, 0x67, 0xbd, 0x81, - 0x9c, 0xf5, 0x70, 0x9e, 0xaf, 0x0f, 0x84, 0x10, 0xc9, 0x46, 0xce, 0xb6, - 0xc4, 0x35, 0x88, 0xf0, 0xe1, 0xa6, 0x25, 0xa5, 0xdf, 0x4d, 0x5e, 0x10, - 0x76, 0x2c, 0xa3, 0x85, 0x42, 0x13, 0xe2, 0x34, 0x57, 0xce, 0x8a, 0x96, - 0x1f, 0x1b, 0x78, 0x87, 0xd6, 0x4d, 0x66, 0x36, 0x8e, 0x2c, 0xc6, 0x8b, - 0x0a, 0x53, 0x26, 0x70, 0xa5, 0x7e, 0x7c, 0x7f, 0x94, 0x8b, 0x89, 0x75, - 0x32, 0x1b, 0x8d, 0x27, 0x6f, 0xb1, 0x64, 0x07, 0xa1, 0xbc, 0x34, 0xe4, - 0x9b, 0xb7, 0x96, 0x4a, 0x9b, 0x96, 0xea, 0xc1, 0x4c, 0x13, 0xa8, 0x28, - 0xe3, 0x70, 0xdd, 0x68, 0x2b, 0xf8, 0xd2, 0xe7, 0x1a, 0xec, 0x34, 0xd2, - 0xce, 0x7c, 0x69, 0xc5, 0xe4, 0xde, 0x98, 0x8d, 0x1d, 0x54, 0x21, 0x12, - 0x25, 0x2d, 0xff, 0xbf, 0x1c, 0x97, 0x01, 0x25, 0x2b, 0xbe, 0xad, 0x98, - 0x4a, 0xd3, 0x19, 0x93, 0x9c, 0x03, 0xe6, 0xa4, 0xeb, 0x6c, 0x18, 0x9d, - 0xae, 0xcc, 0xc4, 0xb8, 0x24, 0x2d, 0xa0, 0xc1, 0x70, 0xa3, 0x5c, 0x2f, - 0x6e, 0xee, 0x1c, 0x66, 0x67, 0x43, 0xd8, 0x50, 0x23, 0xe8, 0xd9, 0xb8, - 0x24, 0x98, 0x3a, 0x7d, 0xcf, 0x12, 0x89, 0xae, 0x1a, 0x11, 0x26, 0xa9, - 0x80, 0xef, 0x08, 0x20, 0xf0, 0x11, 0x95, 0xfc, 0xe8, 0xfc, 0xc3, 0x4a, - 0x8b, 0x55, 0x2e, 0xf8, 0x93, 0x6c, 0xe1, 0x82, 0xcb, 0x33, 0xe6, 0xfa, - 0xa1, 0xc2, 0x1d, 0x26, 0xa1, 0x38, 0xc2, 0x12, 0x53, 0x51, 0xa0, 0xbf, - 0xa9, 0x11, 0x57, 0x18, 0x1a, 0x94, 0x28, 0xe6, 0xf6, 0x71, 0x46, 0x02, - 0xd9, 0x1e, 0x1c, 0x07, 0xf4, 0x95, 0xb9, 0xfb, 0x30, 0x79, 0xa6, 0x8a, - 0xe0, 0x0d, 0x35, 0xb6, 0xb4, 0x4f, 0xde, 0x59, 0x35, 0x7c, 0x1a, 0xf9, - 0xcc, 0x42, 0x40, 0xba, 0x58, 0x07, 0xd6, 0x10, 0x20, 0x7d, 0xa4, 0x49, - 0x17, 0x4f, 0x03, 0xa6, 0xaf, 0x30, 0xbd, 0x54, 0x6b, 0x2a, 0xc3, 0x65, - 0x98, 0x71, 0x6c, 0xcc, 0x75, 0x4e, 0xfb, 0x68, 0x14, 0x9d, 0x50, 0xe2, - 0x4f, 0x93, 0x48, 0x2c, 0xc3, 0x37, 0x6c, 0x7e, 0x6a, 0x87, 0x4f, 0x5a, - 0x01, 0xcc, 0x17, 0x54, 0xe7, 0xc0, 0x3d, 0xb3, 0xb4, 0x5f, 0xb9, 0xf1, - 0xcb, 0x5f, 0x9e, 0x48, 0xa2, 0x01, 0x82, 0xb0, 0xd9, 0x01, 0xa8, 0xf9, - 0xac, 0xbe, 0x44, 0x23, 0xb1, 0x43, 0x85, 0xe6, 0x50, 0x64, 0x80, 0xfc, - 0x62, 0xbd, 0xda, 0xef, 0x85, 0xb2, 0x70, 0x8a, 0x0d, 0x5a, 0x62, 0xda, - 0xcc, 0xb3, 0xc1, 0x3a, 0x21, 0xa0, 0x09, 0xfa, 0x64, 0x79, 0xf5, 0xa5, - 0xb6, 0x52, 0x28, 0xb5, 0x2f, 0xbd, 0x9b, 0x98, 0xae, 0x42, 0x32, 0x15, - 0xcc, 0x1a, 0x7d, 0xa6, 0xef, 0x4a, 0xf8, 0x09, 0x72, 0x3e, 0xc3, 0x69, - 0x31, 0x9f, 0x4b, 0x32, 0x73, 0x5f, 0xbf, 0x5f, 0xd5, 0xc3, 0x9f, 0x1e, - 0xcf, 0x6b, 0x0c, 0xde, 0x32, 0x57, 0x1d, 0x1d, 0xc0, 0xf8, 0xe9, 0x85, - 0x8e, 0xd0, 0xf4, 0x86, 0xad, 0xfa, 0x51, 0x07, 0xed, 0x1c, 0xb6, 0x60, - 0x8f, 0xdc, 0x72, 0x61, 0x36, 0x2e, 0x02, 0xf9, 0xe5, 0x3e, 0x14, 0x19, - 0xa5, 0x30, 0xb6, 0x2a, 0x7e, 0xf9, 0xbc, 0x95, 0x82, 0x0f, 0x1b, 0x61, - 0xa5, 0xad, 0x50, 0x38, 0xa1, 0xfe, 0xa8, 0xd0, 0x86, 0x69, 0x40, 0xb9, - 0x82, 0x21, 0xbc, 0x26, 0x9b, 0x87, 0x2f, 0xf6, 0x39, 0x9c, 0x0a, 0x71, - 0x0d, 0x54, 0x68, 0x78, 0xcc, 0x81, 0xaf, 0x09, 0xd7, 0xa2, 0x1c, 0x7a, - 0xfb, 0xfb, 0xae, 0xe0, 0x59, 0x23, 0x0b, 0x8a, 0x5a, 0x9c, 0x4c, 0x9d, - 0x17, 0xfc, 0x52, 0x66, 0x43, 0xbf, 0x06, 0x6c, 0x56, 0x3f, 0xdd, 0x8e, - 0x33, 0x2e, 0xb8, 0xd7, 0xed, 0x13, 0x44, 0x05, 0x5b, 0xbf, 0x43, 0xc7, - 0xfd, 0x6e, 0x41, 0xf4, 0xb8, 0xf0, 0x84, 0x73, 0x60, 0xe4, 0x72, 0x24, - 0x00, 0xec, 0xdf, 0x1b, 0x0d, 0x57, 0x26, 0x04, 0xa0, 0x8c, 0x25, 0x12, - 0xe0, 0xc6, 0x14, 0x0e, 0x69, 0xc2, 0xc8, 0x43, 0x53, 0xc6, 0x66, 0x50, - 0x96, 0x29, 0x50, 0x6d, 0xab, 0x02, 0x29, 0xbd, 0x17, 0xda, 0xd4, 0x5b, - 0xbe, 0xb1, 0xe8, 0x9a, 0x32, 0x3f, 0x39, 0x12, 0x4b, 0x02, 0xb7, 0x8f, - 0x64, 0xca, 0x24, 0x43, 0x2b, 0xee, 0x04, 0xbb, 0xbd, 0x2b, 0x9f, 0x1c, - 0x66, 0xe0, 0x6a, 0xa5, 0xd4, 0x0e, 0x3f, 0x5e, 0xad, 0xe5, 0xc4, 0xcd, - 0x17, 0x71, 0x57, 0x62, 0xe6, 0x7d, 0xe1, 0xc1, 0xd8, 0x3e, 0x38, 0x30, - 0x31, 0x49, 0xb0, 0x8d, 0x64, 0x80, 0x55, 0x30, 0xc4, 0x38, 0x22, 0xad, - 0xc7, 0x8f, 0x1a, 0xbd, 0x30, 0xf8, 0x29, 0xcc, 0xdc, 0x16, 0x6e, 0xf4, - 0x2d, 0xc4, 0x04, 0x49, 0x9a, 0x20, 0xf3, 0x9a, 0xd9, 0xab, 0x31, 0xe4, - 0xb4, 0x0a, 0xce, 0x4e, 0xff, 0xdd, 0xe0, 0x75, 0x59, 0xe5, 0x40, 0x2d, - 0xb5, 0xba, 0xae, 0x73, 0x91, 0x32, 0xba, 0x0d, 0xf3, 0x4a, 0x38, 0xa3, - 0x0c, 0x11, 0xd2, 0x6c, 0x75, 0x80, 0x7a, 0xe4, 0xd5, 0x98, 0x47, 0x05, - 0x66, 0x6c, 0x2e, 0x9d, 0x96, 0xad, 0x99, 0x30, 0xdf, 0xc2, 0x54, 0x5a, - 0x4d, 0xc3, 0x21, 0x80, 0x52, 0xb7, 0x21, 0xa8, 0xb3, 0xd6, 0xe6, 0xf2, - 0xaf, 0xd3, 0x49, 0x3e, 0xff, 0xb2, 0xc2, 0xc9, 0x8b, 0xba, 0x63, 0x6c, - 0xf8, 0x8c, 0x39, 0x16, 0x52, 0x59, 0x86, 0x20, 0x50, 0x3a, 0xe6, 0x0f, - 0x41, 0x13, 0x68, 0xe7, 0x0f, 0x16, 0x58, 0x38, 0xff, 0xb6, 0x26, 0x69, - 0x41, 0x07, 0xeb, 0x21, 0x45, 0xaa, 0xed, 0xae, 0xea, 0xf6, 0xda, 0x00, - 0x72, 0x30, 0x82, 0x02, 0xc1, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x02, 0xb2, 0x04, 0x82, 0x02, 0xae, - 0x30, 0x82, 0x02, 0xaa, 0x30, 0x82, 0x01, 0x51, 0x06, 0x0b, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x81, 0xbc, - 0x30, 0x81, 0xb9, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0x3a, 0xe1, 0x16, - 0x95, 0xa1, 0x45, 0x12, 0xa2, 0x02, 0x02, 0x08, 0x00, 0x04, 0x81, 0x98, - 0x56, 0x4a, 0x5a, 0xd4, 0xf6, 0x2f, 0x5d, 0x91, 0x3d, 0xed, 0x38, 0x21, - 0x90, 0x2a, 0xe1, 0x2d, 0x6e, 0xb5, 0x1c, 0xd9, 0xb0, 0x88, 0xcf, 0xb9, - 0xc7, 0x3a, 0x2b, 0x21, 0xc3, 0xf6, 0x51, 0x91, 0x0c, 0xfb, 0x29, 0x84, - 0xd1, 0x62, 0x5f, 0x75, 0xee, 0xe6, 0xb0, 0x83, 0x4b, 0x9e, 0x55, 0x7b, - 0xdd, 0xd3, 0x9c, 0x36, 0x1f, 0xe8, 0x0a, 0x23, 0x4e, 0x5d, 0xde, 0x11, - 0x71, 0x26, 0xfd, 0x8d, 0x5b, 0xa8, 0x9e, 0x19, 0x2d, 0xbc, 0x2c, 0x75, - 0xfa, 0x0b, 0xa2, 0x4c, 0xe5, 0x07, 0xed, 0x6b, 0x95, 0x3d, 0x75, 0x12, - 0xb2, 0xec, 0xc5, 0x20, 0x5e, 0xfb, 0x5c, 0x0b, 0x68, 0x35, 0x1f, 0xdf, - 0xe0, 0xaa, 0xd5, 0x93, 0x27, 0x3e, 0xa2, 0xed, 0x3f, 0x6d, 0x2c, 0xc0, - 0x6f, 0x55, 0xf0, 0x21, 0xa6, 0xfa, 0x79, 0xce, 0xc5, 0xd6, 0x39, 0xa6, - 0x04, 0xa8, 0x4a, 0xa6, 0x95, 0xf0, 0x7e, 0xe7, 0x54, 0xee, 0xb2, 0x88, - 0xe2, 0x66, 0x5c, 0xb8, 0x5d, 0x3b, 0x90, 0x32, 0x6a, 0xfb, 0x3e, 0xa3, - 0x8b, 0x6b, 0x96, 0xf6, 0x42, 0x55, 0xb3, 0x9f, 0x31, 0x81, 0x82, 0x30, - 0x5b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x14, - 0x31, 0x4e, 0x1e, 0x4c, 0x00, 0x4d, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, - 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, - 0x00, 0x74, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, - 0x00, 0x6e, 0x00, 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x53, - 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, - 0x00, 0x49, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x69, - 0x00, 0x74, 0x00, 0x79, 0x00, 0x31, 0x00, 0x00, 0x30, 0x23, 0x06, 0x09, - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, - 0x14, 0xf8, 0x15, 0x2d, 0x15, 0x6b, 0x7d, 0x28, 0xe8, 0x23, 0x88, 0xbf, - 0xba, 0xa2, 0x3a, 0x3e, 0x9a, 0x03, 0xe6, 0xc6, 0x89, 0x30, 0x82, 0x01, - 0x51, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, - 0x01, 0x02, 0xa0, 0x81, 0xbc, 0x30, 0x81, 0xb9, 0x30, 0x1c, 0x06, 0x0a, - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, - 0x04, 0x08, 0xe3, 0xef, 0x16, 0x96, 0x45, 0x16, 0xe5, 0xb3, 0x02, 0x02, - 0x08, 0x00, 0x04, 0x81, 0x98, 0xf0, 0x1d, 0x35, 0x91, 0xfc, 0x16, 0x43, - 0xaa, 0x1d, 0xb0, 0x58, 0x12, 0xde, 0x69, 0x92, 0xd0, 0xac, 0x96, 0xbe, - 0xc7, 0xbb, 0xb8, 0xb2, 0x44, 0x4e, 0x17, 0xd1, 0xb5, 0xfb, 0x36, 0xea, - 0xd7, 0x06, 0x3a, 0x0e, 0x9a, 0xaa, 0x23, 0xfa, 0x70, 0x51, 0xb9, 0xf9, - 0x90, 0x78, 0xbc, 0xb3, 0x63, 0x48, 0x8c, 0x84, 0xb2, 0xa2, 0x98, 0xc9, - 0x71, 0x46, 0x82, 0x42, 0x9f, 0x0f, 0x7b, 0xcc, 0xbe, 0xcc, 0xad, 0x3c, - 0x30, 0xdb, 0x1d, 0x34, 0xcc, 0x89, 0x91, 0x6b, 0xee, 0x2f, 0x9c, 0x75, - 0x8b, 0x55, 0xff, 0x2e, 0x0b, 0x1d, 0x71, 0x5e, 0xb1, 0xa2, 0xb2, 0x5e, - 0x7e, 0x48, 0x37, 0x2f, 0x08, 0x67, 0x91, 0x9a, 0xf1, 0x05, 0x1c, 0x7a, - 0x7f, 0xee, 0x6f, 0x1e, 0x5b, 0xd9, 0x7c, 0x2d, 0xb8, 0x09, 0x72, 0xb6, - 0x5a, 0xbf, 0x9a, 0xd7, 0x23, 0x39, 0x6f, 0x1f, 0xf8, 0xd5, 0x72, 0x49, - 0xea, 0xab, 0x4b, 0xa0, 0xcb, 0xa3, 0xc7, 0xef, 0xb8, 0x8c, 0xda, 0x4c, - 0x0a, 0x8f, 0xeb, 0x7f, 0x8f, 0x42, 0xd4, 0xad, 0x45, 0x72, 0xda, 0xd9, - 0xc4, 0x31, 0x81, 0x82, 0x30, 0x5b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31, 0x4e, 0x1e, 0x4c, 0x00, 0x4d, 0x00, - 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, - 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x63, 0x00, - 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x54, 0x00, 0x65, 0x00, - 0x73, 0x00, 0x74, 0x00, 0x53, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, - 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x49, 0x00, 0x64, 0x00, 0x65, 0x00, - 0x6e, 0x00, 0x74, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, 0x31, 0x00, - 0x00, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0xf8, 0x15, 0x2d, 0x15, 0x6b, 0x7d, - 0x28, 0xe8, 0x23, 0x88, 0xbf, 0xba, 0xa2, 0x3a, 0x3e, 0x9a, 0x03, 0xe6, - 0xc6, 0x89, 0x30, 0x30, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, - 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x06, 0xfc, 0xc7, 0x98, 0xaf, - 0x81, 0x75, 0x9f, 0x25, 0x05, 0x0c, 0x6d, 0x78, 0xac, 0x4b, 0x31, 0x23, - 0x6c, 0x9b, 0x4d, 0x04, 0x08, 0xf5, 0x1e, 0x85, 0xf5, 0x54, 0xf6, 0x09, - 0x53, 0x02, 0x01, 0x01 -}; -unsigned int ECDSA_fails_import_p12_len = 2044; - -unsigned char ECDSA_fails_import_priv_only[] = { - 0x30, 0x25, 0x02, 0x01, 0x01, 0x04, 0x20, 0x79, 0xf4, 0x38, 0x5c, 0x35, - 0xe1, 0x97, 0xbf, 0xc7, 0x39, 0xc1, 0x2e, 0x40, 0x52, 0x9f, 0xd1, 0xf0, - 0x13, 0xa6, 0x94, 0xc5, 0xdc, 0x3b, 0x14, 0x5b, 0x08, 0x11, 0x28, 0xc5, - 0xb6, 0xc4, 0xd7 -}; -unsigned int ECDSA_fails_import_priv_only_len = 39; - -/* P521 certificate with passcode test!123 */ -unsigned char ec521_host_pfx[] = { - 0x30, 0x82, 0x05, 0x78, 0x02, 0x01, 0x03, 0x30, 0x82, 0x05, 0x3e, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, - 0x05, 0x2f, 0x04, 0x82, 0x05, 0x2b, 0x30, 0x82, 0x05, 0x27, 0x30, 0x82, - 0x03, 0xaf, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, - 0x06, 0xa0, 0x82, 0x03, 0xa0, 0x30, 0x82, 0x03, 0x9c, 0x02, 0x01, 0x00, - 0x30, 0x82, 0x03, 0x95, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x6d, 0x27, 0xf1, - 0xd2, 0xe2, 0x19, 0xd9, 0xf2, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x03, - 0x68, 0x50, 0x87, 0xe5, 0xec, 0x26, 0x69, 0xcd, 0xa8, 0xd8, 0xd7, 0x0f, - 0x5b, 0x31, 0xc6, 0xfa, 0x0f, 0x3c, 0x62, 0x47, 0x41, 0xbe, 0x13, 0xab, - 0x0a, 0x53, 0x61, 0xe5, 0x0c, 0x61, 0xc3, 0x0b, 0xd3, 0x64, 0xce, 0xe7, - 0x0e, 0xa6, 0x34, 0xaa, 0xd6, 0x8d, 0x8e, 0xa8, 0x6f, 0xc1, 0xc5, 0xd5, - 0x4f, 0xa1, 0x44, 0xfb, 0x64, 0x5f, 0x21, 0xad, 0x80, 0x4f, 0x74, 0x50, - 0x90, 0x6c, 0x16, 0xeb, 0x0a, 0x98, 0xa1, 0x71, 0x2d, 0x4c, 0x60, 0xf4, - 0x68, 0x1b, 0x4f, 0x89, 0x74, 0xfb, 0xda, 0xdf, 0x73, 0xf6, 0x09, 0x76, - 0x34, 0x7c, 0x25, 0x2f, 0x5e, 0xc2, 0x81, 0xdc, 0x35, 0x08, 0x28, 0xb8, - 0x84, 0x9b, 0x3b, 0x31, 0x52, 0x99, 0x13, 0xf4, 0x79, 0x2d, 0xc5, 0x61, - 0x7e, 0x8b, 0x55, 0x70, 0x37, 0xf9, 0xc1, 0xc5, 0xa8, 0xc6, 0xd6, 0x4b, - 0x01, 0xa7, 0x99, 0x4a, 0xe2, 0xcc, 0xa3, 0xa6, 0xea, 0x4b, 0xb2, 0x21, - 0x08, 0x3b, 0xdf, 0x49, 0xb6, 0x95, 0xcf, 0xca, 0xed, 0xd8, 0x59, 0x8c, - 0x5d, 0xef, 0xec, 0xe9, 0x7f, 0xc0, 0xca, 0xea, 0x0c, 0xee, 0x22, 0x91, - 0x35, 0x69, 0x36, 0xa2, 0x1d, 0x77, 0x74, 0xae, 0xc0, 0x96, 0xbe, 0x7d, - 0x60, 0x96, 0x71, 0xd4, 0x83, 0x29, 0xfc, 0xb2, 0x62, 0x85, 0x1e, 0x18, - 0x15, 0xa3, 0xf2, 0x97, 0xdb, 0xf5, 0x48, 0xd6, 0x2b, 0xcd, 0x36, 0x3f, - 0x96, 0x0e, 0xea, 0x3f, 0x4a, 0x2e, 0x13, 0x19, 0xa9, 0xc6, 0x34, 0x03, - 0xb8, 0x67, 0xd8, 0x39, 0x6b, 0x26, 0xa2, 0x2e, 0x5a, 0x1e, 0x32, 0x8e, - 0x92, 0xe8, 0x26, 0xd5, 0x41, 0x6a, 0x5f, 0x14, 0x57, 0x7d, 0x6e, 0xc6, - 0xbd, 0xec, 0xc1, 0x1c, 0x54, 0x86, 0x9a, 0xde, 0x26, 0x71, 0x22, 0xc8, - 0xa4, 0x48, 0x38, 0x24, 0x5c, 0xd5, 0x45, 0x5a, 0x68, 0x91, 0x1e, 0x7f, - 0xd8, 0x2f, 0xf2, 0x0f, 0x07, 0x4e, 0xe2, 0xd3, 0xea, 0x57, 0xd1, 0xcc, - 0xd8, 0x0c, 0x3f, 0x5f, 0xf4, 0x27, 0xd0, 0xc6, 0x5f, 0x78, 0x7d, 0x26, - 0xc4, 0x0d, 0x33, 0x0f, 0xac, 0xe2, 0xa6, 0xf7, 0x98, 0x08, 0xa5, 0xe7, - 0x85, 0x95, 0x2d, 0xa8, 0x65, 0x0c, 0x80, 0xfe, 0x44, 0x8c, 0xff, 0x57, - 0xd3, 0x2d, 0x09, 0xbf, 0x41, 0x93, 0xea, 0x1d, 0xd7, 0xbd, 0xb8, 0xb1, - 0x9d, 0x08, 0x1e, 0x4f, 0xae, 0x15, 0xf9, 0x2e, 0xfc, 0xfc, 0x2f, 0x0f, - 0xe1, 0x44, 0xfb, 0xac, 0x02, 0xb9, 0x58, 0x65, 0x6c, 0x7a, 0x96, 0xad, - 0x98, 0xda, 0xaf, 0xf9, 0x99, 0x22, 0x83, 0xfe, 0x53, 0x1e, 0x96, 0xae, - 0x5c, 0x89, 0x61, 0x68, 0x46, 0x7b, 0x15, 0x3b, 0x9e, 0xd8, 0xee, 0x29, - 0xe6, 0x9b, 0xd1, 0x16, 0x9f, 0xcd, 0xf7, 0x09, 0x8c, 0xd5, 0x9e, 0xea, - 0x6c, 0x63, 0x31, 0x5b, 0xbd, 0x1d, 0x73, 0xca, 0x88, 0x25, 0xa2, 0x74, - 0x61, 0x78, 0x9a, 0x30, 0x65, 0x1c, 0x8d, 0x8f, 0xb0, 0x33, 0xd6, 0xf4, - 0x25, 0xa1, 0x84, 0xe8, 0x16, 0x29, 0x74, 0x11, 0x75, 0x67, 0xac, 0xaa, - 0xd0, 0x26, 0xfd, 0x67, 0xb5, 0x45, 0x4a, 0xc0, 0x73, 0xeb, 0x73, 0x6e, - 0x73, 0xa1, 0xca, 0x66, 0x45, 0x92, 0xdf, 0x1d, 0xc2, 0xf2, 0x9e, 0x8f, - 0x7f, 0x0e, 0x24, 0x6a, 0xb3, 0xcf, 0xe8, 0x02, 0xcc, 0xdc, 0x61, 0xd2, - 0x34, 0x49, 0x3e, 0xb4, 0x15, 0x9a, 0x68, 0x1b, 0xd5, 0x08, 0x83, 0x98, - 0xe5, 0xae, 0xad, 0xe1, 0x0d, 0x19, 0x24, 0x46, 0xda, 0x4b, 0xa4, 0xf7, - 0x5f, 0x9c, 0x07, 0xc7, 0x89, 0x90, 0xa8, 0x8d, 0x95, 0x28, 0xdc, 0x47, - 0xbd, 0x0d, 0x2b, 0x8f, 0x7f, 0xed, 0x20, 0xdd, 0x68, 0xc1, 0x63, 0x3d, - 0x8d, 0x78, 0x3c, 0xab, 0x91, 0xd3, 0x94, 0x84, 0x4d, 0x4d, 0xf8, 0x56, - 0xdb, 0x73, 0x73, 0xe3, 0x79, 0xb1, 0xbc, 0x06, 0x98, 0x03, 0x50, 0xb6, - 0xbc, 0x8f, 0x89, 0x8c, 0xdb, 0x74, 0xa2, 0x55, 0xc8, 0x61, 0xaf, 0x04, - 0xc7, 0x8b, 0x57, 0xa9, 0x63, 0x60, 0xe5, 0x0b, 0x94, 0x46, 0x15, 0xdb, - 0xa0, 0x35, 0x2d, 0x69, 0x3f, 0x20, 0x9c, 0x65, 0x1e, 0x63, 0xb2, 0xd2, - 0xf2, 0x03, 0xf3, 0x49, 0x4b, 0x8c, 0xc1, 0x13, 0x1e, 0x10, 0x31, 0xb5, - 0xdb, 0xaf, 0xc3, 0x60, 0x18, 0xb1, 0xfd, 0x08, 0x23, 0x47, 0xcc, 0x0b, - 0x55, 0x7f, 0x92, 0x2b, 0xc2, 0xed, 0xbd, 0x0b, 0x59, 0x24, 0xff, 0x1c, - 0xdf, 0xd7, 0x50, 0x2b, 0xc1, 0x1e, 0x48, 0xc1, 0xfd, 0x58, 0x79, 0x18, - 0x11, 0x00, 0x0c, 0xc7, 0x85, 0x00, 0xe9, 0x6d, 0x52, 0x4d, 0xfa, 0x80, - 0x71, 0x68, 0xc7, 0xa7, 0xd5, 0x9d, 0x25, 0x75, 0x3a, 0x64, 0x95, 0x72, - 0x5b, 0x8e, 0xad, 0x7b, 0x9b, 0xcb, 0x32, 0x3e, 0xfb, 0xc0, 0x4e, 0x9b, - 0x17, 0xf7, 0x7e, 0xec, 0xa0, 0x60, 0xbc, 0x5a, 0xed, 0xfb, 0x7e, 0x7b, - 0x77, 0xa3, 0xdb, 0xba, 0x40, 0x02, 0x45, 0x33, 0xcf, 0x2f, 0xd0, 0x79, - 0x56, 0x99, 0xc7, 0x1a, 0x58, 0xcd, 0x0e, 0x5a, 0x84, 0x89, 0xce, 0xc0, - 0x7b, 0xd1, 0x62, 0x6d, 0x11, 0x1d, 0x1f, 0x7a, 0xdf, 0xc8, 0x2d, 0x77, - 0xb7, 0x61, 0x86, 0x5e, 0xd7, 0x6a, 0xe2, 0xec, 0x88, 0xf7, 0x1a, 0xc4, - 0x75, 0x09, 0x12, 0xa7, 0x21, 0x2f, 0xee, 0x5d, 0x2a, 0xd6, 0x84, 0xcd, - 0xf1, 0x2d, 0x2b, 0x11, 0x33, 0xb7, 0xfe, 0x6d, 0x4a, 0xe2, 0x4e, 0x6a, - 0x5e, 0xc6, 0x25, 0xde, 0x77, 0x98, 0x32, 0x62, 0xd1, 0xd2, 0x89, 0xfe, - 0xa4, 0x86, 0x65, 0xd9, 0x70, 0x5d, 0x3d, 0xfa, 0x42, 0xcb, 0xec, 0xe3, - 0xa5, 0x95, 0x6d, 0xa2, 0x66, 0x81, 0x87, 0x0c, 0x90, 0x76, 0x8f, 0xfe, - 0x55, 0xa9, 0x98, 0x8a, 0xfd, 0xc4, 0xd1, 0xfe, 0x72, 0xbc, 0x31, 0x71, - 0x8e, 0xd6, 0x87, 0x93, 0x57, 0xc2, 0x62, 0x66, 0x2e, 0x4f, 0xbe, 0x5f, - 0xc9, 0x22, 0x15, 0x85, 0xd8, 0xaf, 0x75, 0x57, 0x5d, 0xeb, 0xe3, 0x6e, - 0xe6, 0x69, 0x16, 0x45, 0xb2, 0xab, 0xfc, 0xf4, 0x4b, 0x86, 0x3d, 0x13, - 0x71, 0x33, 0xfd, 0xe2, 0x29, 0x7f, 0xdc, 0x2c, 0x2f, 0xed, 0xc9, 0x90, - 0x1e, 0x55, 0x08, 0x91, 0x55, 0x64, 0x8a, 0xc9, 0x6f, 0x33, 0x00, 0x98, - 0xab, 0x1d, 0xa8, 0xd2, 0x24, 0x2a, 0xaa, 0xd5, 0x20, 0x04, 0x69, 0xec, - 0x37, 0xb0, 0x44, 0x0c, 0x00, 0x2e, 0x27, 0x2e, 0x8c, 0xab, 0x20, 0x06, - 0x9d, 0x8a, 0x11, 0x8f, 0x05, 0x54, 0x5f, 0x16, 0x62, 0xb4, 0x8b, 0xec, - 0x88, 0x6f, 0xb0, 0xf1, 0x4f, 0x90, 0x23, 0x71, 0xfb, 0x30, 0x82, 0x01, - 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, - 0xa0, 0x82, 0x01, 0x61, 0x04, 0x82, 0x01, 0x5d, 0x30, 0x82, 0x01, 0x59, - 0x30, 0x82, 0x01, 0x55, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, - 0x19, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0xc2, 0xb9, 0xa1, 0x2f, 0x4c, - 0x19, 0x68, 0x12, 0x02, 0x02, 0x08, 0x00, 0x04, 0x81, 0xf8, 0x34, 0x0f, - 0x2b, 0x67, 0x09, 0xbf, 0xc4, 0xf9, 0x91, 0x76, 0xe3, 0xf2, 0x0e, 0x23, - 0x56, 0x57, 0x30, 0x30, 0x7e, 0x1a, 0x60, 0x7a, 0xd3, 0x57, 0x51, 0xf0, - 0x67, 0x83, 0xde, 0xf0, 0x6b, 0x1a, 0x7c, 0xd9, 0xd4, 0x48, 0xe6, 0xa0, - 0x7f, 0xde, 0xe3, 0xd4, 0x55, 0xcb, 0x0d, 0xcf, 0x8b, 0x21, 0x0d, 0xfa, - 0x65, 0xa1, 0xcb, 0x01, 0x6f, 0x81, 0xd4, 0x0d, 0x1c, 0xbd, 0xa6, 0x4b, - 0xbd, 0x6c, 0xe9, 0xa3, 0x6f, 0xb4, 0x4d, 0x07, 0xc1, 0x19, 0xa3, 0x14, - 0xcd, 0x39, 0xda, 0xd0, 0xa0, 0x2a, 0x62, 0x19, 0x87, 0xb6, 0x7b, 0xe6, - 0xd4, 0xd5, 0x7a, 0x70, 0xe8, 0x37, 0x98, 0xb5, 0xfe, 0xe5, 0xcf, 0x7f, - 0xb1, 0xbe, 0x00, 0x27, 0x83, 0xad, 0xfc, 0x46, 0x64, 0x91, 0xe4, 0x4c, - 0x6f, 0x91, 0xb8, 0xc4, 0xf4, 0x8d, 0x1b, 0x31, 0xdb, 0x51, 0xba, 0xc5, - 0x9c, 0xb0, 0x46, 0xf5, 0x33, 0x01, 0xc4, 0xf7, 0x27, 0x1e, 0x46, 0x79, - 0xa6, 0x76, 0x87, 0x19, 0xa8, 0xb9, 0x06, 0x5a, 0x6f, 0xd4, 0x1b, 0x25, - 0xd8, 0x75, 0x3e, 0x3a, 0x47, 0xde, 0x56, 0x58, 0xd4, 0xf1, 0x21, 0xe4, - 0x1b, 0xdc, 0xaa, 0x82, 0x40, 0xf3, 0x50, 0x3a, 0x9c, 0xb3, 0x93, 0x95, - 0xa7, 0x41, 0xfc, 0x94, 0x41, 0x68, 0x27, 0x20, 0x22, 0x2f, 0x24, 0xb3, - 0xae, 0x71, 0x65, 0x3b, 0x9b, 0xb2, 0x69, 0x95, 0xbb, 0xf5, 0xb6, 0x89, - 0x10, 0xfc, 0x0c, 0xba, 0x43, 0x16, 0x28, 0x4a, 0x69, 0x3c, 0x75, 0xdc, - 0x7f, 0x95, 0x22, 0x00, 0x51, 0xbe, 0x68, 0x07, 0xf6, 0xb4, 0x00, 0x18, - 0xac, 0x6d, 0x6d, 0xc9, 0xd9, 0x66, 0xa6, 0xe3, 0x08, 0x5b, 0x54, 0x37, - 0xe0, 0x79, 0xcd, 0xa5, 0x23, 0x1a, 0x9a, 0xdd, 0xf1, 0xdf, 0x97, 0xbf, - 0xbe, 0xe0, 0x53, 0x80, 0x0e, 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, - 0x14, 0x11, 0xda, 0xbc, 0x66, 0xab, 0x86, 0x80, 0xe5, 0x49, 0x74, 0x47, - 0xda, 0x5a, 0x84, 0x31, 0x69, 0x0a, 0x49, 0xa3, 0x66, 0x30, 0x31, 0x30, - 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, - 0x04, 0x14, 0xa5, 0x4e, 0x8d, 0x67, 0x01, 0x9f, 0x1b, 0x55, 0x63, 0x54, - 0xa7, 0x09, 0x7c, 0x1a, 0x76, 0x48, 0xcd, 0x14, 0x84, 0xc8, 0x04, 0x08, - 0xbd, 0x08, 0x86, 0x2c, 0xe9, 0x77, 0xab, 0xaf, 0x02, 0x02, 0x08, 0x00 -}; +#include "shared_regressions.h" +#include "si-61-pkcs12.h" + +#if TARGET_OS_OSX +static void delete_identity(SecCertificateRef cert, SecKeyRef pkey) { + CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(query, kSecClass, kSecClassCertificate); + CFDictionaryAddValue(query, kSecValueRef, cert); + SecItemDelete(query); + + CFDictionaryRemoveAllValues(query); + CFDictionaryAddValue(query, kSecClass, kSecClassKey); + CFDictionaryAddValue(query, kSecValueRef, pkey); + SecItemDelete(query); + CFReleaseNull(query); +} +#endif static void tests(void) @@ -660,8 +69,13 @@ static void tests(void) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnonnull" // Disable compile-time nullability checks, otherwise the code below won't compile. +#if TARGET_OS_IPHONE is_status(SecPKCS12Import(message, NULL, NULL), errSecAuthFailed, "try null password on a known good p12"); +#else + is_status(SecPKCS12Import(message, NULL, NULL), errSecPassphraseRequired, + "try null password on a known good p12"); +#endif #pragma clang diagnostic pop CFStringRef password = CFSTR("user-one"); @@ -681,6 +95,12 @@ static void tests(void) ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key"); ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate"); +#if TARGET_OS_OSX + /* We need to delete the identity from the keychain because SecPKCS12Import imports to the + * keychain on macOS. */ + delete_identity(cert, pkey); +#endif + CFReleaseNull(items); CFReleaseNull(message); CFReleaseNull(options); @@ -707,6 +127,11 @@ static void tests(void) ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key"); ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate"); +#if TARGET_OS_OSX + delete_identity(cert, pkey); +#endif + + CFReleaseNull(items); CFReleaseNull(message); CFReleaseNull(options); @@ -727,7 +152,11 @@ static void tests(void) &kCFTypeDictionaryValueCallBacks); ok_status(SecPKCS12Import(message, options, &items), "import ECDSA_fails_import_p12"); +#if TARGET_OS_OSX + is(CFArrayGetCount(items), 2, "two identities"); //macOS implementation doesn't dedup +#else is(CFArrayGetCount(items), 1, "one identity"); +#endif item = CFArrayGetValueAtIndex(items, 0); ok(identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity), "pull identity from imported data"); @@ -735,28 +164,30 @@ static void tests(void) ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key"); ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate"); - CFDataRef pubdata = NULL; SecKeyRef pubkey = NULL; - - ok_status(SecKeyCopyPublicBytes(pkey, &pubdata), "pub key from priv key"); - ok(pubkey = SecKeyCreateECPublicKey(kCFAllocatorDefault, - CFDataGetBytePtr(pubdata), CFDataGetLength(pubdata), kSecKeyEncodingBytes), - "recreate seckey"); +#if TARGET_OS_OSX + ok_status(SecCertificateCopyPublicKey(cert, &pubkey), "get public key from cert"); +#else + ok(pubkey = SecKeyCopyPublicKey(pkey), "get public key from private key"); +#endif + CFReleaseNull(message); /* Sign something. */ uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, }; - size_t sigLen = SecKeyGetSize(pkey, kSecKeySignatureSize); - uint8_t sig[sigLen]; - ok_status(SecKeyRawSign(pkey, kSecPaddingPKCS1, - something, sizeof(something), sig, &sigLen), "sign something"); - ok_status(SecKeyRawVerify(pubkey, kSecPaddingPKCS1, - something, sizeof(something), sig, sigLen), "verify sig on something"); + message = CFDataCreateWithBytesNoCopy(NULL, something, sizeof(something), kCFAllocatorNull); + CFDataRef signature = NULL; + CFErrorRef error = NULL; + ok(signature = SecKeyCreateSignature(pkey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, message, NULL), "sign something"); + ok(SecKeyVerifySignature(pubkey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, message, signature, NULL), "verify sig on something"); +#if TARGET_OS_OSX + delete_identity(cert, pkey); +#endif - CFReleaseNull(pubdata); CFReleaseNull(pubkey); CFReleaseNull(pkey); + CFDataRef pubdata = NULL; ok(pkey = SecKeyCreateECPrivateKey(kCFAllocatorDefault, ECDSA_fails_import_priv_only, ECDSA_fails_import_priv_only_len, kSecKeyEncodingPkcs1), "import privkey without pub"); @@ -764,12 +195,12 @@ static void tests(void) ok(pubkey = SecKeyCreateECPublicKey(kCFAllocatorDefault, CFDataGetBytePtr(pubdata), CFDataGetLength(pubdata), kSecKeyEncodingBytes), "recreate seckey"); - ok_status(SecKeyRawVerify(pubkey, kSecPaddingPKCS1, - something, sizeof(something), sig, sigLen), "verify sig on something"); + ok(SecKeyVerifySignature(pubkey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, message, signature, &error), "verify sig on something"); CFReleaseNull(pubdata); CFReleaseNull(pubkey); CFReleaseNull(pkey); + CFReleaseNull(signature); CFReleaseNull(items); CFReleaseNull(message); CFReleaseNull(options); @@ -787,17 +218,53 @@ static void tests(void) &kCFTypeDictionaryValueCallBacks); ok_status(SecPKCS12Import(cert_p521_p12, options_p521, &items), "Import p512 PKCS12 cert"); is(CFArrayGetCount(items), 1, "one identity"); + item = CFArrayGetValueAtIndex(items, 0); + ok(identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity), "pull identity from imported data"); + + ok(CFGetTypeID(identity)==SecIdentityGetTypeID(),"this is a SecIdentityRef"); + ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key"); + ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate"); + + +#if TARGET_OS_OSX + delete_identity(cert, pkey); +#endif + CFReleaseNull(items); CFReleaseNull(cert_p521_p12); CFReleaseNull(password_p521); CFReleaseNull(options_p521); + CFReleaseNull(pkey); + CFReleaseNull(cert); +} + +static void test_cert_decode_error() { + CFDataRef message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, _cert_decode_error_p12, + sizeof(_cert_decode_error_p12), kCFAllocatorNull); + CFArrayRef items = NULL; + CFStringRef password = CFSTR("1234"); + CFDictionaryRef options = CFDictionaryCreate(NULL, + (const void **)&kSecImportExportPassphrase, + (const void **)&password, 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); +#if TARGET_OS_IPHONE + is(SecPKCS12Import(message, options, &items), errSecDecode, "import cert decode failure p12"); +#else + is(SecPKCS12Import(message, options, &items), errSecUnknownFormat, "import cert decode failure p12"); +#endif + CFReleaseNull(message); + CFReleaseNull(items); + CFReleaseNull(options); + } int si_61_pkcs12(int argc, char *const *argv) { - plan_tests(29); + plan_tests(33); tests(); + test_cert_decode_error(); return 0; } diff --git a/OSX/sec/Security/Regressions/secitem/si-61-pkcs12.h b/OSX/sec/Security/Regressions/secitem/si-61-pkcs12.h new file mode 100644 index 00000000..4dd0ef83 --- /dev/null +++ b/OSX/sec/Security/Regressions/secitem/si-61-pkcs12.h @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + */ + +#ifndef si_61_pkcs12_h +#define si_61_pkcs12_h + +unsigned char _user_one_p12[] = { + 0x30, 0x82, 0x0a, 0x61, 0x02, 0x01, 0x03, 0x30, 0x82, 0x0a, 0x27, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x0a, 0x18, 0x04, 0x82, 0x0a, 0x14, 0x30, 0x82, + 0x0a, 0x10, 0x30, 0x82, 0x04, 0xc7, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x06, 0xa0, 0x82, 0x04, 0xb8, 0x30, 0x82, 0x04, 0xb4, 0x02, 0x01, 0x00, 0x30, 0x82, 0x04, 0xad, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x09, 0x7a, 0xe8, + 0x65, 0xdb, 0xcd, 0xc8, 0x49, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x04, 0x80, 0xd1, 0x3a, 0x9d, + 0x13, 0x26, 0x70, 0x75, 0x7a, 0xe0, 0x47, 0xff, 0x87, 0x63, 0xba, 0xfc, 0xeb, 0xc2, 0x51, 0x29, + 0xca, 0xed, 0xb3, 0x24, 0x35, 0x48, 0x74, 0xd8, 0xa1, 0x01, 0xdf, 0xf5, 0x56, 0xbf, 0x14, 0xe6, + 0x85, 0x71, 0xde, 0x57, 0xe3, 0x2f, 0x0e, 0x25, 0x93, 0xb4, 0xed, 0x30, 0xc2, 0xb4, 0xf1, 0x45, + 0x82, 0x88, 0x27, 0xba, 0xf0, 0x66, 0x1a, 0x6b, 0xda, 0xe2, 0xe6, 0x1b, 0x9b, 0x26, 0xf4, 0x21, + 0xed, 0xd1, 0xd0, 0xd3, 0x58, 0x0a, 0xdb, 0x0e, 0xbd, 0x5e, 0x89, 0x6a, 0xa3, 0x7c, 0x0a, 0x0f, + 0x83, 0x21, 0xc9, 0xbb, 0x66, 0x3d, 0x0c, 0xa6, 0x4d, 0xac, 0xa2, 0x67, 0x6b, 0x30, 0x70, 0x79, + 0xbf, 0xab, 0x14, 0x37, 0x00, 0x2c, 0x40, 0xe0, 0x19, 0xf7, 0x77, 0xa8, 0x00, 0x2d, 0x13, 0x3f, + 0xb9, 0x61, 0xae, 0xe3, 0x3e, 0x9e, 0x2c, 0x70, 0x54, 0x87, 0x05, 0x3c, 0x75, 0x9b, 0xc3, 0x6d, + 0x65, 0x27, 0x18, 0x37, 0xf2, 0xd7, 0xe3, 0x50, 0xf9, 0x74, 0x14, 0x72, 0xcb, 0x0c, 0x0a, 0xdb, + 0x70, 0xac, 0xa9, 0x6c, 0xf5, 0xc2, 0xc2, 0x6c, 0xcc, 0x7e, 0x64, 0xd3, 0x6a, 0xab, 0x7e, 0x36, + 0xe6, 0x0d, 0xe5, 0xaf, 0x2f, 0x3d, 0x84, 0x64, 0xb3, 0x5d, 0x0e, 0xaf, 0x35, 0xb5, 0x8c, 0xdf, + 0x86, 0x76, 0x8a, 0xc8, 0x74, 0xb7, 0xea, 0xff, 0x3a, 0x11, 0x2b, 0xda, 0x9e, 0x18, 0x7d, 0x54, + 0x43, 0xe4, 0x48, 0x5b, 0x52, 0xa3, 0xa9, 0x1e, 0xc0, 0x79, 0xf2, 0x6c, 0xa0, 0x1d, 0xf1, 0x45, + 0x02, 0x7d, 0xa0, 0xc6, 0x4a, 0x98, 0xc7, 0xc4, 0xef, 0xb2, 0x0c, 0xff, 0x41, 0xee, 0xd6, 0x0d, + 0xec, 0xd9, 0x13, 0x1a, 0xf1, 0x30, 0x75, 0x64, 0x27, 0x3e, 0x32, 0xf2, 0x29, 0x25, 0x4e, 0x0d, + 0x21, 0x9d, 0x85, 0xfe, 0x6f, 0x34, 0x55, 0x27, 0xd8, 0x2d, 0x0c, 0xf5, 0xc5, 0x0c, 0xc5, 0x59, + 0x22, 0x3f, 0x7a, 0x51, 0xcc, 0x48, 0x1f, 0xcb, 0x69, 0xc8, 0x14, 0x5a, 0x44, 0xd3, 0xc1, 0x38, + 0x7d, 0x2e, 0x7a, 0x57, 0x78, 0x9d, 0x92, 0x9b, 0x06, 0xd5, 0xb2, 0x2f, 0xf2, 0xe3, 0xaf, 0xb3, + 0x86, 0x4f, 0x31, 0x6a, 0x97, 0x1c, 0x40, 0x2b, 0xa4, 0x2e, 0x5c, 0xfe, 0xae, 0xc4, 0x4f, 0xbe, + 0x85, 0x25, 0x63, 0xf4, 0x90, 0xbc, 0x3f, 0xbf, 0x34, 0x16, 0xea, 0xb2, 0xe2, 0xe0, 0x1e, 0x2c, + 0x7d, 0x4a, 0x2a, 0xec, 0xf0, 0xfc, 0xe1, 0x22, 0x47, 0x5a, 0xdb, 0xe2, 0x6a, 0x15, 0x0d, 0x64, + 0xd7, 0x05, 0x11, 0x93, 0x5d, 0x7f, 0xc8, 0xac, 0xb1, 0x2b, 0x27, 0xb9, 0x25, 0x69, 0x72, 0x71, + 0x1a, 0x09, 0xaf, 0x97, 0x88, 0x12, 0x22, 0xe2, 0x11, 0x9d, 0x8d, 0x07, 0xb1, 0x47, 0x82, 0x6d, + 0x4c, 0xae, 0xea, 0xb1, 0xe9, 0x02, 0x6f, 0xc5, 0xa8, 0x0d, 0xb5, 0x25, 0x01, 0xc6, 0x87, 0xa4, + 0x7c, 0xc6, 0x2a, 0x3b, 0xcb, 0x4d, 0xf1, 0x9b, 0x46, 0x81, 0x86, 0xd7, 0x3d, 0x8d, 0x7e, 0x44, + 0x86, 0x20, 0xc8, 0x03, 0xb4, 0xd5, 0x57, 0x4a, 0x45, 0xcd, 0xf3, 0x98, 0x5a, 0xd3, 0x00, 0x60, + 0x39, 0xe6, 0x04, 0x4f, 0x47, 0xa5, 0xd0, 0x1c, 0xa2, 0x3a, 0x35, 0x07, 0x9e, 0xc5, 0x16, 0xcf, + 0x17, 0x71, 0x45, 0x2d, 0xaf, 0xfe, 0xb7, 0x29, 0x8e, 0xb1, 0x80, 0x4c, 0x43, 0xc5, 0xca, 0xee, + 0xe7, 0xf2, 0xcd, 0x9b, 0xa2, 0x25, 0xd8, 0x7d, 0x48, 0x92, 0x91, 0xc9, 0x93, 0x1d, 0xc4, 0xb2, + 0xb2, 0x0f, 0x0d, 0xea, 0x87, 0x1e, 0x4a, 0x6c, 0x5d, 0x6e, 0x7f, 0xc2, 0x42, 0x33, 0xcd, 0xaf, + 0xce, 0x37, 0x3e, 0x9b, 0x55, 0xc8, 0xc8, 0x8a, 0x82, 0x3c, 0x32, 0x97, 0x5a, 0xcf, 0x4c, 0xff, + 0x06, 0x24, 0xd0, 0x78, 0x23, 0x37, 0x17, 0x16, 0x77, 0x03, 0x50, 0xbd, 0x58, 0x96, 0x7c, 0x79, + 0x2a, 0x7a, 0x34, 0xc5, 0xd9, 0x72, 0x59, 0x07, 0x65, 0x47, 0x6c, 0x9a, 0x2e, 0x07, 0x68, 0xbc, + 0x47, 0xaa, 0x46, 0xee, 0x67, 0xda, 0x31, 0x7e, 0x78, 0xdf, 0xc2, 0x15, 0x05, 0x57, 0xba, 0xa0, + 0x48, 0x1e, 0x8e, 0xba, 0xe6, 0x42, 0x2f, 0x43, 0x6a, 0x7a, 0x3b, 0x56, 0x8c, 0x0b, 0x4e, 0xf9, + 0xaa, 0x53, 0xd4, 0x7d, 0xaa, 0x6b, 0x9d, 0x1e, 0x2e, 0x28, 0x62, 0x14, 0x18, 0x9d, 0x60, 0xbd, + 0xf9, 0x54, 0x2e, 0xde, 0x46, 0x12, 0x99, 0x5d, 0xa2, 0xf2, 0xa1, 0xf5, 0x17, 0xd2, 0x4c, 0xe1, + 0xb2, 0x63, 0xec, 0x13, 0x7f, 0x88, 0x9b, 0x17, 0x07, 0x21, 0xa6, 0x8e, 0x8f, 0x3d, 0xa4, 0x33, + 0x6a, 0x57, 0x07, 0x9e, 0xc9, 0xca, 0xde, 0x49, 0x41, 0x3e, 0x11, 0xe8, 0x4b, 0x00, 0xa2, 0x17, + 0x70, 0xf0, 0x85, 0x92, 0x53, 0x5f, 0xcc, 0x90, 0x23, 0x46, 0xed, 0xd5, 0xc0, 0x2e, 0x38, 0x61, + 0x2b, 0xf0, 0xb8, 0x8a, 0xb6, 0x82, 0x86, 0x4b, 0x02, 0x2c, 0x7a, 0x38, 0x98, 0xf0, 0xc6, 0xa4, + 0x3a, 0xcc, 0xce, 0x36, 0xc6, 0x76, 0x5b, 0x3b, 0x65, 0xb2, 0x15, 0x9f, 0xb7, 0x25, 0xef, 0x63, + 0xe1, 0x3b, 0xe3, 0x0b, 0xae, 0xdd, 0x14, 0xfd, 0xa9, 0x1b, 0x5f, 0xc1, 0x91, 0x59, 0x2c, 0x16, + 0x18, 0x4b, 0xb3, 0xab, 0x64, 0xaf, 0xed, 0x1b, 0x2c, 0xd9, 0x3b, 0x76, 0xb0, 0xff, 0x92, 0x2e, + 0x7e, 0xd5, 0x0d, 0x81, 0x7a, 0x70, 0xc0, 0x33, 0x75, 0xc3, 0x1f, 0xc8, 0xa0, 0x4b, 0xa3, 0x07, + 0x9c, 0x41, 0x18, 0xac, 0x6c, 0xaa, 0xbc, 0xf8, 0xb2, 0x36, 0x14, 0xcb, 0xfe, 0xba, 0x37, 0x32, + 0xa8, 0xbc, 0xeb, 0x89, 0xcd, 0x78, 0x7f, 0x9d, 0xac, 0x31, 0x1a, 0xc9, 0x54, 0xae, 0xfd, 0x62, + 0x9c, 0xe1, 0xeb, 0x3f, 0x2d, 0x99, 0x8a, 0x0d, 0xfb, 0xe5, 0x85, 0x83, 0xb6, 0xad, 0x22, 0x66, + 0x93, 0xf7, 0x77, 0x20, 0x97, 0x07, 0x30, 0xb8, 0x15, 0x34, 0x2a, 0x48, 0x77, 0xc8, 0x08, 0xee, + 0xfe, 0xb8, 0xf6, 0x24, 0xf0, 0xba, 0x00, 0x82, 0xae, 0x4f, 0xb9, 0x23, 0x51, 0x4e, 0xec, 0x78, + 0x41, 0x90, 0x5a, 0x75, 0xa6, 0x1b, 0xf2, 0xad, 0xcf, 0xc0, 0xb7, 0x46, 0x8d, 0x61, 0x43, 0xea, + 0xaf, 0xa5, 0xe4, 0xaa, 0xe3, 0xad, 0xfc, 0x74, 0x73, 0x2b, 0xd1, 0xae, 0x21, 0x40, 0xed, 0xe1, + 0xd6, 0xec, 0x74, 0x45, 0xe3, 0xe5, 0xfb, 0x7c, 0x09, 0xcd, 0xee, 0x3a, 0xee, 0x66, 0x59, 0xc0, + 0x57, 0x65, 0x07, 0xfd, 0x66, 0xfd, 0x30, 0x3d, 0xdb, 0xc1, 0x2a, 0xf3, 0xe1, 0xbe, 0xdb, 0xca, + 0xc0, 0xe2, 0x9a, 0x2c, 0x25, 0xd9, 0x73, 0xd0, 0x75, 0xae, 0x9e, 0x41, 0x85, 0x01, 0xd5, 0x71, + 0x4c, 0x67, 0x32, 0xab, 0x2a, 0xa7, 0x15, 0xd6, 0xcf, 0xe4, 0xff, 0x01, 0xde, 0x0a, 0x48, 0x7b, + 0xcd, 0xd8, 0x4e, 0x00, 0x93, 0x8f, 0x0a, 0x4e, 0x06, 0xaa, 0x1a, 0xb3, 0x5c, 0xcb, 0xb3, 0x01, + 0x17, 0x9d, 0x48, 0xe7, 0xf3, 0x99, 0x7c, 0x3a, 0x1f, 0xb1, 0xb4, 0xde, 0x79, 0x4a, 0x01, 0xac, + 0x9b, 0x42, 0x84, 0x0d, 0x50, 0xb6, 0x73, 0xee, 0x7d, 0x5a, 0x45, 0x67, 0xed, 0xfd, 0x65, 0xa7, + 0x4a, 0xaf, 0xa4, 0x9b, 0x93, 0x42, 0x0f, 0x50, 0xba, 0xe9, 0x69, 0x86, 0x77, 0x7c, 0xa1, 0xf7, + 0xe1, 0x9c, 0x8c, 0x53, 0x43, 0xcc, 0xa8, 0xed, 0x6a, 0xaa, 0x6a, 0xb5, 0xab, 0x29, 0xc8, 0x2a, + 0x81, 0x78, 0x88, 0x49, 0x29, 0x84, 0xf6, 0x3e, 0x45, 0x47, 0x3d, 0x59, 0xa4, 0x95, 0xd1, 0x90, + 0xb7, 0xa4, 0x20, 0x48, 0x3e, 0xbe, 0x01, 0x42, 0xdb, 0x11, 0x33, 0x79, 0x9f, 0x40, 0x58, 0xd9, + 0x86, 0x81, 0x1d, 0x41, 0xb5, 0x63, 0x18, 0x9f, 0x54, 0xe5, 0x00, 0x7c, 0x1c, 0xf4, 0xb8, 0x8a, + 0x94, 0x91, 0xa0, 0x67, 0x75, 0xcc, 0xa5, 0x49, 0xe2, 0x00, 0xfb, 0x9a, 0xc9, 0x87, 0x94, 0x3d, + 0x6e, 0xef, 0xe5, 0xa5, 0x74, 0x04, 0x32, 0xb3, 0x5f, 0x98, 0xde, 0x0c, 0xec, 0x32, 0xa9, 0x7a, + 0x25, 0xc6, 0x20, 0x8f, 0x2e, 0x62, 0xb5, 0xb8, 0x8f, 0x9d, 0xed, 0xaa, 0x91, 0x5e, 0xbe, 0x01, + 0x4c, 0x17, 0x76, 0xc9, 0xaf, 0x3b, 0xf4, 0xa3, 0xa3, 0x92, 0x83, 0xd6, 0x74, 0x25, 0x66, 0x07, + 0x7a, 0x90, 0x33, 0xfb, 0x65, 0xa5, 0x2c, 0xc9, 0x05, 0xb0, 0xdc, 0xf8, 0x30, 0xdb, 0x45, 0xf3, + 0x57, 0xd1, 0xf3, 0xba, 0x17, 0xef, 0x33, 0xf6, 0x62, 0x65, 0x6c, 0x4b, 0x08, 0x96, 0x04, 0x95, + 0x4b, 0x6d, 0xbe, 0x24, 0x8d, 0x53, 0xc5, 0x1c, 0x01, 0x4e, 0x8e, 0x3e, 0xd9, 0x93, 0x78, 0x57, + 0xa7, 0x2d, 0xc5, 0xb3, 0x08, 0x60, 0x57, 0x41, 0xa0, 0x45, 0xdd, 0xc5, 0xf1, 0x30, 0x82, 0x05, + 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x05, 0x32, + 0x04, 0x82, 0x05, 0x2e, 0x30, 0x82, 0x05, 0x2a, 0x30, 0x82, 0x05, 0x26, 0x06, 0x0b, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x04, 0xee, 0x30, 0x82, 0x04, + 0xea, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, + 0x0e, 0x04, 0x08, 0xda, 0xa7, 0x48, 0xd7, 0xe2, 0xa7, 0xa3, 0x8a, 0x02, 0x02, 0x08, 0x00, 0x04, + 0x82, 0x04, 0xc8, 0x9a, 0x2d, 0x23, 0xba, 0xb5, 0xcd, 0x9e, 0x9a, 0xe0, 0xcb, 0x87, 0xe9, 0xcd, + 0xc1, 0x7b, 0xba, 0xcf, 0xae, 0xbb, 0x1c, 0x96, 0x7a, 0x56, 0x5f, 0xb1, 0x24, 0xaa, 0xbb, 0x33, + 0x1b, 0x95, 0xc2, 0x24, 0x8e, 0x70, 0x4b, 0xd5, 0xe0, 0x82, 0x91, 0x8c, 0x6b, 0x58, 0x3d, 0xa7, + 0x74, 0xdb, 0x22, 0xe8, 0xd1, 0xe3, 0xf5, 0xe4, 0xe9, 0x7e, 0x57, 0x19, 0x81, 0xb9, 0x4d, 0x49, + 0xf2, 0x63, 0x72, 0x89, 0xb2, 0xf0, 0x06, 0x22, 0x96, 0x0a, 0x51, 0xaf, 0xa9, 0x9a, 0xa9, 0x99, + 0x80, 0xe8, 0x68, 0xfa, 0x82, 0x03, 0xf2, 0x13, 0xc4, 0x83, 0xa7, 0xf0, 0xa9, 0x79, 0x41, 0x88, + 0xaf, 0x31, 0x19, 0x39, 0x86, 0xa9, 0x1d, 0x86, 0x2f, 0x70, 0x8a, 0xa5, 0x22, 0xbd, 0xd7, 0x36, + 0x83, 0xd9, 0x53, 0x44, 0x6c, 0x5d, 0xd8, 0x74, 0x8a, 0xa2, 0x81, 0x54, 0xd4, 0x4c, 0xd3, 0x7b, + 0x46, 0x1b, 0x50, 0xea, 0x0a, 0x83, 0xf5, 0x38, 0x93, 0xe7, 0xdd, 0x54, 0x15, 0x6b, 0x62, 0x0a, + 0xc0, 0x31, 0xf4, 0x1e, 0x82, 0xd8, 0xd3, 0xae, 0x80, 0xa4, 0xcb, 0xa3, 0xdd, 0x1b, 0xf5, 0xf9, + 0xee, 0x86, 0x35, 0xa0, 0xdb, 0xcc, 0x9e, 0xf8, 0xc8, 0xeb, 0x9a, 0x15, 0x3c, 0x27, 0xd7, 0x5c, + 0xdd, 0xae, 0x3e, 0x15, 0x11, 0xff, 0x78, 0xb2, 0xcf, 0xa0, 0xec, 0x76, 0x3f, 0x05, 0xb5, 0x30, + 0x52, 0x4f, 0xc9, 0x1b, 0x4c, 0x12, 0x64, 0xa6, 0x20, 0xa4, 0x2f, 0x20, 0x4b, 0xdf, 0x2c, 0x9a, + 0x24, 0x7b, 0x49, 0xab, 0x4c, 0x58, 0x09, 0x2c, 0xdf, 0x49, 0xa9, 0x25, 0xa8, 0x4c, 0xa2, 0x46, + 0xb3, 0x14, 0x3b, 0xdd, 0x71, 0xea, 0x39, 0xef, 0xe1, 0xc7, 0x5f, 0xea, 0x40, 0x3b, 0x3e, 0x13, + 0x3a, 0x11, 0x04, 0xac, 0xc7, 0xf0, 0x23, 0x26, 0xe5, 0xce, 0xf0, 0x42, 0xfe, 0x76, 0x19, 0x47, + 0x85, 0x98, 0xb7, 0x2f, 0xa3, 0xfd, 0x6d, 0x59, 0xec, 0x05, 0xb6, 0x1d, 0xb9, 0x4b, 0x96, 0x92, + 0x0c, 0xc2, 0x35, 0x37, 0xd2, 0xf0, 0xb9, 0x98, 0x7a, 0xcc, 0x44, 0xe1, 0x70, 0x5d, 0xa1, 0x3d, + 0xbd, 0xe9, 0x72, 0x44, 0x71, 0xcf, 0xe8, 0x8a, 0x6a, 0x26, 0x0f, 0xc8, 0x7d, 0xd6, 0xf3, 0x19, + 0xfd, 0x0f, 0xce, 0xc6, 0x1b, 0x89, 0x60, 0xe5, 0x38, 0xf9, 0x3b, 0xd9, 0x73, 0xc3, 0x82, 0x74, + 0x49, 0x17, 0x73, 0x94, 0x55, 0xbb, 0xe8, 0x06, 0x76, 0x20, 0x8e, 0x2a, 0x1f, 0x60, 0xcc, 0xeb, + 0x3e, 0x21, 0xb6, 0xbd, 0xd5, 0x8e, 0xbc, 0xf2, 0xe0, 0x7b, 0x49, 0xb4, 0x8d, 0x3f, 0x6a, 0x5d, + 0x35, 0x2b, 0x98, 0xea, 0x1d, 0x20, 0x6a, 0x51, 0xdd, 0xa4, 0xb1, 0x13, 0x56, 0x2e, 0x85, 0x4b, + 0xd9, 0xfd, 0xe0, 0x83, 0x8e, 0xfd, 0x66, 0x71, 0xf0, 0xcb, 0xc8, 0x7d, 0xaa, 0x09, 0xec, 0x26, + 0x60, 0x68, 0xc5, 0xa7, 0x56, 0xed, 0x8b, 0x3a, 0x2c, 0xcf, 0x80, 0x3b, 0x47, 0xaf, 0xef, 0x7f, + 0xb8, 0x81, 0xa6, 0xd6, 0xd4, 0x13, 0xe7, 0xaa, 0x8c, 0xd9, 0xa9, 0xe9, 0x9a, 0x2c, 0x8b, 0xf2, + 0x19, 0x75, 0xc0, 0x3a, 0xd3, 0x54, 0x70, 0x0a, 0xc3, 0xe6, 0xdf, 0xbb, 0xf1, 0x06, 0xc6, 0x59, + 0x37, 0x5b, 0x5b, 0x22, 0x23, 0x90, 0x4a, 0x05, 0xcb, 0x08, 0xa4, 0x41, 0x13, 0xb2, 0xbc, 0xb8, + 0xcf, 0x5d, 0x9a, 0x79, 0x57, 0xf8, 0x89, 0xd7, 0x63, 0x08, 0xc8, 0xa5, 0xd5, 0xd5, 0x89, 0xff, + 0x73, 0xb9, 0x0f, 0x3a, 0x67, 0x68, 0x9f, 0xc2, 0x81, 0x3b, 0x36, 0x8a, 0xed, 0x81, 0xc9, 0x38, + 0xdd, 0x32, 0xaf, 0x9e, 0xc0, 0xc3, 0x32, 0x76, 0xf6, 0xba, 0x1a, 0x45, 0x8d, 0x81, 0xec, 0xc5, + 0xb2, 0x0e, 0x40, 0x47, 0x2d, 0xf6, 0x2d, 0xcd, 0xaa, 0xb8, 0x1e, 0x1c, 0x53, 0xff, 0xf2, 0xdb, + 0xe5, 0x91, 0x70, 0xc7, 0x0c, 0xd6, 0x33, 0xa9, 0x9b, 0x6b, 0x37, 0xeb, 0x1e, 0x8e, 0x69, 0x25, + 0xb9, 0x55, 0xb8, 0x1b, 0x1d, 0x5c, 0x7d, 0x19, 0xf3, 0x2b, 0x3a, 0xa0, 0xab, 0x9a, 0xe5, 0xb0, + 0xd4, 0x01, 0x84, 0x3f, 0xf3, 0xdd, 0xcf, 0xa5, 0x9a, 0x79, 0x4d, 0xd7, 0x85, 0xc0, 0x68, 0x25, + 0x1e, 0x1f, 0x45, 0x25, 0x72, 0x70, 0xb0, 0x02, 0x0f, 0xce, 0xe8, 0x74, 0x5e, 0xa5, 0x22, 0xed, + 0x36, 0xab, 0x36, 0xf1, 0xfd, 0x8c, 0x37, 0x7a, 0xc4, 0x45, 0x94, 0x52, 0x39, 0x7e, 0x6a, 0xf1, + 0x27, 0x1b, 0xd6, 0x20, 0xee, 0xc0, 0x02, 0x6e, 0xec, 0x78, 0xb5, 0x97, 0xcb, 0xc3, 0xe5, 0xa1, + 0x4a, 0xfc, 0xbb, 0x27, 0xc7, 0x4a, 0x80, 0xea, 0xfa, 0x0e, 0x78, 0x68, 0x73, 0x04, 0x91, 0xa2, + 0x4e, 0xbb, 0x63, 0xbf, 0x45, 0xff, 0x6f, 0xc3, 0x4c, 0xb9, 0xae, 0xc0, 0x9b, 0x8b, 0x90, 0xdf, + 0xc4, 0x1b, 0xee, 0xa7, 0xff, 0x85, 0xfe, 0xdb, 0x80, 0x16, 0xe8, 0x7c, 0x1e, 0xdf, 0xa3, 0xbb, + 0x0e, 0x83, 0xc5, 0xcc, 0xf3, 0x59, 0x38, 0xd2, 0x6a, 0xda, 0xe3, 0x66, 0x80, 0xf5, 0x57, 0x38, + 0x86, 0x07, 0x4b, 0x7a, 0x8b, 0x1d, 0x3d, 0x85, 0xa2, 0x32, 0x78, 0xc4, 0x85, 0xec, 0x5c, 0x92, + 0x8c, 0x1f, 0xa9, 0x78, 0x5f, 0xd6, 0xe9, 0xb2, 0xec, 0xbd, 0xac, 0x58, 0xdf, 0xf8, 0x77, 0xd1, + 0xd4, 0xfd, 0xec, 0x97, 0xce, 0x0c, 0x9f, 0xab, 0xdc, 0xec, 0x2c, 0xba, 0x73, 0xeb, 0x0f, 0x60, + 0x84, 0x35, 0xc8, 0xfb, 0x5b, 0x8f, 0x29, 0x32, 0x48, 0xe1, 0x87, 0x07, 0x2a, 0xdc, 0x03, 0x95, + 0x2e, 0xed, 0x8b, 0xe6, 0x9f, 0x12, 0x01, 0xf8, 0x49, 0xd5, 0xec, 0x29, 0xc6, 0x0b, 0xd4, 0xca, + 0x47, 0x1d, 0x7e, 0x95, 0x75, 0xf5, 0xf8, 0x05, 0x57, 0x43, 0x49, 0x6d, 0x59, 0x77, 0x9b, 0x84, + 0x51, 0x44, 0x16, 0x07, 0x8d, 0xd8, 0xa8, 0xf1, 0x83, 0xa0, 0x4f, 0x80, 0x87, 0xa5, 0xa6, 0xa5, + 0x26, 0xe0, 0xb3, 0x2d, 0x39, 0xe2, 0xbf, 0x60, 0xa3, 0x87, 0xee, 0xd8, 0x98, 0x55, 0xb2, 0x6a, + 0xb5, 0xfd, 0x38, 0x52, 0x87, 0x1d, 0xcd, 0xcc, 0x97, 0xee, 0xfb, 0x4b, 0xb4, 0x3c, 0x9c, 0x6f, + 0x8c, 0xd6, 0xc5, 0x17, 0xe7, 0x6d, 0x80, 0x55, 0x8b, 0x34, 0xa5, 0xde, 0x9b, 0x73, 0x62, 0x22, + 0x20, 0x2b, 0xc0, 0xa4, 0xcb, 0xcf, 0xb3, 0xf0, 0xd1, 0xd0, 0x20, 0x72, 0xf5, 0xa2, 0x99, 0xbe, + 0x63, 0x7f, 0x72, 0xf6, 0xed, 0x86, 0x0f, 0x49, 0x14, 0xcb, 0x15, 0x21, 0x4c, 0x97, 0x4d, 0x60, + 0x1c, 0x05, 0x9c, 0xd6, 0x23, 0x63, 0x11, 0x5d, 0x4f, 0x96, 0xa9, 0x36, 0x8c, 0x97, 0x90, 0x13, + 0xfe, 0x8e, 0xa9, 0xe7, 0x57, 0x02, 0x78, 0x57, 0xf7, 0x92, 0x51, 0x74, 0x43, 0xd7, 0xe2, 0xd9, + 0xbd, 0xe9, 0x50, 0x09, 0xd6, 0xe9, 0x12, 0x3b, 0x87, 0xbf, 0x1a, 0x57, 0x3a, 0x18, 0x26, 0x11, + 0xbf, 0xa9, 0x70, 0xa3, 0x02, 0x86, 0xde, 0xa8, 0xe1, 0x3b, 0x47, 0xf6, 0x95, 0xe8, 0x67, 0x89, + 0xbf, 0x79, 0xd6, 0x53, 0x84, 0x57, 0x92, 0xce, 0x00, 0xe4, 0x6a, 0x34, 0x46, 0x59, 0xa5, 0x32, + 0x50, 0xa2, 0x3d, 0x60, 0xff, 0x13, 0x4d, 0xf3, 0x4c, 0x4c, 0xc1, 0x45, 0x27, 0x1d, 0x81, 0x45, + 0xb9, 0x69, 0x50, 0x1c, 0xd6, 0x4f, 0x82, 0x1d, 0xfd, 0x09, 0x19, 0x91, 0xac, 0xf3, 0x23, 0x95, + 0xc9, 0x24, 0xbd, 0x97, 0x34, 0x73, 0x13, 0x7e, 0x3f, 0x16, 0x73, 0x01, 0x57, 0x31, 0xa5, 0xe4, + 0x2e, 0xf2, 0x1a, 0xe8, 0x26, 0x5e, 0xae, 0xd4, 0x71, 0x4f, 0xfa, 0xd8, 0x11, 0x80, 0x71, 0xcf, + 0x68, 0x49, 0x6d, 0xd1, 0x2a, 0x97, 0x8f, 0x45, 0x51, 0x84, 0xef, 0x93, 0xae, 0x8f, 0xd7, 0x9a, + 0x26, 0x21, 0x88, 0xab, 0x9d, 0xa8, 0x29, 0x2c, 0x32, 0xd6, 0x44, 0x5c, 0x65, 0x13, 0x63, 0xb8, + 0xd4, 0x23, 0x03, 0xc4, 0x22, 0x89, 0x78, 0x09, 0xb6, 0x77, 0x2e, 0xfd, 0x29, 0x82, 0x43, 0x21, + 0xb9, 0xa9, 0x44, 0x2f, 0x92, 0x96, 0x9a, 0x2c, 0x08, 0x31, 0x24, 0x4b, 0x53, 0x39, 0x0d, 0xdd, + 0xdc, 0xd4, 0xcd, 0x29, 0xf7, 0xc6, 0x5b, 0xb4, 0x22, 0x90, 0x9a, 0x54, 0x46, 0x31, 0x62, 0xb5, + 0xa6, 0x34, 0x96, 0xee, 0xb9, 0xc2, 0x99, 0x48, 0x32, 0xf8, 0x64, 0x59, 0xb9, 0x34, 0x35, 0x1c, + 0xa8, 0x25, 0x3f, 0xe8, 0x92, 0x32, 0x2b, 0xc5, 0xec, 0x5c, 0x1b, 0xbd, 0x4b, 0x2b, 0xc3, 0x75, + 0xc6, 0xc0, 0x3c, 0xcf, 0x43, 0xe9, 0x9b, 0x5b, 0xfc, 0x1b, 0x3b, 0x0f, 0x1a, 0x3a, 0x6e, 0x42, + 0x5a, 0xdc, 0x81, 0x13, 0x92, 0xaf, 0xae, 0xc1, 0xdd, 0x45, 0xaf, 0xc6, 0x17, 0xf7, 0xd4, 0xf1, + 0xb7, 0xfb, 0x1a, 0x47, 0x32, 0x11, 0xe2, 0x94, 0x49, 0x9e, 0xdd, 0x85, 0xb3, 0x46, 0x63, 0x52, + 0xde, 0xd8, 0x1b, 0x72, 0x30, 0x0e, 0x47, 0x3c, 0xac, 0xcb, 0xfe, 0xcb, 0xe8, 0xd6, 0xe6, 0xfe, + 0xb4, 0x73, 0xbf, 0xe3, 0xc5, 0x54, 0x87, 0xf5, 0x9c, 0x21, 0xfb, 0xcb, 0x48, 0x3f, 0x86, 0xbf, + 0xb9, 0x45, 0xf8, 0x1c, 0xbe, 0xde, 0xeb, 0x3c, 0xce, 0x28, 0x04, 0x64, 0xc5, 0x04, 0x7e, 0xb7, + 0x41, 0xd8, 0xc1, 0xd7, 0x5f, 0xf4, 0x07, 0x71, 0x98, 0x7e, 0x6c, 0x31, 0x25, 0x30, 0x23, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x77, 0xe3, + 0xaf, 0x7a, 0xa0, 0x26, 0xa0, 0x4c, 0x65, 0xa9, 0xac, 0xc2, 0xcc, 0x27, 0xa3, 0x6e, 0xbf, 0x0b, + 0xbd, 0x6a, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14, 0x0a, 0x49, 0xcb, 0x4f, 0xf2, 0x3d, 0xf2, 0x92, 0x93, 0x2f, 0x32, 0x95, 0x6e, + 0x17, 0x33, 0xd2, 0xa9, 0xc3, 0xee, 0xc4, 0x04, 0x08, 0xbe, 0xc6, 0x44, 0x42, 0x29, 0x96, 0xef, + 0x52, 0x02, 0x02, 0x08, 0x00 +}; + +unsigned char _user_two_p12[] = { + 0x30, 0x82, 0x0a, 0x61, 0x02, 0x01, 0x03, 0x30, 0x82, 0x0a, 0x27, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x0a, 0x18, 0x04, 0x82, 0x0a, 0x14, 0x30, 0x82, + 0x0a, 0x10, 0x30, 0x82, 0x04, 0xc7, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x06, 0xa0, 0x82, 0x04, 0xb8, 0x30, 0x82, 0x04, 0xb4, 0x02, 0x01, 0x00, 0x30, 0x82, 0x04, 0xad, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0xe2, 0xb3, 0x09, + 0x69, 0xc2, 0x99, 0x0f, 0x1e, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x04, 0x80, 0x6a, 0x89, 0x65, + 0xde, 0x1a, 0xf6, 0xd4, 0xbf, 0x7f, 0xf0, 0xcf, 0x25, 0xd0, 0xc8, 0x1a, 0x31, 0xa3, 0xc1, 0xb6, + 0x19, 0xe7, 0x7c, 0xbb, 0x7a, 0x71, 0x05, 0x36, 0x78, 0xf3, 0xa1, 0x7d, 0xfc, 0x4e, 0xb9, 0xad, + 0x27, 0x5d, 0x7f, 0xc6, 0x3d, 0x09, 0x1d, 0x6d, 0xc0, 0x9c, 0x7c, 0x6b, 0xfd, 0x04, 0xac, 0x99, + 0x31, 0x3c, 0xf8, 0x47, 0x87, 0xce, 0x6c, 0x5e, 0x1a, 0x55, 0x23, 0xc8, 0x20, 0xf7, 0x50, 0x66, + 0xde, 0x46, 0xae, 0xeb, 0x2e, 0x1a, 0x4c, 0xb0, 0xea, 0x29, 0x5a, 0x6f, 0x62, 0x4d, 0x02, 0x1e, + 0xc9, 0x45, 0x8b, 0x4c, 0xc9, 0xf4, 0x40, 0x4f, 0x50, 0x9a, 0x39, 0xed, 0x3c, 0x8d, 0xc0, 0x57, + 0x4a, 0xcd, 0xd0, 0x33, 0x3e, 0x89, 0xfc, 0x23, 0x2d, 0x73, 0x45, 0x64, 0x53, 0x07, 0x0e, 0xc6, + 0xd2, 0xac, 0xde, 0x0b, 0x61, 0xcb, 0x56, 0x5e, 0x68, 0x57, 0x6e, 0xf1, 0x7f, 0x1d, 0x62, 0xc3, + 0xf6, 0x75, 0xa7, 0xdb, 0xb6, 0xf1, 0x03, 0x42, 0xd6, 0x2f, 0xf6, 0xcd, 0xb5, 0xdf, 0x15, 0x03, + 0x49, 0xa1, 0x00, 0xd5, 0x1a, 0x07, 0xc3, 0x42, 0x27, 0xf3, 0xa9, 0x1e, 0xcd, 0x29, 0x23, 0xca, + 0x7b, 0x53, 0xbf, 0x6d, 0x79, 0xe7, 0x21, 0xe0, 0xbb, 0x33, 0xb6, 0x22, 0xa5, 0xd0, 0xdb, 0x22, + 0x45, 0xa5, 0x07, 0x6f, 0xa3, 0xa0, 0x61, 0x0d, 0xe7, 0x9d, 0xb5, 0xe2, 0x0c, 0xc1, 0x46, 0x4b, + 0x65, 0x41, 0x0c, 0xe1, 0x3a, 0x93, 0x4f, 0x52, 0x9e, 0x42, 0x6c, 0x9f, 0x8a, 0x6a, 0x7f, 0xef, + 0x2d, 0x8e, 0x43, 0xbf, 0xc8, 0xe8, 0x5c, 0x4a, 0x89, 0xd2, 0xcd, 0xb3, 0x9f, 0xc9, 0x9e, 0xfe, + 0x10, 0x46, 0xdd, 0x90, 0x95, 0xa0, 0x78, 0x5a, 0x3d, 0xab, 0x8b, 0xd9, 0x95, 0x78, 0x06, 0x98, + 0x9e, 0x36, 0x40, 0x5b, 0x06, 0x02, 0x80, 0x3b, 0x2c, 0x86, 0x87, 0xf5, 0x65, 0x3a, 0x52, 0xeb, + 0x60, 0xc9, 0xbe, 0xc6, 0xbb, 0x82, 0xe4, 0x5b, 0x8a, 0x04, 0x28, 0x6a, 0x85, 0x62, 0x38, 0x70, + 0xbd, 0x69, 0x30, 0x9f, 0x8e, 0x23, 0xc9, 0xe6, 0x3a, 0xb4, 0x7b, 0x05, 0x04, 0xfb, 0xae, 0x69, + 0x0b, 0xfa, 0x95, 0xe1, 0x6a, 0xba, 0x97, 0xcd, 0x2c, 0x3a, 0x0a, 0x08, 0xf6, 0xd7, 0x0e, 0xce, + 0xf5, 0x1e, 0xa6, 0x5b, 0x1e, 0x2d, 0xd5, 0xa8, 0x6b, 0x9f, 0xc0, 0xbd, 0xf0, 0x32, 0x9b, 0xef, + 0x7b, 0x7a, 0xc1, 0xfc, 0xe2, 0xc1, 0xc0, 0xcc, 0x8e, 0x96, 0x8e, 0xd5, 0x2a, 0x2e, 0x27, 0xd4, + 0x6f, 0x32, 0x98, 0x67, 0x41, 0xeb, 0xe3, 0xa4, 0xa7, 0x14, 0xcc, 0xcb, 0xf9, 0xb8, 0xcf, 0x1f, + 0x97, 0x24, 0x2d, 0xb1, 0x04, 0x17, 0xde, 0x02, 0x2f, 0x54, 0x5a, 0x14, 0x9b, 0x69, 0xa4, 0xd2, + 0x7d, 0xb8, 0xfd, 0xf5, 0x69, 0x3a, 0x3c, 0x8d, 0x31, 0xd0, 0x1d, 0x36, 0xc0, 0x9d, 0x3d, 0x26, + 0x15, 0xef, 0xaf, 0x55, 0x07, 0xe3, 0x01, 0x83, 0xd8, 0xe4, 0xd1, 0x1e, 0xff, 0x79, 0xe7, 0xbb, + 0x4f, 0x2f, 0x38, 0x7a, 0x35, 0x8b, 0x1a, 0xcf, 0xc4, 0x4d, 0x31, 0xba, 0x5e, 0x3e, 0x60, 0x80, + 0xef, 0xc9, 0xb6, 0x5b, 0x2e, 0xfd, 0x49, 0x46, 0x24, 0x7e, 0xeb, 0xe7, 0x1a, 0xf0, 0x42, 0xf5, + 0x81, 0x0e, 0x7f, 0xff, 0x68, 0x71, 0x9f, 0x5b, 0xee, 0xfc, 0xed, 0x76, 0xf4, 0xa8, 0x27, 0x3d, + 0x47, 0x77, 0x90, 0xfc, 0x88, 0x7f, 0x86, 0x6d, 0xcc, 0x1f, 0xf7, 0xef, 0x09, 0x7d, 0x25, 0xdf, + 0xe4, 0xdf, 0xaf, 0xbf, 0xff, 0x55, 0x52, 0x48, 0x72, 0x94, 0x01, 0x72, 0xfa, 0x51, 0xa4, 0xa3, + 0x8b, 0x66, 0x36, 0x3b, 0xdf, 0xd1, 0xe4, 0xf9, 0x04, 0x77, 0xb5, 0x33, 0xf9, 0x59, 0x07, 0x7a, + 0xe6, 0xa3, 0x0e, 0xca, 0x45, 0xf8, 0xeb, 0x26, 0x9c, 0x36, 0x1e, 0xc5, 0xae, 0xa3, 0x07, 0x34, + 0xb5, 0xbe, 0xaf, 0x63, 0x2e, 0xbb, 0x4a, 0x62, 0x6d, 0x00, 0xd9, 0x1c, 0x8d, 0x2c, 0xd0, 0x95, + 0x11, 0x07, 0x3c, 0x51, 0x2b, 0x40, 0x21, 0x68, 0x13, 0x5f, 0x7d, 0x6a, 0x2f, 0x03, 0x20, 0x92, + 0x58, 0xaa, 0xad, 0xd3, 0xcc, 0xfc, 0x54, 0xd7, 0x67, 0xba, 0x02, 0x8b, 0xbb, 0xeb, 0x3d, 0x9b, + 0xd4, 0x8a, 0x6a, 0x66, 0xbc, 0xf8, 0xd1, 0x0f, 0x5a, 0x09, 0x73, 0x94, 0x64, 0xea, 0x2f, 0x53, + 0x32, 0x63, 0x38, 0x61, 0x4e, 0x2d, 0x02, 0xa4, 0x65, 0xa3, 0x0b, 0x31, 0xba, 0x1d, 0x8f, 0xf5, + 0x41, 0x4e, 0x25, 0xbc, 0x73, 0x52, 0xa8, 0xb4, 0x1a, 0x26, 0xf1, 0x45, 0x68, 0xf2, 0x47, 0x78, + 0x8f, 0x02, 0xe5, 0x7b, 0x5d, 0x72, 0x2a, 0xb9, 0x9a, 0xd1, 0x75, 0xf8, 0x27, 0x47, 0x96, 0x0f, + 0xcd, 0x00, 0x0f, 0xea, 0x09, 0x1f, 0xef, 0x64, 0xbf, 0x45, 0x30, 0x4a, 0x1d, 0x24, 0x35, 0x28, + 0xfa, 0xad, 0x2a, 0x41, 0x15, 0x7e, 0x04, 0x28, 0x38, 0x0a, 0x31, 0xd8, 0x0d, 0x26, 0x7d, 0x61, + 0xc4, 0x3f, 0xb7, 0x13, 0xe9, 0x46, 0x09, 0x30, 0x7e, 0x10, 0x59, 0x90, 0x6d, 0x7c, 0x0c, 0x34, + 0x3f, 0x15, 0x42, 0xca, 0x64, 0xd8, 0x83, 0xc3, 0xd7, 0x2c, 0x2b, 0x33, 0x48, 0xc1, 0xab, 0x99, + 0xba, 0x31, 0x44, 0x96, 0xc6, 0x08, 0x84, 0xdb, 0x56, 0x7e, 0x94, 0x85, 0x18, 0x90, 0x96, 0xa3, + 0x41, 0xeb, 0xe6, 0xe8, 0xf5, 0x94, 0x7b, 0x2d, 0x14, 0xaa, 0x61, 0xab, 0xd1, 0x44, 0x7d, 0x35, + 0x44, 0x7e, 0xf1, 0x12, 0x32, 0xc3, 0xcf, 0x10, 0x8b, 0x83, 0x8f, 0x39, 0x96, 0x1b, 0xcb, 0x62, + 0x9f, 0xe2, 0xe2, 0xfe, 0xe2, 0xd1, 0x1a, 0x38, 0x4f, 0x22, 0x65, 0xa5, 0xe1, 0xb9, 0x4b, 0x69, + 0x24, 0x00, 0xb6, 0xb2, 0x50, 0x54, 0x53, 0xc3, 0x27, 0x17, 0xdd, 0x05, 0x86, 0x01, 0x69, 0x78, + 0x9e, 0xb5, 0xec, 0x88, 0x54, 0xfb, 0x55, 0x7e, 0x5f, 0x79, 0xf8, 0x15, 0x29, 0x24, 0x49, 0x55, + 0x06, 0x32, 0x18, 0x0f, 0xeb, 0x23, 0x62, 0xd3, 0xc4, 0xc1, 0x42, 0xbe, 0xc6, 0x8f, 0x22, 0x4f, + 0xb1, 0xee, 0x9e, 0x4b, 0x27, 0x57, 0x0e, 0xa4, 0xef, 0xb4, 0xca, 0x4b, 0x1e, 0x2d, 0xce, 0x01, + 0xa3, 0xa1, 0xcd, 0xa4, 0xe7, 0x97, 0xff, 0x4e, 0x17, 0x9e, 0x69, 0xa1, 0x17, 0x08, 0xd1, 0xe6, + 0x14, 0x1d, 0xe9, 0x5f, 0xc7, 0xab, 0x5c, 0x26, 0x04, 0x07, 0x12, 0x0e, 0x06, 0x1f, 0x23, 0x05, + 0xce, 0x37, 0x19, 0xbf, 0x2b, 0x14, 0x5b, 0x7a, 0x69, 0x39, 0x1a, 0xb3, 0x9a, 0x3f, 0xe7, 0x66, + 0xf7, 0xb8, 0xc0, 0xf3, 0x20, 0xbd, 0x89, 0x23, 0x1d, 0x4e, 0x39, 0xe8, 0xf1, 0x09, 0x0d, 0xf4, + 0x29, 0x3e, 0x90, 0x00, 0x6e, 0xb1, 0xd3, 0x86, 0x56, 0x7e, 0x54, 0xce, 0x86, 0x4d, 0x77, 0x2f, + 0xe4, 0x02, 0x6b, 0x1b, 0x0a, 0x39, 0x5f, 0x98, 0x8b, 0x25, 0x1b, 0x03, 0x72, 0x08, 0xba, 0x93, + 0x57, 0xe4, 0xc8, 0x34, 0x06, 0xdc, 0x1a, 0xdc, 0xbb, 0x6d, 0x76, 0xe4, 0x27, 0x5d, 0x0f, 0x54, + 0xe3, 0x10, 0xb2, 0xde, 0x23, 0xe4, 0xbd, 0xb4, 0xd1, 0xaa, 0x0a, 0x7f, 0xb4, 0x3f, 0xcf, 0xa3, + 0x84, 0x51, 0xf6, 0xa4, 0x78, 0xd9, 0xaa, 0x95, 0x3f, 0x7f, 0x71, 0xea, 0x24, 0x21, 0x0f, 0x01, + 0x8b, 0x6e, 0x08, 0x29, 0x24, 0xa8, 0xda, 0xf9, 0x76, 0xfc, 0xaa, 0x06, 0xa2, 0xf8, 0xa5, 0x49, + 0xf0, 0x85, 0xf0, 0xeb, 0x48, 0x86, 0x81, 0x14, 0x81, 0x9d, 0xd1, 0x7d, 0x31, 0x09, 0x5b, 0x47, + 0x70, 0x28, 0xb4, 0x45, 0xf6, 0xc7, 0x49, 0x73, 0xd5, 0x12, 0xd7, 0x5b, 0xdc, 0xa4, 0xdc, 0xb1, + 0x08, 0xbe, 0x16, 0x28, 0x92, 0x28, 0x6e, 0xa4, 0xe0, 0x19, 0xa4, 0xf9, 0xa7, 0xc2, 0xbd, 0x6b, + 0xaf, 0xd9, 0x27, 0x8e, 0xb3, 0xf6, 0xe7, 0x96, 0xc5, 0xad, 0xb3, 0x1d, 0xad, 0x51, 0x93, 0x38, + 0xa3, 0x24, 0x2b, 0x16, 0x42, 0x49, 0xa0, 0x15, 0x48, 0x86, 0xf1, 0xe9, 0xb7, 0xc0, 0xa6, 0x2c, + 0x53, 0x79, 0x44, 0xf0, 0x83, 0xb0, 0xfc, 0xdf, 0xa5, 0x7c, 0xed, 0x58, 0xf3, 0x5b, 0x64, 0x3b, + 0x46, 0x3c, 0x20, 0x1b, 0xfe, 0xa1, 0xa3, 0xb0, 0xa0, 0x3c, 0x03, 0x3d, 0x25, 0xeb, 0x4b, 0xdb, + 0x55, 0x97, 0xcb, 0x38, 0xce, 0xd7, 0xf5, 0xd6, 0x33, 0x45, 0xdf, 0xf6, 0x80, 0x9a, 0xc0, 0x07, + 0x1d, 0x2e, 0xa5, 0xf5, 0xb1, 0x4b, 0x99, 0x93, 0xf9, 0xfb, 0xcd, 0x0d, 0xbf, 0x7b, 0x3c, 0x56, + 0x85, 0x1b, 0x0f, 0xff, 0x0d, 0xac, 0xe8, 0x36, 0xe5, 0x43, 0x1e, 0x99, 0x9c, 0x42, 0x6a, 0x2d, + 0xab, 0xe3, 0xd8, 0x9f, 0x75, 0x1e, 0x84, 0x38, 0x32, 0x72, 0xe0, 0x2c, 0x3e, 0x30, 0x82, 0x05, + 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x05, 0x32, + 0x04, 0x82, 0x05, 0x2e, 0x30, 0x82, 0x05, 0x2a, 0x30, 0x82, 0x05, 0x26, 0x06, 0x0b, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x04, 0xee, 0x30, 0x82, 0x04, + 0xea, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, + 0x0e, 0x04, 0x08, 0xc8, 0x3d, 0xa5, 0x69, 0x37, 0xd1, 0x8c, 0x71, 0x02, 0x02, 0x08, 0x00, 0x04, + 0x82, 0x04, 0xc8, 0x76, 0x27, 0xc4, 0xf1, 0xd0, 0x95, 0x82, 0x53, 0xf2, 0x63, 0xef, 0x74, 0xd5, + 0x26, 0x15, 0x63, 0xa8, 0x04, 0x35, 0x0e, 0x95, 0xb2, 0x09, 0xf3, 0x2b, 0xcd, 0x30, 0x7f, 0x9e, + 0x8b, 0xa8, 0x5c, 0x5b, 0xe1, 0xf2, 0xbf, 0xfb, 0x83, 0xd8, 0xbf, 0x9d, 0x30, 0x03, 0xe6, 0xcc, + 0xa8, 0xcd, 0x2c, 0xbd, 0x6e, 0x99, 0xa9, 0x8f, 0x26, 0x0f, 0xc8, 0xcb, 0x82, 0x1c, 0x65, 0x7a, + 0x49, 0xe0, 0x20, 0xd1, 0xf7, 0x22, 0x82, 0xf5, 0x6b, 0x07, 0xbe, 0xb3, 0x42, 0xf4, 0xf9, 0x72, + 0x4b, 0xf2, 0x1e, 0x2f, 0xcb, 0x80, 0xc4, 0x52, 0x52, 0x01, 0x32, 0x0b, 0x48, 0x15, 0x3e, 0x33, + 0x7b, 0x20, 0x5c, 0xaa, 0x93, 0xee, 0x08, 0x63, 0xf2, 0x4e, 0x87, 0x77, 0x08, 0xcd, 0x63, 0x1c, + 0x58, 0x8b, 0xb4, 0xcd, 0x41, 0x9c, 0x6e, 0x04, 0x0a, 0x5b, 0xd3, 0xa0, 0x15, 0x75, 0x11, 0x91, + 0x55, 0xf1, 0x43, 0x73, 0x72, 0xde, 0x72, 0x19, 0x2a, 0x4f, 0xa7, 0xb7, 0xb2, 0x60, 0x11, 0xa8, + 0x75, 0xc7, 0x63, 0xfa, 0x7f, 0x74, 0xd1, 0x39, 0xa9, 0x0a, 0x7b, 0xf6, 0xd6, 0x4e, 0xe3, 0x42, + 0x5f, 0xf0, 0x27, 0xba, 0x71, 0xc2, 0x4e, 0x9e, 0x92, 0x3a, 0x7b, 0xaa, 0xc5, 0x55, 0x1f, 0x6f, + 0xbb, 0x08, 0x0d, 0x7a, 0x0c, 0x14, 0x2c, 0x02, 0x6e, 0x87, 0x78, 0xc3, 0x11, 0xfc, 0x28, 0x78, + 0x7a, 0xd5, 0xbc, 0xa1, 0x53, 0x60, 0x21, 0x58, 0x61, 0x4c, 0xdc, 0x73, 0x51, 0x47, 0x4e, 0xc5, + 0xd2, 0x81, 0xb7, 0xd0, 0xcb, 0x8e, 0x9f, 0x57, 0xfc, 0x1d, 0x41, 0x65, 0x36, 0xad, 0x08, 0x0a, + 0xf4, 0x09, 0xef, 0xfb, 0xc7, 0x3e, 0xb1, 0x7c, 0x38, 0xb4, 0x49, 0x2b, 0xd1, 0xbb, 0x70, 0xef, + 0x64, 0x7a, 0x35, 0xaf, 0x73, 0xfa, 0xca, 0xf1, 0x4b, 0xd3, 0xcd, 0xb1, 0x9e, 0x35, 0xb1, 0xee, + 0x8e, 0xab, 0x24, 0x23, 0x52, 0xcd, 0x12, 0xbb, 0x86, 0xab, 0x88, 0x0b, 0x1d, 0x30, 0xb6, 0x9e, + 0x32, 0x38, 0xd8, 0x9f, 0x85, 0x0d, 0xc4, 0xf9, 0x73, 0x9b, 0x18, 0x26, 0xe1, 0xa1, 0x5b, 0x88, + 0xcd, 0x80, 0x1b, 0x66, 0xb5, 0x71, 0xed, 0xb8, 0x16, 0xbb, 0x0c, 0xb2, 0x16, 0x04, 0xa7, 0x2a, + 0x93, 0x64, 0x7a, 0x28, 0x9f, 0xc2, 0x61, 0xf0, 0x3d, 0x92, 0x1e, 0x3f, 0xa6, 0x10, 0x47, 0xe4, + 0x15, 0x1f, 0x56, 0x10, 0xb6, 0xfc, 0x22, 0xfb, 0xd2, 0x52, 0x69, 0xec, 0x9e, 0x8b, 0xff, 0x9b, + 0x0e, 0x18, 0x3e, 0xa3, 0x17, 0xa9, 0xd1, 0x37, 0x15, 0x26, 0xa0, 0x5a, 0x24, 0x57, 0x66, 0xda, + 0x4d, 0xff, 0x07, 0xa9, 0xb3, 0x7f, 0x81, 0x3b, 0x83, 0x47, 0x91, 0xeb, 0x7c, 0xf2, 0x4b, 0x48, + 0x63, 0x5f, 0x29, 0xb1, 0x58, 0xea, 0x7e, 0x0d, 0x59, 0x1a, 0x1c, 0x3f, 0xff, 0x2c, 0xb3, 0xb5, + 0x9f, 0x0c, 0xb0, 0xd0, 0x76, 0xa4, 0x90, 0xbe, 0x91, 0xbf, 0xa4, 0x22, 0x07, 0xbd, 0x07, 0xc3, + 0x48, 0x0a, 0x5c, 0x5a, 0x7a, 0x07, 0xf1, 0x36, 0x3a, 0xe5, 0x05, 0x66, 0x2e, 0xae, 0xc2, 0x1d, + 0x45, 0x73, 0x1f, 0x69, 0xf4, 0x34, 0xfb, 0xa1, 0x27, 0x48, 0x34, 0x49, 0x03, 0x47, 0xfc, 0xdb, + 0x3b, 0xe1, 0x4f, 0x13, 0x7c, 0xce, 0x62, 0xc5, 0xf2, 0x85, 0x32, 0x63, 0xa8, 0x55, 0x90, 0x30, + 0x0e, 0x77, 0xd5, 0x18, 0xe2, 0x29, 0x3b, 0xf0, 0xef, 0x24, 0x7d, 0xeb, 0xda, 0x81, 0xc6, 0x91, + 0xa1, 0x89, 0xf3, 0x6e, 0x07, 0xa9, 0x8b, 0x9f, 0x91, 0x73, 0xea, 0xb7, 0x93, 0x66, 0xfd, 0x6d, + 0x14, 0x08, 0xb2, 0x44, 0xf2, 0x4d, 0xc2, 0x5b, 0xf7, 0xa8, 0xdf, 0x95, 0x18, 0x4b, 0xd6, 0x3f, + 0x2c, 0xcc, 0x50, 0x8d, 0x6b, 0xa1, 0x67, 0x81, 0xc6, 0x19, 0x6b, 0x83, 0xf2, 0xbc, 0x46, 0x1a, + 0x5e, 0x70, 0x3e, 0xa0, 0xbb, 0xf5, 0x92, 0x6d, 0x1f, 0x22, 0x79, 0xe7, 0x5e, 0xe8, 0x40, 0x47, + 0xfe, 0x82, 0xd6, 0xb0, 0x8c, 0x12, 0x9b, 0x4c, 0x27, 0x21, 0x76, 0xbb, 0xd6, 0x66, 0x5e, 0xfa, + 0xc7, 0x4b, 0x5d, 0x75, 0x2a, 0x26, 0x1e, 0xbc, 0xfc, 0xf6, 0x0b, 0x9c, 0x7a, 0x21, 0x7f, 0x8e, + 0x6b, 0x48, 0x61, 0x73, 0x10, 0xbc, 0x05, 0x10, 0x17, 0x05, 0x0f, 0xd8, 0xa4, 0xdb, 0x92, 0x9b, + 0x89, 0x46, 0xb6, 0xbc, 0x31, 0x04, 0x10, 0x9b, 0x6e, 0xc2, 0xb8, 0x76, 0xd7, 0x12, 0x50, 0x8d, + 0x99, 0xa8, 0x90, 0xfd, 0x9a, 0xf1, 0x69, 0x46, 0xea, 0x9e, 0x0c, 0xa2, 0xf3, 0x58, 0x78, 0x99, + 0x81, 0xda, 0x6c, 0x0a, 0x8a, 0x9a, 0x94, 0xf8, 0x4b, 0x9c, 0x24, 0xe4, 0x7e, 0x2b, 0x48, 0x53, + 0x0f, 0x3b, 0x37, 0xde, 0xb7, 0x63, 0x0d, 0x69, 0x6b, 0x47, 0x53, 0xfb, 0x57, 0x86, 0xc0, 0x32, + 0x11, 0x53, 0xe1, 0xae, 0xb2, 0x5a, 0x2e, 0xf9, 0xb2, 0xb8, 0xce, 0xb6, 0xe3, 0xdd, 0xdf, 0x63, + 0xa3, 0x89, 0xfa, 0x67, 0x90, 0x63, 0xda, 0xd2, 0xc2, 0xed, 0xd3, 0xbe, 0x6b, 0xe2, 0x5f, 0xea, + 0x41, 0xbc, 0x24, 0xa7, 0x8a, 0x50, 0xa9, 0xdb, 0x6f, 0x79, 0x2f, 0xae, 0xc6, 0x7e, 0x1c, 0x50, + 0xc1, 0x0e, 0x92, 0x07, 0xfb, 0xd3, 0x9b, 0xde, 0x4f, 0xc1, 0xa7, 0xdd, 0x74, 0xb6, 0x2a, 0x3f, + 0xbb, 0x80, 0x57, 0xda, 0xe7, 0x5e, 0x9b, 0x37, 0x56, 0xd6, 0x87, 0xe1, 0x7c, 0x02, 0x75, 0xfb, + 0x04, 0x76, 0x88, 0x88, 0xbf, 0x9c, 0x8d, 0x3a, 0xee, 0xac, 0x80, 0xa0, 0x39, 0xac, 0xa0, 0xa0, + 0xc6, 0xeb, 0x29, 0x6c, 0xd7, 0xf1, 0x98, 0xf6, 0x46, 0xc3, 0xf0, 0x2a, 0xac, 0x5c, 0x23, 0x91, + 0x4e, 0x1a, 0x90, 0xc9, 0xe0, 0x5d, 0x89, 0xf9, 0x74, 0x21, 0x3e, 0xb0, 0xfc, 0x84, 0x11, 0x2a, + 0xe3, 0x1f, 0xa0, 0x2e, 0x6c, 0xf8, 0xaf, 0xe4, 0x68, 0x5b, 0x6c, 0x8f, 0x15, 0xd4, 0xc6, 0x00, + 0xcd, 0xa5, 0x6e, 0x4d, 0x96, 0x4e, 0x0d, 0x08, 0x8e, 0x2f, 0x14, 0x12, 0xae, 0xc4, 0x93, 0x96, + 0xa4, 0x7f, 0x8e, 0x71, 0x59, 0xdd, 0xd4, 0xac, 0x41, 0x81, 0x99, 0x23, 0x62, 0xad, 0x35, 0xc4, + 0xab, 0x9a, 0xa7, 0x0c, 0x56, 0xdd, 0x8e, 0x3f, 0x68, 0x8e, 0xb1, 0x52, 0x2a, 0x77, 0x00, 0xbe, + 0xd0, 0x28, 0xb7, 0x47, 0xca, 0x4d, 0x3e, 0xd9, 0xdb, 0x21, 0xec, 0xfa, 0xd7, 0xa9, 0xb6, 0x38, + 0x69, 0x88, 0xc6, 0xbd, 0x68, 0xa3, 0x43, 0x7a, 0x50, 0x61, 0x76, 0x71, 0x96, 0xc8, 0xbb, 0x01, + 0x0d, 0xd8, 0xb9, 0x00, 0x45, 0xbb, 0xe6, 0x92, 0xcc, 0xdc, 0x85, 0xfe, 0x56, 0xf3, 0xac, 0xef, + 0x6b, 0xa2, 0xc2, 0x03, 0x19, 0xec, 0xe3, 0xd1, 0x37, 0x8c, 0x15, 0x07, 0x2b, 0x73, 0x65, 0xd8, + 0xda, 0xc4, 0xee, 0xe9, 0x67, 0xbe, 0x8a, 0x9f, 0xc7, 0x7f, 0x73, 0x8b, 0x54, 0x52, 0x17, 0x8d, + 0xfe, 0x73, 0x98, 0x2e, 0x9f, 0x59, 0x74, 0x9c, 0x86, 0x92, 0x05, 0xc0, 0x1a, 0xfa, 0x38, 0xdc, + 0xb5, 0x29, 0x00, 0xef, 0x27, 0x1a, 0x95, 0x6b, 0x0c, 0x8d, 0x96, 0x04, 0xda, 0x42, 0x69, 0x47, + 0x97, 0x0d, 0x38, 0x9f, 0x65, 0xfe, 0xef, 0xa7, 0xa4, 0x68, 0x92, 0x47, 0x8e, 0x5c, 0xa1, 0x6c, + 0x48, 0xb9, 0xf6, 0xb8, 0x4b, 0xcf, 0x2e, 0xd0, 0xce, 0x26, 0x12, 0xfe, 0x28, 0x19, 0xb0, 0xea, + 0x1c, 0x8f, 0xf3, 0x72, 0x60, 0x69, 0x46, 0x7f, 0xc4, 0xb1, 0xc1, 0xa4, 0xbc, 0x12, 0x13, 0x99, + 0xb9, 0xa3, 0xdc, 0x0f, 0x5e, 0xda, 0xb4, 0xdd, 0x6d, 0xdd, 0x8b, 0x89, 0xe2, 0xa1, 0x07, 0x83, + 0x3a, 0x91, 0x53, 0x8a, 0x94, 0xf4, 0x20, 0x17, 0xaf, 0x26, 0xe2, 0x1c, 0x2a, 0x60, 0x4c, 0x59, + 0x32, 0x72, 0x6a, 0x53, 0x75, 0x94, 0xd7, 0x31, 0x42, 0xf3, 0x53, 0xce, 0x4a, 0xaa, 0x24, 0x0e, + 0x35, 0x7d, 0x69, 0x86, 0x3a, 0x40, 0xa5, 0xaf, 0x0e, 0xa6, 0xb1, 0x5c, 0xb6, 0x73, 0x53, 0xb7, + 0x2d, 0x53, 0xaf, 0xc0, 0x53, 0x3b, 0x6d, 0x9e, 0x09, 0x62, 0x8f, 0x3d, 0x49, 0xde, 0x07, 0x44, + 0x22, 0xee, 0xe1, 0x6c, 0x7c, 0xdf, 0xbc, 0xae, 0xfd, 0xe1, 0x52, 0xd5, 0x87, 0xa6, 0xc9, 0x11, + 0xe1, 0xf7, 0x4b, 0x05, 0x31, 0x92, 0x11, 0xf6, 0x08, 0x21, 0x85, 0xfd, 0x40, 0x62, 0x14, 0xd1, + 0x22, 0x78, 0x6c, 0xad, 0x4a, 0xad, 0x25, 0xa3, 0xf5, 0x05, 0x3b, 0xec, 0x92, 0x6f, 0xb9, 0x37, + 0x71, 0xa2, 0x4f, 0xb8, 0x78, 0x11, 0x45, 0x53, 0x9a, 0xc2, 0xe1, 0x3b, 0x16, 0xde, 0xcf, 0x61, + 0xaf, 0xe4, 0xba, 0x94, 0x05, 0x13, 0x9c, 0xa0, 0x04, 0xb2, 0x1d, 0xd1, 0x88, 0x08, 0x0d, 0x4f, + 0x09, 0xb0, 0xcb, 0xa7, 0x50, 0xa0, 0xd0, 0x89, 0x73, 0x78, 0xfb, 0x52, 0xf5, 0xc2, 0x4b, 0xe0, + 0xfa, 0x94, 0x1f, 0x0b, 0xf2, 0xb2, 0xbc, 0x55, 0x5c, 0xff, 0x02, 0xc2, 0xb9, 0x00, 0xda, 0x6f, + 0xb6, 0x9f, 0xe1, 0x3f, 0xf9, 0xff, 0xad, 0x9e, 0x59, 0xe7, 0xb8, 0x1b, 0x76, 0x5f, 0xa0, 0xbf, + 0x6b, 0xc0, 0xcd, 0xd1, 0xe8, 0xdb, 0x32, 0xe2, 0xb3, 0xee, 0xb2, 0xfc, 0x44, 0x12, 0x0b, 0xac, + 0xc7, 0x74, 0xcf, 0x80, 0xa8, 0x05, 0x00, 0x2e, 0x30, 0x85, 0x44, 0x31, 0x25, 0x30, 0x23, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x81, 0x84, + 0xed, 0xab, 0x56, 0x11, 0x90, 0x73, 0x7a, 0x30, 0x98, 0xe9, 0xd4, 0xae, 0x2b, 0xda, 0xeb, 0xcf, + 0x0e, 0x00, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14, 0x65, 0xfe, 0x32, 0xd1, 0x68, 0x29, 0x33, 0x8a, 0x31, 0x15, 0x0b, 0x40, 0x3c, + 0xf1, 0xc3, 0x17, 0x10, 0xaf, 0xf2, 0xd7, 0x04, 0x08, 0xb2, 0x8a, 0x65, 0x85, 0x2d, 0xcc, 0xd7, + 0x5a, 0x02, 0x02, 0x08, 0x00 +}; + + +unsigned char ECDSA_fails_import_p12[] = { + 0x30, 0x82, 0x07, 0xf8, 0x02, 0x01, 0x03, 0x30, 0x82, 0x07, 0xbf, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, + 0x07, 0xb0, 0x04, 0x82, 0x07, 0xac, 0x30, 0x82, 0x07, 0xa8, 0x30, 0x82, + 0x04, 0xdf, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x06, 0xa0, 0x82, 0x04, 0xd0, 0x30, 0x82, 0x04, 0xcc, 0x02, 0x01, 0x00, + 0x30, 0x82, 0x04, 0xc5, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x32, 0xb1, 0x01, + 0x77, 0xeb, 0x95, 0x02, 0xb9, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x04, + 0x98, 0x8f, 0xa0, 0x71, 0x8a, 0x9a, 0x75, 0x78, 0x29, 0x7e, 0xc9, 0x54, + 0x98, 0xba, 0x58, 0x7f, 0x65, 0x29, 0xb5, 0x9e, 0xb9, 0xc3, 0xfd, 0x9f, + 0xfc, 0x43, 0x31, 0x08, 0x73, 0x45, 0x03, 0x7d, 0xfc, 0x97, 0x20, 0x8f, + 0xb1, 0x4c, 0x85, 0xc3, 0xe9, 0xda, 0xf8, 0x73, 0xbc, 0x77, 0xe5, 0xff, + 0xc7, 0xef, 0x74, 0xc0, 0xb6, 0x18, 0xa9, 0x76, 0x2c, 0x00, 0x2c, 0x00, + 0x9f, 0xcb, 0x34, 0x16, 0x0b, 0xf0, 0x11, 0x7c, 0xc0, 0x65, 0x1c, 0x69, + 0x51, 0xbb, 0x92, 0x86, 0xbf, 0x2e, 0xdf, 0x1e, 0x15, 0xad, 0x1f, 0x66, + 0xdf, 0x5e, 0x9e, 0xb4, 0xf1, 0x9b, 0x86, 0x0d, 0x0f, 0xe6, 0xd2, 0x01, + 0x91, 0x0e, 0x37, 0x43, 0xba, 0x5a, 0xf3, 0x4e, 0x3c, 0x5d, 0xc7, 0x0d, + 0x14, 0x38, 0xc3, 0x4a, 0x10, 0x9a, 0x2d, 0xf8, 0x53, 0x2d, 0xfd, 0x00, + 0xa9, 0x2b, 0xd1, 0x3f, 0xc4, 0xf8, 0x99, 0xb6, 0xaa, 0x1f, 0x70, 0xb4, + 0x2f, 0xa4, 0xa6, 0x07, 0x1a, 0x95, 0xd1, 0x93, 0xf1, 0xd2, 0xfe, 0x3f, + 0x7c, 0xb0, 0x55, 0x18, 0xd5, 0x9f, 0x37, 0x11, 0x3d, 0x2d, 0x1f, 0xb8, + 0xc8, 0x47, 0xa5, 0x03, 0xa5, 0x2e, 0x91, 0x04, 0xe0, 0xd0, 0x15, 0x70, + 0xa2, 0x05, 0xac, 0x71, 0x4a, 0x09, 0x93, 0xbb, 0x44, 0xeb, 0x78, 0x20, + 0x7b, 0xbb, 0x0a, 0x2f, 0x0a, 0x51, 0x5c, 0x16, 0x32, 0x37, 0x82, 0x9e, + 0xc8, 0x90, 0x96, 0xee, 0x9a, 0x4e, 0x77, 0x21, 0xfd, 0x37, 0x80, 0x2f, + 0x55, 0xf2, 0x03, 0xb1, 0x31, 0x7e, 0x9b, 0x90, 0xa9, 0x7b, 0xb4, 0x19, + 0x5d, 0x10, 0xfd, 0x22, 0xa5, 0x07, 0x24, 0xc5, 0xda, 0x86, 0x1e, 0xbd, + 0x4a, 0xa6, 0xc2, 0x02, 0x71, 0xa5, 0x3d, 0xca, 0x5b, 0x19, 0x5d, 0xb6, + 0xc4, 0x7d, 0xe7, 0x74, 0xf5, 0x71, 0xd5, 0xe5, 0x9f, 0x0a, 0x4a, 0x01, + 0xa0, 0xe6, 0xa0, 0x73, 0x93, 0xaa, 0x3b, 0x6c, 0x03, 0x4c, 0xbd, 0x32, + 0xc9, 0x97, 0xaf, 0x84, 0x79, 0x3d, 0x93, 0x49, 0xc6, 0xbc, 0x2a, 0x4f, + 0xe1, 0x3e, 0x9f, 0x86, 0xe3, 0xd2, 0x16, 0xd3, 0xb3, 0xf6, 0xac, 0x3c, + 0xb4, 0x6a, 0xa6, 0x68, 0xb8, 0xf4, 0xe7, 0x68, 0x98, 0xe6, 0xf6, 0x76, + 0x40, 0x64, 0xeb, 0x95, 0xe2, 0xcc, 0x8b, 0x76, 0x4a, 0xab, 0x83, 0xa9, + 0x84, 0x08, 0xf7, 0x43, 0x92, 0xcb, 0x31, 0xd1, 0x0a, 0x90, 0x8b, 0x98, + 0x1d, 0x6a, 0x45, 0x7f, 0x83, 0x9b, 0x01, 0x8d, 0xe8, 0x25, 0x9e, 0x55, + 0xad, 0x27, 0x7e, 0x21, 0xfd, 0x8e, 0xc8, 0x26, 0x1f, 0x43, 0x44, 0x06, + 0x5f, 0x44, 0xbd, 0x5a, 0xf3, 0x15, 0xac, 0x1a, 0x8f, 0xc7, 0x5a, 0x40, + 0xa9, 0x93, 0x09, 0xdc, 0xc4, 0xc9, 0xe9, 0x42, 0xf0, 0xe4, 0xda, 0x29, + 0x90, 0x61, 0x32, 0xcb, 0x05, 0x74, 0x61, 0x71, 0x44, 0xbb, 0x3f, 0x99, + 0xc3, 0x25, 0x29, 0x8c, 0xa1, 0xe1, 0x92, 0xe6, 0xfd, 0x55, 0x8e, 0x22, + 0x37, 0x95, 0x08, 0x59, 0xdc, 0xa2, 0x7c, 0xfc, 0x12, 0x9a, 0x5e, 0x1a, + 0x58, 0x8a, 0x14, 0xa7, 0x96, 0xa2, 0x9e, 0x35, 0xe1, 0x1c, 0x7d, 0xac, + 0x86, 0x1e, 0xcf, 0x1a, 0x35, 0x7a, 0xf1, 0x31, 0x46, 0x67, 0xbd, 0x81, + 0x9c, 0xf5, 0x70, 0x9e, 0xaf, 0x0f, 0x84, 0x10, 0xc9, 0x46, 0xce, 0xb6, + 0xc4, 0x35, 0x88, 0xf0, 0xe1, 0xa6, 0x25, 0xa5, 0xdf, 0x4d, 0x5e, 0x10, + 0x76, 0x2c, 0xa3, 0x85, 0x42, 0x13, 0xe2, 0x34, 0x57, 0xce, 0x8a, 0x96, + 0x1f, 0x1b, 0x78, 0x87, 0xd6, 0x4d, 0x66, 0x36, 0x8e, 0x2c, 0xc6, 0x8b, + 0x0a, 0x53, 0x26, 0x70, 0xa5, 0x7e, 0x7c, 0x7f, 0x94, 0x8b, 0x89, 0x75, + 0x32, 0x1b, 0x8d, 0x27, 0x6f, 0xb1, 0x64, 0x07, 0xa1, 0xbc, 0x34, 0xe4, + 0x9b, 0xb7, 0x96, 0x4a, 0x9b, 0x96, 0xea, 0xc1, 0x4c, 0x13, 0xa8, 0x28, + 0xe3, 0x70, 0xdd, 0x68, 0x2b, 0xf8, 0xd2, 0xe7, 0x1a, 0xec, 0x34, 0xd2, + 0xce, 0x7c, 0x69, 0xc5, 0xe4, 0xde, 0x98, 0x8d, 0x1d, 0x54, 0x21, 0x12, + 0x25, 0x2d, 0xff, 0xbf, 0x1c, 0x97, 0x01, 0x25, 0x2b, 0xbe, 0xad, 0x98, + 0x4a, 0xd3, 0x19, 0x93, 0x9c, 0x03, 0xe6, 0xa4, 0xeb, 0x6c, 0x18, 0x9d, + 0xae, 0xcc, 0xc4, 0xb8, 0x24, 0x2d, 0xa0, 0xc1, 0x70, 0xa3, 0x5c, 0x2f, + 0x6e, 0xee, 0x1c, 0x66, 0x67, 0x43, 0xd8, 0x50, 0x23, 0xe8, 0xd9, 0xb8, + 0x24, 0x98, 0x3a, 0x7d, 0xcf, 0x12, 0x89, 0xae, 0x1a, 0x11, 0x26, 0xa9, + 0x80, 0xef, 0x08, 0x20, 0xf0, 0x11, 0x95, 0xfc, 0xe8, 0xfc, 0xc3, 0x4a, + 0x8b, 0x55, 0x2e, 0xf8, 0x93, 0x6c, 0xe1, 0x82, 0xcb, 0x33, 0xe6, 0xfa, + 0xa1, 0xc2, 0x1d, 0x26, 0xa1, 0x38, 0xc2, 0x12, 0x53, 0x51, 0xa0, 0xbf, + 0xa9, 0x11, 0x57, 0x18, 0x1a, 0x94, 0x28, 0xe6, 0xf6, 0x71, 0x46, 0x02, + 0xd9, 0x1e, 0x1c, 0x07, 0xf4, 0x95, 0xb9, 0xfb, 0x30, 0x79, 0xa6, 0x8a, + 0xe0, 0x0d, 0x35, 0xb6, 0xb4, 0x4f, 0xde, 0x59, 0x35, 0x7c, 0x1a, 0xf9, + 0xcc, 0x42, 0x40, 0xba, 0x58, 0x07, 0xd6, 0x10, 0x20, 0x7d, 0xa4, 0x49, + 0x17, 0x4f, 0x03, 0xa6, 0xaf, 0x30, 0xbd, 0x54, 0x6b, 0x2a, 0xc3, 0x65, + 0x98, 0x71, 0x6c, 0xcc, 0x75, 0x4e, 0xfb, 0x68, 0x14, 0x9d, 0x50, 0xe2, + 0x4f, 0x93, 0x48, 0x2c, 0xc3, 0x37, 0x6c, 0x7e, 0x6a, 0x87, 0x4f, 0x5a, + 0x01, 0xcc, 0x17, 0x54, 0xe7, 0xc0, 0x3d, 0xb3, 0xb4, 0x5f, 0xb9, 0xf1, + 0xcb, 0x5f, 0x9e, 0x48, 0xa2, 0x01, 0x82, 0xb0, 0xd9, 0x01, 0xa8, 0xf9, + 0xac, 0xbe, 0x44, 0x23, 0xb1, 0x43, 0x85, 0xe6, 0x50, 0x64, 0x80, 0xfc, + 0x62, 0xbd, 0xda, 0xef, 0x85, 0xb2, 0x70, 0x8a, 0x0d, 0x5a, 0x62, 0xda, + 0xcc, 0xb3, 0xc1, 0x3a, 0x21, 0xa0, 0x09, 0xfa, 0x64, 0x79, 0xf5, 0xa5, + 0xb6, 0x52, 0x28, 0xb5, 0x2f, 0xbd, 0x9b, 0x98, 0xae, 0x42, 0x32, 0x15, + 0xcc, 0x1a, 0x7d, 0xa6, 0xef, 0x4a, 0xf8, 0x09, 0x72, 0x3e, 0xc3, 0x69, + 0x31, 0x9f, 0x4b, 0x32, 0x73, 0x5f, 0xbf, 0x5f, 0xd5, 0xc3, 0x9f, 0x1e, + 0xcf, 0x6b, 0x0c, 0xde, 0x32, 0x57, 0x1d, 0x1d, 0xc0, 0xf8, 0xe9, 0x85, + 0x8e, 0xd0, 0xf4, 0x86, 0xad, 0xfa, 0x51, 0x07, 0xed, 0x1c, 0xb6, 0x60, + 0x8f, 0xdc, 0x72, 0x61, 0x36, 0x2e, 0x02, 0xf9, 0xe5, 0x3e, 0x14, 0x19, + 0xa5, 0x30, 0xb6, 0x2a, 0x7e, 0xf9, 0xbc, 0x95, 0x82, 0x0f, 0x1b, 0x61, + 0xa5, 0xad, 0x50, 0x38, 0xa1, 0xfe, 0xa8, 0xd0, 0x86, 0x69, 0x40, 0xb9, + 0x82, 0x21, 0xbc, 0x26, 0x9b, 0x87, 0x2f, 0xf6, 0x39, 0x9c, 0x0a, 0x71, + 0x0d, 0x54, 0x68, 0x78, 0xcc, 0x81, 0xaf, 0x09, 0xd7, 0xa2, 0x1c, 0x7a, + 0xfb, 0xfb, 0xae, 0xe0, 0x59, 0x23, 0x0b, 0x8a, 0x5a, 0x9c, 0x4c, 0x9d, + 0x17, 0xfc, 0x52, 0x66, 0x43, 0xbf, 0x06, 0x6c, 0x56, 0x3f, 0xdd, 0x8e, + 0x33, 0x2e, 0xb8, 0xd7, 0xed, 0x13, 0x44, 0x05, 0x5b, 0xbf, 0x43, 0xc7, + 0xfd, 0x6e, 0x41, 0xf4, 0xb8, 0xf0, 0x84, 0x73, 0x60, 0xe4, 0x72, 0x24, + 0x00, 0xec, 0xdf, 0x1b, 0x0d, 0x57, 0x26, 0x04, 0xa0, 0x8c, 0x25, 0x12, + 0xe0, 0xc6, 0x14, 0x0e, 0x69, 0xc2, 0xc8, 0x43, 0x53, 0xc6, 0x66, 0x50, + 0x96, 0x29, 0x50, 0x6d, 0xab, 0x02, 0x29, 0xbd, 0x17, 0xda, 0xd4, 0x5b, + 0xbe, 0xb1, 0xe8, 0x9a, 0x32, 0x3f, 0x39, 0x12, 0x4b, 0x02, 0xb7, 0x8f, + 0x64, 0xca, 0x24, 0x43, 0x2b, 0xee, 0x04, 0xbb, 0xbd, 0x2b, 0x9f, 0x1c, + 0x66, 0xe0, 0x6a, 0xa5, 0xd4, 0x0e, 0x3f, 0x5e, 0xad, 0xe5, 0xc4, 0xcd, + 0x17, 0x71, 0x57, 0x62, 0xe6, 0x7d, 0xe1, 0xc1, 0xd8, 0x3e, 0x38, 0x30, + 0x31, 0x49, 0xb0, 0x8d, 0x64, 0x80, 0x55, 0x30, 0xc4, 0x38, 0x22, 0xad, + 0xc7, 0x8f, 0x1a, 0xbd, 0x30, 0xf8, 0x29, 0xcc, 0xdc, 0x16, 0x6e, 0xf4, + 0x2d, 0xc4, 0x04, 0x49, 0x9a, 0x20, 0xf3, 0x9a, 0xd9, 0xab, 0x31, 0xe4, + 0xb4, 0x0a, 0xce, 0x4e, 0xff, 0xdd, 0xe0, 0x75, 0x59, 0xe5, 0x40, 0x2d, + 0xb5, 0xba, 0xae, 0x73, 0x91, 0x32, 0xba, 0x0d, 0xf3, 0x4a, 0x38, 0xa3, + 0x0c, 0x11, 0xd2, 0x6c, 0x75, 0x80, 0x7a, 0xe4, 0xd5, 0x98, 0x47, 0x05, + 0x66, 0x6c, 0x2e, 0x9d, 0x96, 0xad, 0x99, 0x30, 0xdf, 0xc2, 0x54, 0x5a, + 0x4d, 0xc3, 0x21, 0x80, 0x52, 0xb7, 0x21, 0xa8, 0xb3, 0xd6, 0xe6, 0xf2, + 0xaf, 0xd3, 0x49, 0x3e, 0xff, 0xb2, 0xc2, 0xc9, 0x8b, 0xba, 0x63, 0x6c, + 0xf8, 0x8c, 0x39, 0x16, 0x52, 0x59, 0x86, 0x20, 0x50, 0x3a, 0xe6, 0x0f, + 0x41, 0x13, 0x68, 0xe7, 0x0f, 0x16, 0x58, 0x38, 0xff, 0xb6, 0x26, 0x69, + 0x41, 0x07, 0xeb, 0x21, 0x45, 0xaa, 0xed, 0xae, 0xea, 0xf6, 0xda, 0x00, + 0x72, 0x30, 0x82, 0x02, 0xc1, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x02, 0xb2, 0x04, 0x82, 0x02, 0xae, + 0x30, 0x82, 0x02, 0xaa, 0x30, 0x82, 0x01, 0x51, 0x06, 0x0b, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x81, 0xbc, + 0x30, 0x81, 0xb9, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0x3a, 0xe1, 0x16, + 0x95, 0xa1, 0x45, 0x12, 0xa2, 0x02, 0x02, 0x08, 0x00, 0x04, 0x81, 0x98, + 0x56, 0x4a, 0x5a, 0xd4, 0xf6, 0x2f, 0x5d, 0x91, 0x3d, 0xed, 0x38, 0x21, + 0x90, 0x2a, 0xe1, 0x2d, 0x6e, 0xb5, 0x1c, 0xd9, 0xb0, 0x88, 0xcf, 0xb9, + 0xc7, 0x3a, 0x2b, 0x21, 0xc3, 0xf6, 0x51, 0x91, 0x0c, 0xfb, 0x29, 0x84, + 0xd1, 0x62, 0x5f, 0x75, 0xee, 0xe6, 0xb0, 0x83, 0x4b, 0x9e, 0x55, 0x7b, + 0xdd, 0xd3, 0x9c, 0x36, 0x1f, 0xe8, 0x0a, 0x23, 0x4e, 0x5d, 0xde, 0x11, + 0x71, 0x26, 0xfd, 0x8d, 0x5b, 0xa8, 0x9e, 0x19, 0x2d, 0xbc, 0x2c, 0x75, + 0xfa, 0x0b, 0xa2, 0x4c, 0xe5, 0x07, 0xed, 0x6b, 0x95, 0x3d, 0x75, 0x12, + 0xb2, 0xec, 0xc5, 0x20, 0x5e, 0xfb, 0x5c, 0x0b, 0x68, 0x35, 0x1f, 0xdf, + 0xe0, 0xaa, 0xd5, 0x93, 0x27, 0x3e, 0xa2, 0xed, 0x3f, 0x6d, 0x2c, 0xc0, + 0x6f, 0x55, 0xf0, 0x21, 0xa6, 0xfa, 0x79, 0xce, 0xc5, 0xd6, 0x39, 0xa6, + 0x04, 0xa8, 0x4a, 0xa6, 0x95, 0xf0, 0x7e, 0xe7, 0x54, 0xee, 0xb2, 0x88, + 0xe2, 0x66, 0x5c, 0xb8, 0x5d, 0x3b, 0x90, 0x32, 0x6a, 0xfb, 0x3e, 0xa3, + 0x8b, 0x6b, 0x96, 0xf6, 0x42, 0x55, 0xb3, 0x9f, 0x31, 0x81, 0x82, 0x30, + 0x5b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x14, + 0x31, 0x4e, 0x1e, 0x4c, 0x00, 0x4d, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, + 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, + 0x00, 0x74, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, + 0x00, 0x6e, 0x00, 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x53, + 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, + 0x00, 0x49, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x69, + 0x00, 0x74, 0x00, 0x79, 0x00, 0x31, 0x00, 0x00, 0x30, 0x23, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, + 0x14, 0xf8, 0x15, 0x2d, 0x15, 0x6b, 0x7d, 0x28, 0xe8, 0x23, 0x88, 0xbf, + 0xba, 0xa2, 0x3a, 0x3e, 0x9a, 0x03, 0xe6, 0xc6, 0x89, 0x30, 0x82, 0x01, + 0x51, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, + 0x01, 0x02, 0xa0, 0x81, 0xbc, 0x30, 0x81, 0xb9, 0x30, 0x1c, 0x06, 0x0a, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, + 0x04, 0x08, 0xe3, 0xef, 0x16, 0x96, 0x45, 0x16, 0xe5, 0xb3, 0x02, 0x02, + 0x08, 0x00, 0x04, 0x81, 0x98, 0xf0, 0x1d, 0x35, 0x91, 0xfc, 0x16, 0x43, + 0xaa, 0x1d, 0xb0, 0x58, 0x12, 0xde, 0x69, 0x92, 0xd0, 0xac, 0x96, 0xbe, + 0xc7, 0xbb, 0xb8, 0xb2, 0x44, 0x4e, 0x17, 0xd1, 0xb5, 0xfb, 0x36, 0xea, + 0xd7, 0x06, 0x3a, 0x0e, 0x9a, 0xaa, 0x23, 0xfa, 0x70, 0x51, 0xb9, 0xf9, + 0x90, 0x78, 0xbc, 0xb3, 0x63, 0x48, 0x8c, 0x84, 0xb2, 0xa2, 0x98, 0xc9, + 0x71, 0x46, 0x82, 0x42, 0x9f, 0x0f, 0x7b, 0xcc, 0xbe, 0xcc, 0xad, 0x3c, + 0x30, 0xdb, 0x1d, 0x34, 0xcc, 0x89, 0x91, 0x6b, 0xee, 0x2f, 0x9c, 0x75, + 0x8b, 0x55, 0xff, 0x2e, 0x0b, 0x1d, 0x71, 0x5e, 0xb1, 0xa2, 0xb2, 0x5e, + 0x7e, 0x48, 0x37, 0x2f, 0x08, 0x67, 0x91, 0x9a, 0xf1, 0x05, 0x1c, 0x7a, + 0x7f, 0xee, 0x6f, 0x1e, 0x5b, 0xd9, 0x7c, 0x2d, 0xb8, 0x09, 0x72, 0xb6, + 0x5a, 0xbf, 0x9a, 0xd7, 0x23, 0x39, 0x6f, 0x1f, 0xf8, 0xd5, 0x72, 0x49, + 0xea, 0xab, 0x4b, 0xa0, 0xcb, 0xa3, 0xc7, 0xef, 0xb8, 0x8c, 0xda, 0x4c, + 0x0a, 0x8f, 0xeb, 0x7f, 0x8f, 0x42, 0xd4, 0xad, 0x45, 0x72, 0xda, 0xd9, + 0xc4, 0x31, 0x81, 0x82, 0x30, 0x5b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31, 0x4e, 0x1e, 0x4c, 0x00, 0x4d, 0x00, + 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, + 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00, 0x63, 0x00, + 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x54, 0x00, 0x65, 0x00, + 0x73, 0x00, 0x74, 0x00, 0x53, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, + 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x49, 0x00, 0x64, 0x00, 0x65, 0x00, + 0x6e, 0x00, 0x74, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, 0x31, 0x00, + 0x00, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0xf8, 0x15, 0x2d, 0x15, 0x6b, 0x7d, + 0x28, 0xe8, 0x23, 0x88, 0xbf, 0xba, 0xa2, 0x3a, 0x3e, 0x9a, 0x03, 0xe6, + 0xc6, 0x89, 0x30, 0x30, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x06, 0xfc, 0xc7, 0x98, 0xaf, + 0x81, 0x75, 0x9f, 0x25, 0x05, 0x0c, 0x6d, 0x78, 0xac, 0x4b, 0x31, 0x23, + 0x6c, 0x9b, 0x4d, 0x04, 0x08, 0xf5, 0x1e, 0x85, 0xf5, 0x54, 0xf6, 0x09, + 0x53, 0x02, 0x01, 0x01 +}; +unsigned int ECDSA_fails_import_p12_len = 2044; + +unsigned char ECDSA_fails_import_priv_only[] = { + 0x30, 0x25, 0x02, 0x01, 0x01, 0x04, 0x20, 0x79, 0xf4, 0x38, 0x5c, 0x35, + 0xe1, 0x97, 0xbf, 0xc7, 0x39, 0xc1, 0x2e, 0x40, 0x52, 0x9f, 0xd1, 0xf0, + 0x13, 0xa6, 0x94, 0xc5, 0xdc, 0x3b, 0x14, 0x5b, 0x08, 0x11, 0x28, 0xc5, + 0xb6, 0xc4, 0xd7 +}; +unsigned int ECDSA_fails_import_priv_only_len = 39; + +/* P521 certificate with passcode test!123 */ +unsigned char ec521_host_pfx[] = { + 0x30, 0x82, 0x05, 0x78, 0x02, 0x01, 0x03, 0x30, 0x82, 0x05, 0x3e, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, + 0x05, 0x2f, 0x04, 0x82, 0x05, 0x2b, 0x30, 0x82, 0x05, 0x27, 0x30, 0x82, + 0x03, 0xaf, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x06, 0xa0, 0x82, 0x03, 0xa0, 0x30, 0x82, 0x03, 0x9c, 0x02, 0x01, 0x00, + 0x30, 0x82, 0x03, 0x95, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x6d, 0x27, 0xf1, + 0xd2, 0xe2, 0x19, 0xd9, 0xf2, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x03, + 0x68, 0x50, 0x87, 0xe5, 0xec, 0x26, 0x69, 0xcd, 0xa8, 0xd8, 0xd7, 0x0f, + 0x5b, 0x31, 0xc6, 0xfa, 0x0f, 0x3c, 0x62, 0x47, 0x41, 0xbe, 0x13, 0xab, + 0x0a, 0x53, 0x61, 0xe5, 0x0c, 0x61, 0xc3, 0x0b, 0xd3, 0x64, 0xce, 0xe7, + 0x0e, 0xa6, 0x34, 0xaa, 0xd6, 0x8d, 0x8e, 0xa8, 0x6f, 0xc1, 0xc5, 0xd5, + 0x4f, 0xa1, 0x44, 0xfb, 0x64, 0x5f, 0x21, 0xad, 0x80, 0x4f, 0x74, 0x50, + 0x90, 0x6c, 0x16, 0xeb, 0x0a, 0x98, 0xa1, 0x71, 0x2d, 0x4c, 0x60, 0xf4, + 0x68, 0x1b, 0x4f, 0x89, 0x74, 0xfb, 0xda, 0xdf, 0x73, 0xf6, 0x09, 0x76, + 0x34, 0x7c, 0x25, 0x2f, 0x5e, 0xc2, 0x81, 0xdc, 0x35, 0x08, 0x28, 0xb8, + 0x84, 0x9b, 0x3b, 0x31, 0x52, 0x99, 0x13, 0xf4, 0x79, 0x2d, 0xc5, 0x61, + 0x7e, 0x8b, 0x55, 0x70, 0x37, 0xf9, 0xc1, 0xc5, 0xa8, 0xc6, 0xd6, 0x4b, + 0x01, 0xa7, 0x99, 0x4a, 0xe2, 0xcc, 0xa3, 0xa6, 0xea, 0x4b, 0xb2, 0x21, + 0x08, 0x3b, 0xdf, 0x49, 0xb6, 0x95, 0xcf, 0xca, 0xed, 0xd8, 0x59, 0x8c, + 0x5d, 0xef, 0xec, 0xe9, 0x7f, 0xc0, 0xca, 0xea, 0x0c, 0xee, 0x22, 0x91, + 0x35, 0x69, 0x36, 0xa2, 0x1d, 0x77, 0x74, 0xae, 0xc0, 0x96, 0xbe, 0x7d, + 0x60, 0x96, 0x71, 0xd4, 0x83, 0x29, 0xfc, 0xb2, 0x62, 0x85, 0x1e, 0x18, + 0x15, 0xa3, 0xf2, 0x97, 0xdb, 0xf5, 0x48, 0xd6, 0x2b, 0xcd, 0x36, 0x3f, + 0x96, 0x0e, 0xea, 0x3f, 0x4a, 0x2e, 0x13, 0x19, 0xa9, 0xc6, 0x34, 0x03, + 0xb8, 0x67, 0xd8, 0x39, 0x6b, 0x26, 0xa2, 0x2e, 0x5a, 0x1e, 0x32, 0x8e, + 0x92, 0xe8, 0x26, 0xd5, 0x41, 0x6a, 0x5f, 0x14, 0x57, 0x7d, 0x6e, 0xc6, + 0xbd, 0xec, 0xc1, 0x1c, 0x54, 0x86, 0x9a, 0xde, 0x26, 0x71, 0x22, 0xc8, + 0xa4, 0x48, 0x38, 0x24, 0x5c, 0xd5, 0x45, 0x5a, 0x68, 0x91, 0x1e, 0x7f, + 0xd8, 0x2f, 0xf2, 0x0f, 0x07, 0x4e, 0xe2, 0xd3, 0xea, 0x57, 0xd1, 0xcc, + 0xd8, 0x0c, 0x3f, 0x5f, 0xf4, 0x27, 0xd0, 0xc6, 0x5f, 0x78, 0x7d, 0x26, + 0xc4, 0x0d, 0x33, 0x0f, 0xac, 0xe2, 0xa6, 0xf7, 0x98, 0x08, 0xa5, 0xe7, + 0x85, 0x95, 0x2d, 0xa8, 0x65, 0x0c, 0x80, 0xfe, 0x44, 0x8c, 0xff, 0x57, + 0xd3, 0x2d, 0x09, 0xbf, 0x41, 0x93, 0xea, 0x1d, 0xd7, 0xbd, 0xb8, 0xb1, + 0x9d, 0x08, 0x1e, 0x4f, 0xae, 0x15, 0xf9, 0x2e, 0xfc, 0xfc, 0x2f, 0x0f, + 0xe1, 0x44, 0xfb, 0xac, 0x02, 0xb9, 0x58, 0x65, 0x6c, 0x7a, 0x96, 0xad, + 0x98, 0xda, 0xaf, 0xf9, 0x99, 0x22, 0x83, 0xfe, 0x53, 0x1e, 0x96, 0xae, + 0x5c, 0x89, 0x61, 0x68, 0x46, 0x7b, 0x15, 0x3b, 0x9e, 0xd8, 0xee, 0x29, + 0xe6, 0x9b, 0xd1, 0x16, 0x9f, 0xcd, 0xf7, 0x09, 0x8c, 0xd5, 0x9e, 0xea, + 0x6c, 0x63, 0x31, 0x5b, 0xbd, 0x1d, 0x73, 0xca, 0x88, 0x25, 0xa2, 0x74, + 0x61, 0x78, 0x9a, 0x30, 0x65, 0x1c, 0x8d, 0x8f, 0xb0, 0x33, 0xd6, 0xf4, + 0x25, 0xa1, 0x84, 0xe8, 0x16, 0x29, 0x74, 0x11, 0x75, 0x67, 0xac, 0xaa, + 0xd0, 0x26, 0xfd, 0x67, 0xb5, 0x45, 0x4a, 0xc0, 0x73, 0xeb, 0x73, 0x6e, + 0x73, 0xa1, 0xca, 0x66, 0x45, 0x92, 0xdf, 0x1d, 0xc2, 0xf2, 0x9e, 0x8f, + 0x7f, 0x0e, 0x24, 0x6a, 0xb3, 0xcf, 0xe8, 0x02, 0xcc, 0xdc, 0x61, 0xd2, + 0x34, 0x49, 0x3e, 0xb4, 0x15, 0x9a, 0x68, 0x1b, 0xd5, 0x08, 0x83, 0x98, + 0xe5, 0xae, 0xad, 0xe1, 0x0d, 0x19, 0x24, 0x46, 0xda, 0x4b, 0xa4, 0xf7, + 0x5f, 0x9c, 0x07, 0xc7, 0x89, 0x90, 0xa8, 0x8d, 0x95, 0x28, 0xdc, 0x47, + 0xbd, 0x0d, 0x2b, 0x8f, 0x7f, 0xed, 0x20, 0xdd, 0x68, 0xc1, 0x63, 0x3d, + 0x8d, 0x78, 0x3c, 0xab, 0x91, 0xd3, 0x94, 0x84, 0x4d, 0x4d, 0xf8, 0x56, + 0xdb, 0x73, 0x73, 0xe3, 0x79, 0xb1, 0xbc, 0x06, 0x98, 0x03, 0x50, 0xb6, + 0xbc, 0x8f, 0x89, 0x8c, 0xdb, 0x74, 0xa2, 0x55, 0xc8, 0x61, 0xaf, 0x04, + 0xc7, 0x8b, 0x57, 0xa9, 0x63, 0x60, 0xe5, 0x0b, 0x94, 0x46, 0x15, 0xdb, + 0xa0, 0x35, 0x2d, 0x69, 0x3f, 0x20, 0x9c, 0x65, 0x1e, 0x63, 0xb2, 0xd2, + 0xf2, 0x03, 0xf3, 0x49, 0x4b, 0x8c, 0xc1, 0x13, 0x1e, 0x10, 0x31, 0xb5, + 0xdb, 0xaf, 0xc3, 0x60, 0x18, 0xb1, 0xfd, 0x08, 0x23, 0x47, 0xcc, 0x0b, + 0x55, 0x7f, 0x92, 0x2b, 0xc2, 0xed, 0xbd, 0x0b, 0x59, 0x24, 0xff, 0x1c, + 0xdf, 0xd7, 0x50, 0x2b, 0xc1, 0x1e, 0x48, 0xc1, 0xfd, 0x58, 0x79, 0x18, + 0x11, 0x00, 0x0c, 0xc7, 0x85, 0x00, 0xe9, 0x6d, 0x52, 0x4d, 0xfa, 0x80, + 0x71, 0x68, 0xc7, 0xa7, 0xd5, 0x9d, 0x25, 0x75, 0x3a, 0x64, 0x95, 0x72, + 0x5b, 0x8e, 0xad, 0x7b, 0x9b, 0xcb, 0x32, 0x3e, 0xfb, 0xc0, 0x4e, 0x9b, + 0x17, 0xf7, 0x7e, 0xec, 0xa0, 0x60, 0xbc, 0x5a, 0xed, 0xfb, 0x7e, 0x7b, + 0x77, 0xa3, 0xdb, 0xba, 0x40, 0x02, 0x45, 0x33, 0xcf, 0x2f, 0xd0, 0x79, + 0x56, 0x99, 0xc7, 0x1a, 0x58, 0xcd, 0x0e, 0x5a, 0x84, 0x89, 0xce, 0xc0, + 0x7b, 0xd1, 0x62, 0x6d, 0x11, 0x1d, 0x1f, 0x7a, 0xdf, 0xc8, 0x2d, 0x77, + 0xb7, 0x61, 0x86, 0x5e, 0xd7, 0x6a, 0xe2, 0xec, 0x88, 0xf7, 0x1a, 0xc4, + 0x75, 0x09, 0x12, 0xa7, 0x21, 0x2f, 0xee, 0x5d, 0x2a, 0xd6, 0x84, 0xcd, + 0xf1, 0x2d, 0x2b, 0x11, 0x33, 0xb7, 0xfe, 0x6d, 0x4a, 0xe2, 0x4e, 0x6a, + 0x5e, 0xc6, 0x25, 0xde, 0x77, 0x98, 0x32, 0x62, 0xd1, 0xd2, 0x89, 0xfe, + 0xa4, 0x86, 0x65, 0xd9, 0x70, 0x5d, 0x3d, 0xfa, 0x42, 0xcb, 0xec, 0xe3, + 0xa5, 0x95, 0x6d, 0xa2, 0x66, 0x81, 0x87, 0x0c, 0x90, 0x76, 0x8f, 0xfe, + 0x55, 0xa9, 0x98, 0x8a, 0xfd, 0xc4, 0xd1, 0xfe, 0x72, 0xbc, 0x31, 0x71, + 0x8e, 0xd6, 0x87, 0x93, 0x57, 0xc2, 0x62, 0x66, 0x2e, 0x4f, 0xbe, 0x5f, + 0xc9, 0x22, 0x15, 0x85, 0xd8, 0xaf, 0x75, 0x57, 0x5d, 0xeb, 0xe3, 0x6e, + 0xe6, 0x69, 0x16, 0x45, 0xb2, 0xab, 0xfc, 0xf4, 0x4b, 0x86, 0x3d, 0x13, + 0x71, 0x33, 0xfd, 0xe2, 0x29, 0x7f, 0xdc, 0x2c, 0x2f, 0xed, 0xc9, 0x90, + 0x1e, 0x55, 0x08, 0x91, 0x55, 0x64, 0x8a, 0xc9, 0x6f, 0x33, 0x00, 0x98, + 0xab, 0x1d, 0xa8, 0xd2, 0x24, 0x2a, 0xaa, 0xd5, 0x20, 0x04, 0x69, 0xec, + 0x37, 0xb0, 0x44, 0x0c, 0x00, 0x2e, 0x27, 0x2e, 0x8c, 0xab, 0x20, 0x06, + 0x9d, 0x8a, 0x11, 0x8f, 0x05, 0x54, 0x5f, 0x16, 0x62, 0xb4, 0x8b, 0xec, + 0x88, 0x6f, 0xb0, 0xf1, 0x4f, 0x90, 0x23, 0x71, 0xfb, 0x30, 0x82, 0x01, + 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, + 0xa0, 0x82, 0x01, 0x61, 0x04, 0x82, 0x01, 0x5d, 0x30, 0x82, 0x01, 0x59, + 0x30, 0x82, 0x01, 0x55, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, + 0x19, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0xc2, 0xb9, 0xa1, 0x2f, 0x4c, + 0x19, 0x68, 0x12, 0x02, 0x02, 0x08, 0x00, 0x04, 0x81, 0xf8, 0x34, 0x0f, + 0x2b, 0x67, 0x09, 0xbf, 0xc4, 0xf9, 0x91, 0x76, 0xe3, 0xf2, 0x0e, 0x23, + 0x56, 0x57, 0x30, 0x30, 0x7e, 0x1a, 0x60, 0x7a, 0xd3, 0x57, 0x51, 0xf0, + 0x67, 0x83, 0xde, 0xf0, 0x6b, 0x1a, 0x7c, 0xd9, 0xd4, 0x48, 0xe6, 0xa0, + 0x7f, 0xde, 0xe3, 0xd4, 0x55, 0xcb, 0x0d, 0xcf, 0x8b, 0x21, 0x0d, 0xfa, + 0x65, 0xa1, 0xcb, 0x01, 0x6f, 0x81, 0xd4, 0x0d, 0x1c, 0xbd, 0xa6, 0x4b, + 0xbd, 0x6c, 0xe9, 0xa3, 0x6f, 0xb4, 0x4d, 0x07, 0xc1, 0x19, 0xa3, 0x14, + 0xcd, 0x39, 0xda, 0xd0, 0xa0, 0x2a, 0x62, 0x19, 0x87, 0xb6, 0x7b, 0xe6, + 0xd4, 0xd5, 0x7a, 0x70, 0xe8, 0x37, 0x98, 0xb5, 0xfe, 0xe5, 0xcf, 0x7f, + 0xb1, 0xbe, 0x00, 0x27, 0x83, 0xad, 0xfc, 0x46, 0x64, 0x91, 0xe4, 0x4c, + 0x6f, 0x91, 0xb8, 0xc4, 0xf4, 0x8d, 0x1b, 0x31, 0xdb, 0x51, 0xba, 0xc5, + 0x9c, 0xb0, 0x46, 0xf5, 0x33, 0x01, 0xc4, 0xf7, 0x27, 0x1e, 0x46, 0x79, + 0xa6, 0x76, 0x87, 0x19, 0xa8, 0xb9, 0x06, 0x5a, 0x6f, 0xd4, 0x1b, 0x25, + 0xd8, 0x75, 0x3e, 0x3a, 0x47, 0xde, 0x56, 0x58, 0xd4, 0xf1, 0x21, 0xe4, + 0x1b, 0xdc, 0xaa, 0x82, 0x40, 0xf3, 0x50, 0x3a, 0x9c, 0xb3, 0x93, 0x95, + 0xa7, 0x41, 0xfc, 0x94, 0x41, 0x68, 0x27, 0x20, 0x22, 0x2f, 0x24, 0xb3, + 0xae, 0x71, 0x65, 0x3b, 0x9b, 0xb2, 0x69, 0x95, 0xbb, 0xf5, 0xb6, 0x89, + 0x10, 0xfc, 0x0c, 0xba, 0x43, 0x16, 0x28, 0x4a, 0x69, 0x3c, 0x75, 0xdc, + 0x7f, 0x95, 0x22, 0x00, 0x51, 0xbe, 0x68, 0x07, 0xf6, 0xb4, 0x00, 0x18, + 0xac, 0x6d, 0x6d, 0xc9, 0xd9, 0x66, 0xa6, 0xe3, 0x08, 0x5b, 0x54, 0x37, + 0xe0, 0x79, 0xcd, 0xa5, 0x23, 0x1a, 0x9a, 0xdd, 0xf1, 0xdf, 0x97, 0xbf, + 0xbe, 0xe0, 0x53, 0x80, 0x0e, 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, + 0x14, 0x11, 0xda, 0xbc, 0x66, 0xab, 0x86, 0x80, 0xe5, 0x49, 0x74, 0x47, + 0xda, 0x5a, 0x84, 0x31, 0x69, 0x0a, 0x49, 0xa3, 0x66, 0x30, 0x31, 0x30, + 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, + 0x04, 0x14, 0xa5, 0x4e, 0x8d, 0x67, 0x01, 0x9f, 0x1b, 0x55, 0x63, 0x54, + 0xa7, 0x09, 0x7c, 0x1a, 0x76, 0x48, 0xcd, 0x14, 0x84, 0xc8, 0x04, 0x08, + 0xbd, 0x08, 0x86, 0x2c, 0xe9, 0x77, 0xab, 0xaf, 0x02, 0x02, 0x08, 0x00 +}; + +uint8_t _cert_decode_error_p12[] = { + 0x30, 0x82, 0x0d, 0x2c, 0x02, 0x01, 0x03, 0x30, 0x82, 0x0c, 0xf6, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x0c, 0xe7, 0x04, 0x82, 0x0c, 0xe3, 0x30, 0x82, + 0x0c, 0xdf, 0x30, 0x82, 0x07, 0x77, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x06, 0xa0, 0x82, 0x07, 0x68, 0x30, 0x82, 0x07, 0x64, 0x02, 0x01, 0x00, 0x30, 0x82, 0x07, 0x5d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x6b, 0x80, 0x4a, + 0xe4, 0x8b, 0x9a, 0x82, 0x05, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x07, 0x30, 0x3b, 0x59, 0xf8, + 0x1d, 0x49, 0xdf, 0xd2, 0xc8, 0x54, 0x63, 0xda, 0x5e, 0x91, 0xff, 0x2a, 0xb9, 0x5f, 0x25, 0x2e, + 0x9e, 0x34, 0x3b, 0xa4, 0x4f, 0x89, 0x39, 0xd4, 0xb8, 0xcc, 0x46, 0x0b, 0x55, 0x1e, 0xd3, 0x8b, + 0xb1, 0xd6, 0xc3, 0x74, 0xa3, 0xef, 0xb7, 0xba, 0x46, 0x18, 0x44, 0xb7, 0x68, 0x5f, 0x21, 0xec, + 0x6a, 0x70, 0x25, 0xf3, 0x23, 0xe0, 0x53, 0x9d, 0x9e, 0xc9, 0xe7, 0x36, 0xa2, 0x7a, 0xf0, 0x3c, + 0x04, 0xda, 0xe4, 0xac, 0xe4, 0x60, 0xa4, 0xb9, 0x7e, 0xff, 0x7a, 0x9a, 0xf0, 0x1a, 0x36, 0x37, + 0x92, 0xe8, 0xcc, 0x79, 0x0d, 0x94, 0xd3, 0x95, 0x84, 0xea, 0x50, 0xa3, 0xe3, 0xa4, 0x60, 0x46, + 0xd5, 0x77, 0xe4, 0x5f, 0xa7, 0x6b, 0xf3, 0xce, 0x16, 0x29, 0xf9, 0xcc, 0x7c, 0x67, 0x0d, 0x57, + 0x9f, 0x16, 0x2d, 0xa7, 0x9b, 0x1f, 0xf5, 0x67, 0xc2, 0x3d, 0xf4, 0x38, 0x5f, 0x09, 0x1c, 0xd8, + 0x31, 0xd1, 0xaa, 0x92, 0xa7, 0xff, 0x7f, 0x93, 0xf9, 0xbb, 0xde, 0x55, 0x33, 0xca, 0x9e, 0x55, + 0x2e, 0x21, 0x7c, 0xe2, 0x63, 0xf9, 0x35, 0xcd, 0x42, 0xb0, 0x5b, 0xb6, 0xbd, 0xc3, 0x13, 0x3b, + 0x55, 0x5c, 0xdb, 0x1d, 0xd1, 0xa5, 0xfb, 0x27, 0x80, 0xa5, 0xb4, 0x29, 0xd8, 0xc9, 0xc3, 0x87, + 0xb6, 0xeb, 0x10, 0xa5, 0xca, 0x33, 0x1d, 0x55, 0xeb, 0x94, 0x43, 0xb7, 0x9d, 0x4f, 0x9e, 0x4e, + 0x5a, 0xb9, 0x52, 0xcd, 0x25, 0x4f, 0x45, 0x80, 0x61, 0x06, 0x13, 0x31, 0xa9, 0x80, 0x82, 0x63, + 0x57, 0x90, 0x13, 0x77, 0xfa, 0x9d, 0xb4, 0x01, 0xb7, 0x0d, 0x2d, 0x5b, 0x87, 0x63, 0xd9, 0x56, + 0x96, 0x07, 0x0b, 0xfd, 0x4b, 0xb2, 0x16, 0x4f, 0x01, 0x1d, 0x44, 0x51, 0x33, 0xc3, 0x94, 0x42, + 0x85, 0x1e, 0xa0, 0x42, 0xe3, 0xe2, 0x4b, 0x5a, 0xcc, 0x33, 0x83, 0xd9, 0x77, 0xea, 0x3b, 0x87, + 0xeb, 0x78, 0xb5, 0x0d, 0x85, 0xac, 0x15, 0x85, 0x8c, 0x11, 0xc2, 0x72, 0x98, 0x14, 0x08, 0xbe, + 0xc4, 0x59, 0xd3, 0xac, 0xda, 0x8f, 0xb0, 0x57, 0x38, 0x32, 0x6e, 0x8e, 0x26, 0x83, 0xe7, 0x0b, + 0x17, 0xb8, 0xa8, 0x00, 0x45, 0x68, 0x06, 0xd2, 0x67, 0x97, 0xa0, 0xc1, 0xd6, 0x30, 0xc4, 0x27, + 0x39, 0xf5, 0xa7, 0x9a, 0xbf, 0xa6, 0x24, 0x98, 0xdc, 0xcf, 0xa9, 0xd9, 0x33, 0x34, 0x28, 0xdf, + 0x17, 0x49, 0x1b, 0x21, 0x56, 0xff, 0x44, 0x2e, 0x7e, 0xb9, 0x72, 0xac, 0x25, 0x13, 0x7c, 0xf8, + 0x2e, 0x69, 0xae, 0xa3, 0xb1, 0xa5, 0x26, 0xb3, 0xb3, 0x79, 0x0e, 0x39, 0x95, 0x7f, 0x63, 0x1e, + 0x8c, 0xaa, 0xe0, 0x80, 0xe7, 0x70, 0x57, 0x70, 0x36, 0x03, 0x57, 0x29, 0x7c, 0xca, 0xf9, 0xee, + 0xb8, 0x0e, 0x17, 0x39, 0x2e, 0x71, 0x76, 0xaa, 0xd0, 0xf5, 0x17, 0xd8, 0x42, 0xff, 0xee, 0x0d, + 0xf8, 0xb8, 0x38, 0x4a, 0xb6, 0x20, 0x9e, 0xbb, 0x82, 0x63, 0x72, 0x08, 0x01, 0x5f, 0xb5, 0x8b, + 0x74, 0xe1, 0xa2, 0xdc, 0x7a, 0x3e, 0x1a, 0x7c, 0x4f, 0x4d, 0x2a, 0x63, 0x1d, 0xe8, 0xce, 0x26, + 0xbd, 0xaf, 0x7d, 0xf4, 0xb6, 0x5b, 0x88, 0x77, 0xca, 0x2b, 0xde, 0xc5, 0xdb, 0xa2, 0xdb, 0x44, + 0x85, 0x11, 0xda, 0xe0, 0x17, 0xfe, 0x68, 0x42, 0x60, 0xcc, 0x7a, 0xab, 0xb7, 0x2e, 0x7c, 0x6a, + 0xee, 0x30, 0x59, 0x04, 0xf0, 0xc9, 0x94, 0x84, 0x61, 0xa9, 0x27, 0xa7, 0x81, 0x21, 0xf4, 0x42, + 0x68, 0x58, 0xe9, 0xbe, 0x72, 0x83, 0x46, 0xd4, 0x12, 0xbf, 0xc8, 0x70, 0x87, 0xc6, 0x25, 0x38, + 0xec, 0x1f, 0xe9, 0xe7, 0xc8, 0xfb, 0x3b, 0xdb, 0xfa, 0xcc, 0x4e, 0x50, 0xfb, 0x88, 0x05, 0x13, + 0x59, 0xba, 0x8a, 0x0e, 0xcd, 0x91, 0x10, 0x3e, 0xca, 0xfd, 0x7a, 0x57, 0x13, 0x14, 0x8f, 0x03, + 0x60, 0x31, 0x8e, 0x0b, 0x0c, 0xec, 0x1e, 0x55, 0x4c, 0x87, 0x29, 0x35, 0x6c, 0x2d, 0x28, 0x76, + 0x4d, 0xc9, 0xfc, 0xd6, 0x8e, 0x15, 0x02, 0xab, 0x47, 0x59, 0xbf, 0xe3, 0x7c, 0xfd, 0x1e, 0x11, + 0x9d, 0x53, 0x2a, 0xb7, 0x41, 0xfb, 0x08, 0x8b, 0x95, 0xaf, 0x6e, 0x5f, 0x47, 0x00, 0x97, 0x5b, + 0x53, 0xab, 0x26, 0x8f, 0x1f, 0x1b, 0x5f, 0x53, 0x16, 0x89, 0x21, 0xa9, 0x39, 0x00, 0x05, 0xa2, + 0x9d, 0xd8, 0xff, 0xad, 0xa9, 0x09, 0x5b, 0xe2, 0xd8, 0xf9, 0x35, 0x79, 0xab, 0x83, 0x10, 0xef, + 0xe9, 0x55, 0xdb, 0x70, 0xc9, 0x4f, 0x27, 0x24, 0x04, 0xf2, 0xf8, 0x62, 0x88, 0xa8, 0x02, 0x85, + 0x84, 0x8a, 0xde, 0x85, 0xe0, 0x61, 0x6c, 0x20, 0xa9, 0xde, 0x8d, 0xaf, 0x99, 0x98, 0xde, 0xac, + 0x5b, 0x4d, 0x08, 0xff, 0x1d, 0xb2, 0x44, 0x6b, 0xe0, 0x49, 0x04, 0x57, 0x09, 0x54, 0x59, 0xd5, + 0xe2, 0x2e, 0x4f, 0xc0, 0xe7, 0x6c, 0x02, 0xc1, 0x93, 0x87, 0xa5, 0x77, 0xef, 0xa3, 0xc9, 0xc2, + 0xa2, 0x0c, 0x4c, 0x62, 0xde, 0xf7, 0x5b, 0x6a, 0x84, 0x7e, 0xa6, 0x4e, 0x5e, 0xa6, 0x85, 0x7b, + 0x27, 0x1b, 0x95, 0xab, 0x66, 0x1b, 0x3a, 0xaf, 0x72, 0x07, 0x0a, 0xdf, 0x28, 0xcd, 0x9a, 0xcd, + 0xae, 0xc2, 0x1c, 0x9f, 0xdb, 0xb2, 0xbc, 0x08, 0x41, 0x65, 0xe6, 0x74, 0xce, 0x12, 0xf0, 0x8a, + 0x03, 0x36, 0x62, 0x8c, 0x5b, 0x99, 0xdc, 0xc3, 0xa3, 0x2b, 0x42, 0x14, 0x85, 0xf7, 0x28, 0x9c, + 0x6b, 0xf0, 0x8a, 0x7d, 0x37, 0x70, 0xa2, 0x98, 0x19, 0x73, 0xac, 0x3b, 0x48, 0xf8, 0xf8, 0x3f, + 0x6d, 0x31, 0x63, 0xd6, 0xf4, 0xe1, 0x19, 0x89, 0xec, 0x5d, 0xcf, 0x90, 0x9b, 0x3b, 0x45, 0x54, + 0x8d, 0xcb, 0x2b, 0x44, 0x32, 0x46, 0x70, 0xa0, 0x6a, 0x0c, 0x4f, 0x42, 0x5f, 0x46, 0x34, 0x29, + 0x04, 0xa2, 0x6d, 0xe5, 0x1c, 0xa2, 0xad, 0x59, 0x75, 0x03, 0xb0, 0x5e, 0x64, 0xa8, 0xa5, 0x84, + 0x93, 0x56, 0xa2, 0x32, 0xf8, 0x96, 0x40, 0xf3, 0x72, 0x85, 0xb2, 0xc1, 0x2b, 0xb3, 0xb5, 0x7d, + 0x90, 0x1d, 0xc4, 0x33, 0x1f, 0xf9, 0x9c, 0xf0, 0x11, 0x3e, 0xc8, 0x1d, 0x61, 0x92, 0xb5, 0x6e, + 0xa1, 0x0f, 0x3a, 0x2c, 0x41, 0xb0, 0x67, 0x77, 0x7e, 0xf4, 0x0d, 0xb3, 0x0f, 0xe1, 0x80, 0x97, + 0x4a, 0xd3, 0xa9, 0x23, 0xeb, 0x95, 0x8c, 0x43, 0x34, 0x0a, 0x35, 0xac, 0x15, 0xe8, 0x13, 0x83, + 0xaa, 0x2e, 0x07, 0xa6, 0xc0, 0xce, 0x7e, 0x2a, 0xd8, 0xd4, 0xd4, 0xbf, 0xf5, 0x5c, 0xdf, 0x55, + 0x10, 0x28, 0x1b, 0xea, 0xfe, 0x6d, 0xff, 0xe9, 0x51, 0x02, 0x75, 0x4a, 0x22, 0x5c, 0xd2, 0xf3, + 0xa3, 0xc9, 0x05, 0x4f, 0x95, 0x3e, 0x19, 0xa6, 0xfc, 0x19, 0x92, 0xad, 0xd6, 0xb3, 0x75, 0x9a, + 0x4e, 0xf6, 0xd1, 0xc6, 0x48, 0x6f, 0xd6, 0x7a, 0x21, 0x37, 0x6e, 0xba, 0x25, 0x57, 0x22, 0xd6, + 0x7f, 0x60, 0x28, 0x64, 0x2e, 0xeb, 0xba, 0xb8, 0x36, 0x56, 0xe1, 0xd5, 0xa9, 0xa6, 0x43, 0x4c, + 0xe9, 0x32, 0x38, 0xe1, 0xb0, 0xce, 0x8b, 0xf2, 0x7f, 0xee, 0x67, 0x67, 0x16, 0x8a, 0x74, 0x92, + 0x32, 0x3d, 0xc1, 0x9a, 0x76, 0x22, 0xb2, 0xc4, 0x56, 0xe1, 0x5d, 0xfb, 0xc2, 0x8d, 0xd4, 0x25, + 0xe7, 0xda, 0x52, 0xd1, 0xe4, 0x5e, 0x1f, 0xe8, 0xfa, 0x9d, 0x2b, 0x3e, 0xc5, 0x2b, 0xd7, 0xd7, + 0xc7, 0x01, 0xce, 0x95, 0x67, 0x93, 0x49, 0x42, 0xe1, 0xd2, 0x17, 0xa3, 0x4b, 0x6e, 0xc0, 0xde, + 0x96, 0xa9, 0xd7, 0x07, 0x58, 0xf8, 0xab, 0xe4, 0x79, 0x49, 0x18, 0x12, 0xee, 0x5f, 0xa9, 0x12, + 0xed, 0xfe, 0x49, 0xd6, 0x23, 0xfd, 0xd8, 0xf3, 0xe6, 0x84, 0x5c, 0x4b, 0x4f, 0xc4, 0x66, 0x4d, + 0x26, 0xb5, 0xf6, 0xd9, 0x36, 0xf6, 0x0f, 0x8d, 0xc2, 0x17, 0x15, 0x81, 0x61, 0xb9, 0xaf, 0x24, + 0x71, 0x23, 0xb5, 0x99, 0x87, 0xed, 0x26, 0xcb, 0x4d, 0x08, 0x68, 0x35, 0x07, 0x96, 0xd0, 0x01, + 0xcf, 0xe5, 0x02, 0xdd, 0xc7, 0x6b, 0xcc, 0xc9, 0xab, 0x25, 0x18, 0x4c, 0x71, 0x44, 0x97, 0x47, + 0x23, 0xfa, 0xe4, 0x63, 0x6e, 0x32, 0x2b, 0x9a, 0xe9, 0xf1, 0xc6, 0x7d, 0xd2, 0x41, 0xb0, 0xbe, + 0x6f, 0x5a, 0x1d, 0xa9, 0x79, 0x84, 0x1c, 0x76, 0xbb, 0x76, 0x32, 0xb4, 0x8b, 0xac, 0xc7, 0x38, + 0x95, 0xfd, 0x40, 0x78, 0xd4, 0x44, 0xd5, 0xfc, 0x80, 0x63, 0x6e, 0xbc, 0x2a, 0xf5, 0x3b, 0xfc, + 0xc8, 0x69, 0x59, 0xfe, 0xa2, 0x54, 0x5f, 0xa7, 0xbc, 0xd5, 0x92, 0xeb, 0xaa, 0x1a, 0x82, 0x79, + 0x2a, 0xd5, 0x09, 0xcb, 0xc6, 0x83, 0x50, 0xd5, 0x96, 0x08, 0xe4, 0x6a, 0xf8, 0x88, 0x18, 0x9c, + 0xad, 0x38, 0xf2, 0xae, 0x09, 0x34, 0xdb, 0xd4, 0x2b, 0x52, 0x7d, 0x11, 0xbd, 0xe8, 0xb9, 0x54, + 0xe5, 0xb0, 0x47, 0x74, 0x04, 0xf8, 0x52, 0x0b, 0xf0, 0x17, 0x14, 0x6c, 0xc9, 0xb8, 0x53, 0x81, + 0x56, 0xb8, 0x5c, 0xe2, 0x7e, 0x5a, 0xb0, 0xb8, 0xcd, 0x40, 0xad, 0x8c, 0xfd, 0x3b, 0xcf, 0x96, + 0x62, 0xc5, 0x5d, 0x74, 0x9f, 0xcc, 0xa2, 0x14, 0x87, 0xdb, 0x83, 0x8f, 0xf3, 0xa0, 0xaf, 0x96, + 0xce, 0x6a, 0xd5, 0xfa, 0x72, 0x6d, 0x28, 0x8e, 0x1a, 0x89, 0x38, 0x47, 0x37, 0x6f, 0xf7, 0xf0, + 0xce, 0x9f, 0xae, 0x6c, 0xdf, 0xe8, 0x8c, 0x4d, 0x48, 0x98, 0x97, 0xd1, 0x2e, 0xb3, 0xd3, 0xdc, + 0xbb, 0xdf, 0xdf, 0x27, 0xb3, 0xaa, 0xc9, 0x78, 0xe2, 0xb2, 0xf8, 0xa5, 0x8c, 0x0f, 0x1d, 0xf7, + 0xa4, 0x88, 0xa8, 0xa7, 0x9e, 0xf4, 0xc6, 0x84, 0x74, 0xd4, 0xd3, 0x73, 0x5e, 0xd1, 0x5e, 0xcd, + 0xc5, 0xc5, 0x3e, 0x1d, 0xac, 0x33, 0xc5, 0x4c, 0xa5, 0xe8, 0x47, 0x8b, 0xe8, 0x43, 0x5c, 0x09, + 0xd6, 0x5e, 0xb9, 0x9a, 0x12, 0x2e, 0x47, 0x57, 0xf1, 0xce, 0x4f, 0x03, 0xb6, 0xb4, 0x11, 0xc3, + 0x5b, 0xe9, 0x56, 0x29, 0x2f, 0x05, 0xef, 0x4c, 0xbe, 0xb3, 0xdf, 0x0a, 0xc0, 0x55, 0xef, 0x17, + 0xd3, 0x02, 0x2e, 0xcc, 0x99, 0xab, 0x24, 0x13, 0xb0, 0x11, 0xa1, 0xa4, 0xf3, 0xc8, 0x35, 0xc2, + 0xd5, 0x2c, 0x12, 0x24, 0x5a, 0x21, 0x76, 0x9e, 0xda, 0xe0, 0x51, 0x15, 0x06, 0x06, 0xfd, 0x30, + 0xfd, 0x80, 0x1c, 0x1a, 0xb1, 0xc2, 0xc4, 0x4a, 0xde, 0x95, 0xf0, 0x92, 0xf5, 0x78, 0x3a, 0xdd, + 0xec, 0xdb, 0xae, 0xd9, 0x7f, 0x22, 0xc6, 0x56, 0x7e, 0x92, 0xaf, 0xb4, 0xef, 0xc0, 0x26, 0xb4, + 0x96, 0x93, 0x86, 0x0d, 0xa7, 0xb0, 0x49, 0xce, 0x8b, 0xf9, 0xe5, 0xec, 0x08, 0x2a, 0xa6, 0x9f, + 0x31, 0x73, 0xf1, 0xc6, 0xcf, 0x5c, 0xf8, 0x70, 0xae, 0x02, 0xad, 0xf7, 0x41, 0xa9, 0xee, 0x59, + 0xb3, 0x21, 0x03, 0xcf, 0x99, 0x56, 0x26, 0x81, 0x4a, 0x40, 0xf5, 0x7d, 0xb2, 0xfa, 0x69, 0x5c, + 0x36, 0xf2, 0x58, 0xb0, 0xd2, 0x90, 0xcf, 0x38, 0x56, 0xf8, 0x27, 0xf1, 0x5a, 0xba, 0xbd, 0xb0, + 0xe7, 0x0e, 0xee, 0x8e, 0x45, 0x27, 0x35, 0x1e, 0x88, 0x30, 0xdc, 0xb9, 0x33, 0xa2, 0x30, 0x82, + 0x46, 0x67, 0x8f, 0xdc, 0x8a, 0x93, 0x0f, 0x57, 0x1a, 0xa8, 0x89, 0xcc, 0xbe, 0xaf, 0x69, 0x45, + 0xd4, 0x78, 0x4d, 0xe8, 0x38, 0x64, 0xfc, 0xcc, 0xf9, 0x21, 0x08, 0x8f, 0xe5, 0xf6, 0x88, 0xc3, + 0x7e, 0x1e, 0x7c, 0xca, 0xbb, 0xdf, 0x83, 0xf3, 0x82, 0x02, 0x08, 0xca, 0x94, 0xa5, 0xe0, 0x2d, + 0xe4, 0xcf, 0xa2, 0xd9, 0xb5, 0xd9, 0x3c, 0x9e, 0xcf, 0x2a, 0x78, 0x54, 0x41, 0xc4, 0x17, 0xf6, + 0xda, 0x84, 0x51, 0x2e, 0xee, 0x3b, 0x9a, 0xe0, 0xe6, 0x7a, 0xa1, 0x4f, 0x2d, 0xb3, 0xcb, 0x45, + 0x3d, 0x71, 0xc1, 0xe8, 0xb6, 0x37, 0xa3, 0x4f, 0x86, 0x5f, 0x0b, 0x9b, 0x75, 0xff, 0x02, 0x5a, + 0xc7, 0x01, 0xd3, 0x44, 0x84, 0x4d, 0xdf, 0x1f, 0xe2, 0x0f, 0x77, 0xf6, 0x0d, 0x64, 0xdb, 0x7c, + 0x7e, 0x1e, 0x4a, 0x6b, 0x91, 0xa4, 0xd0, 0x25, 0x67, 0xb5, 0x72, 0xf2, 0x3d, 0xf9, 0x3d, 0x4e, + 0xde, 0x8d, 0x32, 0xca, 0x69, 0x8d, 0xdf, 0x29, 0x84, 0x19, 0xab, 0xfd, 0xe4, 0x8c, 0x6a, 0xa5, + 0xd7, 0xec, 0xac, 0x50, 0x1e, 0x0c, 0xb1, 0x02, 0x76, 0xcf, 0xe0, 0xe5, 0x8e, 0x4f, 0x82, 0xdd, + 0xd5, 0x95, 0x75, 0x88, 0x2a, 0xca, 0x2c, 0x7f, 0x36, 0x16, 0xc6, 0xb8, 0x36, 0x9f, 0x2e, 0x0a, + 0x78, 0x88, 0x77, 0x64, 0xfd, 0x9a, 0x24, 0x49, 0x14, 0x1a, 0x44, 0x48, 0x24, 0x02, 0x65, 0x25, + 0x84, 0x33, 0xe5, 0xb6, 0x3f, 0xf6, 0x43, 0x17, 0x87, 0xf7, 0x7f, 0x67, 0xe1, 0x64, 0xa2, 0xf8, + 0x2a, 0xdc, 0x8a, 0xf6, 0xf1, 0x95, 0xac, 0xd6, 0xa2, 0xd9, 0x50, 0x29, 0x67, 0xeb, 0x93, 0x45, + 0x8f, 0xad, 0x23, 0xcb, 0x2b, 0x26, 0x90, 0xa2, 0x45, 0x28, 0x3e, 0x1e, 0xe9, 0xbf, 0xaa, 0x6b, + 0xdc, 0x83, 0x41, 0xe4, 0xf1, 0x0d, 0x5a, 0x66, 0xd9, 0xd6, 0x41, 0xd0, 0xb2, 0x9c, 0x38, 0x79, + 0xc9, 0xa1, 0x93, 0x6c, 0x26, 0x30, 0x74, 0x0d, 0xcd, 0x28, 0xc9, 0x1b, 0xc8, 0x99, 0x7f, 0x06, + 0x04, 0xf5, 0x34, 0x3d, 0x80, 0x19, 0x1a, 0x88, 0x49, 0xea, 0xe6, 0xc6, 0xb7, 0xe6, 0xe4, 0x28, + 0xe9, 0x8a, 0x4f, 0xe5, 0x61, 0x75, 0xd3, 0x5c, 0xb8, 0x10, 0x1b, 0xa9, 0x85, 0xd8, 0x49, 0x34, + 0xbe, 0x82, 0xa1, 0x67, 0x26, 0xb7, 0x29, 0x5b, 0x03, 0xb3, 0xad, 0x9d, 0x89, 0xfb, 0xf2, 0xc3, + 0xa8, 0xb6, 0x47, 0x9b, 0x4d, 0x9a, 0xa6, 0x3b, 0x45, 0x57, 0xd4, 0xf6, 0x94, 0x5a, 0x3d, 0xd4, + 0x6d, 0xa8, 0x49, 0x97, 0x1d, 0x66, 0x9c, 0x37, 0x3a, 0x5e, 0x38, 0xe1, 0x81, 0x64, 0x30, 0x7d, + 0x86, 0xc7, 0xac, 0xaf, 0xe1, 0x69, 0xf9, 0xce, 0x90, 0xbe, 0x3e, 0x6f, 0x89, 0x30, 0x82, 0x05, + 0x60, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x05, 0x51, + 0x04, 0x82, 0x05, 0x4d, 0x30, 0x82, 0x05, 0x49, 0x30, 0x82, 0x05, 0x45, 0x06, 0x0b, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x04, 0xee, 0x30, 0x82, 0x04, + 0xea, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, + 0x0e, 0x04, 0x08, 0xff, 0x1e, 0xb3, 0x3a, 0xec, 0xa8, 0xad, 0x0e, 0x02, 0x02, 0x08, 0x00, 0x04, + 0x82, 0x04, 0xc8, 0x16, 0x13, 0x24, 0xe3, 0x65, 0x8c, 0xd1, 0xe7, 0xeb, 0x9a, 0x38, 0xd3, 0xf5, + 0xde, 0x9f, 0xc5, 0x60, 0x56, 0xa2, 0x85, 0x31, 0x9c, 0x51, 0xcb, 0x0c, 0xa2, 0xf1, 0x79, 0xb1, + 0xbe, 0xfc, 0x3e, 0x35, 0xb1, 0x98, 0x35, 0x41, 0xc9, 0x3e, 0x55, 0x9d, 0x0d, 0x1e, 0xfe, 0x54, + 0xbb, 0x26, 0x79, 0x69, 0x22, 0xdd, 0x32, 0xab, 0x30, 0x90, 0x7b, 0xf6, 0xdb, 0xab, 0x10, 0xe1, + 0xcd, 0x8f, 0x5a, 0x8a, 0x46, 0x97, 0xb1, 0x3d, 0x61, 0xbd, 0x84, 0x24, 0xf9, 0x70, 0x4b, 0x0e, + 0x40, 0xff, 0x7c, 0x0b, 0x23, 0xa7, 0x46, 0x81, 0x93, 0x4e, 0x77, 0x3f, 0x5b, 0x65, 0x81, 0xc5, + 0x74, 0x8c, 0xa9, 0x42, 0x1c, 0x62, 0x1a, 0xb2, 0xab, 0x6f, 0x3b, 0xa4, 0x50, 0x63, 0x72, 0x31, + 0x31, 0xa3, 0xb7, 0x45, 0x24, 0x5e, 0x04, 0xb1, 0xdb, 0x10, 0x0a, 0xf3, 0x86, 0x24, 0x71, 0x01, + 0xc8, 0xaa, 0x71, 0x49, 0x53, 0x9e, 0xd8, 0x49, 0xd7, 0x58, 0x88, 0xea, 0xac, 0x1a, 0x67, 0xa6, + 0xe6, 0x4d, 0x38, 0x54, 0x6f, 0xb2, 0x3c, 0x9c, 0xda, 0x21, 0x25, 0x80, 0x81, 0xeb, 0xe1, 0x44, + 0x3b, 0xaa, 0x67, 0xc2, 0x37, 0x66, 0x9e, 0x98, 0xf9, 0xc9, 0x86, 0x34, 0x00, 0xc1, 0x75, 0xd6, + 0xa0, 0x1b, 0xa5, 0x46, 0xb9, 0x39, 0xe2, 0x7e, 0xd8, 0x71, 0x9f, 0xa1, 0x63, 0x8b, 0x05, 0xb5, + 0x28, 0x5e, 0x7f, 0x3a, 0xae, 0x8e, 0x11, 0x4d, 0x65, 0x01, 0xac, 0x8d, 0x7a, 0x68, 0xed, 0x09, + 0xb1, 0x89, 0xb7, 0x46, 0x74, 0x06, 0x5b, 0x26, 0x79, 0x74, 0x52, 0xd4, 0x0a, 0x84, 0xc2, 0xbb, + 0x61, 0x71, 0xdc, 0xfd, 0xc0, 0x60, 0x45, 0x67, 0xc1, 0xda, 0x62, 0x6f, 0x12, 0xb0, 0xdd, 0xc7, + 0x67, 0x0f, 0x15, 0x4e, 0x98, 0xc7, 0x21, 0x23, 0x90, 0xa7, 0x25, 0xbe, 0xd1, 0x42, 0xc6, 0x83, + 0x8a, 0xca, 0x5f, 0x3f, 0x22, 0x8f, 0x19, 0xd5, 0xd8, 0xa8, 0xc3, 0x38, 0x20, 0x25, 0xb6, 0x3c, + 0x4c, 0x28, 0x56, 0xa6, 0x22, 0xd3, 0x1f, 0x21, 0x60, 0x7c, 0x34, 0x2d, 0x7b, 0x36, 0xd9, 0x14, + 0x1b, 0xb7, 0x1f, 0x28, 0xf0, 0x8a, 0x27, 0x7e, 0xef, 0x38, 0x96, 0x7d, 0x6a, 0xf1, 0xcf, 0x32, + 0x4d, 0x0d, 0xd0, 0xd2, 0xd5, 0x95, 0x5c, 0xa0, 0x67, 0x45, 0xf0, 0xd9, 0x53, 0x3f, 0x12, 0x76, + 0x1d, 0xe5, 0xa8, 0xa0, 0x41, 0x75, 0xb6, 0x74, 0x1b, 0x9b, 0x44, 0xa0, 0xb1, 0x08, 0xf8, 0x1d, + 0x01, 0x82, 0x05, 0x8a, 0xcc, 0xc2, 0x2a, 0x3c, 0x50, 0xa5, 0xec, 0xed, 0x83, 0xf3, 0x9a, 0xa5, + 0xd3, 0x5f, 0xff, 0x41, 0x02, 0x29, 0xdd, 0x9f, 0x25, 0x2c, 0x8c, 0x11, 0x6c, 0xf0, 0x7a, 0x68, + 0x99, 0x35, 0xf0, 0x5f, 0x03, 0x6a, 0x4d, 0x03, 0x4a, 0xbf, 0x2a, 0x4c, 0xe2, 0x62, 0x32, 0x6b, + 0x41, 0xf8, 0x65, 0xf4, 0xb9, 0x1c, 0x0f, 0x46, 0x00, 0x05, 0x08, 0xaf, 0xfa, 0x63, 0x02, 0xe1, + 0x6c, 0xe5, 0xa2, 0x00, 0xec, 0x65, 0x39, 0x11, 0x54, 0xb9, 0x5c, 0xd7, 0xbd, 0x02, 0xa8, 0x1c, + 0xe9, 0xb2, 0x76, 0x41, 0xb9, 0x9b, 0x87, 0x6b, 0x48, 0x6d, 0xee, 0x46, 0xd2, 0x5f, 0xec, 0xda, + 0x4a, 0x9c, 0xf2, 0x6b, 0x45, 0xd4, 0xa8, 0xd7, 0x9d, 0x39, 0x61, 0x6b, 0x19, 0xb7, 0x4d, 0x9f, + 0x50, 0x71, 0xab, 0x64, 0x5e, 0x24, 0xa2, 0x89, 0x7f, 0x0f, 0x06, 0x4e, 0x84, 0xea, 0x34, 0x64, + 0x63, 0xcc, 0xba, 0x8e, 0x73, 0x1f, 0xdf, 0xff, 0xa7, 0xae, 0xfb, 0x24, 0x6b, 0x84, 0x49, 0x6c, + 0x84, 0xd7, 0x91, 0x79, 0xa8, 0x8f, 0xcc, 0x2b, 0xea, 0xcd, 0x30, 0xd2, 0x19, 0xec, 0x19, 0xc0, + 0xc9, 0x29, 0x17, 0x4d, 0x66, 0xd7, 0xcf, 0x67, 0x1f, 0x97, 0x21, 0x23, 0xd8, 0x07, 0xdf, 0xdd, + 0x39, 0x31, 0x55, 0xa4, 0x45, 0xc9, 0x02, 0x6b, 0x6e, 0xc5, 0xc1, 0x0b, 0x4c, 0xc4, 0xa9, 0xab, + 0x90, 0xa5, 0x79, 0xe7, 0xd9, 0x83, 0x69, 0x7c, 0xe4, 0x23, 0x92, 0x74, 0xdd, 0xd8, 0xa4, 0xbf, + 0x52, 0xa5, 0x6c, 0x47, 0xf1, 0x76, 0xc9, 0x4d, 0xb9, 0x79, 0x4c, 0xae, 0x13, 0xa4, 0x87, 0x1e, + 0x85, 0x7e, 0x7c, 0xcf, 0x40, 0x64, 0x69, 0xfa, 0x19, 0x22, 0xb1, 0x93, 0x38, 0x6e, 0x4b, 0xc3, + 0x20, 0x1d, 0xc9, 0xb7, 0x56, 0x8b, 0x7f, 0x82, 0xca, 0xc6, 0x43, 0x51, 0xb7, 0x08, 0xd4, 0x89, + 0xcd, 0x5a, 0xa0, 0x91, 0xf4, 0x24, 0x31, 0x57, 0x87, 0x00, 0x90, 0x70, 0x9e, 0xd2, 0xa6, 0x14, + 0x4f, 0x5c, 0x60, 0x2f, 0x5d, 0xe9, 0x8a, 0xe6, 0x78, 0x34, 0xb4, 0x77, 0xf7, 0x60, 0xd5, 0x88, + 0x24, 0x3f, 0x42, 0x61, 0xf4, 0x26, 0xf8, 0x71, 0xb5, 0x2c, 0x62, 0xbd, 0x25, 0x11, 0xe3, 0x4f, + 0xa5, 0x80, 0xd0, 0x33, 0x2c, 0x3d, 0xe3, 0xca, 0x08, 0xab, 0xb4, 0x86, 0xd8, 0xaf, 0xcf, 0xd7, + 0x37, 0x83, 0x21, 0x00, 0x1c, 0xe1, 0x2d, 0x1f, 0xea, 0xc5, 0xe9, 0x61, 0xca, 0x2e, 0xe1, 0x38, + 0xb5, 0x6f, 0xec, 0x40, 0x48, 0x56, 0x9b, 0x77, 0x4a, 0xe2, 0xe4, 0xb5, 0x50, 0xbc, 0xb7, 0xcb, + 0x52, 0xd3, 0x43, 0x81, 0xb4, 0x9b, 0xcc, 0xea, 0x86, 0xa5, 0x79, 0x96, 0xe0, 0xc8, 0x22, 0x0f, + 0xc2, 0xdd, 0x02, 0xd0, 0x0e, 0xe0, 0x00, 0x5c, 0xb5, 0xce, 0x51, 0x95, 0xfb, 0xff, 0x49, 0xf4, + 0x95, 0xe1, 0x4d, 0x48, 0xcb, 0x90, 0xba, 0xc8, 0x5d, 0x55, 0x03, 0x9c, 0x1e, 0xaa, 0x50, 0x33, + 0xcc, 0xe8, 0xd0, 0x54, 0x1b, 0x2f, 0x16, 0x76, 0xdb, 0x24, 0x63, 0x74, 0x4b, 0x25, 0xf9, 0x71, + 0xf8, 0x6e, 0xab, 0x9d, 0x31, 0x1e, 0xa4, 0xc6, 0x4f, 0xf6, 0xa8, 0x07, 0x90, 0xd7, 0x69, 0xe5, + 0x85, 0x2c, 0x87, 0x4d, 0x47, 0xd2, 0x6c, 0x9b, 0x43, 0x3f, 0xfd, 0xd9, 0x59, 0x89, 0x1a, 0x8e, + 0x3c, 0x3c, 0xa3, 0xb9, 0x6f, 0x8c, 0x07, 0x2d, 0x02, 0xc0, 0x67, 0xd9, 0x5b, 0x4c, 0x39, 0x56, + 0xab, 0xd9, 0x1b, 0x98, 0x49, 0xf8, 0xa2, 0xc4, 0xcb, 0x3f, 0x5f, 0xae, 0x0e, 0xc4, 0x38, 0xd1, + 0x81, 0xc0, 0xf9, 0x14, 0x89, 0xb5, 0x59, 0xda, 0xe4, 0x47, 0x68, 0x1a, 0x7c, 0xb9, 0x1e, 0x08, + 0x05, 0x8d, 0xc7, 0x70, 0x3d, 0x59, 0xc3, 0x3c, 0x78, 0x39, 0x8e, 0x88, 0x52, 0x65, 0xb9, 0x78, + 0x4e, 0x4e, 0x1a, 0x2e, 0x17, 0x38, 0xc4, 0x1a, 0x23, 0xc2, 0x6f, 0xab, 0x25, 0xbc, 0x65, 0xd2, + 0x16, 0x6c, 0xf3, 0xdc, 0xbd, 0x6d, 0x09, 0xbf, 0x44, 0xdd, 0xe8, 0x6d, 0x71, 0xdc, 0x69, 0x84, + 0x4d, 0x43, 0x87, 0xad, 0xef, 0x1c, 0xf2, 0x12, 0xbb, 0x84, 0x40, 0x59, 0x6c, 0x62, 0x21, 0xed, + 0x41, 0x67, 0x61, 0x51, 0x30, 0xa7, 0x76, 0x2b, 0x95, 0x34, 0x4e, 0x3b, 0x77, 0x62, 0x77, 0x4e, + 0xb6, 0xa4, 0x91, 0x8a, 0x01, 0xd4, 0x95, 0xa8, 0x6b, 0xb4, 0x15, 0xda, 0x78, 0x1b, 0xd0, 0xf9, + 0x4b, 0x93, 0x61, 0x2d, 0x9b, 0x90, 0x7a, 0x85, 0x2e, 0x8a, 0x88, 0xfb, 0x4a, 0x63, 0xa7, 0xe6, + 0xf6, 0x16, 0x64, 0x80, 0x49, 0x3e, 0x13, 0xc5, 0x59, 0x7c, 0xbb, 0xbe, 0x16, 0xf2, 0xab, 0xfa, + 0x00, 0x51, 0x92, 0x26, 0x16, 0x5a, 0x76, 0x08, 0x9d, 0x24, 0xc6, 0x75, 0xd9, 0x59, 0x5c, 0x00, + 0x83, 0x5f, 0x3f, 0xaf, 0x22, 0xe0, 0x1e, 0x13, 0x81, 0xf6, 0xcb, 0xfd, 0x08, 0x92, 0xda, 0x43, + 0xc3, 0xf2, 0xc3, 0x1a, 0xcc, 0xfa, 0x24, 0x1b, 0x27, 0xc2, 0xa8, 0xfe, 0x46, 0x8d, 0x68, 0xb9, + 0x4a, 0xaa, 0x7b, 0x64, 0xab, 0xc4, 0xe3, 0x36, 0xe2, 0x7f, 0x15, 0xee, 0xbe, 0x57, 0xf5, 0x57, + 0xfc, 0xe6, 0x2e, 0x92, 0xf6, 0xc2, 0x9c, 0x61, 0x40, 0x45, 0x32, 0x34, 0xd4, 0xca, 0x82, 0x57, + 0x67, 0x13, 0x43, 0x68, 0xe6, 0x77, 0x18, 0x35, 0x32, 0x26, 0xa7, 0xbd, 0xd9, 0x54, 0x9c, 0xd7, + 0x7b, 0x6a, 0x19, 0xaf, 0x29, 0x53, 0x9e, 0xce, 0x7a, 0x59, 0xb4, 0xc3, 0x4c, 0x19, 0x4d, 0xb8, + 0x5e, 0xd0, 0xd9, 0x03, 0xcd, 0xb8, 0x89, 0x60, 0xff, 0x8e, 0xfd, 0xd1, 0x48, 0x42, 0x89, 0x88, + 0x99, 0xa6, 0xd4, 0xbd, 0x32, 0x2e, 0xfb, 0xd6, 0x91, 0x53, 0xdb, 0x11, 0xa1, 0x8f, 0x01, 0x23, + 0x7c, 0xb1, 0x14, 0xc0, 0x29, 0x58, 0x1d, 0xfd, 0xc3, 0x7a, 0x9d, 0x03, 0xdd, 0x0a, 0x47, 0x2e, + 0xcd, 0x00, 0xa6, 0x74, 0x90, 0x12, 0x27, 0x18, 0x27, 0x4c, 0x12, 0x55, 0x2d, 0xd8, 0x6f, 0x27, + 0x91, 0xc5, 0x40, 0x33, 0x8d, 0x85, 0x34, 0xb0, 0x82, 0xf7, 0x55, 0x2b, 0x17, 0x6d, 0xc1, 0xb6, + 0x98, 0x7f, 0xfd, 0x63, 0x02, 0x56, 0xde, 0xa0, 0x49, 0x51, 0x05, 0xfe, 0x3b, 0x38, 0x74, 0x2b, + 0x8d, 0xa6, 0xe3, 0xb6, 0x6c, 0xe5, 0xd9, 0x06, 0x50, 0x71, 0xee, 0xd2, 0xbf, 0x1f, 0x07, 0x96, + 0x21, 0x27, 0x10, 0x5a, 0xdd, 0x07, 0xa0, 0xbd, 0x23, 0xc3, 0xb6, 0x8b, 0xdf, 0x2e, 0x35, 0x00, + 0x6c, 0xdc, 0x0b, 0xca, 0xfc, 0xf0, 0x0a, 0xd1, 0x04, 0x2d, 0x97, 0x34, 0xe9, 0xf2, 0xf4, 0x89, + 0xa4, 0x73, 0x49, 0xb5, 0x8a, 0xf4, 0xb9, 0xd2, 0x70, 0x26, 0xb7, 0x31, 0x44, 0x30, 0x1d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31, 0x10, 0x1e, 0x0e, 0x00, 0x43, + 0x00, 0x6c, 0x00, 0x69, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x31, 0x30, 0x23, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x54, 0x88, 0x24, + 0x02, 0x6a, 0x0d, 0x83, 0x45, 0xe6, 0xc1, 0x87, 0x43, 0xfb, 0xa1, 0x2c, 0x95, 0x13, 0xf9, 0xf9, + 0x43, 0x30, 0x2d, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, + 0x04, 0x14, 0xcb, 0x7e, 0xf1, 0x39, 0xd9, 0x1a, 0x46, 0x90, 0x77, 0x8d, 0xf6, 0x83, 0x08, 0xb8, + 0xc7, 0xe4, 0x33, 0x24, 0x7c, 0x7d, 0x04, 0x08, 0x24, 0xf3, 0xf9, 0x99, 0x7a, 0xec, 0xae, 0x64 +}; + +#endif /* si_61_pkcs12_h */ diff --git a/OSX/sec/Security/Regressions/secitem/si-64-ossl-cms.c b/OSX/sec/Security/Regressions/secitem/si-64-ossl-cms.c index e34a7621..b136beec 100644 --- a/OSX/sec/Security/Regressions/secitem/si-64-ossl-cms.c +++ b/OSX/sec/Security/Regressions/secitem/si-64-ossl-cms.c @@ -33,12 +33,13 @@ #include #include #include +#include #include #include #include -#include "Security_regressions.h" +#include "shared_regressions.h" /* openssl req -new -newkey rsa:512 -x509 -nodes -subj "/O=foo/CN=bar" -out signer.pem @@ -150,13 +151,19 @@ static void tests(void) SecTrustRef trust = NULL; ok_status(SecCMSVerifyCopyDataAndAttributes(attached_signed_data, NULL, policy, &trust, NULL, NULL), "verify attached data"); - CFRelease(trust); + CFReleaseNull(trust); ok_status(SecCMSVerifyCopyDataAndAttributes(detached_signed_data, detached_data, policy, &trust, NULL, NULL), "verify detached data"); - CFRelease(trust); - ok_status(SecCMSVerifyCopyDataAndAttributes(attached_no_data_signed_data, NULL, policy, &trust, NULL, NULL), "verify attached no data"); - CFRelease(trust); + CFReleaseNull(trust); +#if TARGET_OS_IPHONE + /* iOS supports empty data */ + ok_status(SecCMSVerifyCopyDataAndAttributes(attached_no_data_signed_data, NULL, policy, &trust, NULL, NULL), "verify attached no data"); +#else + /* macOS does not */ + is_status(SecCMSVerifyCopyDataAndAttributes(attached_no_data_signed_data, NULL, policy, &trust, NULL, NULL), errSecAuthFailed, "verify attached no data"); +#endif + CFReleaseNull(trust); ok_status(SecCMSVerifyCopyDataAndAttributes(attached_no_data_signed_data, no_data, policy, &trust, NULL, NULL), "verify attached no data"); - CFRelease(trust); + CFReleaseNull(trust); SecCertificateRef cert = NULL; @@ -164,9 +171,15 @@ static void tests(void) SecIdentityRef identity = NULL; isnt(cert = SecCertificateCreateWithBytes(NULL, signer_der, signer_der_len), NULL, "create certificate"); - isnt(privKey = SecKeyCreateRSAPrivateKey(NULL, privkey_der, privkey_der_len, kSecKeyEncodingPkcs1), NULL, "create private key"); + CFDataRef keyData = CFDataCreate(NULL, privkey_der, privkey_der_len); + CFMutableDictionaryRef keyAttrs = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(keyAttrs, kSecAttrKeyType, kSecAttrKeyTypeRSA); + CFDictionaryAddValue(keyAttrs, kSecAttrKeyClass, kSecAttrKeyClassPrivate); + isnt(privKey = SecKeyCreateWithData(keyData, keyAttrs, NULL), NULL, "Create private key"); isnt(identity = SecIdentityCreate(NULL, cert, privKey), NULL, "create identity"); CFReleaseSafe(privKey); + CFReleaseNull(keyData); + CFReleaseNull(keyAttrs); CFMutableDataRef cms_data = CFDataCreateMutable(kCFAllocatorDefault, 0); ok_status(SecCMSCreateSignedData(identity, detached_data, NULL, NULL, cms_data), "create attached data"); @@ -174,21 +187,28 @@ static void tests(void) CFDataSetLength(cms_data, 0); CFDictionaryRef detached_cms_dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&kSecCMSSignDetached, (const void **)&kCFBooleanTrue, 1, NULL, NULL); ok_status(SecCMSCreateSignedData(identity, detached_data, detached_cms_dict, NULL, cms_data), "create attached data"); - CFRelease(detached_cms_dict); + CFReleaseNull(detached_cms_dict); //write_data("/var/tmp/detached", cms_data); CFDataSetLength(cms_data, 0); - ok_status(SecCMSCreateSignedData(identity, NULL, NULL, NULL, cms_data), "create attached data"); +#if TARGET_OS_IPHONE + /* iOS supports empty data */ + ok_status(SecCMSCreateSignedData(identity, NULL, NULL, NULL, cms_data), "create attached data"); +#else + /* macOS does not */ + is_status(SecCMSCreateSignedData(identity, NULL, NULL, NULL, cms_data), errSecParam, "create attached data"); +#endif + //write_data("/var/tmp/empty_attached", cms_data); CFReleaseSafe(cms_data); CFReleaseSafe(cert); CFReleaseNull(identity); - CFRelease(attached_signed_data); - CFRelease(detached_signed_data); - CFRelease(attached_no_data_signed_data); - CFRelease(detached_data); - CFRelease(no_data); - CFRelease(policy); + CFReleaseSafe(attached_signed_data); + CFReleaseSafe(detached_signed_data); + CFReleaseSafe(attached_no_data_signed_data); + CFReleaseSafe(detached_data); + CFReleaseSafe(no_data); + CFReleaseSafe(policy); } int si_64_ossl_cms(int argc, char *const *argv) diff --git a/OSX/sec/Security/Regressions/secitem/si-65-cms-cert-policy.c b/OSX/sec/Security/Regressions/secitem/si-65-cms-cert-policy.c index 3a27b583..fc816b47 100644 --- a/OSX/sec/Security/Regressions/secitem/si-65-cms-cert-policy.c +++ b/OSX/sec/Security/Regressions/secitem/si-65-cms-cert-policy.c @@ -27,7 +27,7 @@ #include #include #include -#include "Security_regressions.h" +#include "shared_regressions.h" const uint8_t root_ca[] = { diff --git a/OSX/sec/Security/Regressions/secitem/si-66-smime.c b/OSX/sec/Security/Regressions/secitem/si-66-smime.c index d554103f..e02ffeef 100644 --- a/OSX/sec/Security/Regressions/secitem/si-66-smime.c +++ b/OSX/sec/Security/Regressions/secitem/si-66-smime.c @@ -21,6 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ +#include #include #include #include @@ -55,6 +56,7 @@ #include "shared_regressions.h" #include "si-66-smime/signed-receipt.h" +#include "si-66-smime/smime_attr_emails.h" uint8_t message_hash[] = { 0x61, 0x49, 0xAE, 0x84, 0xA6, 0xE6, 0xDE, 0x73, @@ -2437,7 +2439,7 @@ int writeFile( int fd; fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600); - if(fd < 0) { + if(fd == -1) { return errno; } rtn = (int)lseek(fd, 0, SEEK_SET); @@ -2530,15 +2532,17 @@ static void tests(void) self_key, self_val, array_size(self_key), NULL, NULL); const void * cn[] = { kSecOidCommonName, CFSTR("Root CA") }; - CFArrayRef cn_dn = CFArrayCreate(kCFAllocatorDefault, cn, 2, NULL); - CFArrayRef rdns = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_dn, 1, NULL); + CFArrayRef cn_atv = CFArrayCreate(kCFAllocatorDefault, cn, 2, NULL); + CFArrayRef cn_rdn = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_atv, 1, NULL); + CFArrayRef rdns = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_rdn, 1, NULL); SecCertificateRef cert = SecGenerateSelfSignedCertificate(rdns, self_signed_parameters, publicKey, privateKey); CFReleaseNull(subject_alt_names); CFReleaseNull(key_usage_num); CFReleaseSafe(rdns); - CFReleaseNull(cn_dn); + CFReleaseNull(cn_rdn); + CFReleaseNull(cn_atv); CFReleaseSafe(self_signed_parameters); SECOidTag algorithmTag; int keySize; @@ -2686,11 +2690,192 @@ static void tests(void) CFReleaseNull(msg); } +#if TARGET_OS_OSX +static OSStatus +SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd, + SecCmsDigestContextRef digestContext) +{ + SecAsn1Item * *digests; + + PLArenaPool *arena = NULL; + + if ((arena = PORT_NewArena(1024)) == NULL) + goto loser; + + if (SecCmsDigestContextFinishMultiple(digestContext, (SecArenaPoolRef)arena, &digests) != SECSuccess) + goto loser; + + SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(sigd); + if(digestAlgorithms == NULL) { + goto loser; + } + + if (SecCmsSignedDataSetDigests(sigd, digestAlgorithms, digests) != SECSuccess) + goto loser; + + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } + return 0; +loser: + if (arena) + PORT_FreeArena(arena, PR_FALSE); + return errSecInternal; +} + +#endif + +static void testEncKeyPrefs(uint8_t *content, size_t content_length, uint8_t *signature, size_t sig_length) { + SecCmsDecoderRef decoder = NULL; + SecCmsMessageRef cmsg = NULL; + SecCmsContentInfoRef cinfo = NULL; + SecCmsSignedDataRef sigd = NULL; + SecCmsSignerInfoRef signerinfo = NULL; + SecPolicyRef policy = NULL; + SecTrustRef trust = NULL; + SecCertificateRef cert = NULL; + SECAlgorithmID **digestalgs = NULL; + SecCmsDigestContextRef digcx = NULL; + + /* Decode the message */ +#if TARGET_OS_IPHONE + require_noerr_action(SecCmsDecoderCreate(NULL, NULL, NULL, NULL, + NULL, NULL, &decoder), out, + fail("Failed to create decoder")); +#else + require_noerr_action(SecCmsDecoderCreate(NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &decoder), out, + fail("Failed to create decoder")); +#endif + require_noerr_action(SecCmsDecoderUpdate(decoder, signature, sig_length), out, + fail("Failed to add data ")); + OSStatus status = SecCmsDecoderFinish(decoder, &cmsg); + decoder = NULL; // SecCmsDecoderFinish always frees the decoder + require_noerr_action(status, out, fail("Failed to finish decoder")); + + /* Get the signed data */ + require_action(cinfo = SecCmsMessageContentLevel(cmsg, 0), out, + fail("Failed to get content info")); + require_action(SEC_OID_PKCS7_SIGNED_DATA == SecCmsContentInfoGetContentTypeTag(cinfo), out, + fail("Content type was pkcs7 signed data")); + require_action(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out, + fail("Failed to get signed data")); + + /* Set the detached message content */ + require_action(!SecCmsSignedDataHasDigests(sigd), out, + fail("Signed data has content already")); + require_action(digestalgs = SecCmsSignedDataGetDigestAlgs(sigd), out, + fail("Failed to get digest algorithms")); + require_action(digcx = SecCmsDigestContextStartMultiple(digestalgs), out, + fail("Failed to create digest context")); + SecCmsDigestContextUpdate(digcx, content, content_length); + require_noerr_action(SecCmsSignedDataSetDigestContext(sigd, digcx), out, + fail("Failed to set digest context")); + + /* Verify the signature */ + require_action(policy = SecPolicyCreateBasicX509(), out, + fail("Failed to create basic policy")); + require_noerr_action(SecCmsSignedDataVerifySignerInfo(sigd, 0, NULL, policy, &trust), out, + fail("Failed to verify signature")); + + /* Get the Encryption Key Preference certificate */ + require_action(signerinfo = SecCmsSignedDataGetSignerInfo(sigd, 0), out, + fail("Failed to get signer info")); + ok(cert = SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(signerinfo), + "Failed to get encryption key preference cert"); + +out: + if (decoder) { SecCmsDecoderDestroy(decoder); } + if (cmsg) { SecCmsMessageDestroy(cmsg); } +#if TARGET_OS_IPHONE + if (digcx) { SecCmsDigestContextDestroy(digcx); } +#endif + CFReleaseNull(policy); + CFReleaseNull(trust); + CFReleaseNull(cert); +} + +static void test_smime_attrs(void) { + testEncKeyPrefs(_thunderbird_ua_content, sizeof(_thunderbird_ua_content), _thunderbird_ua_cms, sizeof(_thunderbird_ua_cms)); + testEncKeyPrefs(_outlook15_ua_content, sizeof(_outlook15_ua_content), _outlook15_ua_cms, sizeof(_outlook15_ua_cms)); +} + +static void test_sign_no_priv(void) { + SecIdentityRef signer = NULL; + SecCertificateRef cert = NULL; + SecKeyRef publicKey = NULL, privateKey = NULL; + + SecCmsMessageRef cmsg = NULL; + SecCmsContentInfoRef cinfo = NULL; + SecCmsSignedDataRef sigd = NULL; + + const void *keygen_keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits }; + const void *keygen_vals[] = { kSecAttrKeyTypeRSA, CFSTR("2048") }; + CFDictionaryRef parameters = CFDictionaryCreate(kCFAllocatorDefault, + keygen_keys, keygen_vals, array_size(keygen_vals), + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); + + ok_status(SecKeyGeneratePair(parameters, &publicKey, &privateKey), "generate key pair"); + CFReleaseNull(parameters); + + CFMutableDictionaryRef subject_alt_names = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(subject_alt_names, CFSTR("rfc822name"), CFSTR("xey@nl")); + int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment; + CFNumberRef key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage); + const void *self_key[] = { kSecCertificateKeyUsage, kSecSubjectAltName }; + const void *self_val[] = { key_usage_num, subject_alt_names }; + CFDictionaryRef self_signed_parameters = CFDictionaryCreate(kCFAllocatorDefault, + self_key, self_val, array_size(self_key), NULL, NULL); + + const void * cn[] = { kSecOidCommonName, CFSTR("Root CA") }; + CFArrayRef cn_atv = CFArrayCreate(kCFAllocatorDefault, cn, 2, NULL); + CFArrayRef cn_rdn = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_atv, 1, NULL); + CFArrayRef rdns = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_rdn, 1, NULL); + cert = SecGenerateSelfSignedCertificate(rdns, self_signed_parameters, publicKey, privateKey); + + // Bear with us here: the function parameters are slightly different on macOS + ok(signer = SecIdentityCreate(kCFAllocatorDefault, cert, publicKey), "identity"); +#if TARGET_OS_IPHONE + ok(cmsg = SecCmsMessageCreate(), "create message"); +#else + ok(cmsg = SecCmsMessageCreate(NULL), "create message"); +#endif + ok(sigd = SecCmsSignedDataCreate(cmsg), "create signed message"); + ok(cinfo = SecCmsMessageGetContentInfo(cmsg), "get content info"); +#if TARGET_OS_IPHONE + ok_status(SecCmsContentInfoSetContentSignedData(cinfo, sigd), "signed message into message"); +#else + ok_status(SecCmsContentInfoSetContentSignedData(cmsg, cinfo, sigd), "signed message into message"); +#endif + ok(cinfo = SecCmsSignedDataGetContentInfo(sigd), "reset content info"); +#if TARGET_OS_IPHONE + ok_status(SecCmsContentInfoSetContentData(cinfo, NULL, false), "attached"); + is(SecCmsSignerInfoCreate(sigd, signer, SEC_OID_SHA1), NULL, "set up signer with no private key"); +#else + ok_status(SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, false), "attached"); + is(SecCmsSignerInfoCreate(cmsg, signer, SEC_OID_SHA1), NULL, "set up signer with no private key"); +#endif + + CFReleaseNull(cert); + CFReleaseNull(publicKey); + CFReleaseNull(privateKey); + CFReleaseNull(subject_alt_names); + CFReleaseNull(key_usage_num); + CFReleaseNull(self_signed_parameters); + CFReleaseNull(cn_atv); + CFReleaseNull(cn_rdn); + CFReleaseNull(rdns); + CFReleaseNull(signer); + if (cmsg) SecCmsMessageDestroy(cmsg); +} + int si_66_smime(int argc, char *const *argv) { - plan_tests(33); + plan_tests(33+2+9); tests(); + test_smime_attrs(); + test_sign_no_priv(); return 0; } diff --git a/OSX/sec/Security/Regressions/secitem/si-66-smime/smime_attr_emails.h b/OSX/sec/Security/Regressions/secitem/si-66-smime/smime_attr_emails.h new file mode 100644 index 00000000..8a77186f --- /dev/null +++ b/OSX/sec/Security/Regressions/secitem/si-66-smime/smime_attr_emails.h @@ -0,0 +1,1322 @@ +unsigned char _thunderbird_ua_content[] = { + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, + 0x74, 0x3d, 0x49, 0x53, 0x4f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, 0x31, 0x0d, 0x0a, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x64, 0x2d, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x68, 0x65, 0x72, + 0x65, 0x2e, 0x0d, 0x0a, 0x2d, 0x2d, 0x3d, 0x32, 0x30, 0x0d, 0x0a, 0x0d, 0x0a + +}; + +unsigned char _thunderbird_ua_cms[] = { + 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x80, 0x30, + 0x80, 0x02, 0x01, 0x01, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x00, 0x00, + 0xa0, 0x82, 0x2e, 0xc3, 0x30, 0x82, 0x05, 0x2e, 0x30, 0x82, 0x04, 0x16, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x02, 0x0a, 0xa4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, + 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, + 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x43, 0x41, + 0x2d, 0x32, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x31, 0x34, 0x31, + 0x38, 0x31, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x33, 0x32, 0x33, 0x31, 0x34, 0x31, 0x34, + 0x34, 0x30, 0x5a, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, + 0x2e, 0x20, 0x47, 0x4f, 0x56, 0x45, 0x52, 0x4e, 0x4d, 0x45, 0x4e, 0x54, 0x31, 0x0c, 0x30, 0x0a, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x4f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x07, 0x4e, 0x53, 0x41, 0x2f, 0x43, 0x53, 0x53, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x1a, 0x42, 0x4c, 0x41, 0x4e, 0x4b, 0x2e, 0x4a, 0x45, 0x46, 0x46, 0x52, + 0x45, 0x59, 0x2e, 0x44, 0x2e, 0x39, 0x30, 0x30, 0x30, 0x30, 0x33, 0x34, 0x35, 0x34, 0x38, 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, 0x83, 0x96, 0xe3, 0x9b, 0xa1, 0x68, 0x46, 0x5a, 0xd1, 0xf4, 0x52, 0x25, 0xda, 0x47, 0x17, + 0x35, 0xfb, 0xc8, 0xcf, 0xa1, 0x31, 0x96, 0x5c, 0x06, 0x6a, 0x72, 0x8d, 0x60, 0x54, 0x1c, 0xcb, + 0x68, 0x1e, 0x48, 0x79, 0xd6, 0x76, 0xc1, 0x2c, 0xc0, 0x20, 0x06, 0xdd, 0x74, 0xd4, 0x0f, 0x23, + 0x3a, 0x30, 0x6e, 0x0d, 0x8a, 0xaa, 0x1d, 0xb0, 0x33, 0xbb, 0xc9, 0x98, 0xc2, 0xb8, 0xea, 0x84, + 0x7c, 0x16, 0x0e, 0xca, 0x3f, 0x77, 0x4f, 0x51, 0x55, 0xaa, 0xd3, 0xbb, 0x0c, 0x29, 0x6b, 0xd9, + 0x9f, 0x2d, 0x23, 0x4b, 0x3b, 0x1f, 0xb4, 0x3d, 0x77, 0xa8, 0x8e, 0x3c, 0x2d, 0x26, 0xa4, 0x08, + 0x50, 0xc4, 0xc0, 0x95, 0x73, 0x45, 0x64, 0x88, 0x1c, 0xd9, 0xcb, 0x21, 0x88, 0xbf, 0x34, 0xc5, + 0x26, 0x5a, 0xe3, 0x6a, 0xb9, 0xe8, 0x42, 0x23, 0x77, 0xf6, 0x4c, 0xc3, 0x50, 0xfe, 0xe5, 0xca, + 0xde, 0xdd, 0x59, 0xb5, 0x6f, 0x45, 0x3c, 0x9d, 0x0d, 0x0c, 0xe9, 0x3f, 0x42, 0x08, 0xc4, 0x08, + 0x11, 0xb3, 0x66, 0x2e, 0x5c, 0xc0, 0x39, 0x97, 0xc4, 0x97, 0x19, 0x98, 0x10, 0xb8, 0xa3, 0x2b, + 0x1c, 0x5f, 0x3b, 0x9e, 0x61, 0xe4, 0xe1, 0x44, 0xef, 0x02, 0x0a, 0xaf, 0xa8, 0xfe, 0x98, 0x32, + 0x88, 0x5e, 0x32, 0x49, 0x5a, 0xd2, 0x30, 0x1d, 0x52, 0xb3, 0xab, 0x60, 0x8c, 0x0b, 0xe8, 0x5f, + 0x4f, 0x03, 0x45, 0x52, 0x1a, 0x99, 0xfd, 0xb7, 0x4a, 0x26, 0x65, 0x0d, 0x04, 0x3a, 0x8b, 0x36, + 0x81, 0xb2, 0x29, 0xbd, 0xed, 0xe2, 0xde, 0xd9, 0xae, 0x01, 0x47, 0x39, 0x10, 0x03, 0x87, 0x79, + 0xf0, 0x10, 0x05, 0x93, 0x5e, 0xdb, 0x00, 0xf9, 0xf1, 0x73, 0xaf, 0xb2, 0x41, 0xaa, 0x24, 0x36, + 0xcf, 0x35, 0xfd, 0x5b, 0xaa, 0x8f, 0xe5, 0x57, 0xe2, 0x34, 0xa8, 0x6a, 0xdd, 0x42, 0x20, 0x25, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xd9, 0x30, 0x82, 0x01, 0xd5, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xbf, 0xc8, 0xed, 0x44, 0x0e, 0xbb, + 0x33, 0xe6, 0xc7, 0xca, 0x41, 0x2c, 0xa5, 0x31, 0xb9, 0xc9, 0x60, 0x61, 0x89, 0x2e, 0x30, 0x81, + 0xd0, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, 0xc8, 0x30, 0x81, 0xc5, 0x30, 0x2f, 0xa0, 0x2d, + 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x64, + 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x44, 0x4f, 0x44, 0x45, + 0x4d, 0x41, 0x49, 0x4c, 0x43, 0x41, 0x5f, 0x32, 0x37, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x81, 0x91, + 0xa0, 0x81, 0x8e, 0xa0, 0x81, 0x8b, 0x86, 0x81, 0x88, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x64, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, + 0x2f, 0x63, 0x6e, 0x25, 0x33, 0x64, 0x44, 0x4f, 0x44, 0x25, 0x32, 0x30, 0x45, 0x4d, 0x41, 0x49, + 0x4c, 0x25, 0x32, 0x30, 0x43, 0x41, 0x2d, 0x32, 0x37, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, + 0x64, 0x50, 0x4b, 0x49, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, + 0x32, 0x63, 0x6f, 0x25, 0x33, 0x64, 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, 0x6f, 0x76, + 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x25, 0x32, 0x63, 0x63, 0x25, 0x33, 0x64, 0x55, 0x53, + 0x3f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x72, 0x65, 0x76, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x3b, 0x62, 0x69, 0x6e, 0x61, 0x72, + 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x06, + 0xc0, 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1c, 0x30, 0x1a, 0x30, 0x0b, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x05, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x02, 0x01, 0x0b, 0x12, 0x30, 0x21, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, + 0x18, 0x81, 0x16, 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x40, 0x65, 0x63, 0x6c, 0x69, 0x70, 0x73, 0x65, + 0x2e, 0x6e, 0x63, 0x73, 0x63, 0x2e, 0x6d, 0x69, 0x6c, 0x30, 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, 0x36, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x2f, + 0x44, 0x4f, 0x44, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x43, 0x41, 0x5f, 0x32, 0x37, 0x2e, 0x63, 0x65, + 0x72, 0x30, 0x20, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x14, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, + 0x6d, 0x69, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x4c, 0x62, + 0xc5, 0xed, 0x43, 0x01, 0x54, 0xd1, 0x6c, 0x2e, 0x01, 0x29, 0x5e, 0x8c, 0xdb, 0xb2, 0x1d, 0xa2, + 0x4d, 0x65, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x0f, 0x85, 0x22, 0x72, 0xa1, 0x97, 0x12, 0xc6, 0xe7, 0xde, + 0x09, 0x33, 0x20, 0x9b, 0xeb, 0x91, 0x01, 0xe5, 0x85, 0xd2, 0xf0, 0xb9, 0x0f, 0xe8, 0xd3, 0x39, + 0xf3, 0xd1, 0xff, 0xf9, 0xfa, 0xcf, 0x01, 0x04, 0x8f, 0xac, 0xa3, 0xed, 0x6d, 0x84, 0x38, 0xd6, + 0x4f, 0x68, 0x59, 0x0b, 0x5c, 0x99, 0xa7, 0x08, 0xc5, 0x0d, 0x70, 0x09, 0xe4, 0x27, 0x78, 0x73, + 0xe7, 0xc0, 0x75, 0xea, 0xd7, 0xfe, 0xbd, 0x95, 0xcc, 0xd5, 0x79, 0xe9, 0x74, 0x54, 0x06, 0xc9, + 0x66, 0x2a, 0x64, 0x07, 0x5f, 0xcc, 0x34, 0x52, 0x42, 0xcc, 0xa9, 0xd3, 0xd0, 0x63, 0xa9, 0x1d, + 0xd4, 0x21, 0xc8, 0x38, 0xbc, 0x4f, 0x6e, 0x24, 0xe3, 0x13, 0x16, 0xde, 0xf4, 0xa8, 0x80, 0x8a, + 0x58, 0x17, 0x22, 0x29, 0x96, 0xc2, 0x14, 0x25, 0xfe, 0xfa, 0x04, 0xf1, 0x93, 0x91, 0x4b, 0x71, + 0x90, 0xeb, 0xe2, 0xba, 0xf5, 0x66, 0xd4, 0x4a, 0x21, 0xa0, 0x25, 0x2f, 0x5b, 0x7f, 0x45, 0xfc, + 0xf9, 0xb6, 0xda, 0xae, 0x06, 0x83, 0xdf, 0x39, 0xa1, 0x6a, 0xbc, 0xfb, 0xff, 0x5f, 0x23, 0x12, + 0xba, 0xef, 0xad, 0x34, 0xf1, 0xb8, 0xcd, 0xbd, 0xaf, 0x0c, 0xc6, 0x80, 0xc3, 0x4b, 0xbf, 0xb7, + 0xf3, 0xf6, 0xae, 0x45, 0x2d, 0xa7, 0xcd, 0xb7, 0x78, 0x69, 0x5b, 0x0a, 0xea, 0x64, 0x75, 0xfa, + 0x3d, 0xa4, 0x7b, 0x6c, 0x6d, 0xbc, 0x5f, 0x2d, 0x76, 0x52, 0x0a, 0xce, 0x3f, 0xe1, 0xe2, 0x60, + 0xb8, 0x1f, 0x87, 0xda, 0xaa, 0x08, 0x84, 0x21, 0x0d, 0x62, 0xd3, 0x59, 0xdc, 0x24, 0x60, 0x62, + 0xd4, 0xeb, 0xe1, 0xd7, 0x5c, 0xe1, 0xd3, 0x9a, 0x03, 0xe0, 0x99, 0x35, 0x22, 0x0f, 0x94, 0x7a, + 0xfb, 0x4e, 0x65, 0x6d, 0x9a, 0x87, 0x08, 0xca, 0xdb, 0x65, 0x9c, 0xd4, 0x38, 0x50, 0xb4, 0x9d, + 0x75, 0x13, 0x33, 0x10, 0xf6, 0xca, 0x30, 0x82, 0x05, 0x2e, 0x30, 0x82, 0x04, 0x16, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x02, 0x0a, 0xa5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, + 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, + 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, + 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, + 0x43, 0x41, 0x2d, 0x32, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x31, + 0x34, 0x31, 0x38, 0x31, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x33, 0x32, 0x33, 0x31, 0x34, + 0x31, 0x34, 0x34, 0x30, 0x5a, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, + 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x4f, 0x56, 0x45, 0x52, 0x4e, 0x4d, 0x45, 0x4e, 0x54, 0x31, 0x0c, + 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x4f, 0x44, 0x31, 0x0c, 0x30, 0x0a, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x07, 0x4e, 0x53, 0x41, 0x2f, 0x43, 0x53, 0x53, 0x31, 0x23, 0x30, 0x21, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, 0x42, 0x4c, 0x41, 0x4e, 0x4b, 0x2e, 0x4a, 0x45, 0x46, + 0x46, 0x52, 0x45, 0x59, 0x2e, 0x44, 0x2e, 0x39, 0x30, 0x30, 0x30, 0x30, 0x33, 0x34, 0x35, 0x34, + 0x38, 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, 0xd1, 0x50, 0x1e, 0x0d, 0xe2, 0xd7, 0xe6, 0xff, 0x78, 0xde, 0x2d, 0x6c, 0x34, 0xe7, + 0x3d, 0x66, 0x27, 0x78, 0x09, 0x60, 0xdb, 0xb4, 0xfd, 0xf9, 0x95, 0xf8, 0x15, 0x6b, 0x05, 0x97, + 0x6f, 0x01, 0xeb, 0x36, 0xd7, 0x7a, 0xd7, 0x51, 0x92, 0xc5, 0xe2, 0x55, 0x2b, 0xc4, 0xa6, 0x0f, + 0x83, 0x49, 0x01, 0x8b, 0xbc, 0xd6, 0xae, 0xde, 0x58, 0x1e, 0x10, 0x4a, 0xf2, 0x24, 0xd8, 0x2b, + 0x81, 0xa0, 0x15, 0x39, 0x9d, 0xfa, 0xd2, 0xd5, 0xd6, 0x25, 0x51, 0x23, 0xbb, 0x05, 0xc2, 0xf5, + 0xc1, 0x82, 0xaf, 0x03, 0x4d, 0x21, 0xa0, 0xea, 0x9d, 0xc4, 0x1e, 0x66, 0x73, 0x14, 0x50, 0x23, + 0xc1, 0x3c, 0x1e, 0x3e, 0x7c, 0x8c, 0x74, 0xc8, 0x64, 0xe6, 0xe0, 0x46, 0x59, 0x5e, 0xc7, 0x0e, + 0xf7, 0xc7, 0x6b, 0xa1, 0xb9, 0x3b, 0x45, 0x6b, 0x34, 0x3d, 0x6f, 0x3b, 0xa8, 0xf5, 0x1f, 0x4a, + 0xb4, 0xae, 0x7c, 0x9d, 0x88, 0xde, 0x3e, 0x72, 0xf9, 0xd9, 0x2f, 0x03, 0x7f, 0x4f, 0x88, 0x14, + 0xb5, 0x79, 0x35, 0xcf, 0x8e, 0x63, 0xb1, 0xa0, 0xc1, 0xe9, 0xc3, 0x2a, 0xed, 0xdf, 0xd7, 0x2f, + 0x91, 0x03, 0x79, 0xee, 0x10, 0x96, 0xbd, 0x7e, 0x71, 0xf7, 0x04, 0x92, 0x0a, 0x1c, 0x29, 0x78, + 0x25, 0x25, 0x87, 0x5a, 0xea, 0x3c, 0xbf, 0x3b, 0x6e, 0x32, 0x71, 0xa7, 0xc5, 0x5f, 0xb1, 0x84, + 0x0f, 0xd1, 0x6e, 0xa7, 0xf0, 0x26, 0xbf, 0x41, 0x96, 0x0d, 0xd8, 0x04, 0xf5, 0x1d, 0x05, 0x4d, + 0xbb, 0xb6, 0xcc, 0x55, 0xe9, 0x16, 0xca, 0x77, 0xd9, 0x70, 0x62, 0x12, 0xe9, 0xbd, 0xea, 0xb9, + 0xf4, 0x9a, 0x2b, 0x5e, 0xe3, 0x40, 0x32, 0x43, 0xd3, 0x64, 0x4b, 0x7b, 0xfd, 0x6d, 0x62, 0xeb, + 0x94, 0x85, 0x26, 0xc3, 0xcc, 0x7f, 0x62, 0x55, 0xeb, 0xa6, 0x69, 0xb8, 0xf2, 0x6d, 0x0e, 0x5f, + 0x47, 0xb5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xd9, 0x30, 0x82, 0x01, 0xd5, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xbf, 0xc8, 0xed, 0x44, + 0x0e, 0xbb, 0x33, 0xe6, 0xc7, 0xca, 0x41, 0x2c, 0xa5, 0x31, 0xb9, 0xc9, 0x60, 0x61, 0x89, 0x2e, + 0x30, 0x81, 0xd0, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, 0xc8, 0x30, 0x81, 0xc5, 0x30, 0x2f, + 0xa0, 0x2d, 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, + 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x44, 0x4f, + 0x44, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x43, 0x41, 0x5f, 0x32, 0x37, 0x2e, 0x63, 0x72, 0x6c, 0x30, + 0x81, 0x91, 0xa0, 0x81, 0x8e, 0xa0, 0x81, 0x8b, 0x86, 0x81, 0x88, 0x6c, 0x64, 0x61, 0x70, 0x3a, + 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x64, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, + 0x69, 0x6c, 0x2f, 0x63, 0x6e, 0x25, 0x33, 0x64, 0x44, 0x4f, 0x44, 0x25, 0x32, 0x30, 0x45, 0x4d, + 0x41, 0x49, 0x4c, 0x25, 0x32, 0x30, 0x43, 0x41, 0x2d, 0x32, 0x37, 0x25, 0x32, 0x63, 0x6f, 0x75, + 0x25, 0x33, 0x64, 0x50, 0x4b, 0x49, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x44, 0x6f, + 0x44, 0x25, 0x32, 0x63, 0x6f, 0x25, 0x33, 0x64, 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, + 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x25, 0x32, 0x63, 0x63, 0x25, 0x33, 0x64, + 0x55, 0x53, 0x3f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x72, 0x65, + 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6c, 0x69, 0x73, 0x74, 0x3b, 0x62, 0x69, 0x6e, + 0x61, 0x72, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x05, 0x20, 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1c, 0x30, 0x1a, 0x30, 0x0b, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x05, 0x30, 0x0b, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x12, 0x30, 0x21, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, + 0x1a, 0x30, 0x18, 0x81, 0x16, 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x40, 0x65, 0x63, 0x6c, 0x69, 0x70, + 0x73, 0x65, 0x2e, 0x6e, 0x63, 0x73, 0x63, 0x2e, 0x6d, 0x69, 0x6c, 0x30, 0x68, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, 0x36, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x72, 0x6c, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x73, 0x69, 0x67, + 0x6e, 0x2f, 0x44, 0x4f, 0x44, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x43, 0x41, 0x5f, 0x32, 0x37, 0x2e, + 0x63, 0x65, 0x72, 0x30, 0x20, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, + 0x14, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x73, + 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0x9c, 0x19, 0x19, 0x9d, 0x0c, 0xff, 0xbb, 0xab, 0x2b, 0xd5, 0x07, 0x9f, 0x4c, 0x13, 0x23, 0xb5, + 0x96, 0xa1, 0xea, 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x05, 0xe3, 0x50, 0x05, 0x79, 0x87, 0x0e, 0x85, + 0x31, 0xa0, 0xc7, 0x64, 0x1c, 0x8c, 0x6d, 0x05, 0xe0, 0x3d, 0xda, 0x67, 0x12, 0x2a, 0x22, 0xba, + 0x3c, 0x69, 0x80, 0x2e, 0x04, 0xa6, 0x8b, 0xeb, 0x36, 0x5b, 0xf2, 0x2b, 0xee, 0x81, 0x94, 0x97, + 0x38, 0x8b, 0xd1, 0xef, 0x8d, 0xe3, 0xd1, 0xed, 0x0f, 0x07, 0xf4, 0x86, 0x32, 0x0b, 0xf1, 0x7b, + 0xa0, 0xde, 0x7a, 0xd5, 0xcc, 0xf5, 0xc8, 0x4e, 0x94, 0x14, 0x0c, 0xa4, 0x41, 0x06, 0x06, 0x11, + 0x1f, 0x9e, 0x38, 0xdc, 0x98, 0x61, 0x22, 0x44, 0x2c, 0xc2, 0x7a, 0xf4, 0xfe, 0x8b, 0x23, 0x7e, + 0x7a, 0x53, 0x58, 0xa2, 0x0f, 0x0d, 0x51, 0x5f, 0x61, 0xcb, 0x2c, 0x4d, 0xf1, 0xae, 0xc9, 0x4e, + 0x78, 0x27, 0x06, 0xf1, 0xe7, 0x01, 0x29, 0x8a, 0xa9, 0x0e, 0x87, 0xa6, 0x4c, 0x5f, 0x81, 0x33, + 0xe8, 0x53, 0x9a, 0x71, 0x15, 0x8e, 0x58, 0x8f, 0x0d, 0x01, 0x90, 0x3d, 0xc5, 0xbc, 0xad, 0xb5, + 0x8c, 0x12, 0x88, 0x31, 0xde, 0xfb, 0x35, 0x0d, 0x28, 0xdd, 0x12, 0xd9, 0xd2, 0x66, 0x51, 0xc5, + 0x09, 0x15, 0x8d, 0xcc, 0x32, 0xdf, 0x3d, 0x3c, 0xf8, 0x8c, 0xf7, 0xe2, 0xba, 0xa0, 0xd7, 0x0c, + 0x5e, 0x06, 0x3a, 0xeb, 0x39, 0x97, 0x7e, 0xf4, 0x2c, 0x15, 0x08, 0x4e, 0x96, 0x11, 0x29, 0xb4, + 0x7b, 0xf0, 0xc1, 0xde, 0xbb, 0xe2, 0xdb, 0x72, 0x31, 0x31, 0xf0, 0x7b, 0x50, 0x2c, 0x4f, 0x2d, + 0x6c, 0x52, 0x0c, 0xcd, 0xa5, 0x5e, 0xf7, 0xbf, 0x94, 0x4b, 0xfc, 0xc1, 0x27, 0xfe, 0x23, 0x1a, + 0x8d, 0x18, 0x24, 0x62, 0x76, 0x87, 0xc0, 0x64, 0x60, 0xf6, 0x8a, 0xc6, 0xf2, 0x14, 0xb4, 0x31, + 0xb2, 0xe1, 0x0e, 0x55, 0xd1, 0xaf, 0xd2, 0x98, 0x54, 0x90, 0xba, 0x75, 0x9d, 0xcb, 0x90, 0x06, + 0x32, 0xea, 0xbc, 0xf6, 0x0c, 0xb3, 0x60, 0x9f, 0x30, 0x82, 0x05, 0x32, 0x30, 0x82, 0x04, 0x1a, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0e, 0x30, 0xdb, 0x00, 0x01, 0x00, 0x29, 0x91, 0x05, 0x06, + 0xa0, 0xb7, 0xd6, 0xb7, 0x56, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x30, 0x69, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x52, 0x4f, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x20, 0x53, 0x70, 0x65, 0x64, 0x20, 0x53, 0x52, 0x4c, 0x31, 0x21, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x49, 0x6e, 0x64, 0x69, 0x76, 0x69, 0x64, 0x75, 0x61, + 0x6c, 0x20, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x20, 0x43, 0x41, 0x31, + 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x20, + 0x53, 0x70, 0x65, 0x64, 0x20, 0x53, 0x41, 0x46, 0x45, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x31, 0x32, 0x31, 0x31, 0x30, 0x34, 0x37, 0x35, 0x36, 0x5a, + 0x17, 0x0d, 0x31, 0x36, 0x30, 0x31, 0x32, 0x30, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, + 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x23, + 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1a, 0x53, 0x41, 0x46, 0x45, 0x2d, 0x42, 0x69, + 0x6f, 0x70, 0x68, 0x61, 0x72, 0x6d, 0x61, 0x20, 0x41, 0x73, 0x73, 0x6f, 0x63, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x0e, 0x53, 0x41, 0x46, 0x45, 0x20, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 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, 0xb1, 0x17, 0xfc, 0x4a, 0x4a, 0x13, 0x95, 0xc8, 0xd9, 0x26, 0x16, 0x40, 0xab, 0x9e, 0x03, + 0x51, 0x4f, 0xb6, 0x84, 0x5c, 0xfe, 0x60, 0x64, 0x5f, 0xe5, 0xd4, 0xc4, 0x21, 0x6f, 0x1c, 0xf6, + 0xad, 0xef, 0x26, 0x15, 0x8e, 0xad, 0x58, 0x21, 0x1a, 0x34, 0xa1, 0xee, 0x54, 0xa1, 0x3b, 0x24, + 0xc6, 0x99, 0xf2, 0x9a, 0x1a, 0x59, 0x23, 0xa1, 0xe9, 0x1a, 0xa9, 0xb8, 0x78, 0x97, 0xb2, 0x7b, + 0x6a, 0x3e, 0xb4, 0x7d, 0x90, 0x4b, 0x70, 0x96, 0x74, 0xdf, 0xec, 0xda, 0x34, 0xb1, 0x53, 0xc6, + 0x3b, 0xa4, 0xbd, 0x02, 0xf6, 0x6d, 0xe1, 0x2a, 0xf6, 0x49, 0xe8, 0x9f, 0x15, 0xe6, 0xba, 0x9d, + 0x4f, 0xa8, 0x87, 0x81, 0x4b, 0x96, 0x80, 0x81, 0x46, 0x14, 0x76, 0x37, 0xb8, 0x53, 0x46, 0x36, + 0xac, 0xfb, 0x56, 0x12, 0xd0, 0x6a, 0xb1, 0x15, 0x58, 0x3d, 0x5d, 0x36, 0x45, 0x82, 0x6f, 0xc2, + 0xd7, 0xd4, 0x2f, 0x18, 0x4a, 0x58, 0x01, 0x8a, 0x1f, 0xcf, 0x1f, 0xb9, 0xe4, 0x7b, 0x37, 0x0b, + 0xf1, 0xcd, 0xae, 0x78, 0x9e, 0x45, 0x2e, 0xd8, 0xec, 0x8d, 0xc1, 0x60, 0x10, 0xd9, 0x5a, 0x94, + 0xc6, 0xcf, 0x44, 0x5c, 0x53, 0xa1, 0xe6, 0x06, 0xbd, 0x23, 0x41, 0xf8, 0x89, 0xb0, 0x6d, 0x4b, + 0x78, 0x6b, 0x46, 0xe1, 0x11, 0xc6, 0x85, 0x5f, 0xbe, 0x13, 0x44, 0x4c, 0x06, 0x64, 0xb4, 0xf0, + 0x3b, 0xe6, 0x0d, 0x48, 0x78, 0x02, 0xd9, 0xa3, 0xac, 0x29, 0x83, 0xcc, 0x71, 0x34, 0x1c, 0x89, + 0x49, 0x1c, 0x2c, 0xb1, 0x16, 0xa8, 0xa3, 0x38, 0x9e, 0x88, 0xcc, 0x08, 0xf2, 0x35, 0x60, 0xd7, + 0xaa, 0xd8, 0x98, 0x44, 0xa2, 0x45, 0xc7, 0x81, 0x3f, 0x69, 0xeb, 0xe7, 0x31, 0x39, 0xe4, 0x0b, + 0x15, 0x3c, 0x98, 0x81, 0xbc, 0x4f, 0x56, 0x39, 0x11, 0x02, 0xc3, 0xa3, 0x8e, 0x11, 0xcc, 0x15, + 0x91, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xd0, 0x30, 0x82, 0x01, 0xcc, 0x30, 0x24, + 0x06, 0x03, 0x55, 0x1d, 0x21, 0x04, 0x1d, 0x30, 0x1b, 0x30, 0x19, 0x06, 0x0b, 0x2a, 0x82, 0x14, + 0x00, 0x2c, 0x01, 0x01, 0x06, 0x10, 0x01, 0x01, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, + 0xb4, 0x7d, 0x01, 0x03, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x1d, 0x36, 0x04, 0x03, 0x02, 0x01, 0x00, + 0x30, 0x81, 0x9d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x81, 0x90, + 0x30, 0x81, 0x8d, 0x30, 0x45, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, + 0x39, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x73, 0x70, 0x65, 0x64, 0x2e, 0x72, 0x6f, 0x2f, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x73, + 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x5f, 0x73, 0x70, 0x65, 0x64, 0x5f, 0x73, 0x61, 0x66, 0x65, + 0x5f, 0x63, 0x61, 0x5f, 0x49, 0x49, 0x2e, 0x70, 0x37, 0x63, 0x30, 0x44, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x38, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, + 0x63, 0x73, 0x70, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x73, 0x70, 0x65, 0x64, 0x2d, 0x73, 0x61, + 0x66, 0x65, 0x2d, 0x63, 0x61, 0x2d, 0x69, 0x69, 0x2e, 0x74, 0x63, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x33, 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, 0x48, 0x23, 0x52, + 0x97, 0xad, 0x50, 0xaa, 0x3c, 0x5a, 0x3f, 0xd4, 0x50, 0x84, 0x81, 0xbd, 0x34, 0x02, 0xd2, 0x37, + 0xb4, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, + 0x01, 0xff, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x43, 0x30, 0x41, 0x30, 0x3f, 0x06, + 0x0b, 0x2a, 0x82, 0x14, 0x00, 0x2c, 0x01, 0x01, 0x06, 0x10, 0x01, 0x01, 0x30, 0x30, 0x30, 0x2e, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x73, 0x70, 0x65, 0x64, + 0x2e, 0x72, 0x6f, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 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, 0x8e, 0x63, 0xe1, 0xe0, 0x65, 0x1c, 0x51, + 0x91, 0x48, 0xeb, 0x96, 0x1e, 0xfb, 0x9f, 0xec, 0x57, 0x5a, 0x32, 0x4a, 0xa9, 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, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x64, 0x65, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x76, 0x32, + 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x5f, 0x73, 0x70, 0x65, 0x64, 0x5f, 0x73, 0x61, 0x66, 0x65, + 0x5f, 0x63, 0x61, 0x5f, 0x49, 0x49, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x63, 0x5f, + 0x67, 0xf1, 0xae, 0x84, 0xc0, 0xe8, 0x07, 0xcd, 0x0a, 0x49, 0x4c, 0x67, 0x1e, 0xec, 0xfe, 0xca, + 0xe5, 0x4b, 0xaa, 0x03, 0x96, 0x71, 0x49, 0x27, 0xf8, 0x73, 0x4e, 0x0a, 0x59, 0x51, 0x7d, 0xc8, + 0x08, 0x8c, 0xff, 0xd3, 0x5a, 0x99, 0xbd, 0xa7, 0x1c, 0x20, 0xdc, 0xaa, 0x4b, 0x87, 0xd2, 0x94, + 0x7d, 0xc3, 0xeb, 0xe9, 0xe9, 0x0d, 0xd0, 0x24, 0xd3, 0x63, 0x05, 0xc7, 0x4e, 0x59, 0x6b, 0x18, + 0xab, 0x02, 0x27, 0x65, 0x99, 0xa6, 0x0a, 0x45, 0xce, 0x36, 0x4d, 0x3c, 0x45, 0xc5, 0xb3, 0xd2, + 0x8f, 0x57, 0xca, 0x82, 0x5a, 0xc5, 0x2a, 0x51, 0x52, 0x1f, 0x14, 0x97, 0xfe, 0xcd, 0xfb, 0x3c, + 0x2f, 0x92, 0x95, 0x85, 0x24, 0x6b, 0xae, 0x8f, 0x4e, 0xbc, 0x9b, 0x52, 0xfc, 0x0d, 0x85, 0xbd, + 0xd4, 0x98, 0x14, 0xf0, 0x69, 0xf1, 0xd2, 0x58, 0x30, 0x9a, 0xb1, 0x14, 0x94, 0x8d, 0x03, 0x00, + 0xbd, 0x40, 0x31, 0x5d, 0xcc, 0x8f, 0x01, 0x17, 0xbb, 0xba, 0x4f, 0xf9, 0xdf, 0x6a, 0xe4, 0xa7, + 0x4e, 0x05, 0xfa, 0x4a, 0xe8, 0x1c, 0xa1, 0xf0, 0x49, 0x63, 0xff, 0x73, 0x85, 0x87, 0x69, 0x0c, + 0x3b, 0x16, 0x58, 0xf6, 0xcb, 0x11, 0xb5, 0xdd, 0x6b, 0x7d, 0x55, 0x4e, 0x42, 0x45, 0x65, 0x70, + 0xd5, 0xa4, 0xd5, 0x50, 0x31, 0x88, 0x84, 0x09, 0x0e, 0xfd, 0x53, 0xfa, 0x4e, 0xc7, 0x4c, 0x9b, + 0x5f, 0x2a, 0x6f, 0xa0, 0x79, 0xad, 0xa1, 0x8e, 0x84, 0xbb, 0x96, 0xa6, 0xa3, 0xdc, 0x49, 0xd2, + 0x98, 0x51, 0x60, 0xb2, 0x03, 0x62, 0x65, 0xc5, 0x0b, 0x82, 0x29, 0x0c, 0xcc, 0x07, 0x90, 0x3b, + 0x68, 0xff, 0xe6, 0xf4, 0x02, 0xb4, 0xaf, 0x31, 0x45, 0x5c, 0x03, 0xb6, 0xb3, 0xb4, 0xea, 0xbc, + 0x2f, 0xdc, 0x13, 0x59, 0xfb, 0xe8, 0xe8, 0x1d, 0x80, 0x59, 0x7c, 0x82, 0x1f, 0xf7, 0x30, 0x82, + 0x05, 0x52, 0x30, 0x82, 0x04, 0x3a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01, 0xb6, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5b, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, + 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, + 0x50, 0x4b, 0x49, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, 0x44, 0x6f, + 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x31, 0x30, 0x39, 0x30, 0x38, 0x31, 0x36, 0x30, 0x30, 0x31, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x37, + 0x30, 0x39, 0x30, 0x38, 0x31, 0x36, 0x30, 0x30, 0x31, 0x38, 0x5a, 0x30, 0x5d, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, + 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, + 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x43, 0x41, 0x2d, 0x32, 0x37, 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, 0xd3, 0x9d, 0xc2, 0x07, 0xb0, + 0xf5, 0x7e, 0xcc, 0xee, 0xae, 0xb8, 0xab, 0xaa, 0x33, 0xea, 0xa7, 0x92, 0x6e, 0x13, 0x56, 0x40, + 0x68, 0xe5, 0x1f, 0xc6, 0x21, 0xbc, 0xc0, 0x81, 0x97, 0x61, 0x2c, 0x70, 0xd1, 0x5a, 0x15, 0x17, + 0xfe, 0x9c, 0xa3, 0xef, 0x48, 0x69, 0x89, 0xb7, 0x5b, 0x52, 0xf9, 0xac, 0xe0, 0x3a, 0x9c, 0xa6, + 0x43, 0x56, 0x20, 0x28, 0x82, 0x6c, 0xcd, 0xf5, 0x96, 0xfe, 0x80, 0x9d, 0xd9, 0x8d, 0xf1, 0xd1, + 0xee, 0x81, 0x9a, 0xbc, 0xec, 0xf0, 0x85, 0x35, 0x16, 0x41, 0xb9, 0x26, 0x89, 0x0c, 0x26, 0x7a, + 0x40, 0x6e, 0xd0, 0x09, 0x80, 0x51, 0xc0, 0x02, 0xd8, 0xee, 0x84, 0x6f, 0xcc, 0x2c, 0x82, 0x22, + 0xaa, 0x35, 0x85, 0x5e, 0xa4, 0x5e, 0x85, 0x04, 0xd1, 0x09, 0x99, 0xa4, 0xb8, 0x7d, 0x52, 0xb1, + 0x21, 0x7a, 0x4d, 0xd8, 0x21, 0xa7, 0xbc, 0x44, 0x4f, 0xca, 0x15, 0xa2, 0x8c, 0x31, 0x2e, 0x89, + 0xd6, 0x39, 0x2f, 0x40, 0x56, 0x37, 0x78, 0xeb, 0x2e, 0x5d, 0x2e, 0xd1, 0x18, 0x47, 0x16, 0xed, + 0xac, 0xa0, 0x84, 0xd4, 0x0b, 0x82, 0x98, 0xbd, 0x03, 0x18, 0x70, 0xb0, 0x19, 0x5d, 0x8c, 0x6b, + 0xde, 0x35, 0x24, 0x62, 0x5a, 0xc8, 0xfb, 0x0f, 0xba, 0x7a, 0xec, 0xc8, 0x40, 0x49, 0x72, 0x56, + 0x9e, 0x1a, 0x4d, 0x54, 0xc0, 0x4e, 0xe5, 0x10, 0x34, 0x4f, 0x61, 0xd1, 0xd2, 0xed, 0x4d, 0xdf, + 0xd1, 0x59, 0xb0, 0xeb, 0x02, 0x42, 0x2f, 0x0c, 0x1b, 0x52, 0x0c, 0x15, 0xa0, 0xf2, 0xee, 0xba, + 0x36, 0x57, 0xfb, 0xcc, 0xac, 0x11, 0xf1, 0x9a, 0x2d, 0x4c, 0x8b, 0x29, 0x18, 0xf1, 0xf0, 0x70, + 0x92, 0x68, 0xd6, 0x41, 0x26, 0xcc, 0x5b, 0x7c, 0x75, 0x76, 0xd8, 0x05, 0x60, 0x52, 0xd3, 0x09, + 0xfc, 0xad, 0xc0, 0x40, 0x1c, 0xa4, 0x46, 0xd6, 0x30, 0x2d, 0x7b, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x02, 0x1c, 0x30, 0x82, 0x02, 0x18, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0x49, 0x74, 0xbb, 0x0c, 0x5e, 0xba, 0x7a, 0xfe, 0x02, 0x54, 0xef, + 0x7b, 0xa0, 0xc6, 0x95, 0xc6, 0x09, 0x80, 0x70, 0x96, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xbf, 0xc8, 0xed, 0x44, 0x0e, 0xbb, 0x33, 0xe6, 0xc7, 0xca, 0x41, 0x2c, + 0xa5, 0x31, 0xb9, 0xc9, 0x60, 0x61, 0x89, 0x2e, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0c, 0x06, 0x03, + 0x55, 0x1d, 0x24, 0x04, 0x05, 0x30, 0x03, 0x80, 0x01, 0x00, 0x30, 0x66, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x5f, 0x30, 0x5d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, + 0x0b, 0x05, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x09, 0x30, + 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x11, 0x30, 0x0b, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x12, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x02, 0x01, 0x0b, 0x13, 0x30, 0x0c, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x02, 0x01, 0x03, 0x1a, 0x30, 0x0c, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, + 0x03, 0x1b, 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, + 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x44, 0x4f, 0x44, + 0x52, 0x4f, 0x4f, 0x54, 0x43, 0x41, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x82, 0x01, 0x01, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x81, 0xf4, 0x30, 0x81, 0xf1, 0x30, + 0x3a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2e, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, + 0x2f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x74, 0x6f, 0x2f, 0x44, 0x4f, 0x44, 0x52, 0x4f, 0x4f, + 0x54, 0x43, 0x41, 0x32, 0x5f, 0x49, 0x54, 0x2e, 0x70, 0x37, 0x63, 0x30, 0x20, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x14, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x30, 0x81, 0x90, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x81, 0x83, 0x6c, 0x64, 0x61, + 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x64, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x61, + 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x6e, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, 0x32, 0x30, + 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43, 0x41, 0x25, 0x32, 0x30, 0x32, 0x25, 0x32, 0x63, + 0x6f, 0x75, 0x25, 0x33, 0x64, 0x50, 0x4b, 0x49, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, + 0x44, 0x6f, 0x44, 0x25, 0x32, 0x63, 0x6f, 0x25, 0x33, 0x64, 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, + 0x30, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x25, 0x32, 0x63, 0x63, 0x25, + 0x33, 0x64, 0x55, 0x53, 0x3f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x69, 0x72, 0x3b, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x11, 0x7d, 0xf2, 0x4e, 0x5d, 0xa8, 0xd6, 0x46, 0x1a, 0xe7, 0xd9, 0xd4, + 0x66, 0xb1, 0x51, 0xc6, 0x81, 0xe0, 0xe6, 0x7f, 0x3d, 0x71, 0xae, 0x46, 0xa7, 0x70, 0x0b, 0x83, + 0xb4, 0xbd, 0xc0, 0x40, 0x33, 0x50, 0x9b, 0x87, 0x43, 0x94, 0x87, 0x05, 0x69, 0x74, 0xbe, 0x67, + 0x6d, 0xdd, 0x2a, 0xec, 0x0a, 0x31, 0x04, 0xbf, 0x78, 0x95, 0x6f, 0xd8, 0xb1, 0xec, 0x43, 0x27, + 0x0a, 0xcf, 0x00, 0x80, 0x01, 0x16, 0x3c, 0x7d, 0x97, 0x37, 0x85, 0x98, 0x5b, 0xa6, 0x80, 0x73, + 0x0c, 0xb3, 0x77, 0xfe, 0xc9, 0x70, 0x33, 0x52, 0x8b, 0x7a, 0x75, 0xb7, 0xb9, 0x2e, 0xfe, 0xbc, + 0x2d, 0x25, 0x46, 0x96, 0xfa, 0x45, 0x6d, 0x78, 0x28, 0xcd, 0xdb, 0x9b, 0x99, 0x4c, 0x07, 0x9e, + 0x2c, 0x62, 0x0d, 0x8a, 0xdb, 0x7f, 0x78, 0x55, 0x05, 0x47, 0x12, 0x1b, 0xdb, 0x99, 0x02, 0x37, + 0xf9, 0x67, 0x1f, 0x04, 0x31, 0xef, 0x28, 0x81, 0x77, 0x76, 0x5a, 0x2e, 0x94, 0x8b, 0x75, 0x78, + 0x3d, 0x89, 0xcc, 0x78, 0xd0, 0x4b, 0x05, 0x98, 0xa2, 0xc0, 0x70, 0x16, 0x87, 0x70, 0xff, 0x8b, + 0x7c, 0x09, 0xd2, 0xe1, 0x2d, 0x32, 0xed, 0x03, 0xed, 0x61, 0x2b, 0x8d, 0xda, 0xce, 0xcd, 0xd2, + 0x3c, 0xe3, 0xe6, 0x8f, 0xf6, 0x71, 0xe3, 0xba, 0x2f, 0x5c, 0x84, 0x82, 0x6e, 0x88, 0xa6, 0x5d, + 0x3a, 0xab, 0xc1, 0x6d, 0xfe, 0x67, 0xf9, 0xe9, 0xab, 0xe5, 0x38, 0x44, 0xef, 0x43, 0x1b, 0xe5, + 0x2a, 0xb1, 0x30, 0xfb, 0xf4, 0xfb, 0x6f, 0x7d, 0xa4, 0x20, 0x00, 0x54, 0x60, 0x22, 0x3e, 0x5d, + 0x33, 0x64, 0xbb, 0x94, 0xea, 0x5a, 0x76, 0x95, 0x9f, 0xc8, 0x8f, 0x06, 0x6b, 0x3a, 0x60, 0xe8, + 0xc2, 0x46, 0x26, 0x53, 0xab, 0xba, 0xe6, 0x28, 0xcb, 0xf9, 0x5b, 0x8e, 0xbd, 0x43, 0xad, 0xf1, + 0xc7, 0x68, 0x32, 0xbe, 0x30, 0x82, 0x05, 0xb9, 0x30, 0x82, 0x04, 0xa1, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0f, 0x00, 0xeb, 0x96, 0x00, 0x01, 0x00, 0x02, 0x0c, 0xf9, 0xd4, 0x92, 0x01, 0xf1, + 0x21, 0xa4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x76, 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, 0x22, + 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x54, 0x43, 0x20, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, + 0x43, 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x54, 0x43, 0x20, + 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x20, 0x49, 0x49, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, + 0x31, 0x32, 0x35, 0x31, 0x35, 0x31, 0x37, 0x35, 0x37, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, + 0x30, 0x36, 0x32, 0x31, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x69, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x4f, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x20, 0x53, 0x70, 0x65, 0x64, 0x20, 0x53, 0x52, + 0x4c, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x49, 0x6e, 0x64, 0x69, + 0x76, 0x69, 0x64, 0x75, 0x61, 0x6c, 0x20, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x72, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x20, 0x53, 0x70, 0x65, 0x64, 0x20, 0x53, 0x41, 0x46, 0x45, 0x20, 0x43, + 0x41, 0x20, 0x49, 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, 0xa6, 0x5f, 0x73, 0xde, 0x4b, 0x6a, 0x77, 0x6b, 0x8e, 0x0c, 0xe9, + 0xe1, 0x66, 0x55, 0x6a, 0xc7, 0x5a, 0x18, 0x07, 0xc7, 0x59, 0x3f, 0x72, 0x3a, 0x6b, 0x7a, 0x4e, + 0xd0, 0x5a, 0xee, 0x39, 0x72, 0x07, 0xd5, 0xa3, 0xec, 0xf4, 0x9a, 0xb2, 0x95, 0x7c, 0x2d, 0x8f, + 0xdf, 0x58, 0xe4, 0xf3, 0x78, 0x26, 0xfa, 0xb5, 0x69, 0xee, 0xbf, 0xc3, 0x5d, 0x28, 0xf0, 0x0a, + 0xee, 0xe7, 0xc7, 0x93, 0x27, 0x61, 0x54, 0x0c, 0x53, 0x1f, 0xdc, 0x27, 0xb5, 0x5b, 0x75, 0x19, + 0x48, 0xb3, 0xfa, 0x87, 0x19, 0x20, 0xe8, 0x7a, 0xaa, 0xd1, 0x82, 0x5d, 0x92, 0x48, 0xd7, 0x14, + 0x10, 0x6e, 0xdd, 0x35, 0x01, 0x94, 0x8e, 0xae, 0xba, 0x12, 0x8b, 0x64, 0x04, 0x28, 0x73, 0x31, + 0x55, 0x24, 0xb1, 0x94, 0x84, 0xf2, 0xbe, 0x85, 0xa9, 0xc2, 0x22, 0x8b, 0xc7, 0xf3, 0x8a, 0x96, + 0x1e, 0x91, 0x21, 0xad, 0x48, 0x66, 0xc6, 0xa8, 0xf5, 0xa3, 0x11, 0xd8, 0xec, 0x65, 0x6d, 0x44, + 0xbd, 0x17, 0x8c, 0x0c, 0x3e, 0xc8, 0xc2, 0x50, 0x6b, 0x4c, 0xff, 0x5c, 0xcf, 0x03, 0x34, 0x29, + 0x88, 0x85, 0xa9, 0x2a, 0x2c, 0x17, 0xa0, 0xc9, 0xd6, 0x76, 0x85, 0xca, 0xcb, 0x70, 0x6d, 0x8b, + 0x89, 0x88, 0x88, 0xcc, 0xe9, 0x69, 0x78, 0x14, 0x17, 0x0e, 0x93, 0x88, 0x9a, 0xbd, 0x9e, 0x6d, + 0x85, 0x91, 0xbe, 0xd4, 0x3b, 0x63, 0x60, 0xd7, 0x06, 0x4c, 0x93, 0xb8, 0xcd, 0x33, 0xcf, 0xb6, + 0x86, 0x2f, 0xd4, 0x9f, 0xbc, 0xf0, 0x71, 0xe7, 0x17, 0xc2, 0x4c, 0x33, 0xdf, 0x6b, 0x0e, 0x1e, + 0x92, 0xd1, 0x5f, 0xbc, 0xd8, 0xa0, 0xe3, 0x3d, 0x68, 0xbb, 0xef, 0xb3, 0x8e, 0xa4, 0xd9, 0x88, + 0xf6, 0x1f, 0xa3, 0x71, 0x61, 0xc6, 0xd6, 0xa8, 0x7c, 0xe8, 0x88, 0xbd, 0x84, 0xe4, 0x08, 0x10, + 0xc9, 0x80, 0x91, 0x5c, 0x1b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x4f, 0x30, 0x82, + 0x02, 0x4b, 0x30, 0x81, 0x95, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x81, 0x88, 0x30, 0x81, 0x85, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x01, 0x86, 0x26, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, + 0x63, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x33, 0x2d, 0x49, 0x49, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x64, 0x65, 0x30, 0x4f, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x43, 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, 0x5f, 0x33, + 0x5f, 0x63, 0x61, 0x5f, 0x49, 0x49, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xd4, 0xa2, 0xfc, 0x9f, 0xb3, 0xc3, 0xd8, 0x03, 0xd3, + 0x57, 0x5c, 0x07, 0xa4, 0xd0, 0x24, 0xa7, 0xc0, 0xf2, 0x00, 0xd4, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x54, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x4d, 0x30, 0x4b, 0x30, 0x3f, 0x06, 0x0b, 0x2a, 0x82, 0x14, 0x00, 0x2c, + 0x01, 0x01, 0x06, 0x10, 0x01, 0x01, 0x30, 0x30, 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x02, 0x01, 0x16, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x73, 0x70, 0x65, 0x64, 0x2e, 0x72, 0x6f, 0x2f, 0x72, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x30, 0x08, 0x06, 0x06, 0x04, 0x00, 0x8b, 0x30, + 0x01, 0x01, 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, 0x48, 0x23, 0x52, + 0x97, 0xad, 0x50, 0xaa, 0x3c, 0x5a, 0x3f, 0xd4, 0x50, 0x84, 0x81, 0xbd, 0x34, 0x02, 0xd2, 0x37, + 0xb4, 0x30, 0x81, 0xf9, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, 0xf1, 0x30, 0x81, 0xee, 0x30, + 0x81, 0xeb, 0xa0, 0x81, 0xe8, 0xa0, 0x81, 0xe5, 0x86, 0x41, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x74, 0x63, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x33, 0x2d, 0x69, 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, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, + 0x33, 0x5f, 0x63, 0x61, 0x5f, 0x49, 0x49, 0x2e, 0x63, 0x72, 0x6c, 0x86, 0x81, 0x9f, 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, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x25, 0x32, 0x30, 0x33, 0x25, 0x32, 0x30, 0x43, 0x41, 0x25, 0x32, 0x30, 0x49, + 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, 0x99, 0xe8, 0x01, 0x84, 0x11, 0x8e, 0xd1, 0x8f, 0x58, 0xbe, 0xdb, 0x8a, 0xa7, 0x3b, 0x9a, + 0xfc, 0xc3, 0x49, 0x7b, 0xfc, 0x1a, 0x16, 0xdc, 0x68, 0x87, 0x9d, 0x6e, 0xc4, 0x69, 0xa0, 0x07, + 0x32, 0x74, 0x4b, 0xac, 0x61, 0x52, 0x2d, 0x49, 0x5f, 0x3c, 0x58, 0xbe, 0x0e, 0x6b, 0xe9, 0xd8, + 0xfa, 0x66, 0x27, 0x92, 0xd8, 0xe7, 0xe3, 0x8c, 0x32, 0xe9, 0x8e, 0x30, 0x01, 0xf3, 0x73, 0x28, + 0x6a, 0x10, 0x47, 0x33, 0x7f, 0x37, 0x89, 0x9e, 0x7f, 0xe3, 0x9f, 0xdb, 0xa6, 0x38, 0xd6, 0xf6, + 0xc1, 0xd6, 0x8c, 0x39, 0x79, 0x66, 0x4a, 0x92, 0x42, 0xbb, 0x8f, 0xa2, 0x95, 0xf7, 0x9f, 0x53, + 0xed, 0x6a, 0x55, 0x25, 0x30, 0x30, 0x8a, 0xc8, 0x1f, 0xc7, 0xce, 0x5a, 0x20, 0x1a, 0x38, 0xff, + 0x42, 0x46, 0xa4, 0x94, 0xd4, 0x1d, 0x69, 0x49, 0xc3, 0x38, 0x45, 0x28, 0x2b, 0x6a, 0x74, 0xd9, + 0x2a, 0x69, 0x67, 0xe6, 0x89, 0x13, 0xee, 0xac, 0xc1, 0xce, 0x0c, 0xf9, 0xb2, 0x93, 0xbd, 0xbd, + 0x1d, 0x8a, 0xcd, 0x8c, 0x5c, 0xdf, 0x7a, 0xee, 0x95, 0x65, 0x0b, 0x7a, 0x54, 0xbd, 0x73, 0x39, + 0x03, 0xd9, 0xf7, 0x25, 0x6c, 0x6c, 0x5e, 0x79, 0xa1, 0x0f, 0xdb, 0x01, 0x0e, 0x7b, 0x2a, 0x25, + 0x0d, 0xea, 0x64, 0x89, 0x15, 0x13, 0x73, 0x5c, 0xcc, 0x3d, 0xed, 0x91, 0x71, 0x65, 0xd6, 0xd3, + 0x80, 0x12, 0x08, 0x54, 0xa1, 0xb4, 0x75, 0x69, 0xdf, 0xda, 0xd6, 0xbd, 0xb9, 0x24, 0x44, 0x0f, + 0x1c, 0xfa, 0x46, 0x01, 0x55, 0x3b, 0x73, 0xe0, 0x45, 0xf9, 0x93, 0x53, 0xfc, 0x5c, 0xb5, 0x9a, + 0xc3, 0xc6, 0x0e, 0xc2, 0xe1, 0xd7, 0x3d, 0x66, 0xbf, 0x31, 0xd9, 0x40, 0x83, 0x2b, 0xd6, 0x33, + 0x95, 0xe7, 0x7f, 0x54, 0x91, 0x8d, 0x2b, 0x53, 0x88, 0xa9, 0x88, 0x90, 0x78, 0x29, 0x72, 0xe4, + 0x01, 0x30, 0x82, 0x05, 0xc4, 0x30, 0x82, 0x04, 0xac, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, + 0x32, 0xce, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1a, 0x53, 0x41, 0x46, 0x45, 0x2d, + 0x42, 0x69, 0x6f, 0x70, 0x68, 0x61, 0x72, 0x6d, 0x61, 0x20, 0x41, 0x73, 0x73, 0x6f, 0x63, 0x69, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x0e, 0x53, 0x41, 0x46, 0x45, 0x20, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x38, 0x32, 0x33, 0x31, 0x34, 0x33, 0x31, + 0x35, 0x32, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x30, 0x32, 0x31, 0x35, 0x33, 0x30, 0x34, + 0x31, 0x5a, 0x30, 0x56, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, + 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0d, 0x30, 0x0b, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x04, 0x46, 0x50, 0x4b, 0x49, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x15, 0x53, 0x48, 0x41, 0x2d, 0x31, 0x20, 0x46, 0x65, 0x64, 0x65, 0x72, + 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, 0xa7, 0x07, 0x9e, 0x05, 0x3a, + 0x5c, 0x7e, 0xb1, 0xff, 0xb0, 0x99, 0x12, 0xba, 0x65, 0x72, 0x3e, 0xc3, 0x32, 0x3e, 0x8f, 0x8a, + 0x05, 0x4c, 0x32, 0xf8, 0x31, 0x15, 0xba, 0x80, 0x39, 0xf3, 0x66, 0x60, 0x78, 0xae, 0xb7, 0xe8, + 0x8e, 0xfe, 0x6a, 0xf5, 0x60, 0x53, 0x64, 0x33, 0x2e, 0xe6, 0x33, 0x40, 0xc9, 0x21, 0x23, 0xdf, + 0x6a, 0xb1, 0x33, 0x4e, 0x71, 0x4e, 0xf1, 0xfc, 0x72, 0xe4, 0xae, 0x91, 0x99, 0x2a, 0xc1, 0x29, + 0x9a, 0x8d, 0x74, 0xff, 0xb1, 0x32, 0x39, 0x02, 0x72, 0x09, 0x9b, 0x65, 0xc8, 0x07, 0x11, 0xaf, + 0xb2, 0x38, 0xb5, 0xc6, 0x8e, 0xfd, 0xb0, 0x18, 0xc1, 0xea, 0x11, 0x9d, 0x29, 0x64, 0x8f, 0x28, + 0x30, 0x38, 0xe9, 0x48, 0x14, 0x76, 0x1c, 0x47, 0x93, 0xec, 0x96, 0x40, 0xc1, 0xca, 0x59, 0x85, + 0x51, 0x0c, 0x57, 0x3f, 0xbb, 0xe1, 0xc2, 0xc4, 0x7a, 0x3b, 0x0a, 0x19, 0xfb, 0x60, 0x96, 0x8b, + 0x65, 0x6e, 0xe5, 0x29, 0x3d, 0xc0, 0x39, 0x57, 0xb7, 0x00, 0xae, 0x11, 0xae, 0xa9, 0x07, 0x85, + 0xe3, 0x72, 0x38, 0xe9, 0xba, 0x6e, 0x33, 0x01, 0x50, 0xcb, 0xd4, 0xbf, 0xa7, 0x41, 0xc4, 0x3f, + 0x9b, 0x78, 0xfc, 0x01, 0x98, 0x91, 0xf3, 0xe8, 0x2c, 0x88, 0x22, 0x68, 0x22, 0xcf, 0x94, 0x4a, + 0x14, 0x58, 0x79, 0x43, 0x95, 0xea, 0x40, 0x9a, 0x90, 0x84, 0x7a, 0xdd, 0x67, 0x13, 0x00, 0x95, + 0x49, 0x30, 0x94, 0xb2, 0x85, 0x29, 0x90, 0xa7, 0x68, 0xbd, 0x7e, 0xf6, 0x36, 0x68, 0xd3, 0xc7, + 0xf9, 0x94, 0x31, 0x53, 0xfb, 0x22, 0xd2, 0x2b, 0x1c, 0x92, 0xae, 0xd7, 0xda, 0x2f, 0x15, 0x7e, + 0x0c, 0x63, 0xa0, 0xdd, 0xdb, 0xa5, 0x4c, 0x78, 0x82, 0xe3, 0x43, 0xdd, 0x58, 0x83, 0x1c, 0xc3, + 0xfe, 0x6e, 0x6f, 0x81, 0xf2, 0x0b, 0xb3, 0x65, 0x54, 0x90, 0x4f, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x02, 0x81, 0x30, 0x82, 0x02, 0x7d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x81, 0x81, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x75, 0x30, 0x73, 0x30, 0x30, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, + 0x62, 0x63, 0x61, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x2d, 0x62, 0x69, 0x6f, 0x70, 0x68, 0x61, 0x72, + 0x6d, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2f, 0x30, 0x3f, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x33, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x73, 0x62, 0x63, 0x61, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x2d, 0x62, 0x69, 0x6f, 0x70, 0x68, + 0x61, 0x72, 0x6d, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2f, 0x63, + 0x65, 0x72, 0x74, 0x73, 0x32, 0x73, 0x62, 0x63, 0x61, 0x2e, 0x70, 0x37, 0x63, 0x30, 0x33, 0x06, + 0x03, 0x55, 0x1d, 0x20, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, + 0x01, 0x81, 0xb4, 0x7d, 0x01, 0x03, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, + 0xb4, 0x7d, 0x01, 0x02, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xb4, 0x7d, + 0x01, 0x01, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x1d, 0x36, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x82, + 0x01, 0x11, 0x06, 0x03, 0x55, 0x1d, 0x21, 0x04, 0x82, 0x01, 0x08, 0x30, 0x82, 0x01, 0x04, 0x30, + 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xb4, 0x7d, 0x01, 0x03, 0x06, 0x0a, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x0c, 0x30, 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0x81, 0xb4, 0x7d, 0x01, 0x02, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, + 0x01, 0x03, 0x15, 0x30, 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xb4, 0x7d, 0x01, + 0x02, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x03, 0x30, 0x18, 0x06, + 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xb4, 0x7d, 0x01, 0x01, 0x06, 0x0a, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x02, 0x30, 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, + 0x81, 0xb4, 0x7d, 0x01, 0x03, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, + 0x0f, 0x30, 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xb4, 0x7d, 0x01, 0x03, 0x06, + 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x04, 0x30, 0x18, 0x06, 0x0a, 0x2b, + 0x06, 0x01, 0x04, 0x01, 0x81, 0xb4, 0x7d, 0x01, 0x03, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x02, 0x01, 0x03, 0x18, 0x30, 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xb4, + 0x7d, 0x01, 0x03, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x16, 0x30, + 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xb4, 0x7d, 0x01, 0x02, 0x06, 0x0a, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x0e, 0x30, 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0x81, 0xb4, 0x7d, 0x01, 0x02, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, + 0x01, 0x03, 0x17, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x06, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x8e, 0x63, 0xe1, 0xe0, 0x65, 0x1c, 0x51, 0x91, 0x48, 0xeb, 0x96, 0x1e, 0xfb, 0x9f, 0xec, 0x57, + 0x5a, 0x32, 0x4a, 0xa9, 0x30, 0x40, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x39, 0x30, 0x37, 0x30, + 0x35, 0xa0, 0x33, 0xa0, 0x31, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x73, 0x62, 0x63, 0x61, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x2d, 0x62, 0x69, 0x6f, 0x70, + 0x68, 0x61, 0x72, 0x6d, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x63, 0x64, 0x70, 0x2f, 0x73, 0x62, + 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x86, 0x9a, 0x5c, 0x62, 0xff, 0x73, 0x93, 0xd5, 0xe1, 0x8a, 0x7f, 0x4a, 0xc6, 0x88, 0x2e, + 0x9f, 0x6e, 0xa0, 0xae, 0x12, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x0b, 0x17, 0x5e, 0x32, 0x75, 0x70, 0x6f, + 0x96, 0x51, 0xd7, 0x68, 0x5d, 0x5d, 0xa1, 0xbb, 0x98, 0x2e, 0xe8, 0xe4, 0x59, 0xd8, 0x43, 0x8f, + 0x8f, 0x01, 0x81, 0x30, 0xd7, 0x83, 0x5c, 0xe9, 0x7c, 0xc2, 0x81, 0xcf, 0x2d, 0x32, 0x04, 0xca, + 0x72, 0x9a, 0x7e, 0x43, 0x13, 0x2f, 0x99, 0x1b, 0xc3, 0xe6, 0x49, 0x31, 0x24, 0x85, 0x21, 0xc9, + 0x26, 0x6c, 0x94, 0x65, 0x9e, 0xd6, 0x09, 0xda, 0x6d, 0xd2, 0x42, 0x2a, 0x84, 0xc1, 0x60, 0x2f, + 0xc9, 0x3c, 0x36, 0x34, 0x23, 0x1c, 0x10, 0xa2, 0x43, 0xdf, 0xd0, 0x9b, 0x47, 0x60, 0xb8, 0x65, + 0x50, 0x3e, 0x68, 0x9d, 0x63, 0xd7, 0x14, 0x61, 0xd7, 0xcd, 0xdb, 0x9e, 0xc7, 0xaa, 0x55, 0xcd, + 0x68, 0x89, 0xb6, 0xbb, 0x54, 0xd1, 0x15, 0xa7, 0xfd, 0x7f, 0x76, 0x90, 0x83, 0xab, 0x0b, 0x59, + 0x88, 0x1d, 0xb6, 0x05, 0x8f, 0x2b, 0x43, 0x08, 0xbe, 0x2a, 0xef, 0xbe, 0xf5, 0x23, 0x26, 0x6a, + 0x74, 0x14, 0xd6, 0x76, 0x83, 0xec, 0x53, 0x47, 0xc3, 0x7b, 0xa0, 0xe3, 0x53, 0x8e, 0x5c, 0xee, + 0x1b, 0xd7, 0xf2, 0x8c, 0x0c, 0xac, 0x22, 0x2a, 0xa2, 0x99, 0x14, 0x27, 0x30, 0x11, 0x24, 0x07, + 0x5f, 0x2e, 0x78, 0x82, 0x1e, 0x1d, 0xf5, 0xcd, 0x1b, 0x04, 0x5a, 0xd9, 0xe5, 0x9b, 0x3a, 0x4e, + 0xa2, 0x0d, 0x72, 0xf2, 0x17, 0x8a, 0xf5, 0xc7, 0x70, 0x5e, 0x1c, 0x50, 0x8f, 0xed, 0x57, 0xc2, + 0x0c, 0x2c, 0xe5, 0x81, 0x96, 0xae, 0x51, 0x10, 0xe3, 0xa6, 0xe2, 0x77, 0x48, 0x47, 0xf6, 0x3a, + 0x03, 0xa2, 0x82, 0x2d, 0xfb, 0xfd, 0x5b, 0x5f, 0xfc, 0xec, 0x4f, 0xcc, 0x47, 0xad, 0xdc, 0x70, + 0x96, 0x93, 0xa8, 0xcb, 0xed, 0xdf, 0xba, 0xe7, 0xd9, 0xa5, 0x00, 0xe7, 0x61, 0xaf, 0x25, 0x2b, + 0xfd, 0x1b, 0x8a, 0xd2, 0xec, 0x94, 0xb3, 0x1e, 0x07, 0x30, 0x82, 0x06, 0xfd, 0x30, 0x82, 0x05, + 0xe5, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x00, 0x83, 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, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, + 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x27, + 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1e, 0x44, 0x6f, 0x44, 0x20, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x39, 0x30, + 0x37, 0x31, 0x34, 0x31, 0x34, 0x30, 0x37, 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x39, 0x30, 0x36, + 0x31, 0x34, 0x31, 0x34, 0x30, 0x37, 0x5a, 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, + 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, 0x44, 0x6f, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x32, 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, 0x2c, 0xc1, 0xf6, 0x8d, 0x3b, 0xac, 0xff, 0x3f, 0x3c, 0xd6, + 0x71, 0xbe, 0xb8, 0x74, 0x22, 0x07, 0xec, 0x70, 0x41, 0x15, 0xfc, 0xab, 0x40, 0xe3, 0x07, 0xaa, + 0xc1, 0xc3, 0xd8, 0x9f, 0xfe, 0xda, 0x4c, 0x3a, 0xbf, 0x3f, 0xc8, 0xd8, 0x28, 0x7b, 0x4b, 0x36, + 0x01, 0xc0, 0xac, 0x45, 0x25, 0xc3, 0xd2, 0x0e, 0x0a, 0x8f, 0x85, 0x18, 0x64, 0x10, 0x3d, 0x1a, + 0x13, 0x70, 0x2a, 0x6f, 0x8e, 0xd7, 0xdc, 0x8d, 0x93, 0xb3, 0x41, 0x0f, 0x38, 0x21, 0xcd, 0xad, + 0xab, 0xc2, 0x3d, 0x2a, 0x05, 0xd3, 0x57, 0x11, 0x37, 0x0d, 0xcd, 0x8c, 0x51, 0xf9, 0x93, 0xe3, + 0xcc, 0x46, 0x49, 0x21, 0x8e, 0x14, 0xb4, 0xcd, 0xcb, 0x14, 0x3e, 0x38, 0xcd, 0x72, 0x31, 0xee, + 0xab, 0x12, 0xf2, 0x65, 0xea, 0x34, 0x2e, 0x56, 0x5d, 0xff, 0xee, 0x63, 0x75, 0xcb, 0x6d, 0xba, + 0x91, 0x34, 0xfc, 0x9e, 0xf3, 0xf4, 0x2d, 0x1c, 0xbe, 0x50, 0xc4, 0x42, 0xdf, 0x59, 0x88, 0xff, + 0x6a, 0xb3, 0xfa, 0xa8, 0x6c, 0x3d, 0xcb, 0x56, 0x71, 0x71, 0x05, 0x96, 0xbb, 0x9f, 0x80, 0xe5, + 0x80, 0x45, 0x59, 0x67, 0x41, 0xb0, 0xeb, 0xc3, 0xad, 0x60, 0xa4, 0x80, 0x75, 0x06, 0x17, 0x9c, + 0x0e, 0xf4, 0x43, 0xe0, 0x99, 0x0e, 0x1b, 0xfb, 0x7f, 0xf5, 0xb3, 0xcc, 0xb2, 0x81, 0x82, 0xb1, + 0xfd, 0x32, 0xc1, 0xb8, 0xbe, 0x41, 0xa4, 0x64, 0xb5, 0x60, 0x3a, 0x5a, 0x51, 0x30, 0x8c, 0xce, + 0xde, 0x41, 0x2c, 0x19, 0x47, 0x5c, 0x49, 0x10, 0x64, 0xb9, 0x74, 0xa9, 0x87, 0x41, 0xaf, 0x7d, + 0x6e, 0xba, 0xc1, 0xb8, 0xa1, 0xbf, 0x65, 0x31, 0x3a, 0x04, 0x67, 0xf9, 0xb5, 0xbb, 0x8e, 0x92, + 0x8a, 0x00, 0x63, 0xb8, 0xb1, 0xe6, 0x8c, 0x38, 0x5f, 0x83, 0xff, 0x50, 0xd5, 0x3b, 0xa2, 0x5d, + 0x6b, 0xb2, 0x10, 0xcc, 0x63, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x03, 0xb8, 0x30, 0x82, + 0x03, 0xb4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x76, + 0x86, 0x1e, 0xdf, 0xed, 0x00, 0xc9, 0x7e, 0x14, 0x31, 0x7c, 0x5b, 0x94, 0x82, 0x21, 0x49, 0x57, + 0xbe, 0x70, 0x07, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x49, 0x74, + 0xbb, 0x0c, 0x5e, 0xba, 0x7a, 0xfe, 0x02, 0x54, 0xef, 0x7b, 0xa0, 0xc6, 0x95, 0xc6, 0x09, 0x80, + 0x70, 0x96, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x01, 0x06, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x24, 0x04, 0x05, 0x30, 0x03, 0x80, 0x01, 0x00, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, + 0xff, 0x30, 0x4b, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x44, 0x30, 0x42, 0x30, 0x0b, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x05, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x02, 0x01, 0x0b, 0x09, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, + 0x01, 0x0b, 0x12, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x13, + 0x30, 0x0c, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x0d, 0x30, 0x81, + 0xf0, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, 0xe8, 0x30, 0x81, 0xe5, 0x30, 0x3c, 0xa0, 0x3a, + 0xa0, 0x38, 0x86, 0x36, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x64, + 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x44, 0x4f, 0x44, 0x49, + 0x4e, 0x54, 0x45, 0x52, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x52, + 0x4f, 0x4f, 0x54, 0x43, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x81, 0xa4, 0xa0, 0x81, 0xa1, + 0xa0, 0x81, 0x9e, 0x86, 0x81, 0x9b, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, + 0x2e, 0x67, 0x64, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x6e, + 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, 0x32, 0x30, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, + 0x25, 0x32, 0x30, 0x43, 0x41, 0x25, 0x32, 0x30, 0x31, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, + 0x64, 0x50, 0x4b, 0x49, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, + 0x32, 0x63, 0x6f, 0x25, 0x33, 0x64, 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, 0x6f, 0x76, + 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x25, 0x32, 0x63, 0x63, 0x25, 0x33, 0x64, 0x55, 0x53, + 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, 0x3b, 0x62, 0x69, 0x6e, 0x61, 0x72, + 0x79, 0x30, 0x82, 0x01, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x82, 0x01, 0x11, 0x30, 0x82, 0x01, 0x0d, 0x30, 0x4a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, + 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x74, + 0x6f, 0x2f, 0x44, 0x4f, 0x44, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x42, + 0x49, 0x4c, 0x49, 0x54, 0x59, 0x52, 0x4f, 0x4f, 0x54, 0x43, 0x41, 0x31, 0x5f, 0x49, 0x54, 0x2e, + 0x70, 0x37, 0x63, 0x30, 0x20, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, + 0x14, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x73, + 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x30, 0x81, 0x9c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x02, 0x86, 0x81, 0x8f, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, + 0x67, 0x64, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x6e, 0x25, + 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, 0x32, 0x30, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, + 0x32, 0x30, 0x43, 0x41, 0x25, 0x32, 0x30, 0x31, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, + 0x50, 0x4b, 0x49, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, 0x32, + 0x63, 0x6f, 0x25, 0x33, 0x64, 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, 0x6f, 0x76, 0x65, + 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x25, 0x32, 0x63, 0x63, 0x25, 0x33, 0x64, 0x55, 0x53, 0x3f, + 0x63, 0x41, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3b, 0x62, 0x69, + 0x6e, 0x61, 0x72, 0x79, 0x30, 0x81, 0xdf, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x0b, 0x04, 0x81, 0xd2, 0x30, 0x81, 0xcf, 0x30, 0x3a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x05, 0x86, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, + 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x62, + 0x79, 0x2f, 0x44, 0x4f, 0x44, 0x52, 0x4f, 0x4f, 0x54, 0x43, 0x41, 0x32, 0x5f, 0x49, 0x42, 0x2e, + 0x70, 0x37, 0x63, 0x30, 0x81, 0x90, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x05, + 0x86, 0x81, 0x83, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x64, + 0x73, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x6e, 0x25, 0x33, 0x64, + 0x44, 0x6f, 0x44, 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43, 0x41, 0x25, + 0x32, 0x30, 0x32, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x50, 0x4b, 0x49, 0x25, 0x32, + 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, 0x32, 0x63, 0x6f, 0x25, 0x33, 0x64, + 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x25, 0x32, 0x63, 0x63, 0x25, 0x33, 0x64, 0x55, 0x53, 0x3f, 0x63, 0x72, 0x6f, 0x73, 0x73, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x69, 0x72, 0x3b, + 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x33, 0x1e, 0x8f, 0x7b, 0x86, 0xa6, + 0xef, 0xfc, 0xc0, 0x6e, 0x03, 0xeb, 0xf2, 0x29, 0xd9, 0x09, 0xed, 0xb6, 0x34, 0xdc, 0x13, 0x7c, + 0xf3, 0xac, 0x2e, 0x06, 0xc8, 0xad, 0x70, 0x62, 0x59, 0x96, 0x65, 0xb3, 0xce, 0x35, 0xa5, 0x4a, + 0x97, 0x87, 0xb8, 0xd3, 0xfe, 0x25, 0x0b, 0x79, 0xef, 0xc0, 0xf6, 0x7f, 0xd0, 0xe7, 0xea, 0x0f, + 0xb4, 0xe2, 0x58, 0xc6, 0x1a, 0xec, 0xcc, 0x99, 0x22, 0x4d, 0xae, 0xea, 0xca, 0x1f, 0x08, 0xb4, + 0x80, 0x97, 0xee, 0x32, 0x1c, 0x86, 0x20, 0x2e, 0x72, 0xff, 0x6d, 0xc0, 0x39, 0x59, 0x77, 0x26, + 0x98, 0xd6, 0x97, 0x0d, 0x6e, 0x28, 0x76, 0x91, 0x6f, 0x66, 0xc7, 0xde, 0x9d, 0x07, 0x56, 0x40, + 0x13, 0x8d, 0x79, 0x29, 0x28, 0x89, 0xb8, 0xda, 0x0a, 0x84, 0xed, 0x17, 0x8c, 0xfc, 0x96, 0x59, + 0x81, 0xee, 0xb7, 0x08, 0x19, 0x31, 0x73, 0xec, 0x94, 0x82, 0x71, 0xef, 0x85, 0x5e, 0xa8, 0xab, + 0x78, 0xde, 0x1a, 0x56, 0xaf, 0xfb, 0xc0, 0x6d, 0xd5, 0xa0, 0xf4, 0x95, 0x26, 0x96, 0x66, 0x23, + 0x1a, 0x93, 0xe5, 0xba, 0xe7, 0x60, 0x69, 0x38, 0xb8, 0xd8, 0xb0, 0x11, 0xae, 0x74, 0xaf, 0x31, + 0xe4, 0x41, 0x18, 0x99, 0x63, 0x1b, 0x42, 0x79, 0x5a, 0xc7, 0x65, 0xd9, 0xdf, 0x6d, 0x5f, 0xff, + 0x29, 0x20, 0xcb, 0x8b, 0xe5, 0x4e, 0x67, 0x28, 0x22, 0xa1, 0xe6, 0xae, 0xca, 0x9e, 0xd3, 0xc0, + 0xa8, 0x16, 0xf0, 0xbf, 0x63, 0x72, 0x70, 0x37, 0x4d, 0x42, 0xb1, 0x82, 0x46, 0x48, 0x67, 0x22, + 0x00, 0x6c, 0x6c, 0x63, 0x4a, 0x87, 0xef, 0xc0, 0xf1, 0x94, 0xf1, 0xdc, 0x75, 0x7c, 0x75, 0x38, + 0xc3, 0x4f, 0x97, 0xc9, 0xe3, 0x84, 0xf0, 0x95, 0xfc, 0x77, 0x66, 0x4b, 0xb1, 0x75, 0x7b, 0xef, + 0x0f, 0x53, 0x09, 0x88, 0x16, 0xda, 0x14, 0x06, 0x0a, 0x32, 0x30, 0x82, 0x07, 0x49, 0x30, 0x82, + 0x06, 0x31, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x5e, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x56, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x04, 0x46, 0x50, + 0x4b, 0x49, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x53, 0x48, 0x41, + 0x2d, 0x31, 0x20, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x33, 0x30, 0x33, 0x31, 0x38, 0x34, 0x34, + 0x30, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x30, 0x31, 0x30, 0x34, 0x35, 0x39, 0x35, + 0x39, 0x5a, 0x30, 0x6c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, + 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x1e, 0x44, 0x6f, 0x44, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 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, 0x9c, 0x7d, 0xb2, 0xf6, 0xcd, 0x5a, 0x1a, 0x5b, 0xb7, 0x30, 0xf5, 0x32, 0x2f, 0x0b, 0x9e, + 0x9a, 0xc3, 0x1c, 0xa8, 0x42, 0x32, 0x6b, 0x6c, 0x59, 0x57, 0x70, 0x42, 0x3c, 0x4a, 0xa9, 0xa9, + 0xb1, 0xdd, 0x42, 0xe0, 0x59, 0xbe, 0x78, 0x96, 0xc0, 0xff, 0x7b, 0xb9, 0x23, 0xbf, 0x5e, 0x49, + 0x32, 0xf1, 0x1b, 0x69, 0x73, 0xeb, 0xc6, 0x72, 0x47, 0xd7, 0x7f, 0x29, 0xbf, 0x6d, 0xd6, 0x93, + 0xe7, 0xb4, 0x61, 0xe4, 0xa4, 0x7c, 0x1c, 0xf0, 0x56, 0xcd, 0xd0, 0xb3, 0x99, 0x24, 0xc4, 0xc1, + 0x7d, 0xd5, 0xee, 0xd2, 0x83, 0x8d, 0x68, 0x68, 0x8c, 0x8e, 0x98, 0xe5, 0x5d, 0x29, 0x38, 0xc8, + 0xa6, 0xb3, 0xe7, 0xed, 0x21, 0x2b, 0x58, 0xba, 0x83, 0x5b, 0xbc, 0xf4, 0x03, 0x90, 0x3f, 0x60, + 0xee, 0x2b, 0x2f, 0x96, 0xd4, 0x2e, 0x37, 0x8f, 0xab, 0x2c, 0xb4, 0x1b, 0xa2, 0x80, 0x0d, 0x35, + 0x89, 0x47, 0x63, 0x44, 0x46, 0xc4, 0xaa, 0x45, 0x43, 0x7b, 0xc1, 0x3c, 0xd2, 0x21, 0x43, 0x8a, + 0x02, 0x76, 0x13, 0x6d, 0x7b, 0x57, 0x19, 0xbf, 0xa7, 0x38, 0x79, 0x9b, 0x5f, 0xfa, 0x6f, 0xdf, + 0xfa, 0x61, 0x8c, 0x07, 0xd9, 0x4d, 0xf2, 0x26, 0xef, 0xf2, 0x90, 0x35, 0x1f, 0xd7, 0xfd, 0x74, + 0x72, 0x90, 0x29, 0x36, 0xf1, 0x6e, 0x74, 0xc4, 0xdc, 0xf7, 0xb5, 0x1b, 0xd7, 0x85, 0x78, 0x21, + 0xaf, 0x20, 0xc9, 0x7a, 0xa5, 0x7d, 0x0e, 0x74, 0xe1, 0x8f, 0x24, 0x6c, 0x43, 0xd3, 0x09, 0xf4, + 0x83, 0xa5, 0x39, 0x12, 0x2e, 0x4f, 0xd4, 0x94, 0xfa, 0xb3, 0x5f, 0x07, 0xdb, 0x17, 0x83, 0x27, + 0x9e, 0x07, 0xa6, 0xca, 0x07, 0xde, 0xaf, 0x4a, 0x13, 0xee, 0x37, 0x2e, 0x37, 0xac, 0x91, 0xe8, + 0x2d, 0x6c, 0x82, 0x52, 0xbd, 0x02, 0x08, 0xae, 0x1f, 0x09, 0xbc, 0x0a, 0x23, 0xa0, 0x59, 0xfc, + 0xdd, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x04, 0x09, 0x30, 0x82, 0x04, 0x05, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, + 0x81, 0xec, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x81, 0xdf, 0x30, + 0x81, 0xdc, 0x30, 0x45, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x39, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x66, 0x70, 0x6b, 0x69, + 0x2e, 0x67, 0x6f, 0x76, 0x2f, 0x73, 0x68, 0x61, 0x31, 0x66, 0x72, 0x63, 0x61, 0x2f, 0x63, 0x61, + 0x43, 0x65, 0x72, 0x74, 0x73, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x54, 0x6f, 0x73, 0x68, 0x61, + 0x31, 0x66, 0x72, 0x63, 0x61, 0x2e, 0x70, 0x37, 0x63, 0x30, 0x81, 0x92, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x81, 0x85, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, + 0x6c, 0x64, 0x61, 0x70, 0x2e, 0x66, 0x70, 0x6b, 0x69, 0x2e, 0x67, 0x6f, 0x76, 0x2f, 0x63, 0x6e, + 0x3d, 0x53, 0x48, 0x41, 0x2d, 0x31, 0x25, 0x32, 0x30, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x6c, + 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43, 0x41, 0x2c, 0x6f, 0x75, 0x3d, + 0x46, 0x50, 0x4b, 0x49, 0x2c, 0x6f, 0x3d, 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, 0x6f, + 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x63, 0x3d, 0x55, 0x53, 0x3f, 0x63, 0x41, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3b, 0x62, 0x69, 0x6e, 0x61, + 0x72, 0x79, 0x2c, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x50, 0x61, 0x69, 0x72, 0x3b, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x30, 0x54, + 0x06, 0x03, 0x55, 0x1d, 0x21, 0x04, 0x4d, 0x30, 0x4b, 0x30, 0x17, 0x06, 0x0a, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x17, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, + 0x0b, 0x12, 0x30, 0x17, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x18, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x13, 0x30, 0x17, 0x06, 0x0a, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x19, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x02, 0x01, 0x0b, 0x12, 0x30, 0x64, 0x06, 0x03, 0x55, 0x1d, 0x1e, 0x01, 0x01, 0xff, 0x04, 0x5a, + 0x30, 0x58, 0xa0, 0x56, 0x30, 0x39, 0xa4, 0x37, 0x30, 0x35, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x30, + 0x19, 0xa4, 0x17, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, + 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x03, 0x6d, 0x69, 0x6c, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x0c, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, + 0x01, 0x03, 0x17, 0x30, 0x0c, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, + 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x19, 0x30, + 0x82, 0x01, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0b, 0x04, 0x81, 0xf5, + 0x30, 0x81, 0xf2, 0x30, 0x4a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x05, 0x86, + 0x3e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x64, 0x69, 0x73, 0x61, + 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x62, 0x79, 0x2f, 0x44, 0x4f, + 0x44, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54, + 0x59, 0x52, 0x4f, 0x4f, 0x54, 0x43, 0x41, 0x31, 0x5f, 0x49, 0x42, 0x2e, 0x70, 0x37, 0x63, 0x30, + 0x81, 0xa3, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x05, 0x86, 0x81, 0x96, 0x6c, + 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67, 0x64, 0x73, 0x2e, 0x64, 0x69, + 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x6e, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, + 0x32, 0x30, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43, 0x41, 0x25, 0x32, + 0x30, 0x31, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x50, 0x4b, 0x49, 0x25, 0x32, 0x63, + 0x6f, 0x75, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, 0x32, 0x63, 0x6f, 0x25, 0x33, 0x64, 0x55, + 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x25, 0x32, 0x63, 0x63, 0x25, 0x33, 0x64, 0x55, 0x53, 0x3f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x69, 0x72, 0x3b, 0x62, + 0x69, 0x6e, 0x61, 0x72, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0x86, 0x9a, 0x5c, 0x62, 0xff, 0x73, 0x93, 0xd5, 0xe1, 0x8a, 0x7f, 0x4a, 0xc6, 0x88, + 0x2e, 0x9f, 0x6e, 0xa0, 0xae, 0x12, 0x30, 0x81, 0xbb, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, + 0xb3, 0x30, 0x81, 0xb0, 0x30, 0x30, 0xa0, 0x2e, 0xa0, 0x2c, 0x86, 0x2a, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x66, 0x70, 0x6b, 0x69, 0x2e, 0x67, 0x6f, 0x76, + 0x2f, 0x73, 0x68, 0x61, 0x31, 0x66, 0x72, 0x63, 0x61, 0x2f, 0x73, 0x68, 0x61, 0x31, 0x66, 0x72, + 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x7c, 0xa0, 0x7a, 0xa0, 0x78, 0x86, 0x76, 0x6c, 0x64, + 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x64, 0x61, 0x70, 0x2e, 0x66, 0x70, 0x6b, 0x69, 0x2e, 0x67, + 0x6f, 0x76, 0x2f, 0x63, 0x6e, 0x25, 0x33, 0x64, 0x53, 0x48, 0x41, 0x2d, 0x31, 0x25, 0x32, 0x30, + 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x6c, 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, + 0x30, 0x43, 0x41, 0x2c, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x46, 0x50, 0x4b, 0x49, 0x2c, 0x6f, 0x25, + 0x33, 0x64, 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x2c, 0x63, 0x25, 0x33, 0x64, 0x55, 0x53, 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, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x76, + 0x86, 0x1e, 0xdf, 0xed, 0x00, 0xc9, 0x7e, 0x14, 0x31, 0x7c, 0x5b, 0x94, 0x82, 0x21, 0x49, 0x57, + 0xbe, 0x70, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x93, 0x3d, 0x43, 0xfc, 0xcd, 0x57, 0x46, 0x28, 0x5f, + 0xb3, 0xca, 0x78, 0xd6, 0x01, 0x3e, 0x71, 0x0e, 0xee, 0x0d, 0x09, 0xd0, 0xe0, 0xf9, 0xdd, 0x16, + 0xe9, 0xd4, 0xcb, 0x92, 0x5e, 0x8d, 0x9e, 0xfb, 0x2f, 0xf3, 0x49, 0x5e, 0x13, 0x81, 0xe3, 0x94, + 0xd6, 0x39, 0xd5, 0xb2, 0xe3, 0x99, 0x2c, 0x02, 0x0d, 0xa7, 0x42, 0x28, 0x48, 0x50, 0xd5, 0x18, + 0x73, 0x08, 0x3b, 0x36, 0xc6, 0x1f, 0x98, 0xc9, 0x22, 0x6f, 0xc1, 0xd7, 0xb2, 0x25, 0x18, 0x90, + 0x97, 0x5f, 0x20, 0x16, 0x7a, 0xb6, 0xa8, 0xbe, 0x14, 0xc6, 0xa5, 0x92, 0x29, 0x00, 0x81, 0x90, + 0x55, 0xcc, 0xb0, 0x12, 0x55, 0x0b, 0xc1, 0x59, 0xcd, 0x9b, 0x8e, 0xa9, 0x76, 0x92, 0x66, 0x92, + 0xa6, 0x56, 0x22, 0xd2, 0x5d, 0x5b, 0xf8, 0xe3, 0x46, 0x29, 0xe8, 0xbc, 0x23, 0xff, 0x12, 0x9e, + 0x0f, 0xc2, 0x24, 0x15, 0xc9, 0xff, 0x88, 0xbc, 0x6d, 0x43, 0xae, 0xae, 0x2e, 0x4e, 0xc8, 0x06, + 0x7a, 0xcf, 0x7f, 0x3e, 0xd0, 0x52, 0xed, 0x91, 0xed, 0x44, 0x87, 0x30, 0x51, 0xed, 0x96, 0xc4, + 0x2a, 0x0f, 0x98, 0x8f, 0x1d, 0x7e, 0xe2, 0x16, 0x80, 0xf3, 0x13, 0x75, 0x31, 0x26, 0xa8, 0x89, + 0x64, 0x27, 0x98, 0x8f, 0x85, 0x08, 0x61, 0xe2, 0x3e, 0x72, 0x01, 0x46, 0x06, 0x64, 0xf0, 0x3c, + 0x17, 0x94, 0x35, 0x73, 0xb5, 0x99, 0x13, 0x5a, 0x67, 0x5f, 0xd1, 0x18, 0x48, 0x3b, 0x4b, 0xc3, + 0xeb, 0xdc, 0x98, 0x30, 0xcf, 0x1d, 0x4f, 0xf7, 0x3b, 0xcf, 0xb6, 0xdf, 0x5b, 0x52, 0x8a, 0xb0, + 0x3a, 0x6c, 0x39, 0xcf, 0xc2, 0xa7, 0xf7, 0x9d, 0x94, 0xf5, 0x04, 0xb4, 0x88, 0x19, 0xe0, 0xeb, + 0x61, 0x79, 0xe0, 0xc7, 0xbf, 0xd9, 0x7c, 0x30, 0xc2, 0xfb, 0x5b, 0xfa, 0xaf, 0x69, 0x07, 0x7c, + 0x88, 0x4d, 0x1f, 0x94, 0xac, 0x5f, 0x45, 0x31, 0x82, 0x03, 0x43, 0x30, 0x82, 0x03, 0x3f, 0x02, + 0x01, 0x01, 0x30, 0x63, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, + 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, + 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x43, 0x41, + 0x2d, 0x32, 0x37, 0x02, 0x02, 0x0a, 0xa4, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, + 0x05, 0x00, 0xa0, 0x82, 0x01, 0xb5, 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, 0x37, 0x31, 0x36, 0x31, 0x38, 0x35, 0x34, 0x30, 0x32, 0x5a, 0x30, 0x23, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, 0x31, 0x16, 0x04, 0x14, 0x6e, + 0xd4, 0xc7, 0xd3, 0xb4, 0x31, 0xf0, 0xf0, 0x49, 0xf1, 0x35, 0x4f, 0xbd, 0x05, 0x1a, 0xd5, 0xcf, + 0xaa, 0x98, 0x06, 0x30, 0x6c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0f, + 0x31, 0x5f, 0x30, 0x5d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, + 0x2a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02, 0x30, 0x0a, + 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x02, 0x00, 0x80, 0x30, 0x0d, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x01, 0x40, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, + 0x02, 0x07, 0x30, 0x0d, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x01, + 0x28, 0x30, 0x72, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x10, 0x04, 0x31, 0x65, + 0x30, 0x63, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, + 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x43, 0x41, 0x2d, 0x32, + 0x37, 0x02, 0x02, 0x0a, 0xa5, 0x30, 0x74, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x09, 0x10, 0x02, 0x0b, 0x31, 0x65, 0xa0, 0x63, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, + 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, 0x49, + 0x4c, 0x20, 0x43, 0x41, 0x2d, 0x32, 0x37, 0x02, 0x02, 0x0a, 0xa5, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xce, 0x9a, + 0x3a, 0x83, 0xbc, 0xcd, 0xc0, 0x2f, 0xda, 0x88, 0x1f, 0x4e, 0x6e, 0x0f, 0x4d, 0x92, 0x8f, 0x30, + 0x1a, 0xdb, 0x85, 0x1b, 0x24, 0x07, 0xb5, 0x88, 0x09, 0xd5, 0xc2, 0x01, 0xfe, 0x8d, 0x62, 0x59, + 0xd9, 0xa4, 0x78, 0x7d, 0x77, 0xfe, 0xc9, 0xa2, 0xef, 0x36, 0x49, 0x56, 0x24, 0x1c, 0xc0, 0xb1, + 0x28, 0x02, 0xe7, 0x89, 0xcf, 0xb6, 0x79, 0x54, 0x7b, 0x3a, 0x1d, 0xba, 0xf9, 0xc1, 0x8d, 0xf9, + 0x24, 0x35, 0x30, 0x16, 0x19, 0xb9, 0x5f, 0x7e, 0xe8, 0xcc, 0xf0, 0x91, 0x20, 0x71, 0x2d, 0x87, + 0x4b, 0x43, 0xb8, 0x5d, 0xcb, 0x77, 0xd0, 0x75, 0xfe, 0xcd, 0x78, 0x62, 0x3a, 0xad, 0x75, 0x84, + 0x5d, 0x5e, 0x79, 0xec, 0xa1, 0xb4, 0x69, 0x3b, 0x05, 0xbd, 0x67, 0xc7, 0xcd, 0x85, 0xe3, 0xad, + 0x05, 0x69, 0xb6, 0xcc, 0x86, 0xe2, 0x64, 0x33, 0xfd, 0x88, 0x76, 0x09, 0xa9, 0x69, 0x92, 0x53, + 0x0b, 0xea, 0x25, 0xd0, 0xfb, 0x71, 0x52, 0x46, 0x43, 0x8d, 0x65, 0xf0, 0x7a, 0x3d, 0xde, 0x35, + 0xc3, 0xa1, 0x42, 0x93, 0xff, 0xd2, 0xa3, 0xee, 0x57, 0xfe, 0x12, 0xf3, 0x9d, 0xc9, 0x1f, 0xab, + 0x73, 0x5a, 0x75, 0xdf, 0xf6, 0x3c, 0x48, 0xb6, 0x30, 0x2e, 0x95, 0x1c, 0x16, 0x88, 0x1d, 0x77, + 0x44, 0xad, 0xaa, 0xc8, 0x47, 0xa9, 0x42, 0x7d, 0x06, 0x18, 0xd3, 0x60, 0x17, 0x9d, 0xc6, 0x6a, + 0x3b, 0xe2, 0x7c, 0x5d, 0x22, 0x57, 0xa6, 0xa6, 0x8c, 0x33, 0x1b, 0x76, 0x88, 0xd8, 0x18, 0x23, + 0x88, 0x49, 0xc9, 0x2c, 0x00, 0xd7, 0xf2, 0xcc, 0x93, 0xee, 0xab, 0xe6, 0x07, 0x1d, 0xb5, 0xee, + 0xdb, 0xb1, 0xd6, 0xd5, 0xcb, 0x2c, 0x9f, 0x85, 0xb6, 0x2e, 0x9a, 0xc3, 0xc7, 0x8a, 0x89, 0x8c, + 0xef, 0xc2, 0xb4, 0x9d, 0x7d, 0xd6, 0x21, 0xcd, 0xfd, 0xcf, 0xb0, 0xf9, 0xde, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +unsigned char _outlook15_ua_content[] = { + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x6d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x3b, 0x0d, 0x0a, 0x09, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x3d, + 0x22, 0x2d, 0x2d, 0x2d, 0x2d, 0x3d, 0x5f, 0x4e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x72, 0x74, 0x5f, + 0x30, 0x30, 0x31, 0x5f, 0x30, 0x30, 0x43, 0x36, 0x5f, 0x30, 0x31, 0x43, 0x46, 0x32, 0x43, 0x39, + 0x37, 0x2e, 0x31, 0x42, 0x32, 0x33, 0x46, 0x39, 0x36, 0x30, 0x22, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x3d, 0x5f, 0x4e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x72, + 0x74, 0x5f, 0x30, 0x30, 0x31, 0x5f, 0x30, 0x30, 0x43, 0x36, 0x5f, 0x30, 0x31, 0x43, 0x46, 0x32, + 0x43, 0x39, 0x37, 0x2e, 0x31, 0x42, 0x32, 0x33, 0x46, 0x39, 0x36, 0x30, 0x0d, 0x0a, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x0d, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, + 0x74, 0x3d, 0x22, 0x75, 0x73, 0x2d, 0x61, 0x73, 0x63, 0x69, 0x69, 0x22, 0x0d, 0x0a, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x45, + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x37, 0x62, 0x69, 0x74, 0x0d, 0x0a, 0x0d, + 0x0a, 0x48, 0x6f, 0x70, 0x65, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x68, 0x65, 0x6c, 0x70, 0x2e, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x0d, + 0x0a, 0x0d, 0x0a, 0x42, 0x61, 0x69, 0x6c, 0x65, 0x79, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x3d, 0x5f, 0x4e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x72, 0x74, 0x5f, + 0x30, 0x30, 0x31, 0x5f, 0x30, 0x30, 0x43, 0x36, 0x5f, 0x30, 0x31, 0x43, 0x46, 0x32, 0x43, 0x39, + 0x37, 0x2e, 0x31, 0x42, 0x32, 0x33, 0x46, 0x39, 0x36, 0x30, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, + 0x74, 0x6d, 0x6c, 0x3b, 0x0d, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x22, + 0x75, 0x73, 0x2d, 0x61, 0x73, 0x63, 0x69, 0x69, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x45, 0x6e, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x64, 0x2d, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0d, 0x0a, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x20, + 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x76, 0x3d, 0x33, 0x44, 0x22, 0x75, 0x72, 0x6e, 0x3a, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x2d, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, + 0x2d, 0x63, 0x6f, 0x6d, 0x3a, 0x76, 0x6d, 0x6c, 0x22, 0x20, 0x3d, 0x0d, 0x0a, 0x78, 0x6d, 0x6c, + 0x6e, 0x73, 0x3a, 0x6f, 0x3d, 0x33, 0x44, 0x22, 0x75, 0x72, 0x6e, 0x3a, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x73, 0x2d, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2d, 0x63, 0x6f, + 0x6d, 0x3a, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x3a, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x22, + 0x20, 0x3d, 0x0d, 0x0a, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x77, 0x3d, 0x33, 0x44, 0x22, 0x75, + 0x72, 0x6e, 0x3a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x2d, 0x6d, 0x69, 0x63, 0x72, 0x6f, + 0x73, 0x6f, 0x66, 0x74, 0x2d, 0x63, 0x6f, 0x6d, 0x3a, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x3a, + 0x77, 0x6f, 0x72, 0x64, 0x22, 0x20, 0x3d, 0x0d, 0x0a, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x6d, + 0x3d, 0x33, 0x44, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x73, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x65, 0x2f, 0x32, 0x30, 0x30, 0x34, 0x2f, 0x31, 0x32, 0x2f, + 0x6f, 0x6d, 0x6d, 0x6c, 0x22, 0x20, 0x3d, 0x0d, 0x0a, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x33, + 0x44, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x52, 0x45, 0x43, 0x2d, 0x68, 0x74, 0x6d, 0x6c, 0x34, + 0x30, 0x22, 0x3e, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x4d, 0x45, 0x54, 0x41, 0x20, 0x3d, + 0x0d, 0x0a, 0x48, 0x54, 0x54, 0x50, 0x2d, 0x45, 0x51, 0x55, 0x49, 0x56, 0x3d, 0x33, 0x44, 0x22, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x22, 0x20, 0x43, 0x4f, + 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x3d, 0x33, 0x44, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, + 0x6d, 0x6c, 0x3b, 0x20, 0x3d, 0x0d, 0x0a, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x33, + 0x44, 0x75, 0x73, 0x2d, 0x61, 0x73, 0x63, 0x69, 0x69, 0x22, 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, + 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x33, 0x44, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x3d, 0x33, 0x44, 0x22, 0x4d, 0x69, 0x63, + 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x57, 0x6f, 0x72, 0x64, 0x20, 0x31, 0x35, 0x20, 0x3d, + 0x0d, 0x0a, 0x28, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x64, 0x69, + 0x75, 0x6d, 0x29, 0x22, 0x3e, 0x3c, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e, 0x3c, 0x21, 0x2d, 0x2d, + 0x0d, 0x0a, 0x2f, 0x2a, 0x20, 0x46, 0x6f, 0x6e, 0x74, 0x20, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x2a, 0x2f, 0x0d, 0x0a, 0x40, 0x66, 0x6f, 0x6e, 0x74, 0x2d, + 0x66, 0x61, 0x63, 0x65, 0x0d, 0x0a, 0x09, 0x7b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, + 0x69, 0x6c, 0x79, 0x3a, 0x22, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x61, 0x20, 0x4d, 0x61, 0x74, + 0x68, 0x22, 0x3b, 0x0d, 0x0a, 0x09, 0x70, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x2d, 0x31, 0x3a, 0x32, + 0x20, 0x34, 0x20, 0x35, 0x20, 0x33, 0x20, 0x35, 0x20, 0x34, 0x20, 0x36, 0x20, 0x33, 0x20, 0x32, + 0x20, 0x34, 0x3b, 0x7d, 0x0d, 0x0a, 0x40, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x63, 0x65, + 0x0d, 0x0a, 0x09, 0x7b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, + 0x43, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x3b, 0x0d, 0x0a, 0x09, 0x70, 0x61, 0x6e, 0x6f, 0x73, + 0x65, 0x2d, 0x31, 0x3a, 0x32, 0x20, 0x31, 0x35, 0x20, 0x35, 0x20, 0x32, 0x20, 0x32, 0x20, 0x32, + 0x20, 0x34, 0x20, 0x33, 0x20, 0x32, 0x20, 0x34, 0x3b, 0x7d, 0x0d, 0x0a, 0x2f, 0x2a, 0x20, 0x53, + 0x74, 0x79, 0x6c, 0x65, 0x20, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x20, 0x2a, 0x2f, 0x0d, 0x0a, 0x70, 0x2e, 0x4d, 0x73, 0x6f, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, + 0x2c, 0x20, 0x6c, 0x69, 0x2e, 0x4d, 0x73, 0x6f, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2c, 0x20, + 0x64, 0x69, 0x76, 0x2e, 0x4d, 0x73, 0x6f, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x0d, 0x0a, 0x09, + 0x7b, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x30, 0x69, 0x6e, 0x3b, 0x0d, 0x0a, 0x09, 0x6d, + 0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x3a, 0x2e, 0x30, 0x30, + 0x30, 0x31, 0x70, 0x74, 0x3b, 0x0d, 0x0a, 0x09, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, + 0x65, 0x3a, 0x31, 0x31, 0x2e, 0x30, 0x70, 0x74, 0x3b, 0x0d, 0x0a, 0x09, 0x66, 0x6f, 0x6e, 0x74, + 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x22, 0x43, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x22, 0x2c, 0x22, 0x73, 0x61, 0x6e, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x22, 0x3b, 0x7d, + 0x0d, 0x0a, 0x61, 0x3a, 0x6c, 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x73, 0x70, 0x61, 0x6e, 0x2e, 0x4d, + 0x73, 0x6f, 0x48, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x6b, 0x0d, 0x0a, 0x09, 0x7b, 0x6d, + 0x73, 0x6f, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2d, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x3a, 0x39, 0x39, 0x3b, 0x0d, 0x0a, 0x09, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x23, 0x30, + 0x35, 0x36, 0x33, 0x43, 0x31, 0x3b, 0x0d, 0x0a, 0x09, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, + 0x63, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x69, + 0x6e, 0x65, 0x3b, 0x7d, 0x0d, 0x0a, 0x61, 0x3a, 0x76, 0x69, 0x73, 0x69, 0x74, 0x65, 0x64, 0x2c, + 0x20, 0x73, 0x70, 0x61, 0x6e, 0x2e, 0x4d, 0x73, 0x6f, 0x48, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x69, + 0x6e, 0x6b, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x0d, 0x0a, 0x09, 0x7b, 0x6d, 0x73, + 0x6f, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2d, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x3a, 0x39, 0x39, 0x3b, 0x0d, 0x0a, 0x09, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x23, 0x39, 0x35, + 0x34, 0x46, 0x37, 0x32, 0x3b, 0x0d, 0x0a, 0x09, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x64, 0x65, 0x63, + 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x69, 0x6e, + 0x65, 0x3b, 0x7d, 0x0d, 0x0a, 0x73, 0x70, 0x61, 0x6e, 0x2e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x53, + 0x74, 0x79, 0x6c, 0x65, 0x31, 0x37, 0x0d, 0x0a, 0x09, 0x7b, 0x6d, 0x73, 0x6f, 0x2d, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, + 0x6c, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x3b, 0x0d, 0x0a, 0x09, 0x66, 0x6f, 0x6e, + 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x22, 0x43, 0x61, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x22, 0x2c, 0x22, 0x73, 0x61, 0x6e, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x22, 0x3b, + 0x0d, 0x0a, 0x09, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x74, + 0x65, 0x78, 0x74, 0x3b, 0x7d, 0x0d, 0x0a, 0x2e, 0x4d, 0x73, 0x6f, 0x43, 0x68, 0x70, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x0d, 0x0a, 0x09, 0x7b, 0x6d, 0x73, 0x6f, 0x2d, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x6f, + 0x6e, 0x6c, 0x79, 0x3b, 0x0d, 0x0a, 0x09, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, + 0x6c, 0x79, 0x3a, 0x22, 0x43, 0x61, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x22, 0x2c, 0x22, 0x73, 0x61, + 0x6e, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x22, 0x3b, 0x7d, 0x0d, 0x0a, 0x40, 0x70, 0x61, + 0x67, 0x65, 0x20, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x0d, + 0x0a, 0x09, 0x7b, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x38, 0x2e, 0x35, 0x69, 0x6e, 0x20, 0x31, 0x31, + 0x2e, 0x30, 0x69, 0x6e, 0x3b, 0x0d, 0x0a, 0x09, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x31, + 0x2e, 0x30, 0x69, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x69, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x69, 0x6e, + 0x20, 0x31, 0x2e, 0x30, 0x69, 0x6e, 0x3b, 0x7d, 0x0d, 0x0a, 0x64, 0x69, 0x76, 0x2e, 0x57, 0x6f, + 0x72, 0x64, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x0d, 0x0a, 0x09, 0x7b, 0x70, 0x61, + 0x67, 0x65, 0x3a, 0x57, 0x6f, 0x72, 0x64, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x3b, + 0x7d, 0x0d, 0x0a, 0x2d, 0x2d, 0x3e, 0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e, 0x3c, 0x21, + 0x2d, 0x2d, 0x5b, 0x69, 0x66, 0x20, 0x67, 0x74, 0x65, 0x20, 0x6d, 0x73, 0x6f, 0x20, 0x39, 0x5d, + 0x3e, 0x3c, 0x78, 0x6d, 0x6c, 0x3e, 0x0d, 0x0a, 0x3c, 0x6f, 0x3a, 0x73, 0x68, 0x61, 0x70, 0x65, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x76, 0x3a, 0x65, 0x78, 0x74, 0x3d, 0x33, + 0x44, 0x22, 0x65, 0x64, 0x69, 0x74, 0x22, 0x20, 0x73, 0x70, 0x69, 0x64, 0x6d, 0x61, 0x78, 0x3d, + 0x33, 0x44, 0x22, 0x31, 0x30, 0x32, 0x36, 0x22, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x78, + 0x6d, 0x6c, 0x3e, 0x3c, 0x21, 0x5b, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x5d, 0x2d, 0x2d, 0x3e, 0x3c, + 0x21, 0x2d, 0x2d, 0x5b, 0x69, 0x66, 0x20, 0x67, 0x74, 0x65, 0x20, 0x6d, 0x73, 0x6f, 0x20, 0x39, + 0x5d, 0x3e, 0x3c, 0x78, 0x6d, 0x6c, 0x3e, 0x0d, 0x0a, 0x3c, 0x6f, 0x3a, 0x73, 0x68, 0x61, 0x70, + 0x65, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x20, 0x76, 0x3a, 0x65, 0x78, 0x74, 0x3d, 0x33, 0x44, + 0x22, 0x65, 0x64, 0x69, 0x74, 0x22, 0x3e, 0x0d, 0x0a, 0x3c, 0x6f, 0x3a, 0x69, 0x64, 0x6d, 0x61, + 0x70, 0x20, 0x76, 0x3a, 0x65, 0x78, 0x74, 0x3d, 0x33, 0x44, 0x22, 0x65, 0x64, 0x69, 0x74, 0x22, + 0x20, 0x64, 0x61, 0x74, 0x61, 0x3d, 0x33, 0x44, 0x22, 0x31, 0x22, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, + 0x3c, 0x2f, 0x6f, 0x3a, 0x73, 0x68, 0x61, 0x70, 0x65, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x3e, + 0x3c, 0x2f, 0x78, 0x6d, 0x6c, 0x3e, 0x3c, 0x21, 0x5b, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x5d, 0x2d, + 0x2d, 0x3e, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6c, + 0x61, 0x6e, 0x67, 0x3d, 0x33, 0x44, 0x45, 0x4e, 0x2d, 0x55, 0x53, 0x20, 0x3d, 0x0d, 0x0a, 0x6c, + 0x69, 0x6e, 0x6b, 0x3d, 0x33, 0x44, 0x22, 0x23, 0x30, 0x35, 0x36, 0x33, 0x43, 0x31, 0x22, 0x20, + 0x76, 0x6c, 0x69, 0x6e, 0x6b, 0x3d, 0x33, 0x44, 0x22, 0x23, 0x39, 0x35, 0x34, 0x46, 0x37, 0x32, + 0x22, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x33, 0x44, 0x57, + 0x6f, 0x72, 0x64, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x3e, 0x3c, 0x70, 0x20, 0x3d, + 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x33, 0x44, 0x4d, 0x73, 0x6f, 0x4e, 0x6f, 0x72, + 0x6d, 0x61, 0x6c, 0x3e, 0x48, 0x6f, 0x70, 0x65, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x68, 0x65, 0x6c, 0x70, 0x2e, 0x3c, 0x6f, 0x3a, + 0x70, 0x3e, 0x3c, 0x2f, 0x6f, 0x3a, 0x70, 0x3e, 0x3c, 0x2f, 0x70, 0x3e, 0x3c, 0x70, 0x20, 0x3d, + 0x0d, 0x0a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x33, 0x44, 0x4d, 0x73, 0x6f, 0x4e, 0x6f, 0x72, + 0x6d, 0x61, 0x6c, 0x3e, 0x3c, 0x6f, 0x3a, 0x70, 0x3e, 0x26, 0x6e, 0x62, 0x73, 0x70, 0x3b, 0x3c, + 0x2f, 0x6f, 0x3a, 0x70, 0x3e, 0x3c, 0x2f, 0x70, 0x3e, 0x3c, 0x70, 0x20, 0x3d, 0x0d, 0x0a, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x33, 0x44, 0x4d, 0x73, 0x6f, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, + 0x3e, 0x42, 0x61, 0x69, 0x6c, 0x65, 0x79, 0x3c, 0x6f, 0x3a, 0x70, 0x3e, 0x3c, 0x2f, 0x6f, 0x3a, + 0x70, 0x3e, 0x3c, 0x2f, 0x70, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, + 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x3d, 0x5f, 0x4e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x72, 0x74, 0x5f, 0x30, 0x30, 0x31, + 0x5f, 0x30, 0x30, 0x43, 0x36, 0x5f, 0x30, 0x31, 0x43, 0x46, 0x32, 0x43, 0x39, 0x37, 0x2e, 0x31, + 0x42, 0x32, 0x33, 0x46, 0x39, 0x36, 0x30, 0x2d, 0x2d, 0x0d, 0x0a +}; + +unsigned char _outlook15_ua_cms[] = { + 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x80, 0x30, + 0x80, 0x02, 0x01, 0x01, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x00, 0x00, + 0xa0, 0x82, 0x12, 0x8b, 0x30, 0x82, 0x03, 0x70, 0x30, 0x82, 0x02, 0x58, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x01, 0x05, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, + 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x0d, 0x44, 0x6f, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x34, 0x31, 0x32, 0x31, 0x33, 0x31, 0x35, 0x30, 0x30, 0x31, 0x30, + 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x31, 0x32, 0x30, 0x35, 0x31, 0x35, 0x30, 0x30, 0x31, 0x30, 0x5a, + 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, + 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, + 0x44, 0x6f, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 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, 0x2c, + 0xc1, 0xf6, 0x8d, 0x3b, 0xac, 0xff, 0x3f, 0x3c, 0xd6, 0x71, 0xbe, 0xb8, 0x74, 0x22, 0x07, 0xec, + 0x70, 0x41, 0x15, 0xfc, 0xab, 0x40, 0xe3, 0x07, 0xaa, 0xc1, 0xc3, 0xd8, 0x9f, 0xfe, 0xda, 0x4c, + 0x3a, 0xbf, 0x3f, 0xc8, 0xd8, 0x28, 0x7b, 0x4b, 0x36, 0x01, 0xc0, 0xac, 0x45, 0x25, 0xc3, 0xd2, + 0x0e, 0x0a, 0x8f, 0x85, 0x18, 0x64, 0x10, 0x3d, 0x1a, 0x13, 0x70, 0x2a, 0x6f, 0x8e, 0xd7, 0xdc, + 0x8d, 0x93, 0xb3, 0x41, 0x0f, 0x38, 0x21, 0xcd, 0xad, 0xab, 0xc2, 0x3d, 0x2a, 0x05, 0xd3, 0x57, + 0x11, 0x37, 0x0d, 0xcd, 0x8c, 0x51, 0xf9, 0x93, 0xe3, 0xcc, 0x46, 0x49, 0x21, 0x8e, 0x14, 0xb4, + 0xcd, 0xcb, 0x14, 0x3e, 0x38, 0xcd, 0x72, 0x31, 0xee, 0xab, 0x12, 0xf2, 0x65, 0xea, 0x34, 0x2e, + 0x56, 0x5d, 0xff, 0xee, 0x63, 0x75, 0xcb, 0x6d, 0xba, 0x91, 0x34, 0xfc, 0x9e, 0xf3, 0xf4, 0x2d, + 0x1c, 0xbe, 0x50, 0xc4, 0x42, 0xdf, 0x59, 0x88, 0xff, 0x6a, 0xb3, 0xfa, 0xa8, 0x6c, 0x3d, 0xcb, + 0x56, 0x71, 0x71, 0x05, 0x96, 0xbb, 0x9f, 0x80, 0xe5, 0x80, 0x45, 0x59, 0x67, 0x41, 0xb0, 0xeb, + 0xc3, 0xad, 0x60, 0xa4, 0x80, 0x75, 0x06, 0x17, 0x9c, 0x0e, 0xf4, 0x43, 0xe0, 0x99, 0x0e, 0x1b, + 0xfb, 0x7f, 0xf5, 0xb3, 0xcc, 0xb2, 0x81, 0x82, 0xb1, 0xfd, 0x32, 0xc1, 0xb8, 0xbe, 0x41, 0xa4, + 0x64, 0xb5, 0x60, 0x3a, 0x5a, 0x51, 0x30, 0x8c, 0xce, 0xde, 0x41, 0x2c, 0x19, 0x47, 0x5c, 0x49, + 0x10, 0x64, 0xb9, 0x74, 0xa9, 0x87, 0x41, 0xaf, 0x7d, 0x6e, 0xba, 0xc1, 0xb8, 0xa1, 0xbf, 0x65, + 0x31, 0x3a, 0x04, 0x67, 0xf9, 0xb5, 0xbb, 0x8e, 0x92, 0x8a, 0x00, 0x63, 0xb8, 0xb1, 0xe6, 0x8c, + 0x38, 0x5f, 0x83, 0xff, 0x50, 0xd5, 0x3b, 0xa2, 0x5d, 0x6b, 0xb2, 0x10, 0xcc, 0x63, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x3f, 0x30, 0x3d, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0x49, 0x74, 0xbb, 0x0c, 0x5e, 0xba, 0x7a, 0xfe, 0x02, 0x54, 0xef, 0x7b, 0xa0, 0xc6, + 0x95, 0xc6, 0x09, 0x80, 0x70, 0x96, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x86, 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, + 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x98, 0x91, 0x8d, 0x3f, 0x89, 0xc8, 0xbb, 0xf5, + 0xc0, 0x69, 0x73, 0x29, 0x3b, 0x35, 0xac, 0xba, 0xb3, 0x08, 0x76, 0x3d, 0x70, 0x09, 0x92, 0xe9, + 0x84, 0x44, 0x21, 0x01, 0x7d, 0x14, 0x76, 0x1b, 0xee, 0x51, 0x6c, 0x1d, 0x8d, 0x15, 0x37, 0x2d, + 0x7b, 0x31, 0x69, 0xf4, 0x9a, 0x44, 0xb8, 0xaf, 0x46, 0xcc, 0x34, 0xfa, 0x23, 0xcb, 0x03, 0x27, + 0x19, 0xd2, 0x83, 0x21, 0x75, 0x2b, 0xe7, 0xe0, 0x1b, 0x99, 0x26, 0xdc, 0x84, 0x40, 0x95, 0xe8, + 0xa8, 0xd2, 0xcc, 0xf6, 0x58, 0x5c, 0x66, 0xef, 0x3f, 0x4a, 0x97, 0x10, 0x82, 0x1d, 0xba, 0x0a, + 0xa2, 0xdd, 0x5b, 0x06, 0x2b, 0x9d, 0xa7, 0x64, 0x4e, 0xeb, 0x2e, 0x01, 0x35, 0xa4, 0xb4, 0x3f, + 0x13, 0xad, 0x55, 0xe4, 0xd5, 0x73, 0xa8, 0x69, 0x9b, 0x11, 0xf1, 0x98, 0xf2, 0x31, 0x1e, 0x6f, + 0x40, 0xd4, 0xf8, 0x78, 0x9f, 0x8e, 0x91, 0xa0, 0x6f, 0x70, 0x04, 0x90, 0x66, 0xaa, 0x06, 0x2b, + 0xce, 0xe1, 0x7a, 0x92, 0xb5, 0x7d, 0xe1, 0xe0, 0xd1, 0x96, 0xe7, 0xa1, 0x3a, 0x2d, 0xcc, 0xb1, + 0x9d, 0x1f, 0x05, 0x44, 0xed, 0x87, 0x99, 0xd3, 0x4d, 0x1a, 0x70, 0x39, 0xc1, 0x04, 0x0c, 0xe5, + 0x7e, 0xd9, 0xf1, 0xaf, 0xd7, 0x20, 0x0e, 0xf1, 0x22, 0x7a, 0x25, 0xa4, 0x73, 0x99, 0xcc, 0x3f, + 0xa4, 0x07, 0x27, 0x96, 0xa8, 0xa2, 0x95, 0xed, 0x82, 0xb9, 0x16, 0xd3, 0x9e, 0x0b, 0x87, 0xc2, + 0xc1, 0xf2, 0x88, 0xf5, 0x62, 0xdf, 0x68, 0xdf, 0xc7, 0xbc, 0x69, 0x51, 0xed, 0xb1, 0x5c, 0xdc, + 0x54, 0x54, 0x29, 0x0f, 0x09, 0x39, 0x9a, 0xac, 0x03, 0xc1, 0xdb, 0x0c, 0x4d, 0xae, 0x6f, 0x0a, + 0x7a, 0x16, 0x49, 0xf1, 0xbf, 0x91, 0xd2, 0x38, 0x94, 0xd3, 0xf6, 0x95, 0x2c, 0xb7, 0x6c, 0xc9, + 0x42, 0xb6, 0x8d, 0xca, 0x90, 0x8d, 0x85, 0xd9, 0x30, 0x82, 0x04, 0xb7, 0x30, 0x82, 0x03, 0x9f, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x51, 0x28, 0xe9, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, + 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, + 0x49, 0x4c, 0x20, 0x43, 0x41, 0x2d, 0x33, 0x30, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, + 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x31, 0x31, + 0x32, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x7b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, + 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x0c, 0x30, + 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x4f, 0x53, 0x44, 0x31, 0x28, 0x30, 0x26, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x1f, 0x42, 0x41, 0x53, 0x49, 0x4c, 0x45, 0x2e, 0x42, 0x41, 0x49, + 0x4c, 0x45, 0x59, 0x2e, 0x45, 0x4c, 0x49, 0x53, 0x53, 0x45, 0x2e, 0x31, 0x34, 0x30, 0x30, 0x36, + 0x37, 0x32, 0x35, 0x38, 0x36, 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, 0x8d, 0x54, 0x5b, 0x5b, 0x1b, 0x70, 0xfa, 0x2a, 0x34, 0xf2, + 0xff, 0xd7, 0xcc, 0x8e, 0xe4, 0x48, 0xd0, 0xfc, 0x3b, 0x07, 0x40, 0xa5, 0x87, 0xc5, 0x7f, 0x99, + 0x2e, 0xc5, 0x0a, 0x8e, 0x4a, 0xd3, 0x9a, 0x02, 0xbb, 0x80, 0x59, 0xd6, 0x46, 0x4d, 0x7c, 0xb6, + 0x58, 0x9d, 0xfd, 0x8c, 0xdf, 0xe5, 0xbc, 0x27, 0x16, 0x03, 0x56, 0xed, 0x47, 0xb4, 0x21, 0x38, + 0xdb, 0x94, 0x23, 0x31, 0xd6, 0x51, 0x64, 0x31, 0xbd, 0x20, 0x71, 0x1a, 0xef, 0xb6, 0x1d, 0x83, + 0xd6, 0xaa, 0x2f, 0x41, 0x1a, 0xae, 0x1f, 0x91, 0xf8, 0x51, 0x5c, 0x7a, 0xfa, 0x9f, 0x13, 0xd1, + 0x49, 0xdd, 0x0d, 0xc8, 0x75, 0xbb, 0x76, 0x73, 0xf6, 0x14, 0xee, 0x83, 0x07, 0xb3, 0x82, 0xe9, + 0x50, 0x97, 0x3f, 0xf3, 0x90, 0x58, 0xe7, 0xfd, 0xd3, 0x5f, 0x33, 0x13, 0x6f, 0x01, 0x83, 0x26, + 0x46, 0x82, 0xf9, 0xb4, 0xf4, 0xec, 0xb3, 0x73, 0x75, 0xe7, 0x10, 0x79, 0xaa, 0x98, 0x6e, 0xdc, + 0x51, 0x03, 0x1c, 0x36, 0x1b, 0x8e, 0xd8, 0xad, 0x7b, 0x89, 0x94, 0x74, 0x32, 0x99, 0xb3, 0x0a, + 0x88, 0x0d, 0x22, 0xd7, 0xb8, 0xda, 0xbc, 0xfe, 0x43, 0x87, 0x73, 0x56, 0xcd, 0x94, 0x5f, 0xa2, + 0xff, 0xca, 0x42, 0xdf, 0xc7, 0xa1, 0xe3, 0x2b, 0xbf, 0xab, 0x1a, 0x65, 0xee, 0x5e, 0xa9, 0x82, + 0x78, 0xaf, 0xa3, 0x10, 0xa8, 0x95, 0x0b, 0x95, 0xd8, 0xc4, 0xee, 0xd1, 0x5a, 0xf7, 0x00, 0x03, + 0xbd, 0x1c, 0x41, 0x3a, 0x7b, 0x78, 0xd5, 0x7b, 0xa9, 0x0c, 0x22, 0x40, 0x0a, 0xca, 0x86, 0xb2, + 0xd1, 0xbc, 0x1d, 0x24, 0x86, 0x63, 0x58, 0xad, 0x70, 0xcd, 0x67, 0x1b, 0x2d, 0x52, 0x5b, 0xaa, + 0x1c, 0x6e, 0x0b, 0xe7, 0x8b, 0xdc, 0x30, 0x69, 0x7e, 0x47, 0xf9, 0x91, 0x36, 0xbe, 0x9c, 0xab, + 0xf4, 0x02, 0xf9, 0x6f, 0x99, 0x7b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x60, 0x30, + 0x82, 0x01, 0x5c, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x35, 0x61, 0x66, 0x28, 0x09, 0xbc, 0x56, 0x25, 0x5b, 0x8b, 0xcc, 0xbf, 0x81, 0x5e, 0x61, 0x2c, + 0x30, 0x39, 0xd3, 0x21, 0x30, 0x3a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, + 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, + 0x6c, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x44, + 0x4f, 0x44, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x43, 0x41, 0x5f, 0x33, 0x30, 0x2e, 0x63, 0x72, 0x6c, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0x20, + 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1c, 0x30, 0x1a, 0x30, 0x0b, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x09, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x02, 0x01, 0x0b, 0x13, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0xa8, 0x57, 0x8e, 0xa4, 0x5c, 0x37, 0xcf, 0x82, 0x15, 0xea, 0xba, 0xef, 0xa5, 0xcf, 0x24, 0x17, + 0x96, 0xc5, 0xda, 0x8b, 0x30, 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, + 0x04, 0x5c, 0x30, 0x5a, 0x30, 0x36, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, + 0x86, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x64, 0x69, 0x73, + 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x2f, 0x44, 0x4f, 0x44, 0x45, 0x4d, + 0x41, 0x49, 0x4c, 0x43, 0x41, 0x5f, 0x33, 0x30, 0x2e, 0x63, 0x65, 0x72, 0x30, 0x20, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x14, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x30, 0x22, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x1b, 0x30, 0x19, 0x81, 0x17, 0x62, 0x61, 0x69, 0x6c, 0x65, + 0x79, 0x40, 0x65, 0x63, 0x6c, 0x69, 0x70, 0x73, 0x65, 0x2e, 0x6e, 0x63, 0x73, 0x63, 0x2e, 0x6d, + 0x69, 0x6c, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x09, 0x04, 0x14, 0x30, 0x12, 0x30, 0x10, 0x06, + 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x09, 0x04, 0x31, 0x04, 0x13, 0x02, 0x55, 0x53, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x01, 0x00, 0xb1, 0x21, 0xb9, 0x6a, 0x61, 0x66, 0xf4, 0x15, 0x09, 0xe6, 0x5a, 0xb3, 0xa7, + 0x96, 0xec, 0xfd, 0xe9, 0x13, 0x15, 0x32, 0xc0, 0xa7, 0x3c, 0x1b, 0x96, 0x70, 0x31, 0x2a, 0x9a, + 0xf5, 0x15, 0x76, 0xeb, 0xc1, 0xec, 0xa9, 0xdd, 0x7e, 0xac, 0xac, 0x62, 0xd9, 0xcf, 0xa4, 0xe6, + 0x9f, 0x37, 0xf6, 0xcc, 0xa6, 0xb9, 0x32, 0xe2, 0x42, 0x72, 0x06, 0x8a, 0xca, 0x44, 0x04, 0x52, + 0x7d, 0x5a, 0x97, 0x07, 0x6b, 0x59, 0x40, 0x80, 0x15, 0x5b, 0x2c, 0xfe, 0xf2, 0x06, 0xa5, 0x78, + 0x39, 0x2f, 0x56, 0x5d, 0x6e, 0x15, 0x9e, 0xb7, 0x8e, 0xb3, 0xc7, 0x5a, 0x0d, 0x10, 0xa1, 0x55, + 0x8a, 0xc1, 0x3f, 0x6f, 0xf1, 0x15, 0x1b, 0x4f, 0x55, 0xb1, 0x2b, 0xab, 0xa5, 0xc1, 0xf4, 0x62, + 0xb9, 0x11, 0xfa, 0x5f, 0x48, 0x12, 0x69, 0xb6, 0x3b, 0x29, 0x5b, 0xe1, 0x02, 0xaa, 0x9b, 0xa5, + 0xa6, 0x4a, 0x33, 0x71, 0x24, 0xec, 0xf3, 0x53, 0xb7, 0xfc, 0x6b, 0xea, 0xd9, 0xd9, 0x6c, 0xce, + 0x61, 0x62, 0xc9, 0x83, 0x7a, 0x33, 0xc0, 0x6a, 0xe5, 0x68, 0x32, 0x6d, 0x13, 0x50, 0x3b, 0xcd, + 0xad, 0x27, 0x8c, 0xf2, 0x98, 0x97, 0x85, 0xd6, 0x6a, 0x7c, 0x94, 0xec, 0x22, 0xfb, 0x9e, 0xf5, + 0x20, 0xb7, 0x2b, 0x5d, 0xe6, 0x5c, 0xcc, 0xb0, 0x3d, 0x0c, 0x16, 0x54, 0x07, 0x3f, 0xae, 0x0d, + 0xfb, 0x33, 0x0c, 0x9d, 0x14, 0x4d, 0xd8, 0x99, 0xd7, 0x4b, 0x8f, 0xd7, 0xfd, 0x05, 0x3d, 0x27, + 0x93, 0x97, 0x55, 0x17, 0x86, 0x0c, 0x9d, 0xc4, 0xe2, 0x78, 0x1d, 0x86, 0x1c, 0x83, 0xd7, 0xc4, + 0xf5, 0xb2, 0xbb, 0xc0, 0x52, 0x81, 0x4c, 0xd1, 0x19, 0xdf, 0x1e, 0x7d, 0x77, 0x21, 0x83, 0x7e, + 0x10, 0x8b, 0x81, 0xaa, 0x07, 0x07, 0x0b, 0xc2, 0x67, 0x43, 0xcb, 0x77, 0x9a, 0x7f, 0xa2, 0xdd, + 0xe8, 0x18, 0xeb, 0x30, 0x82, 0x05, 0x02, 0x30, 0x82, 0x03, 0xea, 0xa0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x03, 0x51, 0x28, 0xe2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, + 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, + 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x43, 0x41, + 0x2d, 0x33, 0x30, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x31, 0x33, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x35, 0x39, + 0x35, 0x39, 0x5a, 0x30, 0x7b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, + 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x03, 0x4f, 0x53, 0x44, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x1f, 0x42, 0x41, 0x53, 0x49, 0x4c, 0x45, 0x2e, 0x42, 0x41, 0x49, 0x4c, 0x45, 0x59, 0x2e, 0x45, + 0x4c, 0x49, 0x53, 0x53, 0x45, 0x2e, 0x31, 0x34, 0x30, 0x30, 0x36, 0x37, 0x32, 0x35, 0x38, 0x36, + 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, 0xd2, 0xa0, 0xea, 0x40, 0xe0, 0xff, 0xa5, 0xc2, 0xe9, 0xe8, 0x3f, 0x5b, 0x4d, 0x1d, 0x45, + 0x50, 0x4d, 0x63, 0x09, 0xff, 0x45, 0xff, 0x44, 0x15, 0x87, 0xa0, 0xa3, 0x50, 0xe2, 0x61, 0xad, + 0xac, 0x37, 0x74, 0xcf, 0x30, 0x16, 0x0b, 0xb4, 0x95, 0xd9, 0x29, 0xa4, 0xff, 0xfd, 0xae, 0xad, + 0xa3, 0xf3, 0xfa, 0x4d, 0x06, 0x31, 0xff, 0xc7, 0x9c, 0xf2, 0xea, 0xbb, 0x91, 0x0f, 0x11, 0xe6, + 0x3b, 0x10, 0x6e, 0x24, 0x51, 0x8e, 0xc0, 0xfe, 0x27, 0xaf, 0x81, 0xfa, 0xe4, 0xa3, 0x09, 0xb9, + 0x0f, 0x5e, 0xd8, 0x20, 0x00, 0x51, 0xce, 0xf8, 0x4b, 0x97, 0x1a, 0x98, 0x1d, 0xd7, 0x22, 0x52, + 0x23, 0x19, 0x1b, 0x82, 0x2b, 0x72, 0x08, 0x6e, 0x61, 0xca, 0xe6, 0x4f, 0xe8, 0xc7, 0x3e, 0x17, + 0x68, 0xc5, 0xc3, 0x75, 0x16, 0x52, 0xc9, 0x16, 0x8d, 0x54, 0xba, 0x2c, 0xed, 0xa2, 0x75, 0x07, + 0x85, 0x8f, 0x37, 0x64, 0xb5, 0x16, 0x7d, 0xb7, 0x6d, 0xfb, 0x6b, 0x40, 0x84, 0x32, 0x64, 0x28, + 0xdb, 0x47, 0x52, 0x5e, 0x32, 0x77, 0xeb, 0x3a, 0xcd, 0x25, 0x1c, 0xb9, 0x64, 0x3e, 0xc2, 0x93, + 0x7d, 0x02, 0x85, 0x8c, 0x5d, 0xda, 0x2b, 0xa1, 0xc2, 0x77, 0x12, 0xb7, 0x79, 0xf5, 0x4a, 0x5a, + 0x73, 0x52, 0x71, 0x5c, 0xed, 0xcf, 0x38, 0x5e, 0x39, 0x7e, 0xa9, 0xf8, 0x2d, 0xc7, 0x7c, 0x68, + 0x94, 0xb7, 0x62, 0xb7, 0xfd, 0x61, 0xa8, 0x03, 0x56, 0xe3, 0x74, 0x94, 0x66, 0x7d, 0x62, 0xec, + 0xa5, 0xa0, 0x09, 0x9d, 0x2c, 0xf7, 0x5f, 0x6c, 0x93, 0x4f, 0xc6, 0x17, 0x49, 0xad, 0xb0, 0xbd, + 0x91, 0x5a, 0x1f, 0xdc, 0x25, 0xc3, 0x98, 0x50, 0x77, 0xd4, 0x7b, 0x4d, 0x14, 0xb8, 0xa7, 0xfb, + 0x9c, 0xb5, 0x6d, 0x85, 0x36, 0x34, 0x4a, 0xb4, 0xa3, 0xb0, 0xdb, 0xe7, 0x78, 0xe3, 0x83, 0x3d, + 0x83, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xab, 0x30, 0x82, 0x01, 0xa7, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x35, 0x61, 0x66, 0x28, 0x09, + 0xbc, 0x56, 0x25, 0x5b, 0x8b, 0xcc, 0xbf, 0x81, 0x5e, 0x61, 0x2c, 0x30, 0x39, 0xd3, 0x21, 0x30, + 0x3a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x33, 0x30, 0x31, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, + 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x64, 0x69, 0x73, + 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x44, 0x4f, 0x44, 0x45, 0x4d, 0x41, + 0x49, 0x4c, 0x43, 0x41, 0x5f, 0x33, 0x30, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x06, 0xc0, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x1d, 0x20, 0x04, 0x1c, 0x30, 0x1a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, + 0x01, 0x0b, 0x09, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x13, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xcc, 0xd0, 0x77, 0xec, 0x17, + 0xc1, 0x30, 0xbe, 0xbe, 0x50, 0x8a, 0x08, 0x2d, 0x1d, 0xae, 0x3d, 0x12, 0x71, 0x79, 0xc5, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x36, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2a, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, + 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x2f, 0x44, 0x4f, 0x44, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x43, 0x41, + 0x5f, 0x33, 0x30, 0x2e, 0x63, 0x65, 0x72, 0x30, 0x20, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x14, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, + 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, 0x11, + 0x04, 0x3b, 0x30, 0x39, 0x81, 0x17, 0x62, 0x61, 0x69, 0x6c, 0x65, 0x79, 0x40, 0x65, 0x63, 0x6c, + 0x69, 0x70, 0x73, 0x65, 0x2e, 0x6e, 0x63, 0x73, 0x63, 0x2e, 0x6d, 0x69, 0x6c, 0xa0, 0x1e, 0x06, + 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03, 0xa0, 0x10, 0x0c, 0x0e, 0x31, + 0x34, 0x30, 0x30, 0x36, 0x37, 0x32, 0x35, 0x38, 0x36, 0x40, 0x6d, 0x69, 0x6c, 0x30, 0x1b, 0x06, + 0x03, 0x55, 0x1d, 0x09, 0x04, 0x14, 0x30, 0x12, 0x30, 0x10, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x09, 0x04, 0x31, 0x04, 0x13, 0x02, 0x55, 0x53, 0x30, 0x29, 0x06, 0x03, 0x55, 0x1d, + 0x25, 0x04, 0x22, 0x30, 0x20, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, + 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7f, 0x70, 0xdc, 0x53, 0x82, 0xf5, 0x1e, + 0x03, 0x6f, 0x17, 0x1b, 0xbb, 0x21, 0x29, 0xd2, 0x58, 0x72, 0xfa, 0x65, 0x4e, 0xdd, 0x16, 0x4f, + 0xed, 0x41, 0x15, 0x37, 0xc4, 0x85, 0x90, 0x2d, 0x1f, 0x27, 0xcd, 0x84, 0x20, 0x87, 0xd9, 0xe1, + 0xc0, 0x62, 0x9c, 0xe2, 0x66, 0x52, 0x36, 0xbe, 0xec, 0xe2, 0x97, 0x0a, 0x88, 0xce, 0x26, 0x14, + 0x32, 0xd1, 0xee, 0x83, 0x5b, 0x8b, 0x87, 0x18, 0xe7, 0xd2, 0x0b, 0xc5, 0x61, 0xe8, 0xd9, 0xfc, + 0xbb, 0xd7, 0x23, 0x22, 0x2d, 0x50, 0x1c, 0x44, 0xae, 0x70, 0x9f, 0x37, 0x5c, 0x20, 0xb9, 0x89, + 0xc1, 0xd7, 0xa7, 0xe4, 0x29, 0xac, 0x11, 0xb1, 0x7b, 0x56, 0x8d, 0x7e, 0x3d, 0x6a, 0x1e, 0xab, + 0x89, 0xb7, 0x17, 0x05, 0x11, 0x8f, 0xe7, 0x15, 0x16, 0xb4, 0x53, 0x63, 0xe4, 0x2d, 0xf2, 0xb8, + 0xd0, 0xae, 0x3a, 0xc0, 0x2a, 0xfb, 0x48, 0x16, 0xaa, 0x6b, 0x89, 0xa0, 0x97, 0xae, 0x6a, 0x36, + 0xda, 0x85, 0x92, 0xf6, 0x2c, 0x20, 0x43, 0x82, 0x23, 0xa5, 0xea, 0x71, 0x99, 0xc1, 0x36, 0xc1, + 0x9f, 0x4d, 0x38, 0x9d, 0xe3, 0x06, 0x2c, 0xc6, 0xdc, 0x1b, 0xd0, 0x61, 0xad, 0x51, 0x1c, 0xbf, + 0xf7, 0x43, 0x86, 0xb1, 0x6d, 0x9c, 0xa9, 0xc4, 0x9b, 0xad, 0x9e, 0xf4, 0xa8, 0x41, 0x94, 0x21, + 0x1c, 0xc2, 0x0d, 0xd9, 0x4f, 0x9a, 0x25, 0xc8, 0xad, 0x07, 0xa7, 0x46, 0x10, 0xa6, 0xb0, 0x16, + 0x02, 0x04, 0xaf, 0x72, 0x14, 0x48, 0x82, 0xd4, 0xb8, 0x31, 0x40, 0x01, 0xcf, 0x09, 0x7d, 0x55, + 0x74, 0x6b, 0xa9, 0xea, 0x2a, 0x73, 0xd5, 0x99, 0x21, 0x86, 0xfd, 0x98, 0x73, 0x0e, 0xdf, 0x7a, + 0x06, 0xaa, 0x2b, 0x59, 0x2b, 0xbb, 0xad, 0x15, 0xc3, 0x01, 0xf2, 0x81, 0x49, 0x5c, 0x16, 0xe9, + 0xe7, 0xe2, 0xcc, 0x46, 0x62, 0x3f, 0x03, 0x78, 0x64, 0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x04, + 0x3a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01, 0xb9, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, + 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x16, + 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, 0x44, 0x6f, 0x44, 0x20, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x39, 0x30, 0x38, + 0x31, 0x36, 0x30, 0x33, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x39, 0x30, 0x38, 0x31, + 0x36, 0x30, 0x33, 0x30, 0x38, 0x5a, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, + 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, + 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, + 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, + 0x43, 0x41, 0x2d, 0x33, 0x30, 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, 0xe6, 0x29, 0x22, 0xd4, 0x14, 0x26, 0xd1, 0x98, 0x1a, 0x52, + 0x5e, 0xc5, 0x84, 0x83, 0x73, 0x7e, 0xc1, 0x60, 0xb3, 0xb3, 0xd0, 0x94, 0xbe, 0xfd, 0x1c, 0x94, + 0x55, 0xbf, 0xf6, 0x84, 0x2c, 0x9b, 0xc9, 0xc0, 0x74, 0x73, 0xef, 0xcc, 0xc2, 0x99, 0xf2, 0x99, + 0xc9, 0x6d, 0xca, 0x14, 0xd3, 0x74, 0xff, 0xbe, 0x10, 0xf2, 0xf7, 0x2d, 0xbf, 0xcb, 0xbb, 0x06, + 0xa3, 0xee, 0x98, 0x50, 0x41, 0x65, 0x01, 0xe1, 0x57, 0x2c, 0xb6, 0xcb, 0xe4, 0xca, 0x1c, 0xac, + 0x7e, 0x52, 0x34, 0x0e, 0xb1, 0x8e, 0x07, 0x26, 0x3e, 0x32, 0x35, 0xaf, 0xa3, 0x61, 0x0a, 0xc5, + 0xe5, 0x08, 0xb6, 0x12, 0x79, 0x8c, 0x54, 0xc1, 0x7a, 0xe9, 0xf1, 0x50, 0x1f, 0x5d, 0x83, 0x3a, + 0x67, 0x30, 0xb3, 0x29, 0xdb, 0x1d, 0x3a, 0x4c, 0x39, 0x21, 0x50, 0xd8, 0x18, 0x2c, 0x8d, 0x06, + 0x75, 0xee, 0x63, 0x72, 0x78, 0x68, 0xad, 0x62, 0x9c, 0x75, 0xa4, 0x94, 0x06, 0xd3, 0x32, 0x6b, + 0x12, 0xaf, 0x06, 0x07, 0x29, 0xbe, 0x13, 0xa0, 0xc0, 0xa7, 0xf0, 0x25, 0x4f, 0xb7, 0xfe, 0x1f, + 0xb7, 0x57, 0xe0, 0x18, 0x12, 0x8d, 0x21, 0x6a, 0x15, 0xb9, 0x5a, 0x54, 0xfb, 0x77, 0x65, 0xd8, + 0x4c, 0x3f, 0xf5, 0xba, 0x3c, 0xc0, 0x37, 0xe1, 0x06, 0x7e, 0xc2, 0xbe, 0x9e, 0x23, 0x8c, 0x28, + 0xd1, 0x9a, 0xd7, 0xc6, 0x67, 0x38, 0xd7, 0x73, 0xc9, 0xbd, 0x07, 0x1d, 0x85, 0x6f, 0xd5, 0x95, + 0x0a, 0x9a, 0xdc, 0xda, 0x3a, 0x4e, 0x28, 0xf0, 0xa5, 0xeb, 0x09, 0xdf, 0xe5, 0xdb, 0x0b, 0xcd, + 0x47, 0xaf, 0x8a, 0xcd, 0xbb, 0x6f, 0x94, 0x40, 0xe3, 0x59, 0x9c, 0x50, 0x9f, 0xc9, 0x0e, 0xa9, + 0x71, 0x02, 0xb9, 0xdc, 0xe9, 0x69, 0x80, 0x3a, 0x89, 0x3b, 0x45, 0x05, 0x22, 0x18, 0x05, 0x84, + 0xb5, 0x12, 0xf0, 0x3c, 0xc0, 0x81, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x1c, 0x30, + 0x82, 0x02, 0x18, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x01, 0x86, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x49, 0x74, 0xbb, 0x0c, 0x5e, 0xba, 0x7a, 0xfe, 0x02, 0x54, 0xef, 0x7b, 0xa0, 0xc6, 0x95, 0xc6, + 0x09, 0x80, 0x70, 0x96, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x35, + 0x61, 0x66, 0x28, 0x09, 0xbc, 0x56, 0x25, 0x5b, 0x8b, 0xcc, 0xbf, 0x81, 0x5e, 0x61, 0x2c, 0x30, + 0x39, 0xd3, 0x21, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x24, 0x04, 0x05, + 0x30, 0x03, 0x80, 0x01, 0x00, 0x30, 0x66, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x5f, 0x30, 0x5d, + 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x05, 0x30, 0x0b, 0x06, + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x09, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, 0x11, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x02, 0x01, 0x0b, 0x12, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x0b, + 0x13, 0x30, 0x0c, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x1a, 0x30, + 0x0c, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x02, 0x01, 0x03, 0x1b, 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, 0x64, 0x69, 0x73, 0x61, 0x2e, + 0x6d, 0x69, 0x6c, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x44, 0x4f, 0x44, 0x52, 0x4f, 0x4f, 0x54, 0x43, + 0x41, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x82, 0x01, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x01, 0x01, 0x04, 0x81, 0xf4, 0x30, 0x81, 0xf1, 0x30, 0x3a, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x64, 0x74, 0x6f, 0x2f, 0x44, 0x4f, 0x44, 0x52, 0x4f, 0x4f, 0x54, 0x43, 0x41, 0x32, 0x5f, + 0x49, 0x54, 0x2e, 0x70, 0x37, 0x63, 0x30, 0x20, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x14, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, + 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x30, 0x81, 0x90, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x81, 0x83, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x63, + 0x72, 0x6c, 0x2e, 0x67, 0x64, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x61, 0x2e, 0x6d, 0x69, 0x6c, 0x2f, + 0x63, 0x6e, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, 0x32, 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, + 0x32, 0x30, 0x43, 0x41, 0x25, 0x32, 0x30, 0x32, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, + 0x50, 0x4b, 0x49, 0x25, 0x32, 0x63, 0x6f, 0x75, 0x25, 0x33, 0x64, 0x44, 0x6f, 0x44, 0x25, 0x32, + 0x63, 0x6f, 0x25, 0x33, 0x64, 0x55, 0x2e, 0x53, 0x2e, 0x25, 0x32, 0x30, 0x47, 0x6f, 0x76, 0x65, + 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x25, 0x32, 0x63, 0x63, 0x25, 0x33, 0x64, 0x55, 0x53, 0x3f, + 0x63, 0x72, 0x6f, 0x73, 0x73, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x50, 0x61, 0x69, 0x72, 0x3b, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x0a, + 0x88, 0x56, 0x1c, 0xa5, 0x57, 0x26, 0x5a, 0x62, 0xcb, 0x75, 0xd0, 0xdd, 0x86, 0xc5, 0x52, 0xe2, + 0x2f, 0xf3, 0xbc, 0x11, 0x64, 0x3f, 0x8c, 0x2f, 0x3e, 0x11, 0xfc, 0x98, 0x60, 0x40, 0xf2, 0x80, + 0x0d, 0x28, 0x82, 0x9a, 0x68, 0xfe, 0xe0, 0x48, 0x4b, 0x27, 0xd3, 0x3a, 0x0a, 0x7b, 0x95, 0xf6, + 0x03, 0x0c, 0x81, 0x14, 0x91, 0x42, 0x3a, 0x60, 0x6c, 0xe2, 0x2b, 0x53, 0x2d, 0xec, 0xdf, 0x11, + 0xae, 0xf5, 0x54, 0x17, 0xf0, 0x01, 0xf9, 0x97, 0x07, 0xa7, 0x9b, 0xab, 0x0b, 0xdb, 0xac, 0x97, + 0x89, 0x09, 0xc6, 0xef, 0xf9, 0x07, 0x34, 0x16, 0x00, 0xa8, 0x7e, 0x11, 0x53, 0x9e, 0x7c, 0x2f, + 0xa1, 0x38, 0xa2, 0x99, 0x79, 0x39, 0x34, 0x41, 0x6e, 0x7d, 0xb8, 0x58, 0x30, 0x56, 0x88, 0x9e, + 0xe4, 0xaa, 0x64, 0x45, 0xd9, 0xa0, 0x44, 0x62, 0x3a, 0xb7, 0xe5, 0x31, 0xd3, 0x91, 0x80, 0xf1, + 0x1b, 0x10, 0xb2, 0x67, 0x70, 0xd5, 0x5b, 0xab, 0x59, 0xb4, 0x5a, 0x48, 0x16, 0x42, 0xc4, 0x02, + 0x4c, 0xda, 0x6c, 0x68, 0xca, 0x50, 0x1d, 0x31, 0xbe, 0x37, 0x99, 0xc7, 0xcf, 0x53, 0xcc, 0x42, + 0x29, 0x56, 0xc3, 0x9d, 0x17, 0xca, 0x03, 0xe7, 0x10, 0x5a, 0xf1, 0x39, 0x3c, 0x1c, 0xcc, 0xfb, + 0x1b, 0x97, 0x0a, 0x26, 0xf3, 0x31, 0xdf, 0xe0, 0xab, 0x5c, 0x24, 0x9d, 0x9e, 0xde, 0x38, 0x7d, + 0x02, 0x51, 0x67, 0x46, 0xf9, 0x93, 0x70, 0x85, 0xed, 0x0a, 0x55, 0xc2, 0xf4, 0xc1, 0x68, 0x5a, + 0x9f, 0x08, 0xc9, 0x1d, 0x7b, 0x9b, 0x76, 0xdc, 0x54, 0xef, 0x39, 0x8c, 0x18, 0xe5, 0x0c, 0x44, + 0xee, 0xf7, 0x06, 0xb2, 0x1f, 0xf5, 0xcb, 0xe6, 0x0e, 0xbd, 0xd4, 0xa1, 0xff, 0xd4, 0xf9, 0x91, + 0x07, 0x22, 0x52, 0x79, 0xb7, 0xc0, 0xfd, 0xec, 0xb2, 0xf8, 0x85, 0xf4, 0x44, 0xfb, 0x5c, 0x31, + 0x82, 0x03, 0x6e, 0x30, 0x82, 0x03, 0x6a, 0x02, 0x01, 0x01, 0x30, 0x64, 0x30, 0x5d, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, + 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, + 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, + 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x43, 0x41, 0x2d, 0x33, 0x30, 0x02, 0x03, 0x51, 0x28, 0xe2, + 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0xa0, 0x82, 0x01, 0xdf, 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, 0x34, 0x30, 0x32, 0x31, 0x38, + 0x31, 0x35, 0x34, 0x39, 0x33, 0x32, 0x5a, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x09, 0x04, 0x31, 0x16, 0x04, 0x14, 0xde, 0x32, 0xb7, 0xe4, 0x42, 0x7b, 0x5b, 0xe3, + 0x72, 0xf5, 0x7d, 0xef, 0x9f, 0xbb, 0xb6, 0xd0, 0xa0, 0x62, 0xac, 0x80, 0x30, 0x73, 0x06, 0x09, + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x10, 0x04, 0x31, 0x66, 0x30, 0x64, 0x30, 0x5d, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, + 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, + 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, + 0x4b, 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, + 0x20, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x43, 0x41, 0x2d, 0x33, 0x30, 0x02, 0x03, 0x51, 0x28, + 0xe9, 0x30, 0x75, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x0b, + 0x31, 0x66, 0xa0, 0x64, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x55, 0x2e, + 0x53, 0x2e, 0x20, 0x47, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x31, 0x0c, 0x30, + 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x44, 0x6f, 0x44, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x03, 0x50, 0x4b, 0x49, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x0f, 0x44, 0x4f, 0x44, 0x20, 0x45, 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x43, 0x41, + 0x2d, 0x33, 0x30, 0x02, 0x03, 0x51, 0x28, 0xe9, 0x30, 0x81, 0x93, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0f, 0x31, 0x81, 0x85, 0x30, 0x81, 0x82, 0x30, 0x0b, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x01, 0x16, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x03, 0x07, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02, 0x30, + 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x02, 0x00, 0x80, 0x30, + 0x0d, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x01, 0x40, 0x30, 0x07, + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, + 0x02, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, + 0x00, 0xb0, 0x0e, 0x51, 0xaf, 0xab, 0x2a, 0xb1, 0x6c, 0x11, 0x4e, 0x52, 0x33, 0xfd, 0x0e, 0xa9, + 0x8f, 0xfa, 0xab, 0x5f, 0x38, 0xb9, 0xd7, 0x7c, 0x2d, 0x18, 0x5b, 0xd5, 0x3e, 0x0c, 0x55, 0x4c, + 0x28, 0xa8, 0x9e, 0x2d, 0x6d, 0xe2, 0xfe, 0xcf, 0x4e, 0x91, 0xba, 0x56, 0xde, 0x78, 0x5e, 0xbe, + 0xd9, 0xbf, 0xd4, 0x78, 0x23, 0x8e, 0x90, 0xd1, 0xc4, 0x02, 0x70, 0xb4, 0xb5, 0x4c, 0xd8, 0x2f, + 0xc2, 0x7b, 0x24, 0x40, 0xec, 0xdc, 0x20, 0xf2, 0xc4, 0xdb, 0x2a, 0x9e, 0x69, 0x99, 0xc7, 0x54, + 0x6f, 0x01, 0x2a, 0xbf, 0xc4, 0x3d, 0x10, 0x91, 0x13, 0xc2, 0xfe, 0xba, 0x26, 0xab, 0x2e, 0xdc, + 0xab, 0xb1, 0x8d, 0xfc, 0x1c, 0x03, 0xc1, 0x6e, 0xd8, 0xed, 0xde, 0x21, 0xab, 0x35, 0x9c, 0x1f, + 0xd5, 0x68, 0xea, 0xb5, 0xf3, 0x3a, 0xaa, 0x0d, 0x31, 0xa0, 0x66, 0x96, 0xf1, 0x9c, 0xf3, 0x7a, + 0xd6, 0x6f, 0xad, 0xac, 0xa6, 0x0a, 0x9b, 0x3d, 0xbc, 0xc1, 0xec, 0xe4, 0x5f, 0xc9, 0x12, 0x87, + 0xe5, 0x32, 0x53, 0x5b, 0x62, 0x4a, 0x02, 0x1d, 0x7b, 0x9d, 0xda, 0x80, 0x50, 0x25, 0x29, 0x29, + 0xa8, 0x21, 0x15, 0x40, 0x0a, 0xa5, 0xe8, 0xf3, 0x12, 0xb8, 0xca, 0xa3, 0xdc, 0xc9, 0x6f, 0x4b, + 0xcb, 0x38, 0x53, 0x2e, 0xb0, 0x74, 0xfa, 0x77, 0xf8, 0x4f, 0xde, 0x51, 0xa7, 0x74, 0x38, 0xce, + 0x51, 0x08, 0xf8, 0x72, 0xa1, 0xae, 0x4b, 0x5f, 0x53, 0xf4, 0xb7, 0x7f, 0x78, 0x1e, 0x07, 0x45, + 0xba, 0x3c, 0x9c, 0x54, 0xc7, 0x0c, 0xc6, 0x89, 0x07, 0xdc, 0x5e, 0xae, 0xe3, 0x9b, 0x86, 0x3c, + 0x44, 0x44, 0x31, 0xdd, 0xf3, 0x1b, 0xb6, 0xa2, 0x5e, 0xe2, 0xb9, 0xce, 0x12, 0x78, 0x58, 0x6f, + 0x17, 0x00, 0x20, 0xfd, 0x36, 0x18, 0x75, 0x77, 0x10, 0x57, 0x39, 0xf7, 0xe2, 0x52, 0x92, 0xa3, + 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist.c b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist.c similarity index 87% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist.c rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist.c index 94405e1f..e263aff7 100644 --- a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist.c +++ b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist.c @@ -36,16 +36,16 @@ #include #include -#include "si-67-sectrust-blacklist/Global Trustee.cer.h" -#include "si-67-sectrust-blacklist/login.yahoo.com.1.cer.h" -#include "si-67-sectrust-blacklist/UTN-USERFirst-Hardware.cer.h" -#include "si-67-sectrust-blacklist/login.yahoo.com.2.cer.h" -#include "si-67-sectrust-blacklist/addons.mozilla.org.cer.h" -#include "si-67-sectrust-blacklist/login.yahoo.com.cer.h" -#include "si-67-sectrust-blacklist/login.live.com.cer.h" -#include "si-67-sectrust-blacklist/mail.google.com.cer.h" -#include "si-67-sectrust-blacklist/login.skype.com.cer.h" -#include "si-67-sectrust-blacklist/www.google.com.cer.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" @@ -81,7 +81,7 @@ static void tests(void) 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 blacklisting */ + 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); @@ -128,7 +128,7 @@ static int ping_host(char *host_name){ } } -int si_67_sectrust_blacklist(int argc, char *const *argv) +int si_67_sectrust_blocklist(int argc, char *const *argv) { char *hosts[] = { "EVSecure-ocsp.verisign.com", diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/Global Trustee.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/Global Trustee.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/Global Trustee.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/Global Trustee.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/UTN-USERFirst-Hardware.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/UTN-USERFirst-Hardware.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/UTN-USERFirst-Hardware.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/UTN-USERFirst-Hardware.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/addons.mozilla.org.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/addons.mozilla.org.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/addons.mozilla.org.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/addons.mozilla.org.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.live.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.live.com.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.live.com.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.live.com.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.skype.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.skype.com.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.skype.com.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.skype.com.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.yahoo.com.1.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.1.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.yahoo.com.1.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.1.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.yahoo.com.2.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.2.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.yahoo.com.2.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.2.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.yahoo.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/login.yahoo.com.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/mail.google.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/mail.google.com.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/mail.google.com.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/mail.google.com.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/www.google.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/www.google.com.cer.h similarity index 100% rename from OSX/sec/Security/Regressions/secitem/si-67-sectrust-blacklist/www.google.com.cer.h rename to OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/www.google.com.cer.h diff --git a/OSX/sec/Security/Regressions/secitem/si-68-secmatchissuer.c b/OSX/sec/Security/Regressions/secitem/si-68-secmatchissuer.c index ac1d49a2..0e4056b9 100644 --- a/OSX/sec/Security/Regressions/secitem/si-68-secmatchissuer.c +++ b/OSX/sec/Security/Regressions/secitem/si-68-secmatchissuer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -40,7 +40,7 @@ #include #include -#include "Security_regressions.h" +#include "shared_regressions.h" #include /* @@ -114,7 +114,7 @@ static void tests(void) // MARK: generate certificate hierarchy SecKeyRef public_key = NULL, private_key = NULL; - ok_status(test_cert_generate_key(512, kSecAttrKeyTypeRSA, &private_key, &public_key), "generate keypair"); + ok_status(test_cert_generate_key(2048, kSecAttrKeyTypeRSA, &private_key, &public_key), "generate keypair"); // make organization random uuid to avoid previous run to spoil the fun CFUUIDRef UUID = CFUUIDCreate(kCFAllocatorDefault); @@ -171,9 +171,11 @@ static void tests(void) ok_status(SecItemCopyMatching(all_identities_query, &all_matching_identities), "find all identities matching"); CFReleaseNull(all_identities_query); ok(((CFArrayGetTypeID() == CFGetTypeID(all_matching_identities)) && (CFArrayGetCount(all_matching_identities) == 2)), "return 2"); + CFReleaseNull(all_matching_identities); //CFShow(all_matching_identities); } +#if TARGET_OS_IPHONE { int limit = 0x7fff; // To regress-test CFNumberRef cfLimit = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &limit); @@ -186,7 +188,23 @@ static void tests(void) ok(((CFArrayGetTypeID() == CFGetTypeID(all_matching_certificates)) && (CFArrayGetCount(all_matching_certificates) == 2)), "return 2"); //CFShow(all_matching_certificates); CFReleaseSafe(cfLimit); + CFReleaseNull(all_matching_certificates); } +#else + /* On macOS, we don't allow kSecMatchIssuers to be used with kSecClassCertificate because performance is bad. */ + { + int limit = 0x7fff; // To regress-test + CFNumberRef cfLimit = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &limit); + const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit, kSecMatchIssuers }; + const void *vals[] = { kSecClassCertificate, kCFBooleanTrue, cfLimit, all_distinguished_names }; + CFDictionaryRef all_identities_query = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, array_size(keys), NULL, NULL); + CFTypeRef all_matching_certificates = NULL; + is(errSecParam, SecItemCopyMatching(all_identities_query, &all_matching_certificates), "find all certificates matching"); + CFReleaseNull(all_identities_query); + CFReleaseSafe(cfLimit); + CFReleaseNull(all_matching_certificates); + } +#endif remove_item(leaf_identity); CFRelease(leaf_identity); @@ -206,7 +224,11 @@ static void tests(void) int si_68_secmatchissuer(int argc, char *const *argv) { +#if TARGET_OS_IPHONE plan_tests(10); +#else + plan_tests(9); +#endif tests(); diff --git a/OSX/sec/Security/Regressions/secitem/si-82-token-ag.c b/OSX/sec/Security/Regressions/secitem/si-82-token-ag.c index 3cdc50bb..39cade8f 100644 --- a/OSX/sec/Security/Regressions/secitem/si-82-token-ag.c +++ b/OSX/sec/Security/Regressions/secitem/si-82-token-ag.c @@ -19,8 +19,8 @@ static void tests(void) { CFDictionaryAddValue(dict, kSecAttrService, CFSTR("test")); CFDictionaryAddValue(dict, kSecAttrAccessGroup, kSecAttrAccessGroupToken); - ok_status(SecItemAdd(dict, NULL)); - ok_status(SecItemDelete(dict)); + is_status(SecItemAdd(dict, NULL), errSecParam); + is_status(SecItemCopyMatching(dict, NULL), errSecItemNotFound); 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 index 97f17bcf..ab4ed0e9 100644 --- a/OSX/sec/Security/Regressions/secitem/si-84-sectrust-allowlist.m +++ b/OSX/sec/Security/Regressions/secitem/si-84-sectrust-allowlist.m @@ -2,7 +2,7 @@ * si-84-sectrust-allowlist.c * Security * - * Copyright (c) 2015-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2015-2017 Apple Inc. All Rights Reserved. */ #include @@ -20,6 +20,9 @@ #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) { @@ -53,8 +56,8 @@ static void TestLeafOnAllowList() 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"); + /* 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 */ @@ -69,9 +72,24 @@ static void TestLeafOnAllowList() 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: */ + /* 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++) { @@ -173,7 +191,7 @@ static void TestAllowListForRootCA(void) CFArrayRef certs2 = CFArrayCreate(kCFAllocatorDefault, (const void **)test2, 2, &kCFTypeArrayCallBacks); /* - * Whitelisted certificates issued by untrusted root CA. + * Allowlisted certificates issued by untrusted root CA. */ isnt(policy = SecPolicyCreateBasicX509(), NULL, "create policy"); ok_status(SecTrustCreateWithCertificates(certs0, policy, &trust), "create trust"); @@ -181,8 +199,24 @@ static void TestAllowListForRootCA(void) 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: */ + /* 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); } @@ -191,8 +225,19 @@ static void TestAllowListForRootCA(void) 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"); - ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)", +#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: */ + /* 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); } @@ -201,8 +246,25 @@ static void TestAllowListForRootCA(void) 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: */ + /* 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. */ @@ -210,8 +272,16 @@ static void TestAllowListForRootCA(void) 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); } @@ -223,8 +293,19 @@ static void TestAllowListForRootCA(void) 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"); - ok(trustResult == kSecTrustResultRecoverableTrustFailure, "trustResult 5 expected (got %d)", +#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: */ + /* 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); } @@ -359,7 +440,8 @@ static void TestLeafOnAllowListOtherFailures(void) require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out); require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out); require_noerr(SecTrustEvaluate(trust, &trustResult), out); - is(trustResult, kSecTrustResultRecoverableTrustFailure, "hostname failure with cert on allow list succeeded evaluation"); + ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure, + "hostname failure with cert on allow list succeeded evaluation"); CFReleaseNull(policy); trustResult = kSecTrustResultInvalid; @@ -367,7 +449,8 @@ static void TestLeafOnAllowListOtherFailures(void) require(policy = SecPolicyCreateCodeSigning(), out); require_noerr(SecTrustSetPolicies(trust, policy), out); require_noerr(SecTrustEvaluate(trust, &trustResult), out); - is(trustResult, kSecTrustResultRecoverableTrustFailure, "EKU failure with cert on allow list succeeded evaluation"); + ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure, + "EKU failure with cert on allow list succeeded evaluation"); CFReleaseNull(policy); trustResult = kSecTrustResultInvalid; @@ -377,7 +460,8 @@ static void TestLeafOnAllowListOtherFailures(void) (__bridge CFStringRef)@"1.2.840.113635.100.6.27.12"), out); require_noerr(SecTrustSetPolicies(trust, policy), out); require_noerr(SecTrustEvaluate(trust, &trustResult), out); - is(trustResult, kSecTrustResultRecoverableTrustFailure, "Apple pinning policy with cert on allow list succeeded evaluation"); + ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure, + "Apple pinning policy with cert on allow list succeeded evaluation"); out: CFReleaseNull(certs[0]); diff --git a/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.c b/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.c deleted file mode 100644 index a558ac8b..00000000 --- a/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "shared_regressions.h" - -#include "si-87-sectrust-name-constraints.h" - -static void test_att(void) -{ - SecTrustRef trust = NULL; - SecPolicyRef policy = NULL; - SecCertificateRef leaf, int1, int2, cert3, root; - SecTrustResultType trustResult; - - isnt(leaf = SecCertificateCreateWithBytes(NULL, att_leaf, sizeof(att_leaf)), NULL, "create att leaf"); - isnt(int1 = SecCertificateCreateWithBytes(NULL, att_intermediate1, sizeof(att_intermediate1)), NULL, "create att intermediate 1"); - isnt(int2 = SecCertificateCreateWithBytes(NULL, att_intermediate2, sizeof(att_intermediate2)), NULL, "create att intermediate 2"); - isnt(cert3 = SecCertificateCreateWithBytes(NULL, att_intermediate3, sizeof(att_intermediate3)), NULL, "create att intermediate 3"); - isnt(root = SecCertificateCreateWithBytes(NULL, att_root, sizeof(att_root)), NULL, "create att root"); - - const void *v_certs[] = { leaf, int1, int2, cert3 }; - const void *v_roots[] = { root }; - CFArrayRef certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); - CFArrayRef roots = CFArrayCreate(NULL, v_roots, array_size(v_roots), &kCFTypeArrayCallBacks); - - /* Create SSL policy with specific hostname. */ - isnt(policy = SecPolicyCreateSSL(true, CFSTR("nmd.mcd06643.sjc.wayport.net")), NULL, "create policy"); - - /* Create trust reference. */ - ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); - - /* Set explicit verify date: Aug 14 2015. */ - CFDateRef date = NULL; - isnt(date = CFDateCreateForGregorianZuluMoment(NULL, 2015, 8, 14, 12, 0, 0), NULL, "create verify date"); - if (!date) { goto errOut; } - ok_status(SecTrustSetVerifyDate(trust, date), "set date"); - - /* Provide root certificate. */ - ok_status(SecTrustSetAnchorCertificates(trust, roots), "set anchors"); - - ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); - is_status(trustResult, kSecTrustResultUnspecified, "trustResult is kSecTrustResultUnspecified"); - is(SecTrustGetCertificateCount(trust), 5, "cert count is 5"); - -errOut: - CFReleaseSafe(date); - CFReleaseSafe(trust); - CFReleaseSafe(policy); - CFReleaseSafe(certs); - CFReleaseSafe(roots); - CFReleaseSafe(root); - CFReleaseSafe(cert3); - CFReleaseSafe(int2); - CFReleaseSafe(int1); - CFReleaseSafe(leaf); -} - -static void test_intel1(void) -{ - SecTrustRef trust = NULL; - SecPolicyRef policy = NULL; - SecCertificateRef leaf, int1, int2, root; - SecTrustResultType trustResult; - - isnt(leaf = SecCertificateCreateWithBytes(NULL, intel1_leaf, sizeof(intel1_leaf)), NULL, "create intel 1 leaf"); - isnt(int1 = SecCertificateCreateWithBytes(NULL, intel1_intermediate1, sizeof(intel1_intermediate1)), NULL, "create intel 1 intermediate 1"); - isnt(int2 = SecCertificateCreateWithBytes(NULL, intel_intermediate2, sizeof(intel_intermediate2)), NULL, "create intel intermediate 2"); - isnt(root = SecCertificateCreateWithBytes(NULL, intel_root, sizeof(intel_root)), NULL, "create intel root"); - - const void *v_certs[] = { leaf, int1, int2 }; - const void *v_roots[] = { root }; - CFArrayRef certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); - CFArrayRef roots = CFArrayCreate(NULL, v_roots, array_size(v_roots), &kCFTypeArrayCallBacks); - - /* Create SSL policy with specific hostname. */ - isnt(policy = SecPolicyCreateSSL(true, CFSTR("myctx.intel.com")), NULL, "create policy"); - - /* Create trust reference. */ - ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); - - /* Set explicit verify date: Sep 3 2015. */ - CFDateRef date = NULL; - isnt(date = CFDateCreate(NULL, 463037436.0), NULL, "create verify date"); - if (!date) { goto errOut; } - ok_status(SecTrustSetVerifyDate(trust, date), "set date"); - - /* Provide root certificate. */ - ok_status(SecTrustSetAnchorCertificates(trust, roots), "set anchors"); - - ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); - is_status(trustResult, kSecTrustResultUnspecified, "trustResult is kSecTrustResultUnspecified"); - is(SecTrustGetCertificateCount(trust), 4, "cert count is 4"); - -errOut: - CFReleaseSafe(date); - CFReleaseSafe(trust); - CFReleaseSafe(policy); - CFReleaseSafe(certs); - CFReleaseSafe(roots); - CFReleaseSafe(root); - CFReleaseSafe(int2); - CFReleaseSafe(int1); - CFReleaseSafe(leaf); -} - -static void test_intel2(void) -{ - SecTrustRef trust = NULL; - SecPolicyRef policy = NULL; - SecCertificateRef leaf, int1, int2, root; - SecTrustResultType trustResult; - - isnt(leaf = SecCertificateCreateWithBytes(NULL, intel2_leaf, sizeof(intel2_leaf)), NULL, "create intel 2 leaf"); - isnt(int1 = SecCertificateCreateWithBytes(NULL, intel2_intermediate1, sizeof(intel2_intermediate1)), NULL, "create intel 2 intermediate 1"); - isnt(int2 = SecCertificateCreateWithBytes(NULL, intel_intermediate2, sizeof(intel_intermediate2)), NULL, "create intel intermediate 2"); - isnt(root = SecCertificateCreateWithBytes(NULL, intel_root, sizeof(intel_root)), NULL, "create intel root"); - - const void *v_certs[] = { leaf, int1, int2 }; - const void *v_roots[] = { root }; - CFArrayRef certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); - CFArrayRef roots = CFArrayCreate(NULL, v_roots, array_size(v_roots), &kCFTypeArrayCallBacks); - - /* Create SSL policy with specific hostname. */ - isnt(policy = SecPolicyCreateSSL(true, CFSTR("contact.intel.com")), NULL, "create policy"); - - /* Create trust reference. */ - ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); - - /* Set explicit verify date: Sep 3 2015. */ - CFDateRef date = NULL; - isnt(date = CFDateCreate(NULL, 463037436.0), NULL, "create verify date"); - if (!date) { goto errOut; } - ok_status(SecTrustSetVerifyDate(trust, date), "set date"); - - /* Provide root certificate. */ - ok_status(SecTrustSetAnchorCertificates(trust, roots), "set anchors"); - - ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); - is_status(trustResult, kSecTrustResultUnspecified, "trustResult is kSecTrustResultUnspecified"); - is(SecTrustGetCertificateCount(trust), 4, "cert count is 4"); - -errOut: - CFReleaseSafe(date); - CFReleaseSafe(trust); - CFReleaseSafe(policy); - CFReleaseSafe(certs); - CFReleaseSafe(roots); - CFReleaseSafe(root); - CFReleaseSafe(int2); - CFReleaseSafe(int1); - CFReleaseSafe(leaf); -} - -static void test_abb(void) -{ - SecTrustRef trust = NULL; - SecPolicyRef policy = NULL; - SecCertificateRef leaf, int1, int2, root; - SecTrustResultType trustResult; - - isnt(leaf = SecCertificateCreateWithBytes(NULL, _ABB_PKI_cert, sizeof(_ABB_PKI_cert)), NULL, "create ABB leaf"); - isnt(int1 = SecCertificateCreateWithBytes(NULL, _ABBIssuingCA6, sizeof(_ABBIssuingCA6)), NULL, "create ABB intermediate 1"); - isnt(int2 = SecCertificateCreateWithBytes(NULL, _ABBIntermediateCA3, sizeof(_ABBIntermediateCA3)), NULL, "create ABB intermediate 2"); - isnt(root = SecCertificateCreateWithBytes(NULL, _ABBRootCA, sizeof(_ABBRootCA)), NULL, "create ABB root"); - - const void *v_certs[] = { leaf, int1, int2 }; - const void *v_roots[] = { root }; - CFArrayRef certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); - CFArrayRef roots = CFArrayCreate(NULL, v_roots, array_size(v_roots), &kCFTypeArrayCallBacks); - - /* Create SSL policy with specific hostname. */ - isnt(policy = SecPolicyCreateSSL(true, CFSTR("pki.abb.com")), NULL, "create policy"); - - /* Create trust reference. */ - ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); - - /* Set explicit verify date: Sep 16 2015. */ - CFDateRef date = NULL; - isnt(date = CFDateCreate(NULL, 464128479.0), NULL, "create verify date"); - if (!date) { goto errOut; } - ok_status(SecTrustSetVerifyDate(trust, date), "set date"); - - /* Provide root certificate. */ - ok_status(SecTrustSetAnchorCertificates(trust, roots), "set anchors"); - - ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); - is_status(trustResult, kSecTrustResultUnspecified, "trustResult is kSecTrustResultUnspecified"); - is(SecTrustGetCertificateCount(trust), 4, "cert count is 4"); - -errOut: - CFReleaseSafe(date); - CFReleaseSafe(trust); - CFReleaseSafe(policy); - CFReleaseSafe(certs); - CFReleaseSafe(roots); - CFReleaseSafe(root); - CFReleaseSafe(int2); - CFReleaseSafe(int1); - CFReleaseSafe(leaf); -} - -static void test_bechtel1(void) -{ - SecTrustRef trust = NULL; - SecPolicyRef policy = NULL; - SecCertificateRef leaf, int1, int2, root; - SecTrustResultType trustResult; - - isnt(leaf = SecCertificateCreateWithBytes(NULL, _bechtel_leaf_a, sizeof(_bechtel_leaf_a)), NULL, "create Bechtel leaf a"); - isnt(int1 = SecCertificateCreateWithBytes(NULL, _bechtel_int2a, sizeof(_bechtel_int2a)), NULL, "create Bechtel intermediate 2a"); - isnt(int2 = SecCertificateCreateWithBytes(NULL, _bechtel_int1, sizeof(_bechtel_int1)), NULL, "create Bechtel intermediate 1"); - isnt(root = SecCertificateCreateWithBytes(NULL, _bechtel_root, sizeof(_bechtel_root)), NULL, "create Bechtel root"); - - const void *v_certs[] = { leaf, int1, int2 }; - const void *v_roots[] = { root }; - CFArrayRef certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); - CFArrayRef roots = CFArrayCreate(NULL, v_roots, array_size(v_roots), &kCFTypeArrayCallBacks); - - /* Create SSL policy with specific hostname. */ - isnt(policy = SecPolicyCreateSSL(true, CFSTR("supplier.bechtel.com")), NULL, "create policy"); - - /* Create trust reference. */ - ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); - - /* Set explicit verify date: Sep 29 2015. */ - CFDateRef date = NULL; - isnt(date = CFDateCreate(NULL, 465253810.0), NULL, "create verify date"); - if (!date) { goto errOut; } - ok_status(SecTrustSetVerifyDate(trust, date), "set date"); - - /* Provide root certificate. */ - ok_status(SecTrustSetAnchorCertificates(trust, roots), "set anchors"); - - ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); - is_status(trustResult, kSecTrustResultUnspecified, "trustResult is kSecTrustResultUnspecified"); - is(SecTrustGetCertificateCount(trust), 4, "cert count is 4"); - -errOut: - CFReleaseSafe(date); - CFReleaseSafe(trust); - CFReleaseSafe(policy); - CFReleaseSafe(certs); - CFReleaseSafe(roots); - CFReleaseSafe(root); - CFReleaseSafe(int2); - CFReleaseSafe(int1); - CFReleaseSafe(leaf); -} - -static void test_bechtel2(void) -{ - SecTrustRef trust = NULL; - SecPolicyRef policy = NULL; - SecCertificateRef leaf, int1, int2, root; - SecTrustResultType trustResult; - - isnt(leaf = SecCertificateCreateWithBytes(NULL, _bechtel_leaf_b, sizeof(_bechtel_leaf_b)), NULL, "create Bechtel leaf b"); - isnt(int1 = SecCertificateCreateWithBytes(NULL, _bechtel_int2b, sizeof(_bechtel_int2b)), NULL, "create Bechtel intermediate 2b"); - isnt(int2 = SecCertificateCreateWithBytes(NULL, _bechtel_int1, sizeof(_bechtel_int1)), NULL, "create Bechtel intermediate 1"); - isnt(root = SecCertificateCreateWithBytes(NULL, _bechtel_root, sizeof(_bechtel_root)), NULL, "create Bechtel root"); - - const void *v_certs[] = { leaf, int1, int2 }; - const void *v_roots[] = { root }; - CFArrayRef certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks); - CFArrayRef roots = CFArrayCreate(NULL, v_roots, array_size(v_roots), &kCFTypeArrayCallBacks); - - /* Create SSL policy with specific hostname. */ - isnt(policy = SecPolicyCreateSSL(true, CFSTR("login.becpsn.com")), NULL, "create policy"); - - /* Create trust reference. */ - ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); - - /* Set explicit verify date: Sep 29 2015. */ - CFDateRef date = NULL; - isnt(date = CFDateCreate(NULL, 465253810.0), NULL, "create verify date"); - if (!date) { goto errOut; } - ok_status(SecTrustSetVerifyDate(trust, date), "set date"); - - /* Provide root certificate. */ - ok_status(SecTrustSetAnchorCertificates(trust, roots), "set anchors"); - - ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); - is_status(trustResult, kSecTrustResultUnspecified, "trustResult is kSecTrustResultUnspecified"); - is(SecTrustGetCertificateCount(trust), 4, "cert count is 4"); - -errOut: - CFReleaseSafe(date); - CFReleaseSafe(trust); - CFReleaseSafe(policy); - CFReleaseSafe(certs); - CFReleaseSafe(roots); - CFReleaseSafe(root); - CFReleaseSafe(int2); - CFReleaseSafe(int1); - CFReleaseSafe(leaf); -} - -int si_87_sectrust_name_constraints(int argc, char *const *argv) -{ - plan_tests(73); - - test_att(); - test_intel1(); - test_intel2(); - test_abb(); - test_bechtel1(); - test_bechtel2(); - - return 0; -} diff --git a/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.h b/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.h index 99a6783e..1570cf96 100644 --- a/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.h +++ b/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.h @@ -1,2192 +1,362 @@ /* - * Copyright (c) 2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2015-2017 Apple Inc. All Rights Reserved. */ -/* subject:/C=US/ST=Texas/O=ATT Services Inc/OU=ATT Wi-Fi Services/CN=nmd.mcd06643.sjc.wayport.net */ -/* issuer :/C=US/ST=Texas/O=ATT Services Inc/OU=ATT Wi-Fi Services/CN=AWS Managed Device CA G2 */ - -static unsigned char att_leaf[1582]={ - 0x30,0x82,0x06,0x2A,0x30,0x82,0x05,0x12,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x0B, - 0x3B,0x5F,0x62,0x39,0x50,0xB5,0x6E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, - 0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x78,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, - 0x06,0x13,0x02,0x55,0x53,0x31,0x0E,0x30,0x0C,0x06,0x03,0x55,0x04,0x08,0x13,0x05, - 0x54,0x65,0x78,0x61,0x73,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10, - 0x41,0x54,0x54,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x49,0x6E,0x63, - 0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x0B,0x13,0x12,0x41,0x54,0x54,0x20,0x57, - 0x69,0x2D,0x46,0x69,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x31,0x21,0x30, - 0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x41,0x57,0x53,0x20,0x4D,0x61,0x6E,0x61, - 0x67,0x65,0x64,0x20,0x44,0x65,0x76,0x69,0x63,0x65,0x20,0x43,0x41,0x20,0x47,0x32, - 0x30,0x1E,0x17,0x0D,0x31,0x35,0x30,0x38,0x31,0x32,0x30,0x32,0x30,0x35,0x31,0x31, - 0x5A,0x17,0x0D,0x31,0x35,0x30,0x38,0x32,0x32,0x30,0x32,0x30,0x35,0x31,0x31,0x5A, - 0x30,0x7C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, - 0x0E,0x30,0x0C,0x06,0x03,0x55,0x04,0x08,0x13,0x05,0x54,0x65,0x78,0x61,0x73,0x31, - 0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10,0x41,0x54,0x54,0x20,0x53,0x65, - 0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x49,0x6E,0x63,0x31,0x1B,0x30,0x19,0x06,0x03, - 0x55,0x04,0x0B,0x13,0x12,0x41,0x54,0x54,0x20,0x57,0x69,0x2D,0x46,0x69,0x20,0x53, - 0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x03, - 0x13,0x1C,0x6E,0x6D,0x64,0x2E,0x6D,0x63,0x64,0x30,0x36,0x36,0x34,0x33,0x2E,0x73, - 0x6A,0x63,0x2E,0x77,0x61,0x79,0x70,0x6F,0x72,0x74,0x2E,0x6E,0x65,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,0xD0, - 0x65,0xD5,0x7A,0x99,0xB8,0x19,0x83,0x22,0x9F,0xE0,0x0E,0xDA,0x16,0x37,0x74,0x2A, - 0xDD,0xDA,0xD3,0x5A,0xBE,0xBC,0xDC,0xF7,0x3F,0xBC,0x16,0x24,0x94,0x3A,0xDA,0x51, - 0xD6,0xB4,0xA6,0x0E,0x2F,0xC6,0x87,0x74,0x50,0x0F,0x60,0xDD,0x6C,0xD5,0xD6,0x5B, - 0x0C,0x69,0x54,0x06,0x51,0x70,0xB7,0xA3,0x4D,0x2A,0x81,0x07,0xC8,0xE6,0xFB,0x08, - 0x0D,0x4B,0xA3,0xBE,0xC8,0x1D,0x83,0xBB,0x8D,0xD4,0xB6,0x67,0x5A,0x41,0x03,0xF4, - 0x14,0x31,0x23,0x14,0x25,0xF9,0x59,0xAA,0x0D,0x32,0xAF,0xA7,0x4E,0x65,0xDE,0x24, - 0x76,0x06,0x50,0x6D,0xF0,0x0A,0x2A,0x7F,0x88,0xA9,0x6A,0x52,0x1C,0xB0,0xFE,0xF3, - 0xD3,0xE2,0x33,0xBD,0x4E,0xBC,0xB8,0xFB,0x27,0xD0,0x24,0x1F,0x17,0xAF,0xA9,0xDE, - 0x5D,0x40,0xAD,0x20,0xBB,0xF8,0x88,0x90,0x4E,0x34,0x9F,0xEF,0x21,0x70,0xBB,0xB2, - 0x15,0x1C,0xB7,0x86,0x37,0x34,0x31,0x8F,0x73,0xBE,0x97,0xDF,0x25,0xE5,0x8F,0x2F, - 0x0D,0xB8,0xAA,0x24,0x8B,0x73,0x3D,0x73,0xD2,0xFB,0x50,0x0D,0x02,0x31,0x32,0xFC, - 0x8E,0x8E,0x45,0xC7,0x97,0x61,0x68,0xB0,0xFC,0xF3,0xD1,0x49,0xCE,0x66,0x83,0x6A, - 0x15,0x30,0xAF,0x3F,0x8D,0x8F,0xFC,0x0E,0x2D,0xA4,0x05,0x9E,0xAC,0xDF,0xFD,0xB9, - 0xF3,0x83,0x69,0x4A,0xEB,0xA9,0x0E,0x3F,0x32,0xA8,0x25,0x95,0xB5,0x10,0xFF,0xF9, - 0x29,0x1B,0x15,0xA7,0x23,0x35,0x65,0xA5,0x74,0xB3,0x1D,0x0D,0x18,0xE2,0x02,0x5C, - 0xEA,0xD7,0xB6,0x50,0x61,0x0C,0x2B,0x90,0x01,0xED,0x69,0xFA,0xEE,0xE8,0xD1,0x02, - 0x03,0x01,0x00,0x01,0xA3,0x82,0x02,0xB2,0x30,0x82,0x02,0xAE,0x30,0x73,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x67,0x30,0x65,0x30,0x33,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x27,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x63,0x72,0x6C,0x2D,0x62,0x2E,0x70,0x6B,0x69,0x2E,0x77,0x61,0x79,0x70,0x6F, - 0x72,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x6D,0x64,0x63,0x61,0x67,0x32,0x2E,0x63,0x72, - 0x74,0x30,0x2E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x22,0x68, - 0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2D,0x62,0x2E,0x70,0x6B,0x69, - 0x2E,0x77,0x61,0x79,0x70,0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74,0x3A,0x32,0x35,0x36, - 0x30,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x94,0x0A,0xF3,0x3D, - 0x5A,0x66,0xC1,0x2C,0x8B,0x68,0xD9,0x26,0xBB,0xD9,0x09,0x22,0x7F,0x34,0x85,0x96, - 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,0x83,0x85,0x8B,0x92,0x05, - 0x1B,0x41,0x9E,0x45,0xAB,0xAB,0xB2,0xE3,0xFD,0xD5,0x44,0xCA,0x41,0xBD,0xE7,0x30, - 0x81,0xD4,0x06,0x03,0x55,0x1D,0x20,0x04,0x81,0xCC,0x30,0x81,0xC9,0x30,0x81,0xC6, - 0x06,0x0B,0x2B,0x06,0x01,0x04,0x01,0xA3,0x48,0x83,0x7D,0x01,0x01,0x30,0x81,0xB6, - 0x30,0x81,0x80,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02,0x30,0x74,0x1E, - 0x72,0x00,0x43,0x00,0x6F,0x00,0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00, - 0x68,0x00,0x74,0x00,0x20,0x00,0x28,0x00,0x63,0x00,0x29,0x00,0x20,0x00,0x32,0x00, - 0x30,0x00,0x31,0x00,0x33,0x00,0x20,0x00,0x41,0x00,0x54,0x00,0x54,0x00,0x20,0x00, - 0x57,0x00,0x69,0x00,0x2D,0x00,0x46,0x00,0x69,0x00,0x20,0x00,0x53,0x00,0x65,0x00, - 0x72,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x73,0x00,0x20,0x00,0x41,0x00, - 0x6C,0x00,0x6C,0x00,0x20,0x00,0x52,0x00,0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00, - 0x73,0x00,0x20,0x00,0x52,0x00,0x65,0x00,0x73,0x00,0x65,0x00,0x72,0x00,0x76,0x00, - 0x65,0x00,0x64,0x30,0x31,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16, - 0x25,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2D,0x62,0x2E,0x70,0x6B, - 0x69,0x2E,0x77,0x61,0x79,0x70,0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x63,0x70, - 0x73,0x2E,0x68,0x74,0x6D,0x6C,0x30,0x81,0xB9,0x06,0x03,0x55,0x1D,0x1F,0x04,0x81, - 0xB1,0x30,0x81,0xAE,0x30,0x81,0xAB,0xA0,0x2B,0xA0,0x29,0x86,0x27,0x68,0x74,0x74, - 0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2D,0x62,0x2E,0x70,0x6B,0x69,0x2E,0x77,0x61, - 0x79,0x70,0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x6D,0x64,0x63,0x61,0x67,0x32, - 0x2E,0x63,0x72,0x6C,0xA2,0x7C,0xA4,0x7A,0x30,0x78,0x31,0x21,0x30,0x1F,0x06,0x03, - 0x55,0x04,0x03,0x0C,0x18,0x41,0x57,0x53,0x20,0x4D,0x61,0x6E,0x61,0x67,0x65,0x64, - 0x20,0x44,0x65,0x76,0x69,0x63,0x65,0x20,0x43,0x41,0x20,0x47,0x32,0x31,0x1B,0x30, - 0x19,0x06,0x03,0x55,0x04,0x0B,0x0C,0x12,0x41,0x54,0x54,0x20,0x57,0x69,0x2D,0x46, - 0x69,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x31,0x19,0x30,0x17,0x06,0x03, - 0x55,0x04,0x0A,0x0C,0x10,0x41,0x54,0x54,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65, - 0x73,0x20,0x49,0x6E,0x63,0x31,0x0E,0x30,0x0C,0x06,0x03,0x55,0x04,0x08,0x0C,0x05, - 0x54,0x65,0x78,0x61,0x73,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, - 0x55,0x53,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02, - 0x03,0xA8,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,0x27,0x06,0x03,0x55,0x1D,0x11,0x04,0x20,0x30,0x1E,0x82,0x1C,0x6E,0x6D, - 0x64,0x2E,0x6D,0x63,0x64,0x30,0x36,0x36,0x34,0x33,0x2E,0x73,0x6A,0x63,0x2E,0x77, - 0x61,0x79,0x70,0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74,0x30,0x0D,0x06,0x09,0x2A,0x86, - 0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x19,0x90, - 0xD6,0x10,0xBA,0x3E,0x55,0x07,0x1B,0x4E,0x71,0x94,0x9F,0xCE,0x80,0xD7,0x1F,0x90, - 0x2A,0x23,0x79,0x45,0xFB,0x61,0x47,0x19,0xBD,0x32,0x58,0xB2,0x58,0xC5,0x37,0xE9, - 0x01,0x63,0x61,0x6B,0x1E,0x17,0x54,0xC5,0xE9,0x5F,0x2A,0x9F,0xF3,0x01,0x0A,0x4C, - 0x61,0x7C,0x18,0x9A,0x3E,0x91,0x7F,0x14,0x8E,0xDF,0xB2,0x2C,0xB8,0xEC,0x3B,0x7C, - 0xC7,0xE5,0x62,0xC4,0x72,0x22,0x42,0xBB,0x61,0x9C,0xB0,0x5D,0x49,0x44,0x47,0x90, - 0x8E,0xBF,0x85,0x88,0xFF,0x36,0x7A,0x4C,0xCE,0x35,0x1B,0x88,0x93,0xE4,0x0A,0xB4, - 0xD1,0x24,0x44,0x43,0x8E,0xC0,0xFC,0x7F,0xE8,0x03,0xCD,0x91,0xF5,0x21,0x6F,0x4B, - 0xB7,0x9C,0x06,0xDC,0xE0,0xE4,0x5A,0xFD,0x3C,0x33,0xC4,0xE1,0xFB,0xB7,0xC4,0xF5, - 0xD4,0xC4,0xFD,0x63,0x43,0xD8,0x9B,0x2C,0x6C,0x5D,0x45,0xBE,0xD2,0x25,0x80,0xF7, - 0x5D,0x4A,0x73,0xB5,0xB4,0xF0,0xEF,0xDD,0x91,0x11,0xEF,0xAB,0x85,0xD6,0xDF,0x92, - 0xC0,0xA6,0x3E,0xBE,0x7A,0x2B,0xC5,0xD0,0x6C,0x48,0x6C,0x2A,0x9E,0x7D,0x7B,0xFC, - 0x93,0x9D,0x80,0xD1,0xCB,0x2F,0x2C,0x3E,0x94,0x46,0x5B,0xF3,0x8A,0xE8,0xE9,0xC7, - 0x1A,0x49,0x67,0x2B,0xE7,0xDD,0x73,0x05,0x1C,0x83,0x08,0xC5,0xBB,0xBC,0x47,0x5D, - 0x90,0x38,0x08,0xAC,0x49,0x82,0xE7,0xA9,0x28,0xA2,0x42,0x3E,0xFD,0x15,0x5C,0xF9, - 0x63,0x50,0x18,0xCA,0x76,0x1B,0x9C,0x88,0xF7,0x4D,0x7C,0xF4,0x5B,0x0E,0x93,0x53, - 0xBC,0xFD,0x25,0x90,0x88,0x06,0xB7,0xDE,0x33,0x33,0x5D,0xD6,0x9C,0x03, -}; - - -/* subject:/C=US/ST=Texas/O=ATT Services Inc/OU=ATT Wi-Fi Services/CN=AWS Managed Device CA G2 */ -/* issuer :/C=US/ST=Texas/O=ATT Services Inc/OU=ATT Wi-Fi Services/CN=ATT Wi-Fi Services Root Certificate Authority G2 */ - -static unsigned char att_intermediate1[1578]={ - 0x30,0x82,0x06,0x26,0x30,0x82,0x05,0x0E,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x19, - 0x54,0xAA,0x5A,0x22,0x2C,0x5B,0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, - 0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x90,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, - 0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0E,0x30,0x0C,0x06,0x03,0x55,0x04,0x08,0x13, - 0x05,0x54,0x65,0x78,0x61,0x73,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13, - 0x10,0x41,0x54,0x54,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x49,0x6E, - 0x63,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x0B,0x13,0x12,0x41,0x54,0x54,0x20, - 0x57,0x69,0x2D,0x46,0x69,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x31,0x39, - 0x30,0x37,0x06,0x03,0x55,0x04,0x03,0x13,0x30,0x41,0x54,0x54,0x20,0x57,0x69,0x2D, - 0x46,0x69,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x52,0x6F,0x6F,0x74, - 0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74, - 0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x47,0x32,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30, - 0x36,0x30,0x35,0x31,0x38,0x33,0x30,0x31,0x35,0x5A,0x17,0x0D,0x31,0x38,0x30,0x35, - 0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x78,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0E,0x30,0x0C,0x06,0x03,0x55,0x04, - 0x08,0x13,0x05,0x54,0x65,0x78,0x61,0x73,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, - 0x0A,0x13,0x10,0x41,0x54,0x54,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20, - 0x49,0x6E,0x63,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x0B,0x13,0x12,0x41,0x54, - 0x54,0x20,0x57,0x69,0x2D,0x46,0x69,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, - 0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x13,0x18,0x41,0x57,0x53,0x20,0x4D, - 0x61,0x6E,0x61,0x67,0x65,0x64,0x20,0x44,0x65,0x76,0x69,0x63,0x65,0x20,0x43,0x41, - 0x20,0x47,0x32,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,0x8C,0xE4,0xEB,0x2B,0x6D,0x51,0x1E,0xFE,0xBE,0xB9,0x1D,0x72, - 0x6D,0xD9,0x0C,0xBB,0x30,0x58,0x28,0xA2,0xA2,0x03,0x5B,0x99,0xCF,0x12,0x8B,0xF5, - 0xAD,0x91,0x66,0x30,0xEC,0x33,0xDE,0x2D,0xF2,0x8C,0x27,0xD9,0x46,0xCC,0xC5,0x32, - 0x46,0x31,0xC5,0xCA,0x13,0x9A,0xE2,0xD2,0x5E,0x8F,0xCD,0x3C,0x77,0x91,0x71,0x88, - 0xD9,0xD9,0xA1,0x31,0x8F,0xDA,0x32,0x5E,0x61,0x19,0x65,0x80,0xE6,0x3B,0x0C,0xD8, - 0x85,0xBC,0x26,0x4F,0x89,0x6D,0x4F,0xFF,0x3D,0x02,0x8D,0xA7,0x81,0x26,0xF9,0xD5, - 0x2F,0xFD,0x1B,0x30,0xF4,0x7B,0x67,0x51,0x37,0xE3,0x45,0x88,0x2B,0xCF,0x49,0x4E, - 0xDD,0x22,0xFC,0x93,0xA7,0x25,0x4E,0xDE,0x1D,0x61,0x0D,0x8D,0xF4,0xF0,0xD4,0x65, - 0x89,0xAD,0xC0,0xBA,0x7E,0xB4,0x8F,0x05,0x02,0xA9,0xDA,0x48,0x1B,0xE0,0x9E,0x06, - 0x7C,0xC0,0x9C,0x50,0xFB,0x59,0x16,0x09,0xB2,0x91,0xAF,0xC6,0xAD,0x7D,0x18,0x41, - 0x0E,0x41,0xAC,0xBC,0x22,0xFD,0x78,0xF6,0xF7,0xA3,0x02,0x34,0x77,0x5D,0x11,0x47, - 0xC2,0x3B,0xAA,0x60,0x38,0x06,0xCA,0xAF,0x18,0xD5,0xC0,0x1E,0x97,0x4F,0x96,0xD4, - 0x65,0x37,0x23,0xD7,0xAA,0xF1,0xCB,0x27,0xB0,0x53,0xFF,0x74,0x76,0x66,0xEE,0x25, - 0x1A,0xE0,0x18,0x6C,0xFD,0x29,0x15,0xAE,0x89,0x86,0x6D,0xA1,0x56,0x41,0x5D,0x81, - 0x68,0x5A,0xC4,0x4A,0x43,0x30,0x38,0xDB,0x61,0x9B,0xDC,0x9A,0x83,0x26,0xF5,0xCE, - 0x64,0x48,0x1C,0x1A,0x9B,0xE3,0xCB,0xB1,0x8C,0x1C,0x51,0x6C,0x94,0x7C,0x88,0x73, - 0xDB,0x71,0xED,0x57,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x02,0x99,0x30,0x82,0x02, - 0x95,0x30,0x70,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x64,0x30, - 0x62,0x30,0x35,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x29,0x68, - 0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2D,0x62,0x2E,0x70,0x6B,0x69,0x2E, - 0x77,0x61,0x79,0x70,0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x72,0x6F,0x6F,0x74, - 0x63,0x61,0x67,0x32,0x2E,0x63,0x72,0x74,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x30,0x01,0x86,0x1D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73, - 0x70,0x2D,0x62,0x2E,0x70,0x6B,0x69,0x2E,0x77,0x61,0x79,0x70,0x6F,0x72,0x74,0x2E, - 0x6E,0x65,0x74,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x83,0x85, - 0x8B,0x92,0x05,0x1B,0x41,0x9E,0x45,0xAB,0xAB,0xB2,0xE3,0xFD,0xD5,0x44,0xCA,0x41, - 0xBD,0xE7,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06, - 0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30, - 0x16,0x80,0x14,0xF3,0xD3,0xC7,0x5E,0x2C,0x45,0x26,0x7E,0xFD,0xE6,0xE4,0xB4,0x94, - 0xB8,0x04,0x0F,0x39,0x3B,0x10,0xDE,0x30,0x81,0xE3,0x06,0x03,0x55,0x1D,0x20,0x04, - 0x81,0xDB,0x30,0x81,0xD8,0x30,0x81,0xC6,0x06,0x0B,0x2B,0x06,0x01,0x04,0x01,0xA3, - 0x48,0x83,0x7D,0x01,0x01,0x30,0x81,0xB6,0x30,0x81,0x80,0x06,0x08,0x2B,0x06,0x01, - 0x05,0x05,0x07,0x02,0x02,0x30,0x74,0x1E,0x72,0x00,0x43,0x00,0x6F,0x00,0x70,0x00, - 0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00,0x20,0x00,0x28,0x00, - 0x63,0x00,0x29,0x00,0x20,0x00,0x32,0x00,0x30,0x00,0x31,0x00,0x33,0x00,0x20,0x00, - 0x41,0x00,0x54,0x00,0x54,0x00,0x20,0x00,0x57,0x00,0x69,0x00,0x2D,0x00,0x46,0x00, - 0x69,0x00,0x20,0x00,0x53,0x00,0x65,0x00,0x72,0x00,0x76,0x00,0x69,0x00,0x63,0x00, - 0x65,0x00,0x73,0x00,0x20,0x00,0x41,0x00,0x6C,0x00,0x6C,0x00,0x20,0x00,0x52,0x00, - 0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00,0x73,0x00,0x20,0x00,0x52,0x00,0x65,0x00, - 0x73,0x00,0x65,0x00,0x72,0x00,0x76,0x00,0x65,0x00,0x64,0x30,0x31,0x06,0x08,0x2B, - 0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x25,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, - 0x63,0x72,0x6C,0x2D,0x62,0x2E,0x70,0x6B,0x69,0x2E,0x77,0x61,0x79,0x70,0x6F,0x72, - 0x74,0x2E,0x6E,0x65,0x74,0x2F,0x63,0x70,0x73,0x2E,0x68,0x74,0x6D,0x6C,0x30,0x0D, - 0x06,0x0B,0x2B,0x06,0x01,0x04,0x01,0xA3,0x48,0x83,0x7D,0x01,0x02,0x30,0x81,0xD6, - 0x06,0x03,0x55,0x1D,0x1F,0x04,0x81,0xCE,0x30,0x81,0xCB,0x30,0x81,0xC8,0xA0,0x2D, - 0xA0,0x2B,0x86,0x29,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2D,0x62, - 0x2E,0x70,0x6B,0x69,0x2E,0x77,0x61,0x79,0x70,0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74, - 0x2F,0x72,0x6F,0x6F,0x74,0x63,0x61,0x67,0x32,0x2E,0x63,0x72,0x6C,0xA2,0x81,0x96, - 0xA4,0x81,0x93,0x30,0x81,0x90,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, - 0x02,0x55,0x53,0x31,0x0E,0x30,0x0C,0x06,0x03,0x55,0x04,0x08,0x0C,0x05,0x54,0x65, - 0x78,0x61,0x73,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x0C,0x10,0x41,0x54, - 0x54,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x49,0x6E,0x63,0x31,0x1B, - 0x30,0x19,0x06,0x03,0x55,0x04,0x0B,0x0C,0x12,0x41,0x54,0x54,0x20,0x57,0x69,0x2D, - 0x46,0x69,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x31,0x39,0x30,0x37,0x06, - 0x03,0x55,0x04,0x03,0x0C,0x30,0x41,0x54,0x54,0x20,0x57,0x69,0x2D,0x46,0x69,0x20, - 0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65, - 0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72, - 0x69,0x74,0x79,0x20,0x47,0x32,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,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x79,0xE7,0x9C,0xD0,0x93,0x93, - 0xB8,0xD6,0xC5,0x58,0x85,0xD4,0xDA,0xC1,0x22,0x73,0x87,0x2F,0x97,0x9C,0x79,0x9B, - 0x61,0xC1,0x87,0xBB,0xA8,0xFD,0x9F,0x07,0x0C,0x3D,0xA1,0xD3,0xFC,0x17,0x46,0x04, - 0x1E,0xBE,0xEF,0x8B,0x9A,0xB1,0x17,0x82,0x75,0x25,0x41,0x68,0xD6,0x46,0x13,0x7A, - 0x9E,0xFB,0x13,0xCE,0x01,0xCA,0x1F,0xD2,0x3F,0x7F,0xF1,0xF3,0xCB,0xC5,0xF7,0x8A, - 0xAA,0x0F,0x63,0x8E,0xC9,0x68,0x31,0xDB,0x3D,0x69,0x4C,0x55,0xC6,0x34,0x24,0x52, - 0x76,0xC0,0x51,0xF9,0x29,0x2B,0xB2,0x3C,0x3C,0x95,0x11,0x20,0x92,0x1A,0x25,0xB8, - 0x10,0x3E,0x45,0xA3,0x4F,0x27,0x51,0xA3,0x8A,0x1D,0xEC,0x00,0x40,0x35,0x3F,0xAC, - 0x2D,0x49,0xD0,0x20,0x85,0x01,0xAE,0xF7,0x7D,0xFC,0x62,0x4E,0x49,0x9C,0xAA,0x99, - 0x27,0x6A,0x14,0xE3,0x51,0x9D,0x1B,0x1F,0xA9,0x32,0x33,0x4E,0xA9,0xA2,0x55,0x21, - 0xDB,0xFF,0x57,0x5A,0x3D,0xC7,0x80,0x6F,0xF1,0x75,0x3F,0x38,0x09,0x52,0x80,0xD5, - 0x5D,0xFE,0x6D,0x84,0x3A,0x9B,0xA7,0x53,0x62,0x48,0x96,0xA9,0x75,0xB0,0xEA,0x6A, - 0x78,0xB4,0x92,0x1F,0xC4,0xD2,0x46,0x59,0xEA,0xE0,0x14,0x01,0x38,0xD7,0x6B,0x5D, - 0x7F,0xB3,0x30,0x15,0x34,0x11,0x52,0xD1,0xF9,0xFB,0xFF,0x21,0xDB,0x06,0xD4,0x3D, - 0xB8,0x69,0xA0,0x95,0x34,0x20,0x1E,0xA1,0x31,0xF5,0xBD,0x18,0x1E,0x08,0xD8,0x55, - 0x06,0xB3,0x28,0x3B,0xF8,0x58,0x94,0x0C,0xBB,0x23,0xCB,0x9E,0x10,0x28,0x64,0x2D, - 0xB9,0x19,0x86,0xB6,0x29,0x2C,0xF2,0xA5,0x36,0x6B, -}; - - -/* subject:/C=US/ST=Texas/O=ATT Services Inc/OU=ATT Wi-Fi Services/CN=ATT Wi-Fi Services Root Certificate Authority G2 */ -/* issuer :/C=BE/OU=Trusted Root/O=GlobalSign nv-sa/CN=Trusted Root CA G2 */ - -static unsigned char att_intermediate2[1833]={ - 0x30,0x82,0x07,0x25,0x30,0x82,0x06,0x0D,0xA0,0x03,0x02,0x01,0x02,0x02,0x11,0x5C, - 0xD7,0xD8,0x96,0xBA,0xD5,0xC9,0x77,0x11,0xBC,0x14,0xCF,0x0E,0xD3,0x5F,0x20,0x62, - 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30, - 0x5C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x15, - 0x30,0x13,0x06,0x03,0x55,0x04,0x0B,0x13,0x0C,0x54,0x72,0x75,0x73,0x74,0x65,0x64, - 0x20,0x52,0x6F,0x6F,0x74,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10, - 0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76,0x2D,0x73,0x61, - 0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x54,0x72,0x75,0x73,0x74, - 0x65,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x47,0x32,0x30,0x1E,0x17, - 0x0D,0x31,0x33,0x30,0x35,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D, - 0x31,0x38,0x30,0x35,0x33,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x81,0x90, - 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0E,0x30, - 0x0C,0x06,0x03,0x55,0x04,0x08,0x13,0x05,0x54,0x65,0x78,0x61,0x73,0x31,0x19,0x30, - 0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10,0x41,0x54,0x54,0x20,0x53,0x65,0x72,0x76, - 0x69,0x63,0x65,0x73,0x20,0x49,0x6E,0x63,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04, - 0x0B,0x13,0x12,0x41,0x54,0x54,0x20,0x57,0x69,0x2D,0x46,0x69,0x20,0x53,0x65,0x72, - 0x76,0x69,0x63,0x65,0x73,0x31,0x39,0x30,0x37,0x06,0x03,0x55,0x04,0x03,0x13,0x30, - 0x41,0x54,0x54,0x20,0x57,0x69,0x2D,0x46,0x69,0x20,0x53,0x65,0x72,0x76,0x69,0x63, - 0x65,0x73,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63, - 0x61,0x74,0x65,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x20,0x47,0x32, - 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,0x83,0x87,0xD2,0xCE,0xE7,0xA6,0x57,0x09,0xA0,0x0A,0x5D,0xD3,0xBF,0x66,0x2B, - 0x82,0x7E,0xB2,0x8B,0xC2,0x32,0x68,0x61,0x36,0x7D,0xC4,0x96,0xCF,0x2A,0x64,0x7E, - 0xA7,0x9C,0x3F,0x67,0x3C,0x3E,0x50,0x6F,0x33,0x75,0x16,0x8E,0x81,0x70,0x67,0x5C, - 0x37,0x07,0xBD,0xD4,0xD4,0x70,0xD7,0x26,0x3B,0x38,0x25,0x3E,0xB4,0xB6,0x5E,0xCF, - 0x9A,0x89,0x45,0xA0,0x35,0xDE,0x15,0x83,0x36,0x9F,0x22,0x87,0xEA,0xFE,0xC8,0x4F, - 0xE8,0x6C,0x67,0xAA,0xEC,0xBC,0xA9,0xDA,0xA7,0xA4,0x3A,0xEB,0xB9,0xD5,0x31,0x4F, - 0x08,0x15,0x8A,0xCB,0x92,0x1B,0xFC,0xA2,0x5E,0xC6,0x6F,0x6B,0xA3,0x8E,0x9A,0x4C, - 0xAB,0x47,0xA3,0x75,0x06,0xED,0xB9,0xFA,0xD6,0xF4,0xA1,0x29,0xEA,0x3D,0xE1,0x8C, - 0xE5,0x85,0xCF,0x8E,0x35,0x81,0x20,0x9B,0x68,0x46,0x55,0x0F,0xA0,0x38,0x07,0xAF, - 0x6F,0x4F,0xAE,0xFD,0x7F,0x98,0xB6,0x6E,0x06,0xA8,0x14,0xCC,0x5B,0x8D,0xDD,0x4C, - 0xA7,0xC7,0x5A,0x4D,0xFA,0x17,0xFD,0xEC,0x77,0xD4,0x0D,0xA1,0xE8,0xFF,0x33,0x01, - 0x14,0x10,0xBC,0x82,0x38,0xEF,0xEF,0xBC,0xCE,0x8C,0x11,0x0A,0xFC,0xFE,0x55,0xA5, - 0x5B,0xA7,0x37,0xD6,0xBB,0xB2,0x5F,0x85,0x06,0xF6,0x96,0xFB,0x24,0x32,0xF4,0x51, - 0xB9,0x4D,0x1D,0x27,0x6A,0xB5,0xD2,0xC0,0x12,0x4B,0x8A,0x33,0xE0,0xC5,0x45,0x3D, - 0xD9,0x38,0xD6,0xE3,0xEF,0x28,0x32,0x77,0xD5,0x72,0xEE,0x99,0x06,0x6A,0xB0,0x05, - 0x43,0x4D,0xA2,0xB1,0x5F,0x22,0x92,0xD3,0x26,0xAC,0x0F,0x5C,0x91,0x6F,0x17,0x85, - 0x17,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x03,0xAB,0x30,0x82,0x03,0xA7,0x30,0x0E, - 0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x82, - 0x01,0x0B,0x06,0x03,0x55,0x1D,0x20,0x04,0x82,0x01,0x02,0x30,0x81,0xFF,0x30,0x71, - 0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0xA0,0x32,0x01,0x3C,0x01,0x30,0x63,0x30,0x32, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x26,0x68,0x74,0x74,0x70, - 0x73,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x73,0x69, - 0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72, - 0x79,0x2F,0x30,0x2D,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02,0x30,0x21, - 0x0C,0x1F,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x54,0x72,0x75, - 0x73,0x74,0x65,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x50,0x72,0x6F,0x67,0x72,0x61, - 0x6D,0x30,0x81,0x89,0x06,0x0B,0x2B,0x06,0x01,0x04,0x01,0xA3,0x48,0x83,0x7D,0x01, - 0x01,0x30,0x7A,0x30,0x2F,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16, - 0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x70,0x6B,0x69,0x2E, - 0x77,0x61,0x79,0x70,0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74,0x2F,0x63,0x70,0x73,0x2E, - 0x68,0x74,0x6D,0x6C,0x30,0x47,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02, - 0x30,0x3B,0x0C,0x39,0x43,0x6F,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x63, - 0x29,0x20,0x32,0x30,0x31,0x33,0x20,0x41,0x54,0x54,0x20,0x57,0x69,0x2D,0x46,0x69, - 0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x41,0x6C,0x6C,0x20,0x52,0x69, - 0x67,0x68,0x74,0x73,0x20,0x52,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x30,0x12,0x06, - 0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01, - 0x01,0x30,0x82,0x01,0x4B,0x06,0x03,0x55,0x1D,0x1E,0x04,0x82,0x01,0x42,0x30,0x82, - 0x01,0x3E,0xA0,0x82,0x01,0x08,0x30,0x0D,0x82,0x0B,0x77,0x61,0x79,0x70,0x6F,0x72, - 0x74,0x2E,0x6E,0x65,0x74,0x30,0x0D,0x82,0x0B,0x61,0x74,0x74,0x77,0x69,0x66,0x69, - 0x2E,0x63,0x6F,0x6D,0x30,0x10,0x82,0x0E,0x73,0x75,0x70,0x65,0x72,0x63,0x6C,0x69, - 0x63,0x6B,0x2E,0x6E,0x65,0x74,0x30,0x10,0x82,0x0E,0x73,0x75,0x70,0x65,0x72,0x63, - 0x6C,0x69,0x63,0x6B,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x81,0x0B,0x77,0x61,0x79,0x70, - 0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74,0x30,0x0E,0x81,0x0C,0x2E,0x77,0x61,0x79,0x70, - 0x6F,0x72,0x74,0x2E,0x6E,0x65,0x74,0x30,0x0D,0x81,0x0B,0x61,0x74,0x74,0x77,0x69, - 0x66,0x69,0x2E,0x63,0x6F,0x6D,0x30,0x0E,0x81,0x0C,0x2E,0x61,0x74,0x74,0x77,0x69, - 0x66,0x69,0x2E,0x63,0x6F,0x6D,0x30,0x10,0x81,0x0E,0x73,0x75,0x70,0x65,0x72,0x63, - 0x6C,0x69,0x63,0x6B,0x2E,0x6E,0x65,0x74,0x30,0x11,0x81,0x0F,0x2E,0x73,0x75,0x70, - 0x65,0x72,0x63,0x6C,0x69,0x63,0x6B,0x2E,0x6E,0x65,0x74,0x30,0x10,0x81,0x0E,0x73, - 0x75,0x70,0x65,0x72,0x63,0x6C,0x69,0x63,0x6B,0x2E,0x63,0x6F,0x6D,0x30,0x11,0x81, - 0x0F,0x2E,0x73,0x75,0x70,0x65,0x72,0x63,0x6C,0x69,0x63,0x6B,0x2E,0x63,0x6F,0x6D, - 0x30,0x3C,0xA4,0x3A,0x30,0x38,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13, - 0x02,0x55,0x53,0x31,0x0E,0x30,0x0C,0x06,0x03,0x55,0x04,0x08,0x13,0x05,0x54,0x65, - 0x78,0x61,0x73,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10,0x41,0x54, - 0x54,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x20,0x49,0x6E,0x63,0xA1,0x30, - 0x30,0x0A,0x87,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x22,0x87,0x20, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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, - 0x3D,0x06,0x03,0x55,0x1D,0x1F,0x04,0x36,0x30,0x34,0x30,0x32,0xA0,0x30,0xA0,0x2E, - 0x86,0x2C,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x67,0x6C,0x6F, - 0x62,0x61,0x6C,0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x67,0x73,0x2F,0x74, - 0x72,0x75,0x73,0x74,0x72,0x6F,0x6F,0x74,0x67,0x32,0x2E,0x63,0x72,0x6C,0x30,0x81, - 0x84,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x78,0x30,0x76,0x30, - 0x33,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x27,0x68,0x74,0x74, - 0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x32,0x2E,0x67,0x6C,0x6F,0x62,0x61,0x6C, - 0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x74,0x72,0x75,0x73,0x74,0x72,0x6F, - 0x6F,0x74,0x67,0x32,0x30,0x3F,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02, - 0x86,0x33,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x73,0x65,0x63,0x75,0x72,0x65,0x2E, - 0x67,0x6C,0x6F,0x62,0x61,0x6C,0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x63, - 0x61,0x63,0x65,0x72,0x74,0x2F,0x74,0x72,0x75,0x73,0x74,0x72,0x6F,0x6F,0x74,0x67, - 0x32,0x2E,0x63,0x72,0x74,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14, - 0xF3,0xD3,0xC7,0x5E,0x2C,0x45,0x26,0x7E,0xFD,0xE6,0xE4,0xB4,0x94,0xB8,0x04,0x0F, - 0x39,0x3B,0x10,0xDE,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80, - 0x14,0x14,0xF6,0xE5,0x8B,0x31,0xB6,0x45,0x80,0x4A,0x4C,0x6D,0xFC,0xC2,0x87,0x89, - 0xCA,0x36,0xC3,0x90,0x62,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, - 0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x85,0xDE,0x66,0x4A,0x3A,0x3B,0xAD, - 0x8A,0xC7,0x32,0xFF,0x2D,0xD3,0x81,0x69,0x1D,0x1C,0xDE,0xE5,0x1E,0x87,0xE6,0x33, - 0xFE,0x34,0x80,0x1E,0xCF,0xC8,0xF8,0x93,0x38,0x12,0x9B,0x42,0xC4,0x9A,0x49,0x8B, - 0x98,0xAF,0x52,0xEC,0xD7,0x10,0xC4,0x44,0xEA,0x57,0xE6,0xA5,0xA5,0xC4,0x53,0x15, - 0xEB,0xEA,0x3D,0x8A,0xB2,0x9F,0xF2,0x90,0x1A,0x03,0xBA,0xB7,0xC8,0x89,0xCD,0x88, - 0x26,0xF6,0xA3,0xFD,0x41,0x3C,0x70,0x01,0xE1,0x03,0x99,0x33,0xFA,0xF6,0xB1,0x92, - 0xED,0x3C,0xF9,0x03,0xC5,0x28,0xBB,0x18,0xD8,0x25,0x8F,0x6C,0x13,0x12,0x70,0xFA, - 0x38,0x1E,0xB2,0xC8,0xC9,0x60,0x51,0x3A,0x43,0x86,0x4F,0x27,0xEF,0xAD,0x03,0x58, - 0x52,0xCC,0xAF,0x6F,0x03,0xDB,0x7B,0x3B,0xDA,0xF2,0xBC,0xE7,0x40,0x0D,0xE6,0xD9, - 0x8C,0x36,0x2E,0xEA,0x01,0xA9,0x66,0xCA,0x26,0x41,0x71,0x57,0x84,0xE0,0x38,0xA4, - 0x13,0xDE,0x05,0xC4,0xC4,0x0A,0x79,0xCF,0x5F,0xE3,0x8E,0xDE,0xCC,0xD8,0x8E,0x6E, - 0xBC,0x4F,0x50,0x2C,0xD4,0x68,0xDF,0xB6,0xA8,0x61,0x80,0x0B,0x03,0x74,0xF3,0xFF, - 0x09,0x4A,0x13,0xA0,0x57,0x96,0x0B,0xCB,0x62,0x09,0xB4,0x18,0xFB,0x07,0xD2,0x93, - 0x17,0x50,0xCF,0xFE,0x5B,0x50,0x03,0xCE,0x9F,0x19,0x65,0x1E,0x9D,0xAD,0xA1,0x49, - 0x0C,0xC0,0x3D,0xFC,0x1F,0xE9,0xA4,0xEF,0x2D,0x6C,0xFA,0x0C,0xF5,0x0D,0xBB,0x2D, - 0xCA,0x36,0x22,0x5B,0xCE,0xEB,0xC4,0x4F,0xF7,0x78,0xCD,0x3F,0xCC,0xCE,0xA8,0xCF, - 0x4F,0x0B,0x14,0x49,0x6E,0xA0,0xE7,0xF1,0x60, -}; - - -/* subject:/C=BE/OU=Trusted Root/O=GlobalSign nv-sa/CN=Trusted Root CA G2 */ -/* issuer :/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ - -static unsigned char att_intermediate3[1121]={ - 0x30,0x82,0x04,0x5D,0x30,0x82,0x03,0x45,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, - 0x00,0x00,0x00,0x00,0x01,0x36,0xE9,0x3A,0x3A,0xB3,0x30,0x0D,0x06,0x09,0x2A,0x86, - 0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x57,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, - 0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76, - 0x2D,0x73,0x61,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F, - 0x6F,0x74,0x20,0x43,0x41,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12, - 0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20, - 0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x32,0x30,0x34,0x32,0x35,0x31,0x31,0x30,0x30, - 0x30,0x30,0x5A,0x17,0x0D,0x32,0x37,0x30,0x34,0x32,0x35,0x31,0x31,0x30,0x30,0x30, - 0x30,0x5A,0x30,0x5C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42, - 0x45,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0B,0x13,0x0C,0x54,0x72,0x75,0x73, - 0x74,0x65,0x64,0x20,0x52,0x6F,0x6F,0x74,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, - 0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76, - 0x2D,0x73,0x61,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x54,0x72, - 0x75,0x73,0x74,0x65,0x64,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x20,0x47,0x32, - 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,0xAC,0xAE,0xBE,0xAA,0xED,0x70,0xCA,0xFB,0x83,0xB1,0x2E,0x35,0xBB,0xB8,0xB0, - 0xAC,0x31,0x33,0x5D,0xBB,0x52,0xC0,0xA6,0xC7,0x54,0x71,0x6F,0x1C,0x60,0x70,0x0A, - 0xC6,0x4B,0xBA,0xE3,0x89,0xE7,0xE9,0x04,0x7F,0xF0,0xE0,0xB6,0x2B,0xCA,0x68,0xDF, - 0xBD,0xCC,0x35,0xB9,0xEC,0x8C,0x36,0x8A,0x8B,0xA3,0xD9,0xC9,0x33,0x3F,0xCE,0x45, - 0x7B,0xA9,0x6F,0x7E,0x4D,0x35,0xF1,0x3A,0xEB,0xBA,0x6B,0x41,0x81,0xDA,0xFA,0xD4, - 0xE3,0x97,0x52,0x22,0x2A,0x90,0x7B,0x41,0x4C,0x2D,0xDF,0x05,0xCF,0xB9,0x33,0x05, - 0x25,0xAD,0x6D,0x5E,0xD8,0xCA,0xCE,0x4A,0x89,0xCA,0xE2,0x65,0x36,0xE3,0xCA,0x4F, - 0xBE,0x87,0x72,0x38,0x0D,0xAA,0x05,0x75,0xB3,0xDA,0x86,0xE3,0x83,0x03,0xE4,0x8D, - 0x89,0xBC,0x8D,0x76,0x76,0xEF,0x33,0x23,0x56,0xE0,0x75,0x0F,0xA5,0xFC,0xAB,0x17, - 0x91,0x37,0xDB,0x1A,0x35,0x2F,0x84,0xE2,0xCE,0x95,0x53,0x56,0x55,0x00,0xE9,0x2F, - 0xE6,0x0C,0x22,0xB1,0xAA,0x80,0x16,0x31,0xCB,0x94,0xD4,0x36,0x0A,0xC0,0x71,0x1B, - 0x70,0xA4,0xD7,0x52,0xD8,0xA9,0x05,0xE6,0x8B,0x52,0x98,0xCC,0x1E,0x55,0xBE,0x64, - 0x86,0x85,0x15,0xBF,0x7B,0xBC,0x53,0x14,0x07,0xFD,0x65,0x9B,0x36,0x11,0xEA,0xD5, - 0x1A,0xC8,0x96,0x0F,0xF4,0xAC,0x15,0x1F,0x8B,0xFC,0xE2,0x4A,0x16,0x05,0x48,0x1E, - 0xD4,0xF9,0xA2,0xF1,0xE4,0x3C,0x4F,0xA6,0x14,0xC5,0x06,0x20,0xEA,0xB9,0x01,0xA9, - 0xB4,0x1F,0x85,0x0B,0x82,0x6F,0x9E,0xE9,0x03,0x4A,0xD1,0x62,0x85,0x90,0x99,0xD5, - 0x1F,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x23,0x30,0x82,0x01,0x1F,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, - 0x47,0x06,0x03,0x55,0x1D,0x20,0x04,0x40,0x30,0x3E,0x30,0x3C,0x06,0x04,0x55,0x1D, - 0x20,0x00,0x30,0x34,0x30,0x32,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01, - 0x16,0x26,0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x67,0x6C, - 0x6F,0x62,0x61,0x6C,0x73,0x69,0x67,0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70, - 0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, - 0x16,0x04,0x14,0x14,0xF6,0xE5,0x8B,0x31,0xB6,0x45,0x80,0x4A,0x4C,0x6D,0xFC,0xC2, - 0x87,0x89,0xCA,0x36,0xC3,0x90,0x62,0x30,0x33,0x06,0x03,0x55,0x1D,0x1F,0x04,0x2C, - 0x30,0x2A,0x30,0x28,0xA0,0x26,0xA0,0x24,0x86,0x22,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x63,0x72,0x6C,0x2E,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x73,0x69,0x67,0x6E,0x2E, - 0x6E,0x65,0x74,0x2F,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C,0x30,0x3E,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x32,0x30,0x30,0x30,0x2E,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x22,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x6F,0x63,0x73,0x70,0x32,0x2E,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x73,0x69,0x67, - 0x6E,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x6F,0x6F,0x74,0x72,0x31,0x30,0x1F,0x06,0x03, - 0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x60,0x7B,0x66,0x1A,0x45,0x0D,0x97, - 0xCA,0x89,0x50,0x2F,0x7D,0x04,0xCD,0x34,0xA8,0xFF,0xFC,0xFD,0x4B,0x30,0x0D,0x06, - 0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01, - 0x00,0xBE,0xC8,0x1B,0x49,0x7E,0x93,0x82,0xE4,0x72,0x92,0x3E,0x6B,0xF9,0x2F,0x66, - 0xC4,0x91,0xC1,0x23,0x38,0xB8,0x0E,0xB3,0x19,0x7D,0xF8,0x7B,0xBF,0x00,0xDA,0x8C, - 0xAD,0xAF,0xC4,0x46,0xF1,0xB2,0x70,0x55,0xBF,0x3E,0x00,0x73,0x14,0x0F,0xE5,0xDE, - 0xDA,0x46,0x1D,0x87,0xF5,0x23,0xFF,0x06,0x90,0x5D,0xFA,0x91,0xD0,0xE8,0x31,0x41, - 0x72,0xFD,0x0A,0xDE,0x19,0x33,0xE2,0x65,0x47,0x56,0xAF,0xB0,0xD2,0x97,0x58,0xBE, - 0x40,0xC1,0x85,0xC0,0x5C,0x23,0x81,0xDC,0x9E,0x4F,0x5B,0x65,0xCE,0x72,0x4E,0xC7, - 0x67,0x0D,0x2F,0x45,0xB1,0x90,0x86,0x35,0xA3,0x43,0x1F,0x81,0xE0,0xA3,0x94,0x16, - 0x0D,0x5B,0xDE,0x8B,0xFF,0xCF,0xA5,0xE4,0xAF,0x7C,0x9A,0x09,0xF4,0x50,0x85,0x78, - 0x7B,0x28,0x2D,0x01,0x73,0x44,0x57,0x3C,0xF1,0xB9,0x36,0xFE,0x65,0x09,0x6F,0xB3, - 0xB5,0xB6,0xE0,0xD3,0x33,0x26,0xDE,0x4C,0x9F,0x40,0x84,0xD1,0xBA,0xC3,0x12,0x83, - 0xA2,0x01,0xB0,0x32,0x6A,0x3A,0x78,0xDA,0x89,0xA2,0x90,0x45,0xC5,0xE2,0x0F,0x44, - 0xA4,0xE3,0x76,0x57,0x6F,0x66,0xD4,0x28,0xCC,0x42,0xEF,0xE4,0xDD,0xDD,0x02,0xF8, - 0x47,0x21,0xDC,0x58,0x96,0xD0,0xED,0x8C,0xA5,0x2D,0x34,0xBF,0xC7,0xE8,0xF1,0x58, - 0x87,0x0E,0x43,0x4A,0x0E,0xE7,0xFE,0x78,0xB7,0x93,0xD3,0x43,0x5E,0x27,0x79,0x88, - 0x4E,0xCF,0xDC,0x78,0x81,0x49,0x36,0x01,0x80,0x16,0xE9,0xDD,0x6F,0x78,0xFC,0x1B, - 0x85,0xC0,0xBC,0xAE,0x84,0x30,0x90,0x74,0xFB,0x1E,0xF7,0xD8,0x06,0x87,0x3B,0xE0, - 0x53, +/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Name Constraints Test Root CA */ +/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Name Constraints Test Root CA */ +unsigned char _test_root[1522]={ + 0x30,0x82,0x05,0xEE,0x30,0x82,0x03,0xD6,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00, + 0x89,0xE7,0x6B,0x1C,0xA7,0x17,0xF2,0x6E,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,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,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x0C,0x1D,0x4E, + 0x61,0x6D,0x65,0x20,0x43,0x6F,0x6E,0x73,0x74,0x72,0x61,0x69,0x6E,0x74,0x73,0x20, + 0x54,0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D, + 0x31,0x37,0x30,0x35,0x32,0x34,0x30,0x30,0x34,0x34,0x35,0x35,0x5A,0x17,0x0D,0x32, + 0x37,0x30,0x35,0x32,0x32,0x30,0x30,0x34,0x34,0x35,0x35,0x5A,0x30,0x81,0x92,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,0x26,0x30,0x24,0x06,0x03,0x55, + 0x04,0x03,0x0C,0x1D,0x4E,0x61,0x6D,0x65,0x20,0x43,0x6F,0x6E,0x73,0x74,0x72,0x61, + 0x69,0x6E,0x74,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43, + 0x41,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,0xE2,0x1F,0x96,0xEE,0x21,0x91,0x31,0xD5,0x13,0x9F,0x2B,0x2B,0x55,0x85, + 0xA9,0x23,0x9A,0x3F,0x51,0x61,0x77,0x6F,0xFF,0x75,0x6C,0x40,0xC5,0xDA,0x14,0x2D, + 0x6E,0x57,0x4F,0xEC,0x06,0x8A,0x30,0x05,0x18,0x93,0xE3,0x23,0xA9,0xEC,0x14,0xBD, + 0xED,0xA4,0x2E,0xF8,0x56,0x02,0xB7,0x27,0xCA,0x0E,0x61,0x0C,0xDA,0x5D,0xBF,0x01, + 0x54,0x4E,0x3D,0xC5,0x45,0x6E,0x7A,0xB5,0x8C,0xE5,0x95,0xCC,0xDB,0x83,0x3A,0x9B, + 0x6D,0x52,0x30,0xBB,0x71,0x0A,0xCE,0x45,0x90,0x7B,0x5A,0xC6,0x57,0x03,0x41,0xC6, + 0xDA,0x42,0x14,0x82,0x41,0x3D,0xD9,0x96,0xA3,0x8D,0x29,0xEA,0x78,0xBA,0x98,0x98, + 0x97,0x49,0x6B,0x43,0x47,0x97,0xB7,0x6D,0xDD,0x72,0x4D,0xF9,0x28,0x77,0x7B,0x72, + 0xB0,0x5D,0xF8,0x4E,0xBC,0x89,0x92,0x37,0xB3,0xDC,0x79,0x42,0x25,0xE9,0xA3,0x92, + 0xFF,0x26,0x9C,0x99,0xFD,0xD8,0x81,0x6A,0xEE,0x3F,0x31,0x54,0x8C,0x83,0x94,0x91, + 0x42,0x5E,0x2B,0xC5,0x68,0x83,0xE2,0x83,0x19,0x67,0xC2,0x6E,0x48,0xEE,0xB0,0x4E, + 0xD3,0xBB,0x27,0x6A,0x62,0xCA,0xE5,0xBE,0x8D,0xA4,0xC3,0x8F,0x49,0x3E,0xDF,0xCE, + 0xBF,0x4C,0xE3,0x8E,0x5F,0xA9,0x1D,0x55,0x7D,0x3B,0xED,0x7A,0x3C,0xFF,0xFE,0x57, + 0x90,0xA1,0x29,0xE7,0xBA,0xA7,0xEA,0xD6,0x0C,0xDD,0x04,0xCA,0x6E,0x60,0x75,0x2A, + 0xC7,0x91,0xAF,0x80,0x24,0xAB,0xE1,0xAA,0x6D,0x12,0x02,0x0C,0x18,0x9A,0xA0,0x1F, + 0x39,0x80,0x87,0xF2,0x71,0xE0,0xF5,0xA5,0x8E,0x17,0x0A,0xF6,0x82,0x18,0x86,0x4B, + 0x2B,0x71,0xC8,0x9A,0x70,0x0A,0xF7,0x04,0x25,0x72,0x99,0x81,0x01,0xD4,0x6F,0x3D, + 0x6A,0xB7,0x71,0x64,0xF8,0xF3,0x72,0xF3,0x1F,0xB0,0x65,0x35,0x6B,0x42,0x57,0x1C, + 0x8A,0x04,0xAC,0x7B,0x47,0x19,0x30,0xB0,0x83,0xF5,0xDD,0x73,0x4F,0x1D,0x0F,0x3A, + 0xB5,0xB0,0x74,0x39,0x03,0x16,0x0C,0xD3,0xBF,0xCE,0x26,0x26,0x94,0xBD,0x6B,0x89, + 0x22,0x0B,0x9E,0xB1,0x23,0xBD,0xFE,0x1E,0x17,0x28,0xA9,0x5D,0x51,0xAA,0x4F,0xA3, + 0x5D,0xA0,0x67,0xA0,0x12,0x0F,0xB4,0xF5,0x43,0xFE,0x46,0x4B,0x08,0xCC,0x5D,0x45, + 0xA7,0x56,0x9E,0xB8,0x0A,0xAC,0x35,0x9F,0x38,0x94,0x12,0x0D,0x3E,0xC5,0x0F,0xA0, + 0x1C,0x60,0xEC,0x7E,0x14,0x33,0x5D,0x15,0x60,0x40,0xA7,0x31,0x8E,0xD0,0x15,0x17, + 0x29,0x9C,0x73,0xF8,0xEA,0x72,0xEC,0x79,0xBA,0x6D,0xFD,0x4B,0xA3,0xB2,0x01,0x6B, + 0x7D,0xDD,0xF5,0x92,0x63,0x6F,0x95,0x93,0x81,0xB2,0x48,0x77,0x4C,0x9F,0x5C,0xF3, + 0x4C,0x3B,0xAC,0x46,0x42,0x95,0x1E,0xBC,0x53,0x9D,0xCF,0xFB,0xC5,0xB0,0x45,0x6C, + 0xCA,0x8F,0x03,0xB1,0x99,0x15,0xC0,0x26,0xA3,0xFD,0x2A,0x89,0x18,0x1A,0xDF,0xD8, + 0xA8,0x79,0xC1,0xCE,0xB2,0x36,0x81,0x4A,0x7B,0x83,0x10,0xE2,0xA6,0x13,0xF4,0xC3, + 0x20,0x60,0x1D,0x5D,0xFB,0x62,0x8D,0xB7,0x8A,0xB3,0x56,0x56,0xF5,0xFD,0xC6,0x3A, + 0xCA,0x5B,0x65,0x9D,0xB2,0xFD,0x3B,0x12,0xB7,0x74,0x9C,0x51,0xC3,0x80,0x15,0xAD, + 0x16,0x68,0x6B,0x10,0x32,0xDF,0xEC,0xF0,0x8A,0xB1,0xDB,0x7E,0xC4,0x5F,0x44,0xCB, + 0xD6,0x05,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,0x1F,0x9D,0x00,0xFC,0x49,0x77, + 0x92,0x50,0xF6,0xC4,0xE1,0x6A,0x0D,0xC5,0xC6,0x9A,0xB0,0xFB,0xE5,0xF8,0x30,0x0D, + 0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x02, + 0x01,0x00,0xC3,0xF0,0x6B,0x94,0x51,0xFF,0xFC,0x73,0x44,0x8E,0x15,0x32,0x4C,0x46, + 0xAE,0xFF,0x5A,0xB3,0x80,0x55,0xF0,0x1A,0xEB,0x44,0xA2,0xBA,0x2B,0x28,0xDD,0x5B, + 0x48,0x00,0x69,0x58,0x9A,0x9E,0x82,0xB5,0xFE,0xAD,0xA1,0x43,0x40,0x1A,0x43,0x64, + 0xFC,0x85,0xD9,0xD2,0x23,0x14,0x85,0xA7,0x20,0x5F,0xD7,0x3A,0xE1,0x74,0x17,0x6B, + 0x2B,0xFD,0x48,0xE6,0xBD,0x24,0x74,0x57,0xFD,0x62,0x31,0x29,0x74,0x9D,0xA8,0xE5, + 0xE7,0x4C,0xEF,0x2B,0x29,0xAD,0xA7,0x75,0x33,0x67,0x78,0x59,0x42,0x52,0x6A,0x33, + 0x0A,0x7E,0x99,0x38,0xA1,0xAF,0xF1,0x9B,0xBF,0x98,0x02,0xC5,0x58,0x8F,0x91,0x90, + 0xEE,0xFA,0x52,0xA5,0xD4,0xCB,0xB3,0x7D,0x33,0xD3,0xDD,0x5A,0x99,0x50,0x9D,0xBD, + 0xC7,0xA2,0x16,0x3C,0x50,0x44,0x83,0xD4,0x8C,0x38,0x70,0x30,0xB4,0x41,0x50,0x1E, + 0x0F,0xCF,0x5D,0xCE,0xFD,0x39,0xE8,0x5A,0x76,0x8E,0x42,0x30,0x88,0x5D,0xF1,0xA8, + 0xFD,0x63,0xB5,0xA6,0x06,0x59,0x07,0xF5,0x4B,0x2C,0x19,0xF4,0xC8,0x4A,0x79,0x6A, + 0xE9,0x77,0xDE,0x40,0x20,0x3D,0x64,0x5B,0xF1,0xFA,0x89,0x5E,0xDF,0x26,0x2D,0xE3, + 0x53,0xCC,0xC9,0xF2,0x65,0xAC,0x50,0xC6,0x12,0x25,0x2F,0xD0,0x1C,0x99,0x56,0x36, + 0x64,0x22,0x56,0x46,0x27,0xC6,0x02,0x7E,0x79,0xF6,0x2A,0x93,0xFA,0x2E,0x4D,0x08, + 0xB7,0xEB,0xB0,0x11,0x72,0xB9,0x2D,0x97,0xD6,0x01,0x39,0x35,0x90,0x9D,0xAC,0x9F, + 0xD8,0xA2,0x04,0xE9,0x0C,0x8D,0xEF,0x8F,0xA5,0xDD,0x2E,0xF9,0x50,0x54,0x0F,0x9F, + 0xA6,0x94,0x92,0xE0,0x15,0x9D,0x72,0x9F,0x49,0x6A,0x80,0xF2,0x44,0x5F,0xB2,0xE5, + 0x8C,0x9B,0x1F,0xA6,0xE9,0x87,0xAF,0x3B,0xFF,0xF4,0x5B,0xD7,0x20,0x33,0x2A,0x05, + 0x22,0x27,0x5F,0x5F,0xC1,0x41,0x0B,0xB9,0x1E,0xA9,0x5D,0x99,0x56,0xA6,0xDF,0x45, + 0x3E,0xAD,0x9A,0xF2,0x2A,0x00,0x04,0xC8,0xD9,0xD5,0x0C,0xB1,0xCF,0x2A,0x9F,0xBD, + 0xE2,0xFF,0x1C,0x2B,0xB9,0xFF,0x5A,0x75,0x3F,0x27,0xB0,0x75,0x15,0xA4,0xA4,0xBC, + 0xB0,0x56,0xFA,0xC6,0x0C,0xBD,0x33,0xB7,0x6A,0xE5,0x3A,0xB7,0x0A,0xE2,0x82,0x7F, + 0xBA,0x2D,0xD1,0xF5,0xB0,0xF0,0xEC,0xEC,0x89,0xC6,0xFD,0x9A,0xAE,0x6B,0x53,0x27, + 0xB5,0xE7,0x08,0x76,0xE0,0x12,0xAC,0xB2,0xCC,0x8B,0x55,0x7D,0xCF,0xC6,0xBA,0xEF, + 0xB3,0x50,0xFA,0x5B,0xA3,0x01,0x51,0x23,0xE8,0xFC,0xD9,0x36,0x53,0xC0,0x88,0xBB, + 0xF7,0x7F,0x5C,0x26,0xE2,0x35,0x78,0x76,0x82,0x0A,0xB0,0x51,0xE3,0x28,0xA7,0xB8, + 0xA0,0x35,0x97,0xA5,0x43,0x3A,0xE7,0x81,0x6C,0x8C,0x63,0x85,0x8B,0xBE,0x4B,0x53, + 0xFC,0xCD,0xBE,0xA8,0x35,0x92,0x24,0x5C,0x2A,0x32,0xED,0xD0,0x6F,0x4F,0x2D,0x66, + 0xD4,0x99,0xEA,0x95,0xF6,0x9E,0x7A,0xFE,0x36,0x8E,0x92,0x89,0xCD,0x2B,0x08,0x45, + 0x92,0x8A,0x72,0x1C,0x58,0x24,0x14,0xA6,0xE0,0x5C,0xDB,0x06,0xBE,0x82,0xC4,0x9A, + 0xF1,0x0B,0x6D,0x8B,0x89,0xF5,0xF6,0x97,0x1F,0x52,0x4C,0xE7,0x8E,0x51,0x85,0x45, + 0xD0,0x40,0xAF,0xB4,0x61,0xEC,0x4A,0x44,0x9D,0x4B,0xBB,0xB7,0xBE,0x26,0xE7,0xFC, + 0xF5,0x32, }; - -/* subject:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ -/* issuer :/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA */ - -static unsigned char att_root[889]={ - 0x30,0x82,0x03,0x75,0x30,0x82,0x02,0x5D,0xA0,0x03,0x02,0x01,0x02,0x02,0x0B,0x04, - 0x00,0x00,0x00,0x00,0x01,0x15,0x4B,0x5A,0xC3,0x94,0x30,0x0D,0x06,0x09,0x2A,0x86, - 0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x57,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x06,0x13,0x02,0x42,0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04, - 0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76, - 0x2D,0x73,0x61,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F, - 0x6F,0x74,0x20,0x43,0x41,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12, - 0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20, - 0x43,0x41,0x30,0x1E,0x17,0x0D,0x39,0x38,0x30,0x39,0x30,0x31,0x31,0x32,0x30,0x30, - 0x30,0x30,0x5A,0x17,0x0D,0x32,0x38,0x30,0x31,0x32,0x38,0x31,0x32,0x30,0x30,0x30, - 0x30,0x5A,0x30,0x57,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x42, - 0x45,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0A,0x13,0x10,0x47,0x6C,0x6F,0x62, - 0x61,0x6C,0x53,0x69,0x67,0x6E,0x20,0x6E,0x76,0x2D,0x73,0x61,0x31,0x10,0x30,0x0E, - 0x06,0x03,0x55,0x04,0x0B,0x13,0x07,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x1B, - 0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x53, - 0x69,0x67,0x6E,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30, +/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Name Constraints Test Sub-CA */ +/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Name Constraints Test Root CA */ +/* X509v3 Name Constraints: + Permitted: + DNS:apple.com + DNS:.apple.com + DirName: C = US, O = Apple + DirName: C = US, O = Apple Inc. + DirName: C = US, O = "Apple Computer, Inc." + Excluded: + IP:0.0.0.0/0.0.0.0 + */ +unsigned char _test_intermediate[1493]={ + 0x30,0x82,0x05,0xD1,0x30,0x82,0x03,0xB9,0xA0,0x03,0x02,0x01,0x02,0x02,0x14,0x00, + 0xFD,0x7C,0xB1,0xC2,0x34,0xCB,0x38,0x97,0xB1,0x13,0x68,0x31,0x54,0x2B,0x67,0xFD, + 0x48,0xBD,0x69,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, + 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, + 0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x0C,0x1D,0x4E,0x61,0x6D,0x65,0x20,0x43, + 0x6F,0x6E,0x73,0x74,0x72,0x61,0x69,0x6E,0x74,0x73,0x20,0x54,0x65,0x73,0x74,0x20, + 0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x37,0x30,0x35,0x32, + 0x34,0x30,0x31,0x30,0x39,0x35,0x30,0x5A,0x17,0x0D,0x32,0x37,0x30,0x35,0x32,0x32, + 0x30,0x31,0x30,0x39,0x35,0x30,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,0x4E, + 0x61,0x6D,0x65,0x20,0x43,0x6F,0x6E,0x73,0x74,0x72,0x61,0x69,0x6E,0x74,0x73,0x20, + 0x54,0x65,0x73,0x74,0x20,0x53,0x75,0x62,0x2D,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,0xDA,0x0E,0xE6,0x99, - 0x8D,0xCE,0xA3,0xE3,0x4F,0x8A,0x7E,0xFB,0xF1,0x8B,0x83,0x25,0x6B,0xEA,0x48,0x1F, - 0xF1,0x2A,0xB0,0xB9,0x95,0x11,0x04,0xBD,0xF0,0x63,0xD1,0xE2,0x67,0x66,0xCF,0x1C, - 0xDD,0xCF,0x1B,0x48,0x2B,0xEE,0x8D,0x89,0x8E,0x9A,0xAF,0x29,0x80,0x65,0xAB,0xE9, - 0xC7,0x2D,0x12,0xCB,0xAB,0x1C,0x4C,0x70,0x07,0xA1,0x3D,0x0A,0x30,0xCD,0x15,0x8D, - 0x4F,0xF8,0xDD,0xD4,0x8C,0x50,0x15,0x1C,0xEF,0x50,0xEE,0xC4,0x2E,0xF7,0xFC,0xE9, - 0x52,0xF2,0x91,0x7D,0xE0,0x6D,0xD5,0x35,0x30,0x8E,0x5E,0x43,0x73,0xF2,0x41,0xE9, - 0xD5,0x6A,0xE3,0xB2,0x89,0x3A,0x56,0x39,0x38,0x6F,0x06,0x3C,0x88,0x69,0x5B,0x2A, - 0x4D,0xC5,0xA7,0x54,0xB8,0x6C,0x89,0xCC,0x9B,0xF9,0x3C,0xCA,0xE5,0xFD,0x89,0xF5, - 0x12,0x3C,0x92,0x78,0x96,0xD6,0xDC,0x74,0x6E,0x93,0x44,0x61,0xD1,0x8D,0xC7,0x46, - 0xB2,0x75,0x0E,0x86,0xE8,0x19,0x8A,0xD5,0x6D,0x6C,0xD5,0x78,0x16,0x95,0xA2,0xE9, - 0xC8,0x0A,0x38,0xEB,0xF2,0x24,0x13,0x4F,0x73,0x54,0x93,0x13,0x85,0x3A,0x1B,0xBC, - 0x1E,0x34,0xB5,0x8B,0x05,0x8C,0xB9,0x77,0x8B,0xB1,0xDB,0x1F,0x20,0x91,0xAB,0x09, - 0x53,0x6E,0x90,0xCE,0x7B,0x37,0x74,0xB9,0x70,0x47,0x91,0x22,0x51,0x63,0x16,0x79, - 0xAE,0xB1,0xAE,0x41,0x26,0x08,0xC8,0x19,0x2B,0xD1,0x46,0xAA,0x48,0xD6,0x64,0x2A, - 0xD7,0x83,0x34,0xFF,0x2C,0x2A,0xC1,0x6C,0x19,0x43,0x4A,0x07,0x85,0xE7,0xD3,0x7C, - 0xF6,0x21,0x68,0xEF,0xEA,0xF2,0x52,0x9F,0x7F,0x93,0x90,0xCF,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,0x60,0x7B,0x66,0x1A,0x45,0x0D,0x97,0xCA,0x89,0x50,0x2F,0x7D,0x04,0xCD,0x34, - 0xA8,0xFF,0xFC,0xFD,0x4B,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, - 0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xD6,0x73,0xE7,0x7C,0x4F,0x76,0xD0, - 0x8D,0xBF,0xEC,0xBA,0xA2,0xBE,0x34,0xC5,0x28,0x32,0xB5,0x7C,0xFC,0x6C,0x9C,0x2C, - 0x2B,0xBD,0x09,0x9E,0x53,0xBF,0x6B,0x5E,0xAA,0x11,0x48,0xB6,0xE5,0x08,0xA3,0xB3, - 0xCA,0x3D,0x61,0x4D,0xD3,0x46,0x09,0xB3,0x3E,0xC3,0xA0,0xE3,0x63,0x55,0x1B,0xF2, - 0xBA,0xEF,0xAD,0x39,0xE1,0x43,0xB9,0x38,0xA3,0xE6,0x2F,0x8A,0x26,0x3B,0xEF,0xA0, - 0x50,0x56,0xF9,0xC6,0x0A,0xFD,0x38,0xCD,0xC4,0x0B,0x70,0x51,0x94,0x97,0x98,0x04, - 0xDF,0xC3,0x5F,0x94,0xD5,0x15,0xC9,0x14,0x41,0x9C,0xC4,0x5D,0x75,0x64,0x15,0x0D, - 0xFF,0x55,0x30,0xEC,0x86,0x8F,0xFF,0x0D,0xEF,0x2C,0xB9,0x63,0x46,0xF6,0xAA,0xFC, - 0xDF,0xBC,0x69,0xFD,0x2E,0x12,0x48,0x64,0x9A,0xE0,0x95,0xF0,0xA6,0xEF,0x29,0x8F, - 0x01,0xB1,0x15,0xB5,0x0C,0x1D,0xA5,0xFE,0x69,0x2C,0x69,0x24,0x78,0x1E,0xB3,0xA7, - 0x1C,0x71,0x62,0xEE,0xCA,0xC8,0x97,0xAC,0x17,0x5D,0x8A,0xC2,0xF8,0x47,0x86,0x6E, - 0x2A,0xC4,0x56,0x31,0x95,0xD0,0x67,0x89,0x85,0x2B,0xF9,0x6C,0xA6,0x5D,0x46,0x9D, - 0x0C,0xAA,0x82,0xE4,0x99,0x51,0xDD,0x70,0xB7,0xDB,0x56,0x3D,0x61,0xE4,0x6A,0xE1, - 0x5C,0xD6,0xF6,0xFE,0x3D,0xDE,0x41,0xCC,0x07,0xAE,0x63,0x52,0xBF,0x53,0x53,0xF4, - 0x2B,0xE9,0xC7,0xFD,0xB6,0xF7,0x82,0x5F,0x85,0xD2,0x41,0x18,0xDB,0x81,0xB3,0x04, - 0x1C,0xC5,0x1F,0xA4,0x80,0x6F,0x15,0x20,0xC9,0xDE,0x0C,0x88,0x0A,0x1D,0xD6,0x66, - 0x55,0xE2,0xFC,0x48,0xC9,0x29,0x26,0x69,0xE0, -}; - -/* subject:/C=US/ST=CA/L=Santa Clara/O=Intel Corporation/CN=myctx.intel.com */ -/* issuer :/C=US/ST=CA/L=Santa Clara/O=Intel Corporation/CN=Intel External Basic Issuing CA 3A */ -unsigned char intel1_leaf[1644]={ - 0x30,0x82,0x06,0x68,0x30,0x82,0x05,0x50,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x33, - 0x00,0x00,0xAC,0x1A,0x2A,0x79,0x37,0xC7,0x7C,0x92,0x90,0x70,0x00,0x03,0x00,0x00, - 0xAC,0x1A,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,0x55,0x53, - 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x14,0x30, - 0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B,0x53,0x61,0x6E,0x74,0x61,0x20,0x43,0x6C, - 0x61,0x72,0x61,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x49,0x6E, - 0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31, - 0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x49,0x6E,0x74,0x65,0x6C,0x20, - 0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x42,0x61,0x73,0x69,0x63,0x20,0x49, - 0x73,0x73,0x75,0x69,0x6E,0x67,0x20,0x43,0x41,0x20,0x33,0x41,0x30,0x1E,0x17,0x0D, - 0x31,0x33,0x31,0x31,0x31,0x31,0x30,0x31,0x30,0x31,0x31,0x33,0x5A,0x17,0x0D,0x31, - 0x36,0x31,0x30,0x32,0x36,0x30,0x31,0x30,0x31,0x31,0x33,0x5A,0x30,0x66,0x31,0x0B, - 0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, - 0x07,0x13,0x0B,0x53,0x61,0x6E,0x74,0x61,0x20,0x43,0x6C,0x61,0x72,0x61,0x31,0x1A, - 0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x49,0x6E,0x74,0x65,0x6C,0x20,0x43, - 0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x18,0x30,0x16,0x06,0x03, - 0x55,0x04,0x03,0x13,0x0F,0x6D,0x79,0x63,0x74,0x78,0x2E,0x69,0x6E,0x74,0x65,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,0xB5,0x28,0x2C,0x28,0x93,0x36,0x61,0x9D,0x2E,0xA9,0x69, - 0x3D,0xF6,0x28,0x32,0x06,0x63,0x0D,0x74,0x11,0xCF,0xAD,0x68,0x10,0xE4,0x99,0xCA, - 0x24,0x93,0xE2,0x06,0xA0,0xB7,0xC9,0xB4,0xCD,0x43,0xD7,0x2C,0xA0,0xC4,0x36,0x60, - 0x40,0x1D,0x89,0xD2,0xD7,0x71,0x92,0xB5,0x36,0xA3,0x7F,0xC5,0x4B,0x3A,0x85,0x61, - 0x2D,0xED,0x08,0x0E,0x7E,0x33,0xF2,0x48,0x5D,0x30,0x9E,0x8B,0xFB,0xA2,0x6E,0x8A, - 0xE0,0xD2,0xE8,0x21,0xBE,0x5F,0x0D,0xAB,0x41,0x06,0xFE,0xB6,0xCE,0x26,0x02,0x3E, - 0xFC,0xF8,0x12,0x62,0xB5,0xDC,0x89,0xA1,0x93,0xB7,0x11,0xAF,0x57,0x24,0xE4,0xB5, - 0x88,0x75,0x4D,0xFB,0xB8,0x14,0x3C,0xD6,0x1A,0x64,0x55,0x1D,0xE6,0xBE,0x54,0x84, - 0xD9,0x44,0x1C,0x9F,0xC4,0x4B,0xB2,0x11,0x42,0x27,0xC1,0xE6,0x0A,0x9A,0x0E,0x92, - 0xD1,0x38,0xEF,0x98,0x5F,0x22,0xF4,0xD9,0x43,0x97,0x8D,0x85,0x77,0x62,0x8B,0xB0, - 0x6E,0xEC,0xB1,0x7B,0x42,0x40,0x74,0xB3,0x46,0x95,0x20,0x40,0x5A,0xE7,0xCB,0x94, - 0x1E,0xAA,0xC5,0xFB,0x4D,0x32,0x05,0x5E,0x5E,0x24,0x1F,0x63,0x8A,0x32,0xFD,0x1E, - 0xC5,0xAD,0x71,0xBC,0x87,0xEB,0x16,0x55,0xD6,0xE9,0x6E,0xBF,0x69,0x1D,0x99,0xC9, - 0x85,0x5D,0xF9,0xC9,0xAB,0x97,0xEB,0x5F,0xF9,0x3B,0x9F,0xDB,0x88,0x92,0x4F,0xFB, - 0x41,0x44,0x18,0x12,0xBA,0x3F,0x37,0x62,0x64,0x07,0x6B,0xD7,0x0F,0x32,0x05,0x80, - 0xB2,0xF0,0x70,0xC3,0xAA,0xFA,0x98,0xE2,0xF8,0xE8,0x0E,0x5D,0x25,0xEB,0x47,0x33, - 0xA4,0xF2,0xCC,0xE4,0x7F,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x02,0xFA,0x30,0x82, - 0x02,0xF6,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x05,0xA0,0x30, - 0x3D,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x07,0x04,0x30,0x30,0x2E, - 0x06,0x26,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x08,0x86,0xC3,0x8C,0x75,0x84, - 0x99,0xE5,0x51,0x83,0xFD,0x81,0x28,0x85,0x8E,0x9F,0x53,0x82,0x91,0xC0,0x09,0x67, - 0x82,0xFC,0xFB,0x17,0x85,0x9B,0xFA,0x24,0x02,0x01,0x64,0x02,0x01,0x0C,0x30,0x1D, - 0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x71,0x4F,0x14,0x9A,0x04,0x37,0x44, - 0x3B,0x7E,0xB1,0x8A,0xC7,0xB0,0x6F,0x94,0x0A,0xDD,0x79,0x28,0xE2,0x30,0x1F,0x06, - 0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x33,0x38,0x3D,0x81,0xCA,0xC4, - 0xA5,0xCC,0x51,0xBA,0xC5,0x83,0x68,0x84,0xAB,0x0A,0x61,0x6E,0xC9,0x98,0x30,0x81, - 0xCF,0x06,0x03,0x55,0x1D,0x1F,0x04,0x81,0xC7,0x30,0x81,0xC4,0x30,0x81,0xC1,0xA0, - 0x81,0xBE,0xA0,0x81,0xBB,0x86,0x57,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77, - 0x77,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F, - 0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x43,0x52,0x4C,0x2F,0x49,0x6E,0x74,0x65,0x6C, - 0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42,0x61, - 0x73,0x69,0x63,0x25,0x32,0x30,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x25,0x32,0x30, - 0x43,0x41,0x25,0x32,0x30,0x33,0x41,0x28,0x33,0x29,0x2E,0x63,0x72,0x6C,0x86,0x60, - 0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, - 0x74,0x65,0x73,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65, - 0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x43,0x52,0x4C,0x2F,0x49,0x6E,0x74, - 0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30, - 0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x25, - 0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x33,0x41,0x28,0x33,0x29,0x2E,0x63,0x72,0x6C, - 0x30,0x81,0xF5,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x81,0xE8, - 0x30,0x81,0xE5,0x30,0x6C,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86, - 0x60,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x69,0x6E,0x74,0x65, - 0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79, - 0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2F,0x49,0x6E, - 0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32, - 0x30,0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x49,0x73,0x73,0x75,0x69,0x6E,0x67, - 0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x33,0x41,0x28,0x33,0x29,0x2E,0x63,0x72, - 0x74,0x30,0x75,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x69,0x68, - 0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74, - 0x65,0x73,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70, - 0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63, - 0x61,0x74,0x65,0x73,0x2F,0x49,0x6E,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74, - 0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30, - 0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x33, - 0x41,0x28,0x33,0x29,0x2E,0x63,0x72,0x74,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,0x27,0x06,0x09,0x2B,0x06,0x01,0x04,0x01, - 0x82,0x37,0x15,0x0A,0x04,0x1A,0x30,0x18,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x03,0x02,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01, - 0x30,0x56,0x06,0x03,0x55,0x1D,0x11,0x04,0x4F,0x30,0x4D,0x82,0x12,0x6D,0x79,0x63, - 0x74,0x78,0x2D,0x66,0x6D,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x82, - 0x12,0x6D,0x79,0x63,0x74,0x78,0x2D,0x69,0x72,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E, - 0x63,0x6F,0x6D,0x82,0x12,0x6D,0x79,0x63,0x74,0x78,0x2D,0x70,0x67,0x2E,0x69,0x6E, - 0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x82,0x0F,0x6D,0x79,0x63,0x74,0x78,0x2E,0x69, - 0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, - 0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x64,0xDC,0x71,0x94, - 0x8A,0x02,0xAF,0xA1,0xEB,0x83,0x15,0x8B,0xCB,0xB4,0x59,0x39,0x25,0x2D,0xB7,0xCC, - 0x44,0x76,0x03,0x16,0x77,0xED,0x33,0xE6,0x71,0x70,0xBA,0x56,0x75,0x44,0xD9,0x40, - 0x8B,0x1F,0xA0,0xCF,0x50,0x98,0x98,0xFD,0xE2,0x29,0x1A,0xC5,0x6D,0x7D,0x71,0xC5, - 0xF5,0x73,0x16,0x4B,0x89,0xF3,0x13,0xE1,0xBE,0x7C,0x77,0x01,0xD7,0xBC,0xC6,0x65, - 0xED,0xBC,0x7F,0x55,0x42,0xB8,0x32,0xEA,0x82,0x7F,0xE1,0xEF,0x91,0x31,0x92,0x10, - 0xCA,0xC3,0x21,0x0C,0x65,0x26,0xAB,0xBF,0xDB,0x5C,0xF1,0xC1,0x5F,0x54,0x7F,0xBE, - 0x78,0x7F,0x7E,0x1E,0x27,0x49,0xFA,0x86,0xE5,0x52,0x13,0x2D,0x49,0xE8,0x33,0x6F, - 0x71,0x87,0xB6,0x2A,0x94,0x71,0x81,0x40,0x46,0xD9,0xA3,0x3F,0x0D,0x5C,0x07,0x01, - 0x79,0x9D,0x5C,0x15,0x31,0xBC,0x33,0x38,0x41,0x29,0xC9,0x3D,0xDD,0x69,0xA1,0xB7, - 0x94,0x65,0x6F,0xC9,0x72,0x5F,0xAF,0x18,0x9A,0xE8,0xCC,0x4B,0x2D,0xB6,0x05,0x95, - 0x05,0xD8,0xA0,0x6A,0xA7,0x22,0xBD,0xA0,0x2D,0xCC,0x21,0x0B,0x25,0xD1,0x0B,0xF2, - 0x61,0xBE,0xE6,0xD0,0x6F,0xF1,0x16,0xF8,0x12,0xBD,0x95,0x2A,0xD5,0x90,0xE5,0x1D, - 0x79,0x51,0x29,0xBD,0xC9,0x19,0xEE,0xD6,0x88,0xDB,0xE3,0xD0,0x3A,0x85,0x53,0xA5, - 0xDC,0xC3,0xC0,0x93,0x34,0x48,0x41,0xC8,0x98,0xE2,0x82,0x85,0x76,0x7E,0xF7,0xFA, - 0x50,0x55,0xD8,0xEF,0xED,0xF8,0x71,0x1A,0x0D,0x3F,0xBA,0x51,0x91,0xBD,0x7F,0x41, - 0xD6,0x19,0x96,0x66,0x7B,0x97,0x8F,0x0C,0x9F,0x14,0x51,0x89, -}; - -/* subject:/C=US/ST=CA/L=Santa Clara/O=Intel Corporation/CN=Intel External Basic Issuing CA 3A */ -/* issuer :/C=US/O=Intel Corporation/CN=Intel External Basic Policy CA */ -unsigned char intel1_intermediate1[1725]={ - 0x30,0x82,0x06,0xB9,0x30,0x82,0x05,0xA1,0xA0,0x03,0x02,0x01,0x02,0x02,0x0A,0x61, - 0x2C,0x37,0xF2,0x00,0x01,0x00,0x00,0x00,0x0F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x52,0x31,0x0B,0x30,0x09,0x06,0x03, - 0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A, - 0x13,0x11,0x49,0x6E,0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74, - 0x69,0x6F,0x6E,0x31,0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x03,0x13,0x1E,0x49,0x6E, - 0x74,0x65,0x6C,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x42,0x61,0x73, - 0x69,0x63,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D, - 0x31,0x33,0x30,0x32,0x30,0x38,0x32,0x32,0x32,0x30,0x33,0x32,0x5A,0x17,0x0D,0x31, - 0x38,0x30,0x32,0x30,0x38,0x32,0x32,0x33,0x30,0x33,0x32,0x5A,0x30,0x79,0x31,0x0B, - 0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, - 0x07,0x13,0x0B,0x53,0x61,0x6E,0x74,0x61,0x20,0x43,0x6C,0x61,0x72,0x61,0x31,0x1A, - 0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x49,0x6E,0x74,0x65,0x6C,0x20,0x43, - 0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x2B,0x30,0x29,0x06,0x03, - 0x55,0x04,0x03,0x13,0x22,0x49,0x6E,0x74,0x65,0x6C,0x20,0x45,0x78,0x74,0x65,0x72, - 0x6E,0x61,0x6C,0x20,0x42,0x61,0x73,0x69,0x63,0x20,0x49,0x73,0x73,0x75,0x69,0x6E, - 0x67,0x20,0x43,0x41,0x20,0x33,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,0xA6,0x7F,0x0B,0xB7,0x72,0xEB,0xBA,0x00, - 0x19,0x22,0xD7,0x22,0x56,0xF7,0x90,0x51,0x90,0x66,0x8E,0x54,0x9F,0x25,0x70,0x70, - 0xBD,0x3F,0x72,0xD0,0x44,0xE4,0x0F,0xEA,0x09,0x11,0x63,0xD6,0x4E,0x9F,0x5D,0x1E, - 0x2A,0x0F,0xB7,0x92,0x0E,0x72,0x26,0xAB,0x95,0xED,0x46,0xA7,0xC8,0x08,0xFA,0x5A, - 0xD3,0x5A,0x70,0xF8,0xBB,0xBF,0x14,0xEF,0x35,0x8D,0x15,0x9C,0x8F,0x42,0xBC,0xED, - 0x42,0xBB,0xE8,0xA9,0x17,0x39,0xB7,0x7B,0xC8,0x56,0x98,0x3D,0xF0,0x95,0x81,0x67, - 0x51,0x6B,0xEA,0x99,0xB6,0x60,0x72,0x44,0x87,0x26,0xD0,0x42,0x38,0x03,0x4D,0xC7, - 0x46,0x3D,0x6B,0xE1,0xB4,0xE9,0x82,0xEF,0x39,0xBE,0xFF,0x7D,0x63,0xD4,0x73,0x81, - 0x14,0x59,0xC8,0x32,0x42,0x21,0x53,0x43,0x1B,0x6C,0x1B,0x84,0x34,0x9D,0xBE,0x2F, - 0x87,0x31,0x5B,0x5D,0x65,0xF7,0xCC,0xB0,0x59,0xDC,0x94,0x39,0xAB,0xDF,0xAC,0xB2, - 0xC5,0xAB,0x9B,0xC7,0x69,0xD0,0xE8,0x0D,0xF5,0x7E,0x53,0x84,0x0A,0xA5,0xEB,0x25, - 0x1E,0xD1,0xB2,0xBB,0x84,0x55,0x19,0xE1,0x9F,0xD6,0x21,0xC7,0x44,0x68,0x18,0x87, - 0x45,0x60,0x05,0x3A,0xFC,0x5E,0x66,0xF9,0x20,0xD8,0x1B,0xF2,0xA9,0xC3,0x7C,0xBC, - 0x15,0xB6,0x34,0xB7,0x7C,0xDD,0x68,0xFC,0x7E,0xF7,0x1A,0xCA,0xED,0x0A,0x41,0x59, - 0xE0,0xDB,0xB1,0x32,0x64,0xB1,0xE1,0xCF,0x35,0x72,0xFF,0x24,0x58,0x81,0x8E,0x1B, - 0x0B,0x02,0x11,0x5C,0xD3,0x61,0x85,0x3D,0x23,0x32,0x58,0x31,0x72,0xC8,0x8C,0xCA, - 0xDA,0xFC,0xDC,0xFF,0x3F,0xF9,0x5B,0xD1,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x03, - 0x68,0x30,0x82,0x03,0x64,0x30,0x12,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37, - 0x15,0x01,0x04,0x05,0x02,0x03,0x03,0x00,0x03,0x30,0x23,0x06,0x09,0x2B,0x06,0x01, - 0x04,0x01,0x82,0x37,0x15,0x02,0x04,0x16,0x04,0x14,0x4D,0x79,0xA3,0xAC,0x3C,0x5C, - 0xA2,0x96,0x30,0x07,0xC0,0xC5,0xE5,0xBD,0x91,0x39,0x8C,0xD9,0x1B,0x7B,0x30,0x1D, - 0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x33,0x38,0x3D,0x81,0xCA,0xC4,0xA5, - 0xCC,0x51,0xBA,0xC5,0x83,0x68,0x84,0xAB,0x0A,0x61,0x6E,0xC9,0x98,0x30,0x81,0xFA, - 0x06,0x03,0x55,0x1D,0x20,0x04,0x81,0xF2,0x30,0x81,0xEF,0x30,0x81,0xEC,0x06,0x0A, - 0x2A,0x86,0x48,0x86,0xF8,0x4D,0x01,0x05,0x01,0x69,0x30,0x81,0xDD,0x30,0x81,0x9C, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02,0x30,0x81,0x8F,0x1E,0x81,0x8C, - 0x00,0x49,0x00,0x6E,0x00,0x74,0x00,0x65,0x00,0x6C,0x00,0x20,0x00,0x43,0x00,0x6F, - 0x00,0x72,0x00,0x70,0x00,0x6F,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6F, - 0x00,0x6E,0x00,0x20,0x00,0x45,0x00,0x78,0x00,0x74,0x00,0x65,0x00,0x72,0x00,0x6E, - 0x00,0x61,0x00,0x6C,0x00,0x20,0x00,0x42,0x00,0x61,0x00,0x73,0x00,0x69,0x00,0x63, - 0x00,0x20,0x00,0x50,0x00,0x6F,0x00,0x6C,0x00,0x69,0x00,0x63,0x00,0x79,0x00,0x20, - 0x00,0x43,0x00,0x65,0x00,0x72,0x00,0x74,0x00,0x69,0x00,0x66,0x00,0x69,0x00,0x63, - 0x00,0x61,0x00,0x74,0x00,0x65,0x00,0x20,0x00,0x50,0x00,0x72,0x00,0x61,0x00,0x63, - 0x00,0x74,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x61, - 0x00,0x74,0x00,0x65,0x00,0x6D,0x00,0x65,0x00,0x6E,0x00,0x74,0x30,0x3C,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x30,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x77,0x77,0x77,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x72, - 0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x70,0x6B,0x69,0x63,0x70,0x73, - 0x2F,0x69,0x6E,0x64,0x65,0x78,0x2E,0x68,0x74,0x6D,0x30,0x19,0x06,0x09,0x2B,0x06, - 0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x04,0x0C,0x1E,0x0A,0x00,0x53,0x00,0x75,0x00, - 0x62,0x00,0x43,0x00,0x41,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02, - 0x01,0x86,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06, - 0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30, - 0x16,0x80,0x14,0x56,0x3A,0x6F,0x17,0xAB,0x24,0x0C,0xE5,0xB7,0x31,0x64,0xB0,0x11, - 0xED,0xDB,0xEA,0x23,0xBE,0x5E,0xBC,0x30,0x81,0xC3,0x06,0x03,0x55,0x1D,0x1F,0x04, - 0x81,0xBB,0x30,0x81,0xB8,0x30,0x81,0xB5,0xA0,0x81,0xB2,0xA0,0x81,0xAF,0x86,0x51, - 0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x69,0x6E,0x74,0x65,0x6C, - 0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F, - 0x43,0x52,0x4C,0x2F,0x49,0x6E,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65, - 0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x50, - 0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30,0x43,0x41,0x28,0x31,0x29,0x2E,0x63,0x72, - 0x6C,0x86,0x5A,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69,0x66, - 0x69,0x63,0x61,0x74,0x65,0x73,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D, - 0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x43,0x52,0x4C,0x2F, - 0x49,0x6E,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C, - 0x25,0x32,0x30,0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x50,0x6F,0x6C,0x69,0x63, - 0x79,0x25,0x32,0x30,0x43,0x41,0x28,0x31,0x29,0x2E,0x63,0x72,0x6C,0x30,0x81,0xE9, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x81,0xDC,0x30,0x81,0xD9, - 0x30,0x66,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x5A,0x68,0x74, - 0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63, - 0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x63,0x65, - 0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2F,0x49,0x6E,0x74,0x65,0x6C, - 0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42,0x61, - 0x73,0x69,0x63,0x25,0x32,0x30,0x50,0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30,0x43, - 0x41,0x28,0x31,0x29,0x2E,0x63,0x72,0x74,0x30,0x6F,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x30,0x02,0x86,0x63,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72, - 0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E, - 0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x63, - 0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2F,0x49,0x6E,0x74,0x65, - 0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42, - 0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x50,0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30, - 0x43,0x41,0x28,0x31,0x29,0x2E,0x63,0x72,0x74,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x0B,0x3F,0x6F, - 0x3B,0xCC,0xC6,0x8E,0x21,0x82,0x96,0x87,0xCA,0xDC,0x9D,0x44,0x78,0x37,0x93,0x76, - 0xD7,0xAB,0x7E,0xDD,0xC3,0xF4,0x80,0xFD,0x35,0x4E,0xA8,0x0A,0xCA,0xCC,0x15,0xA9, - 0x5B,0xD9,0x6B,0x5C,0x6C,0x7B,0xE3,0xE5,0xF7,0xE0,0x28,0x44,0xE7,0x22,0x55,0x46, - 0xF1,0x12,0x34,0x20,0x8E,0xDA,0xF7,0x3A,0x6B,0xBC,0xD3,0x17,0x08,0x35,0xA5,0xCF, - 0xAB,0xF1,0x03,0xAE,0xAF,0x85,0x3D,0x4A,0xA1,0x5B,0x4E,0x07,0x98,0xAD,0x0C,0xDB, - 0xFC,0xEE,0xB1,0x2E,0xB9,0x9D,0xE4,0xFE,0xB5,0xC6,0x53,0xAB,0xC0,0xC2,0x92,0xE3, - 0x51,0x60,0xEA,0x87,0x7A,0xB0,0x3F,0x41,0x0E,0x92,0x76,0x54,0xFD,0x90,0x4F,0x5F, - 0xDA,0x0E,0x54,0x1A,0x43,0xF0,0x11,0xC6,0x42,0x99,0x1B,0xBA,0xA9,0xA0,0x69,0xCF, - 0xD1,0x3E,0x0D,0xE8,0xC7,0x0A,0x8D,0x07,0xD0,0x20,0x26,0xFC,0x49,0x46,0x65,0xC0, - 0xF2,0x1C,0x28,0x42,0xC7,0x49,0x2F,0x04,0x52,0xBA,0x64,0xAC,0xF8,0x4B,0x48,0x66, - 0x21,0x55,0x59,0x18,0x98,0x0B,0x08,0xAA,0x94,0x15,0x7E,0x78,0xB9,0x70,0xF5,0xA0, - 0xCD,0x30,0xE1,0x18,0x84,0xC0,0x0D,0xF2,0xBD,0xF3,0x67,0x5B,0x22,0x5F,0xE3,0xDF, - 0x3B,0x4C,0x9F,0xAD,0x96,0x07,0xB5,0xC3,0x21,0x95,0x03,0x40,0x08,0x20,0xF6,0x89, - 0x56,0xF6,0x11,0x6C,0x2A,0x65,0x87,0xAD,0xC6,0xF0,0x38,0xF1,0xE8,0x31,0x12,0xAF, - 0xAE,0xC8,0xE9,0x82,0x75,0xD4,0x41,0x50,0x01,0x26,0xCF,0x6F,0xC7,0x7D,0x40,0x20, - 0x4B,0x3C,0x15,0xC1,0x3E,0xD1,0xFE,0x92,0x07,0x71,0xF0,0x76,0xB4, -}; - -/* subject:/C=US/ST=CA/L=Santa Clara/O=Intel Corporation/CN=contact.intel.com */ -/* issuer :/C=US/ST=CA/L=Santa Clara/O=Intel Corporation/CN=Intel External Basic Issuing CA 3B */ -unsigned char intel2_leaf[1725]={ - 0x30,0x82,0x06,0xB9,0x30,0x82,0x05,0xA1,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x33, - 0x00,0x00,0xB6,0x06,0x88,0x89,0x35,0x62,0x16,0x48,0xF1,0x1D,0x00,0x02,0x00,0x00, - 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,0x55,0x53, - 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x14,0x30, - 0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B,0x53,0x61,0x6E,0x74,0x61,0x20,0x43,0x6C, - 0x61,0x72,0x61,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x49,0x6E, - 0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31, - 0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x49,0x6E,0x74,0x65,0x6C,0x20, - 0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x42,0x61,0x73,0x69,0x63,0x20,0x49, - 0x73,0x73,0x75,0x69,0x6E,0x67,0x20,0x43,0x41,0x20,0x33,0x42,0x30,0x1E,0x17,0x0D, - 0x31,0x35,0x30,0x33,0x30,0x36,0x31,0x32,0x30,0x30,0x30,0x36,0x5A,0x17,0x0D,0x31, - 0x36,0x30,0x38,0x32,0x37,0x31,0x32,0x30,0x30,0x30,0x36,0x5A,0x30,0x68,0x31,0x0B, - 0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, - 0x07,0x13,0x0B,0x53,0x61,0x6E,0x74,0x61,0x20,0x43,0x6C,0x61,0x72,0x61,0x31,0x1A, - 0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x49,0x6E,0x74,0x65,0x6C,0x20,0x43, - 0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x1A,0x30,0x18,0x06,0x03, - 0x55,0x04,0x03,0x13,0x11,0x63,0x6F,0x6E,0x74,0x61,0x63,0x74,0x2E,0x69,0x6E,0x74, - 0x65,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,0xE8,0xAD,0x3F,0x95,0x76,0xD6,0x63,0xB4,0x9B, - 0x87,0x0C,0xF8,0x27,0x04,0xF8,0x0B,0x69,0x3B,0xE2,0xC1,0xA6,0xF7,0x28,0xFE,0x0E, - 0x7C,0x66,0x05,0x6C,0xBF,0xFE,0x3E,0x25,0x12,0xA0,0xAD,0x03,0x2F,0x77,0xAC,0x44, - 0x04,0xE8,0xB6,0x57,0x07,0x1D,0xF8,0x0B,0x67,0x35,0x13,0x3D,0x81,0x22,0x7E,0xE1, - 0x0D,0xFE,0x14,0x5B,0x4F,0x94,0x31,0x3C,0xB4,0xA5,0xE4,0xB5,0x6B,0x4E,0x73,0x48, - 0xE0,0x79,0xDD,0x37,0xDF,0xB9,0x26,0xC5,0x5C,0xAC,0x3B,0xB6,0x99,0x6E,0x56,0x4A, - 0x77,0x2A,0x55,0xBD,0xF6,0x71,0x71,0x50,0xBC,0xFC,0x33,0xD2,0x50,0x6E,0x37,0x71, - 0xFF,0x0E,0xFF,0x51,0x12,0xAF,0x19,0xAE,0xA3,0x64,0x1E,0xBA,0x10,0x0A,0xDE,0x9E, - 0xFA,0xEE,0xFE,0x41,0xAD,0xBB,0x15,0xCE,0x61,0x11,0x5A,0x1B,0xA4,0xA4,0x76,0x4A, - 0x32,0x0C,0xC6,0x9A,0x23,0xD2,0x7F,0xF0,0x62,0x94,0x60,0x29,0x38,0x56,0xBD,0xDE, - 0x52,0xDF,0xE6,0x23,0x1F,0xE0,0x2F,0x9D,0x75,0x04,0xF0,0xCA,0x13,0x68,0x9D,0xE1, - 0x80,0xD5,0x20,0x20,0x1F,0x11,0x7B,0xB0,0xCA,0x29,0x81,0xCC,0x15,0xA4,0xE1,0x4C, - 0xA4,0x0D,0xB2,0x20,0x63,0x7E,0xCD,0xB0,0xBC,0xD3,0x04,0x22,0x27,0x93,0x94,0x60, - 0x51,0x8D,0x30,0xB7,0x3D,0x29,0x06,0xBC,0x55,0x3D,0x31,0x8F,0x6B,0xED,0x26,0x98, - 0x6F,0xCB,0x40,0xF1,0xB5,0x22,0xC1,0xA8,0x33,0x0A,0x42,0x93,0x9E,0xCA,0xFA,0x04, - 0x72,0x0B,0xD5,0x31,0x5B,0x63,0x1C,0x35,0xD2,0x0D,0x03,0x37,0x29,0x2F,0xD9,0x79, - 0xF6,0xDA,0x07,0x7E,0x8D,0x31,0xC9,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x03,0x49, - 0x30,0x82,0x03,0x45,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x05, - 0xA0,0x30,0x3D,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x07,0x04,0x30, - 0x30,0x2E,0x06,0x26,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x08,0x86,0xC3,0x8C, - 0x75,0x84,0x99,0xE5,0x51,0x83,0xFD,0x81,0x28,0x85,0x8E,0x9F,0x53,0x82,0x91,0xC0, - 0x09,0x67,0x82,0xFC,0xFB,0x17,0x85,0x9B,0xFA,0x24,0x02,0x01,0x64,0x02,0x01,0x0D, - 0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4B,0x63,0x62,0x54,0x47, - 0xF3,0xCF,0x7F,0x7F,0x7A,0x8B,0x5D,0xC1,0x14,0x0E,0xD8,0x47,0x6C,0x3F,0x4A,0x30, - 0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xE5,0x9C,0x00,0xAE, - 0x43,0x00,0xBD,0x1A,0x5A,0x4A,0xB7,0x89,0xB6,0xE7,0x88,0xD0,0x0E,0x77,0x2D,0x22, - 0x30,0x81,0xCF,0x06,0x03,0x55,0x1D,0x1F,0x04,0x81,0xC7,0x30,0x81,0xC4,0x30,0x81, - 0xC1,0xA0,0x81,0xBE,0xA0,0x81,0xBB,0x86,0x57,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, - 0x77,0x77,0x77,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65, - 0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x43,0x52,0x4C,0x2F,0x49,0x6E,0x74, - 0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30, - 0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x25, - 0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x33,0x42,0x28,0x32,0x29,0x2E,0x63,0x72,0x6C, - 0x86,0x60,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69, - 0x63,0x61,0x74,0x65,0x73,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F, - 0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x43,0x52,0x4C,0x2F,0x49, - 0x6E,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25, - 0x32,0x30,0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x49,0x73,0x73,0x75,0x69,0x6E, - 0x67,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x33,0x42,0x28,0x32,0x29,0x2E,0x63, - 0x72,0x6C,0x30,0x82,0x01,0x1B,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01, - 0x04,0x82,0x01,0x0D,0x30,0x82,0x01,0x09,0x30,0x6C,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x30,0x02,0x86,0x60,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77, - 0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73, - 0x69,0x74,0x6F,0x72,0x79,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74, - 0x65,0x73,0x2F,0x49,0x6E,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72, - 0x6E,0x61,0x6C,0x25,0x32,0x30,0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x49,0x73, - 0x73,0x75,0x69,0x6E,0x67,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x33,0x42,0x28, - 0x32,0x29,0x2E,0x63,0x72,0x74,0x30,0x75,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07, - 0x30,0x02,0x86,0x69,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69, - 0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x63,0x65,0x72, - 0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2F,0x49,0x6E,0x74,0x65,0x6C,0x25, - 0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42,0x61,0x73, - 0x69,0x63,0x25,0x32,0x30,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x25,0x32,0x30,0x43, - 0x41,0x25,0x32,0x30,0x33,0x42,0x28,0x32,0x29,0x2E,0x63,0x72,0x74,0x30,0x22,0x06, - 0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x16,0x68,0x74,0x74,0x70,0x3A, - 0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D, - 0x2F,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,0x27,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x0A,0x04,0x1A,0x30, - 0x18,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x0A,0x06, - 0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x7E,0x06,0x03,0x55,0x1D,0x11, - 0x04,0x77,0x30,0x75,0x82,0x11,0x63,0x6F,0x6E,0x74,0x61,0x63,0x74,0x2E,0x69,0x6E, - 0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x82,0x17,0x6D,0x79,0x70,0x68,0x6F,0x6E,0x65, - 0x61,0x74,0x77,0x6F,0x72,0x6B,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D, - 0x82,0x11,0x6D,0x69,0x61,0x64,0x6D,0x69,0x6E,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E, - 0x63,0x6F,0x6D,0x82,0x19,0x66,0x6D,0x73,0x76,0x73,0x70,0x70,0x72,0x6F,0x64,0x30, - 0x32,0x2E,0x66,0x6D,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x82,0x19, - 0x6A,0x66,0x73,0x76,0x73,0x70,0x70,0x72,0x6F,0x64,0x30,0x32,0x2E,0x6A,0x66,0x2E, - 0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x51,0xB1,0x05, - 0xDD,0xB7,0x55,0x8B,0xAC,0x41,0x7C,0x45,0x05,0x31,0x74,0x08,0x74,0x79,0xB3,0xD3, - 0x2C,0x61,0x82,0xAF,0x3E,0x73,0x44,0x6F,0xFD,0xF1,0x3C,0xEF,0x5C,0xC4,0xCF,0xA3, - 0x8D,0xEB,0x17,0x1F,0x04,0x66,0x41,0xF0,0x1C,0x4E,0x6D,0xEA,0x67,0xC7,0xFC,0x4E, - 0x36,0x68,0xC8,0x17,0xE5,0x8E,0x34,0xE5,0x09,0x4E,0x3E,0x43,0xA8,0xF7,0x4B,0x84, - 0xD7,0x10,0x0E,0x65,0x7B,0xB0,0x07,0xED,0xA1,0x0F,0x73,0x31,0x29,0xDB,0x88,0xFA, - 0xD6,0x87,0x51,0x7A,0x37,0xD9,0x64,0x60,0x25,0xB9,0x0F,0x49,0x0E,0xF7,0xC4,0x10, - 0x61,0xE1,0x47,0x41,0x13,0xEC,0x7D,0xE9,0xBB,0x69,0x51,0x27,0xDC,0x2B,0xAC,0x23, - 0x9A,0x00,0x44,0xE3,0xE8,0x22,0x38,0x06,0xA3,0x53,0x2F,0x8F,0x2D,0x0B,0x70,0xE2, - 0x79,0xC1,0x62,0x12,0xB7,0x89,0xE1,0x05,0x4E,0xA3,0xDF,0x84,0x39,0x29,0xD1,0xBB, - 0x70,0x22,0xA5,0x5A,0xB2,0x8B,0x5D,0xA4,0x95,0x5A,0x7E,0x7A,0xFB,0x36,0xFC,0x6A, - 0xC8,0x29,0xE0,0x7E,0x77,0x1E,0xE6,0x63,0x31,0x09,0x7D,0x42,0x94,0xF4,0xF4,0x6B, - 0x92,0x36,0xF6,0x5B,0x38,0x31,0xC8,0x65,0x35,0xEA,0xE6,0x5E,0x45,0xBC,0x7E,0xF8, - 0x6D,0xF4,0x8C,0x01,0xC2,0xAC,0xAF,0xAD,0xAC,0x56,0xCA,0x08,0x23,0xBB,0x06,0x0B, - 0xD1,0xC9,0xC9,0x8A,0x2C,0x49,0xDD,0xE6,0x34,0xF2,0xB9,0x0F,0x24,0x3F,0x26,0x7B, - 0xFC,0xA4,0xE2,0x86,0xFC,0xE1,0x83,0x35,0x1E,0xB2,0xCD,0xA4,0x01,0xFE,0x14,0xFE, - 0xC1,0x90,0xEF,0x87,0xD3,0x9F,0xB2,0xFC,0x9A,0xDA,0xEB,0x6A,0x6C, -}; - -/* subject:/C=US/ST=CA/L=Santa Clara/O=Intel Corporation/CN=Intel External Basic Issuing CA 3B */ -/* issuer :/C=US/O=Intel Corporation/CN=Intel External Basic Policy CA */ -unsigned char intel2_intermediate1[1725]={ - 0x30,0x82,0x06,0xB9,0x30,0x82,0x05,0xA1,0xA0,0x03,0x02,0x01,0x02,0x02,0x0A,0x61, - 0x2C,0xFF,0x88,0x00,0x01,0x00,0x00,0x00,0x10,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x52,0x31,0x0B,0x30,0x09,0x06,0x03, - 0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A, - 0x13,0x11,0x49,0x6E,0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74, - 0x69,0x6F,0x6E,0x31,0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x03,0x13,0x1E,0x49,0x6E, - 0x74,0x65,0x6C,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x42,0x61,0x73, - 0x69,0x63,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D, - 0x31,0x33,0x30,0x32,0x30,0x38,0x32,0x32,0x32,0x31,0x32,0x33,0x5A,0x17,0x0D,0x31, - 0x38,0x30,0x32,0x30,0x38,0x32,0x32,0x33,0x31,0x32,0x33,0x5A,0x30,0x79,0x31,0x0B, - 0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04, - 0x07,0x13,0x0B,0x53,0x61,0x6E,0x74,0x61,0x20,0x43,0x6C,0x61,0x72,0x61,0x31,0x1A, - 0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x49,0x6E,0x74,0x65,0x6C,0x20,0x43, - 0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x2B,0x30,0x29,0x06,0x03, - 0x55,0x04,0x03,0x13,0x22,0x49,0x6E,0x74,0x65,0x6C,0x20,0x45,0x78,0x74,0x65,0x72, - 0x6E,0x61,0x6C,0x20,0x42,0x61,0x73,0x69,0x63,0x20,0x49,0x73,0x73,0x75,0x69,0x6E, - 0x67,0x20,0x43,0x41,0x20,0x33,0x42,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,0x00,0x93,0xAE,0xF2,0xCA,0x6C,0xA6, - 0x4D,0xCC,0x48,0xBF,0x4A,0x23,0xFC,0x2A,0x9B,0xC8,0x6E,0xED,0x0B,0x83,0x07,0xB1, - 0x3C,0x67,0x39,0x75,0x62,0x80,0x6D,0x10,0xD1,0xA8,0xF0,0xD6,0xA7,0x33,0xA0,0x98, - 0xD8,0x85,0xFA,0x85,0xCF,0x0A,0xEB,0xC9,0xF5,0xBD,0x9B,0x0B,0xB4,0xF7,0xB8,0xB3, - 0xC1,0x64,0xE3,0x9F,0x60,0x3F,0xD0,0x4B,0x2D,0x9C,0x3F,0xBB,0x3E,0x1F,0xD6,0x8B, - 0x8A,0x68,0xA8,0x93,0x71,0xFE,0x30,0xD2,0xE5,0x97,0xAC,0xEF,0x20,0x86,0x15,0xEA, - 0xB1,0xF7,0x6E,0x43,0x7F,0x6D,0xF3,0x00,0x9E,0x73,0xA7,0xD7,0xA1,0xD4,0xA3,0x58, - 0xDB,0x6D,0x61,0xC2,0xBE,0x51,0x6A,0xA3,0x24,0xFA,0x6F,0x80,0x27,0x32,0xA0,0x12, - 0xD8,0x7C,0x9C,0xF6,0x46,0x58,0xB6,0xC8,0x1D,0x61,0x6A,0x05,0xAA,0x85,0xF7,0x28, - 0xE1,0x08,0x29,0xCB,0x02,0xA4,0xDF,0x73,0x76,0x2A,0xFB,0x1D,0xAE,0x98,0xBF,0xEB, - 0xD8,0x7F,0x09,0x1A,0x62,0x3B,0xBF,0xB1,0x0E,0x06,0xCB,0x8C,0x8C,0xE2,0xEA,0xCC, - 0x45,0x81,0xB2,0x95,0xE3,0xFA,0x87,0xF4,0xA8,0x17,0xEA,0xEC,0xBF,0x08,0x0F,0x7F, - 0xB1,0x40,0x0F,0x4F,0x7B,0xBC,0xE9,0xB6,0xAA,0x33,0xE2,0x64,0xC6,0x43,0x6F,0x12, - 0xAE,0x18,0xA9,0x72,0x04,0x1A,0xE5,0x26,0x10,0x13,0xF7,0xE1,0x2B,0x51,0x50,0xB0, - 0x16,0x9C,0x52,0x19,0x16,0x0A,0x24,0x0A,0x06,0xBB,0x26,0xDD,0xF0,0x1A,0xD3,0x1D, - 0x5E,0x31,0xAC,0xE0,0xC4,0xE7,0x2A,0xB3,0xFB,0x18,0x9F,0xCA,0xD3,0x05,0xC7,0x9D, - 0xDD,0x6F,0x6A,0x69,0xA9,0xB2,0x7E,0x85,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x03, - 0x68,0x30,0x82,0x03,0x64,0x30,0x12,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37, - 0x15,0x01,0x04,0x05,0x02,0x03,0x02,0x00,0x02,0x30,0x23,0x06,0x09,0x2B,0x06,0x01, - 0x04,0x01,0x82,0x37,0x15,0x02,0x04,0x16,0x04,0x14,0x06,0x65,0x8B,0xA6,0x92,0xAB, - 0x43,0xBC,0x42,0x5A,0x90,0x2D,0xF5,0xCB,0x91,0x68,0x96,0x06,0x79,0xCF,0x30,0x1D, - 0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xE5,0x9C,0x00,0xAE,0x43,0x00,0xBD, - 0x1A,0x5A,0x4A,0xB7,0x89,0xB6,0xE7,0x88,0xD0,0x0E,0x77,0x2D,0x22,0x30,0x81,0xFA, - 0x06,0x03,0x55,0x1D,0x20,0x04,0x81,0xF2,0x30,0x81,0xEF,0x30,0x81,0xEC,0x06,0x0A, - 0x2A,0x86,0x48,0x86,0xF8,0x4D,0x01,0x05,0x01,0x69,0x30,0x81,0xDD,0x30,0x81,0x9C, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02,0x30,0x81,0x8F,0x1E,0x81,0x8C, - 0x00,0x49,0x00,0x6E,0x00,0x74,0x00,0x65,0x00,0x6C,0x00,0x20,0x00,0x43,0x00,0x6F, - 0x00,0x72,0x00,0x70,0x00,0x6F,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x69,0x00,0x6F, - 0x00,0x6E,0x00,0x20,0x00,0x45,0x00,0x78,0x00,0x74,0x00,0x65,0x00,0x72,0x00,0x6E, - 0x00,0x61,0x00,0x6C,0x00,0x20,0x00,0x42,0x00,0x61,0x00,0x73,0x00,0x69,0x00,0x63, - 0x00,0x20,0x00,0x50,0x00,0x6F,0x00,0x6C,0x00,0x69,0x00,0x63,0x00,0x79,0x00,0x20, - 0x00,0x43,0x00,0x65,0x00,0x72,0x00,0x74,0x00,0x69,0x00,0x66,0x00,0x69,0x00,0x63, - 0x00,0x61,0x00,0x74,0x00,0x65,0x00,0x20,0x00,0x50,0x00,0x72,0x00,0x61,0x00,0x63, - 0x00,0x74,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x61, - 0x00,0x74,0x00,0x65,0x00,0x6D,0x00,0x65,0x00,0x6E,0x00,0x74,0x30,0x3C,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x30,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x77,0x77,0x77,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x72, - 0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x70,0x6B,0x69,0x63,0x70,0x73, - 0x2F,0x69,0x6E,0x64,0x65,0x78,0x2E,0x68,0x74,0x6D,0x30,0x19,0x06,0x09,0x2B,0x06, - 0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x04,0x0C,0x1E,0x0A,0x00,0x53,0x00,0x75,0x00, - 0x62,0x00,0x43,0x00,0x41,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02, - 0x01,0x86,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06, - 0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30, - 0x16,0x80,0x14,0x56,0x3A,0x6F,0x17,0xAB,0x24,0x0C,0xE5,0xB7,0x31,0x64,0xB0,0x11, - 0xED,0xDB,0xEA,0x23,0xBE,0x5E,0xBC,0x30,0x81,0xC3,0x06,0x03,0x55,0x1D,0x1F,0x04, - 0x81,0xBB,0x30,0x81,0xB8,0x30,0x81,0xB5,0xA0,0x81,0xB2,0xA0,0x81,0xAF,0x86,0x51, - 0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x69,0x6E,0x74,0x65,0x6C, - 0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F, - 0x43,0x52,0x4C,0x2F,0x49,0x6E,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65, - 0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x50, - 0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30,0x43,0x41,0x28,0x31,0x29,0x2E,0x63,0x72, - 0x6C,0x86,0x5A,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69,0x66, - 0x69,0x63,0x61,0x74,0x65,0x73,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D, - 0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x43,0x52,0x4C,0x2F, - 0x49,0x6E,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C, - 0x25,0x32,0x30,0x42,0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x50,0x6F,0x6C,0x69,0x63, - 0x79,0x25,0x32,0x30,0x43,0x41,0x28,0x31,0x29,0x2E,0x63,0x72,0x6C,0x30,0x81,0xE9, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x81,0xDC,0x30,0x81,0xD9, - 0x30,0x66,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x5A,0x68,0x74, - 0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63, - 0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x63,0x65, - 0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2F,0x49,0x6E,0x74,0x65,0x6C, - 0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42,0x61, - 0x73,0x69,0x63,0x25,0x32,0x30,0x50,0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30,0x43, - 0x41,0x28,0x31,0x29,0x2E,0x63,0x72,0x74,0x30,0x6F,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x30,0x02,0x86,0x63,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72, - 0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2E,0x69,0x6E,0x74,0x65,0x6C,0x2E, - 0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69,0x74,0x6F,0x72,0x79,0x2F,0x63, - 0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x73,0x2F,0x49,0x6E,0x74,0x65, - 0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x42, - 0x61,0x73,0x69,0x63,0x25,0x32,0x30,0x50,0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30, - 0x43,0x41,0x28,0x31,0x29,0x2E,0x63,0x72,0x74,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x47,0xBB,0x93, - 0xE6,0x03,0xB1,0xD9,0x57,0x0E,0xFF,0x60,0xE9,0x0F,0xC7,0x5E,0x86,0xE6,0x23,0xF7, - 0xDE,0xFA,0x6D,0xC2,0x77,0x32,0xEF,0x23,0xF6,0x8F,0xCC,0x6F,0x25,0x72,0xD4,0xA9, - 0x4B,0xAD,0x11,0xA2,0x73,0xBB,0x8B,0xD2,0xB7,0xB8,0x87,0x94,0x74,0x89,0x0C,0xCC, - 0x5C,0xEA,0x3A,0x9A,0xC0,0x75,0x3A,0x97,0x59,0x7C,0x22,0x00,0x3D,0x7A,0xC7,0xC5, - 0x5B,0xE8,0xD4,0x93,0x13,0xEC,0x8F,0x94,0xCD,0xA8,0x33,0xDF,0xA4,0xD7,0x9A,0xA1, - 0xC8,0xD8,0xA3,0xB4,0x49,0x7E,0x17,0x3A,0x02,0xE9,0x66,0x56,0x97,0x8D,0x16,0xB4, - 0x70,0xAB,0xBC,0x6B,0x10,0x48,0xE7,0x45,0x7B,0x13,0xC7,0x4D,0x05,0xBC,0xA0,0x2C, - 0x05,0x16,0xBE,0x06,0x7E,0xF6,0x79,0x67,0x8F,0x9C,0x34,0x54,0xE6,0x7E,0xEA,0x19, - 0x77,0x14,0xF1,0x9D,0x3B,0x55,0xE4,0x33,0x9F,0x69,0xBB,0xA7,0xA7,0x22,0x54,0x51, - 0x2C,0x67,0x7D,0x04,0x52,0xAA,0x7B,0x66,0xDE,0xA9,0x6A,0xAD,0x8C,0xA1,0x5C,0x79, - 0x39,0xCD,0x1C,0x85,0xEC,0x89,0x06,0x99,0x85,0x46,0x27,0xA0,0x01,0x57,0x6E,0x93, - 0x36,0x51,0x45,0xE1,0x5A,0x3A,0x59,0xAF,0x5B,0x41,0xF9,0x70,0x9D,0xC4,0x16,0x0E, - 0x05,0xE7,0x95,0xB4,0x01,0xB4,0x93,0x1A,0x59,0x0B,0x8A,0x31,0xF7,0xB6,0x48,0xC8, - 0x6A,0xF6,0x22,0x8C,0x9E,0x92,0x28,0x6F,0xA8,0x93,0xB4,0xA7,0x72,0x53,0x3A,0xDA, - 0x2C,0xFA,0xD4,0x3D,0xBF,0x09,0x23,0x7F,0xDF,0xCC,0x65,0x2A,0xD0,0x91,0xAA,0x50, - 0x31,0xC8,0x65,0xF5,0x38,0x58,0xD4,0xB3,0x9B,0xE6,0x31,0x10,0x08, -}; - -/* subject:/C=US/O=Intel Corporation/CN=Intel External Basic Policy CA */ -/* issuer :/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */ -unsigned char intel_intermediate2[2397]={ - 0x30,0x82,0x09,0x59,0x30,0x82,0x08,0x41,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x79, - 0x17,0x4A,0xA9,0x14,0x17,0x36,0xFE,0x15,0xA7,0xCA,0x9F,0x2C,0xFF,0x45,0x88,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,0x31,0x33,0x30,0x32,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5A, - 0x17,0x0D,0x32,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38,0x5A,0x30, - 0x52,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1A, - 0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x49,0x6E,0x74,0x65,0x6C,0x20,0x43, - 0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x27,0x30,0x25,0x06,0x03, - 0x55,0x04,0x03,0x13,0x1E,0x49,0x6E,0x74,0x65,0x6C,0x20,0x45,0x78,0x74,0x65,0x72, - 0x6E,0x61,0x6C,0x20,0x42,0x61,0x73,0x69,0x63,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79, - 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,0xC2,0xB8,0x84,0x95,0x42,0x2D,0xDC,0xB0,0xAA,0x98,0x93,0x9B, - 0xB3,0xEC,0x83,0xA1,0x63,0xC3,0x17,0x92,0x2A,0x81,0x69,0x3A,0x9A,0x82,0x28,0x6D, - 0x88,0xCF,0x7D,0xEC,0x6D,0x66,0x26,0x14,0xE8,0x8D,0xC4,0x7E,0xF0,0x30,0xA0,0xDC, - 0x4F,0x0E,0x43,0x76,0x5A,0x8C,0x1C,0xA1,0xC5,0x19,0x30,0x96,0xC4,0x78,0x4A,0xB9, - 0x79,0xB0,0x64,0xB0,0x59,0xF1,0x7F,0x5D,0xA0,0x07,0x19,0x48,0x56,0x22,0x18,0xC1, - 0x90,0x33,0xBB,0xB6,0x85,0xBE,0x10,0xCC,0xC8,0xF2,0x90,0x23,0x70,0xBC,0x08,0x6D, - 0x19,0x48,0x2F,0x40,0x05,0x9D,0x44,0xDE,0xE9,0x9D,0x03,0x70,0x84,0xB9,0xE3,0x4E, - 0x98,0xFF,0xD3,0x0A,0x13,0x6A,0x0A,0x5D,0xB7,0xF8,0x11,0xB5,0x41,0xBF,0xCF,0x26, - 0x4A,0x40,0x3B,0xE1,0x9F,0xA5,0x64,0x95,0x85,0x37,0x15,0xE7,0x73,0x1F,0xFD,0xC2, - 0xAF,0x14,0x77,0x23,0x18,0xDA,0xF1,0xCD,0xD4,0xA8,0xAB,0xD7,0xF2,0x5B,0xB6,0xBA, - 0x81,0xF7,0x06,0x11,0x06,0x34,0x2D,0x59,0x26,0xC0,0x55,0x94,0x7C,0x9D,0x30,0x4F, - 0xC9,0x1A,0x78,0xBA,0xF4,0x13,0x4B,0x68,0xCE,0x42,0x1F,0xA3,0x4D,0x4A,0x35,0x63, - 0x73,0xBF,0xA3,0x5C,0x60,0xFF,0x34,0x40,0xE0,0x51,0x0E,0x50,0x29,0x5A,0xEF,0x4E, - 0x0E,0x61,0x15,0x24,0x73,0xC3,0x6E,0x5C,0x78,0x8F,0x34,0xD0,0xDC,0x92,0xDA,0xFB, - 0x80,0xEF,0x04,0xD3,0xA3,0x55,0x43,0xA9,0xFA,0x68,0x11,0x9A,0x38,0x96,0xD2,0xB2, - 0xDD,0xAF,0x1C,0x0E,0xC4,0x8A,0x88,0x3B,0x03,0x63,0xC1,0xE3,0x02,0xA7,0xF8,0x60, - 0xC5,0x7F,0xE1,0x4D,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x06,0x0C,0x30,0x82,0x06, - 0x08,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xAD,0xBD, - 0x98,0x7A,0x34,0xB4,0x26,0xF7,0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB, - 0x54,0x1A,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x56,0x3A,0x6F, - 0x17,0xAB,0x24,0x0C,0xE5,0xB7,0x31,0x64,0xB0,0x11,0xED,0xDB,0xEA,0x23,0xBE,0x5E, - 0xBC,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01, - 0x86,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01, - 0x01,0xFF,0x02,0x01,0x01,0x30,0x5E,0x06,0x03,0x55,0x1D,0x25,0x04,0x57,0x30,0x55, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x03,0x02,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x03,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x04,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07, - 0x03,0x08,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x04,0x06,0x0A, - 0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x0C,0x06,0x09,0x2B,0x06,0x01,0x04, - 0x01,0x82,0x37,0x15,0x05,0x30,0x17,0x06,0x03,0x55,0x1D,0x20,0x04,0x10,0x30,0x0E, - 0x30,0x0C,0x06,0x0A,0x2A,0x86,0x48,0x86,0xF8,0x4D,0x01,0x05,0x01,0x69,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,0x2E,0x74,0x72,0x75,0x73, - 0x74,0x2D,0x70,0x72,0x6F,0x76,0x69,0x64,0x65,0x72,0x2E,0x63,0x6F,0x6D,0x2F,0x41, - 0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x43, - 0x41,0x52,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C,0x30,0x81,0xC2,0x06,0x08,0x2B,0x06, - 0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x81,0xB5,0x30,0x81,0xB2,0x30,0x44,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x38,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x63,0x72,0x74,0x2E,0x74,0x72,0x75,0x73,0x74,0x2D,0x70,0x72,0x6F,0x76,0x69, - 0x64,0x65,0x72,0x2E,0x63,0x6F,0x6D,0x2F,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74, - 0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x43,0x41,0x52,0x6F,0x6F,0x74,0x2E,0x70, - 0x37,0x63,0x30,0x3E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x32, - 0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x74,0x2E,0x74,0x72,0x75,0x73,0x74, - 0x2D,0x70,0x72,0x6F,0x76,0x69,0x64,0x65,0x72,0x2E,0x63,0x6F,0x6D,0x2F,0x41,0x64, - 0x64,0x54,0x72,0x75,0x73,0x74,0x55,0x54,0x4E,0x53,0x47,0x43,0x43,0x41,0x2E,0x63, - 0x72,0x74,0x30,0x2A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x1E, - 0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x74,0x72,0x75,0x73, - 0x74,0x2D,0x70,0x72,0x6F,0x76,0x69,0x64,0x65,0x72,0x2E,0x63,0x6F,0x6D,0x30,0x82, - 0x04,0x17,0x06,0x03,0x55,0x1D,0x1E,0x04,0x82,0x04,0x0E,0x30,0x82,0x04,0x0A,0xA0, - 0x82,0x03,0xD4,0x30,0x0B,0x81,0x09,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D, - 0x30,0x0B,0x82,0x09,0x61,0x70,0x70,0x75,0x70,0x2E,0x63,0x6F,0x6D,0x30,0x0E,0x82, - 0x0C,0x63,0x6C,0x6F,0x75,0x64,0x6E,0x70,0x6F,0x2E,0x6F,0x72,0x67,0x30,0x13,0x82, - 0x11,0x65,0x64,0x61,0x63,0x61,0x64,0x74,0x6F,0x6F,0x6C,0x6B,0x69,0x74,0x2E,0x6F, - 0x72,0x67,0x30,0x0B,0x82,0x09,0x66,0x74,0x6C,0x31,0x30,0x2E,0x63,0x6F,0x6D,0x30, - 0x0B,0x82,0x09,0x69,0x68,0x63,0x6D,0x73,0x2E,0x6E,0x65,0x74,0x30,0x0E,0x82,0x0C, - 0x69,0x6E,0x63,0x2D,0x6E,0x65,0x73,0x74,0x2E,0x6E,0x65,0x74,0x30,0x16,0x82,0x14, - 0x69,0x6E,0x64,0x69,0x61,0x65,0x64,0x75,0x73,0x65,0x72,0x76,0x69,0x63,0x65,0x73, - 0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x82,0x0B,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x2E,0x6A,0x70,0x30,0x0D,0x82,0x0B,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x2E, - 0x6B,0x72,0x30,0x0D,0x82,0x0B,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x2E,0x75, - 0x6B,0x30,0x0B,0x82,0x09,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0A, - 0x82,0x08,0x69,0x6E,0x74,0x65,0x6C,0x2E,0x66,0x72,0x30,0x0B,0x82,0x09,0x69,0x6E, - 0x74,0x65,0x6C,0x2E,0x6E,0x65,0x74,0x30,0x13,0x82,0x11,0x69,0x6E,0x74,0x65,0x6C, - 0x61,0x6C,0x6C,0x69,0x61,0x6E,0x63,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12, - 0x69,0x6E,0x74,0x65,0x6C,0x61,0x70,0x61,0x63,0x73,0x74,0x6F,0x72,0x65,0x2E,0x63, - 0x6F,0x6D,0x30,0x16,0x82,0x14,0x69,0x6E,0x74,0x65,0x6C,0x61,0x73,0x73,0x65,0x74, - 0x66,0x69,0x6E,0x64,0x65,0x72,0x2E,0x63,0x6F,0x6D,0x30,0x19,0x82,0x17,0x69,0x6E, - 0x74,0x65,0x6C,0x62,0x65,0x74,0x74,0x65,0x72,0x74,0x6F,0x67,0x65,0x74,0x68,0x65, - 0x72,0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12,0x69,0x6E,0x74,0x65,0x6C,0x63,0x68, - 0x61,0x6C,0x6C,0x65,0x6E,0x67,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x13,0x82,0x11,0x69, - 0x6E,0x74,0x65,0x6C,0x63,0x6C,0x6F,0x75,0x64,0x73,0x73,0x6F,0x2E,0x63,0x6F,0x6D, - 0x30,0x1E,0x82,0x1C,0x69,0x6E,0x74,0x65,0x6C,0x63,0x6F,0x6E,0x73,0x75,0x6D,0x65, - 0x72,0x65,0x6C,0x65,0x63,0x74,0x72,0x6F,0x6E,0x69,0x63,0x73,0x2E,0x63,0x6F,0x6D, - 0x30,0x12,0x82,0x10,0x69,0x6E,0x74,0x65,0x6C,0x63,0x6F,0x72,0x65,0x32,0x30,0x31, - 0x30,0x2E,0x72,0x75,0x30,0x16,0x82,0x14,0x69,0x6E,0x74,0x65,0x6C,0x66,0x65,0x6C, - 0x6C,0x6F,0x77,0x73,0x68,0x69,0x70,0x73,0x2E,0x63,0x6F,0x6D,0x30,0x16,0x82,0x14, - 0x69,0x6E,0x74,0x65,0x6C,0x68,0x79,0x62,0x72,0x69,0x64,0x63,0x6C,0x6F,0x75,0x64, - 0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12,0x69,0x6E,0x74,0x65,0x6C,0x70,0x6F,0x72, - 0x74,0x66,0x6F,0x6C,0x69,0x6F,0x2E,0x63,0x6F,0x6D,0x30,0x0E,0x82,0x0C,0x69,0x6E, - 0x74,0x65,0x6C,0x2D,0x72,0x61,0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12,0x69,0x6E, - 0x74,0x65,0x6C,0x2D,0x72,0x65,0x73,0x65,0x61,0x72,0x63,0x68,0x2E,0x6E,0x65,0x74, - 0x30,0x14,0x82,0x12,0x69,0x6E,0x74,0x65,0x6C,0x72,0x6D,0x61,0x73,0x75,0x72,0x76, - 0x65,0x79,0x2E,0x63,0x6F,0x6D,0x30,0x18,0x82,0x16,0x69,0x6E,0x74,0x65,0x6C,0x73, - 0x6D,0x61,0x6C,0x6C,0x62,0x75,0x73,0x69,0x6E,0x65,0x73,0x73,0x2E,0x63,0x6F,0x6D, - 0x30,0x11,0x82,0x0F,0x6D,0x79,0x69,0x6E,0x74,0x65,0x6C,0x65,0x64,0x67,0x65,0x2E, - 0x63,0x6F,0x6D,0x30,0x11,0x82,0x0F,0x6D,0x79,0x2D,0x6C,0x61,0x70,0x74,0x6F,0x70, - 0x2E,0x63,0x6F,0x2E,0x75,0x6B,0x30,0x12,0x82,0x10,0x6F,0x72,0x69,0x67,0x69,0x6E, - 0x2D,0x61,0x70,0x70,0x75,0x70,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x82,0x1C,0x6F,0x72, - 0x69,0x67,0x69,0x6E,0x2D,0x69,0x6E,0x74,0x65,0x67,0x72,0x61,0x74,0x69,0x6F,0x6E, - 0x2D,0x61,0x70,0x70,0x75,0x70,0x2E,0x63,0x6F,0x6D,0x30,0x08,0x82,0x06,0x70,0x63, - 0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12,0x70,0x63,0x74,0x68,0x65,0x66,0x74,0x64, - 0x65,0x66,0x65,0x6E,0x63,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12,0x70,0x63, - 0x74,0x68,0x65,0x66,0x74,0x64,0x65,0x66,0x65,0x6E,0x73,0x65,0x2E,0x63,0x6F,0x6D, - 0x30,0x0E,0x82,0x0C,0x70,0x76,0x61,0x74,0x72,0x69,0x61,0x6C,0x2E,0x6E,0x65,0x74, - 0x30,0x19,0x82,0x17,0x72,0x65,0x64,0x65,0x66,0x69,0x6E,0x65,0x79,0x6F,0x75,0x72, - 0x6E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x2E,0x63,0x6F,0x6D,0x30,0x0F,0x82,0x0D,0x72, - 0x65,0x74,0x61,0x69,0x6C,0x2D,0x69,0x61,0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12, - 0x73,0x65,0x72,0x76,0x65,0x72,0x2D,0x69,0x6E,0x73,0x69,0x67,0x68,0x74,0x2E,0x63, - 0x6F,0x6D,0x30,0x13,0x82,0x11,0x74,0x68,0x65,0x69,0x6E,0x74,0x65,0x6C,0x73,0x74, - 0x6F,0x72,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x82,0x1B,0x74,0x68,0x72,0x65,0x61, - 0x64,0x69,0x6E,0x67,0x62,0x75,0x69,0x6C,0x64,0x69,0x6E,0x67,0x62,0x6C,0x6F,0x63, - 0x6B,0x73,0x2E,0x6F,0x72,0x67,0x30,0x1B,0x82,0x19,0x74,0x68,0x75,0x6E,0x64,0x65, - 0x72,0x62,0x6F,0x6C,0x74,0x74,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x79,0x2E, - 0x6E,0x65,0x74,0x30,0x20,0x82,0x1E,0x75,0x6C,0x74,0x72,0x61,0x62,0x6F,0x6F,0x6B, - 0x2D,0x73,0x6F,0x66,0x74,0x77,0x61,0x72,0x65,0x2D,0x63,0x6F,0x6E,0x74,0x65,0x73, - 0x74,0x2E,0x63,0x6F,0x6D,0x30,0x50,0xA4,0x4E,0x30,0x4C,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, - 0x08,0x13,0x02,0x43,0x41,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x07,0x13,0x0B, - 0x53,0x61,0x6E,0x74,0x61,0x20,0x43,0x6C,0x61,0x72,0x61,0x31,0x1A,0x30,0x18,0x06, - 0x03,0x55,0x04,0x0A,0x13,0x11,0x49,0x6E,0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70, - 0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0xA1,0x30,0x30,0x0A,0x87,0x08,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x30,0x22,0x87,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x58,0x6F,0xBF, - 0xCD,0x43,0x07,0x42,0x13,0xFC,0xB8,0xD0,0xAD,0x81,0x21,0xF2,0x8A,0x6F,0xEF,0x87, - 0xBC,0x26,0x8A,0x7C,0x00,0xBD,0x68,0x0C,0x2B,0x19,0x64,0x2C,0x11,0x67,0xB3,0xA9, - 0xD9,0x79,0x0A,0xAC,0x39,0x5D,0x65,0x00,0x16,0x3B,0x53,0x46,0x6E,0xA2,0xA6,0xB5, - 0x67,0x99,0xDB,0xE8,0xBF,0xA2,0x25,0xAE,0x04,0x95,0x11,0x09,0x3A,0x2F,0xDE,0xAC, - 0xB7,0x3D,0xB8,0xBC,0x01,0x74,0x30,0x80,0x47,0x48,0x54,0x4C,0xA0,0xFB,0x6B,0xA8, - 0xB8,0xA2,0x84,0xB7,0xF4,0x34,0xE5,0x7B,0xCE,0xDC,0x52,0x78,0xF4,0x31,0x6D,0x42, - 0x51,0xAE,0x87,0xBF,0x94,0xAC,0xBE,0x96,0x16,0xFB,0x55,0xE5,0x79,0x82,0x64,0xFD, - 0xAC,0x50,0x38,0xE4,0xDC,0xCB,0x81,0x2C,0xE7,0x77,0x6F,0x9D,0x9B,0x23,0x5C,0x7D, - 0x04,0x03,0xF4,0x07,0x9E,0x7E,0xD4,0x57,0xE2,0x66,0x94,0x4D,0xEB,0xB5,0x5C,0x5C, - 0x62,0x9E,0x8C,0x2D,0x83,0xE6,0x46,0x14,0xE2,0xA1,0x13,0x80,0xFD,0xDA,0xE0,0x86, - 0x27,0x11,0x92,0x2B,0xBD,0x87,0x17,0x4F,0xCB,0x19,0x18,0x4B,0x5E,0x8C,0xE6,0x0D, - 0xD9,0x8F,0x7D,0x23,0x76,0x6F,0xA4,0xFF,0xA0,0xBA,0x3D,0xE3,0x6D,0x37,0xD6,0x26, - 0x38,0xE8,0x1A,0x9C,0x23,0x92,0xC8,0x56,0x1F,0x1A,0x1A,0x8E,0x00,0xD6,0x33,0xA6, - 0x6B,0x95,0xFA,0x82,0x1E,0x74,0x0B,0x0F,0xA4,0x86,0xDF,0x23,0x33,0x7C,0x9E,0x36, - 0x14,0xB3,0x5C,0xE2,0xA3,0xED,0x48,0xA0,0x8E,0x28,0xF1,0xD7,0x4C,0xF6,0xC0,0x9B, - 0xB4,0xF5,0x3C,0xA3,0xE5,0xA8,0x63,0xA2,0x2C,0x08,0xA5,0xD5,0xFE, + 0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB8,0xC0,0x3A,0xC8, + 0xFE,0x81,0x3B,0x94,0xA0,0x76,0x1C,0x1C,0x3E,0x76,0x18,0x93,0xB6,0x79,0xD1,0x36, + 0x19,0x12,0xD0,0xB4,0xA6,0xCA,0xED,0xB0,0xFD,0x98,0x4A,0xCD,0xF0,0x1B,0x5B,0xE8, + 0xB6,0x82,0x2D,0x79,0x1C,0x33,0x40,0x87,0x5C,0xFE,0xEF,0xA6,0xBA,0xDF,0x9B,0x18, + 0xAB,0x38,0x9A,0x04,0xCF,0x85,0x75,0x4A,0xDD,0xA7,0x8D,0x12,0x8F,0x9A,0x27,0x67, + 0x67,0x58,0x59,0x85,0x9C,0x41,0x7C,0x0A,0xC0,0x68,0xC0,0x2E,0x18,0xD5,0xF2,0x93, + 0xED,0x43,0x88,0x20,0x29,0xA7,0x4B,0xC5,0x56,0x8A,0x6A,0xE4,0x57,0xC5,0x4D,0x33, + 0x08,0x8F,0x4C,0xDF,0x8E,0xD5,0x50,0xA7,0x41,0x1A,0xE3,0x07,0x01,0x08,0x63,0xD0, + 0xCC,0xD1,0x95,0x0C,0xAC,0xAA,0x7C,0xA1,0x49,0xCF,0xB2,0x1F,0x75,0xBF,0x75,0x00, + 0xD5,0x57,0xB2,0xE9,0xD6,0x86,0xEE,0x0C,0xF6,0x45,0xDD,0xFB,0x1F,0x42,0x2A,0x46, + 0xFB,0x8D,0xB9,0x88,0xD4,0x7B,0x12,0x59,0xFD,0x10,0x78,0xBA,0x9D,0xFA,0x7A,0x8C, + 0x24,0x9F,0xB0,0x52,0x71,0x28,0x39,0x51,0xE5,0x80,0xC4,0x22,0x82,0x0A,0x8B,0x46, + 0xF4,0xE1,0x9C,0x9F,0x7D,0x65,0x51,0xE3,0xF9,0x6B,0x12,0x4E,0xCF,0xEC,0xC2,0xD3, + 0xB0,0xB3,0xAC,0x46,0x86,0x25,0xB4,0x41,0x42,0x36,0xBC,0x8E,0xA5,0x3B,0x7C,0x90, + 0xBB,0x1C,0xC4,0x88,0xCB,0x0B,0x32,0x67,0xDA,0x5B,0x96,0xC1,0x95,0x55,0xFF,0x65, + 0xE2,0xAD,0x48,0xE7,0xE8,0xC8,0xBC,0x57,0x5F,0xDA,0x91,0x84,0x68,0x9A,0xEB,0xE7, + 0xC0,0xE7,0x5F,0xDB,0xA6,0x7F,0xAB,0x25,0x80,0xA7,0x71,0x8B,0x02,0x03,0x01,0x00, + 0x01,0xA3,0x82,0x01,0x1C,0x30,0x82,0x01,0x18,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,0x43,0xD7,0xC9,0x6E,0x6E,0x28,0x69,0x32,0xB9,0xB7,0x4F, + 0x36,0x5A,0xD3,0x51,0x80,0x23,0x41,0x9A,0x01,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23, + 0x04,0x18,0x30,0x16,0x80,0x14,0x1F,0x9D,0x00,0xFC,0x49,0x77,0x92,0x50,0xF6,0xC4, + 0xE1,0x6A,0x0D,0xC5,0xC6,0x9A,0xB0,0xFB,0xE5,0xF8,0x30,0x81,0xB4,0x06,0x03,0x55, + 0x1D,0x1E,0x04,0x81,0xAC,0x30,0x81,0xA9,0xA0,0x81,0x98,0x30,0x0B,0x82,0x09,0x61, + 0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x0C,0x82,0x0A,0x2E,0x61,0x70,0x70, + 0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x21,0xA4,0x1F,0x30,0x1D,0x31,0x0B,0x30,0x09, + 0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0E,0x30,0x0C,0x06,0x03,0x55, + 0x04,0x0A,0x0C,0x05,0x41,0x70,0x70,0x6C,0x65,0x30,0x26,0xA4,0x24,0x30,0x22,0x31, + 0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11, + 0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63, + 0x2E,0x30,0x30,0xA4,0x2E,0x30,0x2C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, + 0x13,0x02,0x55,0x53,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0A,0x0C,0x14,0x41, + 0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x6D,0x70,0x75,0x74,0x65,0x72,0x2C,0x20,0x49, + 0x6E,0x63,0x2E,0xA1,0x0C,0x30,0x0A,0x87,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00, + 0x03,0x82,0x02,0x01,0x00,0x57,0xD6,0xB0,0x88,0x26,0x27,0xBD,0x9B,0xA8,0xBF,0xB0, + 0x03,0xD8,0x9D,0x37,0x4D,0x35,0xF0,0x79,0xAF,0x58,0xDD,0x2D,0x50,0x5C,0x29,0x21, + 0xA9,0x91,0xB4,0xB4,0xD8,0x6E,0xDC,0xF5,0x00,0x9C,0xEA,0x51,0x3D,0x8A,0x57,0xA4, + 0x55,0x1E,0xD7,0xD3,0x0F,0xB5,0x4A,0x7B,0x13,0x20,0x2E,0x26,0x8E,0xB1,0x5D,0x61, + 0x1E,0xBE,0xCB,0x28,0xF4,0x8A,0x5F,0x8A,0xA7,0x75,0x12,0xD3,0x0D,0x18,0x88,0x1A, + 0x12,0x6A,0xB4,0x1D,0x6A,0x83,0xE1,0x3A,0xEA,0xBC,0x00,0x13,0x33,0x4A,0x7D,0x95, + 0x2F,0xE7,0x2B,0xCB,0x2D,0xFB,0xE0,0x47,0x04,0x0E,0xA5,0xB6,0x83,0xD3,0xA2,0x58, + 0x17,0x29,0x19,0xAB,0x75,0x7F,0xAC,0x59,0x2B,0xAC,0x37,0x99,0x84,0x8E,0xCC,0x5A, + 0x57,0x92,0x23,0xA9,0xAE,0xF9,0xA5,0xB0,0x82,0x3A,0x34,0x9D,0xAE,0xFA,0xF5,0x13, + 0xA8,0x51,0x86,0xCC,0x92,0x37,0xC3,0xE5,0x0B,0xD0,0xD0,0xE2,0xB5,0xA6,0x8D,0x96, + 0xA1,0x0E,0xA6,0xB2,0x04,0x72,0xE4,0xDE,0x3B,0x51,0xEF,0xF8,0xDB,0xC7,0x39,0xAF, + 0x1F,0x11,0xE6,0xC7,0x68,0x1B,0xC0,0xE5,0x4B,0xA1,0x7A,0x56,0x74,0x03,0x41,0xD6, + 0x8B,0x58,0x89,0x8F,0x90,0x49,0xDF,0xF5,0x35,0x36,0xBA,0xE1,0x01,0xAD,0xD2,0x52, + 0x05,0x51,0x7B,0x17,0x21,0x99,0x1B,0xC5,0xAD,0xA3,0xC3,0x0D,0x50,0x47,0xF1,0xE7, + 0x3E,0x15,0x8A,0x01,0xAF,0x3B,0xBB,0x52,0x8B,0x51,0x40,0x54,0x5B,0x8D,0x9D,0x58, + 0x09,0x62,0x11,0xB1,0x0C,0x16,0xF0,0xBA,0x9E,0x9A,0x5E,0xBF,0xB4,0x0E,0x4A,0x0D, + 0xE8,0x68,0x8B,0xC1,0x17,0x25,0x76,0x8C,0x7F,0xCD,0x3E,0x57,0x84,0x89,0x30,0xDE, + 0xAF,0xFD,0xA2,0x05,0xA8,0xDF,0x31,0x3C,0x89,0x63,0x88,0xD3,0x8F,0x51,0x63,0xA4, + 0x05,0xDE,0xE6,0x37,0xB9,0xC1,0xAD,0xE9,0x53,0x57,0x4E,0xA3,0x0C,0x47,0xFA,0x1A, + 0x75,0xE8,0x45,0x05,0xFF,0x92,0xA3,0x17,0xA8,0x97,0xF9,0x7F,0xAB,0xB1,0xA1,0x75, + 0xD2,0x66,0x97,0x47,0x84,0x2E,0x2D,0x42,0x58,0xE9,0xA6,0xA2,0x93,0xC7,0x7F,0x33, + 0x30,0x3A,0x8E,0x8E,0xED,0x66,0x58,0xEB,0xF0,0x1B,0xF0,0x1E,0x0E,0x41,0x9D,0x16, + 0xF6,0xC8,0x9B,0x01,0xBA,0x18,0xB7,0x7E,0x49,0xB7,0x76,0x2E,0xCF,0xFE,0xDB,0x7F, + 0x14,0x2B,0x46,0xA8,0xD7,0x71,0xA0,0xBB,0xD7,0xA4,0x15,0x72,0x09,0x99,0x48,0x20, + 0xB4,0xB7,0x11,0x31,0x2A,0xD0,0x00,0xE9,0xE2,0xCB,0xB9,0xFF,0x50,0xBB,0x5E,0xA8, + 0x09,0x8A,0xCD,0xEB,0x10,0x48,0xC8,0x4C,0xBD,0x98,0x19,0x29,0x45,0x89,0xC8,0x6C, + 0x1F,0x42,0x50,0xD0,0x41,0x00,0xFB,0x1E,0xD9,0xA2,0x9E,0x12,0x99,0x62,0x67,0x0E, + 0xF8,0x89,0xBE,0x9C,0x53,0x33,0x3F,0xD7,0x80,0x6B,0xF4,0x6E,0x7B,0x55,0x31,0x53, + 0x59,0xE1,0xD8,0x98,0x74,0x12,0x55,0x68,0x82,0xC2,0x71,0xC4,0x32,0x7E,0x19,0x6C, + 0x84,0x43,0x08,0x95,0x83,0x44,0x86,0xAE,0xBA,0x4F,0xDD,0xF0,0x4B,0xE0,0x4E,0x9D, + 0x66,0x91,0xE0,0xA6,0x2D,0xD5,0x31,0x34,0xA4,0x7B,0x68,0x87,0xCF,0xC7,0xC9,0x91, + 0x27,0xF9,0xE9,0xA4,0xF3,0xA9,0xBD,0x48,0x51,0xE6,0x4D,0x5E,0xD7,0x18,0x44,0x71, + 0x42,0x8F,0x2B,0xC4,0xCF, }; -/* 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 */ -unsigned char intel_root[1082]={ - 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, -}; - -/* subject:/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ -/* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ -unsigned char _ABBRootCA[891]={ - 0x30,0x82,0x03,0x77,0x30,0x82,0x02,0x5F,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x02, - 0x00,0x00,0xB9,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, - 0x05,0x00,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49, - 0x45,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74, - 0x69,0x6D,0x6F,0x72,0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A, - 0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03, - 0x55,0x04,0x03,0x13,0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43, - 0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E, - 0x17,0x0D,0x30,0x30,0x30,0x35,0x31,0x32,0x31,0x38,0x34,0x36,0x30,0x30,0x5A,0x17, - 0x0D,0x32,0x35,0x30,0x35,0x31,0x32,0x32,0x33,0x35,0x39,0x30,0x30,0x5A,0x30,0x5A, - 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x45,0x31,0x12,0x30, - 0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72, - 0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A,0x43,0x79,0x62,0x65, - 0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13, - 0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43,0x79,0x62,0x65,0x72, - 0x54,0x72,0x75,0x73,0x74,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,0xA3,0x04,0xBB,0x22,0xAB, - 0x98,0x3D,0x57,0xE8,0x26,0x72,0x9A,0xB5,0x79,0xD4,0x29,0xE2,0xE1,0xE8,0x95,0x80, - 0xB1,0xB0,0xE3,0x5B,0x8E,0x2B,0x29,0x9A,0x64,0xDF,0xA1,0x5D,0xED,0xB0,0x09,0x05, - 0x6D,0xDB,0x28,0x2E,0xCE,0x62,0xA2,0x62,0xFE,0xB4,0x88,0xDA,0x12,0xEB,0x38,0xEB, - 0x21,0x9D,0xC0,0x41,0x2B,0x01,0x52,0x7B,0x88,0x77,0xD3,0x1C,0x8F,0xC7,0xBA,0xB9, - 0x88,0xB5,0x6A,0x09,0xE7,0x73,0xE8,0x11,0x40,0xA7,0xD1,0xCC,0xCA,0x62,0x8D,0x2D, - 0xE5,0x8F,0x0B,0xA6,0x50,0xD2,0xA8,0x50,0xC3,0x28,0xEA,0xF5,0xAB,0x25,0x87,0x8A, - 0x9A,0x96,0x1C,0xA9,0x67,0xB8,0x3F,0x0C,0xD5,0xF7,0xF9,0x52,0x13,0x2F,0xC2,0x1B, - 0xD5,0x70,0x70,0xF0,0x8F,0xC0,0x12,0xCA,0x06,0xCB,0x9A,0xE1,0xD9,0xCA,0x33,0x7A, - 0x77,0xD6,0xF8,0xEC,0xB9,0xF1,0x68,0x44,0x42,0x48,0x13,0xD2,0xC0,0xC2,0xA4,0xAE, - 0x5E,0x60,0xFE,0xB6,0xA6,0x05,0xFC,0xB4,0xDD,0x07,0x59,0x02,0xD4,0x59,0x18,0x98, - 0x63,0xF5,0xA5,0x63,0xE0,0x90,0x0C,0x7D,0x5D,0xB2,0x06,0x7A,0xF3,0x85,0xEA,0xEB, - 0xD4,0x03,0xAE,0x5E,0x84,0x3E,0x5F,0xFF,0x15,0xED,0x69,0xBC,0xF9,0x39,0x36,0x72, - 0x75,0xCF,0x77,0x52,0x4D,0xF3,0xC9,0x90,0x2C,0xB9,0x3D,0xE5,0xC9,0x23,0x53,0x3F, - 0x1F,0x24,0x98,0x21,0x5C,0x07,0x99,0x29,0xBD,0xC6,0x3A,0xEC,0xE7,0x6E,0x86,0x3A, - 0x6B,0x97,0x74,0x63,0x33,0xBD,0x68,0x18,0x31,0xF0,0x78,0x8D,0x76,0xBF,0xFC,0x9E, - 0x8E,0x5D,0x2A,0x86,0xA7,0x4D,0x90,0xDC,0x27,0x1A,0x39,0x02,0x03,0x01,0x00,0x01, - 0xA3,0x45,0x30,0x43,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xE5, - 0x9D,0x59,0x30,0x82,0x47,0x58,0xCC,0xAC,0xFA,0x08,0x54,0x36,0x86,0x7B,0x3A,0xB5, - 0x04,0x4D,0xF0,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,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, - 0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x85,0x0C,0x5D,0x8E,0xE4, - 0x6F,0x51,0x68,0x42,0x05,0xA0,0xDD,0xBB,0x4F,0x27,0x25,0x84,0x03,0xBD,0xF7,0x64, - 0xFD,0x2D,0xD7,0x30,0xE3,0xA4,0x10,0x17,0xEB,0xDA,0x29,0x29,0xB6,0x79,0x3F,0x76, - 0xF6,0x19,0x13,0x23,0xB8,0x10,0x0A,0xF9,0x58,0xA4,0xD4,0x61,0x70,0xBD,0x04,0x61, - 0x6A,0x12,0x8A,0x17,0xD5,0x0A,0xBD,0xC5,0xBC,0x30,0x7C,0xD6,0xE9,0x0C,0x25,0x8D, - 0x86,0x40,0x4F,0xEC,0xCC,0xA3,0x7E,0x38,0xC6,0x37,0x11,0x4F,0xED,0xDD,0x68,0x31, - 0x8E,0x4C,0xD2,0xB3,0x01,0x74,0xEE,0xBE,0x75,0x5E,0x07,0x48,0x1A,0x7F,0x70,0xFF, - 0x16,0x5C,0x84,0xC0,0x79,0x85,0xB8,0x05,0xFD,0x7F,0xBE,0x65,0x11,0xA3,0x0F,0xC0, - 0x02,0xB4,0xF8,0x52,0x37,0x39,0x04,0xD5,0xA9,0x31,0x7A,0x18,0xBF,0xA0,0x2A,0xF4, - 0x12,0x99,0xF7,0xA3,0x45,0x82,0xE3,0x3C,0x5E,0xF5,0x9D,0x9E,0xB5,0xC8,0x9E,0x7C, - 0x2E,0xC8,0xA4,0x9E,0x4E,0x08,0x14,0x4B,0x6D,0xFD,0x70,0x6D,0x6B,0x1A,0x63,0xBD, - 0x64,0xE6,0x1F,0xB7,0xCE,0xF0,0xF2,0x9F,0x2E,0xBB,0x1B,0xB7,0xF2,0x50,0x88,0x73, - 0x92,0xC2,0xE2,0xE3,0x16,0x8D,0x9A,0x32,0x02,0xAB,0x8E,0x18,0xDD,0xE9,0x10,0x11, - 0xEE,0x7E,0x35,0xAB,0x90,0xAF,0x3E,0x30,0x94,0x7A,0xD0,0x33,0x3D,0xA7,0x65,0x0F, - 0xF5,0xFC,0x8E,0x9E,0x62,0xCF,0x47,0x44,0x2C,0x01,0x5D,0xBB,0x1D,0xB5,0x32,0xD2, - 0x47,0xD2,0x38,0x2E,0xD0,0xFE,0x81,0xDC,0x32,0x6A,0x1E,0xB5,0xEE,0x3C,0xD5,0xFC, - 0xE7,0x81,0x1D,0x19,0xC3,0x24,0x42,0xEA,0x63,0x39,0xA9, -}; - - -/* subject:/C=CH/L=Zurich/O=ABB/CN=ABB Intermediate CA 3 */ -/* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ -unsigned char _ABBIntermediateCA3[1866]={ - 0x30,0x82,0x07,0x46,0x30,0x82,0x06,0x2E,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x07, - 0x27,0xCD,0x79,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B, - 0x05,0x00,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49, - 0x45,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74, - 0x69,0x6D,0x6F,0x72,0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A, - 0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03, - 0x55,0x04,0x03,0x13,0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43, - 0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E, - 0x17,0x0D,0x31,0x35,0x30,0x35,0x32,0x31,0x31,0x38,0x35,0x32,0x35,0x33,0x5A,0x17, - 0x0D,0x32,0x32,0x30,0x35,0x32,0x31,0x31,0x38,0x35,0x32,0x32,0x30,0x5A,0x30,0x4C, - 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x0F,0x30, - 0x0D,0x06,0x03,0x55,0x04,0x07,0x13,0x06,0x5A,0x75,0x72,0x69,0x63,0x68,0x31,0x0C, - 0x30,0x0A,0x06,0x03,0x55,0x04,0x0A,0x13,0x03,0x41,0x42,0x42,0x31,0x1E,0x30,0x1C, - 0x06,0x03,0x55,0x04,0x03,0x13,0x15,0x41,0x42,0x42,0x20,0x49,0x6E,0x74,0x65,0x72, - 0x6D,0x65,0x64,0x69,0x61,0x74,0x65,0x20,0x43,0x41,0x20,0x33,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,0x8E,0x43, - 0xE2,0x4C,0xBA,0xC4,0xD2,0xC4,0xF9,0xD5,0xA5,0xA4,0xC3,0xA4,0xB1,0x1D,0x3D,0x24, - 0x09,0xE8,0x6E,0xE6,0x3A,0x74,0x64,0x3E,0x5C,0xAE,0x40,0x93,0x27,0xB0,0xAD,0x01, - 0xC8,0xDA,0xF2,0x6F,0x7A,0x27,0xE9,0x17,0xB4,0x6D,0x52,0x94,0xE6,0x36,0x65,0x7A, - 0xAB,0x36,0x70,0x69,0xC8,0x0A,0x13,0xEC,0xC7,0xE0,0xA9,0xC2,0x0A,0xCD,0x5A,0x71, - 0x1A,0x26,0x27,0x81,0x5A,0xD0,0xB4,0x9C,0xE3,0x4C,0xCE,0x3D,0xB7,0x52,0xAB,0x86, - 0xB4,0x60,0xC6,0x15,0x6A,0xBC,0x38,0xE9,0x77,0xDC,0xA5,0xE2,0x1E,0x7D,0x15,0x80, - 0xF9,0x6B,0x7C,0x8E,0xA5,0xE7,0x95,0xC8,0x46,0x0C,0x6C,0x88,0x7B,0xF2,0x2E,0x1E, - 0xF7,0x4B,0x9E,0x13,0x85,0xB4,0x6E,0xC9,0xAA,0xDD,0x32,0xCF,0x41,0x17,0x4E,0x30, - 0xEB,0xD3,0x6D,0xE3,0x2E,0x44,0x8A,0x15,0x1B,0x6E,0x1B,0x32,0x5A,0xEA,0x98,0xA7, - 0x4C,0xAF,0xC8,0xAD,0x95,0x48,0xA6,0x67,0x3B,0xE2,0x94,0x81,0xB7,0xBF,0x7A,0xFF, - 0x96,0x5B,0xBA,0x83,0x3C,0x09,0x3C,0xF0,0xEA,0xA2,0x49,0x8A,0x5B,0x4B,0xB0,0x3E, - 0x98,0x7E,0x9F,0x52,0x9F,0x1B,0xA3,0x51,0x17,0xCB,0x5A,0x25,0x6E,0x60,0xDB,0xE2, - 0x90,0x02,0x2A,0x61,0x47,0x35,0x33,0x91,0x26,0x37,0x29,0xB8,0xD4,0xB1,0x41,0xB2, - 0xE9,0x3B,0x2B,0x68,0x74,0xBC,0xF3,0xA3,0x4B,0xD9,0x10,0x59,0x16,0x11,0x88,0xA9, - 0x31,0xC3,0x2A,0xD4,0x1D,0x5F,0x28,0x37,0xEB,0x45,0xF2,0x6E,0x83,0x91,0x4C,0xE1, - 0x82,0x58,0x33,0xCA,0xA5,0xA7,0x64,0x81,0xD8,0x5A,0x74,0xC9,0xC9,0x02,0x03,0x01, - 0x00,0x01,0xA3,0x82,0x04,0x20,0x30,0x82,0x04,0x1C,0x30,0x12,0x06,0x03,0x55,0x1D, - 0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x01,0x30,0x82, - 0x01,0x10,0x06,0x03,0x55,0x1D,0x20,0x04,0x82,0x01,0x07,0x30,0x82,0x01,0x03,0x30, - 0x48,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0xB1,0x3E,0x01,0x00,0x30,0x3B,0x30,0x39, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x2D,0x68,0x74,0x74,0x70, - 0x3A,0x2F,0x2F,0x63,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x6F,0x6D, - 0x6E,0x69,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73, - 0x69,0x74,0x6F,0x72,0x79,0x2E,0x63,0x66,0x6D,0x30,0x3B,0x06,0x0C,0x2B,0x06,0x01, - 0x04,0x01,0x81,0xD7,0x07,0x01,0x14,0x0A,0x02,0x30,0x2B,0x30,0x29,0x06,0x08,0x2B, - 0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F, - 0x63,0x70,0x2E,0x70,0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x43, - 0x41,0x36,0x5F,0x53,0x53,0x4C,0x30,0x3C,0x06,0x0C,0x2B,0x06,0x01,0x04,0x01,0x81, - 0xD7,0x07,0x01,0x14,0x14,0x02,0x30,0x2C,0x30,0x2A,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x02,0x01,0x16,0x1E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x70,0x2E, - 0x70,0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x41,0x36,0x5F, - 0x55,0x73,0x65,0x72,0x30,0x3C,0x06,0x0C,0x2B,0x06,0x01,0x04,0x01,0x81,0xD7,0x07, - 0x01,0x14,0x1E,0x02,0x30,0x2C,0x30,0x2A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07, - 0x02,0x01,0x16,0x1E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x70,0x2E,0x70,0x6B, - 0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x41,0x36,0x5F,0x53,0x69, - 0x67,0x6E,0x30,0x73,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x67, - 0x30,0x65,0x30,0x32,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x26, - 0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x6F,0x6D,0x6E,0x69, - 0x72,0x6F,0x6F,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x62,0x61,0x6C,0x74,0x69,0x6D,0x6F, - 0x72,0x65,0x72,0x6F,0x6F,0x74,0x30,0x2F,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07, - 0x30,0x02,0x86,0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x61,0x69,0x61,0x2E,0x70, - 0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x4F,0x6D,0x6E,0x69,0x72, - 0x6F,0x6F,0x74,0x2E,0x63,0x72,0x74,0x30,0x82,0x01,0x6A,0x06,0x03,0x55,0x1D,0x1E, - 0x04,0x82,0x01,0x61,0x30,0x82,0x01,0x5D,0xA0,0x82,0x01,0x4B,0x30,0x09,0x82,0x07, - 0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x30,0x0A,0x82,0x08,0x2E,0x61,0x62,0x62,0x2E, - 0x63,0x6F,0x6D,0x30,0x08,0x82,0x06,0x61,0x62,0x62,0x2E,0x61,0x73,0x30,0x09,0x82, - 0x07,0x2E,0x61,0x62,0x62,0x2E,0x61,0x73,0x30,0x0C,0x82,0x0A,0x61,0x62,0x62,0x65, - 0x78,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x82,0x0B,0x2E,0x61,0x62,0x62,0x65,0x78, - 0x74,0x2E,0x63,0x6F,0x6D,0x30,0x0C,0x82,0x0A,0x76,0x65,0x6E,0x74,0x79,0x78,0x2E, - 0x63,0x6F,0x6D,0x30,0x0D,0x82,0x0B,0x2E,0x76,0x65,0x6E,0x74,0x79,0x78,0x2E,0x63, - 0x6F,0x6D,0x30,0x11,0x82,0x0F,0x72,0x6F,0x62,0x6F,0x74,0x73,0x74,0x75,0x64,0x69, - 0x6F,0x2E,0x63,0x6F,0x6D,0x30,0x12,0x82,0x10,0x2E,0x72,0x6F,0x62,0x6F,0x74,0x73, - 0x74,0x75,0x64,0x69,0x6F,0x2E,0x63,0x6F,0x6D,0x30,0x48,0xA4,0x46,0x30,0x44,0x31, - 0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x0E,0x30,0x0C, - 0x06,0x03,0x55,0x04,0x07,0x13,0x05,0x42,0x61,0x64,0x65,0x6E,0x31,0x25,0x30,0x23, - 0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x41,0x42,0x42,0x20,0x49,0x6E,0x66,0x6F,0x72, - 0x6D,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x79,0x73,0x74,0x65,0x6D,0x73,0x20,0x4C, - 0x74,0x64,0x2E,0x30,0x40,0xA4,0x3E,0x30,0x3C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, - 0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x0F,0x30,0x0D,0x06,0x03,0x55,0x04,0x07,0x13, - 0x06,0x5A,0x75,0x72,0x69,0x63,0x68,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A, - 0x13,0x13,0x41,0x42,0x42,0x20,0x54,0x65,0x63,0x68,0x6E,0x6F,0x6C,0x6F,0x67,0x79, - 0x20,0x4C,0x74,0x64,0x2E,0x30,0x30,0xA4,0x2E,0x30,0x2C,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x0F,0x30,0x0D,0x06,0x03,0x55,0x04, - 0x07,0x13,0x06,0x5A,0x75,0x72,0x69,0x63,0x68,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55, - 0x04,0x0A,0x13,0x03,0x41,0x42,0x42,0xA1,0x0C,0x30,0x0A,0x87,0x08,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04, - 0x04,0x03,0x02,0x01,0xE6,0x30,0x50,0x06,0x03,0x55,0x1D,0x25,0x04,0x49,0x30,0x47, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x03,0x02,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x03,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x04,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07, - 0x03,0x08,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x09,0x06,0x09,0x2B,0x06, - 0x01,0x04,0x01,0x82,0x37,0x15,0x05,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, - 0x30,0x16,0x80,0x14,0xE5,0x9D,0x59,0x30,0x82,0x47,0x58,0xCC,0xAC,0xFA,0x08,0x54, - 0x36,0x86,0x7B,0x3A,0xB5,0x04,0x4D,0xF0,0x30,0x6D,0x06,0x03,0x55,0x1D,0x1F,0x04, - 0x66,0x30,0x64,0x30,0x37,0xA0,0x35,0xA0,0x33,0x86,0x31,0x68,0x74,0x74,0x70,0x3A, - 0x2F,0x2F,0x63,0x64,0x70,0x31,0x2E,0x70,0x75,0x62,0x6C,0x69,0x63,0x2D,0x74,0x72, - 0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x52,0x4C,0x2F,0x4F,0x6D,0x6E,0x69, - 0x72,0x6F,0x6F,0x74,0x32,0x30,0x32,0x35,0x2E,0x63,0x72,0x6C,0x30,0x29,0xA0,0x27, - 0xA0,0x25,0x86,0x23,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x70, - 0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x4F,0x6D,0x6E,0x69,0x72, - 0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16, - 0x04,0x14,0xD3,0xCB,0xD4,0xD2,0x44,0x75,0x8A,0x17,0x29,0x5E,0xC6,0xD7,0xF4,0x03, - 0xDB,0xB2,0x6B,0xB4,0x0C,0x3A,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D, - 0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xA2,0x07,0xEA,0xF9,0xB4,0x31, - 0xA8,0x40,0x29,0x27,0x49,0x9B,0xE0,0x29,0x0F,0x5C,0x18,0xD5,0x2C,0xEE,0xE2,0xA1, - 0xE4,0x1E,0x05,0x88,0xAF,0x16,0xAE,0x05,0xC0,0xCD,0x10,0x10,0xF6,0xDB,0x6A,0xC5, - 0xB5,0xBA,0xE5,0x1B,0x95,0x40,0x26,0xC6,0x5F,0x5A,0x50,0xFA,0x7F,0x73,0xFD,0x0D, - 0x3F,0xA2,0x4D,0x56,0x3B,0x0B,0xD9,0xB8,0x0B,0x09,0x9F,0xD3,0x41,0xD7,0xCA,0x01, - 0xF0,0xCC,0xB2,0x41,0xD9,0xB5,0x8F,0x85,0x27,0xF4,0x1B,0xDB,0x9A,0xA1,0x54,0xB4, - 0x0D,0xC1,0x89,0xD7,0x6C,0xA0,0x9E,0xE1,0x7B,0x0F,0xA6,0xDC,0x1A,0x1F,0xD1,0x8F, - 0x26,0x1D,0xFB,0x61,0x64,0xBF,0x1A,0x58,0x10,0x6D,0x81,0x10,0x3A,0xBE,0x44,0x3E, - 0xC0,0xCB,0xAF,0xC8,0x21,0xD5,0x4C,0x11,0x69,0x8E,0x56,0x12,0x9A,0xF2,0x3B,0x0B, - 0x4A,0x11,0xAC,0x5B,0xEE,0x66,0x4F,0xFE,0xE4,0x5A,0x9E,0xFC,0x69,0x77,0x08,0x1C, - 0x05,0x13,0xA0,0xE1,0xDA,0x06,0x12,0x8A,0x74,0xEB,0x30,0x52,0xE5,0x7A,0xFD,0x9B, - 0x2C,0xAC,0xBA,0xB0,0xC1,0x12,0x9F,0x7E,0xD7,0x7F,0x58,0xCD,0x8E,0xC3,0xE8,0x8D, - 0xAE,0xDA,0x35,0x57,0x8E,0xB0,0x6B,0xC8,0x5F,0xE5,0x27,0xA3,0x38,0x58,0x66,0x0D, - 0x65,0x66,0xC3,0x4B,0x2E,0x12,0x11,0x31,0x70,0x08,0xFC,0x95,0xFD,0x21,0x0C,0x0F, - 0x1F,0x2E,0xCD,0xB8,0xDD,0x39,0xEC,0xE5,0x44,0x2D,0x15,0xF9,0xE6,0xF4,0x11,0xC7, - 0x34,0x33,0xFF,0xBB,0xD1,0x20,0xAF,0x5E,0xF1,0xCA,0x1B,0xFC,0x5A,0x67,0x07,0x2B, - 0xF8,0xFF,0x56,0x32,0xBD,0x34,0x38,0xD8,0xF0,0xD7, -}; - -/* subject:/C=CH/L=Zurich/O=ABB/CN=ABB Issuing CA 6 */ -/* issuer :/C=CH/L=Zurich/O=ABB/CN=ABB Intermediate CA 3 */ -unsigned char _ABBIssuingCA6[1360]={ - 0x30,0x82,0x05,0x4C,0x30,0x82,0x04,0x34,0xA0,0x03,0x02,0x01,0x02,0x02,0x0A,0x76, - 0x8D,0x23,0xB4,0x00,0x00,0x00,0x00,0x00,0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x4C,0x31,0x0B,0x30,0x09,0x06,0x03, - 0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x0F,0x30,0x0D,0x06,0x03,0x55,0x04,0x07, - 0x13,0x06,0x5A,0x75,0x72,0x69,0x63,0x68,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04, - 0x0A,0x13,0x03,0x41,0x42,0x42,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x13, - 0x15,0x41,0x42,0x42,0x20,0x49,0x6E,0x74,0x65,0x72,0x6D,0x65,0x64,0x69,0x61,0x74, - 0x65,0x20,0x43,0x41,0x20,0x33,0x30,0x1E,0x17,0x0D,0x31,0x35,0x30,0x33,0x30,0x34, - 0x30,0x39,0x34,0x36,0x34,0x33,0x5A,0x17,0x0D,0x32,0x30,0x30,0x33,0x30,0x34,0x30, - 0x39,0x35,0x36,0x34,0x33,0x5A,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, - 0x06,0x13,0x02,0x43,0x48,0x31,0x0F,0x30,0x0D,0x06,0x03,0x55,0x04,0x07,0x13,0x06, - 0x5A,0x75,0x72,0x69,0x63,0x68,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04,0x0A,0x13, - 0x03,0x41,0x42,0x42,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x03,0x13,0x10,0x41, - 0x42,0x42,0x20,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x20,0x43,0x41,0x20,0x36,0x30, +/* subject:/C=US/O=Apple Inc./OU=Security Engineering/CN=Name Constraints Test Leaf 1 */ +/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Name Constraints Test Sub-CA */ +/* X509v3 Subject Alternative Name: + DNS:test1.test.apple.com + */ +unsigned char _test_leaf1[1059]={ + 0x30,0x82,0x04,0x1F,0x30,0x82,0x03,0x07,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x63, + 0x82,0xBA,0x4B,0x18,0xB2,0x48,0xF9,0x10,0x06,0xFA,0x70,0x00,0x5D,0x3B,0xF9,0x9E, + 0xE3,0x11,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,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,0x4E,0x61,0x6D,0x65,0x20,0x43,0x6F, + 0x6E,0x73,0x74,0x72,0x61,0x69,0x6E,0x74,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53, + 0x75,0x62,0x2D,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x37,0x30,0x35,0x32,0x34,0x30, + 0x31,0x31,0x39,0x35,0x30,0x5A,0x17,0x0D,0x31,0x38,0x30,0x35,0x32,0x34,0x30,0x31, + 0x31,0x39,0x35,0x30,0x5A,0x30,0x68,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, + 0x13,0x02,0x55,0x53,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,0x4E,0x61,0x6D,0x65,0x20,0x43,0x6F,0x6E,0x73,0x74,0x72,0x61,0x69, + 0x6E,0x74,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x4C,0x65,0x61,0x66,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, - 0xB5,0x9E,0xBF,0x61,0x8C,0xEA,0x40,0x8F,0x15,0x6F,0xC3,0x01,0xE3,0x71,0xDA,0x07, - 0x48,0x34,0x25,0x55,0xCB,0x6D,0xCD,0xBC,0xA4,0xA6,0xF9,0xE8,0x58,0x75,0xF8,0x0A, - 0x2E,0xA5,0xD7,0xBB,0xEC,0xAA,0x82,0x8B,0xB6,0x85,0xD0,0x3F,0x85,0xFF,0x50,0xFF, - 0x42,0x42,0xFB,0x59,0xCD,0x12,0x5F,0x4D,0x74,0xE6,0x00,0x9A,0xE2,0x6A,0xFC,0x8C, - 0xEB,0x22,0xA5,0x0D,0xC1,0x3F,0xE1,0x14,0x09,0x7F,0xB9,0x54,0x3C,0x01,0xB9,0x94, - 0x8E,0x5D,0x2D,0x9D,0x40,0xA0,0xB3,0x2C,0x63,0x1C,0xA2,0x23,0xCA,0x44,0x08,0x05, - 0xE6,0x02,0xEE,0xED,0x79,0xA6,0xF4,0xC7,0xC5,0x38,0xA1,0x71,0x8F,0xDE,0x10,0x7F, - 0x46,0x20,0xE9,0x3D,0xF3,0x52,0x25,0x11,0xB2,0x4C,0xCA,0x11,0x00,0xA6,0xFF,0x66, - 0xA5,0x6A,0xD1,0x15,0xFC,0x24,0x6A,0xC3,0xE8,0xCB,0xBB,0x7D,0x9D,0xC3,0x5B,0xCC, - 0x08,0x80,0xDE,0x95,0x3D,0xA5,0x0D,0x30,0x54,0x0C,0x53,0x83,0xB2,0xE1,0x49,0x73, - 0x6F,0xA4,0x1E,0x7A,0x9D,0x4B,0xD4,0xC0,0x46,0xEC,0x8C,0x12,0xC2,0x70,0x47,0x91, - 0x64,0x3B,0x94,0x5F,0xE3,0xA4,0x6F,0xA8,0x8F,0xA9,0xB9,0x19,0x65,0x97,0x16,0x82, - 0xCF,0x70,0xD2,0x86,0x37,0xCD,0x2A,0x50,0x69,0x6E,0x10,0x4A,0x9C,0x7B,0x6B,0xA2, - 0xB2,0x91,0xCE,0xAC,0xD3,0x23,0x2C,0xD7,0xA5,0xD1,0x34,0xD3,0x54,0x7B,0xC0,0x71, - 0x05,0x22,0x73,0xDC,0x8B,0x75,0x67,0x1C,0x98,0x2D,0xA6,0x51,0x50,0xC3,0x5D,0xA0, - 0x20,0xBD,0xD7,0xE8,0xCC,0xBC,0x40,0xB0,0x90,0xE6,0x10,0x9C,0xFD,0x6F,0x01,0x51, - 0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x02,0x33,0x30,0x82,0x02,0x2F,0x30,0x10,0x06, - 0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x01,0x04,0x03,0x02,0x01,0x00,0x30, - 0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x21,0x98,0x16,0xBF,0x7A,0x05, - 0x77,0xA6,0xAD,0xB7,0x7A,0x52,0xD4,0x9E,0x04,0x54,0xB0,0xFE,0xCC,0x51,0x30,0x19, - 0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x04,0x0C,0x1E,0x0A,0x00, - 0x53,0x00,0x75,0x00,0x62,0x00,0x43,0x00,0x41,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F, - 0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF, - 0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D, - 0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xD3,0xCB,0xD4,0xD2,0x44,0x75,0x8A,0x17,0x29, - 0x5E,0xC6,0xD7,0xF4,0x03,0xDB,0xB2,0x6B,0xB4,0x0C,0x3A,0x30,0x81,0xBF,0x06,0x03, - 0x55,0x1D,0x1F,0x04,0x81,0xB7,0x30,0x81,0xB4,0x30,0x81,0xB1,0xA0,0x81,0xAE,0xA0, - 0x81,0xAB,0x86,0x2D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x70, - 0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x41,0x42,0x42,0x49,0x6E, - 0x74,0x65,0x72,0x6D,0x65,0x64,0x69,0x61,0x74,0x65,0x43,0x41,0x33,0x2E,0x63,0x72, - 0x6C,0x86,0x7A,0x6C,0x64,0x61,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x70,0x6B, - 0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4E,0x3D,0x41,0x42,0x42, - 0x49,0x6E,0x74,0x65,0x72,0x6D,0x65,0x64,0x69,0x61,0x74,0x65,0x43,0x41,0x33,0x2C, - 0x43,0x4E,0x3D,0x43,0x44,0x50,0x2C,0x43,0x4E,0x3D,0x50,0x4B,0x49,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,0x6F,0x62,0x6A, - 0x65,0x63,0x74,0x43,0x6C,0x61,0x73,0x73,0x3D,0x63,0x52,0x4C,0x44,0x69,0x73,0x74, - 0x72,0x69,0x62,0x75,0x74,0x69,0x6F,0x6E,0x50,0x6F,0x69,0x6E,0x74,0x30,0x81,0xC9, - 0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x81,0xBC,0x30,0x81,0xB9, - 0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2D,0x68,0x74, - 0x74,0x70,0x3A,0x2F,0x2F,0x61,0x69,0x61,0x2E,0x70,0x6B,0x69,0x2E,0x61,0x62,0x62, - 0x2E,0x63,0x6F,0x6D,0x2F,0x41,0x42,0x42,0x49,0x6E,0x74,0x65,0x72,0x6D,0x65,0x64, - 0x69,0x61,0x74,0x65,0x43,0x41,0x33,0x2E,0x63,0x72,0x74,0x30,0x7C,0x06,0x08,0x2B, - 0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x70,0x6C,0x64,0x61,0x70,0x3A,0x2F,0x2F, - 0x61,0x69,0x61,0x2E,0x70,0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F, - 0x43,0x4E,0x3D,0x41,0x42,0x42,0x49,0x6E,0x74,0x65,0x72,0x6D,0x65,0x64,0x69,0x61, - 0x74,0x65,0x43,0x41,0x33,0x2C,0x43,0x4E,0x3D,0x41,0x49,0x41,0x2C,0x43,0x4E,0x3D, - 0x50,0x4B,0x49,0x3F,0x63,0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74, - 0x65,0x3F,0x62,0x61,0x73,0x65,0x3F,0x6F,0x62,0x6A,0x65,0x63,0x74,0x43,0x6C,0x61, - 0x73,0x73,0x3D,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E, - 0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x11,0x06,0x03,0x55,0x1D,0x20, - 0x04,0x0A,0x30,0x08,0x30,0x06,0x06,0x04,0x55,0x1D,0x20,0x00,0x30,0x0D,0x06,0x09, - 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00, - 0x3C,0x9E,0xF8,0xC7,0x59,0x55,0x55,0x4B,0x18,0xE3,0x6D,0x8D,0x9F,0xE4,0x8B,0x58, - 0xAE,0x1E,0xA6,0x9C,0xE0,0xCC,0x26,0xE4,0x80,0xD2,0x2A,0x22,0xC3,0x7D,0xE6,0x91, - 0x1F,0x7B,0x6C,0xDD,0x1F,0x6D,0x65,0xF9,0xEE,0x03,0x4D,0xE0,0x8C,0x4A,0xF0,0x6F, - 0x05,0xBB,0xF6,0xD7,0x8A,0x73,0x3C,0xC2,0x0C,0x73,0x4C,0x2C,0x89,0x33,0x5B,0x67, - 0x1E,0x97,0x60,0xB9,0xE8,0x46,0x09,0x5C,0xD0,0x44,0x9A,0xD1,0x88,0x00,0xF2,0x0F, - 0x79,0x5C,0x7B,0xFD,0xC5,0xE2,0xD2,0xA6,0x2C,0x1A,0x10,0x0A,0x70,0x78,0x75,0x20, - 0xD9,0x4C,0xB5,0xCF,0xF1,0x95,0x99,0xE9,0x71,0x7B,0xCD,0x51,0x1C,0x66,0x30,0x63, - 0x32,0xFF,0x78,0x12,0x1B,0x4A,0x44,0xB4,0xC5,0xF7,0x62,0xF5,0x00,0xCC,0x73,0x9B, - 0x41,0xBA,0xA5,0xDB,0x0C,0x85,0x7B,0xBC,0xCA,0xDB,0xC7,0xE9,0x11,0xB6,0x73,0x45, - 0x38,0xC6,0xF5,0x75,0x2B,0x40,0x18,0xA9,0xBE,0xAA,0x9D,0xA4,0x45,0x9A,0xED,0xB4, - 0x95,0xAB,0x53,0x3A,0x44,0x31,0xF3,0xC0,0x09,0x25,0x2E,0x15,0x06,0x12,0x13,0x11, - 0xB0,0x6B,0x0C,0xF2,0xD3,0xD1,0x68,0xAB,0x7C,0xFA,0xBC,0xD4,0x5C,0xEB,0xE8,0x24, - 0x99,0xE2,0xC5,0xD5,0x34,0xD3,0x72,0x2F,0xF1,0xEB,0x9C,0x52,0x8F,0x66,0xB2,0x05, - 0x76,0xDB,0xC2,0x8E,0x6F,0x32,0xE8,0x0A,0xD6,0xC5,0xAB,0x1E,0x78,0xF7,0x1D,0x24, - 0x1E,0xE8,0x9D,0x60,0xDA,0xDB,0xBA,0x01,0xFF,0x72,0x5B,0x11,0xE6,0xA5,0x9F,0xBA, - 0x11,0xCB,0x4F,0xA0,0x78,0xF7,0x8A,0x14,0x70,0x50,0x0B,0xAF,0x47,0xB3,0x52,0x72, -}; - -/* subject:/C=CH/L=Baden/O=ABB Information Systems Ltd./CN=pki.abb.com */ -/* issuer :/C=CH/L=Zurich/O=ABB/CN=ABB Issuing CA 6 */ -unsigned char _ABB_PKI_cert[1889]={ - 0x30,0x82,0x07,0x5D,0x30,0x82,0x06,0x45,0xA0,0x03,0x02,0x01,0x02,0x02,0x0A,0x1A, - 0xDF,0xD6,0x2B,0x00,0x00,0x00,0x00,0x00,0x4C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x47,0x31,0x0B,0x30,0x09,0x06,0x03, - 0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,0x0F,0x30,0x0D,0x06,0x03,0x55,0x04,0x07, - 0x13,0x06,0x5A,0x75,0x72,0x69,0x63,0x68,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04, - 0x0A,0x13,0x03,0x41,0x42,0x42,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x03,0x13, - 0x10,0x41,0x42,0x42,0x20,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x20,0x43,0x41,0x20, - 0x36,0x30,0x1E,0x17,0x0D,0x31,0x35,0x30,0x33,0x30,0x36,0x31,0x34,0x32,0x38,0x34, - 0x37,0x5A,0x17,0x0D,0x31,0x37,0x30,0x38,0x32,0x32,0x31,0x34,0x32,0x38,0x34,0x37, - 0x5A,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48, - 0x31,0x0E,0x30,0x0C,0x06,0x03,0x55,0x04,0x07,0x13,0x05,0x42,0x61,0x64,0x65,0x6E, - 0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0A,0x13,0x1C,0x41,0x42,0x42,0x20,0x49, - 0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x79,0x73,0x74,0x65, - 0x6D,0x73,0x20,0x4C,0x74,0x64,0x2E,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x03, - 0x13,0x0B,0x70,0x6B,0x69,0x2E,0x61,0x62,0x62,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,0xA0,0x67, - 0x31,0xDC,0xE3,0x2F,0x44,0xA5,0xA1,0xFB,0x47,0xAD,0x4B,0x57,0xDE,0xE1,0x36,0x7E, - 0x7F,0x89,0xEB,0x85,0xB5,0x62,0x05,0x62,0x12,0x33,0xE9,0xDC,0xBA,0xD6,0x72,0x17, - 0x1C,0xFC,0xB3,0xFF,0x4A,0xE6,0xD1,0x84,0x70,0xDF,0x7E,0xAB,0xA9,0x14,0xD5,0x1E, - 0x18,0x82,0x87,0xEE,0x5F,0xC7,0xA7,0xE4,0xC3,0xC1,0xD2,0x15,0xE2,0xD8,0xCF,0x95, - 0xF9,0xDD,0xA4,0xD4,0xBE,0x9F,0xB1,0x8F,0x3C,0xCA,0xC2,0x53,0x67,0x8C,0x3D,0x35, - 0x8B,0x94,0x40,0xEC,0xF5,0xC6,0x9B,0xA4,0x63,0xBC,0xB5,0x30,0xA2,0x74,0xB9,0x25, - 0x62,0xE9,0x8D,0x47,0xC4,0xAE,0x5D,0xEB,0xF8,0x89,0x13,0x38,0x85,0x9E,0x9C,0x7C, - 0xF0,0x4B,0x27,0x43,0xC4,0x7D,0xEA,0x2E,0x48,0xD0,0x3F,0xCC,0x73,0xC6,0x7B,0x1F, - 0xBF,0xFB,0xCF,0x5A,0x0C,0x25,0xC0,0x4E,0x31,0xAA,0x9B,0xFF,0xFF,0x29,0x21,0x63, - 0xA1,0x51,0x81,0x49,0x69,0x6E,0x89,0x81,0x6C,0x41,0xC4,0x17,0xF0,0x65,0x3C,0xFD, - 0x4C,0x38,0x78,0x56,0x77,0xB8,0x7F,0x8C,0x3F,0x63,0x6A,0x90,0x1F,0x90,0x8F,0xD5, - 0x7A,0x3A,0xD6,0xE9,0xF8,0x5C,0xEC,0x32,0x6E,0xEB,0xFA,0x3B,0x3F,0x9A,0xFC,0xD3, - 0x87,0xBC,0xD9,0x2D,0xF5,0xC2,0xB7,0x15,0x8A,0x48,0x37,0x55,0x10,0x5D,0x6F,0x32, - 0xE3,0x6D,0xF0,0x79,0xAF,0xE9,0xDC,0xB1,0xAF,0xC6,0x89,0xE0,0x32,0x2E,0xBC,0x70, - 0x07,0x2F,0xE6,0xFB,0xF6,0xCB,0x8A,0x90,0x7E,0x23,0x46,0x7A,0xBF,0x5E,0x07,0x87, - 0xDD,0xC5,0x77,0xF4,0xEB,0x8B,0x82,0x73,0x9E,0xE6,0x11,0xB8,0xF1,0xBB,0x02,0x03, - 0x01,0x00,0x01,0xA3,0x82,0x04,0x36,0x30,0x82,0x04,0x32,0x30,0x0B,0x06,0x03,0x55, - 0x1D,0x0F,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, - 0x16,0x04,0x14,0x07,0xF0,0xC8,0x84,0x00,0x5D,0x67,0x88,0xA7,0xC0,0xD0,0x02,0x48, - 0x38,0xF3,0xEF,0x1B,0xAE,0xBD,0x28,0x30,0x16,0x06,0x03,0x55,0x1D,0x11,0x04,0x0F, - 0x30,0x0D,0x82,0x0B,0x70,0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x30, - 0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x21,0x98,0x16,0xBF, - 0x7A,0x05,0x77,0xA6,0xAD,0xB7,0x7A,0x52,0xD4,0x9E,0x04,0x54,0xB0,0xFE,0xCC,0x51, - 0x30,0x82,0x01,0x62,0x06,0x03,0x55,0x1D,0x1F,0x04,0x82,0x01,0x59,0x30,0x82,0x01, - 0x55,0x30,0x82,0x01,0x51,0xA0,0x82,0x01,0x4D,0xA0,0x82,0x01,0x49,0x86,0x28,0x68, - 0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x70,0x6B,0x69,0x2E,0x61,0x62, - 0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x41,0x42,0x42,0x49,0x73,0x73,0x75,0x69,0x6E,0x67, - 0x43,0x41,0x36,0x2E,0x63,0x72,0x6C,0x86,0x81,0xA5,0x6C,0x64,0x61,0x70,0x3A,0x2F, - 0x2F,0x2F,0x43,0x4E,0x3D,0x41,0x42,0x42,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x43, - 0x41,0x36,0x2C,0x43,0x4E,0x3D,0x43,0x44,0x50,0x2C,0x43,0x4E,0x3D,0x50,0x75,0x62, - 0x6C,0x69,0x63,0x25,0x32,0x30,0x4B,0x65,0x79,0x25,0x32,0x30,0x53,0x65,0x72,0x76, - 0x69,0x63,0x65,0x73,0x2C,0x43,0x4E,0x3D,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73, - 0x2C,0x43,0x4E,0x3D,0x43,0x6F,0x6E,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F, - 0x6E,0x2C,0x44,0x43,0x3D,0x61,0x62,0x62,0x2C,0x44,0x43,0x3D,0x63,0x6F,0x6D,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,0x6F, - 0x62,0x6A,0x65,0x63,0x74,0x43,0x6C,0x61,0x73,0x73,0x3D,0x63,0x52,0x4C,0x44,0x69, - 0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x69,0x6F,0x6E,0x50,0x6F,0x69,0x6E,0x74,0x86, - 0x75,0x6C,0x64,0x61,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x70,0x6B,0x69,0x2E, - 0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4E,0x3D,0x41,0x42,0x42,0x49,0x73, - 0x73,0x75,0x69,0x6E,0x67,0x43,0x41,0x36,0x2C,0x43,0x4E,0x3D,0x43,0x44,0x50,0x2C, - 0x43,0x4E,0x3D,0x50,0x4B,0x49,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,0x6F,0x62,0x6A,0x65,0x63,0x74,0x43,0x6C,0x61,0x73, - 0x73,0x3D,0x63,0x52,0x4C,0x44,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x69,0x6F, - 0x6E,0x50,0x6F,0x69,0x6E,0x74,0x30,0x82,0x01,0x95,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x01,0x01,0x04,0x82,0x01,0x87,0x30,0x82,0x01,0x83,0x30,0x34,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x28,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x61,0x69,0x61,0x2E,0x70,0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D, - 0x2F,0x41,0x42,0x42,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x43,0x41,0x36,0x2E,0x63, - 0x72,0x74,0x30,0x81,0xA8,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86, - 0x81,0x9B,0x6C,0x64,0x61,0x70,0x3A,0x2F,0x2F,0x2F,0x43,0x4E,0x3D,0x41,0x42,0x42, - 0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x43,0x41,0x36,0x2C,0x43,0x4E,0x3D,0x41,0x49, - 0x41,0x2C,0x43,0x4E,0x3D,0x50,0x75,0x62,0x6C,0x69,0x63,0x25,0x32,0x30,0x4B,0x65, - 0x79,0x25,0x32,0x30,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2C,0x43,0x4E,0x3D, - 0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2C,0x43,0x4E,0x3D,0x43,0x6F,0x6E,0x66, - 0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6F,0x6E,0x2C,0x44,0x43,0x3D,0x61,0x62,0x62, - 0x2C,0x44,0x43,0x3D,0x63,0x6F,0x6D,0x3F,0x63,0x41,0x43,0x65,0x72,0x74,0x69,0x66, - 0x69,0x63,0x61,0x74,0x65,0x3F,0x62,0x61,0x73,0x65,0x3F,0x6F,0x62,0x6A,0x65,0x63, - 0x74,0x43,0x6C,0x61,0x73,0x73,0x3D,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61, - 0x74,0x69,0x6F,0x6E,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x77,0x06, - 0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x6B,0x6C,0x64,0x61,0x70,0x3A, - 0x2F,0x2F,0x61,0x69,0x61,0x2E,0x70,0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F, - 0x6D,0x2F,0x43,0x4E,0x3D,0x41,0x42,0x42,0x49,0x73,0x73,0x75,0x69,0x6E,0x67,0x43, - 0x41,0x36,0x2C,0x43,0x4E,0x3D,0x41,0x49,0x41,0x2C,0x43,0x4E,0x3D,0x50,0x4B,0x49, - 0x3F,0x63,0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x3F,0x62, - 0x61,0x73,0x65,0x3F,0x6F,0x62,0x6A,0x65,0x63,0x74,0x43,0x6C,0x61,0x73,0x73,0x3D, - 0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x41,0x75,0x74, - 0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x27,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07, - 0x30,0x01,0x86,0x1B,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x61,0x69,0x61,0x2E,0x70, - 0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30, - 0x3C,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x07,0x04,0x2F,0x30,0x2D, - 0x06,0x25,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x08,0xC7,0xA8,0x26,0x86,0xB0, - 0x84,0x7A,0x86,0xB5,0x8B,0x0A,0x82,0xEA,0x8D,0x6A,0x84,0x8F,0xAD,0x21,0x29,0x84, - 0xF3,0x8F,0x08,0x86,0xCE,0xF7,0x0F,0x02,0x01,0x64,0x02,0x01,0x16,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,0x46,0x06,0x03, - 0x55,0x1D,0x20,0x04,0x3F,0x30,0x3D,0x30,0x3B,0x06,0x0C,0x2B,0x06,0x01,0x04,0x01, - 0x81,0xD7,0x07,0x01,0x14,0x0A,0x02,0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01, - 0x05,0x05,0x07,0x02,0x01,0x16,0x1D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x70, - 0x2E,0x70,0x6B,0x69,0x2E,0x61,0x62,0x62,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x41,0x36, - 0x5F,0x53,0x53,0x4C,0x30,0x27,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15, - 0x0A,0x04,0x1A,0x30,0x18,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03, - 0x02,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x0D,0x06, - 0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01, - 0x00,0x24,0xB7,0xBE,0x08,0xA4,0x97,0x8C,0x78,0x49,0xC7,0x93,0xB9,0x04,0x18,0xAB, - 0x11,0x00,0x39,0xFB,0xA0,0xBE,0xC3,0x39,0xBA,0x04,0x5F,0x3F,0xFE,0xA4,0x6C,0x79, - 0xF2,0xD9,0x00,0xC6,0xE0,0x55,0x7B,0xBE,0x93,0xC2,0x46,0x7B,0xFA,0x9E,0x8D,0xDC, - 0xA8,0x10,0x54,0xBF,0xC2,0x3F,0xC4,0xB1,0xFD,0x30,0xC2,0x27,0xBC,0x38,0x8D,0xAE, - 0x66,0xF4,0xE9,0x62,0x50,0x54,0x4F,0xCD,0x7A,0x2B,0x67,0x17,0xA0,0xA0,0x7E,0x03, - 0xE6,0xA6,0x68,0x0A,0x1B,0xD3,0x5E,0x7D,0xEC,0xF0,0x12,0x89,0xDF,0x3D,0xA5,0xB9, - 0xAC,0xA4,0x9D,0x62,0x3A,0x99,0x9B,0x67,0xA8,0xD9,0xCE,0x11,0xA7,0xCB,0xE4,0xED, - 0x81,0x3F,0xE4,0xDD,0xE7,0xE2,0x0C,0xEB,0x27,0x1E,0x1B,0xEE,0xA2,0x03,0x32,0x79, - 0xA3,0x43,0x50,0xBD,0x7D,0x17,0xE1,0x42,0x8F,0x3D,0x20,0x81,0xC9,0xE3,0x58,0x27, - 0xEC,0x94,0xA9,0xDA,0xC6,0x23,0xF1,0x31,0xF7,0x47,0xCF,0x48,0x9B,0xFE,0xC2,0x09, - 0xAA,0x41,0xFE,0xDE,0x51,0x2B,0x1F,0xBB,0xD1,0xA4,0x62,0xF7,0xA2,0x2C,0x9B,0x4B, - 0x3D,0xD5,0xB5,0x47,0x39,0xA1,0x43,0x9C,0x6B,0xDA,0x78,0x63,0x81,0xC4,0xA1,0x93, - 0x93,0xB9,0xB6,0xA5,0xC7,0xD5,0xA5,0x47,0xF5,0x47,0xC8,0x7F,0xF7,0x4C,0xE8,0x97, - 0xA1,0x99,0xAD,0x78,0x54,0x09,0xF7,0xB7,0xF5,0x2B,0x05,0x1F,0x38,0x32,0xEE,0x4A, - 0x1D,0xCC,0x63,0xE1,0x1A,0xB6,0xA6,0x67,0x4B,0xC6,0xC4,0xB9,0xA6,0x97,0xB3,0x41, - 0xD3,0x5C,0xBC,0xEB,0xD3,0x18,0xBD,0xFB,0x68,0x1C,0xC2,0xEF,0xEC,0x1B,0x06,0xFC, - 0xF0, + 0xD2,0x19,0x59,0xE3,0x14,0x45,0xC8,0x20,0x10,0x1A,0x99,0x27,0x35,0x3B,0xDD,0x53, + 0x80,0xA9,0x77,0x40,0xDE,0x5D,0xD7,0x8E,0x82,0x8E,0xC4,0x14,0x72,0x98,0x32,0x02, + 0xB0,0xC6,0xA6,0xA7,0xAD,0xF3,0x3A,0xCA,0xCE,0x17,0x60,0x70,0x9E,0xA8,0x79,0x1A, + 0x34,0xA5,0xCC,0x4B,0x2C,0x12,0xF7,0x49,0x04,0x4C,0xCD,0xB9,0xFF,0x32,0xCF,0xCD, + 0xCC,0xBE,0x6C,0x80,0x12,0x18,0x50,0xFD,0xA6,0x29,0xE6,0x9F,0xA0,0xB8,0x7D,0xBB, + 0xE6,0x8A,0x5A,0x59,0x7C,0x48,0xE4,0xA7,0x9F,0x83,0xBA,0x6E,0x33,0xEF,0xA9,0xA6, + 0xB5,0xF8,0xD4,0xA0,0x95,0x3B,0x1D,0x4D,0xAC,0x97,0xD0,0x75,0xD5,0xCC,0x3E,0x89, + 0x91,0xD2,0x17,0xCF,0xE8,0xF4,0x6D,0x77,0x27,0x5E,0xC6,0xC3,0x74,0xCD,0x7F,0x36, + 0xE4,0xCC,0xD5,0x00,0x11,0xE9,0xA5,0xE0,0x82,0xA1,0x3E,0x3F,0xEB,0xB6,0xA1,0x7B, + 0xF2,0xA5,0xDF,0x9F,0xA7,0x14,0x3E,0xE2,0xD8,0xD3,0x00,0x75,0x95,0x3C,0xEA,0x82, + 0xF3,0x99,0xF5,0xD0,0x9B,0xFA,0x60,0x48,0x45,0x7B,0x1E,0x9E,0xB3,0xE9,0xA6,0x13, + 0xFE,0xF1,0x72,0xD8,0x9F,0xFE,0xC6,0xCB,0x76,0x4C,0x1C,0x30,0x25,0xB0,0xE7,0x32, + 0x9B,0x99,0xC7,0xBC,0x61,0x7F,0x55,0x5A,0xF3,0xD1,0x89,0x87,0xF5,0xB4,0x0D,0x74, + 0x18,0x08,0x24,0x1A,0x77,0xEC,0x41,0x55,0x79,0xEA,0x5A,0xB1,0x46,0xE7,0x07,0x16, + 0x53,0x5D,0x55,0xFC,0x61,0x20,0x08,0x5C,0xC1,0x79,0xCC,0x4D,0x22,0xC6,0x3D,0x20, + 0xC1,0x42,0xEB,0xAD,0xAC,0xC2,0xA2,0x13,0x9F,0x31,0xBD,0x63,0x91,0x9B,0xA7,0xCF, + 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,0x31, + 0x2E,0x74,0x65,0x73,0x74,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30, + 0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xCA,0xE5,0xDF,0x27,0x6E,0xFA, + 0x13,0xE0,0x60,0x64,0xEA,0x00,0x49,0xF7,0x77,0x8D,0x12,0x4D,0xA0,0xEC,0x30,0x1F, + 0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x43,0xD7,0xC9,0x6E,0x6E, + 0x28,0x69,0x32,0xB9,0xB7,0x4F,0x36,0x5A,0xD3,0x51,0x80,0x23,0x41,0x9A,0x01,0x30, + 0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82, + 0x01,0x01,0x00,0xB0,0x54,0x1F,0xA6,0xBF,0x93,0x07,0x08,0x66,0x82,0x02,0xC0,0x46, + 0x23,0x8C,0xF1,0xB2,0x7A,0xDC,0xE4,0xAF,0xDD,0x75,0x05,0xFD,0x39,0xF1,0xD3,0x90, + 0x56,0xDD,0xED,0xC2,0x96,0xEE,0x5E,0x5F,0x08,0xC6,0xAB,0x28,0x6C,0x70,0x4C,0x6F, + 0x7E,0xFE,0x9B,0x21,0x26,0x63,0xA1,0x26,0xBE,0xEB,0x25,0x29,0xA3,0x4D,0x00,0xA9, + 0x0E,0x7D,0x5A,0x05,0x3F,0xA5,0x73,0xA8,0xA4,0x47,0x5A,0xEE,0x4B,0xB1,0x08,0xC9, + 0x92,0x43,0x6E,0x23,0x8A,0x83,0x37,0xB0,0x68,0xE2,0xA5,0x24,0xCC,0x39,0xCD,0x4F, + 0x4E,0x48,0x8D,0xC3,0x74,0x55,0x34,0x00,0x99,0xEF,0x79,0x4D,0xBE,0x2F,0x97,0xB1, + 0x21,0x5B,0xF7,0xB9,0xFE,0x11,0xA8,0xB7,0x4A,0x8F,0x51,0x6F,0x53,0x95,0x41,0x4E, + 0x22,0xE9,0x4D,0xA7,0x44,0x5C,0x2F,0x57,0x95,0x57,0x78,0x62,0x10,0x2B,0x0A,0x67, + 0x7F,0x65,0x7D,0xAB,0x6C,0x22,0x22,0x88,0xAA,0x23,0x34,0xD4,0x2C,0x76,0xC8,0x40, + 0x79,0x73,0x84,0x0C,0x7C,0x3E,0xEF,0xD6,0x52,0x34,0x42,0xE2,0x23,0xE8,0x3C,0x57, + 0x6C,0x8A,0xFE,0x4A,0x19,0xA1,0xE5,0x00,0x56,0xBA,0x0D,0xB8,0xA1,0x93,0x1C,0x79, + 0x58,0x25,0x44,0x25,0x7B,0xAB,0x3A,0x18,0x03,0x02,0x6E,0xCF,0x7A,0x48,0xCB,0x9F, + 0xED,0x41,0x72,0xC5,0xDD,0x43,0x8A,0xB6,0x59,0xA5,0xD8,0x14,0xB6,0x2F,0xCB,0x94, + 0x22,0xC6,0x98,0xB4,0x20,0x68,0x53,0x6C,0x2E,0x8C,0xE2,0x15,0xC4,0xF0,0xD1,0x40, + 0xDB,0x01,0x64,0x73,0x87,0xB0,0x44,0x72,0x07,0x1B,0x32,0xEB,0x00,0x3D,0x04,0xC7, + 0xE5,0x8D,0x20, }; -/* subject:/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ -/* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ -unsigned char _bechtel_root[891]={ - 0x30,0x82,0x03,0x77,0x30,0x82,0x02,0x5F,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x02, - 0x00,0x00,0xB9,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05, - 0x05,0x00,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49, - 0x45,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74, - 0x69,0x6D,0x6F,0x72,0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A, - 0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03, - 0x55,0x04,0x03,0x13,0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43, - 0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E, - 0x17,0x0D,0x30,0x30,0x30,0x35,0x31,0x32,0x31,0x38,0x34,0x36,0x30,0x30,0x5A,0x17, - 0x0D,0x32,0x35,0x30,0x35,0x31,0x32,0x32,0x33,0x35,0x39,0x30,0x30,0x5A,0x30,0x5A, - 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49,0x45,0x31,0x12,0x30, - 0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72, - 0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A,0x43,0x79,0x62,0x65, - 0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13, - 0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43,0x79,0x62,0x65,0x72, - 0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x82,0x01,0x22,0x30,0x0D, +/* subject:/C=US/O=Apple/OU=Security Engineering/CN=Name Constraints Test Leaf 2 */ +/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Name Constraints Test Sub-CA */ +/* X509v3 Subject Alternative Name: + DNS:apple.com + */ +unsigned char _test_leaf2[1043]={ + 0x30,0x82,0x04,0x0F,0x30,0x82,0x02,0xF7,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x63, + 0x82,0xBA,0x4B,0x18,0xB2,0x48,0xF9,0x10,0x06,0xFA,0x70,0x00,0x5D,0x3B,0xF9,0x9E, + 0xE3,0x12,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,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,0x4E,0x61,0x6D,0x65,0x20,0x43,0x6F, + 0x6E,0x73,0x74,0x72,0x61,0x69,0x6E,0x74,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53, + 0x75,0x62,0x2D,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x37,0x30,0x35,0x32,0x34,0x30, + 0x31,0x32,0x30,0x35,0x31,0x5A,0x17,0x0D,0x31,0x38,0x30,0x35,0x32,0x34,0x30,0x31, + 0x32,0x30,0x35,0x31,0x5A,0x30,0x63,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, + 0x13,0x02,0x55,0x53,0x31,0x0E,0x30,0x0C,0x06,0x03,0x55,0x04,0x0A,0x0C,0x05,0x41, + 0x70,0x70,0x6C,0x65,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,0x4E,0x61, + 0x6D,0x65,0x20,0x43,0x6F,0x6E,0x73,0x74,0x72,0x61,0x69,0x6E,0x74,0x73,0x20,0x54, + 0x65,0x73,0x74,0x20,0x4C,0x65,0x61,0x66,0x20,0x32,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,0xA3,0x04,0xBB,0x22,0xAB, - 0x98,0x3D,0x57,0xE8,0x26,0x72,0x9A,0xB5,0x79,0xD4,0x29,0xE2,0xE1,0xE8,0x95,0x80, - 0xB1,0xB0,0xE3,0x5B,0x8E,0x2B,0x29,0x9A,0x64,0xDF,0xA1,0x5D,0xED,0xB0,0x09,0x05, - 0x6D,0xDB,0x28,0x2E,0xCE,0x62,0xA2,0x62,0xFE,0xB4,0x88,0xDA,0x12,0xEB,0x38,0xEB, - 0x21,0x9D,0xC0,0x41,0x2B,0x01,0x52,0x7B,0x88,0x77,0xD3,0x1C,0x8F,0xC7,0xBA,0xB9, - 0x88,0xB5,0x6A,0x09,0xE7,0x73,0xE8,0x11,0x40,0xA7,0xD1,0xCC,0xCA,0x62,0x8D,0x2D, - 0xE5,0x8F,0x0B,0xA6,0x50,0xD2,0xA8,0x50,0xC3,0x28,0xEA,0xF5,0xAB,0x25,0x87,0x8A, - 0x9A,0x96,0x1C,0xA9,0x67,0xB8,0x3F,0x0C,0xD5,0xF7,0xF9,0x52,0x13,0x2F,0xC2,0x1B, - 0xD5,0x70,0x70,0xF0,0x8F,0xC0,0x12,0xCA,0x06,0xCB,0x9A,0xE1,0xD9,0xCA,0x33,0x7A, - 0x77,0xD6,0xF8,0xEC,0xB9,0xF1,0x68,0x44,0x42,0x48,0x13,0xD2,0xC0,0xC2,0xA4,0xAE, - 0x5E,0x60,0xFE,0xB6,0xA6,0x05,0xFC,0xB4,0xDD,0x07,0x59,0x02,0xD4,0x59,0x18,0x98, - 0x63,0xF5,0xA5,0x63,0xE0,0x90,0x0C,0x7D,0x5D,0xB2,0x06,0x7A,0xF3,0x85,0xEA,0xEB, - 0xD4,0x03,0xAE,0x5E,0x84,0x3E,0x5F,0xFF,0x15,0xED,0x69,0xBC,0xF9,0x39,0x36,0x72, - 0x75,0xCF,0x77,0x52,0x4D,0xF3,0xC9,0x90,0x2C,0xB9,0x3D,0xE5,0xC9,0x23,0x53,0x3F, - 0x1F,0x24,0x98,0x21,0x5C,0x07,0x99,0x29,0xBD,0xC6,0x3A,0xEC,0xE7,0x6E,0x86,0x3A, - 0x6B,0x97,0x74,0x63,0x33,0xBD,0x68,0x18,0x31,0xF0,0x78,0x8D,0x76,0xBF,0xFC,0x9E, - 0x8E,0x5D,0x2A,0x86,0xA7,0x4D,0x90,0xDC,0x27,0x1A,0x39,0x02,0x03,0x01,0x00,0x01, - 0xA3,0x45,0x30,0x43,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xE5, - 0x9D,0x59,0x30,0x82,0x47,0x58,0xCC,0xAC,0xFA,0x08,0x54,0x36,0x86,0x7B,0x3A,0xB5, - 0x04,0x4D,0xF0,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,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7, - 0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x85,0x0C,0x5D,0x8E,0xE4, - 0x6F,0x51,0x68,0x42,0x05,0xA0,0xDD,0xBB,0x4F,0x27,0x25,0x84,0x03,0xBD,0xF7,0x64, - 0xFD,0x2D,0xD7,0x30,0xE3,0xA4,0x10,0x17,0xEB,0xDA,0x29,0x29,0xB6,0x79,0x3F,0x76, - 0xF6,0x19,0x13,0x23,0xB8,0x10,0x0A,0xF9,0x58,0xA4,0xD4,0x61,0x70,0xBD,0x04,0x61, - 0x6A,0x12,0x8A,0x17,0xD5,0x0A,0xBD,0xC5,0xBC,0x30,0x7C,0xD6,0xE9,0x0C,0x25,0x8D, - 0x86,0x40,0x4F,0xEC,0xCC,0xA3,0x7E,0x38,0xC6,0x37,0x11,0x4F,0xED,0xDD,0x68,0x31, - 0x8E,0x4C,0xD2,0xB3,0x01,0x74,0xEE,0xBE,0x75,0x5E,0x07,0x48,0x1A,0x7F,0x70,0xFF, - 0x16,0x5C,0x84,0xC0,0x79,0x85,0xB8,0x05,0xFD,0x7F,0xBE,0x65,0x11,0xA3,0x0F,0xC0, - 0x02,0xB4,0xF8,0x52,0x37,0x39,0x04,0xD5,0xA9,0x31,0x7A,0x18,0xBF,0xA0,0x2A,0xF4, - 0x12,0x99,0xF7,0xA3,0x45,0x82,0xE3,0x3C,0x5E,0xF5,0x9D,0x9E,0xB5,0xC8,0x9E,0x7C, - 0x2E,0xC8,0xA4,0x9E,0x4E,0x08,0x14,0x4B,0x6D,0xFD,0x70,0x6D,0x6B,0x1A,0x63,0xBD, - 0x64,0xE6,0x1F,0xB7,0xCE,0xF0,0xF2,0x9F,0x2E,0xBB,0x1B,0xB7,0xF2,0x50,0x88,0x73, - 0x92,0xC2,0xE2,0xE3,0x16,0x8D,0x9A,0x32,0x02,0xAB,0x8E,0x18,0xDD,0xE9,0x10,0x11, - 0xEE,0x7E,0x35,0xAB,0x90,0xAF,0x3E,0x30,0x94,0x7A,0xD0,0x33,0x3D,0xA7,0x65,0x0F, - 0xF5,0xFC,0x8E,0x9E,0x62,0xCF,0x47,0x44,0x2C,0x01,0x5D,0xBB,0x1D,0xB5,0x32,0xD2, - 0x47,0xD2,0x38,0x2E,0xD0,0xFE,0x81,0xDC,0x32,0x6A,0x1E,0xB5,0xEE,0x3C,0xD5,0xFC, - 0xE7,0x81,0x1D,0x19,0xC3,0x24,0x42,0xEA,0x63,0x39,0xA9, -}; - -/* subject:/C=US/O=Bechtel Corporation/OU=Information Security/CN=Bechtel External Policy CA 1 */ -/* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ -unsigned char _bechtel_int1[2057]={ - 0x30,0x82,0x08,0x05,0x30,0x82,0x06,0xED,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x07, - 0x27,0xC9,0x87,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B, - 0x05,0x00,0x30,0x5A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x49, - 0x45,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x0A,0x13,0x09,0x42,0x61,0x6C,0x74, - 0x69,0x6D,0x6F,0x72,0x65,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0B,0x13,0x0A, - 0x43,0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x31,0x22,0x30,0x20,0x06,0x03, - 0x55,0x04,0x03,0x13,0x19,0x42,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x20,0x43, - 0x79,0x62,0x65,0x72,0x54,0x72,0x75,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E, - 0x17,0x0D,0x31,0x35,0x30,0x33,0x31,0x38,0x31,0x37,0x34,0x31,0x33,0x32,0x5A,0x17, - 0x0D,0x32,0x32,0x30,0x33,0x31,0x38,0x31,0x37,0x34,0x31,0x31,0x30,0x5A,0x30,0x71, - 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C,0x30, - 0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20, - 0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x1D,0x30,0x1B,0x06, - 0x03,0x55,0x04,0x0B,0x13,0x14,0x49,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F, - 0x6E,0x20,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x31,0x25,0x30,0x23,0x06,0x03, - 0x55,0x04,0x03,0x13,0x1C,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x45,0x78,0x74, - 0x65,0x72,0x6E,0x61,0x6C,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,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,0xAD,0x18,0x32,0x22,0xCB,0x4E,0x4E,0x2D,0x8E,0x2D,0xA4,0x1B,0x5E,0x85, - 0x63,0x9E,0xF3,0x89,0x3A,0x8A,0x1B,0x85,0x9E,0x59,0xCD,0xB1,0xCC,0x31,0x6D,0x66, - 0x20,0xB6,0xA9,0xF9,0xEC,0xD2,0x9D,0x19,0x0B,0x1E,0xEA,0x31,0x2B,0x51,0x4B,0x41, - 0x18,0x9C,0x27,0xB0,0xA4,0x08,0x76,0x92,0xE8,0xF4,0x42,0xE6,0xBF,0x11,0x0D,0xF8, - 0xF8,0xD2,0x17,0xB8,0x6A,0xAB,0xDA,0x0E,0x50,0xE3,0x93,0xC5,0xE9,0x89,0x7B,0x2B, - 0xD7,0xD1,0x69,0xD1,0x71,0x6D,0xE1,0x7F,0x70,0x0D,0x26,0xED,0x4D,0xC7,0x3A,0xBA, - 0xAC,0x74,0x39,0x18,0x15,0x8C,0x06,0x4C,0x8F,0xA1,0x27,0xA8,0x39,0x65,0xE1,0x08, - 0xDE,0x7E,0x1B,0xF9,0x59,0x27,0x0A,0xCC,0x7A,0xD8,0xD4,0x48,0x37,0x74,0x4E,0x58, - 0xAA,0x7B,0x5A,0xD3,0x67,0x15,0x4D,0x66,0xF7,0x86,0xE2,0x8F,0x9E,0xB5,0x19,0x73, - 0x5B,0x7E,0xA8,0x6F,0x3C,0xE2,0x9C,0x27,0xD2,0xCC,0x7C,0x2B,0xB9,0x50,0x6D,0xF0, - 0x12,0x14,0x47,0x07,0x8B,0xA6,0x7D,0x9F,0xD2,0xCE,0x16,0x77,0x97,0x63,0x37,0x0E, - 0xED,0x98,0x09,0xC5,0xF1,0x6A,0x45,0x89,0xCC,0x72,0xE5,0xD3,0xEB,0xEB,0x86,0x4E, - 0xE3,0x13,0x77,0x05,0x36,0xAC,0x1F,0x9D,0x9F,0xD7,0x0F,0x67,0xBE,0x0D,0xDC,0x40, - 0x2D,0xB8,0xBA,0xF5,0x21,0x0D,0xF4,0x9E,0x2C,0x18,0x58,0x0E,0xB1,0x95,0x08,0x8B, - 0xBC,0x5A,0x9D,0xFE,0x1D,0x45,0x57,0xD2,0x62,0x5B,0x91,0xB2,0x02,0x42,0xB8,0x17, - 0x7E,0x7D,0x18,0xAE,0x46,0xF4,0xA4,0x22,0xFC,0x91,0xEB,0xB8,0xBE,0x11,0x6C,0x08, - 0xC9,0x6B,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x04,0xBA,0x30,0x82,0x04,0xB6,0x30, - 0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF, - 0x02,0x01,0x01,0x30,0x6F,0x06,0x03,0x55,0x1D,0x20,0x04,0x68,0x30,0x66,0x30,0x48, - 0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0xB1,0x3E,0x01,0x00,0x30,0x3B,0x30,0x39,0x06, - 0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x2D,0x68,0x74,0x74,0x70,0x3A, - 0x2F,0x2F,0x63,0x79,0x62,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x6F,0x6D,0x6E, - 0x69,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x72,0x65,0x70,0x6F,0x73,0x69, - 0x74,0x6F,0x72,0x79,0x2E,0x63,0x66,0x6D,0x30,0x0C,0x06,0x0A,0x2B,0x06,0x01,0x04, - 0x01,0xFD,0x52,0x02,0x05,0x01,0x30,0x0C,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0xFD, - 0x52,0x02,0x05,0x02,0x30,0x82,0x03,0x22,0x06,0x03,0x55,0x1D,0x1E,0x04,0x82,0x03, - 0x19,0x30,0x82,0x03,0x15,0xA0,0x82,0x03,0x03,0x30,0x0C,0x82,0x0A,0x62,0x65,0x63, - 0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x82,0x0B,0x2E,0x62,0x65,0x63,0x70, - 0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x30,0x0B,0x82,0x09,0x6D,0x79,0x70,0x73,0x6E,0x2E, - 0x63,0x6F,0x6D,0x30,0x0C,0x82,0x0A,0x2E,0x6D,0x79,0x70,0x73,0x6E,0x2E,0x63,0x6F, - 0x6D,0x30,0x0E,0x82,0x0C,0x69,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x6D,0x30,0x0F,0x82,0x0D,0x2E,0x69,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63, - 0x6F,0x6D,0x30,0x0D,0x82,0x0B,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x6D,0x30,0x0E,0x82,0x0C,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x6D,0x30,0x0E,0x82,0x0C,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x61,0x73,0x69, - 0x61,0x30,0x0F,0x82,0x0D,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x61,0x73, - 0x69,0x61,0x30,0x0F,0x82,0x0D,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x2E,0x75,0x6B,0x30,0x10,0x82,0x0E,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E, - 0x63,0x6F,0x2E,0x75,0x6B,0x30,0x10,0x82,0x0E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C, - 0x2E,0x63,0x6F,0x6D,0x2E,0x61,0x75,0x30,0x11,0x82,0x0F,0x2E,0x62,0x65,0x63,0x68, - 0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2E,0x61,0x75,0x30,0x0D,0x82,0x0B,0x62,0x61, - 0x63,0x73,0x72,0x6D,0x70,0x2E,0x63,0x6F,0x6D,0x30,0x0E,0x82,0x0C,0x2E,0x62,0x61, - 0x63,0x73,0x72,0x6D,0x70,0x2E,0x63,0x6F,0x6D,0x30,0x13,0x82,0x11,0x63,0x6E,0x73, - 0x74,0x72,0x61,0x6E,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x63,0x6F,0x6D,0x30,0x14, - 0x82,0x12,0x2E,0x63,0x6E,0x73,0x74,0x72,0x61,0x6E,0x73,0x69,0x74,0x69,0x6F,0x6E, - 0x2E,0x63,0x6F,0x6D,0x30,0x11,0x82,0x0F,0x74,0x7A,0x62,0x70,0x61,0x72,0x74,0x6E, - 0x65,0x72,0x73,0x2E,0x63,0x6F,0x6D,0x30,0x12,0x82,0x10,0x2E,0x74,0x7A,0x62,0x70, - 0x61,0x72,0x74,0x6E,0x65,0x72,0x73,0x2E,0x63,0x6F,0x6D,0x30,0x13,0x82,0x11,0x63, - 0x74,0x69,0x2D,0x6D,0x6F,0x74,0x69,0x76,0x61,0x63,0x65,0x70,0x2E,0x63,0x6F,0x6D, - 0x30,0x14,0x82,0x12,0x2E,0x63,0x74,0x69,0x2D,0x6D,0x6F,0x74,0x69,0x76,0x61,0x63, - 0x65,0x70,0x2E,0x63,0x6F,0x6D,0x30,0x1C,0x82,0x1A,0x62,0x65,0x63,0x68,0x74,0x65, - 0x6C,0x74,0x72,0x61,0x6E,0x73,0x69,0x74,0x70,0x61,0x72,0x74,0x6E,0x65,0x72,0x73, - 0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x82,0x1B,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C, - 0x74,0x72,0x61,0x6E,0x73,0x69,0x74,0x70,0x61,0x72,0x74,0x6E,0x65,0x72,0x73,0x2E, - 0x63,0x6F,0x6D,0x30,0x62,0xA4,0x60,0x30,0x5E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55, - 0x04,0x06,0x13,0x02,0x41,0x55,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04,0x08,0x13, - 0x03,0x51,0x4C,0x44,0x31,0x11,0x30,0x0F,0x06,0x03,0x55,0x04,0x07,0x13,0x08,0x42, - 0x72,0x69,0x73,0x62,0x61,0x6E,0x65,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,0x0A, - 0x13,0x25,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x41,0x75,0x73,0x74,0x72,0x61, - 0x6C,0x69,0x61,0x20,0x50,0x72,0x6F,0x70,0x72,0x69,0x65,0x74,0x61,0x72,0x79,0x20, - 0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x30,0x38,0xA4,0x36,0x30,0x34,0x31,0x0B,0x30, - 0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x0F,0x30,0x0D,0x06,0x03, - 0x55,0x04,0x07,0x13,0x06,0x4C,0x6F,0x6E,0x64,0x6F,0x6E,0x31,0x14,0x30,0x12,0x06, - 0x03,0x55,0x04,0x0A,0x13,0x0B,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x4C,0x74, - 0x64,0x30,0x54,0xA4,0x52,0x30,0x50,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, - 0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x43, - 0x41,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x07,0x13,0x0D,0x53,0x61,0x6E,0x20, - 0x46,0x72,0x61,0x6E,0x63,0x69,0x73,0x63,0x6F,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55, - 0x04,0x0A,0x13,0x13,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70, - 0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x30,0x0C,0x82,0x0A,0x62,0x65,0x63,0x68,0x74, - 0x65,0x6C,0x2E,0x63,0x6C,0x30,0x0D,0x82,0x0B,0x2E,0x62,0x65,0x63,0x68,0x74,0x65, - 0x6C,0x2E,0x63,0x6C,0x30,0x0C,0x82,0x0A,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E, - 0x61,0x65,0x30,0x0D,0x82,0x0B,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x61, - 0x65,0x30,0x0B,0x82,0x09,0x62,0x62,0x65,0x68,0x63,0x2E,0x63,0x6F,0x6D,0x30,0x0C, - 0x82,0x0A,0x2E,0x62,0x62,0x65,0x68,0x63,0x2E,0x63,0x6F,0x6D,0xA1,0x0C,0x30,0x0A, - 0x87,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x06,0x08,0x2B,0x06, - 0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x36,0x30,0x34,0x30,0x32,0x06,0x08,0x2B,0x06, - 0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x26,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F, - 0x63,0x73,0x70,0x2E,0x6F,0x6D,0x6E,0x69,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x6F,0x6D, - 0x2F,0x62,0x61,0x6C,0x74,0x69,0x6D,0x6F,0x72,0x65,0x72,0x6F,0x6F,0x74,0x30,0x0E, - 0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,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,0x02,0x06,0x08,0x2B, - 0x06,0x01,0x05,0x05,0x07,0x03,0x09,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03, - 0x0E,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xE5,0x9D, - 0x59,0x30,0x82,0x47,0x58,0xCC,0xAC,0xFA,0x08,0x54,0x36,0x86,0x7B,0x3A,0xB5,0x04, - 0x4D,0xF0,0x30,0x42,0x06,0x03,0x55,0x1D,0x1F,0x04,0x3B,0x30,0x39,0x30,0x37,0xA0, - 0x35,0xA0,0x33,0x86,0x31,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x64,0x70,0x31, - 0x2E,0x70,0x75,0x62,0x6C,0x69,0x63,0x2D,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F, - 0x6D,0x2F,0x43,0x52,0x4C,0x2F,0x4F,0x6D,0x6E,0x69,0x72,0x6F,0x6F,0x74,0x32,0x30, - 0x32,0x35,0x2E,0x63,0x72,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04, - 0x14,0x07,0x88,0x41,0xE1,0x68,0x1D,0x6B,0x15,0x64,0xEE,0x7C,0x4D,0xA1,0x8D,0xFA, - 0x67,0xC3,0x53,0x59,0x37,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, - 0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x4D,0x7E,0x6A,0x4C,0x46,0x5E,0x32, - 0x6E,0x8E,0x77,0x9E,0xD3,0x70,0x7F,0xE2,0x58,0x97,0xE2,0x10,0xB7,0x68,0xC8,0x8A, - 0xAC,0x89,0xD0,0x3A,0x9C,0x6F,0x64,0x3B,0xC8,0xC0,0xE5,0x3B,0x9F,0x2C,0xC1,0x0A, - 0x10,0x05,0x4C,0xEA,0x02,0xD1,0xEA,0x84,0xA1,0x2E,0x37,0x88,0xC6,0x26,0x9B,0x27, - 0xB4,0x71,0x7C,0xBE,0x78,0x81,0x54,0x1F,0xC3,0xEB,0xA3,0x21,0x1B,0x40,0x6A,0x7C, - 0x1D,0xDB,0xE7,0x71,0xD2,0xB3,0xB9,0x08,0x8A,0xA4,0x69,0xA4,0x93,0xB8,0xCC,0x97, - 0xA9,0xFC,0x11,0x09,0x81,0xEE,0x3E,0x95,0xBE,0xFD,0xC9,0xB0,0xD7,0x8C,0x06,0xBD, - 0xFD,0x1B,0xE1,0xA1,0xDA,0xF9,0xD0,0x08,0x81,0x19,0x64,0x30,0xCD,0x22,0xEE,0x51, - 0x09,0xD5,0xD9,0xF0,0x74,0x8A,0x53,0x70,0xA4,0xB4,0xB8,0x87,0x81,0xB8,0xC0,0x2A, - 0x5C,0xDE,0x4E,0x94,0xA9,0x05,0x86,0xD0,0x4B,0xC9,0x53,0xE9,0xD2,0x3D,0x43,0xB0, - 0xE8,0x30,0x4A,0xD9,0x0C,0x31,0x54,0x26,0x44,0xB9,0x3D,0x85,0x42,0xEB,0xA6,0xCD, - 0x39,0x7E,0xDD,0x88,0xA4,0x04,0xB5,0xB3,0x35,0x38,0x29,0xAD,0x89,0x4D,0x95,0x49, - 0x70,0x31,0xFF,0x9F,0x53,0xC0,0x1E,0x66,0x75,0xD5,0x1D,0x7B,0x37,0xB3,0x3D,0x87, - 0xEB,0xD7,0x55,0xEF,0x80,0xAD,0x3D,0xD4,0x02,0x2C,0x19,0x2F,0x5C,0x83,0x4A,0xC9, - 0xD3,0xF1,0x2B,0x92,0xB7,0x5A,0xBE,0x2B,0xAD,0x91,0x76,0xCC,0x6A,0xC5,0x8A,0xFE, - 0x55,0x49,0x72,0xFA,0x75,0x2C,0x9B,0xF6,0xD9,0xFF,0xAC,0xD0,0xCC,0x60,0xAB,0xA9, - 0x09,0x70,0x8A,0xCF,0xC3,0x11,0xCB,0x4F,0x50, -}; - -/* subject:/C=US/ST=CA/L=San Francisco/O=Bechtel Corporation/OU=Information Security/CN=IEXTCA-SSL.ibechtel.com */ -/* issuer :/C=US/O=Bechtel Corporation/OU=Information Security/CN=Bechtel External Policy CA 1 */ -/* X509v3 Subject Key Identifier: 76:BB:3A:B1:8F:D3:F9:E8:F2:65:60:C9:3B:9D:EE:BB:ED:46:76:EE */ -unsigned char _bechtel_int2a[1353]={ - 0x30,0x82,0x05,0x45,0x30,0x82,0x04,0x2D,0xA0,0x03,0x02,0x01,0x02,0x02,0x0A,0x61, - 0x2D,0x7E,0x8B,0x00,0x04,0x00,0x00,0x00,0x24,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x71,0x31,0x0B,0x30,0x09,0x06,0x03, - 0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A, - 0x13,0x13,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72, - 0x61,0x74,0x69,0x6F,0x6E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14, - 0x49,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x63,0x75, - 0x72,0x69,0x74,0x79,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C,0x42, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20, - 0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x43,0x41,0x20,0x31,0x30,0x1E,0x17,0x0D,0x31, - 0x35,0x30,0x33,0x31,0x39,0x31,0x32,0x35,0x31,0x30,0x37,0x5A,0x17,0x0D,0x32,0x32, - 0x30,0x33,0x31,0x38,0x31,0x37,0x34,0x31,0x31,0x30,0x5A,0x30,0x81,0x91,0x31,0x0B, - 0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04, - 0x07,0x13,0x0D,0x53,0x61,0x6E,0x20,0x46,0x72,0x61,0x6E,0x63,0x69,0x73,0x63,0x6F, - 0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x42,0x65,0x63,0x68,0x74, - 0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x1D, - 0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14,0x49,0x6E,0x66,0x6F,0x72,0x6D,0x61, - 0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x31,0x20,0x30, - 0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x49,0x45,0x58,0x54,0x43,0x41,0x2D,0x53, - 0x53,0x4C,0x2E,0x69,0x62,0x65,0x63,0x68,0x74,0x65,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, - 0xCF,0x3E,0xCD,0xB4,0xFF,0xC3,0x66,0x2C,0x9E,0x83,0xB7,0x9A,0xD0,0xB7,0x59,0x3A, - 0x74,0xB4,0xCE,0x3C,0xF4,0x97,0x67,0x43,0xD1,0xCA,0xFE,0x90,0x7F,0x27,0x35,0x86, - 0x9D,0x70,0x4C,0x1A,0x3D,0xD1,0xFE,0xA1,0x98,0x75,0x1C,0x82,0xBF,0x67,0x5F,0xB2, - 0xE0,0xF8,0xA0,0x34,0x84,0x06,0x17,0x54,0x5B,0xA3,0x0D,0x3B,0x69,0x87,0x79,0xB3, - 0x4E,0xBE,0xCA,0x51,0x15,0xF5,0x1F,0x5D,0x22,0xAE,0x87,0xC9,0x2F,0xE3,0xB0,0x16, - 0xFA,0x84,0x90,0xB1,0xED,0xBD,0x71,0xD8,0xDA,0xD9,0xA4,0xCD,0xDF,0x66,0x54,0xB8, - 0x20,0xF8,0x5D,0x8C,0xA3,0xD5,0xC4,0xC3,0x68,0xFB,0x07,0xE6,0x5F,0x9F,0xC4,0x2E, - 0x26,0xA3,0x4E,0x53,0x8B,0xAB,0xE1,0x80,0x09,0xD1,0x29,0xC4,0x52,0xEA,0xD2,0xEA, - 0xF7,0x5D,0x24,0x5F,0x93,0x6D,0x2A,0x93,0x6B,0xF9,0x29,0x23,0x56,0x2D,0x3F,0x17, - 0x1B,0x5C,0xE8,0xA3,0xB4,0x8A,0xF1,0x86,0x06,0xF6,0xF6,0xB8,0x6A,0x34,0x6F,0x37, - 0x2C,0x4F,0x81,0x1C,0xDF,0x7D,0xD5,0x05,0x10,0xB3,0x93,0x7B,0x2B,0xD7,0xF2,0x9C, - 0xD9,0x2E,0xC0,0xB3,0x14,0x37,0x9E,0x79,0xEF,0x40,0x17,0x7A,0xF9,0x28,0x7C,0x6F, - 0x29,0x48,0xDE,0x22,0x8A,0xDB,0x57,0x5D,0x52,0xE8,0xC5,0x95,0xD8,0xC0,0x6A,0x63, - 0xFD,0x36,0x7A,0xE6,0xA6,0x76,0x2E,0x35,0x8B,0xD5,0x50,0xEB,0xC1,0xA7,0x74,0x3D, - 0x15,0x0E,0x7D,0xEA,0xA4,0xD6,0xA9,0xA1,0x73,0xE8,0xD0,0x91,0x0F,0x77,0x10,0x7F, - 0x33,0x8F,0x66,0x1F,0x6E,0x1B,0x41,0xF8,0xC1,0x58,0xA8,0x94,0x31,0x2C,0xEA,0x8F, - 0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0xBC,0x30,0x82,0x01,0xB8,0x30,0x0B,0x06, - 0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x12,0x06,0x09,0x2B,0x06, - 0x01,0x04,0x01,0x82,0x37,0x15,0x01,0x04,0x05,0x02,0x03,0x01,0x00,0x01,0x30,0x23, - 0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x02,0x04,0x16,0x04,0x14,0x3F, - 0xB2,0xF0,0xC3,0x5A,0xC6,0xBA,0xC1,0x34,0xFD,0xBD,0x81,0x03,0xFC,0x0B,0x0E,0x17, - 0xB1,0x66,0x73,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x76,0xBB, - 0x3A,0xB1,0x8F,0xD3,0xF9,0xE8,0xF2,0x65,0x60,0xC9,0x3B,0x9D,0xEE,0xBB,0xED,0x46, - 0x76,0xEE,0x30,0x25,0x06,0x03,0x55,0x1D,0x20,0x04,0x1E,0x30,0x1C,0x30,0x0C,0x06, - 0x0A,0x2B,0x06,0x01,0x04,0x01,0xFD,0x52,0x02,0x05,0x01,0x30,0x0C,0x06,0x0A,0x2B, - 0x06,0x01,0x04,0x01,0xFD,0x52,0x02,0x05,0x02,0x30,0x19,0x06,0x09,0x2B,0x06,0x01, - 0x04,0x01,0x82,0x37,0x14,0x02,0x04,0x0C,0x1E,0x0A,0x00,0x53,0x00,0x75,0x00,0x62, - 0x00,0x43,0x00,0x41,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08, - 0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04, - 0x18,0x30,0x16,0x80,0x14,0x07,0x88,0x41,0xE1,0x68,0x1D,0x6B,0x15,0x64,0xEE,0x7C, - 0x4D,0xA1,0x8D,0xFA,0x67,0xC3,0x53,0x59,0x37,0x30,0x61,0x06,0x03,0x55,0x1D,0x1F, - 0x04,0x5A,0x30,0x58,0x30,0x56,0xA0,0x54,0xA0,0x52,0x86,0x50,0x68,0x74,0x74,0x70, - 0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x61,0x75,0x74,0x68,0x2E,0x62,0x65,0x63,0x68, - 0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x65,0x72,0x74,0x44,0x61,0x74,0x61, - 0x2F,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72, - 0x6E,0x61,0x6C,0x25,0x32,0x30,0x50,0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30,0x43, - 0x41,0x25,0x32,0x30,0x31,0x28,0x34,0x29,0x2E,0x63,0x72,0x6C,0x30,0x77,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x6B,0x30,0x69,0x30,0x67,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x5B,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x63,0x65,0x72,0x74,0x61,0x75,0x74,0x68,0x2E,0x62,0x65,0x63,0x68,0x74,0x65, - 0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x65,0x72,0x74,0x44,0x61,0x74,0x61,0x2F,0x70, - 0x6F,0x6C,0x65,0x78,0x74,0x63,0x61,0x30,0x31,0x5F,0x42,0x65,0x63,0x68,0x74,0x65, - 0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x50, - 0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x31,0x28,0x34, - 0x29,0x2E,0x63,0x72,0x74,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, - 0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x38,0xC9,0xFE,0x7A,0xEF,0xF0,0xD8, - 0x24,0x69,0x11,0x68,0x81,0x31,0xEC,0x1C,0x8A,0x9C,0xD9,0x77,0xF6,0xFD,0xC7,0x2E, - 0xAC,0x46,0x6A,0xA8,0xB9,0xD7,0x7F,0xB2,0xC7,0x99,0x2D,0xDF,0xFD,0x8D,0x09,0x89, - 0x54,0x02,0xB4,0x4D,0xA2,0x8A,0x2B,0xC2,0x2F,0x3F,0xBB,0x8C,0x23,0x57,0xC6,0x06, - 0xC0,0x7E,0x2C,0x08,0xEB,0x6A,0x1B,0x04,0x3A,0x89,0xAC,0x20,0x44,0x97,0x85,0x79, - 0x59,0x72,0x8A,0xFF,0x9C,0x77,0x49,0x3E,0x3B,0xAF,0x75,0xA1,0x24,0xFC,0xD7,0x1C, - 0xAC,0xDE,0x95,0x7F,0x8E,0x50,0x7B,0xED,0x7B,0x6D,0x6C,0x28,0xB7,0x74,0x5F,0x15, - 0x5B,0x64,0x93,0x2E,0xD6,0x4F,0x05,0xFA,0x5A,0x32,0xD1,0x0C,0x7C,0x33,0x4A,0x99, - 0xAF,0xAB,0xC2,0x2A,0x0C,0x9A,0x76,0x54,0xBE,0xF9,0x6B,0xC7,0x65,0x44,0x7F,0xC8, - 0x73,0xE4,0xFB,0x94,0x9C,0x53,0xAF,0xD0,0x66,0xA9,0xF9,0x0D,0xD6,0x26,0x5A,0xBD, - 0x2E,0xE9,0xE2,0xFC,0x8C,0x9D,0x78,0x56,0xE8,0xBF,0x87,0xFE,0x3C,0x79,0x41,0x9B, - 0xA6,0xBB,0x90,0x92,0x53,0xCC,0x3C,0x84,0x5E,0x14,0x9D,0x3E,0x4F,0x4E,0x80,0x63, - 0x4F,0x11,0xFC,0xDF,0x86,0xE3,0x0B,0x03,0x4C,0x41,0x88,0x91,0xE5,0x51,0x0A,0x77, - 0x12,0x2F,0x9F,0x5B,0xC5,0x19,0x41,0x96,0xA7,0xA1,0x72,0x11,0x46,0x59,0x4C,0xCB, - 0xC7,0x2E,0xF8,0xD5,0x11,0xF8,0x6A,0xB1,0x3A,0x3E,0x37,0x2E,0xA2,0x93,0x75,0xF5, - 0x9B,0xE7,0xFA,0xAC,0xB1,0x9D,0xE2,0x76,0x6C,0x6F,0xDE,0x62,0xEE,0x9F,0x26,0x51, - 0x38,0x17,0xB2,0x39,0x85,0x14,0x42,0x3A,0x68, -}; - -/* subject:/C=US/ST=CA/L=San Francisco/O=Bechtel Corporation/OU=Information Security/CN=IEXTCA-SSL.ibechtel.com */ -/* issuer :/C=US/O=Bechtel Corporation/OU=Information Security/CN=Bechtel External Policy CA 1 */ -/* X509v3 Subject Key Identifier: D9:44:EB:2D:3C:C0:9F:CA:19:3E:3C:6E:23:A0:EF:96:27:9F:DB:42 */ -unsigned char _bechtel_int2b[2242]={ - 0x30,0x82,0x08,0xBE,0x30,0x82,0x07,0xA6,0xA0,0x03,0x02,0x01,0x02,0x02,0x0A,0x61, - 0x12,0xEA,0x4E,0x00,0x04,0x00,0x00,0x00,0x25,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x71,0x31,0x0B,0x30,0x09,0x06,0x03, - 0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A, - 0x13,0x13,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72, - 0x61,0x74,0x69,0x6F,0x6E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14, - 0x49,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x63,0x75, - 0x72,0x69,0x74,0x79,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x13,0x1C,0x42, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20, - 0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x43,0x41,0x20,0x31,0x30,0x1E,0x17,0x0D,0x31, - 0x35,0x30,0x39,0x31,0x38,0x31,0x31,0x35,0x33,0x33,0x32,0x5A,0x17,0x0D,0x32,0x32, - 0x30,0x33,0x31,0x38,0x31,0x37,0x34,0x31,0x31,0x30,0x5A,0x30,0x81,0x91,0x31,0x0B, - 0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04, - 0x07,0x13,0x0D,0x53,0x61,0x6E,0x20,0x46,0x72,0x61,0x6E,0x63,0x69,0x73,0x63,0x6F, - 0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x42,0x65,0x63,0x68,0x74, - 0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x1D, - 0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x13,0x14,0x49,0x6E,0x66,0x6F,0x72,0x6D,0x61, - 0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x31,0x20,0x30, - 0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x49,0x45,0x58,0x54,0x43,0x41,0x2D,0x53, - 0x53,0x4C,0x2E,0x69,0x62,0x65,0x63,0x68,0x74,0x65,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, - 0x9C,0x41,0x41,0x35,0x28,0x9E,0x70,0x93,0xC9,0xAB,0x3B,0x18,0x46,0x19,0xB6,0x98, - 0x4A,0xD8,0xEC,0xE8,0x2C,0x56,0xBC,0xFC,0xF3,0xE4,0xD2,0x62,0x41,0x00,0xC0,0x19, - 0x72,0x6B,0xE6,0xFD,0xE7,0x91,0x94,0x0B,0xAC,0x25,0x9B,0xC1,0x0A,0xBB,0x18,0x52, - 0x1A,0x60,0x09,0xA5,0x32,0x26,0x36,0xBA,0x1D,0x55,0xDA,0xD8,0xB9,0x81,0x2E,0xF9, - 0x9E,0x50,0x19,0xC1,0x3F,0xB3,0xE1,0x99,0xE9,0x9B,0xE7,0x19,0x6E,0x0D,0x50,0xA3, - 0x5B,0xEE,0xE1,0xFF,0x7B,0x79,0x61,0xD0,0xE9,0x8E,0xD8,0xF3,0x65,0x5F,0xF3,0xF6, - 0xFA,0x70,0xAB,0xF1,0x4A,0xE0,0x61,0x6E,0x54,0xDE,0x98,0xE4,0xD5,0x3E,0x57,0x4E, - 0x88,0x93,0x2D,0x65,0x10,0x7C,0x75,0x71,0x88,0x24,0xE7,0x7C,0x37,0x02,0x02,0x53, - 0x01,0x79,0x7A,0xB0,0xB2,0xA2,0xEE,0x4B,0xF0,0x2F,0xB2,0xBD,0x6A,0x04,0x30,0xF7, - 0x0C,0xD9,0x29,0xB3,0x88,0x49,0x96,0xD6,0xB1,0x3B,0xB5,0x52,0x20,0xE8,0xF4,0xBF, - 0xE0,0xF5,0x1D,0x40,0x1F,0xF1,0x86,0xCF,0x1D,0xEB,0xC7,0xFC,0xC1,0xDA,0x7C,0x5F, - 0xAB,0x5C,0xC1,0x59,0x95,0x87,0x72,0x1E,0x86,0x13,0x6D,0xE7,0xF5,0x57,0x28,0xDA, - 0x83,0xBA,0x53,0x13,0xF7,0x32,0xAC,0xDC,0x70,0xD7,0xC7,0xB8,0x48,0x5D,0x84,0x5E, - 0xC6,0x4F,0x6D,0x9B,0x3B,0x79,0xCE,0xE0,0x09,0xE5,0x95,0x15,0xA6,0x5B,0x3A,0xB2, - 0x50,0x22,0x39,0xFE,0x0E,0xB7,0x88,0x48,0xDD,0x4E,0x49,0x86,0x33,0xB3,0xAA,0xD2, - 0x55,0x4C,0x06,0x21,0x9B,0xF1,0xD4,0xA3,0x60,0x05,0x5E,0xF9,0xDA,0x7B,0xC7,0x8F, - 0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x05,0x35,0x30,0x82,0x05,0x31,0x30,0x0B,0x06, - 0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x12,0x06,0x09,0x2B,0x06, - 0x01,0x04,0x01,0x82,0x37,0x15,0x01,0x04,0x05,0x02,0x03,0x02,0x00,0x02,0x30,0x23, - 0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x02,0x04,0x16,0x04,0x14,0xAA, - 0xE3,0xDD,0x81,0x94,0xC5,0x93,0x65,0x65,0x2A,0x65,0xB4,0x7C,0x7B,0xC7,0x2E,0x97, - 0x95,0xA3,0xA0,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xD9,0x44, - 0xEB,0x2D,0x3C,0xC0,0x9F,0xCA,0x19,0x3E,0x3C,0x6E,0x23,0xA0,0xEF,0x96,0x27,0x9F, - 0xDB,0x42,0x30,0x25,0x06,0x03,0x55,0x1D,0x20,0x04,0x1E,0x30,0x1C,0x30,0x0C,0x06, - 0x0A,0x2B,0x06,0x01,0x04,0x01,0xFD,0x52,0x02,0x05,0x01,0x30,0x0C,0x06,0x0A,0x2B, - 0x06,0x01,0x04,0x01,0xFD,0x52,0x02,0x05,0x02,0x30,0x19,0x06,0x09,0x2B,0x06,0x01, - 0x04,0x01,0x82,0x37,0x14,0x02,0x04,0x0C,0x1E,0x0A,0x00,0x53,0x00,0x75,0x00,0x62, - 0x00,0x43,0x00,0x41,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08, - 0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04, - 0x18,0x30,0x16,0x80,0x14,0x07,0x88,0x41,0xE1,0x68,0x1D,0x6B,0x15,0x64,0xEE,0x7C, - 0x4D,0xA1,0x8D,0xFA,0x67,0xC3,0x53,0x59,0x37,0x30,0x61,0x06,0x03,0x55,0x1D,0x1F, - 0x04,0x5A,0x30,0x58,0x30,0x56,0xA0,0x54,0xA0,0x52,0x86,0x50,0x68,0x74,0x74,0x70, - 0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x61,0x75,0x74,0x68,0x2E,0x62,0x65,0x63,0x68, - 0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x65,0x72,0x74,0x44,0x61,0x74,0x61, - 0x2F,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72, - 0x6E,0x61,0x6C,0x25,0x32,0x30,0x50,0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30,0x43, - 0x41,0x25,0x32,0x30,0x31,0x28,0x34,0x29,0x2E,0x63,0x72,0x6C,0x30,0x77,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x6B,0x30,0x69,0x30,0x67,0x06,0x08, - 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x5B,0x68,0x74,0x74,0x70,0x3A,0x2F, - 0x2F,0x63,0x65,0x72,0x74,0x61,0x75,0x74,0x68,0x2E,0x62,0x65,0x63,0x68,0x74,0x65, - 0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x65,0x72,0x74,0x44,0x61,0x74,0x61,0x2F,0x70, - 0x6F,0x6C,0x65,0x78,0x74,0x63,0x61,0x30,0x31,0x5F,0x42,0x65,0x63,0x68,0x74,0x65, - 0x6C,0x25,0x32,0x30,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x25,0x32,0x30,0x50, - 0x6F,0x6C,0x69,0x63,0x79,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x31,0x28,0x34, - 0x29,0x2E,0x63,0x72,0x74,0x30,0x82,0x03,0x42,0x06,0x03,0x55,0x1D,0x1E,0x04,0x82, - 0x03,0x39,0x30,0x82,0x03,0x35,0xA0,0x82,0x03,0x23,0x30,0x12,0xA0,0x10,0x06,0x0A, - 0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x03,0xA0,0x02,0x0C,0x00,0x30,0x02, - 0x81,0x00,0x30,0x0C,0x82,0x0A,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D, - 0x30,0x0D,0x82,0x0B,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x30, - 0x0B,0x82,0x09,0x6D,0x79,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x30,0x0C,0x82,0x0A, - 0x2E,0x6D,0x79,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x30,0x0E,0x82,0x0C,0x69,0x62, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0F,0x82,0x0D,0x2E,0x69, - 0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x82,0x0B,0x62, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0E,0x82,0x0C,0x2E,0x62, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0E,0x82,0x0C,0x62,0x65, - 0x63,0x68,0x74,0x65,0x6C,0x2E,0x61,0x73,0x69,0x61,0x30,0x0F,0x82,0x0D,0x2E,0x62, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x61,0x73,0x69,0x61,0x30,0x0F,0x82,0x0D,0x62, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x2E,0x75,0x6B,0x30,0x10,0x82,0x0E, - 0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x2E,0x75,0x6B,0x30,0x10, - 0x82,0x0E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2E,0x61,0x75, - 0x30,0x11,0x82,0x0F,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D, - 0x2E,0x61,0x75,0x30,0x0D,0x82,0x0B,0x62,0x61,0x63,0x73,0x72,0x6D,0x70,0x2E,0x63, - 0x6F,0x6D,0x30,0x0E,0x82,0x0C,0x2E,0x62,0x61,0x63,0x73,0x72,0x6D,0x70,0x2E,0x63, - 0x6F,0x6D,0x30,0x13,0x82,0x11,0x63,0x6E,0x73,0x74,0x72,0x61,0x6E,0x73,0x69,0x74, - 0x69,0x6F,0x6E,0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12,0x2E,0x63,0x6E,0x73,0x74, - 0x72,0x61,0x6E,0x73,0x69,0x74,0x69,0x6F,0x6E,0x2E,0x63,0x6F,0x6D,0x30,0x11,0x82, - 0x0F,0x74,0x7A,0x62,0x70,0x61,0x72,0x74,0x6E,0x65,0x72,0x73,0x2E,0x63,0x6F,0x6D, - 0x30,0x12,0x82,0x10,0x2E,0x74,0x7A,0x62,0x70,0x61,0x72,0x74,0x6E,0x65,0x72,0x73, - 0x2E,0x63,0x6F,0x6D,0x30,0x13,0x82,0x11,0x63,0x74,0x69,0x2D,0x6D,0x6F,0x74,0x69, - 0x76,0x61,0x63,0x65,0x70,0x2E,0x63,0x6F,0x6D,0x30,0x14,0x82,0x12,0x2E,0x63,0x74, - 0x69,0x2D,0x6D,0x6F,0x74,0x69,0x76,0x61,0x63,0x65,0x70,0x2E,0x63,0x6F,0x6D,0x30, - 0x1C,0x82,0x1A,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x74,0x72,0x61,0x6E,0x73,0x69, - 0x74,0x70,0x61,0x72,0x74,0x6E,0x65,0x72,0x73,0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x82, - 0x1B,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x74,0x72,0x61,0x6E,0x73,0x69,0x74, - 0x70,0x61,0x72,0x74,0x6E,0x65,0x72,0x73,0x2E,0x63,0x6F,0x6D,0x30,0x0C,0x82,0x0A, - 0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6C,0x30,0x0D,0x82,0x0B,0x2E,0x62, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6C,0x30,0x0C,0x82,0x0A,0x62,0x65,0x63, - 0x68,0x74,0x65,0x6C,0x2E,0x61,0x65,0x30,0x0D,0x82,0x0B,0x2E,0x62,0x65,0x63,0x68, - 0x74,0x65,0x6C,0x2E,0x61,0x65,0x30,0x0B,0x82,0x09,0x62,0x62,0x65,0x68,0x63,0x2E, - 0x63,0x6F,0x6D,0x30,0x0C,0x82,0x0A,0x2E,0x62,0x62,0x65,0x68,0x63,0x2E,0x63,0x6F, - 0x6D,0x30,0x62,0xA4,0x60,0x30,0x5E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06, - 0x13,0x02,0x41,0x55,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04,0x08,0x13,0x03,0x51, - 0x4C,0x44,0x31,0x11,0x30,0x0F,0x06,0x03,0x55,0x04,0x07,0x13,0x08,0x42,0x72,0x69, - 0x73,0x62,0x61,0x6E,0x65,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,0x0A,0x13,0x25, - 0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x41,0x75,0x73,0x74,0x72,0x61,0x6C,0x69, - 0x61,0x20,0x50,0x72,0x6F,0x70,0x72,0x69,0x65,0x74,0x61,0x72,0x79,0x20,0x4C,0x69, - 0x6D,0x69,0x74,0x65,0x64,0x30,0x38,0xA4,0x36,0x30,0x34,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x0F,0x30,0x0D,0x06,0x03,0x55,0x04, - 0x07,0x13,0x06,0x4C,0x6F,0x6E,0x64,0x6F,0x6E,0x31,0x14,0x30,0x12,0x06,0x03,0x55, - 0x04,0x0A,0x13,0x0B,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x4C,0x74,0x64,0x30, - 0x54,0xA4,0x52,0x30,0x50,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02, - 0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31, - 0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x07,0x13,0x0D,0x53,0x61,0x6E,0x20,0x46,0x72, - 0x61,0x6E,0x63,0x69,0x73,0x63,0x6F,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A, - 0x13,0x13,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72, - 0x61,0x74,0x69,0x6F,0x6E,0x30,0x02,0x86,0x00,0x30,0x02,0x87,0x00,0xA1,0x0C,0x30, - 0x0A,0x87,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x02,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x03,0x09,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x0E,0x30,0x0D, - 0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01, - 0x01,0x00,0x85,0x1F,0x94,0xB5,0x4E,0x94,0x8F,0xD8,0xEE,0xC5,0x01,0x6A,0x8F,0x19, - 0x82,0x94,0x61,0x60,0x8D,0xB5,0xA7,0xD9,0xD5,0xDB,0xFA,0x33,0x3A,0x8C,0xEB,0xD0, - 0x2E,0x12,0x74,0x16,0x75,0x1A,0x0B,0x8A,0x15,0x27,0x9E,0x96,0x57,0x2C,0x3E,0x54, - 0xF9,0x97,0x4B,0xA1,0xC4,0xFB,0xE8,0x5F,0x2C,0x60,0x80,0xB8,0x1C,0x93,0xB4,0x26, - 0x74,0x4D,0x04,0xD9,0xD9,0xDF,0x7A,0xE8,0xA4,0xD4,0xE5,0xF6,0x56,0x99,0x03,0xA1, - 0x0C,0x2E,0x55,0xFE,0x01,0xA6,0xC7,0x71,0x25,0xC3,0x75,0x8F,0xFA,0x5D,0x6D,0x77, - 0xEC,0x68,0x6A,0xAB,0xFA,0x3E,0xCD,0xAD,0xEB,0xB6,0x68,0x94,0x13,0x22,0x0F,0xB0, - 0x22,0xFD,0x66,0xE8,0x79,0xAC,0xB3,0x05,0x30,0x57,0x36,0x6C,0x67,0x70,0x17,0x3F, - 0xA9,0xFA,0x4B,0x6F,0xCB,0x08,0xAC,0x81,0x67,0x77,0x41,0xF7,0x3B,0x29,0xA5,0x73, - 0xE4,0x3D,0xE4,0x0F,0xC5,0x08,0xB0,0xF9,0x02,0x3B,0x6C,0xCF,0xC9,0x49,0x60,0xAE, - 0xAA,0xD8,0xFD,0x51,0x4D,0x2A,0xBC,0x74,0xDC,0x56,0xC5,0xFD,0xAD,0xBF,0x97,0x8F, - 0x45,0x99,0x8A,0x2B,0x6C,0xA6,0x3C,0x9B,0xD7,0x87,0xC7,0xC7,0x2F,0x7E,0x0C,0x6E, - 0x86,0xC6,0x47,0x35,0x40,0x69,0xA7,0xA2,0x42,0x77,0x1F,0xDD,0x03,0xC8,0x7A,0x44, - 0xB8,0x9E,0x59,0xA8,0x1E,0x87,0x30,0xE0,0x7D,0xF7,0x24,0xE0,0xE0,0xD2,0x72,0x5B, - 0x87,0x01,0x60,0xF1,0x5B,0x84,0x1E,0xAE,0x1D,0xF6,0x2D,0x69,0x9D,0xC0,0xCE,0x3D, - 0x35,0x17,0xDF,0x88,0x65,0xAA,0x1E,0x99,0x3E,0x15,0x36,0xDF,0x44,0xE6,0x8F,0xF3, - 0xD6,0xF6, -}; - -/* subject:/C=US/ST=CA/L=San Francisco/O=Bechtel Corporation/OU=IS&T/CN=MSAN_supplier.bechtel.com */ -/* issuer :/C=US/ST=CA/L=San Francisco/O=Bechtel Corporation/OU=Information Security/CN=IEXTCA-SSL.ibechtel.com */ -/* X509v3 Authority Key Identifier: keyid:76:BB:3A:B1:8F:D3:F9:E8:F2:65:60:C9:3B:9D:EE:BB:ED:46:76:EE */ -unsigned char _bechtel_leaf_a[1441]={ - 0x30,0x82,0x05,0x9D,0x30,0x82,0x04,0x85,0xA0,0x03,0x02,0x01,0x02,0x02,0x0A,0x3F, - 0xF2,0xCF,0x8E,0x00,0x01,0x00,0x00,0x10,0x1D,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,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, - 0x08,0x13,0x02,0x43,0x41,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x07,0x13,0x0D, - 0x53,0x61,0x6E,0x20,0x46,0x72,0x61,0x6E,0x63,0x69,0x73,0x63,0x6F,0x31,0x1C,0x30, - 0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20, - 0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x1D,0x30,0x1B,0x06, - 0x03,0x55,0x04,0x0B,0x13,0x14,0x49,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F, - 0x6E,0x20,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x31,0x20,0x30,0x1E,0x06,0x03, - 0x55,0x04,0x03,0x13,0x17,0x49,0x45,0x58,0x54,0x43,0x41,0x2D,0x53,0x53,0x4C,0x2E, - 0x69,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D, - 0x31,0x35,0x30,0x36,0x32,0x36,0x31,0x36,0x30,0x32,0x30,0x37,0x5A,0x17,0x0D,0x31, - 0x37,0x30,0x36,0x32,0x35,0x31,0x36,0x30,0x32,0x30,0x37,0x5A,0x30,0x81,0x83,0x31, - 0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09, - 0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x16,0x30,0x14,0x06,0x03,0x55, - 0x04,0x07,0x13,0x0D,0x53,0x61,0x6E,0x20,0x46,0x72,0x61,0x6E,0x63,0x69,0x73,0x63, - 0x6F,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x42,0x65,0x63,0x68, - 0x74,0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31, - 0x0D,0x30,0x0B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x04,0x49,0x53,0x26,0x54,0x31,0x22, - 0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x0C,0x19,0x4D,0x53,0x41,0x4E,0x5F,0x73,0x75, - 0x70,0x70,0x6C,0x69,0x65,0x72,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,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,0xAC,0xD5,0x28,0xD6,0x28,0x35,0xB7,0x8D,0x51,0x00,0x02,0xB9,0xAE, - 0x0C,0x1E,0x7D,0xF7,0xA1,0xE3,0x4E,0xC9,0x22,0x8B,0xE5,0x06,0x9A,0x55,0x6E,0xFD, - 0xAA,0x48,0x84,0x68,0x26,0x53,0xE7,0xC7,0x86,0x5C,0x7F,0x93,0xAB,0xE7,0xA0,0x4A, - 0xF2,0x26,0x01,0x21,0x43,0xF0,0x2A,0x38,0x69,0x34,0x29,0x09,0xDC,0x5F,0x19,0x84, - 0x2E,0x92,0x1F,0xB8,0x25,0x53,0x4A,0xFE,0x38,0x4F,0x8F,0x1D,0x5D,0x8F,0x22,0xD2, - 0x2D,0xB6,0xDD,0x81,0x94,0xEE,0x88,0xEE,0x35,0xDA,0x91,0xFA,0x0B,0xA8,0x26,0x35, - 0x50,0x87,0x5C,0xA8,0x34,0xE2,0x90,0x58,0x5C,0x99,0x5F,0xA1,0x81,0x53,0x5D,0x2D, - 0x31,0x97,0x3D,0xA9,0xC5,0x96,0xCB,0x46,0xB9,0xC9,0xAE,0x08,0xB9,0xDC,0x23,0xAE, - 0xCB,0xB7,0x5A,0xB5,0x5F,0x89,0x59,0x36,0x16,0x48,0xFA,0x4A,0x69,0x73,0xA8,0x67, - 0x57,0xF1,0xE6,0xA1,0xAC,0x40,0xF2,0x14,0x7E,0xA2,0x29,0xAB,0x03,0x2E,0xC4,0x53, - 0xD9,0xF9,0x5A,0xEC,0x5A,0xED,0x3D,0x99,0x62,0x68,0xDD,0x41,0xAD,0x13,0x46,0x8E, - 0xDE,0xD9,0x8F,0xCA,0x81,0x7D,0x43,0xF7,0x01,0x8F,0x42,0x1A,0xFD,0x96,0x09,0x93, - 0x14,0xBD,0x77,0x6B,0x43,0xBF,0xA3,0x88,0x2C,0xCC,0xF0,0xDF,0x8A,0xBE,0x11,0xE8, - 0x15,0x10,0x0C,0x87,0x0B,0x23,0xE9,0x60,0xE7,0x61,0xE4,0x5F,0x01,0x7E,0x4E,0x70, - 0x53,0x9A,0x40,0x87,0x8D,0x2A,0x76,0x89,0xE2,0xE7,0x6F,0x08,0xA0,0x34,0xE6,0x20, - 0xB8,0x37,0xF5,0xD1,0x36,0x5F,0x13,0x9A,0x15,0x14,0xCA,0x20,0xF4,0x3E,0xD7,0x72, - 0x2F,0x64,0xA7,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x02,0x01,0x30,0x82,0x01,0xFD, - 0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x3E,0x06, - 0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x07,0x04,0x31,0x30,0x2F,0x06,0x27, - 0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x08,0x81,0xA9,0xF0,0x78,0x83,0xE0,0xED, - 0x66,0x83,0xE9,0x87,0x15,0x85,0xC8,0xA3,0x18,0x86,0x94,0xF0,0x53,0x81,0x4C,0x82, - 0x9D,0xDA,0x36,0x84,0xC6,0xCC,0x1D,0x02,0x01,0x64,0x02,0x01,0x06,0x30,0x1D,0x06, - 0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBF,0x53,0xDA,0xE9,0xE8,0x25,0xCC,0x30, - 0x48,0x2D,0x54,0xB9,0x9E,0xE7,0xC9,0x18,0xC5,0xE1,0x0C,0x4F,0x30,0x1F,0x06,0x03, - 0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x76,0xBB,0x3A,0xB1,0x8F,0xD3,0xF9, - 0xE8,0xF2,0x65,0x60,0xC9,0x3B,0x9D,0xEE,0xBB,0xED,0x46,0x76,0xEE,0x30,0x54,0x06, - 0x03,0x55,0x1D,0x1F,0x04,0x4D,0x30,0x4B,0x30,0x49,0xA0,0x47,0xA0,0x45,0x86,0x43, - 0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x61,0x75,0x74,0x68,0x2E, - 0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x63,0x65,0x72,0x74, - 0x64,0x61,0x74,0x61,0x2F,0x49,0x45,0x58,0x54,0x43,0x41,0x2D,0x53,0x53,0x4C,0x2E, - 0x69,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x28,0x31,0x29,0x2E, - 0x63,0x72,0x6C,0x30,0x77,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04, - 0x6B,0x30,0x69,0x30,0x67,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86, - 0x5B,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x61,0x75,0x74,0x68, - 0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x2F,0x63,0x65,0x72, - 0x74,0x64,0x61,0x74,0x61,0x2F,0x49,0x45,0x58,0x54,0x43,0x41,0x2D,0x53,0x53,0x4C, - 0x2E,0x69,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x5F,0x49,0x45, - 0x58,0x54,0x43,0x41,0x2D,0x53,0x53,0x4C,0x2E,0x69,0x62,0x65,0x63,0x68,0x74,0x65, - 0x6C,0x2E,0x63,0x6F,0x6D,0x28,0x31,0x29,0x2E,0x63,0x72,0x74,0x30,0x13,0x06,0x03, - 0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03, - 0x01,0x30,0x1B,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x0A,0x04,0x0E, - 0x30,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x6D, - 0x06,0x03,0x55,0x1D,0x11,0x04,0x66,0x30,0x64,0x82,0x14,0x73,0x75,0x70,0x70,0x6C, - 0x69,0x65,0x72,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x82, - 0x18,0x73,0x75,0x70,0x70,0x6C,0x69,0x65,0x72,0x32,0x30,0x31,0x32,0x2E,0x62,0x65, - 0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x82,0x16,0x63,0x6F,0x6E,0x74,0x72, - 0x61,0x63,0x74,0x6F,0x72,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x6D,0x82,0x1A,0x63,0x6F,0x6E,0x74,0x72,0x61,0x63,0x74,0x6F,0x72,0x32,0x30,0x31, - 0x32,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x06, - 0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01, - 0x00,0xC5,0x7E,0x87,0xF0,0x3E,0x7C,0x26,0xE6,0x75,0x2E,0xA3,0x25,0x5E,0x44,0xB0, - 0x1C,0xF7,0x91,0x58,0x7A,0x97,0xC5,0x05,0x39,0x08,0x5E,0x5E,0x39,0x7F,0x65,0x6A, - 0x69,0xA3,0x7B,0x13,0xF1,0x7B,0xD7,0x50,0x25,0xD9,0x65,0xC0,0x31,0x6F,0x25,0x2E, - 0xCB,0x69,0xB3,0x1B,0xFB,0x19,0xE9,0x22,0x78,0xF0,0x9A,0x61,0xC4,0x3C,0x52,0x92, - 0xCE,0xFB,0x12,0xBA,0x58,0x44,0xC9,0xFC,0x4B,0x31,0x49,0x10,0x38,0xC7,0x95,0x08, - 0x86,0x43,0xEE,0xCD,0xDB,0x94,0xC7,0xDA,0x98,0x0F,0x00,0x05,0xEB,0xE4,0x98,0x3F, - 0x91,0x7E,0x9B,0x13,0x63,0x63,0x0F,0xD4,0x17,0x4C,0xDD,0x2A,0x94,0xEA,0x41,0x15, - 0x26,0xFF,0xE4,0xC0,0x77,0x50,0x1D,0x96,0x13,0x4A,0xC8,0x3C,0xBC,0xD7,0x05,0x47, - 0x72,0xFD,0x8D,0xBB,0xF3,0x76,0x0E,0x47,0x36,0xA8,0x13,0x8A,0xB0,0xDB,0x7F,0xD3, - 0xD1,0x53,0x09,0xFC,0xBE,0x5E,0xE7,0xB0,0x04,0x08,0x6A,0xC6,0x20,0xCE,0xFA,0x92, - 0xFB,0xE1,0x0A,0xA2,0xDF,0x3A,0x1C,0x58,0x83,0x5B,0x51,0x80,0x0B,0x48,0x05,0x0D, - 0xA2,0x7B,0x10,0xF2,0xF1,0x47,0x51,0x84,0xBA,0x00,0x5F,0x28,0x1F,0xA0,0xC5,0xFA, - 0x12,0xC5,0x8A,0x87,0x03,0xD0,0xA7,0x04,0xC5,0x44,0x10,0x4C,0x59,0x05,0x5E,0x5B, - 0x4A,0x02,0x04,0xC1,0x07,0x16,0x2D,0xA7,0xF5,0xCB,0x32,0xDE,0x8E,0x7A,0x57,0x0E, - 0xE3,0x07,0x3B,0x59,0x92,0x0C,0x20,0x03,0xF0,0xFE,0xC5,0xDB,0xCC,0xCF,0x49,0x11, - 0x05,0x90,0xF4,0xC3,0xA8,0x96,0x9B,0xC0,0x38,0x53,0xE1,0x8C,0xCF,0x65,0xFC,0x27, - 0xBD, -}; - -/* subject:/C=US/ST=CA/L=San Francisco/O=Bechtel Corporation/OU=IS&T/CN=MSAN.becpsn.com */ -/* issuer :/C=US/ST=CA/L=San Francisco/O=Bechtel Corporation/OU=Information Security/CN=IEXTCA-SSL.ibechtel.com */ -/* X509v3 Authority Key Identifier: keyid:D9:44:EB:2D:3C:C0:9F:CA:19:3E:3C:6E:23:A0:EF:96:27:9F:DB:42 */ -unsigned char _bechtel_leaf_b[1684]={ - 0x30,0x82,0x06,0x90,0x30,0x82,0x05,0x78,0xA0,0x03,0x02,0x01,0x02,0x02,0x0A,0x62, - 0xDD,0x4C,0x71,0x00,0x02,0x00,0x00,0x12,0xAA,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,0x0B,0x30,0x09,0x06,0x03,0x55,0x04, - 0x08,0x13,0x02,0x43,0x41,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x07,0x13,0x0D, - 0x53,0x61,0x6E,0x20,0x46,0x72,0x61,0x6E,0x63,0x69,0x73,0x63,0x6F,0x31,0x1C,0x30, - 0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x42,0x65,0x63,0x68,0x74,0x65,0x6C,0x20, - 0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x1D,0x30,0x1B,0x06, - 0x03,0x55,0x04,0x0B,0x13,0x14,0x49,0x6E,0x66,0x6F,0x72,0x6D,0x61,0x74,0x69,0x6F, - 0x6E,0x20,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x31,0x20,0x30,0x1E,0x06,0x03, - 0x55,0x04,0x03,0x13,0x17,0x49,0x45,0x58,0x54,0x43,0x41,0x2D,0x53,0x53,0x4C,0x2E, - 0x69,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x1E,0x17,0x0D, - 0x31,0x35,0x30,0x39,0x31,0x38,0x31,0x34,0x34,0x33,0x30,0x33,0x5A,0x17,0x0D,0x31, - 0x37,0x30,0x39,0x31,0x37,0x31,0x34,0x34,0x33,0x30,0x33,0x5A,0x30,0x79,0x31,0x0B, - 0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06, - 0x03,0x55,0x04,0x08,0x13,0x02,0x43,0x41,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04, - 0x07,0x13,0x0D,0x53,0x61,0x6E,0x20,0x46,0x72,0x61,0x6E,0x63,0x69,0x73,0x63,0x6F, - 0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,0x13,0x42,0x65,0x63,0x68,0x74, - 0x65,0x6C,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x69,0x6F,0x6E,0x31,0x0D, - 0x30,0x0B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x04,0x49,0x53,0x26,0x54,0x31,0x18,0x30, - 0x16,0x06,0x03,0x55,0x04,0x03,0x13,0x0F,0x4D,0x53,0x41,0x4E,0x2E,0x62,0x65,0x63, - 0x70,0x73,0x6E,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,0xD9,0xC9,0x8F,0x11,0x2C,0x09,0x56,0x3D, - 0x07,0x48,0x07,0xD1,0x81,0x86,0x12,0xC1,0xD5,0x1B,0xA0,0x88,0xE1,0x12,0xEA,0x95, - 0x29,0x2B,0xB4,0x20,0xBB,0xFB,0x6A,0xFE,0x8E,0x99,0xA8,0x5D,0xFE,0x5B,0xD9,0xE4, - 0x45,0x87,0xF5,0x26,0x96,0x67,0xC6,0x3A,0xA0,0x40,0xFE,0x63,0x02,0x06,0x29,0xAE, - 0x5D,0xDF,0xC7,0xFE,0xFD,0x92,0x88,0x42,0x93,0xCB,0x34,0xC9,0x77,0xC6,0x2D,0xE5, - 0xB3,0x6F,0x30,0x66,0xF9,0x5C,0xC3,0xD3,0x5E,0x9E,0x47,0x07,0xE5,0x21,0x20,0xF2, - 0xAD,0x97,0x12,0x1D,0xA4,0xA4,0xC7,0xDC,0x7C,0xE8,0xE0,0xBC,0x86,0xE0,0xBD,0x14, - 0x11,0x9B,0x62,0x7B,0xC4,0x56,0x99,0x74,0x1F,0xFE,0x15,0x54,0xB4,0x28,0x0F,0x8E, - 0x06,0x13,0xA5,0xDE,0xB3,0xAB,0x76,0x9C,0xEA,0x49,0x66,0x39,0x64,0x0D,0x7A,0x4C, - 0xB0,0x07,0x5E,0x5F,0x41,0x2E,0x83,0xE1,0x3C,0xD4,0x29,0x1F,0x14,0x81,0xB9,0x03, - 0xD5,0xC3,0xC8,0xB9,0xB0,0xF2,0x0C,0x63,0x3B,0x45,0x50,0xB9,0x7A,0x3B,0x75,0xE8, - 0x85,0x23,0x06,0xB9,0x5E,0x38,0x98,0x52,0x97,0x09,0x70,0xB6,0x64,0x13,0x8E,0x54, - 0x4E,0xB2,0x5B,0x9F,0xCE,0xC3,0x96,0x4E,0x6B,0x23,0xDC,0x5F,0xB4,0x90,0x00,0xE2, - 0xFB,0x73,0x87,0xE1,0x00,0x4E,0x61,0x38,0x89,0xE4,0x8B,0xBE,0xEF,0x04,0x26,0xD2, - 0x02,0x5A,0xD3,0x3E,0x73,0xE5,0xBF,0x55,0xA1,0x12,0x89,0xA0,0x66,0x7D,0x7D,0xBD, - 0xB3,0xDE,0x14,0xCE,0x08,0x1A,0xC0,0x4E,0xC3,0x26,0xBE,0x51,0x78,0x15,0xD4,0xE2, - 0xC8,0x3D,0x4F,0x82,0xBD,0xDB,0x19,0xE3,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x02, - 0xFF,0x30,0x82,0x02,0xFB,0x30,0x0B,0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02, - 0x05,0xA0,0x30,0x3E,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x07,0x04, - 0x31,0x30,0x2F,0x06,0x27,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x15,0x08,0x81,0xA9, - 0xF0,0x78,0x83,0xE0,0xED,0x66,0x83,0xE9,0x87,0x15,0x85,0xC8,0xA3,0x18,0x86,0x94, - 0xF0,0x53,0x81,0x4C,0x82,0x9D,0xDA,0x36,0x84,0xC6,0xCC,0x1D,0x02,0x01,0x64,0x02, - 0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x8D,0x17,0xB9, - 0x2B,0xED,0x8E,0x93,0x41,0xF8,0xD9,0xC9,0xC4,0x38,0x9E,0x9D,0xB0,0x04,0x72,0xF2, - 0xF8,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xD9,0x44, - 0xEB,0x2D,0x3C,0xC0,0x9F,0xCA,0x19,0x3E,0x3C,0x6E,0x23,0xA0,0xEF,0x96,0x27,0x9F, - 0xDB,0x42,0x30,0x54,0x06,0x03,0x55,0x1D,0x1F,0x04,0x4D,0x30,0x4B,0x30,0x49,0xA0, - 0x47,0xA0,0x45,0x86,0x43,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74, - 0x61,0x75,0x74,0x68,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D, - 0x2F,0x63,0x65,0x72,0x74,0x64,0x61,0x74,0x61,0x2F,0x49,0x45,0x58,0x54,0x43,0x41, - 0x2D,0x53,0x53,0x4C,0x2E,0x69,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x6D,0x28,0x32,0x29,0x2E,0x63,0x72,0x6C,0x30,0x77,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x01,0x01,0x04,0x6B,0x30,0x69,0x30,0x67,0x06,0x08,0x2B,0x06,0x01,0x05, - 0x05,0x07,0x30,0x02,0x86,0x5B,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72, - 0x74,0x61,0x75,0x74,0x68,0x2E,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F, - 0x6D,0x2F,0x63,0x65,0x72,0x74,0x64,0x61,0x74,0x61,0x2F,0x49,0x45,0x58,0x54,0x43, - 0x41,0x2D,0x53,0x53,0x4C,0x2E,0x69,0x62,0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63, - 0x6F,0x6D,0x5F,0x49,0x45,0x58,0x54,0x43,0x41,0x2D,0x53,0x53,0x4C,0x2E,0x69,0x62, - 0x65,0x63,0x68,0x74,0x65,0x6C,0x2E,0x63,0x6F,0x6D,0x28,0x32,0x29,0x2E,0x63,0x72, - 0x74,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06, - 0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x1B,0x06,0x09,0x2B,0x06,0x01,0x04,0x01,0x82, - 0x37,0x15,0x0A,0x04,0x0E,0x30,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05, - 0x07,0x03,0x01,0x30,0x82,0x01,0x69,0x06,0x03,0x55,0x1D,0x11,0x04,0x82,0x01,0x60, - 0x30,0x82,0x01,0x5C,0x82,0x19,0x2A,0x2E,0x61,0x70,0x61,0x63,0x2E,0x73,0x74,0x61, - 0x67,0x69,0x6E,0x67,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82, - 0x14,0x2A,0x2E,0x61,0x70,0x61,0x63,0x2E,0x71,0x61,0x2E,0x62,0x65,0x63,0x70,0x73, - 0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x15,0x2A,0x2E,0x61,0x70,0x61,0x63,0x2E,0x64,0x65, - 0x76,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x11,0x2A,0x2E, - 0x61,0x70,0x61,0x63,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82, - 0x19,0x2A,0x2E,0x65,0x61,0x6D,0x73,0x2E,0x73,0x74,0x61,0x67,0x69,0x6E,0x67,0x2E, - 0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x14,0x2A,0x2E,0x65,0x61, - 0x6D,0x73,0x2E,0x71,0x61,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D, - 0x82,0x15,0x2A,0x2E,0x65,0x61,0x6D,0x73,0x2E,0x64,0x65,0x76,0x2E,0x62,0x65,0x63, - 0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x11,0x2A,0x2E,0x65,0x61,0x6D,0x73,0x2E, - 0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x1A,0x2A,0x2E,0x61,0x6D, - 0x65,0x72,0x73,0x2E,0x73,0x74,0x61,0x67,0x69,0x6E,0x67,0x2E,0x62,0x65,0x63,0x70, - 0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x15,0x2A,0x2E,0x61,0x6D,0x65,0x72,0x73,0x2E, - 0x71,0x61,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x16,0x2A, - 0x2E,0x61,0x6D,0x65,0x72,0x73,0x2E,0x64,0x65,0x76,0x2E,0x62,0x65,0x63,0x70,0x73, - 0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x12,0x2A,0x2E,0x61,0x6D,0x65,0x72,0x73,0x2E,0x62, - 0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82,0x14,0x2A,0x2E,0x73,0x74,0x61, - 0x67,0x69,0x6E,0x67,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D,0x82, - 0x0F,0x2A,0x2E,0x71,0x61,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D, - 0x82,0x10,0x2A,0x2E,0x64,0x65,0x76,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63, - 0x6F,0x6D,0x82,0x0C,0x2A,0x2E,0x62,0x65,0x63,0x70,0x73,0x6E,0x2E,0x63,0x6F,0x6D, - 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03, - 0x82,0x01,0x01,0x00,0x24,0xAF,0x6F,0x43,0x26,0x70,0x05,0x1C,0x0D,0x3E,0x1C,0xFE, - 0x42,0x65,0x9B,0x8C,0xF0,0xCD,0x31,0x89,0x2F,0x55,0xAE,0xB4,0xA9,0x0E,0x94,0xA2, - 0x8D,0x32,0x38,0x65,0xC8,0xE3,0x32,0x30,0x47,0xAE,0x05,0x1C,0xB0,0xDC,0x2B,0x47, - 0xB0,0x4E,0x56,0x8E,0x01,0x93,0xAC,0x47,0xAC,0x1C,0x2D,0xF5,0x8A,0xBE,0x35,0x15, - 0x66,0xE8,0x45,0xFC,0x06,0xBD,0x98,0xA3,0x59,0x06,0x0B,0x20,0x8B,0x6C,0xF5,0xAA, - 0x08,0x79,0x16,0x9B,0x0A,0x08,0xE1,0x9E,0xEB,0x98,0xF7,0x82,0x4B,0x54,0x03,0xF5, - 0x22,0x60,0xF3,0x8E,0x3A,0xCB,0x1D,0x62,0x7A,0x65,0xA9,0x35,0xDF,0xCF,0x3F,0x2B, - 0x5B,0x0F,0x96,0x8B,0x70,0xAF,0xBF,0x9E,0x23,0x5F,0x1E,0x60,0x64,0x26,0x22,0xBE, - 0xC6,0xED,0x5E,0xA0,0x37,0xDD,0xDB,0xDF,0x23,0x3E,0xC9,0x4D,0xC8,0x4A,0x23,0xBB, - 0x5B,0x87,0x7E,0x65,0xD5,0x32,0x9A,0x5C,0xA6,0xCA,0x1A,0x7B,0xDF,0x08,0x65,0xD8, - 0x13,0xC6,0x9B,0x7E,0xA7,0x5E,0xCC,0x21,0x38,0x6A,0x3B,0xAE,0x6F,0xE7,0x73,0x74, - 0x56,0x18,0xB2,0xD6,0x39,0xA0,0xDD,0xAE,0x1E,0x8D,0x2D,0xE9,0xB2,0x54,0x45,0x71, - 0x8C,0xCC,0xD4,0xED,0x8C,0xCE,0x3D,0x4D,0xD8,0xCD,0x68,0x25,0x8D,0x0E,0xCE,0xD2, - 0x58,0x18,0x8A,0x1B,0x80,0xB9,0xA7,0xC8,0xFE,0x99,0x9A,0xDF,0x03,0xA7,0x6B,0x23, - 0x1D,0xBF,0xB8,0xF6,0x45,0x33,0x44,0xD1,0x9E,0xC5,0xBE,0x76,0xA4,0xFF,0xD3,0xE1, - 0x83,0x65,0x56,0x31,0x6D,0x3C,0xAA,0xC6,0xAB,0x55,0xD3,0x4E,0x94,0x60,0x3F,0xAE, - 0x5D,0x0C,0x18,0xED, + 0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xCA,0x0B,0xF1,0xE7,0x84, + 0x9B,0xF3,0x4B,0x82,0x32,0x13,0xFC,0x1E,0x67,0x8D,0x16,0x5F,0xAD,0xA6,0x85,0xEB, + 0x7D,0xEF,0x8A,0xF4,0xB6,0x99,0xF8,0x01,0xD4,0x40,0x75,0x97,0xC2,0x10,0x57,0x92, + 0x95,0xA0,0x77,0x7E,0x11,0xA1,0xCA,0x14,0x83,0xC7,0x8F,0x48,0x16,0x38,0x6C,0x42, + 0x50,0x28,0xD0,0x0D,0x02,0x4A,0xF0,0x2F,0xDE,0xDD,0x4D,0xB9,0x74,0x48,0x34,0x4A, + 0xF9,0xEE,0xE4,0xA0,0xEC,0x7D,0xEA,0xF8,0xF7,0xD1,0xD0,0x47,0x41,0xB8,0x24,0x38, + 0xF1,0x54,0x32,0x80,0xAF,0xB7,0x84,0x1B,0xEF,0x64,0xD2,0x6E,0xED,0x78,0x4A,0x26, + 0x2E,0x27,0x89,0xB7,0x73,0x67,0xB8,0xD1,0xDE,0x12,0xFC,0xEB,0xA4,0x94,0xF5,0x2C, + 0xE7,0xF9,0xB5,0xB4,0xE7,0x33,0x99,0xB0,0xC2,0xF3,0x7F,0x32,0xD6,0x62,0xFE,0x57, + 0xD2,0x1A,0x33,0x36,0x38,0xF1,0x1B,0x89,0x93,0xD9,0x17,0x66,0x04,0xFC,0xFF,0x3B, + 0xA5,0xC7,0x16,0xD6,0xB8,0xB8,0x8C,0x47,0x72,0x6D,0x25,0x9E,0x60,0x02,0x9F,0x7A, + 0xA5,0xE7,0xF8,0x4F,0x81,0x85,0x83,0xA2,0xA7,0x13,0x3D,0x36,0xCC,0x82,0xFD,0x19, + 0xC7,0xBE,0xA3,0x54,0xDF,0x4B,0x06,0xA3,0x41,0xCC,0x14,0xEF,0x32,0x76,0xCA,0x1F, + 0xFE,0x65,0xBD,0x7C,0xB1,0xB6,0x37,0x86,0x00,0x4E,0x0A,0x14,0xAB,0xC7,0x7F,0xD2, + 0xE2,0x92,0x6C,0x55,0xDF,0x65,0xEB,0x84,0x93,0x95,0x7A,0x6F,0x1D,0x6C,0x45,0x07, + 0x86,0xA5,0xFE,0xD0,0x4E,0x49,0xAA,0x50,0x20,0xE6,0x0D,0xA8,0x4C,0xF2,0x5E,0x19, + 0xFC,0x6F,0x56,0xDF,0x9A,0xEA,0xA2,0x53,0xDE,0xB1,0xF1,0x02,0x03,0x01,0x00,0x01, + 0xA3,0x81,0x8C,0x30,0x81,0x89,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,0x14,0x06,0x03,0x55,0x1D,0x11, + 0x04,0x0D,0x30,0x0B,0x82,0x09,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30, + 0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x2E,0x37,0xD1,0xEF,0x0D,0x28, + 0xDE,0x61,0xDE,0x79,0x8E,0x37,0x15,0xA9,0xC6,0x8F,0x41,0x8C,0x92,0x3B,0x30,0x1F, + 0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x43,0xD7,0xC9,0x6E,0x6E, + 0x28,0x69,0x32,0xB9,0xB7,0x4F,0x36,0x5A,0xD3,0x51,0x80,0x23,0x41,0x9A,0x01,0x30, + 0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82, + 0x01,0x01,0x00,0x3B,0x68,0x0C,0xA9,0x72,0x90,0xEF,0x66,0xB1,0xE6,0xD0,0x6C,0x77, + 0x04,0x23,0x69,0xEE,0x1F,0xF2,0x0B,0x03,0x92,0xED,0x7D,0x2B,0xFD,0x0D,0xC2,0xC7, + 0x61,0xE6,0x45,0x4C,0x52,0x62,0x3B,0x28,0x48,0x8F,0x71,0xDF,0xD1,0xBE,0x54,0xDE, + 0x71,0xB5,0xE4,0xE4,0xF6,0x51,0x24,0x10,0xEA,0xDC,0x38,0x95,0x76,0x25,0x84,0x2A, + 0xCD,0x2B,0x31,0xC8,0x3C,0x04,0x85,0xA0,0xDA,0x2A,0xF4,0x5D,0xF3,0x8C,0x27,0x9D, + 0x5C,0xDE,0x29,0xDE,0xF1,0x53,0xFF,0x88,0x7E,0x48,0x33,0x2F,0x7D,0xC4,0x0E,0xBA, + 0x05,0xF6,0xE8,0xC9,0x53,0x12,0x2A,0x4F,0x76,0x65,0x1E,0xE8,0x55,0x9A,0xD6,0x69, + 0x61,0x41,0x68,0xBA,0x58,0xA6,0x8B,0x68,0x86,0xF2,0x79,0x85,0xE9,0x46,0xF4,0xC1, + 0x7B,0x7C,0xFD,0xFE,0x15,0x2B,0xCA,0x80,0xCF,0x84,0x28,0x34,0x82,0x20,0xB6,0x15, + 0x5D,0x0F,0xD0,0x3A,0x37,0x22,0xE1,0xF2,0xA1,0x7A,0x74,0x7C,0x37,0x2D,0x2C,0x2A, + 0x50,0x7C,0x18,0x6F,0xF1,0x2F,0xE7,0xAA,0xC4,0xA4,0xE9,0x3D,0xC4,0xD2,0x00,0x5A, + 0xB6,0xFC,0x4C,0x35,0x47,0x22,0xC1,0x2F,0x24,0x01,0x51,0x3F,0x39,0x0D,0x2A,0x48, + 0x8F,0x81,0xE6,0x8E,0xE8,0x21,0x36,0x68,0xE2,0x92,0xC4,0x3F,0xEC,0x15,0x5D,0x35, + 0xE3,0x9D,0xFD,0x33,0x01,0xBD,0x0C,0x5E,0x90,0x68,0x17,0xC6,0xC8,0xFE,0xE3,0x2F, + 0xF7,0xC9,0xCC,0x3A,0x8E,0x2A,0x2B,0x50,0x16,0xD8,0xC1,0xC6,0x3B,0x5B,0x4A,0x30, + 0x65,0xE6,0x30,0xFD,0xED,0x1F,0x0A,0x9E,0x27,0x8D,0x56,0x59,0x7A,0xFB,0xBF,0x52, + 0x99,0x50,0xCE, }; diff --git a/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.m b/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.m new file mode 100644 index 00000000..c1423458 --- /dev/null +++ b/OSX/sec/Security/Regressions/secitem/si-87-sectrust-name-constraints.m @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015-2017 Apple Inc. All Rights Reserved. + */ + +#include +#import + +#include +#include +#include +#include +#include +#include + +#include "shared_regressions.h" + +#include "si-87-sectrust-name-constraints.h" + + +static void tests(void) { + SecCertificateRef root = NULL, subca = NULL, leaf1 = NULL, leaf2 = NULL; + NSArray *certs1 = nil, *certs2, *anchors = nil; + SecPolicyRef policy = SecPolicyCreateBasicX509(); + SecTrustRef trust = NULL; + SecTrustResultType trustResult = kSecTrustResultInvalid; + NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:517282600.0]; // 23 May 2017 + + require_action(root = SecCertificateCreateWithBytes(NULL, _test_root, sizeof(_test_root)), errOut, + fail("Failed to create root cert")); + require_action(subca = SecCertificateCreateWithBytes(NULL, _test_intermediate, sizeof(_test_intermediate)), errOut, + fail("Failed to create subca cert")); + require_action(leaf1 = SecCertificateCreateWithBytes(NULL, _test_leaf1, sizeof(_test_leaf1)), errOut, + fail("Failed to create leaf cert 1")); + require_action(leaf2 = SecCertificateCreateWithBytes(NULL, _test_leaf2, sizeof(_test_leaf2)), errOut, + fail("Failed to create leaf cert 2")); + + certs1 = @[(__bridge id)leaf1, (__bridge id)subca]; + certs2 = @[(__bridge id)leaf2, (__bridge id)subca]; + anchors = @[(__bridge id)root]; + + require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs1, + policy, &trust), errOut, + fail("Failed to create trust for leaf 1")); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, + fail("Failed to set verify date")); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, + fail("Failed to set anchors")); + require_noerr_action(SecTrustEvaluate(trust, &trustResult), errOut, + fail("Failed to evaluate trust")); + is(trustResult, kSecTrustResultUnspecified, "Got wrong trust result for leaf 1"); + + CFReleaseNull(trust); + trustResult = kSecTrustResultInvalid; + + require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs2, + policy, &trust), errOut, + fail("Failed to create trust for leaf 1")); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, + fail("Failed to set verify date")); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, + fail("Failed to set anchors")); + require_noerr_action(SecTrustEvaluate(trust, &trustResult), errOut, + fail("Failed to evaluate trust")); + is(trustResult, kSecTrustResultUnspecified, "Got wrong trust result for leaf 1"); + +errOut: + CFReleaseNull(root); + CFReleaseNull(subca); + CFReleaseNull(leaf1); + CFReleaseNull(leaf2); + CFReleaseNull(policy); + CFReleaseNull(trust); +} + +int si_87_sectrust_name_constraints(int argc, char *const *argv) +{ + plan_tests(2); + tests(); + return 0; +} diff --git a/OSX/sec/Security/Regressions/secitem/si-89-cms-hash-agility.c b/OSX/sec/Security/Regressions/secitem/si-89-cms-hash-agility.c index d611bbfb..1133ca2d 100644 --- a/OSX/sec/Security/Regressions/secitem/si-89-cms-hash-agility.c +++ b/OSX/sec/Security/Regressions/secitem/si-89-cms-hash-agility.c @@ -30,8 +30,7 @@ #include "si-89-cms-hash-agility.h" - -static void tests(void) +static void ios_shim_tests(void) { CFDataRef message = NULL, contentData = NULL, hashAgilityOid = NULL, hashAgilityValue = NULL; SecPolicyRef policy = NULL; @@ -98,11 +97,205 @@ static void tests(void) CFReleaseNull(attrs); } +/* MARK: macOS Shim tests */ +#include +#include + +/* encode test */ +static void encode_test(void) +{ + CMSEncoderRef encoder = NULL; + CFDataRef attributeData = NULL, message = NULL, p12Data = NULL; + CFArrayRef imported_items = NULL; + SecIdentityRef identity = NULL; + CFStringRef password = CFSTR("password"); + CFDictionaryRef options = CFDictionaryCreate(NULL, + (const void **)&kSecImportExportPassphrase, + (const void **)&password, 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionaryRef itemDict = NULL; + + + /* Create encoder */ + ok_status(CMSEncoderCreate(&encoder), "Create CMS encoder"); + ok_status(CMSEncoderSetSignerAlgorithm(encoder, kCMSEncoderDigestAlgorithmSHA256), + "Set digest algorithm to SHA256"); + + /* Load identity and set as signer */ + ok(p12Data = CFDataCreate(NULL, signing_identity_p12, sizeof(signing_identity_p12)), + "Create p12 data"); + ok_status(SecPKCS12Import(p12Data, options, &imported_items), + "Import identity"); + is(CFArrayGetCount(imported_items),1,"Imported 1 items"); + is(CFGetTypeID(CFArrayGetValueAtIndex(imported_items, 0)), CFDictionaryGetTypeID(), + "Got back a dictionary"); + ok(itemDict = CFArrayGetValueAtIndex(imported_items, 0), "Retreive item dictionary"); + is(CFGetTypeID(CFDictionaryGetValue(itemDict, kSecImportItemIdentity)), SecIdentityGetTypeID(), + "Got back an identity"); + ok(identity = (SecIdentityRef) CFRetainSafe(CFDictionaryGetValue(itemDict, kSecImportItemIdentity)), + "Retrieve identity"); + ok_status(CMSEncoderAddSigners(encoder, identity), "Set Signer identity"); + + /* Add signing time attribute for 3 November 2015 */ + ok_status(CMSEncoderAddSignedAttributes(encoder, kCMSAttrSigningTime), + "Set signing time flag"); + ok_status(CMSEncoderSetSigningTime(encoder, 468295000.0), "Set Signing time"); + + /* Add hash agility attribute */ + ok_status(CMSEncoderAddSignedAttributes(encoder, kCMSAttrAppleCodesigningHashAgility), + "Set hash agility flag"); + ok(attributeData = CFDataCreate(NULL, attribute, sizeof(attribute)), + "Create atttribute object"); + ok_status(CMSEncoderSetAppleCodesigningHashAgility(encoder, attributeData), + "Set hash agility data"); + + /* Load content */ + ok_status(CMSEncoderSetHasDetachedContent(encoder, true), "Set detached content"); + ok_status(CMSEncoderUpdateContent(encoder, content, sizeof(content)), "Set content"); + + /* output cms message */ + ok_status(CMSEncoderCopyEncodedContent(encoder, &message), "Finish encoding and output message"); + + /* decode message */ + CMSDecoderRef decoder = NULL; + CFDataRef contentData = NULL; + isnt(message, NULL, "Encoded message exists"); + ok_status(CMSDecoderCreate(&decoder), "Create CMS decoder"); + ok_status(CMSDecoderUpdateMessage(decoder, CFDataGetBytePtr(message), CFDataGetLength(message)), + "Update decoder with CMS message"); + ok(contentData = CFDataCreate(NULL, content, sizeof(content)), "Create detached content"); + ok_status(CMSDecoderSetDetachedContent(decoder, contentData), "Set detached content"); + ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder"); + + + CFReleaseNull(encoder); + CFReleaseNull(p12Data); + CFReleaseNull(imported_items); + CFReleaseNull(identity); + CFReleaseNull(attributeData); + CFReleaseNull(message); + CFReleaseNull(decoder); + CFReleaseNull(contentData); +} + +static void decode_positive_test(void) +{ + CMSDecoderRef decoder = NULL; + CFDataRef contentData = NULL, attrValue = NULL; + SecPolicyRef policy = NULL; + SecTrustRef trust = NULL; + CMSSignerStatus signerStatus; + CFAbsoluteTime signingTime = 0.0; + + /* Create decoder and decode */ + ok_status(CMSDecoderCreate(&decoder), "Create CMS decoder"); + ok_status(CMSDecoderUpdateMessage(decoder, valid_message, sizeof(valid_message)), + "Update decoder with CMS message"); + ok(contentData = CFDataCreate(NULL, content, sizeof(content)), "Create detached content"); + ok_status(CMSDecoderSetDetachedContent(decoder, contentData), "Set detached content"); + ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder"); + + /* Get signer status */ + ok(policy = SecPolicyCreateBasicX509(), "Create policy"); + ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL), + "Copy Signer status"); + is(signerStatus, kCMSSignerValid, "Valid signature"); + + /* Get Hash Agility Attribute value */ + ok_status(CMSDecoderCopySignerAppleCodesigningHashAgility(decoder, 0, &attrValue), + "Copy hash agility attribute value"); + is((size_t)CFDataGetLength(attrValue), sizeof(attribute), "Decoded attribute size"); + is(memcmp(attribute, CFDataGetBytePtr(attrValue), sizeof(attribute)), 0, + "Decoded value same as input value"); + + /* Get Signing Time Attribute value */ + ok_status(CMSDecoderCopySignerSigningTime(decoder, 0, &signingTime), + "Copy signing time attribute value"); + is(signingTime, 468295000.0, "Decoded date same as input date"); + + CFReleaseNull(decoder); + CFReleaseNull(contentData); + CFReleaseNull(policy); + CFReleaseNull(trust); + CFReleaseNull(attrValue); +} + +static void decode_negative_test(void) +{ + CMSDecoderRef decoder = NULL; + CFDataRef contentData = NULL; + SecPolicyRef policy = NULL; + SecTrustRef trust = NULL; + CMSSignerStatus signerStatus; + + /* Create decoder and decode */ + ok_status(CMSDecoderCreate(&decoder), "Create CMS decoder"); + ok_status(CMSDecoderUpdateMessage(decoder, invalid_message, sizeof(invalid_message)), + "Update decoder with CMS message"); + ok(contentData = CFDataCreate(NULL, content, sizeof(content)), "Create detached content"); + ok_status(CMSDecoderSetDetachedContent(decoder, contentData), "Set detached content"); + ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder"); + + /* Get signer status */ + ok(policy = SecPolicyCreateBasicX509(), "Create policy"); + ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL), + "Copy Signer status"); + is(signerStatus, kCMSSignerInvalidSignature, "Invalid signature"); + + CFReleaseNull(decoder); + CFReleaseNull(contentData); + CFReleaseNull(policy); + CFReleaseNull(trust); +} + +static void decode_no_attr_test(void) +{ + CMSDecoderRef decoder = NULL; + CFDataRef contentData = NULL, attrValue = NULL; + SecPolicyRef policy = NULL; + SecTrustRef trust = NULL; + CMSSignerStatus signerStatus; + + /* Create decoder and decode */ + ok_status(CMSDecoderCreate(&decoder), "Create CMS decoder"); + ok_status(CMSDecoderUpdateMessage(decoder, valid_no_attr, sizeof(valid_no_attr)), + "Update decoder with CMS message"); + ok(contentData = CFDataCreate(NULL, content, sizeof(content)), "Create detached content"); + ok_status(CMSDecoderSetDetachedContent(decoder, contentData), "Set detached content"); + ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder"); + + /* Get signer status */ + ok(policy = SecPolicyCreateBasicX509(), "Create policy"); + ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL), + "Copy Signer status"); + is(signerStatus, kCMSSignerValid, "Valid signature"); + + /* Get Hash Agility Attribute value */ + ok_status(CMSDecoderCopySignerAppleCodesigningHashAgility(decoder, 0, &attrValue), + "Copy empty hash agility attribute value"); + is(attrValue, NULL, "NULL attribute value"); + + CFReleaseNull(decoder); + CFReleaseNull(contentData); + CFReleaseNull(policy); + CFReleaseNull(trust); + CFReleaseNull(attrValue); +} + +static void macos_shim_tests(void) { + encode_test(); + decode_positive_test(); + decode_negative_test(); + decode_no_attr_test(); +} + int si_89_cms_hash_agility(int argc, char *const *argv) { - plan_tests(20); + plan_tests(20+24+13+8+10); - tests(); + ios_shim_tests(); + macos_shim_tests(); return 0; } diff --git a/OSX/sec/Security/Regressions/secitem/si-89-cms-hash-agility.h b/OSX/sec/Security/Regressions/secitem/si-89-cms-hash-agility.h index 8fe4bd98..3b245171 100644 --- a/OSX/sec/Security/Regressions/secitem/si-89-cms-hash-agility.h +++ b/OSX/sec/Security/Regressions/secitem/si-89-cms-hash-agility.h @@ -601,4 +601,237 @@ unsigned char valid_no_attr[] = { 0x00 }; +/* + * password: "password" + * localKeyID: 01 AE 1A 61 75 AE 23 D9 11 5C 28 93 A9 E2 49 5E 74 28 4C 08 + * subject=/C=US/ST=California/L=Cupertino/O=Apple, Inc./OU=Security Engineering and Architecture/CN=CMS Test Signer + * issuer=/C=US/ST=California/L=Cupertino/O=Apple, Inc./OU=Security Engineering and Architecture/CN=CMS Test Signer + */ +unsigned char signing_identity_p12[4477] = { + 0x30, 0x82, 0x11, 0x79, 0x02, 0x01, 0x03, 0x30, 0x82, 0x11, 0x3f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x07, 0x01, 0xa0, 0x82, 0x11, 0x30, 0x04, 0x82, 0x11, 0x2c, 0x30, 0x82, 0x11, 0x28, 0x30, 0x82, 0x07, 0x57, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06, 0xa0, 0x82, 0x07, 0x48, 0x30, 0x82, 0x07, 0x44, 0x02, 0x01, 0x00, + 0x30, 0x82, 0x07, 0x3d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0xed, 0xd8, 0x65, 0x57, 0xbb, 0xca, 0x25, + 0x46, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x07, 0x10, 0xc0, 0x1d, 0x0d, 0x5c, 0x7f, 0x3b, 0xbe, 0x20, 0xd4, 0x9a, 0x0d, + 0xaf, 0xb6, 0x4b, 0xc7, 0x7f, 0xa8, 0xa8, 0x3f, 0x6c, 0x96, 0x1c, 0xea, 0x90, 0xd2, 0x79, 0x9f, 0x56, 0x3a, 0x5a, 0x29, + 0x93, 0xff, 0x72, 0x39, 0x9e, 0x41, 0xd9, 0x5a, 0xfc, 0xb5, 0x54, 0x2d, 0x89, 0x60, 0x18, 0xf2, 0xea, 0x8c, 0xeb, 0x7f, + 0xba, 0x87, 0xc6, 0x70, 0x42, 0x25, 0x55, 0x24, 0xc5, 0x4f, 0x26, 0x66, 0x8d, 0x78, 0x44, 0x47, 0x85, 0x36, 0x53, 0x86, + 0xc9, 0x18, 0x83, 0x33, 0x4b, 0x4b, 0x08, 0x2d, 0x7b, 0x68, 0x37, 0x29, 0x4c, 0x20, 0x74, 0xd4, 0x4f, 0xbb, 0x6e, 0x97, + 0x7a, 0xf4, 0xbf, 0xcb, 0x40, 0x26, 0x2d, 0xac, 0x95, 0x82, 0xe0, 0x88, 0xfe, 0x54, 0x80, 0xe9, 0xf5, 0xda, 0x8e, 0x6e, + 0x3a, 0x47, 0x2d, 0xc8, 0xd4, 0xe7, 0x2e, 0xff, 0xec, 0xfa, 0xa5, 0x70, 0xcd, 0x2e, 0x99, 0x26, 0x32, 0xc8, 0x1d, 0x53, + 0x60, 0x1e, 0x6f, 0x68, 0xcb, 0x49, 0xd0, 0xa2, 0xf8, 0x47, 0x70, 0x1b, 0x9e, 0x85, 0xbe, 0x4e, 0x56, 0xb5, 0x8b, 0x66, + 0x45, 0x57, 0xe3, 0xbd, 0x57, 0xed, 0x94, 0x53, 0xf6, 0x72, 0xd7, 0xb7, 0xc6, 0x9f, 0x05, 0xf5, 0x98, 0xb4, 0x13, 0x35, + 0x69, 0x24, 0x94, 0xd9, 0x3d, 0x80, 0xbc, 0xa8, 0xea, 0x78, 0x0c, 0xe0, 0xa2, 0xfe, 0x1b, 0xd2, 0x82, 0x3d, 0x83, 0x34, + 0x76, 0xb4, 0x45, 0xf8, 0x14, 0x09, 0x66, 0x02, 0x68, 0xc3, 0x1b, 0xcb, 0x6c, 0x91, 0x6b, 0x3e, 0xdc, 0x35, 0x68, 0xab, + 0x49, 0x47, 0x6c, 0x60, 0xea, 0xe3, 0xd5, 0x59, 0x82, 0x9c, 0x18, 0xb0, 0x6d, 0x45, 0xc0, 0x2f, 0x58, 0xf1, 0x44, 0x79, + 0xe3, 0xd2, 0xd6, 0x16, 0xbc, 0xde, 0x17, 0xae, 0xf7, 0xea, 0x3c, 0xe4, 0xb4, 0x7b, 0xdf, 0xba, 0x9b, 0xf1, 0xb8, 0xa8, + 0xb0, 0x51, 0xeb, 0xe8, 0xc3, 0xe9, 0x9c, 0x1b, 0x06, 0xdd, 0x89, 0x07, 0x98, 0xf8, 0x01, 0x7f, 0xde, 0x7e, 0x05, 0xa6, + 0x72, 0x0b, 0x3f, 0xf4, 0x7d, 0xca, 0x74, 0x7b, 0xc9, 0x87, 0x0d, 0x35, 0x8b, 0x05, 0x3a, 0x73, 0x04, 0x08, 0x7a, 0x51, + 0x34, 0x29, 0x5b, 0xd8, 0x90, 0x0f, 0xa7, 0xf0, 0x48, 0xfc, 0x9c, 0x74, 0xca, 0xe9, 0x34, 0x75, 0x1c, 0xd1, 0xa6, 0xd1, + 0xfb, 0x9f, 0xc7, 0x82, 0x40, 0x75, 0x87, 0xdd, 0xa2, 0x22, 0xeb, 0x91, 0xd7, 0x85, 0x1a, 0x2c, 0xa7, 0x3d, 0xd5, 0xe4, + 0xca, 0x85, 0x00, 0x33, 0x11, 0x6d, 0x62, 0xa8, 0xb7, 0xd3, 0x45, 0x46, 0xdc, 0xb4, 0xa3, 0xeb, 0xae, 0x5e, 0x8c, 0xc2, + 0x7a, 0x0b, 0x83, 0x98, 0x5a, 0x94, 0x0f, 0x68, 0x61, 0x36, 0x57, 0x6e, 0x94, 0xe0, 0x6d, 0x93, 0x76, 0xa0, 0x5d, 0x3f, + 0x25, 0x8b, 0x3b, 0x46, 0x1e, 0x0c, 0x15, 0x6b, 0x9f, 0x1d, 0xc3, 0x5f, 0x61, 0x42, 0xd5, 0xf8, 0x79, 0xcd, 0xd1, 0x0a, + 0x96, 0xce, 0x49, 0x8a, 0xff, 0x54, 0x46, 0x77, 0x65, 0x37, 0x70, 0xcd, 0x65, 0x6f, 0x3d, 0x49, 0xc1, 0x29, 0x8d, 0x16, + 0xbd, 0x36, 0x47, 0x54, 0xa5, 0x4d, 0x06, 0xfb, 0x33, 0x00, 0x29, 0xd8, 0x31, 0x09, 0x58, 0x12, 0x4c, 0xfe, 0xef, 0x8e, + 0xf9, 0x1e, 0x30, 0xf7, 0x05, 0xb2, 0xd8, 0xd4, 0x7d, 0xae, 0xab, 0x57, 0xb7, 0x46, 0x09, 0xff, 0xca, 0xc7, 0x7b, 0xca, + 0x73, 0xfa, 0xf9, 0x50, 0xa0, 0xb8, 0x09, 0xc2, 0x80, 0x43, 0x0d, 0x99, 0x7f, 0x4e, 0xdf, 0xd5, 0x6c, 0xc4, 0x42, 0x1a, + 0x05, 0xbd, 0x65, 0xf4, 0x57, 0x2a, 0xe5, 0xc4, 0xcb, 0x79, 0x3f, 0x8f, 0x74, 0x93, 0x66, 0x8d, 0x93, 0xda, 0xba, 0x23, + 0x77, 0x3f, 0xad, 0xd3, 0x8b, 0xae, 0xf5, 0xf1, 0x5c, 0xc1, 0xd2, 0x00, 0x3a, 0x60, 0x8e, 0xc3, 0x32, 0xd6, 0x8e, 0xce, + 0x95, 0x24, 0x03, 0x79, 0x03, 0xf2, 0xb8, 0x2a, 0x94, 0xeb, 0x15, 0x97, 0xdc, 0x18, 0x8d, 0xc7, 0xd9, 0xc2, 0x63, 0x69, + 0xfb, 0xf9, 0x8f, 0x05, 0xd3, 0x7c, 0x60, 0x5a, 0x57, 0xe4, 0xa5, 0xc1, 0xdf, 0x1d, 0x11, 0x84, 0x69, 0xba, 0x20, 0xd8, + 0x79, 0xc3, 0x34, 0x3a, 0xb1, 0x63, 0x4c, 0xd2, 0x91, 0x2d, 0x87, 0x1e, 0xec, 0x06, 0xea, 0x35, 0x97, 0x0e, 0x59, 0x54, + 0x83, 0x50, 0x3e, 0xac, 0xf2, 0xea, 0x6c, 0x0c, 0xa0, 0x57, 0xfb, 0xe8, 0x6b, 0xf9, 0xd1, 0x25, 0xc0, 0xa2, 0xb0, 0xa2, + 0xcd, 0xde, 0x2b, 0xa7, 0xb3, 0x40, 0x75, 0x36, 0xf7, 0x20, 0xbe, 0xd7, 0xd1, 0x2e, 0x66, 0xc5, 0x3c, 0xf8, 0x6e, 0xce, + 0xcb, 0x76, 0x7f, 0x1d, 0x32, 0x3b, 0x14, 0x27, 0x9c, 0x9e, 0xa3, 0xeb, 0x0c, 0x2f, 0x71, 0xba, 0x0d, 0xca, 0x27, 0x90, + 0x42, 0xfd, 0xd4, 0x34, 0xb9, 0x96, 0xae, 0xcb, 0xd8, 0xfe, 0x31, 0x62, 0xe8, 0x4c, 0x07, 0x71, 0xb9, 0x0c, 0x9f, 0xe2, + 0x8e, 0x66, 0xc2, 0x39, 0xc5, 0xc3, 0x1c, 0xfd, 0x5e, 0x18, 0x0b, 0xd4, 0x93, 0x3d, 0x98, 0x33, 0xaf, 0x6d, 0xb4, 0x6f, + 0xe6, 0x75, 0x67, 0x62, 0xe7, 0x42, 0xee, 0xc6, 0xf2, 0x2e, 0x21, 0xa9, 0x75, 0xde, 0x0a, 0x8c, 0x39, 0xb7, 0x4b, 0x54, + 0x01, 0xa7, 0xeb, 0x5a, 0x88, 0x79, 0xa8, 0xb3, 0x3f, 0x31, 0x8c, 0x47, 0x08, 0x94, 0x47, 0x52, 0xcf, 0x3c, 0xac, 0xd9, + 0x32, 0x57, 0x4a, 0x18, 0x55, 0x5b, 0x66, 0xdc, 0x89, 0xd2, 0xc6, 0xa1, 0x11, 0x40, 0x19, 0x9c, 0x46, 0x88, 0x21, 0x77, + 0xc1, 0x7f, 0x09, 0xc7, 0xfb, 0x52, 0x92, 0xec, 0x1a, 0xe0, 0xdd, 0x76, 0xb9, 0xfd, 0xa7, 0x8f, 0x61, 0xe3, 0xf0, 0x1b, + 0x4e, 0xdb, 0xa0, 0xde, 0x90, 0xd6, 0x49, 0xea, 0xe9, 0x86, 0xc6, 0x5d, 0xac, 0xd0, 0xc2, 0xc5, 0x01, 0xcb, 0x3f, 0xcb, + 0xf0, 0x62, 0x90, 0xa1, 0x17, 0x4b, 0x72, 0x5c, 0xc8, 0xe9, 0x24, 0x93, 0xda, 0x5c, 0x75, 0x24, 0x96, 0x35, 0x54, 0xf4, + 0xfa, 0xc8, 0x27, 0xe1, 0xdd, 0x32, 0xda, 0x2f, 0x2b, 0x7d, 0xf6, 0xd8, 0x0b, 0xf2, 0xca, 0xb5, 0xee, 0x8a, 0xcf, 0xb6, + 0x26, 0x71, 0x65, 0x85, 0xfe, 0x8c, 0x37, 0xf1, 0x17, 0x6b, 0x5e, 0x8a, 0xee, 0xb4, 0xc7, 0x0a, 0xff, 0xb2, 0x9a, 0x72, + 0xe5, 0x85, 0xf3, 0xc0, 0xf9, 0x84, 0xbc, 0xe0, 0x18, 0x3c, 0x12, 0x0c, 0xa1, 0xe9, 0x10, 0xd4, 0x3b, 0x1a, 0x21, 0x35, + 0xc6, 0x06, 0x93, 0xa0, 0xdf, 0x0d, 0x68, 0xa3, 0xf1, 0x06, 0xd9, 0xed, 0xb7, 0xa7, 0xba, 0xb0, 0x22, 0xc2, 0x0b, 0x6b, + 0x70, 0x50, 0xf5, 0x49, 0x9a, 0x4f, 0x99, 0xaa, 0x1e, 0x9c, 0xa6, 0xf3, 0x99, 0x3a, 0xfd, 0x3b, 0xd2, 0xeb, 0xce, 0x1e, + 0x72, 0x62, 0x99, 0xc0, 0x1e, 0x2b, 0x09, 0x75, 0x4a, 0xfb, 0xc8, 0x26, 0xcf, 0x76, 0xa2, 0x0e, 0xef, 0xf4, 0xa8, 0x70, + 0x31, 0xd8, 0xa1, 0x22, 0x62, 0xcc, 0x9f, 0xd5, 0xa3, 0x55, 0xc2, 0x78, 0xd7, 0x27, 0xfc, 0x3c, 0x53, 0xe8, 0xeb, 0x7e, + 0x7a, 0x27, 0xcf, 0x6d, 0x52, 0xb5, 0x9a, 0x2b, 0x49, 0x8d, 0x3f, 0x89, 0x80, 0x1a, 0x5c, 0x39, 0xe7, 0x53, 0xb3, 0xf3, + 0x33, 0x97, 0xcf, 0x7d, 0xfb, 0x8e, 0x19, 0xf4, 0x72, 0xeb, 0xe7, 0xdf, 0xb1, 0xe3, 0xc1, 0x6c, 0x7f, 0x17, 0x89, 0x34, + 0x4f, 0x45, 0x0f, 0xc5, 0xfc, 0x15, 0xb3, 0x3f, 0xc6, 0xdc, 0x25, 0xa6, 0xda, 0x28, 0x85, 0x5d, 0x25, 0x02, 0x78, 0x74, + 0xd9, 0x74, 0xb8, 0x65, 0x48, 0x3a, 0x8a, 0x2a, 0xd5, 0xa9, 0xb8, 0x7f, 0xaa, 0x9d, 0xe7, 0xaf, 0xbd, 0xdf, 0xfd, 0x00, + 0x67, 0xab, 0x39, 0xe1, 0x2c, 0x3d, 0xd1, 0x5c, 0x9b, 0x61, 0x2b, 0x51, 0xdc, 0x87, 0x19, 0x6c, 0xa0, 0x12, 0xd4, 0x60, + 0xed, 0x94, 0xe9, 0xeb, 0x4e, 0x51, 0xd8, 0x50, 0xcb, 0x97, 0x8a, 0x20, 0x21, 0xdf, 0xe9, 0x2c, 0xd2, 0xe2, 0x04, 0x14, + 0xaf, 0x7b, 0x7e, 0xd6, 0xeb, 0x1d, 0x25, 0x09, 0x98, 0x8e, 0x9e, 0x56, 0xf8, 0x7d, 0xfc, 0x0f, 0xbf, 0xd2, 0x6b, 0xbc, + 0xab, 0xed, 0xca, 0x43, 0x6d, 0x28, 0xbe, 0xd5, 0x20, 0x44, 0xcb, 0x6b, 0xbc, 0x80, 0x5a, 0x82, 0x13, 0x50, 0xbd, 0xda, + 0x18, 0x10, 0xac, 0xae, 0x56, 0xb9, 0x46, 0xc5, 0xa2, 0xca, 0xb2, 0x03, 0xf0, 0x57, 0xfe, 0xcd, 0x9a, 0x1b, 0x81, 0x6a, + 0x10, 0x51, 0x2e, 0x88, 0x30, 0x57, 0x3c, 0xfe, 0x7c, 0x56, 0x0c, 0x00, 0x89, 0x5c, 0x21, 0x57, 0x19, 0x96, 0x85, 0x98, + 0xeb, 0x43, 0x71, 0x0d, 0x8a, 0x35, 0xc3, 0xae, 0x36, 0x59, 0x72, 0x97, 0x12, 0x6d, 0xcd, 0x28, 0x64, 0x17, 0x9e, 0xe7, + 0x2c, 0x28, 0xfd, 0x32, 0xa8, 0x10, 0x67, 0x4e, 0xc0, 0x14, 0x21, 0x7c, 0x36, 0x20, 0xe9, 0x46, 0x68, 0x62, 0xc1, 0xff, + 0xb0, 0xdf, 0xaa, 0x87, 0xff, 0x94, 0xa4, 0xf3, 0xb3, 0xc8, 0x53, 0x57, 0x18, 0x92, 0x15, 0xc7, 0x78, 0x2d, 0x91, 0xba, + 0xb3, 0x1f, 0x06, 0x13, 0x79, 0x21, 0x86, 0x1d, 0xa2, 0x38, 0x2c, 0xda, 0x35, 0x31, 0xbb, 0x04, 0x65, 0xa3, 0x01, 0xa6, + 0x63, 0xa4, 0x4a, 0xa2, 0xc1, 0xad, 0x04, 0xc1, 0xfa, 0x78, 0xe1, 0xb6, 0x50, 0x46, 0xab, 0xad, 0x1c, 0xcf, 0xf4, 0xe5, + 0xba, 0xa5, 0xe2, 0x91, 0x29, 0x4b, 0xa1, 0xc6, 0x4b, 0x30, 0xa5, 0x31, 0x02, 0xe9, 0xd0, 0x50, 0x72, 0x2c, 0x8e, 0xbd, + 0xb2, 0x12, 0xd9, 0x4f, 0x7c, 0x87, 0x4b, 0xa0, 0x45, 0x71, 0x0c, 0x23, 0x37, 0x6b, 0x60, 0xd7, 0x9f, 0x19, 0xe8, 0x0b, + 0x85, 0x57, 0x72, 0xb6, 0xbb, 0x20, 0x23, 0xd3, 0x7d, 0x9a, 0x9b, 0x9a, 0x05, 0x46, 0x5c, 0xf5, 0x02, 0xf1, 0x56, 0x00, + 0xc2, 0x05, 0x85, 0x48, 0xd3, 0x8d, 0x8e, 0xe1, 0xcb, 0xc5, 0x83, 0x1f, 0x78, 0xd0, 0xc5, 0xb1, 0xdf, 0x80, 0x9d, 0x04, + 0xe7, 0xac, 0xd1, 0x68, 0x1a, 0x19, 0x18, 0x16, 0xfa, 0x3a, 0xe2, 0xd2, 0x30, 0x08, 0x17, 0x4d, 0x50, 0x2b, 0xd4, 0xa3, + 0xbe, 0x98, 0x5f, 0xe0, 0xcf, 0xed, 0x7d, 0x74, 0x94, 0xd1, 0xb2, 0x77, 0xbc, 0x72, 0xbc, 0xf5, 0xc7, 0x82, 0x26, 0x53, + 0x14, 0xcc, 0xf9, 0xf7, 0x71, 0xea, 0x97, 0xaa, 0xbf, 0x21, 0x46, 0x59, 0x2c, 0x9a, 0xc4, 0xeb, 0xa3, 0x4a, 0x97, 0x91, + 0x11, 0xf1, 0x01, 0x19, 0x7e, 0xb1, 0xb2, 0x63, 0x0d, 0xf0, 0x5d, 0xaf, 0x53, 0xdf, 0x4d, 0xa1, 0x90, 0xe5, 0x12, 0x82, + 0x33, 0x6f, 0x1d, 0x73, 0xdf, 0xdb, 0x1f, 0x18, 0xa0, 0x72, 0xc1, 0xd6, 0xa7, 0x4d, 0xb2, 0x3e, 0x24, 0xb7, 0xa7, 0x76, + 0x15, 0x46, 0x22, 0x48, 0x49, 0x55, 0xd1, 0xfb, 0x66, 0x32, 0x02, 0xa9, 0xfc, 0xbe, 0x7e, 0x16, 0xcf, 0xac, 0x32, 0xbc, + 0xdb, 0xd5, 0xd8, 0xa3, 0x23, 0x6a, 0x10, 0xa6, 0x37, 0x03, 0xf6, 0x2a, 0xde, 0xba, 0xde, 0x2d, 0x7d, 0xef, 0x1d, 0xb9, + 0xf3, 0x93, 0xd4, 0xf2, 0x13, 0xf4, 0x9c, 0x5a, 0x32, 0xba, 0x5f, 0xef, 0x7b, 0xd0, 0x6b, 0xd7, 0x91, 0x6d, 0x7b, 0xe1, + 0x4d, 0xf2, 0x8c, 0xe7, 0xf1, 0x66, 0xb9, 0xad, 0xc6, 0x30, 0x08, 0x9e, 0x51, 0xd4, 0x39, 0x87, 0x09, 0xfa, 0x6b, 0x7a, + 0xa7, 0x5f, 0x1a, 0x9c, 0x98, 0xc5, 0x76, 0xb0, 0x71, 0x76, 0xf5, 0xfc, 0x56, 0x88, 0x1c, 0xca, 0xee, 0x76, 0xd4, 0x2c, + 0xa6, 0x64, 0x80, 0x59, 0x12, 0x8c, 0x08, 0xce, 0x83, 0xb3, 0xd9, 0x68, 0x59, 0xc1, 0x26, 0x86, 0xa7, 0x80, 0x10, 0xbc, + 0x41, 0x28, 0x6c, 0x45, 0xd4, 0x6d, 0x15, 0xd0, 0x76, 0x44, 0x0e, 0xcf, 0xc1, 0xde, 0xef, 0x7a, 0x97, 0x36, 0x8f, 0x0d, + 0x8a, 0xf5, 0x45, 0xde, 0xae, 0x61, 0xd0, 0x55, 0xe9, 0x8d, 0x62, 0xfd, 0xa3, 0x0d, 0x44, 0x0f, 0x49, 0xb6, 0x5a, 0xa4, + 0xaa, 0x03, 0x4e, 0x60, 0x35, 0x53, 0x86, 0x9e, 0xec, 0x75, 0xd9, 0x0a, 0xca, 0x14, 0xe3, 0x1b, 0x06, 0x05, 0xd6, 0x8f, + 0x4f, 0x11, 0xb3, 0x13, 0xdd, 0x26, 0x35, 0xbd, 0x56, 0x55, 0xf1, 0x43, 0x89, 0x5e, 0x5b, 0x25, 0x4d, 0xa8, 0x09, 0xdd, + 0xf2, 0x6d, 0x9e, 0x8c, 0xcd, 0xa2, 0xde, 0x84, 0x00, 0x6a, 0x0a, 0xc6, 0x92, 0x30, 0x82, 0xcf, 0xa4, 0x31, 0x67, 0xbd, + 0xd4, 0x36, 0x6a, 0x8b, 0xc6, 0x33, 0xdf, 0x8b, 0xde, 0x33, 0x01, 0x7b, 0x9d, 0xbf, 0xe9, 0x12, 0x35, 0x8a, 0x97, 0x07, + 0x72, 0x0b, 0x6b, 0x60, 0xe6, 0x1e, 0x7d, 0x78, 0x22, 0x9f, 0xbf, 0x66, 0x8e, 0x02, 0xf4, 0xdc, 0xa1, 0xb0, 0x42, 0x73, + 0x86, 0xca, 0x34, 0xf0, 0xa7, 0x2e, 0x15, 0x84, 0xa4, 0x60, 0xa8, 0x47, 0x05, 0x80, 0x03, 0x27, 0xa8, 0x04, 0x03, 0xfe, + 0x47, 0xd4, 0xeb, 0x33, 0x27, 0xbf, 0x89, 0xff, 0x4c, 0xd9, 0x27, 0x0e, 0xd0, 0xa9, 0x41, 0x8b, 0xd5, 0x7c, 0xc4, 0x14, + 0x7a, 0x9c, 0xb3, 0xaa, 0x13, 0x32, 0xa4, 0x67, 0xd5, 0x95, 0xdc, 0x4a, 0x3d, 0xf2, 0x54, 0xd7, 0x02, 0xf8, 0x06, 0x7b, + 0x1d, 0x9a, 0xa4, 0x53, 0xa0, 0x9c, 0x76, 0x7d, 0xf4, 0x01, 0xa3, 0x4b, 0xb2, 0x8b, 0x44, 0x85, 0xf6, 0x80, 0x99, 0x2f, + 0x77, 0x08, 0x20, 0xea, 0x08, 0xf8, 0x14, 0x76, 0xfe, 0xa0, 0x5a, 0xf9, 0x1f, 0x87, 0x03, 0xff, 0x8d, 0x1f, 0x5d, 0x02, + 0x64, 0x8a, 0xf4, 0xa5, 0x8c, 0xb7, 0x0a, 0x34, 0x68, 0xaa, 0xca, 0xc8, 0xe1, 0x78, 0x9b, 0xd3, 0x6c, 0x5c, 0x07, 0x99, + 0xc1, 0x10, 0x3f, 0x77, 0x0c, 0x45, 0xa2, 0xda, 0xda, 0xab, 0x7c, 0xf0, 0x90, 0x12, 0xa2, 0x7c, 0x84, 0x30, 0x82, 0x09, + 0xc9, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x09, 0xba, 0x04, 0x82, 0x09, 0xb6, + 0x30, 0x82, 0x09, 0xb2, 0x30, 0x82, 0x09, 0xae, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, + 0x02, 0xa0, 0x82, 0x09, 0x76, 0x30, 0x82, 0x09, 0x72, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0xd3, 0x5d, 0xa8, 0x14, 0xbc, 0x7a, 0xaa, 0x5f, 0x02, 0x02, 0x08, 0x00, 0x04, + 0x82, 0x09, 0x50, 0xaf, 0xe9, 0x63, 0xb6, 0x05, 0x8b, 0x48, 0xe1, 0x11, 0xd0, 0x37, 0x1d, 0x48, 0x71, 0x22, 0x70, 0xdc, + 0xbd, 0xca, 0x98, 0x5d, 0x72, 0xca, 0x38, 0xdc, 0x2e, 0x4f, 0xd4, 0x71, 0xd3, 0xac, 0xf3, 0x0c, 0xcf, 0x78, 0x4e, 0x5c, + 0x63, 0x35, 0xaa, 0xac, 0x5a, 0xf0, 0xef, 0x6c, 0xc0, 0x89, 0x28, 0xc4, 0x64, 0xec, 0x5c, 0x92, 0x72, 0xbc, 0xe5, 0x30, + 0xe9, 0x5c, 0x35, 0xff, 0xe0, 0xb1, 0x1f, 0xc6, 0x37, 0x50, 0xb7, 0x3d, 0x94, 0x28, 0xbd, 0x3b, 0xf0, 0xd9, 0x5c, 0xb1, + 0x45, 0x93, 0xde, 0x41, 0x5b, 0x12, 0xba, 0xfa, 0x27, 0x49, 0x6b, 0xb7, 0x9a, 0xa6, 0x46, 0x8e, 0xe3, 0x15, 0x1b, 0x7f, + 0x2c, 0x91, 0x2e, 0x33, 0xf3, 0xef, 0x7a, 0x9b, 0x9d, 0xa8, 0x82, 0x95, 0xa0, 0x7e, 0x43, 0xd6, 0x9d, 0xe2, 0xfb, 0xb1, + 0xb0, 0xcf, 0xbd, 0xb6, 0x9b, 0x55, 0x4c, 0xc8, 0x4a, 0xc7, 0x82, 0xeb, 0x3d, 0x09, 0x8d, 0x85, 0x6f, 0x8c, 0x42, 0x6d, + 0x10, 0x7d, 0x77, 0x57, 0x29, 0x00, 0xe2, 0xd8, 0x2f, 0xed, 0x7c, 0x10, 0x5b, 0x03, 0xfa, 0x60, 0x34, 0xc9, 0x63, 0x25, + 0x4d, 0x02, 0x77, 0x8f, 0x7f, 0x4b, 0x53, 0xe4, 0x8d, 0x1e, 0x4e, 0x2c, 0x0c, 0x7f, 0x0e, 0x48, 0x4b, 0xcd, 0xc8, 0x6a, + 0xfa, 0xd3, 0x9f, 0x6f, 0x20, 0x4e, 0x2c, 0x77, 0x2a, 0x84, 0x5e, 0x6c, 0xc3, 0x57, 0xba, 0x97, 0xa7, 0xa8, 0xcb, 0x6f, + 0x22, 0xc1, 0xa7, 0x61, 0xf7, 0x7e, 0x7a, 0xae, 0xda, 0xbd, 0x3a, 0xea, 0xb3, 0x46, 0x54, 0x8d, 0x46, 0x48, 0x1f, 0xf3, + 0x5c, 0xaa, 0x2e, 0x44, 0xe1, 0x83, 0x69, 0x45, 0x30, 0x02, 0x49, 0x63, 0xa6, 0xdd, 0xf0, 0x25, 0xce, 0x81, 0xab, 0x66, + 0x20, 0x04, 0x12, 0x2f, 0x94, 0x2f, 0x8f, 0xf9, 0x88, 0xea, 0x5b, 0xba, 0x87, 0xd7, 0xbe, 0x63, 0x2e, 0xb4, 0xa4, 0x15, + 0xe8, 0x56, 0x9e, 0xb5, 0x7b, 0x27, 0xf8, 0x06, 0xfd, 0xf5, 0x21, 0x93, 0x2b, 0x64, 0xb0, 0xe2, 0x31, 0xb3, 0x19, 0xe0, + 0x6b, 0x10, 0x8c, 0xa5, 0xa5, 0x38, 0x27, 0x78, 0xc9, 0x9c, 0x01, 0xa7, 0x42, 0x22, 0x3d, 0xf8, 0x8c, 0x23, 0x46, 0xc5, + 0x4e, 0x47, 0xa5, 0x9e, 0xd7, 0xa5, 0x50, 0x24, 0x02, 0x30, 0xe9, 0x15, 0x3e, 0x17, 0xba, 0x2c, 0xf2, 0x5e, 0xc7, 0x01, + 0x25, 0x9a, 0x74, 0x73, 0x5c, 0x5e, 0xca, 0x01, 0xe2, 0x58, 0x96, 0x47, 0x3e, 0x4c, 0xb9, 0x0f, 0x95, 0xbf, 0xf3, 0xc4, + 0x24, 0x98, 0x6c, 0xc5, 0x40, 0xd2, 0xf3, 0x88, 0x62, 0xb0, 0x25, 0x54, 0xb5, 0xf6, 0x2b, 0xfd, 0xf5, 0x6a, 0x6d, 0x15, + 0xb2, 0x18, 0x7d, 0xef, 0x3e, 0x66, 0x7d, 0x38, 0x4c, 0xda, 0xc9, 0x1a, 0xcd, 0x40, 0x2a, 0xc6, 0x7b, 0x2e, 0x8a, 0x15, + 0xa7, 0xae, 0x99, 0xf5, 0x93, 0x39, 0x20, 0xd2, 0xd8, 0xfd, 0x1f, 0x87, 0x2e, 0xa0, 0xcd, 0x95, 0xa2, 0xd7, 0xd0, 0x48, + 0xf7, 0x6e, 0x81, 0x91, 0x1c, 0x37, 0x8a, 0x28, 0x6f, 0x22, 0x7b, 0x37, 0x69, 0x30, 0x3a, 0x64, 0x6e, 0x4a, 0x5f, 0x0a, + 0xa6, 0xd7, 0x53, 0xce, 0x1d, 0x60, 0x88, 0xa5, 0x0b, 0xde, 0xf5, 0x01, 0x3a, 0x20, 0xfa, 0xd6, 0x08, 0xdf, 0x83, 0x39, + 0x2e, 0xb8, 0x3a, 0x91, 0xec, 0x39, 0x47, 0xaa, 0x66, 0x8a, 0xb4, 0x35, 0x70, 0xaf, 0x88, 0x24, 0xb2, 0xc3, 0xdc, 0x7c, + 0xd0, 0x8f, 0x93, 0x0d, 0xa4, 0x53, 0xf1, 0x55, 0x92, 0xae, 0xd9, 0xeb, 0x31, 0xa0, 0x68, 0x29, 0xf5, 0xdb, 0x2f, 0xd1, + 0xa3, 0xfe, 0x34, 0x2f, 0xcd, 0x64, 0x0c, 0x11, 0x13, 0x14, 0x50, 0xeb, 0x27, 0x56, 0xda, 0xc0, 0x30, 0x3a, 0x8c, 0x92, + 0xb3, 0xb8, 0xc8, 0xb7, 0x19, 0xea, 0x4c, 0x74, 0xb9, 0x95, 0x46, 0x9f, 0xc0, 0x63, 0xfd, 0x72, 0x35, 0x0b, 0xb9, 0x1d, + 0x1e, 0x85, 0xf8, 0xf9, 0x23, 0xf7, 0x42, 0xe2, 0xf4, 0x67, 0xbf, 0x3d, 0x30, 0x4b, 0x6a, 0xf2, 0x44, 0x2f, 0xcb, 0x6f, + 0xe9, 0x73, 0x4b, 0x8f, 0x09, 0x29, 0x69, 0xcd, 0x8d, 0xcd, 0xc7, 0xd4, 0xa2, 0x0c, 0x6a, 0xc4, 0x9a, 0x33, 0xe2, 0x64, + 0x5f, 0x07, 0xf2, 0xb6, 0xf8, 0x86, 0x7f, 0x05, 0x04, 0xf1, 0x1d, 0x9d, 0xd1, 0xc8, 0x3c, 0x16, 0x6e, 0x18, 0x96, 0x15, + 0x33, 0xda, 0x84, 0xb6, 0xfd, 0x13, 0x29, 0x2f, 0x5e, 0xa0, 0x0e, 0xaa, 0xf6, 0x24, 0xb4, 0xa5, 0x48, 0x01, 0x02, 0x07, + 0x31, 0x98, 0x0d, 0x9c, 0x65, 0x59, 0x68, 0x61, 0x22, 0xdb, 0x64, 0x16, 0x05, 0xae, 0xd8, 0x64, 0x5f, 0xba, 0x51, 0xab, + 0x5e, 0xe0, 0xbe, 0x3d, 0x29, 0x67, 0x20, 0x94, 0x63, 0xfe, 0xc7, 0x90, 0x30, 0xc9, 0x43, 0xf1, 0xce, 0x9c, 0x53, 0x01, + 0x2c, 0x64, 0x56, 0x85, 0xb7, 0x3b, 0xa4, 0x05, 0x5d, 0x88, 0xdf, 0x44, 0xda, 0x18, 0xf3, 0x8c, 0xdb, 0xae, 0xd2, 0x9f, + 0xee, 0x4e, 0x08, 0x17, 0xf9, 0xd8, 0xe0, 0xc9, 0x7d, 0xa5, 0xad, 0x79, 0x06, 0x1b, 0x8c, 0x92, 0xe7, 0x53, 0xdf, 0xde, + 0xa3, 0xa5, 0x84, 0x1d, 0xd8, 0x75, 0x35, 0x78, 0x32, 0x55, 0x6f, 0x4f, 0x29, 0x34, 0x4e, 0x6f, 0x32, 0x16, 0xe4, 0xfd, + 0xbc, 0xf5, 0x76, 0x99, 0xf3, 0x48, 0x5b, 0xa0, 0x65, 0xb2, 0xef, 0xeb, 0x58, 0x6c, 0xf4, 0x1e, 0x97, 0x34, 0xee, 0xf9, + 0x74, 0xe2, 0x94, 0xc0, 0xf2, 0xf5, 0x0b, 0x97, 0x40, 0xce, 0x25, 0xd6, 0xe5, 0xdf, 0x0b, 0x3b, 0x6b, 0xf3, 0x38, 0x28, + 0xc3, 0xa6, 0x30, 0xa5, 0x22, 0x3c, 0xb0, 0xbd, 0x4d, 0xd5, 0x79, 0x25, 0xb9, 0xb2, 0xb4, 0xc4, 0x31, 0x62, 0x0b, 0xe7, + 0x73, 0x4e, 0xf9, 0xa7, 0x57, 0xdf, 0x33, 0x0e, 0xf0, 0xb9, 0x3b, 0x6d, 0xff, 0x6b, 0x11, 0xb0, 0x90, 0x10, 0x2a, 0x7b, + 0xb5, 0x0b, 0x41, 0x17, 0x0b, 0x12, 0xc7, 0x61, 0xef, 0xb1, 0x9b, 0x57, 0x3a, 0x01, 0x55, 0x91, 0xe3, 0xd5, 0xc8, 0xd5, + 0xeb, 0x26, 0x90, 0x2b, 0x67, 0x5b, 0xc2, 0x0b, 0xad, 0x6f, 0x26, 0x3a, 0xf5, 0x45, 0xb2, 0xd7, 0x6a, 0x78, 0xaa, 0x43, + 0xd0, 0xdb, 0x53, 0x6f, 0x1a, 0x7a, 0x5c, 0x92, 0xe1, 0xb7, 0xe5, 0xad, 0xda, 0xac, 0x3b, 0x5a, 0x20, 0x06, 0xe1, 0x56, + 0xf0, 0x55, 0x66, 0x64, 0x42, 0xd4, 0xe4, 0x77, 0x3b, 0xa5, 0x60, 0x8d, 0x5b, 0x24, 0x7a, 0x2a, 0xb9, 0xe2, 0x2f, 0xc6, + 0x02, 0xd1, 0x21, 0xf3, 0x08, 0xbd, 0x7b, 0xf4, 0x44, 0x47, 0x00, 0xd2, 0xca, 0x3c, 0x80, 0x37, 0xb0, 0xf2, 0x3d, 0x07, + 0x87, 0xbd, 0xe8, 0x59, 0x01, 0x17, 0x7b, 0xb3, 0x1b, 0xc3, 0xce, 0x45, 0x77, 0x3c, 0x0e, 0xdd, 0xac, 0x38, 0xf1, 0x5e, + 0xde, 0x5e, 0xdd, 0xad, 0xf2, 0xc9, 0x0f, 0xed, 0xec, 0xe5, 0x00, 0x8b, 0x61, 0xf4, 0x62, 0xd5, 0x58, 0x37, 0xec, 0xbf, + 0x36, 0xcf, 0x7a, 0x6a, 0x55, 0x1f, 0x25, 0x53, 0xba, 0xcd, 0x76, 0xc3, 0x07, 0x5e, 0x12, 0xf0, 0xc3, 0x82, 0x52, 0x5f, + 0xc6, 0x24, 0x54, 0x76, 0x49, 0xa3, 0xf1, 0xdd, 0x67, 0x29, 0x81, 0x19, 0x5f, 0x7b, 0xcd, 0xc6, 0x60, 0x3e, 0x80, 0x02, + 0xb3, 0xd9, 0xb6, 0x9d, 0x29, 0x59, 0xdc, 0x79, 0x90, 0xab, 0x53, 0xf4, 0xe6, 0x23, 0xb4, 0x77, 0x0f, 0xc8, 0xf2, 0x88, + 0xb3, 0x1c, 0x70, 0xb4, 0xeb, 0xa8, 0xdf, 0x25, 0x5b, 0x94, 0xa6, 0xce, 0x80, 0xbd, 0x46, 0xe6, 0x26, 0x8c, 0x4f, 0xee, + 0x37, 0x81, 0x84, 0xc6, 0xff, 0x0a, 0x37, 0x2e, 0xa4, 0xcb, 0xdf, 0x62, 0x81, 0x79, 0x3b, 0xa2, 0xdb, 0x07, 0x14, 0x0c, + 0xf7, 0x44, 0x1e, 0xda, 0xe0, 0x6c, 0x1a, 0xb6, 0x52, 0x7f, 0xd8, 0xce, 0xe7, 0x29, 0x98, 0xc1, 0x69, 0x40, 0xb9, 0x2a, + 0xe7, 0xb4, 0xee, 0x04, 0x67, 0xf7, 0x54, 0xac, 0x94, 0x12, 0x5c, 0x67, 0xb4, 0x51, 0x9c, 0xf6, 0xfa, 0x9b, 0x10, 0xd3, + 0x7e, 0xce, 0x78, 0xd5, 0x88, 0x80, 0xd7, 0x88, 0xea, 0x16, 0x51, 0x0c, 0xc9, 0xf2, 0x55, 0xda, 0xbd, 0x22, 0x34, 0x1a, + 0x65, 0x8f, 0xd7, 0x52, 0x00, 0x98, 0xc3, 0x76, 0xff, 0x3e, 0xfc, 0x44, 0x4b, 0x7e, 0xc2, 0x40, 0x00, 0x94, 0xf3, 0xc6, + 0xd5, 0xa3, 0x0f, 0x95, 0x9a, 0x96, 0xbb, 0x50, 0xcd, 0xd0, 0x6f, 0x75, 0xd7, 0xcc, 0x89, 0xb4, 0xc2, 0x85, 0x7f, 0x5f, + 0x06, 0xc1, 0xdf, 0x3c, 0xdd, 0x32, 0xdb, 0x44, 0xae, 0x1e, 0xd8, 0x56, 0xde, 0x93, 0xb0, 0xbd, 0xed, 0x8c, 0xb6, 0xcc, + 0x15, 0xe7, 0x81, 0x98, 0x36, 0x36, 0xd6, 0x91, 0x61, 0xd8, 0x65, 0x57, 0x5d, 0xcd, 0xbf, 0xf1, 0x3b, 0x31, 0xb6, 0xdd, + 0x6e, 0xc6, 0xd3, 0x1b, 0xc9, 0x47, 0x8c, 0x09, 0x03, 0x81, 0x7d, 0xbd, 0x64, 0xa9, 0x09, 0x66, 0x81, 0x2d, 0x56, 0x43, + 0xe8, 0x3c, 0x3e, 0xaa, 0xf8, 0x28, 0x92, 0x13, 0xea, 0x1f, 0xc1, 0x81, 0x4f, 0xb1, 0x1e, 0x88, 0xd2, 0x47, 0xdb, 0xb4, + 0x7e, 0xcb, 0xac, 0xc4, 0xbc, 0x07, 0x68, 0x83, 0x7d, 0xd2, 0x90, 0x90, 0x01, 0xa7, 0x0b, 0xac, 0x60, 0x67, 0x0f, 0xf4, + 0x1b, 0x2c, 0x1e, 0x93, 0x93, 0x6a, 0x16, 0x63, 0x78, 0x36, 0x7d, 0xc5, 0xa5, 0x04, 0xf4, 0x96, 0x1d, 0xae, 0x1a, 0xdf, + 0x1d, 0xba, 0xfc, 0x00, 0x21, 0x07, 0x8c, 0xa7, 0x9d, 0x00, 0x60, 0xb7, 0xa4, 0x05, 0xdd, 0xcd, 0x05, 0xee, 0x70, 0x5e, + 0xc5, 0x79, 0x6c, 0xc1, 0x22, 0x57, 0xfb, 0x5a, 0x25, 0x3e, 0xb9, 0x37, 0x76, 0x61, 0xc2, 0x7d, 0x14, 0x3c, 0xd3, 0x3a, + 0x13, 0xb9, 0x33, 0x07, 0xf6, 0x53, 0xc9, 0x5b, 0xb9, 0x97, 0x03, 0xd0, 0x76, 0xb8, 0xd1, 0xf1, 0x43, 0x9d, 0x7f, 0x37, + 0x46, 0x1a, 0xda, 0xdf, 0xd7, 0x4a, 0xb7, 0x79, 0x84, 0x9e, 0x47, 0x73, 0xac, 0x26, 0xf7, 0xd7, 0x54, 0x16, 0xad, 0x49, + 0x5e, 0x5d, 0x77, 0x61, 0x79, 0xdd, 0x52, 0x13, 0x2f, 0x20, 0xce, 0x26, 0x35, 0xa3, 0x60, 0x28, 0x3f, 0xc5, 0x67, 0xce, + 0x43, 0xa0, 0x86, 0x28, 0xf7, 0xa6, 0xf9, 0x6a, 0xbf, 0x25, 0x41, 0xb7, 0x7d, 0xbc, 0x04, 0x02, 0xd1, 0xe5, 0xed, 0x74, + 0xf5, 0xf5, 0x39, 0xf5, 0x18, 0x42, 0x9f, 0xdc, 0xaf, 0x46, 0xb6, 0x55, 0x48, 0x72, 0xa6, 0x66, 0x94, 0xef, 0x4a, 0x45, + 0x92, 0xf8, 0x31, 0x7a, 0x19, 0x69, 0xcb, 0xcf, 0xf3, 0x10, 0x4a, 0x65, 0x53, 0x18, 0xf4, 0x7f, 0x47, 0xe8, 0xe5, 0x07, + 0xb1, 0x8b, 0x3c, 0x3b, 0xb1, 0x1f, 0xdb, 0xb8, 0x5d, 0x53, 0xcb, 0xad, 0xf7, 0x38, 0x91, 0x8a, 0x1e, 0xa6, 0x76, 0x05, + 0x48, 0x89, 0xcc, 0xff, 0x51, 0x59, 0x53, 0xe9, 0xd7, 0x6e, 0x1a, 0x6e, 0xad, 0xf2, 0xcb, 0xf5, 0xfd, 0x48, 0xbe, 0xa8, + 0x70, 0xae, 0x5e, 0xc1, 0x7e, 0x1e, 0x07, 0x8e, 0x64, 0x0d, 0x70, 0xb7, 0x92, 0xda, 0x6f, 0x45, 0xb0, 0xe3, 0x8a, 0x30, + 0xbc, 0x45, 0xd1, 0x65, 0xf2, 0xb7, 0xab, 0x4e, 0x16, 0x5c, 0xa2, 0xb2, 0x9a, 0x4d, 0x2f, 0x76, 0x26, 0x62, 0x92, 0x7a, + 0x3c, 0x47, 0xf6, 0x87, 0x04, 0x0f, 0x7b, 0xda, 0x4b, 0x02, 0x6b, 0xd6, 0x16, 0x79, 0xbd, 0x16, 0x24, 0x42, 0x7a, 0xf4, + 0x44, 0x58, 0xb4, 0x68, 0x71, 0xce, 0xb3, 0x28, 0xba, 0x84, 0x6c, 0x26, 0x82, 0x1e, 0xba, 0x19, 0x83, 0xb7, 0x75, 0x1b, + 0xde, 0x09, 0xf6, 0x1b, 0x4f, 0x31, 0x65, 0xae, 0xb6, 0x45, 0xc2, 0xa7, 0x35, 0x2d, 0x9f, 0x14, 0x10, 0xe0, 0x3e, 0x43, + 0xa7, 0x82, 0x01, 0x06, 0x95, 0x2c, 0x19, 0x43, 0x8c, 0x94, 0xd4, 0x8c, 0x85, 0x6d, 0x88, 0x33, 0xff, 0x19, 0x51, 0xd3, + 0x7c, 0xf2, 0xa7, 0x5b, 0x05, 0xd1, 0x2b, 0x56, 0x18, 0x5e, 0xa6, 0xb9, 0x66, 0x3c, 0xf7, 0x4d, 0xbd, 0xa9, 0x95, 0x75, + 0xa9, 0xa1, 0x87, 0x24, 0x87, 0xf0, 0x60, 0xbb, 0x39, 0xec, 0xd1, 0xe5, 0x67, 0x51, 0x76, 0x99, 0xbc, 0x64, 0x7b, 0x5a, + 0xd5, 0xa6, 0x54, 0x4f, 0x16, 0x10, 0xb2, 0xe9, 0x43, 0x1c, 0x3a, 0x4c, 0x88, 0x51, 0xf4, 0xc2, 0x95, 0x16, 0x8e, 0xbf, + 0x79, 0x19, 0x22, 0x95, 0xd1, 0x76, 0x99, 0xb8, 0x68, 0xf3, 0x6a, 0x1a, 0x4e, 0x43, 0xf8, 0x9c, 0x6b, 0x75, 0x8c, 0xa5, + 0xbd, 0x65, 0x3a, 0x83, 0x0b, 0x47, 0xcf, 0x08, 0xf7, 0x22, 0x86, 0xad, 0xd5, 0x89, 0xd0, 0x6f, 0x4e, 0xbe, 0x2a, 0x81, + 0x1d, 0x1c, 0xf1, 0xc8, 0xf3, 0x18, 0x44, 0x40, 0xf3, 0x99, 0xfd, 0x18, 0xe3, 0x1a, 0xc9, 0x7f, 0x3b, 0x93, 0x68, 0x84, + 0xe2, 0x49, 0xb9, 0xcf, 0x00, 0x5c, 0x76, 0xc4, 0xcc, 0x4b, 0x7e, 0x86, 0x7e, 0x3f, 0x4b, 0x23, 0x61, 0x92, 0x7c, 0xcb, + 0x0c, 0x0c, 0x3e, 0x97, 0x34, 0xcc, 0xfd, 0x34, 0xa9, 0xcc, 0xf0, 0x83, 0xb1, 0xbc, 0x50, 0x4c, 0x84, 0x6f, 0xba, 0x68, + 0x01, 0x4f, 0x71, 0x57, 0x05, 0x7f, 0x01, 0xe2, 0x18, 0x23, 0xe9, 0x44, 0xa8, 0x4d, 0x93, 0x11, 0xee, 0xc0, 0x79, 0x5a, + 0x94, 0x13, 0x81, 0xf4, 0x67, 0xa0, 0x50, 0x79, 0x83, 0xa1, 0x13, 0x5f, 0x0e, 0x82, 0x9a, 0x72, 0x90, 0xba, 0x43, 0x21, + 0x28, 0xa9, 0x65, 0x1c, 0x16, 0x97, 0x6f, 0xdb, 0xc3, 0x1e, 0x23, 0xc5, 0x4a, 0xdb, 0x3b, 0x3c, 0x42, 0x4a, 0xc4, 0xb5, + 0x7f, 0x6b, 0x5d, 0xfc, 0x09, 0x08, 0x43, 0x2f, 0xf8, 0x11, 0x27, 0x6f, 0x1d, 0xc0, 0x12, 0x59, 0x04, 0xa4, 0x5b, 0xe9, + 0x9f, 0x25, 0xd1, 0x58, 0x3a, 0x1f, 0xac, 0x05, 0x15, 0x18, 0xea, 0xbd, 0x4b, 0xd2, 0xba, 0x67, 0xf3, 0x1d, 0x89, 0x09, + 0x52, 0xe5, 0x0e, 0x15, 0xd6, 0x5b, 0x87, 0xf5, 0xc3, 0x3c, 0x98, 0xbc, 0x46, 0x4e, 0x19, 0x8d, 0xbb, 0x3e, 0xe0, 0xde, + 0x19, 0x59, 0x53, 0x32, 0x62, 0x31, 0x16, 0xd4, 0xea, 0x63, 0xda, 0xf4, 0xcc, 0x94, 0xd0, 0x18, 0x98, 0xbc, 0x00, 0xd3, + 0x6c, 0xe2, 0xa5, 0xac, 0x30, 0x08, 0x9d, 0x68, 0x82, 0x8e, 0xbb, 0xdf, 0x9a, 0xa1, 0x13, 0xa5, 0x98, 0x18, 0xa9, 0x11, + 0xde, 0x49, 0x18, 0x88, 0xab, 0xff, 0xc6, 0x2c, 0xa8, 0xe1, 0xf7, 0x49, 0xba, 0x17, 0x93, 0x1c, 0x6c, 0x7f, 0x2c, 0xa9, + 0x3a, 0xee, 0x77, 0x9d, 0x46, 0x0c, 0xf9, 0x1c, 0x24, 0x33, 0x6f, 0x9b, 0xf8, 0x47, 0x9d, 0xc9, 0x7f, 0x9c, 0x80, 0xa0, + 0x2c, 0x96, 0x63, 0xe1, 0x97, 0x75, 0x75, 0x1f, 0xb3, 0xc6, 0x0d, 0xa9, 0x49, 0x82, 0x66, 0x86, 0x13, 0xa4, 0x62, 0x4c, + 0x56, 0x89, 0x73, 0x03, 0x1b, 0x61, 0xff, 0xfa, 0x0f, 0xf4, 0x84, 0xe3, 0xad, 0x89, 0xc0, 0x8e, 0x03, 0x91, 0x1c, 0x99, + 0x9f, 0x99, 0x92, 0x7e, 0xb5, 0xd8, 0xe3, 0xee, 0x6c, 0x21, 0x27, 0x5d, 0xa2, 0xa5, 0x90, 0xf2, 0x67, 0xed, 0xf3, 0xca, + 0x51, 0x56, 0x28, 0x7d, 0xa9, 0xd0, 0x4a, 0x4b, 0x76, 0x2b, 0xa8, 0x95, 0x8a, 0x37, 0xb4, 0x72, 0x96, 0xb2, 0xa0, 0xbe, + 0x90, 0x4f, 0x4e, 0x37, 0xbb, 0x14, 0xf8, 0xd2, 0x76, 0x7c, 0x79, 0xf3, 0xd2, 0xbf, 0x35, 0xad, 0x64, 0xbc, 0x98, 0x73, + 0xe5, 0xb9, 0xb3, 0xa2, 0x9b, 0x54, 0x17, 0x9b, 0x99, 0xa1, 0xeb, 0xfd, 0xc2, 0x8b, 0xbd, 0xac, 0x6d, 0x14, 0x35, 0xc2, + 0x3b, 0xc9, 0x88, 0x57, 0x64, 0xaa, 0x52, 0x3d, 0xf1, 0x80, 0x9c, 0xb2, 0xfc, 0xe9, 0x53, 0x7c, 0x12, 0x81, 0xe6, 0x07, + 0xa1, 0x0b, 0x2b, 0xb3, 0x88, 0xa6, 0x07, 0xb8, 0x10, 0x7e, 0xc4, 0x55, 0x14, 0xa2, 0x66, 0xf1, 0xcc, 0xff, 0x49, 0x84, + 0xbc, 0x54, 0x15, 0x41, 0x26, 0x15, 0x44, 0xf1, 0xe4, 0x4e, 0x8a, 0xf4, 0x02, 0xb1, 0x87, 0x51, 0xa7, 0xa4, 0xe6, 0x4f, + 0xbb, 0xff, 0xfe, 0x94, 0x51, 0x54, 0x20, 0x7e, 0x16, 0x60, 0x23, 0xfe, 0x05, 0x8c, 0x1a, 0xe1, 0x12, 0x7c, 0xd4, 0xc0, + 0xae, 0x3a, 0x96, 0x13, 0x5d, 0x83, 0x89, 0x49, 0x99, 0x2c, 0x3e, 0x19, 0x8b, 0xa8, 0xf0, 0x0d, 0x65, 0x5d, 0x35, 0x37, + 0xa1, 0x2d, 0xdd, 0xe2, 0x6b, 0x0d, 0xa9, 0x47, 0x9e, 0xf0, 0x22, 0xb5, 0x8e, 0xab, 0xc1, 0x34, 0x93, 0x4c, 0xff, 0x89, + 0x9b, 0x24, 0xd4, 0x01, 0x24, 0xbc, 0xf5, 0x42, 0xd8, 0xee, 0xc2, 0xbc, 0x78, 0x03, 0xc1, 0x24, 0xa8, 0x88, 0xba, 0x3f, + 0x71, 0x58, 0x3d, 0xdd, 0xef, 0xa8, 0xf8, 0x15, 0x4c, 0xb0, 0x68, 0x7c, 0xbc, 0x41, 0x66, 0x72, 0xc4, 0x4d, 0x9f, 0xd0, + 0xdb, 0x9a, 0xd0, 0x65, 0xde, 0xf1, 0x25, 0x02, 0x35, 0xff, 0x49, 0x4a, 0xd8, 0xa4, 0x19, 0x49, 0xb4, 0x51, 0xda, 0x4b, + 0x75, 0x81, 0x17, 0xa7, 0x84, 0x80, 0x70, 0x3f, 0xc7, 0x0d, 0xb2, 0x79, 0x24, 0x25, 0x7c, 0xe2, 0x30, 0x67, 0x15, 0x00, + 0x80, 0x68, 0x1e, 0xde, 0xf0, 0x3e, 0xda, 0xc6, 0x31, 0x4d, 0xa7, 0xf0, 0x53, 0x0d, 0x88, 0x08, 0xe1, 0xd8, 0xe2, 0x8b, + 0x01, 0xdb, 0x9f, 0x5b, 0x7c, 0xd4, 0x68, 0x89, 0xb1, 0xeb, 0xdb, 0x4e, 0x6f, 0xac, 0x21, 0xad, 0xf2, 0xed, 0x6f, 0x61, + 0x4d, 0x1f, 0x2f, 0x64, 0x0b, 0xdb, 0x07, 0x54, 0x65, 0xd7, 0xf0, 0xf8, 0x40, 0xdb, 0xd9, 0x5e, 0x2d, 0xaf, 0x4f, 0x14, + 0x9f, 0x5b, 0x0b, 0x74, 0x4e, 0xad, 0x07, 0x60, 0xac, 0x24, 0x04, 0x5b, 0xc8, 0xf4, 0xc9, 0x6f, 0x28, 0xb0, 0x2b, 0xb3, + 0xd9, 0x43, 0xf1, 0x55, 0xc9, 0x25, 0x01, 0xb7, 0xab, 0x8f, 0xd8, 0x0f, 0x78, 0x6a, 0xbf, 0xa0, 0x4e, 0x80, 0x22, 0xc6, + 0x8a, 0x42, 0x37, 0x6d, 0x3a, 0xbd, 0xf3, 0x66, 0xbe, 0x84, 0x87, 0xf6, 0xa1, 0xa0, 0x99, 0x7f, 0x13, 0x66, 0x40, 0x39, + 0xce, 0x43, 0x8f, 0xe5, 0x83, 0x48, 0x94, 0xc6, 0x59, 0xc2, 0xce, 0x55, 0x35, 0x44, 0x74, 0xa6, 0x37, 0x0c, 0x3c, 0x69, + 0xdc, 0xdb, 0x2b, 0x3a, 0xd8, 0x32, 0x4d, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x01, 0xae, 0x1a, 0x61, 0x75, 0xae, 0x23, 0xd9, 0x11, 0x5c, 0x28, 0x93, 0xa9, 0xe2, + 0x49, 0x5e, 0x74, 0x28, 0x4c, 0x08, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14, 0x3d, 0xc6, 0xb0, 0x07, 0xf5, 0xd4, 0xa7, 0x42, 0x90, 0xa1, 0x2f, 0x4d, 0x1e, 0x43, 0x09, 0x7d, 0xd5, + 0xfe, 0x15, 0xb1, 0x04, 0x08, 0xdd, 0xee, 0x2c, 0x8a, 0x3d, 0x65, 0x41, 0x94, 0x02, 0x02, 0x08, 0x00 +}; + #endif /* si_89_cms_hash_agility_h */ diff --git a/OSX/sec/Security/Regressions/vmdh/vmdh-41-example.c b/OSX/sec/Security/Regressions/vmdh/vmdh-41-example.c index b237f350..089c59ee 100644 --- a/OSX/sec/Security/Regressions/vmdh/vmdh-41-example.c +++ b/OSX/sec/Security/Regressions/vmdh/vmdh-41-example.c @@ -16,20 +16,18 @@ #endif /* How to reach in the internals of SecDH/vmdh struct */ +//these are copies of SecDH_gp() and SecDH_priv() static inline ccdh_gp_t vmdh_gp(struct vmdh *dh) { - ccdh_gp_t gp; - gp.gp = (ccdh_gp *)dh; - return gp; + return (ccdh_gp_t)dh; } static inline ccdh_full_ctx_t vmdh_priv(struct vmdh *dh) { - void *p = dh; - cczp_t zp; - zp.zp = (struct cczp *) dh; - cc_size s = ccn_sizeof_n(cczp_n(zp)); - ccdh_full_ctx_t priv = { .hdr = (struct ccdh_ctx_header *)(p+ccdh_gp_size(s)) }; + 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; } diff --git a/OSX/sec/Security/Regressions/vmdh/vmdh-42-example2.c b/OSX/sec/Security/Regressions/vmdh/vmdh-42-example2.c index 345cee70..3c79e75e 100644 --- a/OSX/sec/Security/Regressions/vmdh/vmdh-42-example2.c +++ b/OSX/sec/Security/Regressions/vmdh/vmdh-42-example2.c @@ -16,20 +16,18 @@ #endif /* How to reach in the internals of SecDH/vmdh struct */ +//these are copies of SecDH_gp() and SecDH_priv() static inline ccdh_gp_t vmdh_gp(struct vmdh *dh) { - ccdh_gp_t gp; - gp.gp = (ccdh_gp *)dh; - return gp; + return (ccdh_gp_t)dh; } static inline ccdh_full_ctx_t vmdh_priv(struct vmdh *dh) { - void *p = dh; - cczp_t zp; - zp.zp = (struct cczp *) dh; - cc_size s = ccn_sizeof_n(cczp_n(zp)); - ccdh_full_ctx_t priv = { .hdr = (struct ccdh_ctx_header *)(p+ccdh_gp_size(s)) }; + 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; } @@ -107,7 +105,6 @@ static void tests(void) /* No SecDH API to import a private key, so we have to reach inside the opaque struct */ ccdh_gp_t gp = vmdh_gp(vmdh); ccdh_full_ctx_t priv = vmdh_priv(vmdh); - ok_status(ccdh_import_priv(gp, sizeof(client_priv), client_priv, priv), "Import DH private key"); uint8_t encpw[vmdh_encpw_len(sizeof(pw))]; diff --git a/OSX/sec/Security/SecAccessControl.c b/OSX/sec/Security/SecAccessControl.c index d7c506d4..b6141fe1 100644 --- a/OSX/sec/Security/SecAccessControl.c +++ b/OSX/sec/Security/SecAccessControl.c @@ -242,13 +242,13 @@ static bool checkItemInArray(CFTypeRef item, const CFTypeRef *values, CFIndex co return true; } } - return SecError(errSecParam, error, errMessage, item); + return SecError(errSecParam, error, CFSTR("%@: %@"), errMessage, item); } #define CheckItemInArray(item, values, msg) \ { \ const CFTypeRef vals[] = values; \ - if (!checkItemInArray(item, vals, sizeof(vals)/sizeof(*vals), CFSTR(msg), error)) { \ + if (!checkItemInArray(item, vals, sizeof(vals)/sizeof(*vals), msg, error)) { \ return false; \ } \ } @@ -264,7 +264,7 @@ bool SecAccessControlSetProtection(SecAccessControlRef access_control, CFTypeRef kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly), - "SecAccessControl: invalid protection %@"); + CFSTR("SecAccessControl: invalid protection")); } // Protection valid, use it. @@ -346,7 +346,7 @@ bool SecAccessControlAddConstraintForOperation(SecAccessControlRef access_contro kAKSKeyOpSign, kAKSKeyOpAttest, kAKSKeyOpComputeKey, #endif kAKSKeyOpSync, kAKSKeyOpDefaultAcl, kAKSKeyOpDelete), - "SecAccessControl: invalid operation %@"); + CFSTR("SecAccessControl: invalid operation")); if (!isDictionary(constraint) && !CFEqual(constraint, kCFBooleanTrue) && !CFEqual(constraint, kCFBooleanFalse) ) { return SecError(errSecParam, error, CFSTR("invalid constraint")); } diff --git a/OSX/sec/Security/SecAccessControlExports.exp-in b/OSX/sec/Security/SecAccessControlExports.exp-in index 2a58b75d..1ace3743 100644 --- a/OSX/sec/Security/SecAccessControlExports.exp-in +++ b/OSX/sec/Security/SecAccessControlExports.exp-in @@ -34,3 +34,4 @@ _kSecUseAuthenticationUIFail _kSecUseAuthenticationUISkip _kSecUseAuthenticationContext _kSecUseCallerName +_kSecUseTokenRawItems diff --git a/OSX/sec/Security/SecBackupKeybagEntry.h b/OSX/sec/Security/SecBackupKeybagEntry.h new file mode 100644 index 00000000..c01bc2b5 --- /dev/null +++ b/OSX/sec/Security/SecBackupKeybagEntry.h @@ -0,0 +1,53 @@ +/* + * 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 "CKKSSQLDatabaseObject.h" +#include +#include + +#ifndef SecBackupKeybagEntry_h +#define SecBackupKeybagEntry_h + +#if OCTAGON + +@interface SecBackupKeybagEntry : CKKSSQLDatabaseObject { + +} + +//@property (getter=getChangeToken,setter=setChangeToken:) CKServerChangeToken* changeToken; +@property NSData* publickeyHash; +@property NSData* publickey; +@property NSData* musr; // musr + ++ (instancetype) state: (NSString*) ckzone; + ++ (instancetype) fromDatabase: (NSData*) publickeyHash error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase: (NSData*) publickeyHash error: (NSError * __autoreleasing *) error; + +- (instancetype) initWithPublicKey: (NSData*)publicKey publickeyHash: (NSData*) publickeyHash user: (NSData*) user; + +- (BOOL)isEqual: (id) object; +@end + +#endif +#endif /* SecBackupKeybagEntry_h */ diff --git a/OSX/sec/Security/SecBackupKeybagEntry.m b/OSX/sec/Security/SecBackupKeybagEntry.m new file mode 100644 index 00000000..ba8bede5 --- /dev/null +++ b/OSX/sec/Security/SecBackupKeybagEntry.m @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#import + +#include +#include +#include + +#if OCTAGON + +#import "SecBackupKeybagEntry.h" + +// from CKKSZoneStateEntry.m + +@implementation SecBackupKeybagEntry + +- (instancetype) initWithPublicKey: (NSData*)publicKey publickeyHash: (NSData*) publickeyHash user: (NSData*) user { + if (self = [super init]) { + _publickey = publicKey; + _publickeyHash = publickeyHash; + _musr = user; + } + return self; +} + +- (BOOL)isEqual: (id) object { + if(![object isKindOfClass:[SecBackupKeybagEntry class]]) { + return NO; + } + + SecBackupKeybagEntry* obj = (SecBackupKeybagEntry*) object; + + return ([self.publickeyHash isEqual: obj.publickeyHash]) ? YES : NO; +} + ++ (instancetype) state: (NSData*) publickeyHash { + NSError* error = nil; + SecBackupKeybagEntry* ret = [SecBackupKeybagEntry tryFromDatabase:publickeyHash error:&error]; + + if (error) { + secerror("CKKS: error fetching SecBackupKeybagEntry(%@): %@", publickeyHash, error); + } + + if(!ret) { + ret = [[SecBackupKeybagEntry alloc] initWithPublicKey: nil publickeyHash: (NSData*) publickeyHash user: nil]; + } + return ret; +} + +#pragma mark - Database Operations + ++ (instancetype) fromDatabase: (NSData*) publickeyHash error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"publickeyHash": publickeyHash} error: error]; +} + ++ (instancetype) tryFromDatabase: (NSData*) publickeyHash error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"publickeyHash": publickeyHash} error: error]; +} + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*) sqlTable { + return @"backup_keybag"; +} + ++ (NSArray*) sqlColumns { + return @[@"publickey", @"publickeyHash", @"musr"]; +} + +- (NSDictionary*) whereClauseToFindSelf { + return @{@"publickeyHash": self.publickeyHash}; +} + +// used by saveToDatabaseWithConnection to write to db +- (NSDictionary*) sqlValues { + return @{ + @"publickey": self.publickey, + @"publickeyHash": self.publickeyHash, + @"musr": self.musr + }; +} + ++ (instancetype) fromDatabaseRow: (NSDictionary*) row { + return [[SecBackupKeybagEntry alloc] initWithPublicKey: row[@"publickey"] publickeyHash: row[@"publickeyHash"] user: row[@"musr"]]; +} + +@end + +#endif diff --git a/OSX/sec/Security/SecCMS.c b/OSX/sec/Security/SecCMS.c index aa79e2c1..ea18169d 100644 --- a/OSX/sec/Security/SecCMS.c +++ b/OSX/sec/Security/SecCMS.c @@ -76,6 +76,7 @@ CFTypeRef kSecCMSAdditionalCerts = CFSTR("kSecCMSAdditionalCerts"); CFTypeRef kSecCMSSignedAttributes = CFSTR("kSecCMSSignedAttributes"); CFTypeRef kSecCMSSignDate = CFSTR("kSecCMSSignDate"); CFTypeRef kSecCMSAllCerts = CFSTR("kSecCMSAllCerts"); +CFTypeRef kSecCMSHashAgility = CFSTR("kSecCMSHashAgility"); CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm"); CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC"); @@ -505,6 +506,13 @@ static OSStatus SecCMSVerifySignedData_internal(CFDataRef message, CFDataRef det } } + CFDataRef hash_agility_value = NULL; + if (errSecSuccess == SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd->signerInfos[0], &hash_agility_value)) { + if (hash_agility_value) { + CFDictionarySetValue(attrs, kSecCMSHashAgility, hash_agility_value); + } + } + *signed_attributes = attrs; CFReleaseSafe(certs); } diff --git a/OSX/sec/Security/SecCMS.h b/OSX/sec/Security/SecCMS.h index 1832b655..224dec7d 100644 --- a/OSX/sec/Security/SecCMS.h +++ b/OSX/sec/Security/SecCMS.h @@ -44,6 +44,7 @@ extern const void * kSecCMSAdditionalCerts; extern const void * kSecCMSSignedAttributes; extern const void * kSecCMSSignDate; extern const void * kSecCMSAllCerts; +extern const void * kSecCMSHashAgility; extern const void * kSecCMSEncryptionAlgorithmDESCBC; extern const void * kSecCMSEncryptionAlgorithmAESCBC; diff --git a/OSX/sec/Security/SecCTKKey.c b/OSX/sec/Security/SecCTKKey.c index 079d4679..819d1364 100644 --- a/OSX/sec/Security/SecCTKKey.c +++ b/OSX/sec/Security/SecCTKKey.c @@ -39,12 +39,11 @@ #include "SecCTKKeyPriv.h" const CFStringRef kSecUseToken = CFSTR("u_Token"); -const CFStringRef kSecUseTokenObjectID = CFSTR("u_TokenOID"); typedef struct { TKTokenRef token; CFStringRef token_id; - CFDataRef objectID; + CFDataRef object_id; SecCFDictionaryCOW auth_params; SecCFDictionaryCOW attributes; CFMutableDictionaryRef params; @@ -54,7 +53,7 @@ static void SecCTKKeyDestroy(SecKeyRef key) { SecCTKKeyData *kd = key->key; CFReleaseNull(kd->token); CFReleaseNull(kd->token_id); - CFReleaseNull(kd->objectID); + CFReleaseNull(kd->object_id); CFReleaseNull(kd->auth_params.mutable_dictionary); CFReleaseNull(kd->attributes.mutable_dictionary); CFReleaseNull(kd->params); @@ -62,7 +61,9 @@ static void SecCTKKeyDestroy(SecKeyRef key) { static CFIndex SecCTKGetAlgorithmID(SecKeyRef key) { SecCTKKeyData *kd = key->key; - if (CFEqualSafe(CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeyType), kSecAttrKeyTypeECSECPrimeRandom)) { + if (CFEqualSafe(CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeyType), kSecAttrKeyTypeECSECPrimeRandom) || + CFEqualSafe(CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeyType), kSecAttrKeyTypeECSECPrimeRandomPKA) || + CFEqualSafe(CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeyType), kSecAttrKeyTypeSecureEnclaveAttestation)) { return kSecECDSAAlgorithmID; } return kSecRSAAlgorithmID; @@ -91,37 +92,83 @@ static const CFTypeRef *aclOperations[] = { [kSecKeyOperationTypeKeyExchange] = &kAKSKeyOpComputeKey, }; +static TKTokenRef SecCTKKeyCreateToken(SecKeyRef key, CFDictionaryRef auth_params, CFDictionaryRef *last_params, CFErrorRef *error) { + TKTokenRef token = NULL; + SecCTKKeyData *kd = key->key; + SecCFDictionaryCOW attributes = { auth_params }; + if (kd->params && CFDictionaryGetCount(kd->params) > 0) { + CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attributes), CFSTR(kTKTokenCreateAttributeAuxParams), kd->params); + } + require_quiet(token = SecTokenCreate(kd->token_id, attributes.dictionary, error), out); + if (last_params != NULL) { + CFAssignRetained(*last_params, auth_params ? CFDictionaryCreateCopy(NULL, auth_params) : NULL); + } + +out: + CFReleaseNull(attributes.mutable_dictionary); + return token; +} + +static TKTokenRef SecCTKKeyCopyToken(SecKeyRef key, CFErrorRef *error) { + SecCTKKeyData *kd = key->key; + TKTokenRef token = CFRetainSafe(kd->token); + if (token == NULL) { + token = SecCTKKeyCreateToken(key, kd->auth_params.dictionary, NULL, error); + } + return token; +} + static CFTypeRef SecCTKKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, CFArrayRef algorithms, SecKeyOperationMode mode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { SecCTKKeyData *kd = key->key; __block SecCFDictionaryCOW auth_params = { kd->auth_params.dictionary }; + __block CFDictionaryRef last_params = kd->auth_params.dictionary ? CFDictionaryCreateCopy(NULL, kd->auth_params.dictionary) : NULL; __block TKTokenRef token = CFRetainSafe(kd->token); __block CFTypeRef result = kCFNull; CFErrorRef localError = NULL; - SecItemAuthDo(&auth_params, &localError, ^SecItemAuthResult(CFDictionaryRef ap, CFArrayRef *ac_pairs, CFErrorRef *error) { - if (auth_params.mutable_dictionary != NULL || token == NULL || kd->params != NULL) { + SecItemAuthDo(&auth_params, &localError, ^SecItemAuthResult(CFArrayRef *ac_pairs, CFErrorRef *error) { + if (!CFEqualSafe(last_params, auth_params.dictionary) || token == NULL) { // token was not connected yet or auth_params were modified, so reconnect the token in order to update the attributes. - SecCFDictionaryCOW attributes = { ap }; - if (kd->params && CFDictionaryGetCount(kd->params) > 0) { - CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attributes), CFSTR(kTKTokenCreateAttributeAuxParams), kd->params); - } - CFAssignRetained(token, SecTokenCreate(kd->token_id, attributes.dictionary, error)); - CFReleaseSafe(attributes.mutable_dictionary); + CFAssignRetained(token, SecCTKKeyCreateToken(key, auth_params.dictionary, &last_params, error)); if (token == NULL) { return kSecItemAuthResultError; } } - result = TKTokenCopyOperationResult(token, kd->objectID, operation, algorithms, mode, in1, in2, error); + result = kCFBooleanTrue; + if (mode == kSecKeyOperationModePerform) { + // Check, whether we are not trying to perform the operation with large data. If yes, explicitly do the check whether + // the operation is supported first, in order to avoid jetsam of target extension with operation type which is typically + // not supported by the extension at all. + // unable to decrypt large data with kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM + CFIndex inputSize = 0; + if (in1 != NULL && CFGetTypeID(in1) == CFDataGetTypeID()) { + inputSize += CFDataGetLength(in1); + } + if (in2 != NULL && CFGetTypeID(in2) == CFDataGetTypeID()) { + inputSize += CFDataGetLength(in2); + } + if (inputSize > 32 * 1024) { + result = TKTokenCopyOperationResult(token, kd->object_id, operation, algorithms, kSecKeyOperationModeCheckIfSupported, + NULL, NULL, error); + } + } + + if (CFEqualSafe(result, kCFBooleanTrue)) { + result = TKTokenCopyOperationResult(token, kd->object_id, operation, algorithms, mode, in1, in2, error); + } return (result != NULL) ? kSecItemAuthResultOK : SecCTKProcessError(*aclOperations[operation], token, - kd->objectID, ac_pairs, error); + kd->object_id, ac_pairs, error); + }, ^{ + CFAssignRetained(token, SecCTKKeyCreateToken(key, auth_params.dictionary, &last_params, NULL)); }); CFErrorPropagate(localError, error); - CFReleaseSafe(auth_params.mutable_dictionary); - CFReleaseSafe(token); + CFReleaseNull(auth_params.mutable_dictionary); + CFReleaseNull(token); + CFReleaseNull(last_params); return result; } @@ -141,14 +188,17 @@ static OSStatus SecCTKKeyCopyPublicOctets(SecKeyRef key, CFDataRef *data) { OSStatus status = errSecSuccess; CFErrorRef error = NULL; CFDataRef publicData = NULL; + TKTokenRef token = NULL; SecCTKKeyData *kd = key->key; - require_action_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out, + require_action_quiet(token = SecCTKKeyCopyToken(key, &error), out, status = SecErrorGetOSStatus(error)); + require_action_quiet(publicData = TKTokenCopyPublicKeyData(token, kd->object_id, &error), out, status = SecErrorGetOSStatus(error)); *data = publicData; out: CFReleaseSafe(error); + CFReleaseSafe(token); return status; } @@ -163,7 +213,7 @@ static const CFStringRef *kSecExportableCTKKeyAttributes[] = { &kSecClass, &kSecAttrTokenID, &kSecAttrKeyClass, - &kSecAttrIsPermanent, + &kSecAttrAccessControl, &kSecAttrIsPrivate, &kSecAttrIsModifiable, &kSecAttrKeyType, @@ -189,12 +239,14 @@ static CFDictionaryRef SecCTKKeyCopyAttributeDictionary(SecKeyRef key) { CFMutableDictionaryRef attrs = NULL; CFErrorRef error = NULL; CFDataRef publicData = NULL, digest = NULL; + TKTokenRef token = NULL; SecCTKKeyData *kd = key->key; // Encode ApplicationLabel as SHA1 digest of public key bytes. - require_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out); + require_quiet(token = SecCTKKeyCopyToken(key, &error), out); + require_quiet(publicData = TKTokenCopyPublicKeyData(token, kd->object_id, &error), out); - /* Calculate the digest of the public key. */ + // Calculate the digest of the public key. require(digest = SecSHA1DigestCreate(NULL, CFDataGetBytePtr(publicData), CFDataGetLength(publicData)), out); attrs = CFDictionaryCreateMutableForCFTypes(CFGetAllocator(key)); CFDictionarySetValue(attrs, kSecAttrApplicationLabel, digest); @@ -206,10 +258,18 @@ static CFDictionaryRef SecCTKKeyCopyAttributeDictionary(SecKeyRef key) { } } + // Consistently with existing RSA and EC software keys implementation, mark all keys as permanent ones. + CFDictionarySetValue(attrs, kSecAttrIsPermanent, kCFBooleanTrue); + + // Always export token_id and object_id. + CFDictionarySetValue(attrs, kSecAttrTokenID, kd->token_id); + CFDictionarySetValue(attrs, kSecAttrTokenOID, kd->object_id); + out: CFReleaseSafe(error); CFReleaseSafe(publicData); CFReleaseSafe(digest); + CFReleaseSafe(token); return attrs; } @@ -245,9 +305,10 @@ static Boolean SecCTKKeySetParameter(SecKeyRef key, CFStringRef name, CFProperty name = kSecUseCredentialReference; } + // Release existing token connection to enforce creation of new connection with new params. + CFReleaseNull(kd->token); + if (isUseFlag) { - // Release existing token connection to enforce creation of new connection with new auth params. - CFReleaseNull(kd->token); if (value != NULL) { CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->auth_params), name, value); } else { @@ -289,7 +350,7 @@ static SecKeyRef SecCTKKeyCreateDuplicate(SecKeyRef key) { SecKeyRef result = SecKeyCreate(CFGetAllocator(key), &kSecCTKKeyDescriptor, 0, 0, 0); SecCTKKeyData *kd = key->key, *rd = result->key; rd->token = CFRetainSafe(kd->token); - rd->objectID = CFRetainSafe(kd->objectID); + rd->object_id = CFRetainSafe(kd->object_id); rd->token_id = CFRetainSafe(kd->token_id); if (kd->attributes.dictionary != NULL) { rd->attributes.dictionary = kd->attributes.dictionary; @@ -306,11 +367,11 @@ SecKeyRef SecKeyCreateCTKKey(CFAllocatorRef allocator, CFDictionaryRef refAttrib SecKeyRef key = SecKeyCreate(allocator, &kSecCTKKeyDescriptor, 0, 0, 0); SecCTKKeyData *kd = key->key; kd->token = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecUseToken)); - kd->objectID = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecUseTokenObjectID)); + kd->object_id = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecAttrTokenOID)); kd->token_id = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecAttrTokenID)); kd->attributes.dictionary = refAttributes; CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecUseToken); - CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecUseTokenObjectID); + CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecAttrTokenOID); SecItemAuthCopyParams(&kd->auth_params, &kd->attributes); if (CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrIsPrivate) == NULL) { CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecAttrIsPrivate, kCFBooleanTrue); @@ -324,15 +385,34 @@ SecKeyRef SecKeyCreateCTKKey(CFAllocatorRef allocator, CFDictionaryRef refAttrib NULL, }; - for (const CFStringRef **attrName = &numericAttributes[0]; *attrName != NULL; attrName++) { - CFTypeRef value = CFDictionaryGetValue(kd->attributes.dictionary, **attrName); - if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID()) { - CFIndex number; - if (CFNumberGetValue(value, kCFNumberCFIndexType, &number)) { - CFStringRef newValue = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), (long)number); - if (newValue != NULL) { - CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->attributes), **attrName, newValue); - CFRelease(newValue); + if (kd->token == NULL) { + kd->token = SecCTKKeyCopyToken(key, error); + if (kd->token != NULL) { + CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, kd->attributes.dictionary); + CFAssignRetained(kd->object_id, TKTokenCreateOrUpdateObject(kd->token, kd->object_id, attrs, error)); + CFDictionaryForEach(attrs, ^(const void *key, const void *value) { + CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(&kd->attributes), key, value); + }); + CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecAttrTokenOID); + CFReleaseSafe(attrs); + } + + if (kd->token == NULL || kd->object_id == NULL) { + CFReleaseNull(key); + } + } + + if (key != NULL) { + for (const CFStringRef **attrName = &numericAttributes[0]; *attrName != NULL; attrName++) { + CFTypeRef value = CFDictionaryGetValue(kd->attributes.dictionary, **attrName); + if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID()) { + CFIndex number; + if (CFNumberGetValue(value, kCFNumberCFIndexType, &number)) { + CFStringRef newValue = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), (long)number); + if (newValue != NULL) { + CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->attributes), **attrName, newValue); + CFRelease(newValue); + } } } } @@ -343,34 +423,37 @@ SecKeyRef SecKeyCreateCTKKey(CFAllocatorRef allocator, CFDictionaryRef refAttrib OSStatus SecCTKKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) { OSStatus status; - CFMutableDictionaryRef attrs = NULL; - CFDictionaryRef keyAttrs = NULL; + __block SecCFDictionaryCOW attrs = { NULL }; CFDataRef publicData = NULL; require_action_quiet(publicKey != NULL, out, status = errSecParam); require_action_quiet(privateKey != NULL, out, status = errSecParam); - // Simply adding key on the token without value will cause the token to generate the key and automatically - // add it to the keychain. Prepare dictionary specifying item to add. - keyAttrs = CFDictionaryGetValue(parameters, kSecPrivateKeyAttrs); - attrs = (keyAttrs == NULL) ? CFDictionaryCreateMutableForCFTypes(NULL) : CFDictionaryCreateMutableCopy(NULL, 0, keyAttrs); + // Simply adding key on the token without value will cause the token to generate the key. + // Prepare dictionary specifying item to add. + attrs.dictionary = CFDictionaryGetValue(parameters, kSecPrivateKeyAttrs); CFDictionaryForEach(parameters, ^(const void *key, const void *value) { if (!CFEqual(key, kSecPrivateKeyAttrs) && !CFEqual(key, kSecPublicKeyAttrs)) { - CFDictionarySetValue(attrs, key, value); + CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attrs), key, value); } }); - CFDictionaryRemoveValue(attrs, kSecValueData); - CFDictionarySetValue(attrs, kSecClass, kSecClassKey); - CFDictionarySetValue(attrs, kSecAttrKeyClass, kSecAttrKeyClassPrivate); - CFDictionarySetValue(attrs, kSecReturnRef, kCFBooleanTrue); + CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&attrs), kSecValueData); + CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attrs), kSecClass, kSecClassKey); + CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attrs), kSecAttrKeyClass, kSecAttrKeyClassPrivate); + CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attrs), kSecReturnRef, kCFBooleanTrue); + + // Do not automatically store tke key into the keychain, caller will do it on its own if it is really requested. + CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attrs), kSecAttrIsPermanent, kCFBooleanFalse); // Add key from given attributes to the token (having no data will cause the token to actually generate the key). - require_noerr_quiet(status = SecItemAdd(attrs, (CFTypeRef *)privateKey), out); + require_noerr_quiet(status = SecItemAdd(attrs.dictionary, (CFTypeRef *)privateKey), out); // Create non-token public key. require_noerr_quiet(status = SecCTKKeyCopyPublicOctets(*privateKey, &publicData), out); - if (CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeEC)) { + if (CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeEC) || + CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeECSECPrimeRandomPKA) || + CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeSecureEnclaveAttestation)) { *publicKey = SecKeyCreateECPublicKey(NULL, CFDataGetBytePtr(publicData), CFDataGetLength(publicData), kSecKeyEncodingBytes); } else if (CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeRSA)) { @@ -386,124 +469,86 @@ OSStatus SecCTKKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, } out: - CFReleaseSafe(attrs); + CFReleaseSafe(attrs.mutable_dictionary); CFReleaseSafe(publicData); return status; } -SecKeyRef SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType, CFErrorRef *error) { - if (keyType != kSecKeyAttestationKeyTypeSIK && keyType != kSecKeyAttestationKeyTypeGID) { - SecError(errSecParam, error, CFSTR("unexpected attestation key type %u"), (unsigned)keyType); - return NULL; - } +const CFStringRef kSecKeyParameterSETokenAttestationNonce = CFSTR("com.apple.security.seckey.setoken.attestation-nonce"); - // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.sik" dataUsingEncoding:NSUTF8StringEncoding]]; - static const uint8_t sikObjectIDBytes[] = { - 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14, - 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74, - 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c, - 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24, - 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, - 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x73, 0x69, 0x6b, 0x80, 0x02, 0xd2, - 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58, - 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74, - 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b, - 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54, - 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46, - 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6 - }; +SecKeyRef SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType, CFErrorRef *error) { + CFDictionaryRef attributes = NULL; + CFDataRef object_id = NULL; + SecKeyRef key = NULL; - // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.gid" dataUsingEncoding:NSUTF8StringEncoding]]; - static const uint8_t gidObjectIDBytes[] = { - 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14, - 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74, - 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c, - 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24, - 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, - 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x67, 0x69, 0x64, 0x80, 0x02, 0xd2, - 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58, - 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74, - 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b, - 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54, - 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46, - 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6 - }; + require_action_quiet(keyType == kSecKeyAttestationKeyTypeSIK || keyType == kSecKeyAttestationKeyTypeGID, out, + SecError(errSecParam, error, CFSTR("unexpected attestation key type %u"), (unsigned)keyType)); - CFDataRef objectID = (keyType == kSecKeyAttestationKeyTypeSIK) ? - CFDataCreate(kCFAllocatorDefault, sikObjectIDBytes, sizeof(sikObjectIDBytes)) : - CFDataCreate(kCFAllocatorDefault, gidObjectIDBytes, sizeof(gidObjectIDBytes)) ; + // [[TKTLVBERRecord alloc] initWithPropertyList:[@"com.apple.setoken.sik" dataUsingEncoding:NSUTF8StringEncoding]].data + static const uint8_t sikObjectIDBytes[] = { 0x04, 21, 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', '.', 's', 'e', 't', 'o', 'k', 'e', 'n', '.', 's', 'i', 'k' }; + // [[TKTLVBERRecord alloc] initWithPropertyList:[@"com.apple.setoken.gid" dataUsingEncoding:NSUTF8StringEncoding]].data + static const uint8_t gidObjectIDBytes[] = { 0x04, 21, 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', '.', 's', 'e', 't', 'o', 'k', 'e', 'n', '.', 'g', 'i', 'd' }; - const void *keys[] = { kSecUseToken, kSecUseTokenObjectID, kSecAttrTokenID }; - const void *values[] = { kCFNull, objectID, CFSTR("com.apple.setoken.attest") }; + object_id = (keyType == kSecKeyAttestationKeyTypeSIK ? + CFDataCreate(kCFAllocatorDefault, sikObjectIDBytes, sizeof(sikObjectIDBytes)) : + CFDataCreate(kCFAllocatorDefault, gidObjectIDBytes, sizeof(gidObjectIDBytes))); - CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault, - keys, values, sizeof(keys) / sizeof(*keys), - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + attributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecAttrTokenOID, object_id, + kSecAttrTokenID, kSecAttrTokenIDAppleKeyStore, + NULL); + key = SecKeyCreateCTKKey(kCFAllocatorDefault, attributes, error); - return SecKeyCreateCTKKey(kCFAllocatorDefault, attributes, error); +out: + CFReleaseSafe(attributes); + CFReleaseSafe(object_id); + return key; } CFDataRef SecKeyCreateAttestation(SecKeyRef key, SecKeyRef keyToAttest, CFErrorRef *error) { - if (!key || !keyToAttest) { - SecError(errSecParam, error, CFSTR("attestation key(s) is NULL")); - return NULL; - } - + __block CFDictionaryRef attributes = NULL, outputAttributes = NULL; + CFDataRef attestationData = NULL; + CFErrorRef localError = NULL; SecCTKKeyData *attestingKeyData = key->key; SecCTKKeyData *keyToAttestData = keyToAttest->key; + __block TKTokenRef token = NULL; - if (key->key_class != &kSecCTKKeyDescriptor) { - SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported by key %@"), key); - return NULL; + if (error == NULL) { + error = &localError; } - if (keyToAttest->key_class != &kSecCTKKeyDescriptor || CFEqual(keyToAttestData->token, kCFNull)) { - SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported for key %@"), keyToAttest); - return NULL; - } - - const void *keys[] = { - CFSTR(kTKTokenControlAttribAttestingKey), - CFSTR(kTKTokenControlAttribKeyToAttest), - }; - const void *values[] = { - attestingKeyData->objectID, - keyToAttestData->objectID - }; - CFDictionaryRef attributes = NULL; - __block CFDictionaryRef outputAttributes = NULL; - CFDataRef attestationData = NULL; - __block SecCFDictionaryCOW sign_auth_params = { keyToAttestData->auth_params.dictionary }; + __block SecCFDictionaryCOW auth_params = { keyToAttestData->auth_params.dictionary }; - attributes = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(*keys), - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - SecItemAuthDo(&sign_auth_params, error, ^SecItemAuthResult(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error) { - outputAttributes = TKTokenControl(keyToAttestData->token, attributes, error); - return outputAttributes ? kSecItemAuthResultOK : SecCTKProcessError(kAKSKeyOpAttest, keyToAttestData->token, keyToAttestData->objectID, ac_pairs, error); - }); - require(outputAttributes, out); + require_action_quiet(key->key_class == &kSecCTKKeyDescriptor, out, + SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported by key %@"), key)); + require_action_quiet(keyToAttest->key_class == &kSecCTKKeyDescriptor, out, + SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported for key %@"), keyToAttest)); - attestationData = CFDictionaryGetValue(outputAttributes, CFSTR(kTKTokenControlAttribAttestationData)); - require_action(attestationData, out, SecError(errSecInternal, error, CFSTR("could not get attestation data"))); + attributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + CFSTR(kTKTokenControlAttribAttestingKey), attestingKeyData->object_id, + CFSTR(kTKTokenControlAttribKeyToAttest), keyToAttestData->object_id, + NULL); - if (CFGetTypeID(attestationData) != CFDataGetTypeID()) { - SecError(errSecInternal, error, CFSTR("unexpected attestation object type")); - attestationData = NULL; - } + bool ok = SecItemAuthDo(&auth_params, error, ^SecItemAuthResult(CFArrayRef *ac_pairs, CFErrorRef *error) { + if (auth_params.mutable_dictionary != NULL || token == NULL) { + CFAssignRetained(token, SecCTKKeyCopyToken(key, error)); + if (token == NULL) { + return kSecItemAuthResultError; + } + } - CFRetainSafe(attestationData); + outputAttributes = TKTokenControl(token, attributes, error); + return outputAttributes ? kSecItemAuthResultOK : SecCTKProcessError(kAKSKeyOpAttest, keyToAttestData->token, keyToAttestData->object_id, ac_pairs, error); + }, NULL); + require_quiet(ok, out); + require_action_quiet(attestationData = CFRetainSafe(CFDictionaryGetValue(outputAttributes, CFSTR(kTKTokenControlAttribAttestationData))), + out, SecError(errSecInternal, error, CFSTR("could not get attestation data"))); out: CFReleaseSafe(attributes); CFReleaseSafe(outputAttributes); + CFReleaseSafe(localError); + CFReleaseSafe(auth_params.mutable_dictionary); + CFReleaseSafe(token); return attestationData; } diff --git a/OSX/sec/Security/SecCTKKeyPriv.h b/OSX/sec/Security/SecCTKKeyPriv.h index a91b857d..660a0080 100644 --- a/OSX/sec/Security/SecCTKKeyPriv.h +++ b/OSX/sec/Security/SecCTKKeyPriv.h @@ -30,7 +30,6 @@ __BEGIN_DECLS extern const CFStringRef kSecUseToken; -extern const CFStringRef kSecUseTokenObjectID; OSStatus SecCTKKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *rsaPublicKey, SecKeyRef *rsaPrivateKey); diff --git a/OSX/sec/Security/SecCertificate.c b/OSX/sec/Security/SecCertificate.c index de16cfed..a9c0a1f2 100644 --- a/OSX/sec/Security/SecCertificate.c +++ b/OSX/sec/Security/SecCertificate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -68,13 +68,20 @@ #include #include "SecBase64.h" #include "AppleBaselineEscrowCertificates.h" +#include "AppleiPhoneDeviceCACertificates.h" #include #include +#pragma clang diagnostic ignored "-Wformat=2" + /* The minimum key sizes necessary to not be considered "weak" */ #define MIN_RSA_KEY_SIZE 128 // 1024-bit #define MIN_EC_KEY_SIZE 20 // 160-bit +/* The minimum key sizes necessary to be considered "strong" */ +#define MIN_STRONG_RSA_KEY_SIZE 256 // 2048-bit +#define MIN_STRONG_EC_KEY_SIZE 28 // 224-bit + typedef struct SecCertificateExtension { DERItem extnID; bool critical; @@ -207,7 +214,7 @@ SEC_CONST_DECL (kSecPropertyTypeURL, "url"); SEC_CONST_DECL (kSecPropertyTypeDate, "date"); /* Extension parsing routine. */ -typedef void (*SecCertificateExtensionParser)(SecCertificateRef certificate, +typedef bool (*SecCertificateExtensionParser)(SecCertificateRef certificate, const SecCertificateExtension *extn); /* Mapping from extension OIDs (as a DERItem *) to @@ -601,7 +608,7 @@ static OSStatus parseX501Name(const DERItem *x501Name, void *context, /********************** Extension Parsing Routines **********************/ /************************************************************************/ -static void SecCEPSubjectKeyIdentifier(SecCertificateRef certificate, +static bool SecCEPSubjectKeyIdentifier(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERDecodedInfo keyIdentifier; @@ -610,12 +617,13 @@ static void SecCEPSubjectKeyIdentifier(SecCertificateRef certificate, require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER); certificate->_subjectKeyIdentifier = keyIdentifier.content; - return; + return true; badDER: secwarning("Invalid SubjectKeyIdentifier Extension"); + return false; } -static void SecCEPKeyUsage(SecCertificateRef certificate, +static bool SecCEPKeyUsage(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); SecKeyUsage keyUsage = extn->critical ? kSecKeyUsageCritical : 0; @@ -645,28 +653,33 @@ static void SecCEPKeyUsage(SecCertificateRef certificate, mask >>= 1; } certificate->_keyUsage = keyUsage; - return; + return true; badDER: certificate->_keyUsage = kSecKeyUsageUnspecified; + secwarning("Invalid KeyUsage Extension"); + return false; } -static void SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate, +static bool SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); + return true; } -static void SecCEPSubjectAltName(SecCertificateRef certificate, +static bool SecCEPSubjectAltName(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); certificate->_subjectAltName = extn; + return true; } -static void SecCEPIssuerAltName(SecCertificateRef certificate, +static bool SecCEPIssuerAltName(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); + return true; } -static void SecCEPBasicConstraints(SecCertificateRef certificate, +static bool SecCEPBasicConstraints(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERBasicConstraints basicConstraints; @@ -683,10 +696,11 @@ static void SecCEPBasicConstraints(SecCertificateRef certificate, } certificate->_basicConstraints.present = true; certificate->_basicConstraints.critical = extn->critical; - return; + return true; badDER: certificate->_basicConstraints.present = false; secwarning("Invalid BasicConstraints Extension"); + return false; } @@ -763,7 +777,7 @@ badDER: return drtn; } -static void SecCEPNameConstraints(SecCertificateRef certificate, +static bool SecCEPNameConstraints(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERNameConstraints nc; @@ -780,9 +794,10 @@ static void SecCEPNameConstraints(SecCertificateRef certificate, require_noerr_quiet(parseGeneralSubtrees(&nc.excludedSubtrees, &certificate->_excludedSubtrees), badDER); } - return; + return true; badDER: - secdebug("cert", "failed to parse Name Constraints extension"); + secwarning("Invalid Name Constraints extension"); + return false; } static OSStatus appendCRLDPFromGeneralNames(void *context, SecCEGeneralNameType type, @@ -816,7 +831,7 @@ static OSStatus appendCRLDPFromGeneralNames(void *context, SecCEGeneralNameType fullName [0] GeneralNames, nameRelativeToCRLIssuer [1] RelativeDistinguishedName } */ -static void SecCEPCrlDistributionPoints(SecCertificateRef certificate, +static bool SecCEPCrlDistributionPoints(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERSequence crlDPSeq; @@ -856,9 +871,10 @@ static void SecCEPCrlDistributionPoints(SecCertificateRef certificate, } } require_quiet(drtn == DR_EndOfSequence, badDER); - return; + return true; badDER: - secdebug("cert", "failed to parse CRL Distribution Points extension"); + secwarning("Invalid CRL Distribution Points extension"); + return false; } /* @@ -877,7 +893,7 @@ badDER: */ /* maximum number of policies of 8192 seems more than adequate */ #define MAX_CERTIFICATE_POLICIES 8192 -static void SecCEPCertificatePolicies(SecCertificateRef certificate, +static bool SecCEPCertificatePolicies(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERTag tag; @@ -894,8 +910,9 @@ static void SecCEPCertificatePolicies(SecCertificateRef certificate, policy_count++; } require_quiet(drtn == DR_EndOfSequence, badDER); - policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation) - * (policy_count > 0 ? policy_count : 1)); + require_quiet(policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation) + * (policy_count > 0 ? policy_count : 1)), + badDER); drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq); require_noerr_quiet(drtn, badDER); DERSize policy_ix = 0; @@ -914,12 +931,13 @@ static void SecCEPCertificatePolicies(SecCertificateRef certificate, certificate->_certificatePolicies.critical = extn->critical; certificate->_certificatePolicies.numPolicies = policy_count; certificate->_certificatePolicies.policies = policies; - return; + return true; badDER: if (policies) free(policies); certificate->_certificatePolicies.present = false; secwarning("Invalid CertificatePolicies Extension"); + return false; } /* @@ -930,7 +948,7 @@ badDER: subjectDomainPolicy CertPolicyId } */ #define MAX_POLICY_MAPPINGS 8192 -static void SecCEPPolicyMappings(SecCertificateRef certificate, +static bool SecCEPPolicyMappings(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERTag tag; @@ -947,8 +965,9 @@ static void SecCEPPolicyMappings(SecCertificateRef certificate, mapping_count++; } require_quiet(drtn == DR_EndOfSequence, badDER); - mappings = (SecCEPolicyMapping *)malloc(sizeof(SecCEPolicyMapping) - * (mapping_count > 0 ? mapping_count : 1)); + require_quiet(mappings = (SecCEPolicyMapping *)malloc(sizeof(SecCEPolicyMapping) + * (mapping_count > 0 ? mapping_count : 1)), + badDER); drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq); require_noerr_quiet(drtn, badDER); DERSize mapping_ix = 0; @@ -968,13 +987,14 @@ static void SecCEPPolicyMappings(SecCertificateRef certificate, certificate->_policyMappings.critical = extn->critical; certificate->_policyMappings.numMappings = mapping_count; certificate->_policyMappings.mappings = mappings; - return; + return true; badDER: if (mappings) { free(mappings); } certificate->_policyMappings.present = false; secwarning("Invalid CertificatePolicies Extension"); + return false; } /* @@ -987,7 +1007,7 @@ AuthorityKeyIdentifier ::= SEQUENCE { KeyIdentifier ::= OCTET STRING */ -static void SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate, +static bool SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERAuthorityKeyIdentifier akid; @@ -1009,12 +1029,13 @@ static void SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate, certificate->_authorityKeyIdentifierSerialNumber = akid.authorityCertSerialNumber; } - return; + return true; badDER: secwarning("Invalid AuthorityKeyIdentifier Extension"); + return false; } -static void SecCEPPolicyConstraints(SecCertificateRef certificate, +static bool SecCEPPolicyConstraints(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERPolicyConstraints pc; @@ -1040,15 +1061,17 @@ static void SecCEPPolicyConstraints(SecCertificateRef certificate, certificate->_policyConstraints.present = true; certificate->_policyConstraints.critical = extn->critical; - return; + return true; badDER: certificate->_policyConstraints.present = false; secwarning("Invalid PolicyConstraints Extension"); + return false; } -static void SecCEPExtendedKeyUsage(SecCertificateRef certificate, +static bool SecCEPExtendedKeyUsage(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); + return true; } /* @@ -1056,7 +1079,7 @@ static void SecCEPExtendedKeyUsage(SecCertificateRef certificate, SkipCerts ::= INTEGER (0..MAX) */ -static void SecCEPInhibitAnyPolicy(SecCertificateRef certificate, +static bool SecCEPInhibitAnyPolicy(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERDecodedInfo iapContent; @@ -1068,10 +1091,11 @@ static void SecCEPInhibitAnyPolicy(SecCertificateRef certificate, certificate->_inhibitAnyPolicySkipCerts.present = true; certificate->_inhibitAnyPolicySkipCerts.critical = extn->critical; - return; + return true; badDER: certificate->_inhibitAnyPolicySkipCerts.present = false; secwarning("Invalid InhibitAnyPolicy Extension"); + return false; } /* @@ -1090,7 +1114,7 @@ badDER: id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } */ -static void SecCEPAuthorityInfoAccess(SecCertificateRef certificate, +static bool SecCEPAuthorityInfoAccess(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); DERTag tag; @@ -1146,9 +1170,10 @@ static void SecCEPAuthorityInfoAccess(SecCertificateRef certificate, } } require_quiet(drtn == DR_EndOfSequence, badDER); - return; + return true; badDER: - secdebug("cert", "failed to parse Authority Information Access extension"); + secwarning("Invalid Authority Information Access extension"); + return false; } /* Apple Worldwide Developer Relations Certificate Authority subject name. @@ -1193,24 +1218,28 @@ static void checkForMissingRevocationInfo(SecCertificateRef certificate) { } } -static void SecCEPSubjectInfoAccess(SecCertificateRef certificate, +static bool SecCEPSubjectInfoAccess(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); + return true; } -static void SecCEPNetscapeCertType(SecCertificateRef certificate, +static bool SecCEPNetscapeCertType(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); + return true; } -static void SecCEPEntrustVersInfo(SecCertificateRef certificate, +static bool SecCEPEntrustVersInfo(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); + return true; } -static void SecCEPEscrowMarker(SecCertificateRef certificate, +static bool SecCEPEscrowMarker(SecCertificateRef certificate, const SecCertificateExtension *extn) { secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); + return true; } @@ -1507,6 +1536,32 @@ badDER: return NULL; } +static CFDataRef SecDERItemCopySequence(DERItem *content) { + DERSize seq_len_length = DERLengthOfLength(content->length); + size_t sequence_length = 1 + seq_len_length + content->length; + CFMutableDataRef sequence = CFDataCreateMutable(kCFAllocatorDefault, + sequence_length); + CFDataSetLength(sequence, sequence_length); + uint8_t *sequence_ptr = CFDataGetMutableBytePtr(sequence); + *sequence_ptr++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE; + require_noerr_quiet(DEREncodeLength(content->length, + sequence_ptr, &seq_len_length), out); + sequence_ptr += seq_len_length; + memcpy(sequence_ptr, content->data, content->length); + return sequence; +out: + CFReleaseSafe(sequence); + return NULL; +} + +static CFDataRef SecCopySequenceFromContent(CFDataRef content) { + DERItem tmpItem; + tmpItem.data = (void *)CFDataGetBytePtr(content); + tmpItem.length = CFDataGetLength(content); + + return SecDERItemCopySequence(&tmpItem); +} + CFDataRef SecDistinguishedNameCopyNormalizedContent(CFDataRef distinguished_name) { const DERItem name = { (unsigned char *)CFDataGetBytePtr(distinguished_name), CFDataGetLength(distinguished_name) }; @@ -1517,6 +1572,16 @@ CFDataRef SecDistinguishedNameCopyNormalizedContent(CFDataRef distinguished_name return NULL; } +CFDataRef SecDistinguishedNameCopyNormalizedSequence(CFDataRef distinguished_name) +{ + if (!distinguished_name) { return NULL; } + CFDataRef normalizedContent = SecDistinguishedNameCopyNormalizedContent(distinguished_name); + if (!normalizedContent) { return NULL; } + CFDataRef result = SecCopySequenceFromContent(normalizedContent); + CFReleaseNull(normalizedContent); + return result; +} + /* AUDIT[securityd]: certificate->_der is a caller provided data of any length (might be 0). @@ -1581,17 +1646,28 @@ static bool SecCertificateParse(SecCertificateRef certificate) certificate->_version = 0; } - /* The serial number is in the tbsCert.serialNum - it was saved in + /* The serial number is in the tbsCert.serialNum - it was saved in INTEGER form without the tag and length. */ - certificate->_serialNum = tbsCert.serialNum; - certificate->_serialNumber = CFDataCreate(allocator, - tbsCert.serialNum.data, tbsCert.serialNum.length); - /* RFC5280 4.1.2.2 limits serial number values to 20 octets. - %%% At some point, this should be treated as a hard error.*/ - if (tbsCert.serialNum.length < 1 || tbsCert.serialNum.length > 20) { + certificate->_serialNum = tbsCert.serialNum; + + /* Note: RFC5280 4.1.2.2 limits serial number values to 20 octets. + For now, we warn about larger values, but will still create the + certificate with values up to 36 octets to avoid breaking some + nonconforming certs with slightly longer serial numbers. + We also explicitly allow serial numbers of 21 octets where the + leading byte is 0x00 which is used to make a negative 20 octet + value positive. + */ + if (tbsCert.serialNum.length < 1 || tbsCert.serialNum.length > 21 || + (tbsCert.serialNum.length == 21 && tbsCert.serialNum.data[0] != 0x00)) { secwarning("Invalid serial number length (%ld), must be 1..20", tbsCert.serialNum.length); } + require_quiet(tbsCert.serialNum.data != NULL && + tbsCert.serialNum.length >= 1 && + tbsCert.serialNum.length <= 36, badCert); + certificate->_serialNumber = CFDataCreate(allocator, + tbsCert.serialNum.data, tbsCert.serialNum.length); /* sequence we're given: decode the tbsCerts TBS Signature Algorithm. */ drtn = DERParseSequenceContent(&tbsCert.tbsSigAlg, @@ -1699,6 +1775,7 @@ static bool SecCertificateParse(SecCertificateRef certificate) certificate->_extensionCount = extensionCount; certificate->_extensions = malloc(sizeof(SecCertificateExtension) * (extensionCount > 0 ? extensionCount : 1)); + require_quiet(certificate->_extensions, badCert); CFIndex ix = 0; drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag, &derSeq); @@ -1723,8 +1800,10 @@ static bool SecCertificateParse(SecCertificateRef certificate) (SecCertificateExtensionParser)CFDictionaryGetValue( sExtensionParsers, &certificate->_extensions[ix].extnID); if (parser) { - /* Invoke the parser. */ - parser(certificate, &certificate->_extensions[ix]); + /* Invoke the parser. If the extension is critical and the + * parser fails, fail the cert. */ + require_quiet(parser(certificate, &certificate->_extensions[ix]) || + !certificate->_extensions[ix].critical, badCert); } else if (certificate->_extensions[ix].critical) { if (isAppleExtensionOID(&extn.extnID)) { continue; @@ -1871,6 +1950,8 @@ CFDataRef SecCertificateCopyPrecertTBS(SecCertificateRef certificate) DERTBSCert tbsCert; DERReturn drtn; + require_quiet(extensionsList && extensionsListSpecs, out); + /* decode the TBSCert - it was saved in full DER form */ drtn = DERParseSequence(&tbsIn, DERNumTBSCertItemSpecs, DERTBSCertItemSpecs, @@ -1931,10 +2012,10 @@ CFDataRef SecCertificateCopyPrecertTBS(SecCertificateRef certificate) outData = CFDataCreate(kCFAllocatorDefault, tbsOut.data, tbsOut.length); out: - free(extensionsOut.data); - free(tbsOut.data); - free(extensionsList); - free(extensionsListSpecs); + if (extensionsOut.data) free(extensionsOut.data); + if (tbsOut.data) free(tbsOut.data); + if (extensionsList) free(extensionsList); + if (extensionsListSpecs) free(extensionsListSpecs); return outData; } @@ -2596,7 +2677,8 @@ static CFStringRef copyIntegerContentDescription(CFAllocatorRef allocator, static CFStringRef copyDERThingContentDescription(CFAllocatorRef allocator, DERTag tag, const DERItem *derThing, bool printableOnly) { - switch(tag) { + if (!derThing) { return NULL; } + switch(tag) { case ASN1_INTEGER: case ASN1_BOOLEAN: return printableOnly ? NULL : copyIntegerContentDescription(allocator, derThing); @@ -2636,12 +2718,13 @@ static CFStringRef copyDERThingContentDescription(CFAllocatorRef allocator, return NULL; } else { CFStringRef fmt = SecCopyCertString(SEC_NOT_DISPLAYED_KEY); + if (!fmt) { return NULL; } CFStringRef result = CFStringCreateWithFormat(allocator, NULL, fmt, - tag, derThing->length); + (unsigned long)tag, (unsigned long)derThing->length); CFRelease(fmt); return result; } - } + } } static CFStringRef copyDERThingDescription(CFAllocatorRef allocator, @@ -2664,8 +2747,10 @@ static void appendDERThingProperty(CFMutableArrayRef properties, CFStringRef label, CFStringRef localizedLabel, const DERItem *derThing) { CFStringRef value = copyDERThingDescription(CFGetAllocator(properties), derThing, false); - appendProperty(properties, kSecPropertyTypeString, label, localizedLabel, - value); + if (value) { + appendProperty(properties, kSecPropertyTypeString, label, localizedLabel, + value); + } CFReleaseSafe(value); } @@ -3291,18 +3376,22 @@ static void appendIntegerSequenceContent(CFMutableArrayRef properties, require_noerr_quiet(drtn, badDER); DERDecodedInfo intContent; fmt = SecCopyCertString(SEC_STRING_LIST_KEY); + require_quiet(fmt, badDER); while ((drtn = DERDecodeSeqNext(&intSeq, &intContent)) == DR_Success) { require_quiet(intContent.tag == ASN1_INTEGER, badDER); intDesc = copyIntegerContentDescription( allocator, &intContent.content); + require_quiet(intDesc, badDER); if (value) { v = CFStringCreateWithFormat(allocator, NULL, fmt, value, intDesc); CFReleaseNull(value); + require_quiet(v, badDER); value = v; - CFReleaseNull(intDesc); } else { - value = intDesc; + value = CFStringCreateMutableCopy(allocator, 0, intDesc); + require_quiet(value, badDER); } + CFReleaseNull(intDesc); } CFReleaseNull(fmt); require_quiet(drtn == DR_EndOfSequence, badDER); @@ -3315,13 +3404,15 @@ static void appendIntegerSequenceContent(CFMutableArrayRef properties, badDER: CFReleaseNull(fmt); CFReleaseNull(intDesc); - CFReleaseNull(v); + CFReleaseNull(value); appendInvalidProperty(properties, label, intSequenceContent); } static void appendCertificatePolicies(CFMutableArrayRef properties, const DERItem *extnValue) { CFAllocatorRef allocator = CFGetAllocator(properties); + CFStringRef piLabel = NULL, piFmt = NULL, lpiLabel = NULL; + CFStringRef pqLabel = NULL, pqFmt = NULL, lpqLabel = NULL; DERTag tag; DERSequence piSeq; DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &piSeq); @@ -3337,15 +3428,15 @@ static void appendCertificatePolicies(CFMutableArrayRef properties, DERPolicyInformationItemSpecs, &pi, sizeof(pi)); require_noerr_quiet(drtn, badDER); - CFStringRef piLabel = CFStringCreateWithFormat(allocator, NULL, - SEC_POLICY_IDENTIFIER_KEY, pin); - CFStringRef piFmt = SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY); - CFStringRef lpiLabel = CFStringCreateWithFormat(allocator, NULL, - piFmt, pin++); - CFRelease(piFmt); + require_quiet(piLabel = CFStringCreateWithFormat(allocator, NULL, + SEC_POLICY_IDENTIFIER_KEY, pin), badDER); + require_quiet(piFmt = SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY), badDER); + require_quiet(lpiLabel = CFStringCreateWithFormat(allocator, NULL, + piFmt, pin++), badDER); + CFReleaseNull(piFmt); appendOIDProperty(properties, piLabel, lpiLabel, &pi.policyIdentifier); - CFRelease(piLabel); - CFRelease(lpiLabel); + CFReleaseNull(piLabel); + CFReleaseNull(lpiLabel); if (pi.policyQualifiers.length == 0) continue; @@ -3364,16 +3455,16 @@ static void appendCertificatePolicies(CFMutableArrayRef properties, DERDecodedInfo qualifierContent; drtn = DERDecodeItem(&pqi.qualifier, &qualifierContent); require_noerr_quiet(drtn, badDER); - CFStringRef pqLabel = CFStringCreateWithFormat(allocator, NULL, - SEC_POLICY_QUALIFIER_KEY, pqn); - CFStringRef pqFmt = SecCopyCertString(SEC_POLICY_QUALIFIER_KEY); - CFStringRef lpqLabel = CFStringCreateWithFormat(allocator, NULL, - pqFmt, pqn++); - CFRelease(pqFmt); + require_quiet(pqLabel = CFStringCreateWithFormat(allocator, NULL, + SEC_POLICY_QUALIFIER_KEY, pqn), badDER); + require_quiet(pqFmt = SecCopyCertString(SEC_POLICY_QUALIFIER_KEY), badDER); + require_quiet(lpqLabel = CFStringCreateWithFormat(allocator, NULL, + pqFmt, pqn++), badDER); + CFReleaseNull(pqFmt); appendOIDProperty(properties, pqLabel, lpqLabel, &pqi.policyQualifierID); - CFRelease(pqLabel); - CFRelease(lpqLabel); + CFReleaseNull(pqLabel); + CFReleaseNull(lpqLabel); if (DEROidCompare(&oidQtCps, &pqi.policyQualifierID)) { require_quiet(qualifierContent.tag == ASN1_IA5_STRING, badDER); appendURLContentProperty(properties, SEC_CPS_URI_KEY, @@ -3413,6 +3504,12 @@ static void appendCertificatePolicies(CFMutableArrayRef properties, require_quiet(drtn == DR_EndOfSequence, badDER); return; badDER: + CFReleaseNull(piFmt); + CFReleaseNull(piLabel); + CFReleaseNull(lpiLabel); + CFReleaseNull(pqFmt); + CFReleaseNull(pqLabel); + CFReleaseNull(lpqLabel); appendInvalidProperty(properties, SEC_CERT_POLICIES_KEY, extnValue); } @@ -3619,11 +3716,11 @@ static bool appendPrintableDERSequence(CFMutableArrayRef properties, CFStringRef string = copyDERThingContentDescription(CFGetAllocator(properties), currDecoded.tag, &currDecoded.content, false); - //CFStringRef cleanString = copyStringRemovingPercentEscapes(string); + require_quiet(string, badSequence); appendProperty(properties, kSecPropertyTypeString, label, NULL, string); - CFRelease(string); + CFReleaseNull(string); appendedSomething = true; break; } @@ -3986,29 +4083,40 @@ CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) { CFAllocatorRef allocator = CFGetAllocator(certificate); CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); + require_quiet(properties, out); + /* First we put the Subject Name in the property list. */ - CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator, - &certificate->_subject); - appendProperty(properties, kSecPropertyTypeSection, - SEC_SUBJECT_NAME_KEY, NULL, subject_plist); - CFRelease(subject_plist); - - /* Next we put the Issuer Name in the property list. */ - CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator, - &certificate->_issuer); - appendProperty(properties, kSecPropertyTypeSection, - SEC_ISSUER_NAME_KEY, NULL, issuer_plist); - CFRelease(issuer_plist); - - /* Version */ + CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator, + &certificate->_subject); + if (subject_plist) { + appendProperty(properties, kSecPropertyTypeSection, + SEC_SUBJECT_NAME_KEY, NULL, subject_plist); + } + CFReleaseNull(subject_plist); + + /* Next we put the Issuer Name in the property list. */ + CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator, + &certificate->_issuer); + if (issuer_plist) { + appendProperty(properties, kSecPropertyTypeSection, + SEC_ISSUER_NAME_KEY, NULL, issuer_plist); + } + CFReleaseNull(issuer_plist); + + /* Version */ CFStringRef fmt = SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY); - CFStringRef versionString = CFStringCreateWithFormat(allocator, - NULL, fmt, certificate->_version + 1); - CFRelease(fmt); - appendProperty(properties, kSecPropertyTypeString, - SEC_VERSION_KEY, NULL, versionString); - CFRelease(versionString); + CFStringRef versionString = NULL; + if (fmt) { + versionString = CFStringCreateWithFormat(allocator, NULL, fmt, + certificate->_version + 1); + } + CFReleaseNull(fmt); + if (versionString) { + appendProperty(properties, kSecPropertyTypeString, + SEC_VERSION_KEY, NULL, versionString); + } + CFReleaseNull(versionString); /* Serial Number */ appendSerialNumberProperty(properties, SEC_SERIAL_NUMBER_KEY, &certificate->_serialNum); @@ -4040,15 +4148,16 @@ CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) { certificate->_properties = properties; } - CFRetain(certificate->_properties); +out: + CFRetainSafe(certificate->_properties); return certificate->_properties; } -#if TARGET_OS_OSX -/* On OS X, the SecCertificateCopySerialNumber API takes two arguments. */ -CFDataRef SecCertificateCopySerialNumber( +/* Unified serial number API */ +CFDataRef SecCertificateCopySerialNumberData( SecCertificateRef certificate, - CFErrorRef *error) { + CFErrorRef *error) +{ if (!certificate) { if (error) { *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL); @@ -4060,14 +4169,19 @@ CFDataRef SecCertificateCopySerialNumber( } return certificate->_serialNumber; } + +#if TARGET_OS_OSX +/* On OS X, the SecCertificateCopySerialNumber API takes two arguments. */ +CFDataRef SecCertificateCopySerialNumber( + SecCertificateRef certificate, + CFErrorRef *error) { + return SecCertificateCopySerialNumberData(certificate, error); +} #else /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */ CFDataRef SecCertificateCopySerialNumber( SecCertificateRef certificate) { - if (certificate->_serialNumber) { - CFRetain(certificate->_serialNumber); - } - return certificate->_serialNumber; + return SecCertificateCopySerialNumberData(certificate, NULL); } #endif @@ -4367,6 +4481,9 @@ OSStatus SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArray return errSecParam; } *emailAddresses = SecCertificateCopyRFC822Names(certificate); + if (*emailAddresses == NULL) { + *emailAddresses = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); + } return errSecSuccess; } @@ -4726,24 +4843,6 @@ CFStringRef SecCertificateCopyCompanyName(SecCertificateRef certificate) { return string; } -static CFDataRef SecDERItemCopySequence(DERItem *content) { - DERSize seq_len_length = DERLengthOfLength(content->length); - size_t sequence_length = 1 + seq_len_length + content->length; - CFMutableDataRef sequence = CFDataCreateMutable(kCFAllocatorDefault, - sequence_length); - CFDataSetLength(sequence, sequence_length); - uint8_t *sequence_ptr = CFDataGetMutableBytePtr(sequence); - *sequence_ptr++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE; - require_noerr_quiet(DEREncodeLength(content->length, - sequence_ptr, &seq_len_length), out); - sequence_ptr += seq_len_length; - memcpy(sequence_ptr, content->data, content->length); - return sequence; -out: - CFReleaseSafe(sequence); - return NULL; -} - CFDataRef SecCertificateCopyIssuerSequence( SecCertificateRef certificate) { return SecDERItemCopySequence(&certificate->_issuer); @@ -4758,22 +4857,14 @@ CFDataRef SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certifica if (!certificate || !certificate->_normalizedIssuer) { return NULL; } - DERItem tmpItem; - tmpItem.data = (void *)CFDataGetBytePtr(certificate->_normalizedIssuer); - tmpItem.length = CFDataGetLength(certificate->_normalizedIssuer); - - return SecDERItemCopySequence(&tmpItem); + return SecCopySequenceFromContent(certificate->_normalizedIssuer); } CFDataRef SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate) { if (!certificate || !certificate->_normalizedSubject) { return NULL; } - DERItem tmpItem; - tmpItem.data = (void *)CFDataGetBytePtr(certificate->_normalizedSubject); - tmpItem.length = CFDataGetLength(certificate->_normalizedSubject); - - return SecDERItemCopySequence(&tmpItem); + return SecCopySequenceFromContent(certificate->_normalizedSubject); } const DERAlgorithmId *SecCertificateGetPublicKeyAlgorithm( @@ -4818,16 +4909,39 @@ __nullable SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate) return CFRetainSafe(certificate->_pubKey); } -bool SecCertificateIsWeakKey(SecCertificateRef certificate) { - bool weak = true; +static CFIndex SecCertificateGetPublicKeyAlgorithmIdAndSize(SecCertificateRef certificate, size_t *keySizeInBytes) { + CFIndex keyAlgID = kSecNullAlgorithmID; + size_t size = 0; + SecKeyRef pubKey = NULL; + require_quiet(certificate, out); #if TARGET_OS_OSX require_quiet(pubKey = SecCertificateCopyPublicKey_ios(certificate), out); #else require_quiet(pubKey = SecCertificateCopyPublicKey(certificate) ,out); #endif - size_t size = SecKeyGetBlockSize(pubKey); - switch (SecKeyGetAlgorithmIdentifier(pubKey)) { + size = SecKeyGetBlockSize(pubKey); + keyAlgID = SecKeyGetAlgorithmId(pubKey); + +out: + CFReleaseNull(pubKey); + if (keySizeInBytes) { *keySizeInBytes = size; } + return keyAlgID; +} + +/* + * Public keys in certificates may be considered "weak" or "strong" or neither + * (that is, in between). Certificates using weak keys are not trusted at all. + * Certificates using neither strong nor weak keys are only trusted in certain + * contexts. SecPolicy and SecPolicyServer define the contexts by which we enforce + * these (or stronger) key size trust policies. + */ +bool SecCertificateIsWeakKey(SecCertificateRef certificate) { + if (!certificate) { return true; } + + bool weak = true; + size_t size = 0; + switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) { case kSecRSAAlgorithmID: if (MIN_RSA_KEY_SIZE <= size) weak = false; break; @@ -4837,13 +4951,29 @@ bool SecCertificateIsWeakKey(SecCertificateRef certificate) { default: weak = true; } - -out: - CFReleaseSafe(pubKey); return weak; } +bool SecCertificateIsStrongKey(SecCertificateRef certificate) { + if (!certificate) { return false; } + + bool strong = false; + size_t size = 0; + switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) { + case kSecRSAAlgorithmID: + if (MIN_STRONG_RSA_KEY_SIZE <= size) strong = true; + break; + case kSecECDSAAlgorithmID: + if (MIN_STRONG_EC_KEY_SIZE <= size) strong = true; + break; + default: + strong = false; + } + return strong; +} + bool SecCertificateIsWeakHash(SecCertificateRef certificate) { + if (!certificate) { return true; } SecSignatureHashAlgorithm certAlg = 0; certAlg = SecCertificateGetSignatureHashAlgorithm(certificate); if (certAlg == kSecSignatureHashAlgorithmUnknown || @@ -4858,17 +4988,13 @@ bool SecCertificateIsWeakHash(SecCertificateRef certificate) { bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate, CFDictionaryRef keySizes) { + if (!certificate) { return false; } + bool goodSize = false; - SecKeyRef pubKey = NULL; -#if TARGET_OS_OSX - require_quiet(pubKey = SecCertificateCopyPublicKey_ios(certificate), out); -#else - require_quiet(pubKey = SecCertificateCopyPublicKey(certificate) ,out); -#endif - size_t size = SecKeyGetBlockSize(pubKey); + size_t size = 0; CFNumberRef minSize; size_t minSizeInBits; - switch (SecKeyGetAlgorithmIdentifier(pubKey)) { + switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) { case kSecRSAAlgorithmID: if(CFDictionaryGetValueIfPresent(keySizes, kSecAttrKeyTypeRSA, (const void**)&minSize) && minSize && CFNumberGetValue(minSize, kCFNumberLongType, &minSizeInBits)) { @@ -4884,8 +5010,6 @@ bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate, default: goodSize = false; } -out: - CFReleaseSafe(pubKey); return goodSize; } @@ -5036,10 +5160,17 @@ void SecCertificateShow(SecCertificateRef certificate) { #ifndef STANDALONE CFDictionaryRef SecCertificateCopyAttributeDictionary( SecCertificateRef certificate) { + if (!certificate || !(CFGetTypeID(certificate) == SecCertificateGetTypeID())) { + return NULL; + } CFAllocatorRef allocator = CFGetAllocator(certificate); - CFNumberRef certificateType, certificateEncoding; - CFStringRef label, alias; - CFDataRef skid, pubKeyDigest, certData; + CFNumberRef certificateType = NULL; + CFNumberRef certificateEncoding = NULL; + CFStringRef label = NULL; + CFStringRef alias = NULL; + CFDataRef skid = NULL; + CFDataRef pubKeyDigest = NULL; + CFDataRef certData = NULL; CFDictionaryRef dict = NULL; DICT_DECLARE(11); @@ -5048,11 +5179,16 @@ CFDictionaryRef SecCertificateCopyAttributeDictionary( SInt32 ctv = certificate->_version + 1; SInt32 cev = 3; /* CSSM_CERT_ENCODING_DER */ certificateType = CFNumberCreate(allocator, kCFNumberSInt32Type, &ctv); + require_quiet(certificateType != NULL, out); certificateEncoding = CFNumberCreate(allocator, kCFNumberSInt32Type, &cev); + require_quiet(certificateEncoding != NULL, out); certData = SecCertificateCopyData(certificate); + require_quiet(certData != NULL, out); skid = SecCertificateGetSubjectKeyID(certificate); + require_quiet(certificate->_pubKeyDER.data != NULL && certificate->_pubKeyDER.length > 0, out); pubKeyDigest = SecSHA1DigestCreate(allocator, certificate->_pubKeyDER.data, certificate->_pubKeyDER.length); + require_quiet(pubKeyDigest != NULL, out); #if 0 /* We still need to figure out how to deal with multi valued attributes. */ alias = SecCertificateCopyRFC822Names(certificate); @@ -5065,20 +5201,29 @@ CFDictionaryRef SecCertificateCopyAttributeDictionary( DICT_ADDPAIR(kSecClass, kSecClassCertificate); DICT_ADDPAIR(kSecAttrCertificateType, certificateType); DICT_ADDPAIR(kSecAttrCertificateEncoding, certificateEncoding); - if (label) + if (label) { DICT_ADDPAIR(kSecAttrLabel, label); - if (alias) + } + if (alias) { DICT_ADDPAIR(kSecAttrAlias, alias); - DICT_ADDPAIR(kSecAttrSubject, certificate->_normalizedSubject); + } + if (isData(certificate->_normalizedSubject)) { + DICT_ADDPAIR(kSecAttrSubject, certificate->_normalizedSubject); + } + require_quiet(isData(certificate->_normalizedIssuer), out); DICT_ADDPAIR(kSecAttrIssuer, certificate->_normalizedIssuer); + require_quiet(isData(certificate->_serialNumber), out); DICT_ADDPAIR(kSecAttrSerialNumber, certificate->_serialNumber); - if (skid) + if (skid) { DICT_ADDPAIR(kSecAttrSubjectKeyID, skid); + } DICT_ADDPAIR(kSecAttrPublicKeyHash, pubKeyDigest); DICT_ADDPAIR(kSecValueData, certData); - dict = DICT_CREATE(allocator); + dict = DICT_CREATE(allocator); +out: CFReleaseSafe(label); + CFReleaseSafe(alias); CFReleaseSafe(pubKeyDigest); CFReleaseSafe(certData); CFReleaseSafe(certificateEncoding); @@ -5186,10 +5331,9 @@ CFArrayRef SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate) require_quiet(currDecoded.tag == ASN1_OBJECT_ID, out); CFDataRef oid = CFDataCreate(kCFAllocatorDefault, currDecoded.content.data, currDecoded.content.length); - if (oid) { - CFArrayAppendValue(extended_key_usage_oids, oid); - CFRelease(oid); - } + require_quiet(oid, out); + CFArrayAppendValue(extended_key_usage_oids, oid); + CFReleaseNull(oid); } require_quiet(drtn == DR_EndOfSequence, out); return extended_key_usage_oids; @@ -5617,9 +5761,9 @@ SecCertificateRef SecCertificateCreateWithPEM(CFAllocatorRef allocator, return NULL; begin += sizeof(begin_cert) - 1; size_t base64_length = SecBase64Decode(begin, end - begin, NULL, 0); - if (base64_length) { + if (base64_length && (base64_length < (size_t)CFDataGetLength(pem_certificate))) { require_quiet(base64_data = calloc(1, base64_length), out); - require_quiet(base64_length = SecBase64Decode(begin, end - begin, base64_data, base64_length), out); + require_action_quiet(base64_length = SecBase64Decode(begin, end - begin, base64_data, base64_length), out, free(base64_data)); cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, base64_data, base64_length); free(base64_data); } @@ -5707,7 +5851,7 @@ exit: return certificates; } -#define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); } +#define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); } static CFArrayRef CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType, CFErrorRef* error) @@ -5911,3 +6055,25 @@ SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificate return result; } +CFArrayRef SecCertificateCopyiPhoneDeviceCAChain(void) { + CFMutableArrayRef result = NULL; + SecCertificateRef iPhoneDeviceCA = NULL, iPhoneCA = NULL, appleRoot = NULL; + + require_quiet(iPhoneDeviceCA = SecCertificateCreateWithBytes(NULL, _AppleiPhoneDeviceCA, sizeof(_AppleiPhoneDeviceCA)), + errOut); + require_quiet(iPhoneCA = SecCertificateCreateWithBytes(NULL, _AppleiPhoneCA, sizeof(_AppleiPhoneCA)), + errOut); + require_quiet(appleRoot = SecCertificateCreateWithBytes(NULL, _AppleRootCA, sizeof(_AppleRootCA)), + errOut); + + require_quiet(result = CFArrayCreateMutable(NULL, 3, &kCFTypeArrayCallBacks), errOut); + CFArrayAppendValue(result, iPhoneDeviceCA); + CFArrayAppendValue(result, iPhoneCA); + CFArrayAppendValue(result, appleRoot); + +errOut: + CFReleaseNull(iPhoneDeviceCA); + CFReleaseNull(iPhoneCA); + CFReleaseNull(appleRoot); + return result; +} diff --git a/OSX/sec/Security/SecCertificateInternal.h b/OSX/sec/Security/SecCertificateInternal.h index 998960d8..45289d57 100644 --- a/OSX/sec/Security/SecCertificateInternal.h +++ b/OSX/sec/Security/SecCertificateInternal.h @@ -160,6 +160,7 @@ OSStatus SecCertificateParseGeneralNames(const DERItem *generalNames, void *cont bool SecCertificateIsWeakKey(SecCertificateRef certificate); bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate, CFDictionaryRef keySizes); +bool SecCertificateIsStrongKey(SecCertificateRef certificate); extern const CFStringRef kSecSignatureDigestAlgorithmUnknown; extern const CFStringRef kSecSignatureDigestAlgorithmMD2; diff --git a/OSX/sec/Security/SecCertificatePath.c b/OSX/sec/Security/SecCertificatePath.c index 86c1810b..373136d2 100644 --- a/OSX/sec/Security/SecCertificatePath.c +++ b/OSX/sec/Security/SecCertificatePath.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2010,2012-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2007-2010,2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -49,7 +49,6 @@ #include #include #include -#include #include #include @@ -62,29 +61,6 @@ struct SecCertificatePath { CFRuntimeBase _base; CFIndex count; - /* Index of next parent source to search for parents. */ - CFIndex nextParentSource; - - /* Index of last certificate in chain who's signature has been verified. - 0 means nothing has been checked. 1 means the leaf has been verified - against it's issuer, etc. */ - CFIndex lastVerifiedSigner; - - /* Index of first self issued certificate in the chain. -1 mean there is - none. 0 means the leaf is self signed. */ - CFIndex selfIssued; - - /* True iff cert at index selfIssued does in fact self verify. */ - bool isSelfSigned; - - /* True if the root of this path is a trusted anchor. - FIXME get rid of this since it's a property of the evaluation, not a - static feature of a certificate path? */ - bool isAnchored; - - /* Usage constraints derived from trust settings. */ - CFMutableArrayRef usageConstraints; - SecCertificateRef certificates[]; }; @@ -96,7 +72,6 @@ static void SecCertificatePathDestroy(CFTypeRef cf) { for (ix = 0; ix < certificatePath->count; ++ix) { CFRelease(certificatePath->certificates[ix]); } - CFRelease(certificatePath->usageConstraints); } static Boolean SecCertificatePathCompare(CFTypeRef cf1, CFTypeRef cf2) { @@ -109,8 +84,6 @@ static Boolean SecCertificatePathCompare(CFTypeRef cf1, CFTypeRef cf2) { if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix])) return false; } - if (!CFEqual(cp1->usageConstraints, cp2->usageConstraints)) - return false; return true; } @@ -123,7 +96,6 @@ static CFHashCode SecCertificatePathHash(CFTypeRef cf) { for (ix = 0; ix < certificatePath->count; ++ix) { hashCode += CFHash(certificatePath->certificates[ix]); } - hashCode += CFHash(certificatePath->usageConstraints); return hashCode; } @@ -132,8 +104,7 @@ static CFStringRef SecCertificatePathCopyFormatDescription(CFTypeRef cf, CFDicti CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0); CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf)); CFStringAppendFormat(desc, NULL, - CFSTR("<%@ lvs: %" PRIdCFIndex " certs: "), typeStr, - certificatePath->lastVerifiedSigner); + CFSTR("<%@ certs: "), typeStr); CFRelease(typeStr); CFIndex ix; for (ix = 0; ix < certificatePath->count; ++ix) { @@ -149,66 +120,6 @@ static CFStringRef SecCertificatePathCopyFormatDescription(CFTypeRef cf, CFDicti return desc; } -/* Create a new certificate path from an old one. */ -SecCertificatePathRef SecCertificatePathCreate(SecCertificatePathRef path, - SecCertificateRef certificate, CFArrayRef usageConstraints) { - CFAllocatorRef allocator = kCFAllocatorDefault; - check(certificate); - CFIndex count; - CFIndex selfIssued, lastVerifiedSigner; - bool isSelfSigned; - if (path) { - count = path->count + 1; - lastVerifiedSigner = path->lastVerifiedSigner; - selfIssued = path->selfIssued; - isSelfSigned = path->isSelfSigned; - } else { - count = 1; - lastVerifiedSigner = 0; - selfIssued = -1; - isSelfSigned = false; - } - - CFIndex size = sizeof(struct SecCertificatePath) + - count * sizeof(SecCertificateRef); - SecCertificatePathRef result = - (SecCertificatePathRef)_CFRuntimeCreateInstance(allocator, - SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0); - if (!result) - return NULL; - - result->count = count; - result->nextParentSource = 0; - result->lastVerifiedSigner = lastVerifiedSigner; - result->selfIssued = selfIssued; - result->isSelfSigned = isSelfSigned; - result->isAnchored = false; - CFIndex ix; - for (ix = 0; ix < count - 1; ++ix) { - result->certificates[ix] = path->certificates[ix]; - CFRetain(result->certificates[ix]); - } - result->certificates[count - 1] = certificate; - CFRetainSafe(certificate); - - CFArrayRef emptyArray = NULL; - if (!usageConstraints) { - require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result)); - usageConstraints = emptyArray; - } - CFMutableArrayRef constraints; - if (path) { - require_action_quiet(constraints = CFArrayCreateMutableCopy(kCFAllocatorDefault, count, path->usageConstraints), exit, CFReleaseNull(result)); - } else { - require_action_quiet(constraints = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result)); - } - CFArrayAppendValue(constraints, usageConstraints); - result->usageConstraints = constraints; - -exit: - CFReleaseSafe(emptyArray); - return result; -} /* Create a new certificate path from an xpc_array of data. */ SecCertificatePathRef SecCertificatePathCreateWithXPCArray(xpc_object_t xpc_path, CFErrorRef *error) { @@ -219,26 +130,14 @@ SecCertificatePathRef SecCertificatePathCreateWithXPCArray(xpc_object_t xpc_path require_action_quiet(count = xpc_array_get_count(xpc_path), exit, SecError(errSecDecode, error, CFSTR("xpc_path array count == 0"))); size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef); require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit, SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL"))); - CFMutableArrayRef constraints; - require_action_quiet(constraints = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, SecError(errSecAllocate, error, CFSTR("failed to create constraints")); CFReleaseNull(result)); - result->count = count; - result->nextParentSource = 0; - result->lastVerifiedSigner = count; - result->selfIssued = -1; - result->isSelfSigned = false; - result->isAnchored = false; - result->usageConstraints = constraints; + result->count = count; size_t ix; for (ix = 0; ix < count; ++ix) { SecCertificateRef certificate = SecCertificateCreateWithXPCArrayAtIndex(xpc_path, ix, error); if (certificate) { result->certificates[ix] = certificate; - CFArrayRef emptyArray; - require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, SecError(errSecAllocate, error, CFSTR("failed to create emptyArray")); CFReleaseNull(result)); - CFArrayAppendValue(result->usageConstraints, emptyArray); - CFRelease(emptyArray); } else { result->count = ix; // total allocated CFReleaseNull(result); @@ -260,28 +159,14 @@ SecCertificatePathRef SecCertificatePathCreateDeserialized(CFArrayRef certificat size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef); require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit, SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL"))); - CFMutableArrayRef constraints; - require_action_quiet(constraints = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, - SecError(errSecAllocate, error, CFSTR("failed to create constraints")); CFReleaseNull(result)); result->count = count; - result->nextParentSource = 0; - result->lastVerifiedSigner = count; - result->selfIssued = -1; - result->isSelfSigned = false; - result->isAnchored = false; - result->usageConstraints = constraints; size_t ix; for (ix = 0; ix < count; ++ix) { SecCertificateRef certificate = SecCertificateCreateWithData(NULL, CFArrayGetValueAtIndex(certificates, ix)); if (certificate) { result->certificates[ix] = certificate; - CFArrayRef emptyArray; - require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, - SecError(errSecAllocate, error, CFSTR("failed to create emptyArray")); CFReleaseNull(result)); - CFArrayAppendValue(result->usageConstraints, emptyArray); - CFRelease(emptyArray); } else { result->count = ix; // total allocated CFReleaseNull(result); @@ -293,110 +178,6 @@ exit: return result; } -SecCertificatePathRef SecCertificatePathCopyFromParent( - SecCertificatePathRef path, CFIndex skipCount) { - CFAllocatorRef allocator = kCFAllocatorDefault; - CFIndex count; - CFIndex selfIssued, lastVerifiedSigner; - bool isSelfSigned; - - /* Ensure we are at least returning a path of length 1. */ - if (skipCount < 0 || path->count < 1 + skipCount) - return NULL; - - count = path->count - skipCount; - lastVerifiedSigner = path->lastVerifiedSigner > skipCount - ? path->lastVerifiedSigner - skipCount : 0; - selfIssued = path->selfIssued >= skipCount - ? path->selfIssued - skipCount : -1; - isSelfSigned = path->selfIssued >= 0 ? path->isSelfSigned : false; - - CFIndex size = sizeof(struct SecCertificatePath) + - count * sizeof(SecCertificateRef); - SecCertificatePathRef result = - (SecCertificatePathRef)_CFRuntimeCreateInstance(allocator, - SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0); - if (!result) - return NULL; - - CFMutableArrayRef constraints; - require_action_quiet(constraints = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result)); - - result->count = count; - result->nextParentSource = 0; - result->lastVerifiedSigner = lastVerifiedSigner; - result->selfIssued = selfIssued; - result->isSelfSigned = isSelfSigned; - result->isAnchored = path->isAnchored; - result->usageConstraints = constraints; - CFIndex ix; - for (ix = 0; ix < count; ++ix) { - CFIndex pathIX = ix + skipCount; - result->certificates[ix] = path->certificates[pathIX]; - CFRetain(result->certificates[ix]); - CFArrayAppendValue(result->usageConstraints, CFArrayGetValueAtIndex(path->usageConstraints, pathIX)); - } - -exit: - return result; -} - -SecCertificatePathRef SecCertificatePathCopyAddingLeaf(SecCertificatePathRef path, - SecCertificateRef leaf) { - CFAllocatorRef allocator = kCFAllocatorDefault; - CFIndex count; - CFIndex selfIssued, lastVerifiedSigner; - bool isSelfSigned; - - /* First make sure the new leaf is signed by path's current leaf. */ - SecKeyRef issuerKey = SecCertificatePathCopyPublicKeyAtIndex(path, 0); - if (!issuerKey) - return NULL; - OSStatus status = SecCertificateIsSignedBy(leaf, issuerKey); - CFRelease(issuerKey); - if (status) - return NULL; - - count = path->count + 1; - lastVerifiedSigner = path->lastVerifiedSigner + 1; - selfIssued = path->selfIssued; - isSelfSigned = path->isSelfSigned; - - CFIndex size = sizeof(struct SecCertificatePath) + - count * sizeof(SecCertificateRef); - SecCertificatePathRef result = - (SecCertificatePathRef)_CFRuntimeCreateInstance(allocator, - SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0); - if (!result) - return NULL; - - CFMutableArrayRef constraints; - require_action_quiet(constraints = CFArrayCreateMutableCopy(kCFAllocatorDefault, count, path->usageConstraints), exit, CFReleaseNull(result)); - - result->count = count; - result->nextParentSource = 0; - result->lastVerifiedSigner = lastVerifiedSigner; - result->selfIssued = selfIssued; - result->isSelfSigned = isSelfSigned; - result->isAnchored = path->isAnchored; - result->usageConstraints = constraints; - CFIndex ix; - for (ix = 1; ix < count; ++ix) { - result->certificates[ix] = path->certificates[ix - 1]; - CFRetain(result->certificates[ix]); - } - result->certificates[0] = leaf; - CFRetain(leaf); - - CFArrayRef emptyArray; - require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result)); - CFArrayInsertValueAtIndex(result->usageConstraints, 0, emptyArray); - CFRelease(emptyArray); - -exit: - return result; -} - /* Create an array of CFDataRefs from a certificate path. */ xpc_object_t SecCertificatePathCopyXPCArray(SecCertificatePathRef path, CFErrorRef *error) { xpc_object_t xpc_chain = NULL; @@ -430,6 +211,35 @@ exit: return outCerts; } +SecCertificatePathRef SecCertificatePathCreateWithCertificates(CFArrayRef certificates, CFErrorRef *error) { + SecCertificatePathRef result = NULL; + require_action_quiet(isArray(certificates), exit, + SecError(errSecParam, error, CFSTR("certificates is not an array"))); + size_t count = 0; + require_action_quiet(count = CFArrayGetCount(certificates), exit, + SecError(errSecDecode, error, CFSTR("certificates array count == 0"))); + size_t size = sizeof(struct SecCertificatePath) + count * sizeof(SecCertificateRef); + require_action_quiet(result = (SecCertificatePathRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, SecCertificatePathGetTypeID(), size - sizeof(CFRuntimeBase), 0), exit, + SecError(errSecDecode, error, CFSTR("_CFRuntimeCreateInstance returned NULL"))); + + result->count = count; + + size_t ix; + for (ix = 0; ix < count; ++ix) { + SecCertificateRef certificate = (SecCertificateRef)CFArrayGetValueAtIndex(certificates, ix); + if (certificate) { + result->certificates[ix] = CFRetainSafe(certificate); + } else { + result->count = ix; // total allocated + CFReleaseNull(result); + break; + } + } + +exit: + return result; +} + CFArrayRef SecCertificatePathCreateSerialized(SecCertificatePathRef path, CFErrorRef *error) { CFMutableArrayRef serializedCerts = NULL; require_quiet(path, exit); @@ -448,78 +258,6 @@ exit: return serializedCerts; } -/* Record the fact that we found our own root cert as our parent - certificate. */ -void SecCertificatePathSetSelfIssued( - SecCertificatePathRef certificatePath) { - if (certificatePath->selfIssued >= 0) { - secdebug("trust", "%@ is already issued at %" PRIdCFIndex, certificatePath, - certificatePath->selfIssued); - return; - } - secdebug("trust", "%@ is self issued", certificatePath); - certificatePath->selfIssued = certificatePath->count - 1; - - /* now check that the selfIssued cert was actually self-signed */ - if (certificatePath->selfIssued >= 0 && !certificatePath->isSelfSigned) { - SecCertificateRef cert = certificatePath->certificates[certificatePath->selfIssued]; - Boolean isSelfSigned = false; - OSStatus status = SecCertificateIsSelfSigned(cert, &isSelfSigned); - if ((status == errSecSuccess) && isSelfSigned) { - certificatePath->isSelfSigned = true; - } else { - certificatePath->selfIssued = -1; - } - } -} - -void SecCertificatePathSetIsAnchored( - SecCertificatePathRef certificatePath) { - secdebug("trust", "%@ is anchored", certificatePath); - certificatePath->isAnchored = true; - - /* Now check if that anchor (last cert) was actually self-signed. - * In the non-anchor case, this is handled by SecCertificatePathSetSelfIssued. - * Because anchored chains immediately go into the candidate bucket in the trust - * server, we need to ensure that the self-signed/self-issued members are set - * for the purposes of scoring. */ - if (!certificatePath->isSelfSigned && certificatePath->count > 0) { - SecCertificateRef cert = certificatePath->certificates[certificatePath->count - 1]; - Boolean isSelfSigned = false; - OSStatus status = SecCertificateIsSelfSigned(cert, &isSelfSigned); - if ((status == errSecSuccess) && isSelfSigned) { - certificatePath->isSelfSigned = true; - if (certificatePath->selfIssued == -1) { - certificatePath->selfIssued = certificatePath->count - 1; - } - } - } -} - -/* Return the index of the first non anchor certificate in the chain that is - self signed counting from the leaf up. Return -1 if there is none. */ -CFIndex SecCertificatePathSelfSignedIndex( - SecCertificatePathRef certificatePath) { - if (certificatePath->isSelfSigned) - return certificatePath->selfIssued; - return -1; -} - -Boolean SecCertificatePathIsAnchored( - SecCertificatePathRef certificatePath) { - return certificatePath->isAnchored; -} - -void SecCertificatePathSetNextSourceIndex( - SecCertificatePathRef certificatePath, CFIndex sourceIndex) { - certificatePath->nextParentSource = sourceIndex; -} - -CFIndex SecCertificatePathGetNextSourceIndex( - SecCertificatePathRef certificatePath) { - return certificatePath->nextParentSource; -} - CFIndex SecCertificatePathGetCount( SecCertificatePathRef certificatePath) { check(certificatePath); @@ -542,23 +280,6 @@ CFIndex SecCertificatePathGetIndexOfCertificate(SecCertificatePathRef path, return kCFNotFound; } -#if 0 -/* Return the leaf certificate for certificatePath. */ -SecCertificateRef SecCertificatePathGetLeaf( - SecCertificatePathRef certificatePath) { - return SecCertificatePathGetCertificateAtIndex(certificatePath, 0); -} -#endif - -/* Return the root certificate for certificatePath. Note that root is just - the top of the path as far as it is constructed. It may or may not be - trusted or self signed. */ -SecCertificateRef SecCertificatePathGetRoot( - SecCertificatePathRef certificatePath) { - return SecCertificatePathGetCertificateAtIndex(certificatePath, - SecCertificatePathGetCount(certificatePath) - 1); -} - SecKeyRef SecCertificatePathCopyPublicKeyAtIndex( SecCertificatePathRef certificatePath, CFIndex ix) { SecCertificateRef certificate = @@ -569,132 +290,3 @@ SecKeyRef SecCertificatePathCopyPublicKeyAtIndex( return SecCertificateCopyPublicKey(certificate); #endif } - -CFArrayRef SecCertificatePathGetUsageConstraintsAtIndex( - SecCertificatePathRef certificatePath, CFIndex ix) { - return (CFArrayRef)CFArrayGetValueAtIndex(certificatePath->usageConstraints, ix); -} - -SecPathVerifyStatus SecCertificatePathVerify( - SecCertificatePathRef certificatePath) { - check(certificatePath); - if (!certificatePath) - return kSecPathVerifyFailed; - for (; - certificatePath->lastVerifiedSigner < certificatePath->count - 1; - ++certificatePath->lastVerifiedSigner) { - SecKeyRef issuerKey = - SecCertificatePathCopyPublicKeyAtIndex(certificatePath, - certificatePath->lastVerifiedSigner + 1); - if (!issuerKey) - return kSecPathVerifiesUnknown; - OSStatus status = SecCertificateIsSignedBy( - certificatePath->certificates[certificatePath->lastVerifiedSigner], - issuerKey); - CFRelease(issuerKey); - if (status) { - return kSecPathVerifyFailed; - } - } - - return kSecPathVerifySuccess; -} - -bool SecCertificatePathIsValid(SecCertificatePathRef certificatePath, CFAbsoluteTime verifyTime) { - CFIndex ix; - for (ix = 0; ix < certificatePath->count; ++ix) { - if (!SecCertificateIsValid(certificatePath->certificates[ix], - verifyTime)) - return false; - } - return true; -} - -bool SecCertificatePathHasWeakHash(SecCertificatePathRef certificatePath) { - CFIndex ix, count = certificatePath->count; - - if (SecCertificatePathIsAnchored(certificatePath)) { - /* For anchored paths, don't check the hash algorithm of the anchored cert, - * since we already decided to trust it. */ - count--; - } - for (ix = 0; ix < count; ++ix) { - if (SecCertificateIsWeakHash(certificatePath->certificates[ix])) { - return true; - } - } - return false; -} - -bool SecCertificatePathHasWeakKeySize(SecCertificatePathRef certificatePath) { - CFDictionaryRef keySizes = NULL; - CFNumberRef rsaSize = NULL, ecSize = NULL; - bool result = true; - - /* RSA key sizes are 2048-bit or larger. EC key sizes are P-224 or larger. */ - require(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), errOut); - require(ecSize = CFNumberCreateWithCFIndex(NULL, 224), errOut); - const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC }; - const void *values[] = { rsaSize, ecSize }; - require(keySizes = CFDictionaryCreate(NULL, keys, values, 2, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); - - CFIndex ix; - for (ix = 0; ix < certificatePath->count; ++ix) { - if (!SecCertificateIsAtLeastMinKeySize(certificatePath->certificates[ix], - keySizes)) { - result = true; - goto errOut; - } - } - result = false; - -errOut: - CFReleaseSafe(keySizes); - CFReleaseSafe(rsaSize); - CFReleaseSafe(ecSize); - return result; -} - -/* Return a score for this certificate chain. */ -CFIndex SecCertificatePathScore( - SecCertificatePathRef 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. */ - score += 1000; - /* Shorter chains ending in a self-signed cert are preferred. */ - score -= 1 * certificatePath->count; - } else { - /* Longer chains are preferred when the chain doesn't end in a self-signed cert. */ - score += 1 * certificatePath->count; - } - - if (SecCertificatePathIsValid(certificatePath, verifyTime)) { - score += 100; - } - - if (!SecCertificatePathHasWeakHash(certificatePath)) { - score += 10; - } - - if (!SecCertificatePathHasWeakKeySize(certificatePath)) { - score += 10; - } - - return score; -} diff --git a/OSX/sec/Security/SecCertificatePath.h b/OSX/sec/Security/SecCertificatePath.h index 4d9aac04..efa8eb81 100644 --- a/OSX/sec/Security/SecCertificatePath.h +++ b/OSX/sec/Security/SecCertificatePath.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2009,2012-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2007-2009,2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -43,10 +43,6 @@ typedef struct SecCertificatePath *SecCertificatePathRef; /* SecCertificatePath API functions. */ CFTypeID SecCertificatePathGetTypeID(void); -/* Create a new certificate path from an old one. */ -SecCertificatePathRef SecCertificatePathCreate(SecCertificatePathRef path, - SecCertificateRef certificate, CFArrayRef usageConstraints); - /* Create a new certificate path from an xpc_array of datas. */ SecCertificatePathRef SecCertificatePathCreateWithXPCArray(xpc_object_t xpc_path, CFErrorRef *error); @@ -59,37 +55,12 @@ xpc_object_t SecCertificatePathCopyXPCArray(SecCertificatePathRef path, CFErrorR /* Create an array of SecCertificateRefs from a certificate path. */ CFArrayRef SecCertificatePathCopyCertificates(SecCertificatePathRef path, CFErrorRef *error); +/* Create a new certificate path from an array of SecCertificateRefs. */ +SecCertificatePathRef SecCertificatePathCreateWithCertificates(CFArrayRef certificates, CFErrorRef *error); + /* Create a serialized Certificate Array from a certificate path. */ CFArrayRef SecCertificatePathCreateSerialized(SecCertificatePathRef path, CFErrorRef *error); -SecCertificatePathRef SecCertificatePathCopyAddingLeaf(SecCertificatePathRef path, -SecCertificateRef leaf); - -/* Return a new certificate path without the first skipCount certificates. */ -SecCertificatePathRef SecCertificatePathCopyFromParent(SecCertificatePathRef path, CFIndex skipCount); - -/* Record the fact that we found our own root cert as our parent - certificate. */ -void SecCertificatePathSetSelfIssued( - SecCertificatePathRef certificatePath); - -void SecCertificatePathSetIsAnchored( - SecCertificatePathRef certificatePath); - -/* Return the index of the first non anchor certificate in the chain that is - self signed counting from the leaf up. Return -1 if there is none. */ -CFIndex SecCertificatePathSelfSignedIndex( - SecCertificatePathRef certificatePath); - -Boolean SecCertificatePathIsAnchored( - SecCertificatePathRef certificatePath); - -void SecCertificatePathSetNextSourceIndex( - SecCertificatePathRef certificatePath, CFIndex sourceIndex); - -CFIndex SecCertificatePathGetNextSourceIndex( - SecCertificatePathRef certificatePath); - CFIndex SecCertificatePathGetCount( SecCertificatePathRef certificatePath); @@ -101,42 +72,9 @@ SecCertificateRef SecCertificatePathGetCertificateAtIndex( CFIndex SecCertificatePathGetIndexOfCertificate(SecCertificatePathRef path, SecCertificateRef certificate); -/* Return the root certificate for certificatePath. Note that root is just - the top of the path as far as it is constructed. It may or may not be - trusted or self signed. */ -SecCertificateRef SecCertificatePathGetRoot( - SecCertificatePathRef certificatePath); - -CFArrayRef SecCertificatePathGetUsageConstraintsAtIndex( - SecCertificatePathRef certificatePath, CFIndex ix); - SecKeyRef SecCertificatePathCopyPublicKeyAtIndex( SecCertificatePathRef certificatePath, CFIndex ix); -typedef CFIndex SecPathVerifyStatus; -enum { - kSecPathVerifiesUnknown = -1, - kSecPathVerifySuccess = 0, - kSecPathVerifyFailed = 1 -}; - -SecPathVerifyStatus SecCertificatePathVerify( - SecCertificatePathRef certificatePath); - -bool SecCertificatePathIsValid(SecCertificatePathRef certificatePath, CFAbsoluteTime verifyTime); - -bool SecCertificatePathHasWeakHash(SecCertificatePathRef certificatePath); - -bool SecCertificatePathHasWeakKeySize(SecCertificatePathRef certificatePath); - -CFIndex SecCertificatePathScore(SecCertificatePathRef certificatePath, - CFAbsoluteTime verifyTime); - - -/* -Node based version is possible. We need to make sure we extract algorithm oid and parameters in the chain. When constructing a new path (with a new parent from a path with the child at it's head), we duplicate each child node for which we could not previously establish a public key because the parameters were missing and there was no cert with the same algorithm in the chain which does have parameters. This is because, when extended with a different parent certificate that has different parameters for the childs algorithm, the signatures in the child chain must be reverified using the new parameters and therefore might yeild a different result. -We could allow more sharing if we stored the parameters found in the search up the chain in each node, and only duplicate the nodes if the parameters differ and then reset the isSigned status of each node with changed parameters. */ - __END_DECLS #endif /* !_SECURITY_SECCERTIFICATEPATH_H_ */ diff --git a/OSX/sec/Security/SecCertificateRequest.c b/OSX/sec/Security/SecCertificateRequest.c index 330fdecb..e24320be 100644 --- a/OSX/sec/Security/SecCertificateRequest.c +++ b/OSX/sec/Security/SecCertificateRequest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2009,2012-2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2008-2009,2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -418,16 +418,6 @@ static const uint8_t encoded_asn1_true = 0xFF; static const SecAsn1Item asn1_true = { sizeof(encoded_asn1_true), (uint8_t*)&encoded_asn1_true }; -__unused static inline uint32_t highest_bit(uint32_t n) -{ - return ((n) >> 16 ? ((n)>>=16, 16) : 0) + \ - ((n) >> 8 ? ((n)>>=8, 8) : 0) + \ - ((n) >> 4 ? ((n)>>=4, 4) : 0) + \ - ((n) >> 2 ? ((n)>>=2, 2) : 0) + \ - ((n) >> 1 ? ((n)>>=1, 1) : 0) + \ - (n); -} - struct add_custom_extension_args { PLArenaPool *poolp; NSS_CertExtension *csr_extension; @@ -678,6 +668,10 @@ static const SecAsn1Item asn1_null = { sizeof(encoded_null), (uint8_t*)encoded_n CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject, CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey) { + if (subject == NULL || *subject == NULL) { + return NULL; + } + CFDataRef csr = NULL; CFDataRef publicKeyData= NULL; uint8_t *signature = NULL, *spki_params = NULL; @@ -719,7 +713,7 @@ CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject, for (one_atv = *one_rdn; one_atv->oid; one_atv++) { if (!make_nss_atv(poolp, one_atv->oid, one_atv->value, one_atv->type, &atvs[atv_num])) - return NULL; + goto out; atvps[atv_num] = &atvs[atv_num]; atv_num++; } @@ -838,7 +832,7 @@ CFDataRef SecGenerateCertificateRequest(CFArrayRef subject, { CFDataRef csr = NULL; PRArenaPool *poolp = PORT_NewArena(1024); - CFDictionaryRef pubkey_attrs = NULL; + CFDataRef publicKeyData = NULL; uint8_t *signature = NULL; if (!poolp) @@ -860,11 +854,9 @@ CFDataRef SecGenerateCertificateRequest(CFArrayRef subject, certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data = oidRsa.data; certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters = asn1_null; - pubkey_attrs = SecKeyCopyAttributeDictionary(publicKey); - CFDataRef pkcs1_pubkey = (CFDataRef)CFDictionaryGetValue(pubkey_attrs, kSecValueData); - - certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(pkcs1_pubkey); - certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(pkcs1_pubkey); + publicKeyData = SecKeyCopyExternalRepresentation(publicKey, NULL); + certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(publicKeyData); + certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(publicKeyData); certReq.reqInfo.attributes = nss_attributes_from_parameters_dict(poolp, parameters); SecCmsArraySortByDER((void **)certReq.reqInfo.attributes, kSecAsn1AttributeTemplate, NULL); @@ -902,7 +894,7 @@ CFDataRef SecGenerateCertificateRequest(CFArrayRef subject, out: if (poolp) PORT_FreeArena(poolp, PR_TRUE); - CFReleaseSafe(pubkey_attrs); + CFReleaseSafe(publicKeyData); if (signature) { free(signature); } return csr; } @@ -1176,7 +1168,7 @@ SecIdentitySignCertificate(SecIdentityRef issuer, CFDataRef serialno, uint8_t *signature = NULL; PRArenaPool *poolp = PORT_NewArena(1024); - CFDictionaryRef pubkey_attrs = NULL; + CFDataRef publicKeyData = NULL; if (!poolp) return NULL; @@ -1227,16 +1219,14 @@ SecIdentitySignCertificate(SecIdentityRef issuer, CFDataRef serialno, } /* @@@ we only handle rsa keys */ - pubkey_attrs = SecKeyCopyAttributeDictionary(publicKey); - CFTypeRef key_type = CFDictionaryGetValue(pubkey_attrs, kSecAttrKeyType); - if (key_type && CFEqual(key_type, kSecAttrKeyTypeRSA)) { + if (SecKeyGetAlgorithmId(publicKey) == kSecRSAAlgorithmID) { /* public key data and algorithm */ cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.algorithm = CSSMOID_RSA; cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.parameters = asn1_null; - CFDataRef pkcs1_pubkey = (CFDataRef)CFDictionaryGetValue(pubkey_attrs, kSecValueData); - cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(pkcs1_pubkey); - cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(pkcs1_pubkey); + publicKeyData = SecKeyCopyExternalRepresentation(publicKey, NULL); + cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(publicKeyData); + cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(publicKeyData); /* signature algorithm */ cert_tmpl.tbs.signature.algorithm = CSSMOID_SHA1WithRSA; @@ -1278,7 +1268,7 @@ out: CFReleaseSafe(privateKey); if (poolp) PORT_FreeArena(poolp, PR_TRUE); - CFReleaseSafe(pubkey_attrs); + CFReleaseSafe(publicKeyData); if (signature) { free(signature); } return cert; } diff --git a/OSX/sec/Security/SecDH.c b/OSX/sec/Security/SecDH.c index 2ff80628..a3ec3805 100644 --- a/OSX/sec/Security/SecDH.c +++ b/OSX/sec/Security/SecDH.c @@ -43,23 +43,37 @@ #define DH_DEBUG 1 #endif +/* SecDHContext memory layout ++-----------------+ +| ccdh_gp | ++-----------------+ +| ccdh_full_ctx | ++-----------------+ +*/ + static inline ccdh_gp_t SecDH_gp(SecDHContext dh) { - ccdh_gp_t gp; - gp.gp = (ccdh_gp *)dh; - return gp; + return (ccdh_gp_t)dh; } static inline ccdh_full_ctx_t SecDH_priv(SecDHContext dh) { - void *p = dh; - cczp_t zp; - zp.zp = (struct cczp *) dh; - cc_size s = ccn_sizeof_n(cczp_n(zp)); - ccdh_full_ctx_t priv = { .hdr = (struct ccdh_ctx_header *)(p+ccdh_gp_size(s)) }; + 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; } +size_t SecDHGetMaxKeyLength(SecDHContext dh) { + + ccdh_gp_t gp = SecDH_gp(dh); + cc_size s = ccn_sizeof_n(ccdh_gp_n(gp)); + + return s; +} + + static inline size_t SecDH_context_size(size_t p_len) { cc_size n = ccn_nof_size(p_len); @@ -102,10 +116,10 @@ OSStatus SecDHCreate(uint32_t g, const uint8_t *p, size_t p_len, cc_size n = ccn_nof_size(p_len); size_t context_size = SecDH_context_size(p_len); void *context = malloc(context_size); - bzero(context, context_size); + cc_clear(context_size, context); ccdh_gp_t gp; - gp.gp = context; + gp = context; CCDH_GP_N(gp) = n; CCDH_GP_L(gp) = l; @@ -115,9 +129,9 @@ OSStatus SecDHCreate(uint32_t g, const uint8_t *p, size_t p_len, if(recip) { if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), recip_len, recip)) goto errOut; - CCZP_MOD_PRIME(gp.zp) = cczp_mod; + CCZP_MOD_PRIME(CCDH_GP_ZP(gp)) = cczp_mod; } else { - cczp_init(gp.zp); + cczp_init(CCDH_GP_ZP(gp)); }; ccn_seti(n, CCDH_GP_G(gp), g); @@ -203,8 +217,7 @@ OSStatus SecDHCreateFromParameters(const uint8_t *params, bzero(context, context_size); - ccdh_gp_t gp; - gp.gp = context; + ccdh_gp_t gp = context; CCDH_GP_N(gp) = n; CCDH_GP_L(gp) = l; @@ -214,9 +227,9 @@ OSStatus SecDHCreateFromParameters(const uint8_t *params, if(decodedParams.recip.length) { if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), decodedParams.recip.length, decodedParams.recip.data)) goto errOut; - CCZP_MOD_PRIME(gp.zp) = cczp_mod; + CCZP_MOD_PRIME(CCDH_GP_ZP(gp)) = cczp_mod; } else { - cczp_init(gp.zp); + cczp_init(CCDH_GP_ZP(gp)); }; if(ccn_read_uint(n, CCDH_GP_G(gp), decodedParams.g.length, decodedParams.g.data)) @@ -249,14 +262,6 @@ OSStatus SecDHCreateFromAlgorithmId(const uint8_t *alg, size_t alg_len, algorithmId.params.length, pdh); } -size_t SecDHGetMaxKeyLength(SecDHContext dh) { - cczp_const_t zp; - zp.u = (cc_unit *)dh; - - return ccn_sizeof_n(cczp_n(zp)); -} - - OSStatus SecDHGenerateKeypair(SecDHContext dh, uint8_t *pub_key, size_t *pub_key_len) { @@ -290,6 +295,7 @@ OSStatus SecDHComputeKey(SecDHContext dh, if(ccdh_import_pub(gp, pub_key_len, pub_key, pub)) return errSecInvalidKey; + //ccdh_compute_shared_secret() cannot be used directly, because it doesn't allow truncated output. Buffering is needed. if(ccdh_compute_key(priv, pub, r)) return errSecInvalidKey; @@ -307,7 +313,7 @@ void SecDHDestroy(SecDHContext dh) { cc_size p_len = ccn_sizeof_n(ccdh_gp_n(gp)); size_t context_size = SecDH_context_size(p_len); - bzero(dh, context_size); + cc_clear(context_size, dh); free(dh); } diff --git a/OSX/sec/Security/SecECKey.c b/OSX/sec/Security/SecECKey.c index 7c1ab2b3..8436aca7 100644 --- a/OSX/sec/Security/SecECKey.c +++ b/OSX/sec/Security/SecECKey.c @@ -68,10 +68,9 @@ static CFIndex SecECKeyGetAlgorithmID(SecKeyRef key) { /* Public key static functions. */ static void SecECPublicKeyDestroy(SecKeyRef key) { /* Zero out the public key */ - ccec_pub_ctx_t pubkey; - pubkey.pub = key->key; - if (ccec_ctx_cp(pubkey).zp) - cc_clear(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey))), pubkey.pub); + ccec_pub_ctx_t pubkey = key->key; + if (ccec_ctx_cp(pubkey)) + cc_clear(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey))), pubkey); } static ccec_const_cp_t getCPForPublicSize(CFIndex encoded_length) @@ -80,8 +79,7 @@ static ccec_const_cp_t getCPForPublicSize(CFIndex encoded_length) if(ccec_keysize_is_supported(keysize)) { return ccec_get_cp(keysize); } - ccec_const_cp_t nullCP = { .zp = NULL }; - return nullCP; + return NULL; } static ccec_const_cp_t getCPForPrivateSize(CFIndex encoded_length) @@ -90,8 +88,7 @@ static ccec_const_cp_t getCPForPrivateSize(CFIndex encoded_length) if(ccec_keysize_is_supported(keysize)) { return ccec_get_cp(keysize); } - ccec_const_cp_t nullCP = { .zp = NULL }; - return nullCP; + return NULL; } static ccoid_t ccoid_secp192r1 = CC_EC_OID_SECP192R1; @@ -120,8 +117,7 @@ static ccec_const_cp_t ccec_cp_for_oid(const unsigned char *oid) static OSStatus SecECPublicKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { - ccec_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccec_pub_ctx_t pubkey = key->key; OSStatus err = errSecParam; switch (encoding) { @@ -134,7 +130,7 @@ static OSStatus SecECPublicKeyInit(SecKeyRef key, } ccec_const_cp_t cp = getCPForPublicSize(derKey->keyLength); - require_action_quiet(cp.zp, errOut, err = errSecDecode); + 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) @@ -144,19 +140,18 @@ static OSStatus SecECPublicKeyInit(SecKeyRef key, case kSecKeyEncodingBytes: { ccec_const_cp_t cp = getCPForPublicSize(keyDataLength); - require_action_quiet(cp.zp, errOut, err = errSecDecode); + require_action_quiet(cp, errOut, err = errSecDecode); err = (ccec_import_pub(cp, keyDataLength, keyData, pubkey) ? errSecDecode : errSecSuccess); break; } case kSecExtractPublicFromPrivate: { - ccec_full_ctx_t fullKey; - fullKey._full = (ccec_full_ctx *) keyData; + ccec_full_ctx_t fullKey = (ccec_full_ctx_t)keyData; cc_size fullKeyN = ccec_ctx_n(fullKey); require_quiet(fullKeyN <= ccn_nof(kMaximumECKeySize), errOut); - memcpy(pubkey._pub, fullKey.pub, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN))); + memcpy(pubkey, fullKey, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN))); err = errSecSuccess; break; } @@ -184,14 +179,14 @@ static CFTypeRef SecECPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperatio int err = -1; size_t sigLen = CFDataGetLength(in2); uint8_t *sig = (uint8_t *)CFDataGetBytePtr(in2); - ccec_pub_ctx_t pubkey = { .pub = key->key }; + ccec_pub_ctx_t pubkey = key->key; if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) { err = ccec_verify(pubkey, CFDataGetLength(in1), CFDataGetBytePtr(in1), sigLen, sig, &valid); } else { - if (ccec_signature_r_s_size(pubkey.fullt) * 2 != sigLen) { + if (ccec_signature_r_s_size(pubkey) * 2 != sigLen) { SecError(errSecParam, error, CFSTR("bad signature size, got %d, expecting %d bytes"), - (int)sigLen, (int)ccec_signature_r_s_size(pubkey.fullt) * 2); + (int)sigLen, (int)ccec_signature_r_s_size(pubkey) * 2); return NULL; } err = ccec_verify_composite(pubkey, CFDataGetLength(in1), CFDataGetBytePtr(in1), @@ -219,9 +214,7 @@ static CFTypeRef SecECPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperatio static size_t SecECPublicKeyBlockSize(SecKeyRef key) { /* Get key size in octets */ - ccec_pub_ctx_t pubkey; - pubkey.pub = key->key; - return ccec_ctx_size(pubkey); + return ccec_ctx_size(ccec_ctx_pub(key->key)); } /* Encode the public key and return it in a newly allocated CFDataRef. */ @@ -234,15 +227,13 @@ static CFDataRef SecECPublicKeyExport(CFAllocatorRef allocator, } static CFDataRef SecECPublicKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { - ccec_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccec_pub_ctx_t pubkey = key->key; return SecECPublicKeyExport(NULL, pubkey); } static OSStatus SecECPublicKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation) { - ccec_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccec_pub_ctx_t pubkey = key->key; CFAllocatorRef allocator = CFGetAllocator(key); *serailziation = SecECPublicKeyExport(allocator, pubkey); @@ -287,7 +278,7 @@ static CFStringRef SecECPublicKeyCopyKeyDescription(SecKeyRef key) CFMutableStringRef strings[2] = { NULL, }; const char* curve = getCurveName(key); - ccec_pub_ctx_t ecPubkey = { .pub = key->key }; + ccec_pub_ctx_t ecPubkey = key->key; size_t len = ccec_ctx_size(ecPubkey); uint8_t buffer[len]; for (int i = 0; i < 2; ++i) { @@ -329,15 +320,13 @@ static const struct ccec_rfc6637_curve * get_rfc6637_curve(SecKeyRef key) static CFDataRef SecECKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) { - ccec_pub_ctx_t pubkey; + ccec_pub_ctx_t pubkey = key->key; int err = errSecUnimplemented; const struct ccec_rfc6637_curve *curve; const struct ccec_rfc6637_wrap *wrap = NULL; uint8_t sym_alg = 0; int32_t flags = 0; - pubkey.pub = key->key; - if (type != kSecKeyWrapPublicKeyPGP) { SecError(errSecUnsupportedOperation, error, CFSTR("unsupported key wrapping algorithm")); return NULL; @@ -444,17 +433,16 @@ SecKeyRef SecKeyCreateECPublicKey(CFAllocatorRef allocator, /* Private key static functions. */ static void SecECPrivateKeyDestroy(SecKeyRef key) { /* Zero out the public key */ - ccec_full_ctx_t fullkey; - fullkey.hdr = key->key; - if (ccec_ctx_cp(fullkey).zp) - cc_clear(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey))), fullkey.hdr); + ccec_full_ctx_t fullkey = key->key; + + if (ccec_ctx_cp(fullkey)) + cc_clear(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey))), fullkey); } static OSStatus SecECPrivateKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { - ccec_full_ctx_t fullkey; - fullkey.hdr = key->key; + ccec_full_ctx_t fullkey = key->key; OSStatus err = errSecParam; switch (encoding) { @@ -470,11 +458,11 @@ static OSStatus SecECPrivateKeyInit(SecKeyRef key, require_noerr_quiet(ccec_der_import_priv_keytype(keyDataLength, keyData, (ccoid_t*)&oid, &n), abort); cp = ccec_cp_for_oid(oid); - if (cp.zp == NULL) { + if (cp == NULL) { cp = ccec_curve_for_length_lookup(n * 8 /* bytes -> bits */, ccec_cp_192(), ccec_cp_224(), ccec_cp_256(), ccec_cp_384(), ccec_cp_521(), NULL); } - require_action_quiet(cp.zp != NULL, abort, err = errSecDecode); + require_action_quiet(cp != NULL, abort, err = errSecDecode); ccec_ctx_init(cp, fullkey); require_noerr_quiet(ccec_der_import_priv(cp, keyDataLength, keyData, fullkey), abort); @@ -484,15 +472,15 @@ static OSStatus SecECPrivateKeyInit(SecKeyRef key, case kSecKeyEncodingBytes: { ccec_const_cp_t cp = getCPForPrivateSize(keyDataLength); - require_quiet(cp.zp != NULL, abort); + require_quiet(cp != NULL, abort); ccec_ctx_init(cp, fullkey); - size_t pubSize = ccec_export_pub_size(fullkey); + size_t pubSize = ccec_export_pub_size(ccec_ctx_pub(fullkey)); - require_quiet(pubSize < (size_t) keyDataLength, abort); - require_noerr_action_quiet(ccec_import_pub(cp, pubSize, keyData, fullkey), - abort, - err = errSecDecode); + require(pubSize < (size_t) keyDataLength, abort); + require_noerr_action_quiet(ccec_import_pub(cp, pubSize, keyData, ccec_ctx_pub(fullkey)), + abort, + err = errSecDecode); keyData += pubSize; @@ -516,7 +504,7 @@ static OSStatus SecECPrivateKeyInit(SecKeyRef key, ccec_const_cp_t cp = ccec_get_cp(keyLengthInBits); - if (!cp.zp) { + if (!cp) { secwarning("Invalid or missing key size in: %@", parameters); return errSecKeySizeNotAllowed; } @@ -539,13 +527,13 @@ static CFTypeRef SecECPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperati // Default answer is 'unsupported', unless we find out that we can support it. CFTypeRef result = kCFNull; - ccec_full_ctx_t fullkey = { .hdr = key->key }; + ccec_full_ctx_t fullkey = key->key; switch (operation) { case kSecKeyOperationTypeSign: { if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureRFC4754)) { if (mode == kSecKeyOperationModePerform) { // Perform r/s mode of signature. - cc_size r_s_size = ccec_signature_r_s_size(fullkey); + cc_size r_s_size = ccec_signature_r_s_size(ccec_ctx_public(fullkey)); result = CFDataCreateMutableWithScratch(NULL, r_s_size << 1); uint8_t *signatureBuffer = CFDataGetMutableBytePtr((CFMutableDataRef)result); int err = ccec_sign_composite(fullkey, CFDataGetLength(in1), CFDataGetBytePtr(in1), @@ -581,10 +569,9 @@ static CFTypeRef SecECPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperati if (mode == kSecKeyOperationModePerform) { int err; ccec_const_cp_t cp = getCPForPublicSize(CFDataGetLength(in1)); - require_action_quiet(cp.zp != NULL, out, + require_action_quiet(cp != NULL, out, SecError(errSecParam, error, CFSTR("ECpriv sharedsecret: bad public key"))); - uint8_t pubkeyBuffer[ccec_pub_ctx_size(ccn_sizeof(kMaximumECKeySize))]; - ccec_pub_ctx_t pubkey = { .pub = (struct ccec_ctx_public *)pubkeyBuffer }; + ccec_pub_ctx_decl_cp(cp, pubkey); err = ccec_import_pub(cp, CFDataGetLength(in1), CFDataGetBytePtr(in1), pubkey); require_noerr_action_quiet(err, out, SecError(errSecParam, error, CFSTR("ECpriv sharedsecret: bad public key (err %d)"), err)); @@ -611,19 +598,17 @@ out: } static size_t SecECPrivateKeyBlockSize(SecKeyRef key) { - ccec_full_ctx_t fullkey; - fullkey.hdr = key->key; + ccec_full_ctx_t fullkey = key->key; /* Get key size in octets */ return ccec_ctx_size(fullkey); } static OSStatus SecECPrivateKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serailziation) { - ccec_full_ctx_t fullkey; - fullkey.hdr = key->key; + ccec_full_ctx_t fullkey = key->key; CFAllocatorRef allocator = CFGetAllocator(key); - *serailziation = SecECPublicKeyExport(allocator, fullkey); + *serailziation = SecECPublicKeyExport(allocator, ccec_ctx_pub(fullkey)); if (NULL == *serailziation) return errSecDecode; @@ -632,13 +617,12 @@ static OSStatus SecECPrivateKeyCopyPublicOctets(SecKeyRef key, CFDataRef *serail } static CFDataRef SecECPrivateKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { - ccec_full_ctx_t fullkey; - fullkey.hdr = key->key; + ccec_full_ctx_t fullkey = key->key; size_t prime_size = ccec_cp_prime_size(ccec_ctx_cp(fullkey)); - size_t key_size = ccec_export_pub_size(fullkey) + prime_size; + size_t key_size = ccec_export_pub_size(ccec_ctx_pub(fullkey)) + prime_size; CFMutableDataRef blob = CFDataCreateMutableWithScratch(NULL, key_size); - ccec_export_pub(fullkey, CFDataGetMutableBytePtr(blob)); - UInt8 *dest = CFDataGetMutableBytePtr(blob) + ccec_export_pub_size(fullkey); + ccec_export_pub(ccec_ctx_pub(fullkey), CFDataGetMutableBytePtr(blob)); + UInt8 *dest = CFDataGetMutableBytePtr(blob) + ccec_export_pub_size(ccec_ctx_pub(fullkey)); const cc_unit *k = ccec_ctx_k(fullkey); ccn_write_uint_padded(ccec_ctx_n(fullkey), k, prime_size, dest); return blob; @@ -646,8 +630,6 @@ static CFDataRef SecECPrivateKeyCopyExternalRepresentation(SecKeyRef key, CFErro static CFDictionaryRef SecECPrivateKeyCopyAttributeDictionary(SecKeyRef key) { /* Export the full ec key pair. */ - ccec_full_ctx_t fullkey; - fullkey.hdr = key->key; CFDataRef fullKeyBlob = SecECPrivateKeyCopyExternalRepresentation(key, NULL); CFDictionaryRef dict = SecKeyGeneratePrivateAttributeDictionary(key, kSecAttrKeyTypeEC, fullKeyBlob); @@ -666,14 +648,12 @@ static CFDataRef SecECKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDat { const struct ccec_rfc6637_curve *curve; const struct ccec_rfc6637_unwrap *unwrap; - ccec_full_ctx_t fullkey; + ccec_full_ctx_t fullkey = key->key; CFMutableDataRef data; int res; uint8_t sym_alg = 0; int32_t flags = 0; - fullkey.hdr = key->key; - curve = get_rfc6637_curve(key); if (curve == NULL) { SecError(errSecUnsupportedOperation, error, CFSTR("unsupported curve")); diff --git a/OSX/sec/Security/SecEMCS.m b/OSX/sec/Security/SecEMCS.m index e22cb7c5..6facd618 100644 --- a/OSX/sec/Security/SecEMCS.m +++ b/OSX/sec/Security/SecEMCS.m @@ -79,28 +79,28 @@ CopyWrappedKey(CFDataRef wrappingKey, CFDataRef unwrappedKey) return wrappedKey; } -static CFDataRef +static NSData * CopyUnwrappedKey(CFDataRef wrappingKey, CFDataRef wrappedKey) { const struct ccmode_ecb *ecb_mode = ccaes_ecb_decrypt_mode(); ccecb_ctx_decl(ccecb_context_size(ecb_mode), key); - CFMutableDataRef unwrappedKey = NULL; + NSMutableData *unwrappedKey = NULL; require(CFDataGetLength(wrappedKey) >= CCWRAP_SEMIBLOCK, out); require(CFDataGetLength(wrappingKey) == KEY_LENGTH, out); ccecb_init(ecb_mode, key, CFDataGetLength(wrappingKey), CFDataGetBytePtr(wrappingKey)); - unwrappedKey = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), ccwrap_unwrapped_size(CFDataGetLength(wrappedKey))); + unwrappedKey = CFBridgingRelease(CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), ccwrap_unwrapped_size(CFDataGetLength(wrappedKey)))); require(unwrappedKey, out); size_t obytes = 0; int unwrap_status = ccwrap_auth_decrypt(ecb_mode, key, CFDataGetLength(wrappedKey), CFDataGetBytePtr(wrappedKey), - &obytes, CFDataGetMutableBytePtr(unwrappedKey)); + &obytes, [unwrappedKey mutableBytes]); if (unwrap_status == 0) { - assert(obytes == (size_t)CFDataGetLength(unwrappedKey)); + assert(obytes == (size_t)[unwrappedKey length]); } else { - CFReleaseNull(unwrappedKey); + unwrappedKey = NULL; goto out; } @@ -161,10 +161,10 @@ CreateDerivedKey(CFDataRef salt, long iterations, NSString *managedCredential) NSData * SecEMCSCreateDerivedEMCSKey(NSDictionary *iDMSData, NSString *managedCredential, NSError **error) { - CFDataRef key = NULL, emcsKey = NULL; - CFDataRef userDerivedKey = NULL; + CFDataRef userDerivedKey = NULL, emcsKey = NULL; CFNumberRef number = NULL; CFDataRef salt = NULL; + NSData *key = NULL; long iterations; salt = CFDictionaryGetValue((__bridge CFDictionaryRef)iDMSData, kiDMSSalt); @@ -185,7 +185,7 @@ SecEMCSCreateDerivedEMCSKey(NSDictionary *iDMSData, NSString *managedCredential, key = CopyUnwrappedKey(userDerivedKey, emcsKey); CFRelease(userDerivedKey); - return (__bridge NSData *)key; + return key; } /* diff --git a/OSX/sec/Security/SecExports.exp-in b/OSX/sec/Security/SecExports.exp-in index 0a85fdd6..fb94cab5 100644 --- a/OSX/sec/Security/SecExports.exp-in +++ b/OSX/sec/Security/SecExports.exp-in @@ -40,6 +40,7 @@ _SecPasswordValidatePasswordFormat // _SecBase64Encode +_SecBase64Decode #if TARGET_OS_IPHONE _SecBase64Encode2 #endif @@ -51,8 +52,11 @@ _SecIsInternalRelease // Policies +_kSecPolicyAppleAppTransportSecurity _kSecPolicyAppleAST2DiagnosticsServerAuth _kSecPolicyAppleATVVPNProfileSigning +_kSecPolicyAppleBasicAttestationSystem +_kSecPolicyAppleBasicAttestationUser _kSecPolicyAppleCodeSigning _kSecPolicyAppleEAP _kSecPolicyAppleEscrowProxyCompatibilityServerAuth @@ -79,13 +83,17 @@ _kSecPolicyAppleiPhoneApplicationSigning _kSecPolicyAppleiPhoneDeviceCertificate _kSecPolicyAppleiPhoneProfileApplicationSigning _kSecPolicyAppleiPhoneProvisioningProfileSigning +_kSecPolicyAppleiPhoneVPNApplicationSigning _kSecPolicyAppleIPsec _kSecPolicyAppleiTunesStoreURLBag _kSecPolicyAppleLegacyPushService _kSecPolicyAppleLockdownPairing +_kSecPolicyAppleMacOSProfileApplicationSigning _kSecPolicyAppleMMCSCompatibilityServerAuth _kSecPolicyAppleMMCSService _kSecPolicyAppleMobileAsset +_kSecPolicyAppleMobileAssetDevelopment +_kSecPolicyAppleMobileSoftwareUpdate _kSecPolicyAppleMobileStore _kSecPolicyAppleOCSPSigner _kSecPolicyAppleOSXProvisioningProfileSigning @@ -121,6 +129,17 @@ _kSecPolicyAppleURLBag _kSecPolicyAppleWarsaw _kSecPolicyAppleX509Basic _kSecPolicyMacAppStoreReceipt +_kSecPolicyNameAppleAST2Service +_kSecPolicyNameAppleEscrowProxyService +_kSecPolicyNameAppleFMiPService +_kSecPolicyNameAppleGalaxyProviderService +_kSecPolicyNameAppleGSService +_kSecPolicyNameAppleHomeKitService +_kSecPolicyNameAppleiCloudSetupService +_kSecPolicyNameAppleIDSService +_kSecPolicyNameAppleMMCSService +_kSecPolicyNameApplePPQService +_kSecPolicyNameApplePushService // Policy Checks _kSecPolicyAppleAnchorIncludeTestRoots @@ -157,6 +176,7 @@ _kSecPolicyCheckLeafMarkersProdAndQA _kSecPolicyCheckNoNetworkAccess _kSecPolicyCheckNonEmptySubject _kSecPolicyCheckNotValidBefore +_kSecPolicyCheckPinningRequired _kSecPolicyCheckQualifiedCertStatements _kSecPolicyCheckRevocation _kSecPolicyCheckRevocationAny @@ -172,6 +192,7 @@ _kSecPolicyCheckSubjectCommonNameTEST _kSecPolicyCheckSubjectOrganization _kSecPolicyCheckSubjectOrganizationalUnit _kSecPolicyCheckSystemTrustedWeakHash +_kSecPolicyCheckSystemTrustedWeakKey _kSecPolicyCheckUsageConstraints _kSecPolicyCheckValidIntermediates _kSecPolicyCheckValidLeaf @@ -211,6 +232,7 @@ _SecPolicyCheckCertExtendedKeyUsage _SecPolicyCheckCertLeafMarkerOid _SecPolicyCheckCertLeafMarkerOidWithoutValueCheck _SecPolicyCheckCertKeyUsage +_SecPolicyCheckCertNonEmptySubject _SecPolicyCheckCertNotValidBefore _SecPolicyCheckCertSignatureHashAlgorithms _SecPolicyCheckCertSSLHostname @@ -222,8 +244,11 @@ _SecPolicyCheckCertSubjectOrganization _SecPolicyCheckCertSubjectOrganizationalUnit _SecPolicyCopyProperties _SecPolicyCreate +_SecPolicyCreateAppleAppTransportSecurity _SecPolicyCreateAppleAST2Service _SecPolicyCreateAppleATVVPNProfileSigning +_SecPolicyCreateAppleBasicAttestationSystem +_SecPolicyCreateAppleBasicAttestationUser _SecPolicyCreateAppleCompatibilityEscrowProxyService _SecPolicyCreateAppleCompatibilityMMCSService _SecPolicyCreateAppleCompatibilityiCloudSetupService @@ -265,11 +290,15 @@ _SecPolicyCreateiPhoneApplicationSigning _SecPolicyCreateiPhoneDeviceCertificate _SecPolicyCreateiPhoneProfileApplicationSigning _SecPolicyCreateiPhoneProvisioningProfileSigning +_SecPolicyCreateiPhoneVPNApplicationSigning _SecPolicyCreateIPSec _SecPolicyCreateiTunesStoreURLBag _SecPolicyCreateLockdownPairing _SecPolicyCreateMacAppStoreReceipt +_SecPolicyCreateMacOSProfileApplicationSigning _SecPolicyCreateMobileAsset +_SecPolicyCreateMobileAssetDevelopment +_SecPolicyCreateMobileSoftwareUpdate _SecPolicyCreateMobileStoreSigner _SecPolicyCreateOCSPSigner _SecPolicyCreateOSXProvisioningProfileSigning @@ -291,6 +320,8 @@ _SecPolicyCreateWithProperties _SecPolicyGetName _SecPolicyGetOidString _SecPolicyGetTypeID +_SecPolicySetName +_SecPolicySetOptionsValue #if TARGET_OS_OSX _SecPolicyCopy _SecPolicyCopyAll @@ -308,6 +339,8 @@ _SecPolicySetProperties _SecPolicySetValue #endif +_kSecCertificateDetailSHA1Digest +_kSecCertificateDetailStatusCodes _kSecPropertyKeyLabel _kSecPropertyKeyLocalizedLabel @@ -338,7 +371,6 @@ _kSecTrustCertificateTransparencyWhiteList _kSecTrustEvaluationDate _kSecTrustExtendedValidation _kSecTrustInfoCertificateTransparencyKey -_kSecTrustInfoCertificateTransparencyWhiteListKey _kSecTrustInfoCompanyNameKey _kSecTrustInfoExtendedValidationKey _kSecTrustInfoRevocationKey @@ -377,6 +409,7 @@ _SecTrustGetOTAPKIAssetVersionNumber _SecTrustGetTrustResult _SecTrustGetTypeID _SecTrustGetVerifyTime +_SecTrustIsExpiredOnly _SecTrustOTAPKIGetUpdatedAsset _SecTrustSerialize _SecTrustSetAnchorCertificates @@ -385,6 +418,8 @@ _SecTrustSetExceptions _SecTrustSetKeychainsAllowed _SecTrustSetNetworkFetchAllowed _SecTrustSetOCSPResponse +_SecTrustSetPinningException +_SecTrustSetPinningPolicyName _SecTrustSetPolicies _SecTrustSetSignedCertificateTimestamps _SecTrustSetTrustedLogs @@ -399,7 +434,7 @@ _SecTrustGetCssmResultCode _SecTrustGetResult _SecTrustGetTPHandle _SecTrustGetUserTrust -_SecTrustLegacySourcesEventRunloopCreate +_SecTrustLegacySourcesListenForKeychainEvents _SecTrustLegacyCRLFetch _SecTrustLegacyCRLStatus _SecTrustSetKeychains @@ -408,32 +443,33 @@ _SecTrustSetParameters _SecTrustSetUserTrust _SecTrustSetUserTrustLegacy -_SecTrustSettingsCopyCertificates -_SecTrustSettingsCopyCertificatesForUserAdminDomains -_SecTrustSettingsCopyModificationDate -_SecTrustSettingsCopyQualifiedCerts -_SecTrustSettingsCopyTrustSettings -_SecTrustSettingsCopyUnrestrictedRoots -_SecTrustSettingsCreateExternalRepresentation -_SecTrustSettingsEvaluateCert -_SecTrustSettingsImportExternalRepresentation -_SecTrustSettingsRemoveTrustSettings -_SecTrustSettingsSetTrustSettings -_SecTrustSettingsSetTrustSettingsExternal -_SecTrustedApplicationCopyData -_SecTrustedApplicationCopyExternalRepresentation -_SecTrustedApplicationCopyRequirement -_SecTrustedApplicationCreateApplicationGroup -_SecTrustedApplicationCreateFromPath -_SecTrustedApplicationCreateFromRequirement -_SecTrustedApplicationCreateWithExternalRepresentation -_SecTrustedApplicationGetTypeID -_SecTrustedApplicationIsUpdateCandidate -_SecTrustedApplicationMakeEquivalent -_SecTrustedApplicationRemoveEquivalence -_SecTrustedApplicationSetData -_SecTrustedApplicationUseAlternateSystem -_SecTrustedApplicationValidateWithPath +_SecTrustSettingsCopyCertificates +_SecTrustSettingsCopyCertificatesForUserAdminDomains +_SecTrustSettingsCopyModificationDate +_SecTrustSettingsCopyQualifiedCerts +_SecTrustSettingsCopyTrustSettings +_SecTrustSettingsCopyUnrestrictedRoots +_SecTrustSettingsCreateExternalRepresentation +_SecTrustSettingsEvaluateCert +_SecTrustSettingsImportExternalRepresentation +_SecTrustSettingsRemoveTrustSettings +_SecTrustSettingsSetTrustSettings +_SecTrustSettingsSetTrustSettingsExternal +_SecTrustSettingsSetTrustedCertificateForSSLHost +_SecTrustedApplicationCopyData +_SecTrustedApplicationCopyExternalRepresentation +_SecTrustedApplicationCopyRequirement +_SecTrustedApplicationCreateApplicationGroup +_SecTrustedApplicationCreateFromPath +_SecTrustedApplicationCreateFromRequirement +_SecTrustedApplicationCreateWithExternalRepresentation +_SecTrustedApplicationGetTypeID +_SecTrustedApplicationIsUpdateCandidate +_SecTrustedApplicationMakeEquivalent +_SecTrustedApplicationRemoveEquivalence +_SecTrustedApplicationSetData +_SecTrustedApplicationUseAlternateSystem +_SecTrustedApplicationValidateWithPath #endif #if TARGET_OS_IPHONE @@ -460,6 +496,7 @@ _SecIdentityGetTypeID // Certificate // +_kSecCertificateDetailSHA1Digest _kSecCertificateEscrowFileName _kSecCertificateProductionEscrowKey _kSecCertificateProductionPCSEscrowKey @@ -475,6 +512,7 @@ _SecCertificateCopyEscrowRoots _SecCertificateCopyExtendedKeyUsage _SecCertificateCopyiAPAuthCapabilities _SecCertificateCopyIPAddresses +_SecCertificateCopyiPhoneDeviceCAChain _SecCertificateCopyIssuerSHA1Digest _SecCertificateCopyIssuerSequence _SecCertificateCopyIssuerSummary @@ -490,6 +528,7 @@ _SecCertificateCopyPublicKey _SecCertificateCopyPublicKeySHA1Digest _SecCertificateCopyRFC822Names _SecCertificateCopySerialNumber +_SecCertificateCopySerialNumberData _SecCertificateCopySHA256Digest _SecCertificateCopySignedCertificateTimestamps _SecCertificateCopySubjectPublicKeyInfoSHA1Digest @@ -539,6 +578,7 @@ _SecCertificateIsOidString _SecCertificateIsSelfSigned _SecCertificateIsSelfSignedCA _SecCertificateIsSignedBy +_SecCertificateIsStrongKey _SecCertificateIsValid _SecCertificateIsWeakHash _SecCertificateIsWeakKey @@ -550,6 +590,7 @@ _SecCertificateSetKeychainItem _SecCertificateShow _SecCertificateVersion _SecDistinguishedNameCopyNormalizedContent +_SecDistinguishedNameCopyNormalizedSequence #if TARGET_OS_OSX _SecCertificateAddToKeychain _SecCertificateCopyFieldValues @@ -601,28 +642,14 @@ _SecCertificateBundleImport // // CertificatePath // -_SecCertificatePathCopyAddingLeaf -_SecCertificatePathCopyCertificates -_SecCertificatePathCopyFromParent _SecCertificatePathCopyPublicKeyAtIndex -_SecCertificatePathCreate +_SecCertificatePathCopyXPCArray +_SecCertificatePathCreateDeserialized _SecCertificatePathCreateSerialized +_SecCertificatePathCreateWithCertificates _SecCertificatePathGetCertificateAtIndex _SecCertificatePathGetCount _SecCertificatePathGetIndexOfCertificate -_SecCertificatePathGetNextSourceIndex -_SecCertificatePathGetRoot -_SecCertificatePathGetUsageConstraintsAtIndex -_SecCertificatePathHasWeakHash -_SecCertificatePathHasWeakKeySize -_SecCertificatePathIsAnchored -_SecCertificatePathIsValid -_SecCertificatePathScore -_SecCertificatePathSelfSignedIndex -_SecCertificatePathSetIsAnchored -_SecCertificatePathSetNextSourceIndex -_SecCertificatePathSetSelfIssued -_SecCertificatePathVerify #if TARGET_OS_IPHONE // @@ -700,6 +727,7 @@ _SecOTRSessionCreateRemote _SecOTRSessionProcessPacketRemote #endif +_SecOTRSessionIsSessionInAwaitingState _SecOTRFullIdentityCreateFromSecKeyRef _SecOTRSIsForKeys _SecOTRPublicIdentityCreateFromSecKeyRef @@ -734,13 +762,12 @@ _SecDHEncodeParams _SecDHGenerateKeypair _SecDHGetMaxKeyLength -#if TARGET_OS_IPHONE // // Securityd client // _gSecurityd -#endif +_gTrustd #if TARGET_OS_IPHONE // @@ -751,6 +778,7 @@ _kSecXPCKeyPeerInfoArray _kSecXPCKeyPeerInfo _kSecXPCKeyOperation _kSecXPCKeyResult +_kSecXPCKeyEndpoint _kSecXPCKeyError _kSecXPCKeyClientToken _kSecXPCKeyUserLabel @@ -760,6 +788,7 @@ _sSecXPCErrorDomain _kSecXPCKeyOTAFileDirectory _kSecXPCKeyEscrowLabel _kSecXPCKeyTriesLabel +_kSecXPCVersion #endif @@ -777,6 +806,51 @@ _SecSetLoggingInfoForCircleScope #if TARGET_OS_IPHONE +_kCMSEncoderDigestAlgorithmSHA1 +_kCMSEncoderDigestAlgorithmSHA256 +_CMSEncodeContent +_CMSEncoderAddSupportingCerts +_CMSEncoderAddRecipients +_CMSEncoderAddSigners +_CMSEncoderCopySupportingCerts +_CMSEncoderCopyRecipients +_CMSEncoderCopySigners +_CMSEncoderCreate +_CMSEncoderCopyEncodedContent +_CMSEncoderGetCmsMessage +_CMSEncoderSetSignerAlgorithm +_CMSEncoderSetHasDetachedContent +_CMSEncoderGetHasDetachedContent +_CMSEncoderCopyEncapsulatedContentType +_CMSEncoderGetEncoder +_CMSEncoderGetTypeID +_CMSEncoderSetEncapsulatedContentTypeOID +_CMSEncoderSetEncoder +_CMSEncoderAddSignedAttributes +_CMSEncoderSetSigningTime +_CMSEncoderSetAppleCodesigningHashAgility +_CMSEncoderSetCertificateChainMode +_CMSEncoderGetCertificateChainMode +_CMSEncoderUpdateContent +_CMSDecoderCopyAllCerts +_CMSDecoderCopyContent +_CMSDecoderCopyDetachedContent +_CMSDecoderCopySignerStatus +_CMSDecoderCreate +_CMSDecoderGetTypeID +_CMSDecoderFinalizeMessage +_CMSDecoderGetDecoder +_CMSDecoderCopyEncapsulatedContentType +_CMSDecoderIsContentEncrypted +_CMSDecoderGetNumSigners +_CMSDecoderSetDecoder +_CMSDecoderSetDetachedContent +_CMSDecoderUpdateMessage +_CMSDecoderGetCmsMessage +_CMSDecoderCopySignerEmailAddress +_CMSDecoderCopySignerCert +_CMSDecoderCopySignerSigningTime +_CMSDecoderCopySignerAppleCodesigningHashAgility _SecCMSCertificatesOnlyMessageCopyCertificates _SecCMSCreateCertificatesOnlyMessage _SecCMSCreateCertificatesOnlyMessageIAP @@ -875,6 +949,7 @@ _SecCmsSignerInfoGetSigningTime _SecCmsSignerInfoGetVerificationStatus _SecCmsSignerInfoIncludeCerts _SecCmsSignerInfoSaveSMIMEProfile +_SecCmsSignerInfoCopyCertFromEncryptionKeyPreference _SecCmsUtilVerificationStatusToString _kSecCMSAdditionalCerts _kSecCMSAllCerts @@ -883,6 +958,7 @@ _kSecCMSCertChainMode _kSecCMSCertChainModeNone _kSecCMSEncryptionAlgorithmAESCBC _kSecCMSEncryptionAlgorithmDESCBC +_kSecCMSHashAgility _kSecCMSHashingAlgorithmMD5 _kSecCMSHashingAlgorithmSHA1 _kSecCMSHashingAlgorithmSHA256 @@ -905,6 +981,8 @@ _SecCMSCreateCertificatesOnlyMessage _SecCMSCreateCertificatesOnlyMessageIAP _SecCMSCreateEnvelopedData _SecCMSDecryptEnvelopedData +_SecCMSSignDataAndAttributes +_SecCMSSignDigestAndAttributes _SecCmsContentInfoGetBulkKey _SecCmsContentInfoGetBulkKeySize _SecCmsContentInfoGetChildContentInfo @@ -1007,6 +1085,7 @@ _SecCmsSignerInfoGetTimestampTime _SecCmsSignerInfoGetVerificationStatus _SecCmsSignerInfoIncludeCerts _SecCmsSignerInfoSaveSMIMEProfile +_SecCmsSignerInfoCopyCertFromEncryptionKeyPreference _SecCmsTSADefaultCallback _SecCmsTSAGetDefaultContext _SecCmsUtilVerificationStatusToString @@ -1017,6 +1096,7 @@ _kSecCMSBulkEncryptionAlgorithm _kSecCMSCertChainMode _kSecCMSEncryptionAlgorithmAESCBC _kSecCMSEncryptionAlgorithmDESCBC +_kSecCMSHashAgility _kSecCMSHashingAlgorithmSHA1 _kSecCMSHashingAlgorithmSHA256 _kSecCMSHashingAlgorithmSHA384 @@ -1077,14 +1157,13 @@ _SecKeyCopyModulus _SecKeyCopyPersistentRef _SecKeyCopyPublicBytes _SecKeyCopyPublicKey +_SecKeyCopyPublicKeyHash _SecKeyCreate _SecKeyCreateAttestation _SecKeyCreateDecryptedData _SecKeyCreateDuplicate -#if TARGET_OS_IPHONE _SecKeyCreateECPrivateKey _SecKeyCreateECPublicKey -#endif /* TARGET_OS_IPHONE */ _SecKeyCreateEncryptedData _SecKeyCreateFromAttributeDictionary @@ -1095,6 +1174,7 @@ _SecKeyCreateFromData _SecKeyCreateFromPublicBytes _SecKeyCreateFromPublicData _SecKeyCreateFromSubjectPublicKeyInfoData +_SecKeyCopySubjectPublicKeyInfo #if TARGET_OS_OSX _SecKeyCreatePair #endif /* TARGET_OS_OSX */ @@ -1204,11 +1284,19 @@ _kSecKeyAlgorithmECDSASignatureMessageX962SHA256 _kSecKeyAlgorithmECDSASignatureMessageX962SHA384 _kSecKeyAlgorithmECDSASignatureMessageX962SHA512 _kSecKeyAlgorithmECDSASignatureRFC4754 +_kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM +_kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM +_kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM +_kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM _kSecKeyAlgorithmECIESEncryptionCofactorX963SHA1AESGCM _kSecKeyAlgorithmECIESEncryptionCofactorX963SHA224AESGCM _kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM _kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM _kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM +_kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM +_kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM +_kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM +_kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM _kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM _kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM _kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM @@ -1228,21 +1316,28 @@ _kSecKeyAlgorithmRSAEncryptionPKCS1 _kSecKeyAlgorithmRSAEncryptionRaw _kSecKeyAlgorithmRSAEncryptionRawCCUnit _kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5 -_kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5 -_kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw _kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw _kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1 _kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224 _kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256 _kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384 _kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512 -_kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5 +_kSecKeyAlgorithmRSASignatureDigestPSSSHA1 +_kSecKeyAlgorithmRSASignatureDigestPSSSHA224 +_kSecKeyAlgorithmRSASignatureDigestPSSSHA256 +_kSecKeyAlgorithmRSASignatureDigestPSSSHA384 +_kSecKeyAlgorithmRSASignatureDigestPSSSHA512 _kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5 _kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1 _kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224 _kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256 _kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384 _kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512 +_kSecKeyAlgorithmRSASignatureMessagePSSSHA1 +_kSecKeyAlgorithmRSASignatureMessagePSSSHA224 +_kSecKeyAlgorithmRSASignatureMessagePSSSHA256 +_kSecKeyAlgorithmRSASignatureMessagePSSSHA384 +_kSecKeyAlgorithmRSASignatureMessagePSSSHA512 _kSecKeyAlgorithmRSASignatureRaw _kSecKeyAlgorithmRSASignatureRawCCUnit #if TARGET_OS_OSX @@ -1250,6 +1345,7 @@ _kSecKeyAttributeName #endif /* TARGET_OS_OSX */ _kSecKeyKeyExchangeParameterRequestedSize _kSecKeyKeyExchangeParameterSharedInfo +_kSecKeyParameterSETokenAttestationNonce #if TARGET_OS_IPHONE _kSecPrivateKeyAttrs _kSecPublicKeyAttrs @@ -1377,14 +1473,22 @@ _kSecAttrSubjectKeyID _kSecAttrSynchronizable _kSecAttrSynchronizableAny _kSecAttrSyncViewHint +_kSecAttrSysBound +_kSecAttrPersistantReference +_kSecAttrPersistentReference _kSecAttrTokenID _kSecAttrTokenIDSecureEnclave +_kSecAttrTokenIDAppleKeyStore _kSecAttrTokenOID _kSecAttrTombstone _kSecAttrType +_kSecAttrUUID _kSecAttrVolume _kSecAttrWasAlwaysSensitive _kSecAttrWasNeverExtractable +_kSecAttrKeyTypeECSECPrimeRandomPKA +_kSecAttrKeyTypeSecureEnclaveAttestation +_kSecAttrSecureEnclaveKeyBlob #elif TARGET_OS_OSX _kSecAttrAFPServerSignature @@ -1520,16 +1624,30 @@ _kSecAttrSubjectKeyID _kSecAttrSyncViewHint _kSecAttrSynchronizable _kSecAttrSynchronizableAny +_kSecAttrSysBound +_kSecAttrPersistantReference +_kSecAttrPersistentReference _kSecAttrTokenID _kSecAttrTokenIDSecureEnclave +_kSecAttrTokenIDAppleKeyStore _kSecAttrTokenOID _kSecAttrTombstone _kSecAttrType +_kSecAttrUUID _kSecAttrVolume _kSecAttrWasAlwaysSensitive _kSecAttrWasNeverExtractable +_kSecAttrKeyTypeECSECPrimeRandomPKA +_kSecAttrKeyTypeSecureEnclaveAttestation +_kSecAttrSecureEnclaveKeyBlob #endif // TARGET_OS_OSX +_kSecAttrDeriveSyncIDFromItemAttributes +_kSecAttrPCSPlaintextServiceIdentifier +_kSecAttrPCSPlaintextPublicKey +_kSecAttrPCSPlaintextPublicIdentity +_kSecAttrSHA1 + #include "Security/SecureObjectSync/SOSViews.exp-in" _kSecClass @@ -1568,15 +1686,21 @@ _kSecReturnData _kSecReturnPersistentRef _kSecReturnRef _SecItemAdd +_SecItemCertificateExists _SecItemCopyDisplayNames _SecItemCopyMatching +_SecItemCopyParentCertificates_ios _SecItemDelete #if TARGET_OS_IPHONE _SecItemDeleteAll #endif _SecItemUpdate +__SecItemAddAndNotifyOnSync +_SecItemSetCurrentItemAcrossAllDevices +_SecItemFetchCurrentItemAcrossAllDevices +__SecItemFetchDigests -__SecItemMakePersistentRef +__SecItemCreatePersistentRef __SecItemParsePersistentRef __SecKeychainBackupSyncable __SecKeychainCopyBackup @@ -1601,6 +1725,8 @@ _SecRequestSharedWebCredential _SecCreateSharedWebCredentialPassword _kSecSharedPassword #endif +_kSOSInternalAccessGroup +_kSecNetworkExtensionAccessGroupSuffix __SecSecuritydCopyWhoAmI __SecSyncBubbleTransfer @@ -1608,7 +1734,10 @@ __SecSystemKeychainTransfer __SecSyncDeleteUserViews _SecItemUpdateTokenItems _SecItemDeleteAllWithAccessGroups -__SecTokenItemCopyValueData +_SecTokenItemValueCopy + +__SecSecuritydCopyCKKSEndpoint +__SecSecuritydCopySOSStatusEndpoint #if TARGET_OS_IPHONE _kSecXPCKeyAttributesToUpdate @@ -1628,7 +1757,6 @@ _kSecXPCKeyIDSMessage _kSecXPCKeySendIDSMessage #endif -_SecCertificatePathCopyXPCArray _SecCertificateXPCArrayCopyArray _SecPolicyXPCArrayCopyArray #if TARGET_OS_IPHONE @@ -1670,6 +1798,35 @@ _SecEMCSCreateDerivedEMCSKey _SecEMCSCreateNewiDMSKey #endif +#if TARGET_OS_IPHONE +// +// libsecurity_codesigning_ios +// + +_SecCodeSetDetachedSignature +_SecCodeCopySigningInformation + +_SecStaticCodeCreateWithPathAndAttributes +_SecStaticCodeCheckValidityWithErrors + +_kSecCodeAttributeUniversalFileOffset + +_kSecCodeInfoTime +_kSecCodeInfoIdentifier +_kSecCodeInfoTeamIdentifier +_kSecCodeInfoCertificates +_kSecCodeInfoCdHashes +_kSecCodeInfoDigestAlgorithms +_kSecCodeInfoEntitlements +_kSecCodeInfoEntitlementsDict +_kSecCodeInfoUnique + +_kSecCFErrorResourceAdded +_kSecCFErrorResourceAltered +_kSecCFErrorResourceMissing + +#endif // TARGET_OS_IPHONE + // // Custom CFAllocators // diff --git a/OSX/sec/Security/SecFramework.c b/OSX/sec/Security/SecFramework.c index a9ebe114..3a895015 100644 --- a/OSX/sec/Security/SecFramework.c +++ b/OSX/sec/Security/SecFramework.c @@ -106,7 +106,7 @@ CFDataRef SecFrameworkCopyResourceContents(CFStringRef resourceName, const SecRandomRef kSecRandomDefault = NULL; -int SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes) { +int SecRandomCopyBytes(SecRandomRef rnd, size_t count, void *bytes) { if (rnd != kSecRandomDefault) return errSecParam; return CCRandomCopyBytes(kCCRandomDefault, bytes, count); diff --git a/OSX/sec/Security/SecFrameworkStrings.h b/OSX/sec/Security/SecFrameworkStrings.h index 5f4519b0..702093b6 100644 --- a/OSX/sec/Security/SecFrameworkStrings.h +++ b/OSX/sec/Security/SecFrameworkStrings.h @@ -52,7 +52,7 @@ __BEGIN_DECLS #define SEC_BITS_KEY SecStringWithDefaultValue("bits", "Certificate", 0, "bits", "") #define SEC_SEQUENCE_KEY SecStringWithDefaultValue("Sequence", "Certificate", 0, "Sequence", "First argument to SEC_BLOB_KEY format string for a Sequence") #define SEC_SET_KEY SecStringWithDefaultValue("Set", "Certificate", 0, "Set", "First argument to SEC_BLOB_KEY format string for a Set") -#define SEC_NOT_DISPLAYED_KEY SecStringWithDefaultValue("not displayed (tag = %@; length %d)", "Certificate", 0, "not displayed (tag = %@; length %d)", "format string for undisplayed field data with a given DER tag and length") +#define SEC_NOT_DISPLAYED_KEY SecStringWithDefaultValue("not displayed (tag = %ld; length %ld)", "Certificate", 0, "not displayed (tag = %ld; length %ld)", "format string for undisplayed field data with a given DER tag and length") #define SEC_RDN_KEY SecStringWithDefaultValue("RDN", "Certificate", 0, "RDN", "Label of a RDN") #define SEC_X501_NAME_KEY SecStringWithDefaultValue("X.501 Name", "Certificate", 0, "X.501 Name", "Label of a X.501 Name") #define SEC_YES_KEY SecStringWithDefaultValue("Yes", "Certificate", 0, "Yes", "Value for a boolean property when it's value is true (example critical: yes)") @@ -221,14 +221,20 @@ __BEGIN_DECLS #define SEC_CK_CONTINUE SecStringWithDefaultValue("Continue", "CloudKeychain", 0, "Continue", "Button text to continue to iCloud settings (iOS)") #define SEC_CK_NOT_NOW SecStringWithDefaultValue("Not Now", "CloudKeychain", 0, "Not Now", "Button text to dismiss alert") -#define SEC_CK_APPROVAL_TITLE_OSX SecStringWithDefaultValue("Apple ID Sign In Alert", "CloudKeychain", 0, "Apple ID Sign In Alert", "Title for alert when approving another device") -#define SEC_CK_APPROVAL_BODY_OSX SecStringWithDefaultValue("“%@” wants to use your iCloud account.", "CloudKeychain", 0, "“%@” wants to use your iCloud account.", "Body text when approving another device") -#define SEC_CK_APPROVAL_TITLE_IOS SecStringWithDefaultValue("Allow “%@” to use iCloud?", "CloudKeychain", 0, "Allow “%@” to use iCloud?", "Title for alert when approving another device") -#define SEC_CK_APPROVAL_BODY_IOS_IPAD SecStringWithDefaultValue("Enter the password for “%@” to allow this new iPad to use your iCloud account.", "CloudKeychain", 0, "Enter the password for “%@” to allow this new iPad to use your iCloud account.", "Body text when approving an iPad") -#define SEC_CK_APPROVAL_BODY_IOS_IPHONE SecStringWithDefaultValue("Enter the password for “%@” to allow this new iPhone to use your iCloud account.", "CloudKeychain", 0, "Enter the password for “%@” to allow this new iPhone to use your iCloud account.", "Body text when approving an iPhone") -#define SEC_CK_APPROVAL_BODY_IOS_IPOD SecStringWithDefaultValue("Enter the password for “%@” to allow this new iPod to use your iCloud account.", "CloudKeychain", 0, "Enter the password for “%@” to allow this new iPod to use your iCloud account.", "Body text when approving an iPod") -#define SEC_CK_APPROVAL_BODY_IOS_MAC SecStringWithDefaultValue("Enter the password for “%@” to allow this new Mac to use your iCloud account.", "CloudKeychain", 0, "Enter the password for “%@” to allow this new Mac to use your iCloud account.", "Body text when approving another Mac") -#define SEC_CK_APPROVAL_BODY_IOS_GENERIC SecStringWithDefaultValue("Enter the password for “%@” to allow this new device to use your iCloud account.", "CloudKeychain", 0, "Enter the password for “%@” to allow this new device to use your iCloud account.", "Body text when approving another (generic) device") +#define SEC_CK_APPROVAL_TITLE SecStringWithDefaultValue("Approve “%@”?", "CloudKeychain", 0, "Approve “%@”?", "Title for alert when approving another device") +#define SEC_CK_APPROVAL_BODY_OSX_IPAD SecStringWithDefaultValue("This iPad wants to use your iCloud account.", "CloudKeychain", 0, "This iPad wants to use your iCloud account.", "Body text when approving an iPad on Mac") +#define SEC_CK_APPROVAL_BODY_OSX_IPHONE SecStringWithDefaultValue("This iPhone wants to use your iCloud account.", "CloudKeychain", 0, "This iPhone wants to use your iCloud account.", "Body text when approving an iPhone on Mac") +#define SEC_CK_APPROVAL_BODY_OSX_IPOD SecStringWithDefaultValue("This iPod wants to use your iCloud account.", "CloudKeychain", 0, "This iPod wants to use your iCloud account.", "Body text when approving an iPod on Mac") +#define SEC_CK_APPROVAL_BODY_OSX_MAC SecStringWithDefaultValue("This Mac wants to use your iCloud account.", "CloudKeychain", 0, "This Mac wants to use your iCloud account.", "Body text when approving a Mac on Mac") +#define SEC_CK_APPROVAL_BODY_OSX_GENERIC SecStringWithDefaultValue("This device wants to use your iCloud account.", "CloudKeychain", 0, "This device wants to use your iCloud account.", "Body text when approving a device on Mac") +#define SEC_CK_APPROVE SecStringWithDefaultValue("Approve", "CloudKeychain", 0, "Approve", "Button text to approve icloud sign in request") +#define SEC_CK_DECLINE SecStringWithDefaultValue("Decline", "CloudKeychain", 0, "Decline", "Button text to decline icloud sign in request") + +#define SEC_CK_APPROVAL_BODY_IOS_IPAD SecStringWithDefaultValue("Enter the password for the Apple ID “%@” to allow this new iPad to use your iCloud account.", "CloudKeychain", 0, "Enter the password for the Apple ID “%@” to allow this new iPad to use your iCloud account.", "Body text when approving an iPad") +#define SEC_CK_APPROVAL_BODY_IOS_IPHONE SecStringWithDefaultValue("Enter the password for the Apple ID “%@” to allow this new iPhone to use your iCloud account.", "CloudKeychain", 0, "Enter the password for the Apple ID “%@” to allow this new iPhone to use your iCloud account.", "Body text when approving an iPhone") +#define SEC_CK_APPROVAL_BODY_IOS_IPOD SecStringWithDefaultValue("Enter the password for the Apple ID “%@” to allow this new iPod to use your iCloud account.", "CloudKeychain", 0, "Enter the password for the Apple ID “%@” to allow this new iPod to use your iCloud account.", "Body text when approving an iPod") +#define SEC_CK_APPROVAL_BODY_IOS_MAC SecStringWithDefaultValue("Enter the password for the Apple ID “%@” to allow this new Mac to use your iCloud account.", "CloudKeychain", 0, "Enter the password for the Apple ID “%@” to allow this new Mac to use your iCloud account.", "Body text when approving another Mac") +#define SEC_CK_APPROVAL_BODY_IOS_GENERIC SecStringWithDefaultValue("Enter the password for the Apple ID “%@” to allow this new device to use your iCloud account.", "CloudKeychain", 0, "Enter the password for the Apple ID “%@” to allow this new device to use your iCloud account.", "Body text when approving another (generic) device") #define SEC_CK_REMINDER_TITLE_OSX SecStringWithDefaultValue("iCloud Approval Required", "CloudKeychain", 0, "iCloud Approval Required", "Title for reminder that iCloud Keychain Application (from this device) is still pending") #define SEC_CK_REMINDER_BODY_OSX SecStringWithDefaultValue("This Mac is still waiting for approval by another device.", "CloudKeychain", 0, "This Mac is still waiting for approval by another device.", "Body text for reminder that iCloud Keychain Application (from this device) is still pending") diff --git a/OSX/sec/Security/SecImportExport.c b/OSX/sec/Security/SecImportExport.c index 0c4b416a..44ecf2eb 100644 --- a/OSX/sec/Security/SecImportExport.c +++ b/OSX/sec/Security/SecImportExport.c @@ -45,6 +45,11 @@ const CFStringRef kSecImportItemTrust = CFSTR("trust"); const CFStringRef kSecImportItemCertChain = CFSTR("chain"); const CFStringRef kSecImportItemIdentity = CFSTR("identity"); +typedef struct { + CFMutableArrayRef certs; + p12_error *status; +} collect_certs_context; + static void collect_certs(const void *key, const void *value, void *context) { @@ -52,11 +57,14 @@ static void collect_certs(const void *key, const void *value, void *context) CFDataRef cert_bytes = CFDictionaryGetValue(value, CFSTR("cert")); if (!cert_bytes) return; + collect_certs_context *a_collect_certs_context = (collect_certs_context *)context; SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes); - if (!cert) + if (!cert) { + *a_collect_certs_context->status = p12_decodeErr; return; - CFMutableArrayRef cert_array = (CFMutableArrayRef)context; + } + CFMutableArrayRef cert_array = a_collect_certs_context->certs; CFArrayAppendValue(cert_array, cert); CFRelease(cert); } @@ -65,6 +73,7 @@ static void collect_certs(const void *key, const void *value, void *context) typedef struct { CFMutableArrayRef identities; CFArrayRef certs; + p12_error *status; } build_trust_chains_context; static void build_trust_chains(const void *key, const void *value, @@ -97,11 +106,14 @@ static void build_trust_chains(const void *key, const void *value, CFDataGetBytePtr(key_bytes), CFDataGetLength(key_bytes), kSecKeyEncodingPkcs1), out); } else { + *a_build_trust_chains_context->status = p12_decodeErr; goto out; } - require(cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes), out); - require(identity = SecIdentityCreate(kCFAllocatorDefault, cert, private_key), out); + require_action(cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes), out, + *a_build_trust_chains_context->status = p12_decodeErr); + require_action(identity = SecIdentityCreate(kCFAllocatorDefault, cert, private_key), out, + *a_build_trust_chains_context->status = p12_decodeErr); CFDictionarySetValue(identity_dict, kSecImportItemIdentity, identity); eval_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); @@ -143,19 +155,21 @@ OSStatus SecPKCS12Import(CFDataRef pkcs12_data, CFDictionaryRef options, CFArray context.passphrase = CFDictionaryGetValue(options, kSecImportExportPassphrase); context.items = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - int status = p12decode(&context, pkcs12_data); + p12_error status = p12decode(&context, pkcs12_data); if (!status) { CFMutableArrayRef certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFDictionaryApplyFunction(context.items, collect_certs, certs); - - CFMutableArrayRef identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - build_trust_chains_context a_build_trust_chains_context = { identities, certs }; - CFDictionaryApplyFunction(context.items, build_trust_chains, &a_build_trust_chains_context); - CFReleaseSafe(certs); - - /* ignoring certs that weren't picked up as part of the certchain for found keys */ - - *items = identities; + collect_certs_context a_collect_certs_context = { certs, &status }; + CFDictionaryApplyFunction(context.items, collect_certs, &a_collect_certs_context); + + if (!status) { + CFMutableArrayRef identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + build_trust_chains_context a_build_trust_chains_context = { identities, certs, &status }; + CFDictionaryApplyFunction(context.items, build_trust_chains, &a_build_trust_chains_context); + CFReleaseSafe(certs); + + /* ignoring certs that weren't picked up as part of the certchain for found keys */ + *items = identities; + } } CFReleaseSafe(context.items); diff --git a/OSX/sec/Security/SecItem.c b/OSX/sec/Security/SecItem.c index e44d8840..05a3e566 100644 --- a/OSX/sec/Security/SecItem.c +++ b/OSX/sec/Security/SecItem.c @@ -74,7 +74,6 @@ #include #include #include -#include #include #include @@ -99,39 +98,39 @@ #include +const CFStringRef kSecNetworkExtensionAccessGroupSuffix = CFSTR("com.apple.networkextensionsharing"); + /* Return an OSStatus for a sqlite3 error code. */ static OSStatus osstatus_for_s3e(int s3e) { - if (s3e > 0 && s3e <= SQLITE_DONE) switch (s3e) + switch (s3e) { case SQLITE_OK: - return 0; - case SQLITE_ERROR: - return errSecNotAvailable; /* errSecDuplicateItem; */ - case SQLITE_FULL: /* Happens if we run out of uniqueids */ - return errSecNotAvailable; /* TODO: Replace with a better error code. */ - case SQLITE_PERM: + case SQLITE_DONE: + return errSecSuccess; case SQLITE_READONLY: - return errSecNotAvailable; - case SQLITE_CANTOPEN: - return errSecNotAvailable; - case SQLITE_EMPTY: - return errSecNotAvailable; + return errSecReadOnly; case SQLITE_CONSTRAINT: return errSecDuplicateItem; - case SQLITE_ABORT: + case SQLITE_ABORT: // There is no errSecOperationCancelled return -1; case SQLITE_MISMATCH: return errSecNoSuchAttr; - case SQLITE_AUTH: - return errSecNotAvailable; case SQLITE_NOMEM: - return -2; /* TODO: Replace with a real error code. */ + return errSecAllocate; + case SQLITE_IOERR: + return errSecIO; case SQLITE_INTERNAL: + return errSecInternalComponent; + case SQLITE_FULL: // Happens if we run out of uniqueids or disk is full (TODO: replace with better code) + case SQLITE_PERM: // No acess permission + case SQLITE_AUTH: // No authorization (e.g. no class key for file) + case SQLITE_CANTOPEN: // can be several reasons for this. Caller should sqlite3_system_errno() + case SQLITE_EMPTY: // SQLite does not seem to use this. Was already here, so keeping + case SQLITE_ERROR: default: - return errSecNotAvailable; /* TODO: Replace with a real error code. */ + return errSecNotAvailable; } - return s3e; } static OSStatus osstatus_for_kern_return(CFIndex kernResult) @@ -259,7 +258,7 @@ OSStatus SecErrorGetOSStatus(CFErrorRef error) { status = osstatus_for_xpc_error(CFErrorGetCode(error)); } else if (CFEqual(sSecDERErrorDomain, domain)) { status = osstatus_for_der_error(CFErrorGetCode(error)); - } else if (CFEqual(kSecIDSErrorDomain, domain)) { + }else if (CFEqual(kSecIDSErrorDomain, domain)) { status = osstatus_for_ids_error(CFErrorGetCode(error)); } else if (CFEqual(CFSTR(kLAErrorDomain), domain)) { status = osstatus_for_localauthentication_error(CFErrorGetCode(error)); @@ -368,6 +367,7 @@ AttributeCreateFilteredOutSecAttrs(CFDictionaryRef attributes) CFDictionaryRemoveValue(filtered, kSecAttrCanUnwrap); CFDictionaryRemoveValue(filtered, kSecAttrCanSignRecover); CFDictionaryRemoveValue(filtered, kSecAttrCanVerifyRecover); + CFDictionaryRemoveValue(filtered, kSecAttrIsPermanent); return filtered; } @@ -528,9 +528,11 @@ static bool explode_identity(CFDictionaryRef attributes, secitem_operation opera if (!status) { /* result is a persistent ref to a cert */ sqlite_int64 rowid; - if (_SecItemParsePersistentRef(result, NULL, &rowid)) { - *return_result = _SecItemMakePersistentRef(kSecClassIdentity, rowid); + CFDictionaryRef tokenAttrs = NULL; + if (_SecItemParsePersistentRef(result, NULL, &rowid, &tokenAttrs)) { + *return_result = _SecItemCreatePersistentRef(kSecClassIdentity, rowid, tokenAttrs); } + CFReleaseNull(tokenAttrs); } CFRelease(result); } @@ -656,61 +658,125 @@ static void infer_cert_label(SecCFDictionaryCOW *attributes) } } -/* A persistent ref is just the class and the rowid of the record. */ -CF_RETURNS_RETAINED CFDataRef _SecItemMakePersistentRef(CFTypeRef class, sqlite_int64 rowid) +static CFDataRef CreateTokenPersistentRefData(CFTypeRef class, CFDictionaryRef attributes) { - uint8_t bytes[sizeof(sqlite_int64) + 4]; - if (rowid < 0) - return NULL; - if (CFStringGetCString(class, (char *)bytes, 4 + 1 /*null-term*/, - kCFStringEncodingUTF8)) - { - OSWriteBigInt64(bytes + 4, 0, rowid); - return CFDataCreate(NULL, bytes, sizeof(bytes)); + CFDataRef tokenPersistentRef = NULL; + CFStringRef tokenId = CFDictionaryGetValue(attributes, kSecAttrTokenID); + CFDictionaryRef itemValue = NULL; + if (CFEqual(class, kSecClassIdentity)) { + itemValue = SecTokenItemValueCopy(CFDictionaryGetValue(attributes, kSecAttrIdentityCertificateData), NULL); + } else { + itemValue = SecTokenItemValueCopy(CFDictionaryGetValue(attributes, kSecValueData), NULL); } - return NULL; + require(itemValue, out); + CFDataRef oid = CFDictionaryGetValue(itemValue, kSecTokenValueObjectIDKey); + require(oid, out); + CFArrayRef array = CFArrayCreateForCFTypes(kCFAllocatorDefault, class, tokenId, oid, NULL); + tokenPersistentRef = CFPropertyListCreateDERData(kCFAllocatorDefault, array, NULL); + CFRelease(array); +out: + CFReleaseNull(itemValue); + return tokenPersistentRef; +} + +static const uint8_t tk_persistent_ref_id[] = {'t', 'k', 'p', 'r'}; +/* A persistent ref is just the class and the rowid of the record. + Persistent ref for token items is a der blob with class, tokenID and objectId. */ +CFDataRef _SecItemCreatePersistentRef(CFTypeRef class, sqlite_int64 rowid, CFDictionaryRef attributes) +{ + CFDataRef result = NULL; + if (attributes && CFDictionaryContainsKey(attributes, kSecAttrTokenID)) { + CFDataRef tokenPersistentRef = CreateTokenPersistentRefData(class, attributes); + require(tokenPersistentRef, out); + 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); + CFReleaseNull(tokenPersistentRef); + result = tmpData; + } else { + require(rowid >= 0, out); + uint8_t bytes[sizeof(sqlite_int64) + 4]; + if (CFStringGetCString(class, (char *)bytes, 4 + 1 /*null-term*/, + kCFStringEncodingUTF8)) + { + OSWriteBigInt64(bytes + 4, 0, rowid); + result = CFDataCreate(NULL, bytes, sizeof(bytes)); + } + } +out: + return result; +} + +static Boolean isValidClass(CFStringRef class, CFStringRef *return_class) { + const void *valid_classes[] = { kSecClassGenericPassword, + kSecClassInternetPassword, + kSecClassAppleSharePassword, + kSecClassCertificate, + kSecClassKey, + kSecClassIdentity }; + + for (size_t i = 0; i < array_size(valid_classes); i++) { + if (CFEqual(valid_classes[i], class)) { + if (return_class) + *return_class = valid_classes[i]; + return true; + } + } + + return false; +} + +static bool ParseTokenPersistentRefData(CFDataRef persistent_ref, CFStringRef *return_class, CFDictionaryRef *return_token_attrs) { + bool valid_ref = false; + 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_end, out); + require_quiet(CFGetTypeID(pl) == CFArrayGetTypeID(), out); + require_quiet(CFArrayGetCount(pl) == 3, out); + require_quiet(valid_ref = isValidClass(CFArrayGetValueAtIndex(pl, 0), return_class), out); + if (return_token_attrs) { + *return_token_attrs = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kSecAttrTokenID, CFArrayGetValueAtIndex(pl, 1), + kSecAttrTokenOID, CFArrayGetValueAtIndex(pl, 2), NULL); + } +out: + CFReleaseNull(pl); + return valid_ref; } /* AUDIT[securityd](done): persistent_ref (ok) is a caller provided, non NULL CFTypeRef. */ -bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, sqlite_int64 *return_rowid) +bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, sqlite_int64 *return_rowid, CFDictionaryRef *return_token_attrs) { bool valid_ref = false; - if (CFGetTypeID(persistent_ref) == CFDataGetTypeID() && - CFDataGetLength(persistent_ref) == (CFIndex)(sizeof(sqlite_int64) + 4)) { + require(CFGetTypeID(persistent_ref) == CFDataGetTypeID(), out); + + if (CFDataGetLength(persistent_ref) > (CFIndex)sizeof(tk_persistent_ref_id) && + memcmp(tk_persistent_ref_id, CFDataGetBytePtr(persistent_ref), sizeof(tk_persistent_ref_id)) == 0) { + valid_ref = ParseTokenPersistentRefData(persistent_ref, return_class, return_token_attrs); + } else if (CFDataGetLength(persistent_ref) == (CFIndex)(sizeof(sqlite_int64) + 4)) { const uint8_t *bytes = CFDataGetBytePtr(persistent_ref); sqlite_int64 rowid = OSReadBigInt64(bytes + 4, 0); CFStringRef class = CFStringCreateWithBytes(kCFAllocatorDefault, bytes, CFStringGetLength(kSecClassGenericPassword), kCFStringEncodingUTF8, true); - const void *valid_classes[] = { kSecClassGenericPassword, - kSecClassInternetPassword, - kSecClassAppleSharePassword, - kSecClassCertificate, - kSecClassKey, - kSecClassIdentity }; - unsigned i; - for (i=0; i< array_size(valid_classes); i++) { - if (CFEqual(valid_classes[i], class)) { - if (return_class) - *return_class = valid_classes[i]; - if (return_rowid) - *return_rowid = rowid; - valid_ref = true; - break; - } + if ((valid_ref = isValidClass(class, return_class))) { + if (return_rowid) + *return_rowid = rowid; } CFRelease(class); } +out: return valid_ref; } -static bool cf_bool_value(CFTypeRef cf_bool) -{ - return (cf_bool && CFEqual(kCFBooleanTrue, cf_bool)); +static bool cf_bool_value(CFTypeRef cf_bool) { + return cf_bool && CFBooleanGetValue(cf_bool); } CFMutableDictionaryRef SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW *cow_dictionary) { @@ -727,11 +793,6 @@ CFMutableDictionaryRef SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW *cow_dict return cow_dictionary->mutable_dictionary; } -// Keys for dictionary of kSecvalueData of token-based items. -static const CFStringRef kSecTokenValueObjectIDKey = CFSTR("oid"); -static const CFStringRef kSecTokenValueAccessControlKey = CFSTR("ac"); -static const CFStringRef kSecTokenValueDataKey = CFSTR("data"); - // Creates kSecValueData field stored in the DB for token-based items. Data field consists of objectID, real // access_control and optionally of the data value. static CFDataRef SecTokenItemValueCreate(CFDataRef oid, CFDataRef access_control, CFDataRef object_value, CFErrorRef *error) { @@ -749,7 +810,7 @@ static CFDataRef SecTokenItemValueCreate(CFDataRef oid, CFDataRef access_control return value_data; } -static CFDictionaryRef SecTokenItemValueCopy(CFDataRef db_value, CFErrorRef *error) { +CFDictionaryRef SecTokenItemValueCopy(CFDataRef db_value, CFErrorRef *error) { CFPropertyListRef plist = NULL; const uint8_t *der = CFDataGetBytePtr(db_value); const uint8_t *der_end = der + CFDataGetLength(db_value); @@ -762,18 +823,6 @@ out: return plist; } -CFDataRef _SecTokenItemCopyValueData(CFDataRef db_value, CFErrorRef *error) { - CFDataRef valueData = NULL; - CFDictionaryRef itemDict = NULL; - require_quiet(itemDict = SecTokenItemValueCopy(db_value, error), out); - CFRetainAssign(valueData, CFDictionaryGetValue(itemDict, kSecTokenValueDataKey)); - require_action_quiet(valueData, out, SecError(errSecInternal, error, CFSTR("token item does not contain value data"))); - -out: - CFReleaseSafe(itemDict); - return valueData; -} - TKTokenRef SecTokenCreate(CFStringRef token_id, CFDictionaryRef auth_params, CFErrorRef *error) { CFMutableDictionaryRef token_attrs = NULL; TKTokenRef token = NULL; @@ -801,11 +850,11 @@ static bool SecTokenItemCreateFromAttributes(CFDictionaryRef attributes, CFDicti if (auth_params != NULL) { CFDictionaryForEach(auth_params, ^(const void *key, const void *value) { - CFDictionarySetValue(attrs, key, value); + CFDictionaryAddValue(attrs, key, value); }); } CFDictionarySetValue(attrs, kSecUseToken, token); - CFDictionarySetValue(attrs, kSecUseTokenObjectID, object_id); + CFDictionarySetValue(attrs, kSecAttrTokenOID, object_id); CFRelease(token); } *ref = SecItemCreateFromAttributeDictionary(attrs); @@ -857,6 +906,11 @@ static bool SecItemResultCopyPrepared(CFTypeRef raw_result, TKTokenRef token, CFRetainAssign(cert_token, token); } + if ((token_item || cert_token_item) && cf_bool_value(CFDictionaryGetValue(query, kSecUseTokenRawItems))) { + token_item = false; + cert_token_item = false; + } + // Decode and prepare data value, if it is requested at the output, or if we want attributes from token. if (wants_data || wants_ref || (token_item && wants_attributes)) { if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID()) @@ -907,82 +961,84 @@ static bool SecItemResultCopyPrepared(CFTypeRef raw_result, TKTokenRef token, } } - if (wants_ref || wants_attributes || (wants_data && wants_persistent_ref)) { - // For these cases we need output dictionary. - if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID()) - *result = CFDictionaryCreateMutableCopy(NULL, 0, raw_result); - else - *result = CFDictionaryCreateForCFTypes(NULL, NULL); - CFMutableDictionaryRef output = (CFMutableDictionaryRef)*result; - - if ((wants_data || wants_ref) && value != NULL) - CFDictionarySetValue(output, kSecValueData, value); - else - CFDictionaryRemoveValue(output, kSecValueData); + if (!wants_ref && !wants_attributes && (!wants_data || !wants_persistent_ref)) { + *result = NULL; + ok = true; + goto out; + } - if (wants_persistent_ref && persistent_ref != NULL) - CFDictionarySetValue(output, kSecValuePersistentRef, persistent_ref); - else - CFDictionaryRemoveValue(output, kSecValuePersistentRef); - - if ((wants_ref || wants_attributes) && cert_token_item && - CFEqualSafe(CFDictionaryGetValue(output, kSecClass), kSecClassIdentity)) { - // Decode also certdata field of the identity. - CFDataRef data = CFDictionaryGetValue(output, kSecAttrIdentityCertificateData); - if (data != NULL) { - CFDictionaryRef parsed_value; - require_quiet(parsed_value = SecTokenItemValueCopy(data, error), out); - cert_data = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueDataKey)); - cert_object_id = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueObjectIDKey)); - CFRelease(parsed_value); - if (cert_data == NULL) { - // Retrieve value directly from the token. - if (cert_token == NULL) { - require_quiet(cert_token = SecTokenCreate(cert_token_id, auth_params, error), out); - } - require_quiet(cert_data = TKTokenCopyObjectData(cert_token, cert_object_id, error), out); - if (CFEqual(cert_data, kCFNull)) - CFReleaseNull(cert_data); - } - if (cert_data != NULL) { - CFDictionarySetValue(output, kSecAttrIdentityCertificateData, cert_data); - } else { - CFDictionaryRemoveValue(output, kSecAttrIdentityCertificateData); + // For other cases we need an output dictionary. + if (CFGetTypeID(raw_result) == CFDictionaryGetTypeID()) + *result = CFDictionaryCreateMutableCopy(NULL, 0, raw_result); + else + *result = CFDictionaryCreateForCFTypes(NULL, NULL); + CFMutableDictionaryRef output = (CFMutableDictionaryRef)*result; + + if ((wants_data || wants_ref) && value != NULL) + CFDictionarySetValue(output, kSecValueData, value); + else + CFDictionaryRemoveValue(output, kSecValueData); + + if (wants_persistent_ref && persistent_ref != NULL) + CFDictionarySetValue(output, kSecValuePersistentRef, persistent_ref); + else + CFDictionaryRemoveValue(output, kSecValuePersistentRef); + + if ((wants_ref || wants_attributes) && cert_token_item && + CFEqualSafe(CFDictionaryGetValue(output, kSecClass), kSecClassIdentity)) { + // Decode also certdata field of the identity. + CFDataRef data = CFDictionaryGetValue(output, kSecAttrIdentityCertificateData); + if (data != NULL) { + CFDictionaryRef parsed_value; + require_quiet(parsed_value = SecTokenItemValueCopy(data, error), out); + cert_data = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueDataKey)); + cert_object_id = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueObjectIDKey)); + CFRelease(parsed_value); + if (cert_data == NULL) { + // Retrieve value directly from the token. + if (cert_token == NULL) { + require_quiet(cert_token = SecTokenCreate(cert_token_id, auth_params, error), out); } + require_quiet(cert_data = TKTokenCopyObjectData(cert_token, cert_object_id, error), out); + if (CFEqual(cert_data, kCFNull)) + CFReleaseNull(cert_data); + } + if (cert_data != NULL) { + CFDictionarySetValue(output, kSecAttrIdentityCertificateData, cert_data); + } else { + CFDictionaryRemoveValue(output, kSecAttrIdentityCertificateData); } } + } - if (wants_ref) { - CFTypeRef ref; - require_quiet(SecTokenItemCreateFromAttributes(output, auth_params, token, object_id, &ref, error), out); - if (!(wants_attributes || wants_data || wants_persistent_ref)) { - CFAssignRetained(*result, ref); - } else if (ref != NULL) { - CFDictionarySetValue(output, kSecValueRef, ref); - CFRelease(ref); - if (!wants_data) { - // We could have stored data value previously to make ref creation succeed. - // They are not needed any more and in case that caller did not want the data, avoid returning them. - CFDictionaryRemoveValue(output, kSecValueData); - } - } + if (wants_ref || wants_attributes) { + // Convert serialized form of access control to object form. + if (!token_item) { + CFRetainAssign(ac_data, CFDictionaryGetValue(output, kSecAttrAccessControl)); } - if (wants_attributes) { - // Convert serialized form of access control to object form. - if (!token_item) { - CFRetainAssign(ac_data, CFDictionaryGetValue(output, kSecAttrAccessControl)); - } + if (ac_data != NULL) { + SecAccessControlRef ac; + require_quiet(ac = SecAccessControlCreateFromData(kCFAllocatorDefault, ac_data, error), out); + CFDictionarySetValue(output, kSecAttrAccessControl, ac); + CFRelease(ac); + } + } - if (ac_data != NULL) { - SecAccessControlRef ac; - require_quiet(ac = SecAccessControlCreateFromData(kCFAllocatorDefault, ac_data, error), out); - CFDictionarySetValue(output, kSecAttrAccessControl, ac); - CFRelease(ac); + if (wants_ref) { + CFTypeRef ref; + require_quiet(SecTokenItemCreateFromAttributes(output, auth_params, token, object_id, &ref, error), out); + if (!(wants_attributes || wants_data || wants_persistent_ref)) { + CFAssignRetained(*result, ref); + } else if (ref != NULL) { + CFDictionarySetValue(output, kSecValueRef, ref); + CFRelease(ref); + if (!wants_data) { + // We could have stored data value previously to make ref creation succeed. + // They are not needed any more and in case that caller did not want the data, avoid returning them. + CFDictionaryRemoveValue(output, kSecValueData); } } - } else { - *result = NULL; } ok = true; @@ -1000,7 +1056,7 @@ out: return ok; } -static bool SecItemResultProcess(CFDictionaryRef query, CFDictionaryRef auth_params, TKTokenRef token, +bool SecItemResultProcess(CFDictionaryRef query, CFDictionaryRef auth_params, TKTokenRef token, CFTypeRef raw_result, CFTypeRef *result, CFErrorRef *error) { bool ok = false; require_action_quiet(raw_result != NULL, out, ok = true); @@ -1050,6 +1106,33 @@ static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, C 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); + if (value) { + CFDictionaryRef ref_attributes; + require_action_quiet(ref_attributes = SecItemCopyAttributeDictionary(value, forQuery), out, + SecError(errSecValueRefUnsupported, error, CFSTR("unsupported kSecValueRef in query"))); + + // Replace any attributes we already got from the ref with the ones from the attributes dictionary the caller passed us. + // This allows a caller to add an item using attributes from the ref and still override some of them in the dictionary directly. + CFDictionaryForEach(ref_attributes, ^(const void *key, const void *value) { + // Attributes already present in 'attrs' have precedence over the generic ones retrieved from the ref, + // so add only those attributes from 'ref' which are missing in attrs. + CFDictionaryAddValue(SecCFDictionaryCOWGetMutable(attrs), key, value); + }); + CFRelease(ref_attributes); + + if (forQuery) { + CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrTokenOID); + } + + // Remove original expanded valueRef. Do not remove it in case when adding token item, because it is needed later to avoid + // another roundtrip to token driver. + if (forQuery || !CFDictionaryContainsKey(attrs->dictionary, kSecAttrTokenID)) { + CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecValueRef); + } + } + SecAccessControlRef access_control = (SecAccessControlRef)CFDictionaryGetValue(attrs->dictionary, kSecAttrAccessControl); if (access_control != NULL) { require_quiet(ac_data = SecAccessControlCopyData(access_control), out); @@ -1065,27 +1148,6 @@ static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, C CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseCredentialReference, acm_context); } - // If a ref was specified we get its attribute dictionary and parse it. - CFTypeRef value = CFDictionaryGetValue(attrs->dictionary, kSecValueRef); - if (value) { - CFDictionaryRef ref_attributes; - require_action_quiet(ref_attributes = SecItemCopyAttributeDictionary(value, forQuery), out, - SecError(errSecValueRefUnsupported, error, CFSTR("unsupported kSecValueRef in query"))); - - /* Replace any attributes we already got from the ref with the ones - from the attributes dictionary the caller passed us. This allows - a caller to add an item using attributes from the ref and still - override some of them in the dictionary directly. */ - CFMutableDictionaryRef new_query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, ref_attributes); - CFRelease(ref_attributes); - CFDictionaryForEach(attrs->dictionary, ^(const void *key, const void *value) { - if (!CFEqual(key, kSecValueRef)) - CFDictionarySetValue(new_query, key, value); - }); - CFAssignRetained(attrs->mutable_dictionary, new_query); - attrs->dictionary = attrs->mutable_dictionary; - } - CFTypeRef policy = CFDictionaryGetValue(attrs->dictionary, kSecMatchPolicy); if (policy) { require_action_quiet(CFGetTypeID(policy) == SecPolicyGetTypeID(), out, @@ -1111,9 +1173,7 @@ static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, C /* convert DN to canonical issuer, if value is DN (top level sequence) */ const DERItem name = { (unsigned char *)CFDataGetBytePtr(value), CFDataGetLength(value) }; DERDecodedInfo content; - if (!DERDecodeItem(&name, &content) && - (content.tag == ASN1_CONSTR_SEQUENCE)) - { + if (DERDecodeItem(&name, &content) == DR_Success && content.tag == ASN1_CONSTR_SEQUENCE) { CFDataRef canonical_issuer = createNormalizedX501Name(kCFAllocatorDefault, &content.content); if (canonical_issuer) { CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrIssuer, canonical_issuer); @@ -1122,6 +1182,11 @@ static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, C } } + if (CFDictionaryContainsKey(attrs->dictionary, kSecUseTokenRawItems)) { + // This use flag is client-only, securityd does not understand it. + CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(attrs), kSecUseTokenRawItems); + } + ok = true; out: @@ -1146,15 +1211,15 @@ static bool SecItemAuthMaxAttemptsReached(CFArrayRef ac_pairs, CFErrorRef *error } CFStringRef reason = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Reached maximum count of authentication attempts\n %@"), log_string); - SecError(errSecAuthFailed, error, reason); + SecError(errSecAuthFailed, error, CFSTR("%@"), reason); __security_simulatecrash(reason, __sec_exception_code_AuthLoop); - CFRelease(reason); CFRelease(log_string); return false; } -bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAuthResult (^perform)(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error)) { +bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAuthResult (^perform)(CFArrayRef *ac_pairs, CFErrorRef *error), + void (^newCredentialRefAdded)()) { bool ok = false; CFArrayRef ac_pairs = NULL; SecCFDictionaryCOW auth_options = { NULL }; @@ -1182,7 +1247,7 @@ bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAu for (uint32_t i = 0;; ++i) { // If the operation succeeded or failed with other than auth-needed error, just leave. - SecItemAuthResult auth_result = perform(auth_params->dictionary, &ac_pairs, error); + SecItemAuthResult auth_result = perform(&ac_pairs, error); require_quiet(auth_result != kSecItemAuthResultError, out); require_action_quiet(auth_result == kSecItemAuthResultNeedAuth, out, ok = true); @@ -1200,6 +1265,9 @@ bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAu require_quiet(acm_context = LACopyACMContext(auth_handle, error), out); CFDictionarySetValue(SecCFDictionaryCOWGetMutable(auth_params), kSecUseCredentialReference, acm_context); CFRelease(acm_context); + if (newCredentialRefAdded) { + newCredentialRefAdded(); + } } } @@ -1316,10 +1384,10 @@ static SecItemAuthResult SecItemCreatePairsFromError(CFErrorRef *error, CFArrayR } // Wrapper to handle automatic authentication and token/secd case switching. -static bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attributes, const void *secItemOperation, CFErrorRef *error, +bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attributes, const void *secItemOperation, CFErrorRef *error, bool (^perform)(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error)) { bool ok = false; - SecCFDictionaryCOW auth_params = { NULL }; + __block SecCFDictionaryCOW auth_params = { NULL }; SecAccessControlRef access_control = NULL; __block TKTokenRef token = NULL; @@ -1352,17 +1420,17 @@ static bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *at CFSTR("kSecUseAuthenticationUISkip is allowed only for SecItemCopyMatching"))); } - ok = SecItemAuthDo(&auth_params, error, ^SecItemAuthResult(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error) { + ok = SecItemAuthDo(&auth_params, error, ^SecItemAuthResult(CFArrayRef *ac_pairs, CFErrorRef *error) { SecItemAuthResult result = kSecItemAuthResultError; // Propagate actual credential reference to the query. - if (auth_params != NULL) { - CFDataRef acm_context = CFDictionaryGetValue(auth_params, kSecUseCredentialReference); + if (auth_params.dictionary != NULL) { + CFDataRef acm_context = CFDictionaryGetValue(auth_params.dictionary, kSecUseCredentialReference); if (acm_context != NULL) { CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecUseCredentialReference, acm_context); } - CFDataRef acl_data_ref = CFDictionaryGetValue(auth_params, kSecAttrAccessControl); + CFDataRef acl_data_ref = CFDictionaryGetValue(auth_params.dictionary, kSecAttrAccessControl); if (acl_data_ref != NULL) { CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attributes ?: query), kSecAttrAccessControl, acl_data_ref); } @@ -1371,11 +1439,11 @@ static bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *at // Prepare connection to target token if it is present. CFStringRef token_id = CFDictionaryGetValue(query->dictionary, kSecAttrTokenID); if (secItemOperation != SecItemCopyMatching && token_id != NULL) { - require_quiet(CFAssignRetained(token, SecTokenCreate(token_id, auth_params, error)), out); + require_quiet(CFAssignRetained(token, SecTokenCreate(token_id, auth_params.dictionary, error)), out); } CFDictionaryRef attrs = (attributes != NULL) ? attributes->dictionary : NULL; - if(!perform(token, query->dictionary, attrs, auth_params, error)) { + if(!perform(token, query->dictionary, attrs, auth_params.dictionary, error)) { require_quiet((result = SecItemCreatePairsFromError(error, ac_pairs)) == kSecItemAuthResultOK, out); } @@ -1383,7 +1451,7 @@ static bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *at out: return result; - }); + }, NULL); require_quiet(ok, out); ok = true; @@ -1482,6 +1550,7 @@ static bool SecTokenProcessError(CFStringRef operation, TKTokenRef token, CFType static CFTypeRef SecTokenCopyUpdatedObjectID(TKTokenRef token, CFDataRef object_id, CFMutableDictionaryRef attributes, CFErrorRef *error) { CFDataRef access_control = NULL, db_value = NULL, new_object_id = NULL; SecAccessControlRef ac = NULL; + CFDictionaryRef old_attrs = NULL; // Make sure that ACL is bound - if not, generate an error which will trigger binding. CFDataRef ac_data = CFDictionaryGetValue(attributes, kSecAttrAccessControl); @@ -1492,8 +1561,14 @@ static CFTypeRef SecTokenCopyUpdatedObjectID(TKTokenRef token, CFDataRef object_ } // Create or update the object on the token. + old_attrs = CFDictionaryCreateCopy(kCFAllocatorDefault, attributes); require_action_quiet(new_object_id = TKTokenCreateOrUpdateObject(token, object_id, attributes, error), out, SecTokenProcessError(kAKSKeyOpEncrypt, token, object_id ?: (CFTypeRef)attributes, error)); + CFDictionaryForEach(old_attrs, ^(const void *key, const void *value) { + if (!CFEqual(key, kSecValueData)) { + CFDictionaryAddValue(attributes, key, value); + } + }); // Prepare kSecValueData field for the item to be stored into the keychain DB. require_quiet(access_control = TKTokenCopyObjectAccessControl(token, new_object_id, error), out); @@ -1508,6 +1583,7 @@ out: CFReleaseSafe(ac); CFReleaseSafe(access_control); CFReleaseSafe(db_value); + CFReleaseSafe(old_attrs); return new_object_id; } @@ -1517,20 +1593,29 @@ static bool SecTokenItemAdd(TKTokenRef token, CFDictionaryRef attributes, CFDict CFTypeRef object_id = NULL, ref = NULL; CFDictionaryRef ref_attrs = NULL; CFTypeRef db_result = NULL; - + CFDataRef db_value = NULL; CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, attributes); - require_quiet(object_id = SecTokenCopyUpdatedObjectID(token, NULL, attrs, error), out); - - // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done - // by creating ref and getting back its attributes. - require_quiet(SecTokenItemCreateFromAttributes(attrs, auth_params, token, object_id, &ref, error), out); - if (ref != NULL) { - if ((ref_attrs = SecItemCopyAttributeDictionary(ref, false)) != NULL) { - CFDictionaryForEach(ref_attrs, ^(const void *key, const void *value) { - if (!CFEqual(key, kSecValueData)) { - CFDictionaryAddValue(attrs, key, value); - } - }); + + CFDictionarySetValue(attrs, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate); //token items should be accesible always because have own ACL encoded in OID + object_id = CFRetainSafe(CFDictionaryGetValue(attrs, kSecAttrTokenOID)); + CFDictionaryRemoveValue(attrs, kSecAttrTokenOID); + require_quiet(CFAssignRetained(object_id, SecTokenCopyUpdatedObjectID(token, object_id, attrs, error)), out); + if (CFDictionaryContainsKey(attrs, kSecValueRef)) { + // All attributes already had been extracted from valueRef, so do not go through that step again, just remove + // the ref from the dictionary since it is of no use any more. + CFDictionaryRemoveValue(attrs, kSecValueRef); + } else { + // Augment attributes from default attributes of the related ref (SecKeyRef, SecCertificateRef). This is best done + // by creating ref and getting back its attributes. + require_quiet(SecTokenItemCreateFromAttributes(attrs, auth_params, token, object_id, &ref, error), out); + if (ref != NULL) { + if ((ref_attrs = SecItemCopyAttributeDictionary(ref, false)) != NULL) { + CFDictionaryForEach(ref_attrs, ^(const void *key, const void *value) { + if (!CFEqual(key, kSecValueData)) { + CFDictionaryAddValue(attrs, key, value); + } + }); + } } } @@ -1547,11 +1632,11 @@ static bool SecTokenItemAdd(TKTokenRef token, CFDictionaryRef attributes, CFDict db_result = CFRetain(attrs); } require_quiet(SecItemResultProcess(attributes, auth_params, token, db_result, result, error), out); - ok = true; out: CFReleaseSafe(db_result); + CFReleaseSafe(db_value); CFReleaseSafe(attrs); CFReleaseSafe(ref_attrs); CFReleaseSafe(object_id); @@ -1563,8 +1648,10 @@ OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) { __block SecCFDictionaryCOW attrs = { attributes }; OSStatus status; - os_activity_t trace_activity = os_activity_start("SecItemAdd_ios", OS_ACTIVITY_FLAG_DEFAULT); - + os_activity_t activity = os_activity_create("SecItemAdd_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + require_quiet(!explode_identity(attrs.dictionary, (secitem_operation)SecItemAdd, &status, result), errOut); infer_cert_label(&attrs); @@ -1588,7 +1675,6 @@ OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) { errOut: CFReleaseSafe(attrs.mutable_dictionary); - os_activity_end(trace_activity); return status; } @@ -1597,8 +1683,10 @@ OSStatus SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) { OSStatus status; __block SecCFDictionaryCOW query = { inQuery }; - os_activity_t trace_activity = os_activity_start("SecItemCopyMatching_ios", OS_ACTIVITY_FLAG_DEFAULT); - + os_activity_t activity = os_activity_create("SecItemCopyMatching_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemCopyMatching, &status, result), errOut); bool wants_data = cf_bool_value(CFDictionaryGetValue(query.dictionary, kSecReturnData)); @@ -1628,7 +1716,6 @@ OSStatus SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) { errOut: CFReleaseSafe(query.mutable_dictionary); - os_activity_end(trace_activity); return status; } @@ -1734,6 +1821,10 @@ static bool SecTokenItemUpdate(TKTokenRef token, CFDictionaryRef query, CFDictio } OSStatus SecItemUpdate(CFDictionaryRef inQuery, CFDictionaryRef inAttributesToUpdate) { + os_activity_t activity = os_activity_create("SecItemUpdate_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + return SecOSStatusWith(^bool(CFErrorRef *error) { return SecItemUpdateWithError(inQuery, inAttributesToUpdate, error); }); @@ -1770,7 +1861,7 @@ static OSStatus explode_persistent_identity_ref(SecCFDictionaryCOW *query) OSStatus status = errSecSuccess; CFTypeRef persist = CFDictionaryGetValue(query->dictionary, kSecValuePersistentRef); CFStringRef class; - if (persist && _SecItemParsePersistentRef(persist, &class, NULL) + if (persist && _SecItemParsePersistentRef(persist, &class, NULL, NULL) && CFEqual(class, kSecClassIdentity)) { const void *keys[] = { kSecReturnRef, kSecValuePersistentRef }; const void *vals[] = { kCFBooleanTrue, persist }; @@ -1781,6 +1872,8 @@ static OSStatus explode_persistent_identity_ref(SecCFDictionaryCOW *query) CFReleaseNull(persistent_query); if (status) return status; + if (item_query == NULL) + return errSecItemNotFound; CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(query), kSecValuePersistentRef); CFDictionarySetValue(SecCFDictionaryCOWGetMutable(query), kSecValueRef, item_query); @@ -1794,8 +1887,10 @@ OSStatus SecItemDelete(CFDictionaryRef inQuery) { OSStatus status; __block SecCFDictionaryCOW query = { inQuery }; - os_activity_t trace_activity = os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT); - + os_activity_t activity = os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + require_noerr_quiet(status = explode_persistent_identity_ref(&query), errOut); require_quiet(!explode_identity(query.dictionary, (secitem_operation)SecItemDelete, &status, NULL), errOut); @@ -1827,8 +1922,7 @@ OSStatus SecItemDelete(CFDictionaryRef inQuery) { errOut: CFReleaseSafe(query.mutable_dictionary); - os_activity_end(trace_activity); - + return status; } @@ -1838,11 +1932,6 @@ SecItemDeleteAll(void) return SecOSStatusWith(^bool (CFErrorRef *error) { bool ok = true; if (gSecurityd) { -#ifndef SECITEM_SHIM_OSX - SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser); - if (!gSecurityd->sec_truststore_remove_all(ts, error)) - ok &= SecError(errSecInternal, error, CFSTR("sec_truststore_remove_all is NULL")); -#endif // *** END SECITEM_SHIM_OSX *** if (!gSecurityd->sec_item_delete_all(error)) ok &= SecError(errSecInternal, error, CFSTR("sec_item_delete_all is NULL")); } else { @@ -1852,6 +1941,7 @@ SecItemDeleteAll(void) }); } +#if 0 static bool agrps_client_to_error_request(enum SecXPCOperation op, CFArrayRef agrps, __unused SecurityClient *client, CFErrorRef *error) { @@ -1859,19 +1949,17 @@ agrps_client_to_error_request(enum SecXPCOperation op, CFArrayRef agrps, __unuse return SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, agrps, error); }, NULL); } +#endif bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups, CFErrorRef *error) { #if 0 - os_activity_t trace_activity = os_activity_start("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_FLAG_DEFAULT); - - bool ok = SECURITYD_XPC(sec_delete_items_with_access_groups, agrps_client_to_error_request, accessGroups, - SecSecurityClientGet(), error); + os_activity_t activity = os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); - os_activity_end(trace_activity); - return ok; + return SECURITYD_XPC(sec_delete_items_with_access_groups, agrps_client_to_error_request, accessGroups, + SecSecurityClientGet(), error); #else - os_activity_t trace_activity = os_activity_start("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_FLAG_DEFAULT); - os_activity_end(trace_activity); return true; #endif } @@ -1885,7 +1973,9 @@ SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes) { OSStatus status; - os_activity_t trace_activity = os_activity_start("SecItemDelete_ios", OS_ACTIVITY_FLAG_DEFAULT); + os_activity_t activity = os_activity_create("SecItemDelete_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); status = SecOSStatusWith(^bool(CFErrorRef *error) { CFArrayRef tmpArrayRef = tokenItemsAttributes; @@ -1922,8 +2012,6 @@ SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes) return SECURITYD_XPC(sec_item_update_token_items, cfstring_array_to_error_request, tokenID, tmpArrayRef, SecSecurityClientGet(), error); }); - os_activity_end(trace_activity); - return status; } @@ -1970,4 +2058,52 @@ bool _SecKeychainRollKeys(bool force, CFErrorRef *error) return result; } +static CFArrayRef data_array_to_array_error_request(enum SecXPCOperation op, CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) { + __block CFArrayRef results = NULL; + securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { + SecXPCDictionarySetData(message, kSecXPCKeyNormalizedIssuer, normalizedIssuer, error); + SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, accessGroups, error); + return true; + }, ^bool(xpc_object_t response, CFErrorRef *error) { + return SecXPCDictionaryCopyArrayOptional(response, kSecXPCKeyResult, &results, error); + }); + return results; +} + +static bool data_data_array_to_bool_error_request(enum SecXPCOperation op, CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) { + __block bool result = false; + securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { + SecXPCDictionarySetData(message, kSecXPCKeyNormalizedIssuer, normalizedIssuer, error); + SecXPCDictionarySetData(message, kSecXPCKeySerialNumber, serialNumber, error); + SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, accessGroups, error); + return true; + }, ^bool(xpc_object_t response, CFErrorRef *error) { + result = xpc_dictionary_get_bool(response, kSecXPCKeyResult); + return result; + }); + return result; +} + +CFArrayRef SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) { + CFArrayRef results = NULL; + + os_activity_t activity = os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + + results = SECURITYD_XPC(sec_item_copy_parent_certificates, data_array_to_array_error_request, normalizedIssuer, accessGroups, error); + + return results; +} +bool SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) { + bool results = false; + + os_activity_t activity = os_activity_create("SecItemCopyParentCertificates_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + os_release(activity); + + results = SECURITYD_XPC(sec_item_certificate_exists, data_data_array_to_bool_error_request, normalizedIssuer, serialNumber, accessGroups, error); + + return results; +} diff --git a/OSX/sec/Security/SecItem.m b/OSX/sec/Security/SecItem.m new file mode 100644 index 00000000..7af25f37 --- /dev/null +++ b/OSX/sec/Security/SecItem.m @@ -0,0 +1,151 @@ +/* + * 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@ + */ + +/* + * Implements SecItem.c things using Obj-c. + */ + +#include +#include +#include +#include +#include + +#include + +#import + +OSStatus _SecItemAddAndNotifyOnSync(CFDictionaryRef attributes, CFTypeRef * CF_RETURNS_RETAINED result, void (^syncCallback)(bool didSync, CFErrorRef error)) { + __block SecCFDictionaryCOW attrs = { attributes }; + OSStatus status = errSecParam; + + os_activity_t activity = os_activity_create("_SecItemAddAndNotifyOnSync", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + + status = SecOSStatusWith(^bool(CFErrorRef *statuserror) { + return SecItemAuthDoQuery(&attrs, NULL, SecItemAdd, statuserror, ^bool(TKTokenRef token, CFDictionaryRef authedattributes, CFDictionaryRef unused, CFDictionaryRef auth_params, CFErrorRef *autherror) { + if (token != NULL) { + syncCallback(false, NULL); + return false; + } + + __block CFTypeRef raw_result = NULL; + __block CFErrorRef raw_error = NULL; + + id rpc = SecuritydXPCProxyObject(^(NSError *error) { + syncCallback(false, (__bridge CFErrorRef)error); + }); + if (rpc == NULL) { + return false; + } + SecuritydXPCCallback* xpcCallback = [[SecuritydXPCCallback alloc] initWithCallback: ^void(bool didSync, NSError* error) { + syncCallback(didSync, (__bridge CFErrorRef) error); + }]; + + dispatch_semaphore_t wait_for_secd = dispatch_semaphore_create(0); + [rpc SecItemAddAndNotifyOnSync: (__bridge NSDictionary*) authedattributes syncCallback:xpcCallback complete: ^void (NSDictionary* opDictResult, NSArray* opArrayResult, NSError* operror) { + raw_result = opDictResult ? CFBridgingRetain(opDictResult) : + opArrayResult ? CFBridgingRetain(opArrayResult) : NULL; + raw_error = (CFErrorRef) CFBridgingRetain(operror); + dispatch_semaphore_signal(wait_for_secd); + }]; + dispatch_semaphore_wait(wait_for_secd, DISPATCH_TIME_FOREVER); + + if(autherror) { + *autherror = raw_error; + } + + bool ok = false; + + // SecItemResultProcess isn't intended to handle error cases, so bypass it. + if(!raw_error) { + ok = SecItemResultProcess(authedattributes, auth_params, token, raw_result, result, autherror); + } + CFReleaseNull(raw_result); + return ok; + }); + }); + CFReleaseNull(attrs.mutable_dictionary); + + return status; +} + +void SecItemSetCurrentItemAcrossAllDevices(CFStringRef accessGroup, + CFStringRef identifier, + CFStringRef viewHint, + CFDataRef newCurrentItemReference, + CFDataRef newCurrentItemHash, + CFDataRef oldCurrentItemReference, + CFDataRef oldCurrentItemHash, + void (^complete)(CFErrorRef error)) +{ + os_activity_t activity = os_activity_create("SecItemSetCurrentItemAcrossAllDevices", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + + id rpc = SecuritydXPCProxyObject(^(NSError *error) { + complete((__bridge CFErrorRef) error); + }); + [rpc secItemSetCurrentItemAcrossAllDevices:(__bridge NSData*)newCurrentItemReference + newCurrentItemHash:(__bridge NSData*)newCurrentItemHash + accessGroup:(__bridge NSString*)accessGroup + identifier:(__bridge NSString*)identifier + viewHint:(__bridge NSString*)viewHint + oldCurrentItemReference:(__bridge NSData*)oldCurrentItemReference + oldCurrentItemHash:(__bridge NSData*)oldCurrentItemHash + complete: ^ (NSError* operror) { + complete((__bridge CFErrorRef) operror); + }]; +} + +void SecItemFetchCurrentItemAcrossAllDevices(CFStringRef accessGroup, + CFStringRef identifier, + CFStringRef viewHint, + bool fetchCloudValue, + void (^complete)(CFDataRef persistentRef, CFErrorRef error)) +{ + os_activity_t activity = os_activity_create("SecItemFetchCurrentItemAcrossAllDevices", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + + id rpc = SecuritydXPCProxyObject(^(NSError *error) { + complete(NULL, (__bridge CFErrorRef) error); + }); + [rpc secItemFetchCurrentItemAcrossAllDevices:(__bridge NSString*)accessGroup + identifier:(__bridge NSString*)identifier + viewHint:(__bridge NSString*)viewHint + fetchCloudValue:fetchCloudValue + complete: ^(NSData* persistentRef, NSError* operror) { + complete((__bridge CFDataRef) persistentRef, (__bridge CFErrorRef) operror); + }]; +} + +void _SecItemFetchDigests(NSString *itemClass, NSString *accessGroup, void (^complete)(NSArray *, NSError *)) +{ + os_activity_t activity = os_activity_create("_SecItemFetchDigests", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + + id rpc = SecuritydXPCProxyObject(^(NSError *error) { + complete(NULL, error); + }); + [rpc secItemDigest:itemClass accessGroup:accessGroup complete:complete]; +} + diff --git a/OSX/sec/Security/SecItemBackup.c b/OSX/sec/Security/SecItemBackup.c index d11bdee0..c55d70f0 100644 --- a/OSX/sec/Security/SecItemBackup.c +++ b/OSX/sec/Security/SecItemBackup.c @@ -199,7 +199,7 @@ _SecKeychainRestoreBackupFromFileDescriptor(int fd, CFDataRef backupKeybag, CFDa CFStringRef _SecKeychainCopyKeybagUUIDFromFileDescriptor(int fd, CFErrorRef *error) { - __block CFStringRef result; + __block CFStringRef result = NULL; os_activity_initiate("_SecKeychainCopyKeybagUUID", OS_ACTIVITY_FLAG_DEFAULT, ^{ securityd_send_sync_and_do(sec_keychain_backup_keybag_uuid_id, error, ^bool(xpc_object_t message, CFErrorRef *error) { return SecXPCDictionarySetFileDescriptor(message, kSecXPCKeyFileDescriptor, fd, error); @@ -280,21 +280,40 @@ static bool SecKeychainWithBackupFile(CFStringRef backupName, CFErrorRef *error, } // Rewind file to start - lseek(fd, 0, SEEK_SET); + if (lseek(fd, 0, SEEK_SET)) { + secdebug("backup", "Could not seek in fd %d for %@", fd, backupName); + return SecCheckErrno(true, error, CFSTR("lseek")); + } FILE *backup = fdopen(fd, "r"); if (!backup) { - close(fd); secdebug("backup", "Receiving file for %@ failed, %d", backupName, errno); - return SecCheckErrno(!backup, error, CFSTR("fdopen")); + SecCheckErrno(!backup, error, CFSTR("fdopen")); + if (close(fd)) { + secdebug("backup", "Encountered error closing file %@: %d", backupName, errno); + SecCheckErrno(true, error, CFSTR("close")); + } + return false; } else { struct stat sb; - fstat(fd, &sb); + if (fstat(fd, &sb)) { + secdebug("backup", "Unable to get file metadata for %@, fd %d", backupName, fd); + SecCheckErrno(true, error, CFSTR("fstat")); + if (fclose(backup)) { + secdebug("backup", "Encountered error closing file %@: %d", backupName, errno); + SecCheckErrno(true, error, CFSTR("fclose")); + } + return false; + } secdebug("backup", "Receiving file for %@ with fd %d of size %llu", backupName, fd, sb.st_size); } with(backup); - fclose(backup); + if (fclose(backup)) { + secdebug("backup", "Encountered error %d closing file %@ after backup handler", errno, backupName); + SecCheckErrno(true, error, CFSTR("fclose")); + // read only file and block has its own error handling for IO failure, no need to return false + } return true; } @@ -566,4 +585,32 @@ CFDictionaryRef SecItemBackupCopyMatching(CFDataRef keybag, CFDataRef secret, CF return NULL; } +bool SecBackupKeybagAdd(CFDataRef passcode, CFDataRef *identifier, CFURLRef *pathinfo, CFErrorRef *error) { + __block bool result = false; + os_activity_initiate("_SecServerBackupKeybagAdd", OS_ACTIVITY_FLAG_DEFAULT, ^{ + securityd_send_sync_and_do(kSecXPCOpBackupKeybagAdd, error, ^bool(xpc_object_t message, CFErrorRef *error) { + return SecXPCDictionarySetDataOptional(message, kSecXPCKeyUserPassword, passcode, error); + }, ^bool(xpc_object_t response, CFErrorRef *error) { + result = SecXPCDictionaryCopyDataOptional(response, kSecXPCKeyBackupKeybagIdentifier, identifier, error) && + SecXPCDictionaryCopyURLOptional(response, kSecXPCKeyBackupKeybagPath, pathinfo, error) && + SecXPCDictionaryGetBool(response, kSecXPCKeyResult, error); + return result; + }); + }); + return result; +} + +bool SecBackupKeybagDelete(CFDictionaryRef query, CFErrorRef *error) { + __block bool result = false; + os_activity_initiate("_SecBackupKeybagDelete", OS_ACTIVITY_FLAG_DEFAULT, ^{ + securityd_send_sync_and_do(kSecXPCOpBackupKeybagDelete, error, ^bool(xpc_object_t message, CFErrorRef *error) { + return SecXPCDictionarySetPList(message, kSecXPCKeyQuery, query, error); + }, ^bool(xpc_object_t response, CFErrorRef *error) { + result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, error); + return result; + }); + }); + return result; +} + diff --git a/OSX/sec/Security/SecItemBackup.h b/OSX/sec/Security/SecItemBackup.h index 5cf8fc69..b6b73679 100644 --- a/OSX/sec/Security/SecItemBackup.h +++ b/OSX/sec/Security/SecItemBackup.h @@ -31,6 +31,7 @@ #include #include +#include __BEGIN_DECLS @@ -105,6 +106,26 @@ CFDictionaryRef SecItemBackupCopyMatching(CFDataRef keybag, CFDataRef secret, CF // Utility function to compute a confirmed manifest from a v0 backup dictionary. CFDataRef SecItemBackupCreateManifest(CFDictionaryRef backup, CFErrorRef *error); +/*! + @function SecBackupKeybagAdd + @abstract Add a new asymmetric keybag to the backup table. + @param passcode User entropy to protect the keybag. + @param identifier Unique identifier for the keybag. + @param pathinfo The directory or file containing the keychain. + @param error Returned if there is a failure. + @result bool standard CFError contract. + @discussion The keybag is created and stored in the backup keybag table */ +bool SecBackupKeybagAdd(CFDataRef passcode, CFDataRef *identifier, CFURLRef *pathinfo, CFErrorRef *error); + +/*! + @function SecBackupKeybagDelete + @abstract Remove an asymmetric keybag from the backup table. + @param query Specify which keybag(s) to delete + @param error Returned if there is a failure. + @result bool standard CFError contract. + @discussion The keychain must be unlocked */ +bool SecBackupKeybagDelete(CFDictionaryRef query, CFErrorRef *error); + __END_DECLS #endif /* _SECURITY_ITEMBACKUP_H_ */ diff --git a/OSX/sec/Security/SecItemConstants.c b/OSX/sec/Security/SecItemConstants.c index 978d009b..799e0c9d 100644 --- a/OSX/sec/Security/SecItemConstants.c +++ b/OSX/sec/Security/SecItemConstants.c @@ -109,6 +109,16 @@ SEC_CONST_DECL (kSecAttrTombstone, "tomb"); SEC_CONST_DECL (kSecAttrMultiUser, "musr"); SEC_CONST_DECL (kSecAttrNoLegacy, "nleg"); SEC_CONST_DECL (kSecAttrTokenOID, "toid"); +SEC_CONST_DECL (kSecAttrUUID, "UUID"); +SEC_CONST_DECL (kSecAttrPersistantReference, "persistref"); +SEC_CONST_DECL (kSecAttrPersistentReference, "persistref"); +SEC_CONST_DECL (kSecAttrSysBound, "sysb"); +SEC_CONST_DECL (kSecAttrSHA1, "sha1"); + +SEC_CONST_DECL (kSecAttrDeriveSyncIDFromItemAttributes, "dspk"); +SEC_CONST_DECL (kSecAttrPCSPlaintextServiceIdentifier, "pcss"); +SEC_CONST_DECL (kSecAttrPCSPlaintextPublicKey, "pcsk"); +SEC_CONST_DECL (kSecAttrPCSPlaintextPublicIdentity, "pcsi"); /* Predefined access groups constants */ SEC_CONST_DECL (kSecAttrAccessGroupToken, "com.apple.token"); @@ -149,6 +159,7 @@ SEC_CONST_DECL (kSecUseAuthenticationUI, "u_AuthUI"); SEC_CONST_DECL (kSecUseSystemKeychain, "u_SystemKeychain"); SEC_CONST_DECL (kSecUseSyncBubbleKeychain, "u_SyncBubbleKeychain"); SEC_CONST_DECL (kSecUseCallerName, "u_CallerName"); +SEC_CONST_DECL (kSecUseTokenRawItems, "u_TokenRawItems"); /* kSecAttrAccessible Value Constants. */ SEC_CONST_DECL (kSecAttrAccessibleWhenUnlocked, "ak"); @@ -218,6 +229,8 @@ SEC_CONST_DECL (kSecAttrKeyClassSymmetric, "2"); SEC_CONST_DECL (kSecAttrKeyTypeRSA, "42"); SEC_CONST_DECL (kSecAttrKeyTypeEC, "73"); /* rdar://10755886 */ SEC_CONST_DECL (kSecAttrKeyTypeECSECPrimeRandom, "73"); +SEC_CONST_DECL (kSecAttrKeyTypeECSECPrimeRandomPKA, "2147483678"); /* CSSM_ALGID__FIRST_UNUSED */ +SEC_CONST_DECL (kSecAttrKeyTypeSecureEnclaveAttestation, "2147483679"); /* CSSM_ALGID__FIRST_UNUSED + 1 */ /* kSecAttrSynchronizable Value Constants. */ SEC_CONST_DECL (kSecAttrSynchronizableAny, "syna"); @@ -227,6 +240,9 @@ SEC_CONST_DECL (kSecAttrSynchronizableAny, "syna"); SEC_CONST_DECL (kSecPrivateKeyAttrs, "private"); SEC_CONST_DECL (kSecPublicKeyAttrs, "public"); +/* This is here only temporarily until MobileActivation starts using kSecAttrTokenOID instead of this specific attribute. */ +SEC_CONST_DECL (kSecAttrSecureEnclaveKeyBlob, "toid"); + /* Constants used by SecPassword - in SecPasswordStrength */ SEC_CONST_DECL (kSecPasswordMaxLength, "PasswordMaxLength"); SEC_CONST_DECL (kSecPasswordMinLength, "PasswordMaxLength"); @@ -243,6 +259,10 @@ SEC_CONST_DECL (kSecUseAuthenticationContext, "u_AuthCtx"); /* kSecAttrTokenID Value Constants. */ SEC_CONST_DECL (kSecAttrTokenIDSecureEnclave, "com.apple.setoken"); +SEC_CONST_DECL (kSecAttrTokenIDAppleKeyStore, "com.apple.setoken:aks"); + +/* Internal kSecAttrAccessGroup for syncing */ +SEC_CONST_DECL (kSOSInternalAccessGroup, "com.apple.security.sos"); /* View Hint Constants */ @@ -250,6 +270,7 @@ SEC_CONST_DECL (kSecAttrTokenIDSecureEnclave, "com.apple.setoken"); #define DO_SEC_CONST_DECL_(VIEWNAME, DEFSTRING) const CFTypeRef kSecAttrViewHint##VIEWNAME = CFSTR(DEFSTRING); #define DO_SEC_CONST_DECL_V(VIEWNAME, DEFSTRING) -#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) DO_SEC_CONST_DECL_##V0SETTING(VIEWNAME, DEFSTRING) +#define DOVIEWMACRO(VIEWNAME, DEFSTRING, CMDSTRING, SYSTEM, DEFAULTSETTING, INITIALSYNCSETTING, ALWAYSONSETTING, BACKUPSETTING, V0SETTING) DO_SEC_CONST_DECL_##V0SETTING(VIEWNAME, DEFSTRING) #include "Security/SecureObjectSync/ViewList.list" #undef DOVIEWMACRO + diff --git a/OSX/sec/Security/SecItemInternal.h b/OSX/sec/Security/SecItemInternal.h index 30d4c20b..b4b0ac8e 100644 --- a/OSX/sec/Security/SecItemInternal.h +++ b/OSX/sec/Security/SecItemInternal.h @@ -43,10 +43,15 @@ __BEGIN_DECLS static const CFStringRef kSecAttrIdentityCertificateData = CFSTR("certdata"); static const CFStringRef kSecAttrIdentityCertificateTokenID = CFSTR("certtkid"); -CF_RETURNS_RETAINED CFDataRef _SecItemMakePersistentRef(CFTypeRef iclass, sqlite_int64 rowid); +// Keys for dictionary of kSecvalueData of token-based items. +static const CFStringRef kSecTokenValueObjectIDKey = CFSTR("oid"); +static const CFStringRef kSecTokenValueAccessControlKey = CFSTR("ac"); +static const CFStringRef kSecTokenValueDataKey = CFSTR("data"); + +CFDataRef _SecItemCreatePersistentRef(CFTypeRef iclass, sqlite_int64 rowid, CFDictionaryRef attributes); bool _SecItemParsePersistentRef(CFDataRef persistent_ref, CFStringRef *return_class, - sqlite_int64 *return_rowid); + sqlite_int64 *return_rowid, CFDictionaryRef *return_token_attrs); OSStatus _SecRestoreKeychain(const char *path); @@ -75,22 +80,33 @@ typedef struct { CFMutableDictionaryRef SecCFDictionaryCOWGetMutable(SecCFDictionaryCOW *cow_dictionary); +bool SecItemResultProcess(CFDictionaryRef query, CFDictionaryRef auth_params, TKTokenRef token, + CFTypeRef raw_result, CFTypeRef *result, CFErrorRef *error); + typedef enum { kSecItemAuthResultOK, kSecItemAuthResultError, kSecItemAuthResultNeedAuth } SecItemAuthResult; -bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAuthResult (^perform)(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error)); +bool SecItemAuthDo(SecCFDictionaryCOW *auth_params, CFErrorRef *error, SecItemAuthResult (^perform)(CFArrayRef *ac_pairs, CFErrorRef *error), + void (^newCredentialRefAdded)()); + +bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attributes, const void *secItemOperation, CFErrorRef *error, + bool (^perform)(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error)); void SecItemAuthCopyParams(SecCFDictionaryCOW *auth_params, SecCFDictionaryCOW *query); TKTokenRef SecTokenCreate(CFStringRef token_id, CFDictionaryRef auth_params, CFErrorRef *error); -CFDataRef _SecTokenItemCopyValueData(CFDataRef db_value, CFErrorRef *error); +CFDictionaryRef SecTokenItemValueCopy(CFDataRef db_value, CFErrorRef *error); CFDataRef SecItemAttributesCopyPreparedAuthContext(CFTypeRef la_context, CFErrorRef *error); +CFArrayRef SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error); + +bool SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error); + __END_DECLS #endif /* !_SECURITY_SECITEMINTERNAL_H_ */ diff --git a/OSX/sec/Security/SecKey.c b/OSX/sec/Security/SecKey.c index 8a7c75fe..ac6a5ef7 100644 --- a/OSX/sec/Security/SecKey.c +++ b/OSX/sec/Security/SecKey.c @@ -131,8 +131,8 @@ static CFDictionaryRef SecKeyCopyAttributeDictionaryWithLocalKey(SecKeyRef key, DICT_ADDPAIR(kSecAttrCanWrap, privateBlob ? kCFBooleanFalse : kCFBooleanTrue); DICT_ADDPAIR(kSecAttrCanUnwrap, privateBlob ? kCFBooleanTrue : kCFBooleanFalse); DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob); - dict = DICT_CREATE(allocator); - + dict = CFDictionaryCreate(allocator, keys, values, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + errOut: // @@@ Zero out key material. CFReleaseSafe(pubKeyDigest); @@ -294,12 +294,13 @@ OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, require_noerr_quiet(result, errOut); - /* Store the keys in the keychain if they are marked as permanent. */ + // Store the keys in the keychain if they are marked as permanent. Governed by kSecAttrIsPermanent attribute, with default + // to 'false' (ephemeral keys), except private token-based keys, in which case the default is 'true' (permanent keys). if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) { + CFDictionaryRemoveValue(pubParams, kSecAttrTokenID); require_noerr_quiet(result = add_ref(pubKey, pubParams), errOut); } - /* Token-based private keys are automatically stored on the token. */ - if (tokenID == NULL && getBoolForKey(privParams, kSecAttrIsPermanent, false)) { + if (getBoolForKey(privParams, kSecAttrIsPermanent, CFDictionaryContainsKey(privParams, kSecAttrTokenID))) { require_noerr_quiet(result = add_ref(privKey, privParams), errOut); } @@ -469,7 +470,101 @@ SecKeyRef SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator, CFD out: return NULL; +} + +static const DERByte oidRSA[] = { + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, +}; +static const DERByte oidECsecp256[] = { + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, +}; +static const DERByte oidECsecp384[] = { + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, +}; +static const DERByte oidECsecp521[] = { + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, +}; + + +CFDataRef SecKeyCopySubjectPublicKeyInfo(SecKeyRef key) +{ + CFMutableDataRef data = NULL; + CFDataRef publicKey = NULL; + CFDataRef dataret = NULL; + DERSubjPubKeyInfo spki; + DERReturn drtn; + size_t zeroPad = 0; + + memset(&spki, 0, sizeof(spki)); + + /* encode the public key. */ + require_noerr(SecKeyCopyPublicBytes(key, &publicKey), errOut); + require_quiet(publicKey, errOut); + + require(CFDataGetLength(publicKey) != 0, errOut); + + // Add prefix 00 is needed to avoid creating negative bit strings + if (((uint8_t *)CFDataGetBytePtr(publicKey))[0] & 0x80) + zeroPad = 1; + + + CFMutableDataRef paddedKey = CFDataCreateMutable(NULL, 0); + /* the bit strings bits used field first */ + CFDataAppendBytes(paddedKey, (const UInt8 *)"\x00", 1); + if (zeroPad) + CFDataAppendBytes(paddedKey, (const UInt8 *)"\x00", 1); + + CFDataAppendBytes(paddedKey, CFDataGetBytePtr(publicKey), CFDataGetLength(publicKey)); + CFTransferRetained(publicKey, paddedKey); + + spki.pubKey.data = (DERByte *)CFDataGetBytePtr(publicKey); + spki.pubKey.length = CFDataGetLength(publicKey); + + // Encode algId according to algorithm used. + CFIndex algorithm = SecKeyGetAlgorithmIdentifier(key); + if (algorithm == kSecRSAAlgorithmID) { + spki.algId.data = (DERByte *)oidRSA; + spki.algId.length = sizeof(oidRSA); + } else if (algorithm == kSecECDSAAlgorithmID) { + SecECNamedCurve curve = SecECKeyGetNamedCurve(key); + switch(curve) { + case kSecECCurveSecp256r1: + spki.algId.data = (DERByte *)oidECsecp256; + spki.algId.length = sizeof(oidECsecp256); + break; + case kSecECCurveSecp384r1: + spki.algId.data = (DERByte *)oidECsecp384; + spki.algId.length = sizeof(oidECsecp384); + break; + case kSecECCurveSecp521r1: + spki.algId.data = (DERByte *)oidECsecp521; + spki.algId.length = sizeof(oidECsecp521); + break; + default: + goto errOut; + } + } else { + goto errOut; + } + + DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &spki, + DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs); + data = CFDataCreateMutable(kCFAllocatorDefault, size); + CFDataSetLength(data, size); + + drtn = DEREncodeSequence(ASN1_CONSTR_SEQUENCE, &spki, + DERNumSubjPubKeyInfoItemSpecs, + DERSubjPubKeyInfoItemSpecs, + CFDataGetMutableBytePtr(data), &size); + require(drtn == DR_Success, errOut); + CFDataSetLength(data, size); + dataret = CFRetain(data); +errOut: + CFReleaseNull(data); + CFReleaseNull(publicKey); + + return dataret; } @@ -702,9 +797,7 @@ size_t SecKeyGetBlockSize(SecKeyRef key) { /* Private API functions. */ CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) { - if (key->key_class->copyDictionary) - return key->key_class->copyDictionary(key); - return NULL; + return SecKeyCopyAttributes(key); } SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes) { @@ -1032,23 +1125,33 @@ _SecKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, C return NULL; } -static SInt32 SecKeyParamsGetSInt32(CFTypeRef value, CFStringRef errName, CFErrorRef *error) { - SInt32 result = -1; - if (CFGetTypeID(value) == CFNumberGetTypeID()) { - if (!CFNumberGetValue(value, kCFNumberSInt32Type, &result) || result < 0) { - SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); +static CFIndex SecKeyParamsGetCFIndex(CFTypeRef value, CFStringRef errName, CFErrorRef *error) { + CFIndex result = -1; + CFNumberRef localValue = NULL; + + if (isString(value)) { + CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault, CFLocaleGetSystem(), kCFNumberFormatterDecimalStyle); + localValue = CFNumberFormatterCreateNumberFromString(kCFAllocatorDefault, formatter, value, NULL, kCFNumberFormatterParseIntegersOnly); + CFReleaseSafe(formatter); + + if (localValue) { + CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%@"), localValue); + if (CFEqual(t, value)) { + value = localValue; + } + CFReleaseSafe(t); } - } else if (isString(value)) { - result = CFStringGetIntValue(value); - CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) result); - if (!CFEqual(t, value) || result < 0) { + } + + if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID()) { + if (!CFNumberGetValue(value, kCFNumberCFIndexType, &result) || result < 0) { SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); - result = -1; } - CFReleaseSafe(t); } else { SecError(errSecParam, error, CFSTR("Unsupported %@: %@"), errName, value); } + + CFReleaseSafe(localValue); return result; } @@ -1057,13 +1160,15 @@ SecKeyRef SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef parameters, CF SecKeyRef key = NULL; CFAllocatorRef allocator = NULL; + if (CFDictionaryGetValue(parameters, kSecAttrTokenID) != NULL) { + return SecKeyCreateCTKKey(allocator, parameters, error); + } /* First figure out the key type (algorithm). */ - SInt32 algorithm; + CFIndex algorithm, class; CFTypeRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType); - require_quiet((algorithm = SecKeyParamsGetSInt32(ktype, CFSTR("key type"), error)) >= 0, out); - SInt32 class; + require_quiet((algorithm = SecKeyParamsGetCFIndex(ktype, CFSTR("key type"), error)) >= 0, out); CFTypeRef kclass = CFDictionaryGetValue(parameters, kSecAttrKeyClass); - require_quiet((class = SecKeyParamsGetSInt32(kclass, CFSTR("key class"), error)) >= 0, out); + require_quiet((class = SecKeyParamsGetCFIndex(kclass, CFSTR("key class"), error)) >= 0, out); switch (class) { case 0: // kSecAttrKeyClassPublic @@ -1091,10 +1196,6 @@ SecKeyRef SecKeyCreateWithData(CFDataRef keyData, CFDictionaryRef parameters, CF }; break; case 1: // kSecAttrKeyClassPrivate - if (CFDictionaryGetValue(parameters, kSecAttrTokenID) != NULL) { - key = SecKeyCreateCTKKey(allocator, parameters, error); - break; - } switch (algorithm) { case 42: // kSecAlgorithmRSA key = SecKeyCreateRSAPrivateKey(allocator, @@ -1140,9 +1241,35 @@ CFDataRef SecKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { } CFDictionaryRef SecKeyCopyAttributes(SecKeyRef key) { - if (key->key_class->copyDictionary) + if (key->key_class->copyDictionary) { return key->key_class->copyDictionary(key); - return NULL; + } else { + // Create dictionary with basic values derived from other known information of the key. + CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFIndex blockSize = SecKeyGetBlockSize(key) * 8; + if (blockSize > 0) { + CFNumberRef blockSizeRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &blockSize); + CFDictionarySetValue(dict, kSecAttrKeySizeInBits, blockSizeRef); + CFRelease(blockSizeRef); + } + + switch (SecKeyGetAlgorithmIdentifier(key)) { + case kSecRSAAlgorithmID: + CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeRSA); + break; + case kSecECDSAAlgorithmID: + CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom); + break; + } + + if (key->key_class->rawSign != NULL || key->key_class->decrypt != NULL) { + CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPrivate); + } else if (key->key_class->rawVerify != NULL || key->key_class->encrypt != NULL) { + CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPublic); + } + + return dict; + } } SecKeyRef SecKeyCopyPublicKey(SecKeyRef key) { diff --git a/OSX/sec/Security/SecKeyAdaptors.c b/OSX/sec/Security/SecKeyAdaptors.c index 901cf6fa..8a7861f5 100644 --- a/OSX/sec/Security/SecKeyAdaptors.c +++ b/OSX/sec/Security/SecKeyAdaptors.c @@ -60,6 +60,11 @@ const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224 = CFSTR(" const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256 = CFSTR("algid:sign:RSA:digest-PKCS1v15:SHA256"); const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384 = CFSTR("algid:sign:RSA:digest-PKCS1v15:SHA384"); const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512 = CFSTR("algid:sign:RSA:digest-PKCS1v15:SHA512"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA1 = CFSTR("algid:sign:RSA:digest-PSS:SHA1:SHA1:20"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA224 = CFSTR("algid:sign:RSA:digest-PSS:SHA224:SHA224:24"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA256 = CFSTR("algid:sign:RSA:digest-PSS:SHA256:SHA256:32"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA384 = CFSTR("algid:sign:RSA:digest-PSS:SHA384:SHA384:48"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA512 = CFSTR("algid:sign:RSA:digest-PSS:SHA512:SHA512:64"); const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5 = CFSTR("algid:sign:RSA:message-PKCS1v15:MD5"); const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1 = CFSTR("algid:sign:RSA:message-PKCS1v15:SHA1"); @@ -67,6 +72,11 @@ const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224 = CFSTR( const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256 = CFSTR("algid:sign:RSA:message-PKCS1v15:SHA256"); const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384 = CFSTR("algid:sign:RSA:message-PKCS1v15:SHA384"); const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512 = CFSTR("algid:sign:RSA:message-PKCS1v15:SHA512"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA1 = CFSTR("algid:sign:RSA:message-PSS:SHA1:SHA1:20"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA224 = CFSTR("algid:sign:RSA:message-PSS:SHA224:SHA224:24"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA256 = CFSTR("algid:sign:RSA:message-PSS:SHA256:SHA256:32"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA384 = CFSTR("algid:sign:RSA:message-PSS:SHA384:SHA384:48"); +const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA512 = CFSTR("algid:sign:RSA:message-PSS:SHA512:SHA512:64"); const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureRFC4754 = CFSTR("algid:sign:ECDSA:RFC4754"); @@ -110,6 +120,16 @@ const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM = const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM = CFSTR("algid:encrypt:ECIES:ECDHC:KDFX963:SHA384:AESGCM"); const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM = CFSTR("algid:encrypt:ECIES:ECDHC:KDFX963:SHA512:AESGCM"); +const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM = CFSTR("algid:encrypt:ECIES:ECDH:KDFX963:SHA224:AESGCM-KDFIV"); +const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM = CFSTR("algid:encrypt:ECIES:ECDH:KDFX963:SHA256:AESGCM-KDFIV"); +const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM = CFSTR("algid:encrypt:ECIES:ECDH:KDFX963:SHA384:AESGCM-KDFIV"); +const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM = CFSTR("algid:encrypt:ECIES:ECDH:KDFX963:SHA512:AESGCM-KDFIV"); + +const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM = CFSTR("algid:encrypt:ECIES:ECDHC:KDFX963:SHA224:AESGCM-KDFIV"); +const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM = CFSTR("algid:encrypt:ECIES:ECDHC:KDFX963:SHA256:AESGCM-KDFIV"); +const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM = CFSTR("algid:encrypt:ECIES:ECDHC:KDFX963:SHA384:AESGCM-KDFIV"); +const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM = CFSTR("algid:encrypt:ECIES:ECDHC:KDFX963:SHA512:AESGCM-KDFIV"); + const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandard = CFSTR("algid:keyexchange:ECDH"); const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1 = CFSTR("algid:keyexchange:ECDH:KDFX963:SHA1"); const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224 = CFSTR("algid:keyexchange:ECDH:KDFX963:SHA224"); @@ -138,8 +158,8 @@ static void PerformWithCFDataBuffer(CFIndex size, void (^operation)(uint8_t *buf }); } -static CF_RETURNS_RETAINED CFDataRef SecKeyMessageToDigestAdaptor(SecKeyOperationContext *context, CFDataRef message, CFDataRef in2, - const struct ccdigest_info *di, CFErrorRef *error) { +static CFDataRef SecKeyCopyDigestForMessage(SecKeyOperationContext *context, CFDataRef message, CFDataRef in2, + const struct ccdigest_info *di, CFErrorRef *error) { if (context->mode == kSecKeyOperationModeCheckIfSupported) { return SecKeyRunAlgorithmAndCopyResult(context, NULL, NULL, error); } @@ -152,34 +172,58 @@ static CF_RETURNS_RETAINED CFDataRef SecKeyMessageToDigestAdaptor(SecKeyOperatio return result; } -#define SECKEY_DIGEST_RSA_ADAPTORS(name, di) \ -static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePKCS1v15 ## name( \ +static CFTypeRef SecKeyCopyECDSASignatureForDigest(SecKeyOperationContext *context, CFDataRef digest, CFDataRef in2, + SecKeyAlgorithm algorithm, const struct ccdigest_info *di, CFErrorRef *error) { + CFArrayAppendValue(context->algorithm, kSecKeyAlgorithmECDSASignatureDigestX962); + if (context->mode == kSecKeyOperationModeCheckIfSupported) { + return SecKeyRunAlgorithmAndCopyResult(context, NULL, NULL, error); + } + + if (CFDataGetLength(digest) != (CFIndex)di->output_size) { + SecError(errSecParam, error, CFSTR("bad digest size for signing with algorithm %@"), algorithm); + return NULL; + } + + return SecKeyRunAlgorithmAndCopyResult(context, digest, in2, error); +} + +#define DIGEST_RSA_ADAPTORS(name, di) \ +static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessage ## name( \ SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { \ - CFArrayAppendValue(context->algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15 ## name); \ - return SecKeyMessageToDigestAdaptor(context, in1, in2, di, error); \ + CFArrayAppendValue(context->algorithm, kSecKeyAlgorithmRSASignatureDigest ## name); \ + return SecKeyCopyDigestForMessage(context, in1, in2, di, error); \ } -#define SECKEY_DIGEST_ADAPTORS(name, di) SECKEY_DIGEST_RSA_ADAPTORS(name, di) \ -static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureMessageX962 ## name( \ +#define DIGEST_ECDSA_ADAPTORS(name, di) \ +static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureMessage ## name( \ SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { \ - CFArrayAppendValue(context->algorithm, kSecKeyAlgorithmECDSASignatureDigestX962 ## name); \ - return SecKeyMessageToDigestAdaptor(context, in1, in2, di, error); \ + CFArrayAppendValue(context->algorithm, kSecKeyAlgorithmECDSASignatureDigest ## name); \ + return SecKeyCopyDigestForMessage(context, in1, in2, di, error); \ } \ -static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureDigestX962 ## name( \ +static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureDigest ## name( \ SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { \ - CFArrayAppendValue(context->algorithm, kSecKeyAlgorithmECDSASignatureDigestX962); \ - return SecKeyRunAlgorithmAndCopyResult(context, in1, in2, error); \ + return SecKeyCopyECDSASignatureForDigest(context, in1, in2, kSecKeyAlgorithmECDSASignatureDigest ## name, di, error); \ } -SECKEY_DIGEST_ADAPTORS(SHA1, ccsha1_di()) -SECKEY_DIGEST_ADAPTORS(SHA224, ccsha224_di()) -SECKEY_DIGEST_ADAPTORS(SHA256, ccsha256_di()) -SECKEY_DIGEST_ADAPTORS(SHA384, ccsha384_di()) -SECKEY_DIGEST_ADAPTORS(SHA512, ccsha512_di()) -SECKEY_DIGEST_RSA_ADAPTORS(MD5, ccmd5_di()) - -#undef SECKEY_DIGEST_RSA_ADAPTORS -#undef SECKEY_DIGEST_ADAPTORS +DIGEST_RSA_ADAPTORS(PKCS1v15SHA1, ccsha1_di()) +DIGEST_RSA_ADAPTORS(PKCS1v15SHA224, ccsha224_di()) +DIGEST_RSA_ADAPTORS(PKCS1v15SHA256, ccsha256_di()) +DIGEST_RSA_ADAPTORS(PKCS1v15SHA384, ccsha384_di()) +DIGEST_RSA_ADAPTORS(PKCS1v15SHA512, ccsha512_di()) +DIGEST_RSA_ADAPTORS(PKCS1v15MD5, ccmd5_di()) +DIGEST_RSA_ADAPTORS(PSSSHA1, ccsha1_di()) +DIGEST_RSA_ADAPTORS(PSSSHA224, ccsha224_di()) +DIGEST_RSA_ADAPTORS(PSSSHA256, ccsha256_di()) +DIGEST_RSA_ADAPTORS(PSSSHA384, ccsha384_di()) +DIGEST_RSA_ADAPTORS(PSSSHA512, ccsha512_di()) +DIGEST_ECDSA_ADAPTORS(X962SHA1, ccsha1_di()) +DIGEST_ECDSA_ADAPTORS(X962SHA224, ccsha224_di()) +DIGEST_ECDSA_ADAPTORS(X962SHA256, ccsha256_di()) +DIGEST_ECDSA_ADAPTORS(X962SHA384, ccsha384_di()) +DIGEST_ECDSA_ADAPTORS(X962SHA512, ccsha512_di()) + +#undef DIGEST_RSA_ADAPTORS +#undef DIGEST_ECDSA_ADAPTORS static CFDataRef SecKeyRSACopyBigEndianToCCUnit(CFDataRef bigEndian, size_t size) { CFMutableDataRef result = NULL; @@ -231,17 +275,35 @@ static void PerformWithCCUnitToBigEndian(CFDataRef ccunits, size_t size, void (^ }); } -static CFTypeRef SecKeyRSACopyPKCS1EMSASignature(SecKeyOperationContext *context, - CFDataRef in1, CFDataRef in2, CFErrorRef *error, const uint8_t *oid) { - if (oid != NULL) { +static CFTypeRef SecKeyRSACopyEMSASignature(SecKeyOperationContext *context, + CFDataRef in1, CFDataRef in2, CFErrorRef *error, bool pss, const struct ccdigest_info *di) { + CFDictionaryRef parameters = NULL; + __block CFTypeRef result = NULL; + + require_action_quiet(parameters = SecKeyCopyAttributes(context->key), out, + SecError(errSecParam, error, CFSTR("Unable to export key parameters"))); + require_action_quiet(CFEqual(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeRSA), out, result = kCFNull); + require_action_quiet(CFEqual(CFDictionaryGetValue(parameters, kSecAttrKeyClass), kSecAttrKeyClassPrivate), out, result = kCFNull); + CFReleaseNull(parameters); + + if (pss) { + // Verify that algorithm is compatible with the modulus size. + size_t blockSize = SecKeyGetBlockSize(context->key); + require_action_quiet(blockSize >= di->output_size * 2 + 2, out, + SecError(errSecParam, error, CFSTR("algorithm %@ incompatible with %lubit RSA key"), + CFArrayGetValueAtIndex(context->algorithm, CFArrayGetCount(context->algorithm) - 1), + blockSize * 8)); + } + + if (!pss && di != NULL) { CFArrayAppendValue(context->algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw); } + CFArrayAppendValue(context->algorithm, kSecKeyAlgorithmRSASignatureRawCCUnit); if (context->mode == kSecKeyOperationModeCheckIfSupported) { return SecKeyRunAlgorithmAndCopyResult(context, NULL, NULL, error); } - __block CFTypeRef result = NULL; size_t size = SecKeyGetBlockSize(context->key); if (size == 0) { SecError(errSecParam, error, CFSTR("expecting RSA key")); @@ -249,33 +311,49 @@ static CFTypeRef SecKeyRSACopyPKCS1EMSASignature(SecKeyOperationContext *context } PerformWithCFDataBuffer(size, ^(uint8_t *buffer, CFDataRef data) { uint8_t s[size]; - int err = ccrsa_emsa_pkcs1v15_encode(size, s, CFDataGetLength(in1), CFDataGetBytePtr(in1), oid); - require_noerr_action_quiet(err, out, SecError(errSecParam, error, CFSTR("RSAsign wrong input data length"))); + if (pss) { + uint8_t salt[di->output_size]; + int err = ccrng_generate(ccrng_seckey, di->output_size, salt); + require_noerr_action_quiet(err, out, SecError(errSecInternal, error, CFSTR("PSS salt gen fail (%zu bytes), err %d"), + di->output_size, err)); + err = ccrsa_emsa_pss_encode(di, di, di->output_size, salt, + CFDataGetLength(in1), CFDataGetBytePtr(in1), size * 8 - 1, s); + require_noerr_action_quiet(err, out, SecError(errSecParam, error, CFSTR("RSASSA-PSS incompatible algorithm for key size"))); + } else { + int err = ccrsa_emsa_pkcs1v15_encode(size, s, CFDataGetLength(in1), CFDataGetBytePtr(in1), di ? di->oid : NULL); + require_noerr_action_quiet(err, out, SecError(errSecParam, error, CFSTR("RSAsign wrong input data length"))); + } ccn_read_uint(ccn_nof_size(size), (cc_unit *)buffer, size, s); require_quiet(result = SecKeyRunAlgorithmAndCopyResult(context, data, NULL, error), out); CFAssignRetained(result, SecKeyRSACopyCCUnitToBigEndian(result, SecKeyGetBlockSize(context->key))); out:; }); + +out: + CFReleaseSafe(parameters); return result; } -#define seckey_ccoid_md5 ((unsigned char *)"\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05") - -#define PKCS1v15_EMSA_SIGN_ADAPTOR(name, oid) \ -static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigestPKCS1v15 ## name( \ +#define RSA_EMSA_SIGN_ADAPTOR(name, pss, di) \ +static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigest ## name( \ SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { \ - return SecKeyRSACopyPKCS1EMSASignature(context, in1, in2, error, oid); \ + return SecKeyRSACopyEMSASignature(context, in1, in2, error, pss, di); \ } -PKCS1v15_EMSA_SIGN_ADAPTOR(SHA1, ccoid_sha1) -PKCS1v15_EMSA_SIGN_ADAPTOR(SHA224, ccoid_sha224) -PKCS1v15_EMSA_SIGN_ADAPTOR(SHA256, ccoid_sha256) -PKCS1v15_EMSA_SIGN_ADAPTOR(SHA384, ccoid_sha384) -PKCS1v15_EMSA_SIGN_ADAPTOR(SHA512, ccoid_sha512) -PKCS1v15_EMSA_SIGN_ADAPTOR(Raw, NULL) -PKCS1v15_EMSA_SIGN_ADAPTOR(MD5, seckey_ccoid_md5) - -#undef PKCS1v15_EMSA_SIGN_ADAPTOR +RSA_EMSA_SIGN_ADAPTOR(PKCS1v15SHA1, false, ccsha1_di()) +RSA_EMSA_SIGN_ADAPTOR(PKCS1v15SHA224, false, ccsha224_di()) +RSA_EMSA_SIGN_ADAPTOR(PKCS1v15SHA256, false, ccsha256_di()) +RSA_EMSA_SIGN_ADAPTOR(PKCS1v15SHA384, false, ccsha384_di()) +RSA_EMSA_SIGN_ADAPTOR(PKCS1v15SHA512, false, ccsha512_di()) +RSA_EMSA_SIGN_ADAPTOR(PKCS1v15Raw, false, NULL) +RSA_EMSA_SIGN_ADAPTOR(PKCS1v15MD5, false, ccmd5_di()) +RSA_EMSA_SIGN_ADAPTOR(PSSSHA1, true, ccsha1_di()) +RSA_EMSA_SIGN_ADAPTOR(PSSSHA224, true, ccsha224_di()) +RSA_EMSA_SIGN_ADAPTOR(PSSSHA256, true, ccsha256_di()) +RSA_EMSA_SIGN_ADAPTOR(PSSSHA384, true, ccsha384_di()) +RSA_EMSA_SIGN_ADAPTOR(PSSSHA512, true, ccsha512_di()) + +#undef RSA_EMSA_SIGN_ADAPTOR static CFTypeRef SecKeyAlgorithmAdaptorCopyBigEndianToCCUnit(SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { @@ -367,15 +445,31 @@ static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPKCS1 }); \ } -PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA1, ccoid_sha1) -PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA224, ccoid_sha224) -PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA256, ccoid_sha256) -PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA384, ccoid_sha384) -PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA512, ccoid_sha512) +#define PSS_EMSA_VERIFY_ADAPTOR(name, di) \ +static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPSS ## name( \ + SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { \ + return SecKeyRSAVerifyAdaptorCopyResult(context, in2, error, ^Boolean(CFDataRef decrypted) { \ + return ccrsa_emsa_pss_decode(di, di, di->output_size, CFDataGetLength(in1), CFDataGetBytePtr(in1), \ + CFDataGetLength(decrypted) * 8 - 1, (uint8_t *)CFDataGetBytePtr(decrypted)) == 0; \ + }); \ +} + +PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA1, ccsha1_di()->oid) +PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA224, ccsha224_di()->oid) +PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA256, ccsha256_di()->oid) +PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA384, ccsha384_di()->oid) +PKCS1v15_EMSA_VERIFY_ADAPTOR(SHA512, ccsha512_di()->oid) PKCS1v15_EMSA_VERIFY_ADAPTOR(Raw, NULL) -PKCS1v15_EMSA_VERIFY_ADAPTOR(MD5, seckey_ccoid_md5) +PKCS1v15_EMSA_VERIFY_ADAPTOR(MD5, ccmd5_di()->oid) + +PSS_EMSA_VERIFY_ADAPTOR(SHA1, ccsha1_di()) +PSS_EMSA_VERIFY_ADAPTOR(SHA224, ccsha224_di()) +PSS_EMSA_VERIFY_ADAPTOR(SHA256, ccsha256_di()) +PSS_EMSA_VERIFY_ADAPTOR(SHA384, ccsha384_di()) +PSS_EMSA_VERIFY_ADAPTOR(SHA512, ccsha512_di()) #undef PKCS1v15_EMSA_VERIFY_ADAPTOR +#undef PSS_EMSA_VERIFY_ADAPTOR static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_EncryptDecrypt_RSAEncryptionRaw(SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { @@ -550,13 +644,13 @@ static CFIndex SecKeyGetCFIndexFromRef(CFTypeRef ref) { return result; } -typedef CFDataRef (*SecKeyECIESKeyExchangeCopyResult)(SecKeyOperationContext *context, SecKeyAlgorithm keyExchangeAlgorithm, bool encrypt, CFDataRef ephemeralPubKey, CFDataRef pubKey, CFErrorRef *error); +typedef CFDataRef (*SecKeyECIESKeyExchangeCopyResult)(SecKeyOperationContext *context, SecKeyAlgorithm keyExchangeAlgorithm, bool encrypt, CFDataRef ephemeralPubKey, CFDataRef pubKey, bool variableIV, CFErrorRef *error); typedef Boolean (*SecKeyECIESEncryptCopyResult)(CFDataRef keyExchangeResult, CFDataRef inData, CFMutableDataRef result, CFErrorRef *error); typedef CFDataRef SecKeyECIESDecryptCopyResult(CFDataRef keyExchangeResult, CFDataRef inData, CFErrorRef *error); static CFTypeRef SecKeyECIESCopyEncryptedData(SecKeyOperationContext *context, SecKeyAlgorithm keyExchangeAlgorithm, SecKeyECIESKeyExchangeCopyResult keyExchangeCopyResult, - SecKeyECIESEncryptCopyResult encryptCopyResult, + SecKeyECIESEncryptCopyResult encryptCopyResult, bool variableIV, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { CFDictionaryRef parameters = NULL; SecKeyRef ephemeralPrivateKey = NULL, ephemeralPublicKey = NULL; @@ -583,7 +677,7 @@ static CFTypeRef SecKeyECIESCopyEncryptedData(SecKeyOperationContext *context, S context->key = ephemeralPrivateKey; require_quiet(keyExchangeResult = keyExchangeCopyResult(context, keyExchangeAlgorithm, true, - ephemeralPubKeyData, pubKeyData, error), out); + ephemeralPubKeyData, pubKeyData, variableIV, error), out); if (context->mode == kSecKeyOperationModePerform) { // Encrypt input data using AES-GCM. ciphertext = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, ephemeralPubKeyData); @@ -607,7 +701,7 @@ out: static CFTypeRef SecKeyECIESCopyDecryptedData(SecKeyOperationContext *context, SecKeyAlgorithm keyExchangeAlgorithm, SecKeyECIESKeyExchangeCopyResult keyExchangeCopyResult, - SecKeyECIESDecryptCopyResult decryptCopyResult, + SecKeyECIESDecryptCopyResult decryptCopyResult, bool variableIV, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { CFTypeRef result = NULL; CFDictionaryRef parameters = NULL; @@ -638,7 +732,7 @@ static CFTypeRef SecKeyECIESCopyDecryptedData(SecKeyOperationContext *context, S // Perform keyExchange operation. require_quiet(keyExchangeResult = keyExchangeCopyResult(context, keyExchangeAlgorithm, false, - ephemeralPubKeyData, pubKeyData, error), out); + ephemeralPubKeyData, pubKeyData, variableIV, error), out); if (context->mode == kSecKeyOperationModePerform) { // Decrypt ciphertext using AES-GCM. ciphertext = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ciphertextBuffer, CFDataGetLength(in1) - (keySize * 2 + 1), @@ -662,7 +756,7 @@ static const CFIndex kSecKeyIESTagLength = 16; static const UInt8 kSecKeyIESIV[16] = { 0 }; static CFDataRef SecKeyECIESKeyExchangeKDFX963CopyResult(SecKeyOperationContext *context, SecKeyAlgorithm keyExchangeAlgorithm, - bool encrypt, CFDataRef ephemeralPubKey, CFDataRef pubKey, + bool encrypt, CFDataRef ephemeralPubKey, CFDataRef pubKey, bool variableIV, CFErrorRef *error) { CFDictionaryRef parameters = NULL; CFNumberRef keySizeRef = NULL; @@ -676,6 +770,10 @@ static CFDataRef SecKeyECIESKeyExchangeKDFX963CopyResult(SecKeyOperationContext CFIndex keySize = ((CFDataGetLength(pubKey) - 1) / 2) * 8; keySize = (keySize > 256) ? (256 / 8) : (128 / 8); + if (variableIV) { + keySize += sizeof(kSecKeyIESIV); + } + // Generate shared secret using KDF. keySizeRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &keySize); parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, @@ -685,6 +783,12 @@ static CFDataRef SecKeyECIESKeyExchangeKDFX963CopyResult(SecKeyOperationContext } result = SecKeyRunAlgorithmAndCopyResult(context, encrypt ? pubKey : ephemeralPubKey, parameters, error); + if (context->mode == kSecKeyOperationModePerform && !variableIV && result != NULL) { + // Append all-zero IV to the result. + CFMutableDataRef data = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, result); + CFDataAppendBytes(data, kSecKeyIESIV, sizeof(kSecKeyIESIV)); + CFAssignRetained(result, data); + } CFReleaseSafe(parameters); CFReleaseSafe(keySizeRef); return result; @@ -697,9 +801,11 @@ static Boolean SecKeyECIESEncryptAESGCMCopyResult(CFDataRef keyExchangeResult, C CFDataSetLength(result, prefix + CFDataGetLength(inData) + kSecKeyIESTagLength); UInt8 *resultBuffer = CFDataGetMutableBytePtr(result) + prefix; UInt8 *tagBuffer = resultBuffer + CFDataGetLength(inData); + CFIndex aesKeySize = CFDataGetLength(keyExchangeResult) - sizeof(kSecKeyIESIV); + const UInt8 *ivBuffer = CFDataGetBytePtr(keyExchangeResult) + aesKeySize; require_action_quiet(ccgcm_one_shot(ccaes_gcm_encrypt_mode(), - CFDataGetLength(keyExchangeResult), CFDataGetBytePtr(keyExchangeResult), - sizeof(kSecKeyIESIV), kSecKeyIESIV, + aesKeySize, CFDataGetBytePtr(keyExchangeResult), + sizeof(kSecKeyIESIV), ivBuffer, 0, NULL, CFDataGetLength(inData), CFDataGetBytePtr(inData), resultBuffer, kSecKeyIESTagLength, tagBuffer) == 0, out, @@ -715,9 +821,11 @@ static CFDataRef SecKeyECIESDecryptAESGCMCopyResult(CFDataRef keyExchangeResult, CFMutableDataRef tag = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), kSecKeyIESTagLength); CFDataGetBytes(inData, CFRangeMake(CFDataGetLength(inData) - kSecKeyIESTagLength, kSecKeyIESTagLength), CFDataGetMutableBytePtr(tag)); + CFIndex aesKeySize = CFDataGetLength(keyExchangeResult) - sizeof(kSecKeyIESIV); + const UInt8 *ivBuffer = CFDataGetBytePtr(keyExchangeResult) + aesKeySize; require_action_quiet(ccgcm_one_shot(ccaes_gcm_decrypt_mode(), - CFDataGetLength(keyExchangeResult), CFDataGetBytePtr(keyExchangeResult), - sizeof(kSecKeyIESIV), kSecKeyIESIV, + aesKeySize, CFDataGetBytePtr(keyExchangeResult), + sizeof(kSecKeyIESIV), ivBuffer, 0, NULL, CFDataGetLength(plaintext), CFDataGetBytePtr(inData), CFDataGetMutableBytePtr(plaintext), kSecKeyIESTagLength, CFDataGetMutableBytePtr(tag)) == 0, out, @@ -729,33 +837,42 @@ out: return result; } -#define ECIES_X963_ADAPTOR(hashname, cofactor) \ -static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIES ## cofactor ## X963 ## hashname( \ +#define ECIES_X963_ADAPTOR(hashname, cofactor, namepart, variableIV) \ +static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIES ## cofactor ## namepart ## hashname( \ SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { \ return SecKeyECIESCopyEncryptedData(context, kSecKeyAlgorithmECDHKeyExchange ## cofactor ## X963 ## hashname, \ - SecKeyECIESKeyExchangeKDFX963CopyResult, SecKeyECIESEncryptAESGCMCopyResult, in1, in2, error); \ + SecKeyECIESKeyExchangeKDFX963CopyResult, SecKeyECIESEncryptAESGCMCopyResult, variableIV, in1, in2, error); \ } \ -static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIES ## cofactor ## X963 ## hashname( \ +static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIES ## cofactor ## namepart ## hashname( \ SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { \ return SecKeyECIESCopyDecryptedData(context, kSecKeyAlgorithmECDHKeyExchange ## cofactor ## X963 ## hashname, \ - SecKeyECIESKeyExchangeKDFX963CopyResult, SecKeyECIESDecryptAESGCMCopyResult, in1, in2, error); \ + SecKeyECIESKeyExchangeKDFX963CopyResult, SecKeyECIESDecryptAESGCMCopyResult, variableIV, in1, in2, error); \ } -ECIES_X963_ADAPTOR(SHA1, Standard) -ECIES_X963_ADAPTOR(SHA224, Standard) -ECIES_X963_ADAPTOR(SHA256, Standard) -ECIES_X963_ADAPTOR(SHA384, Standard) -ECIES_X963_ADAPTOR(SHA512, Standard) -ECIES_X963_ADAPTOR(SHA1, Cofactor) -ECIES_X963_ADAPTOR(SHA224, Cofactor) -ECIES_X963_ADAPTOR(SHA256, Cofactor) -ECIES_X963_ADAPTOR(SHA384, Cofactor) -ECIES_X963_ADAPTOR(SHA512, Cofactor) +ECIES_X963_ADAPTOR(SHA1, Standard, X963, false) +ECIES_X963_ADAPTOR(SHA224, Standard, X963, false) +ECIES_X963_ADAPTOR(SHA256, Standard, X963, false) +ECIES_X963_ADAPTOR(SHA384, Standard, X963, false) +ECIES_X963_ADAPTOR(SHA512, Standard, X963, false) +ECIES_X963_ADAPTOR(SHA1, Cofactor, X963, false) +ECIES_X963_ADAPTOR(SHA224, Cofactor, X963, false) +ECIES_X963_ADAPTOR(SHA256, Cofactor, X963, false) +ECIES_X963_ADAPTOR(SHA384, Cofactor, X963, false) +ECIES_X963_ADAPTOR(SHA512, Cofactor, X963, false) + +ECIES_X963_ADAPTOR(SHA224, Standard, VariableIVX963, true) +ECIES_X963_ADAPTOR(SHA256, Standard, VariableIVX963, true) +ECIES_X963_ADAPTOR(SHA384, Standard, VariableIVX963, true) +ECIES_X963_ADAPTOR(SHA512, Standard, VariableIVX963, true) +ECIES_X963_ADAPTOR(SHA224, Cofactor, VariableIVX963, true) +ECIES_X963_ADAPTOR(SHA256, Cofactor, VariableIVX963, true) +ECIES_X963_ADAPTOR(SHA384, Cofactor, VariableIVX963, true) +ECIES_X963_ADAPTOR(SHA512, Cofactor, VariableIVX963, true) #undef ECIES_X963_ADAPTOR static CFDataRef SecKeyECIESKeyExchangeSHA2562PubKeysCopyResult(SecKeyOperationContext *context, SecKeyAlgorithm keyExchangeAlgorithm, - bool encrypt, CFDataRef ephemeralPubKey, CFDataRef pubKey, + bool encrypt, CFDataRef ephemeralPubKey, CFDataRef pubKey, bool variableIV, CFErrorRef *error) { CFArrayAppendValue(context->algorithm, keyExchangeAlgorithm); context->operation = kSecKeyOperationTypeKeyExchange; @@ -786,7 +903,7 @@ static CFTypeRef SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIES_Standard_SHA256_ SecKeyOperationContext *context, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { return SecKeyECIESCopyDecryptedData(context, kSecKeyAlgorithmECDHKeyExchangeStandard, SecKeyECIESKeyExchangeSHA2562PubKeysCopyResult, - SecKeyECIESDecryptAESCBCCopyResult, + SecKeyECIESDecryptAESCBCCopyResult, false, in1, in2, error); } @@ -932,6 +1049,12 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5, + kSecKeyAlgorithmRSASignatureDigestPSSSHA1, + kSecKeyAlgorithmRSASignatureDigestPSSSHA224, + kSecKeyAlgorithmRSASignatureDigestPSSSHA256, + kSecKeyAlgorithmRSASignatureDigestPSSSHA384, + kSecKeyAlgorithmRSASignatureDigestPSSSHA512, + kSecKeyAlgorithmRSASignatureRaw, kSecKeyAlgorithmRSASignatureRawCCUnit, @@ -942,6 +1065,12 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512, kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5, + kSecKeyAlgorithmRSASignatureMessagePSSSHA1, + kSecKeyAlgorithmRSASignatureMessagePSSSHA224, + kSecKeyAlgorithmRSASignatureMessagePSSSHA256, + kSecKeyAlgorithmRSASignatureMessagePSSSHA384, + kSecKeyAlgorithmRSASignatureMessagePSSSHA512, + kSecKeyAlgorithmECDSASignatureMessageX962SHA1, kSecKeyAlgorithmECDSASignatureMessageX962SHA224, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, @@ -963,6 +1092,12 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigestPKCS1v15Raw, SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigestPKCS1v15MD5, + SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigestPSSSHA1, + SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigestPSSSHA224, + SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigestPSSSHA256, + SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigestPSSSHA384, + SecKeyAlgorithmAdaptorCopyResult_Sign_RSASignatureDigestPSSSHA512, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureRaw, SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureRawCCUnit, @@ -973,6 +1108,12 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePKCS1v15SHA512, SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePKCS1v15MD5, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA1, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA224, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA256, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA384, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA512, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureMessageX962SHA1, SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureMessageX962SHA224, SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureMessageX962SHA256, @@ -1000,6 +1141,12 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5, + kSecKeyAlgorithmRSASignatureDigestPSSSHA1, + kSecKeyAlgorithmRSASignatureDigestPSSSHA224, + kSecKeyAlgorithmRSASignatureDigestPSSSHA256, + kSecKeyAlgorithmRSASignatureDigestPSSSHA384, + kSecKeyAlgorithmRSASignatureDigestPSSSHA512, + kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256, @@ -1007,6 +1154,12 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512, kSecKeyAlgorithmRSASignatureMessagePKCS1v15MD5, + kSecKeyAlgorithmRSASignatureMessagePSSSHA1, + kSecKeyAlgorithmRSASignatureMessagePSSSHA224, + kSecKeyAlgorithmRSASignatureMessagePSSSHA256, + kSecKeyAlgorithmRSASignatureMessagePSSSHA384, + kSecKeyAlgorithmRSASignatureMessagePSSSHA512, + kSecKeyAlgorithmECDSASignatureMessageX962SHA1, kSecKeyAlgorithmECDSASignatureMessageX962SHA224, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, @@ -1030,6 +1183,12 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPKCS1v15Raw, SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPKCS1v15MD5, + SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPSSSHA1, + SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPSSSHA224, + SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPSSSHA256, + SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPSSSHA384, + SecKeyAlgorithmAdaptorCopyResult_Verify_RSASignatureDigestPSSSHA512, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePKCS1v15SHA1, SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePKCS1v15SHA224, SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePKCS1v15SHA256, @@ -1037,6 +1196,12 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePKCS1v15SHA512, SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePKCS1v15MD5, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA1, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA224, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA256, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA384, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_RSASignatureMessagePSSSHA512, + SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureMessageX962SHA1, SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureMessageX962SHA224, SecKeyAlgorithmAdaptorCopyResult_SignVerify_ECDSASignatureMessageX962SHA256, @@ -1081,6 +1246,16 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM, + + kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM, + kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM, + kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM, + kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM, + + kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM, + kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM, + kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM, + kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM, }; const void *encryptValues[] = { SecKeyAlgorithmAdaptorCopyResult_EncryptDecrypt_RSAEncryptionRaw, @@ -1110,6 +1285,16 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESCofactorX963SHA256, SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESCofactorX963SHA384, SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESCofactorX963SHA512, + + SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESStandardVariableIVX963SHA224, + SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESStandardVariableIVX963SHA256, + SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESStandardVariableIVX963SHA384, + SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESStandardVariableIVX963SHA512, + + SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESCofactorVariableIVX963SHA224, + SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESCofactorVariableIVX963SHA256, + SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESCofactorVariableIVX963SHA384, + SecKeyAlgorithmAdaptorCopyResult_Encrypt_ECIESCofactorVariableIVX963SHA512, }; check_compile_time(array_size(encryptKeys) == array_size(encryptValues)); adaptors[kSecKeyOperationTypeEncrypt] = CFDictionaryCreate(kCFAllocatorDefault, encryptKeys, encryptValues, @@ -1144,6 +1329,16 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM, + kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM, + kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM, + kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM, + kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM, + + kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM, + kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM, + kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM, + kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM, + kSecKeyAlgorithmECIESEncryptionAKSSmartCard, }; const void *decryptValues[] = { @@ -1175,6 +1370,16 @@ SecKeyAlgorithmAdaptor SecKeyGetAlgorithmAdaptor(SecKeyOperationType operation, SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESCofactorX963SHA384, SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESCofactorX963SHA512, + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESStandardVariableIVX963SHA224, + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESStandardVariableIVX963SHA256, + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESStandardVariableIVX963SHA384, + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESStandardVariableIVX963SHA512, + + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESCofactorVariableIVX963SHA224, + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESCofactorVariableIVX963SHA256, + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESCofactorVariableIVX963SHA384, + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIESCofactorVariableIVX963SHA512, + SecKeyAlgorithmAdaptorCopyResult_Decrypt_ECIES_Standard_SHA256_2PubKeys, }; check_compile_time(array_size(decryptKeys) == array_size(decryptValues)); diff --git a/OSX/sec/Security/SecOTRDHKey.c b/OSX/sec/Security/SecOTRDHKey.c index 5bb75172..b4440141 100644 --- a/OSX/sec/Security/SecOTRDHKey.c +++ b/OSX/sec/Security/SecOTRDHKey.c @@ -70,9 +70,9 @@ static size_t AppendECPublicKeyAsDATA(CFMutableDataRef data, ccec_pub_ctx_t publ static size_t AppendECCompactPublicKey(CFMutableDataRef data, ccec_pub_ctx_t public_key) { - size_t size = ccec_compact_export_size(false, public_key._full); + size_t size = ccec_compact_export_size(false, public_key); - ccec_compact_export(false, CFDataIncreaseLengthAndGetMutableBytes(data, (CFIndex)size), public_key._full); + ccec_compact_export(false, CFDataIncreaseLengthAndGetMutableBytes(data, (CFIndex)size), (ccec_full_ctx_t)public_key); return size; } @@ -104,7 +104,7 @@ static CFStringRef SecOTRFullDHKeyCopyFormatDescription(CFTypeRef cf, CFDictiona SecOTRFullDHKeyRef fullDHKey = (SecOTRFullDHKeyRef)cf; __block CFStringRef description = NULL; - withXandY(fullDHKey->_key, ^(CFStringRef x, CFStringRef y) { + withXandY(ccec_ctx_pub(fullDHKey->_key), ^(CFStringRef x, CFStringRef y) { BufferPerformWithHexString(fullDHKey->keyHash, sizeof(fullDHKey->keyHash), ^(CFStringRef dataString) { description = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR(""), fullDHKey, x, y, dataString); }); @@ -130,7 +130,7 @@ static void SecOTRFullDHKeyDestroy(CFTypeRef cf) static inline void SecOTRFDHKUpdateHash(SecOTRFullDHKeyRef fullKey) { - GenerateHashForKey(fullKey->_key, fullKey->keyHash); + GenerateHashForKey(ccec_ctx_pub(fullKey->_key), fullKey->keyHash); } SecOTRFullDHKeyRef SecOTRFullDHKCreate(CFAllocatorRef allocator) @@ -152,7 +152,7 @@ SecOTRFullDHKeyRef SecOTRFullDHKCreateFromBytes(CFAllocatorRef allocator, const require_noerr(ReadLong(bytes, size, &publicKeySize), fail); require(publicKeySize <= *size, fail); - require_noerr(ccec_import_pub(ccec_cp_256(), publicKeySize, *bytes, newFDHK->_key), fail); + require_noerr(ccec_import_pub(ccec_cp_256(), publicKeySize, *bytes, ccec_ctx_pub(newFDHK->_key)), fail); *size -= publicKeySize; *bytes += publicKeySize; @@ -184,20 +184,20 @@ void SecFDHKNewKey(SecOTRFullDHKeyRef fullKey) void SecFDHKAppendSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef appendTo) { - AppendECPublicKeyAsDATA(appendTo, fullKey->_key); + AppendECPublicKeyAsDATA(appendTo, ccec_ctx_pub(fullKey->_key)); AppendMPI(appendTo, ccec_ctx_n(fullKey->_key), ccec_ctx_k(fullKey->_key)); } void SecFDHKAppendPublicSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef appendTo) { if(ccec_ctx_bitlen(fullKey->_key) != kECKeySize) return; - AppendECPublicKeyAsDATA(appendTo, fullKey->_key); + AppendECPublicKeyAsDATA(appendTo, ccec_ctx_pub(fullKey->_key)); } void SecFDHKAppendCompactPublicSerialization(SecOTRFullDHKeyRef fullKey, CFMutableDataRef appendTo) { if(ccec_ctx_bitlen(fullKey->_key) != kECKeySize) return; - AppendECCompactPublicKey(appendTo, fullKey->_key); + AppendECCompactPublicKey(appendTo, ccec_ctx_pub(fullKey->_key)); } @@ -254,16 +254,15 @@ static inline void SecOTRPDHKUpdateHash(SecOTRPublicDHKeyRef pubKey) static void ccec_copy_public(ccec_pub_ctx_t source, ccec_pub_ctx_t dest) { - ccec_ctx_cp(dest) = ccec_ctx_cp(source); - // TODO: +1?! - ccn_set(3*ccec_ctx_n(source), (cc_unit*) ccec_ctx_point(dest)._p, (cc_unit*) ccec_ctx_point(source)._p); + cc_size sourceKeyN = ccec_ctx_n(source); + memcpy(dest, source, ccec_pub_ctx_size(ccn_sizeof_n(sourceKeyN))); } SecOTRPublicDHKeyRef SecOTRPublicDHKCreateFromFullKey(CFAllocatorRef allocator, SecOTRFullDHKeyRef full) { SecOTRPublicDHKeyRef newPDHK = CFTypeAllocate(SecOTRPublicDHKey, struct _SecOTRPublicDHKey, allocator); - ccec_copy_public(full->_key, newPDHK->_key); + ccec_copy_public(ccec_ctx_pub(full->_key), newPDHK->_key); memcpy(newPDHK->keyHash, full->keyHash, CCSHA1_OUTPUT_SIZE); return newPDHK; @@ -376,7 +375,7 @@ static int ccec_cmp(ccec_pub_ctx_t l, ccec_pub_ctx_t r) bool SecDHKIsGreater(SecOTRFullDHKeyRef myKey, SecOTRPublicDHKeyRef theirKey) { - return ccec_cmp(myKey->_key, theirKey->_key) > 0; + return ccec_cmp(ccec_ctx_pub(myKey->_key), theirKey->_key) > 0; } static void DeriveKeys(CFDataRef dataToHash, diff --git a/OSX/sec/Security/SecOTRMath.c b/OSX/sec/Security/SecOTRMath.c index 32323637..2106016c 100644 --- a/OSX/sec/Security/SecOTRMath.c +++ b/OSX/sec/Security/SecOTRMath.c @@ -39,17 +39,6 @@ #include -void OTRExponentiate(cc_unit* res, const cc_unit* base, const cc_unit* exponent) -{ - ccdh_const_gp_t gp = ccdh_gp_rfc3526group05(); - cczp_power(gp.zp, res, base, exponent); -} - -void OTRGroupExponentiate(cc_unit* res, const cc_unit* exponent) -{ - OTRExponentiate(res, ccdh_gp_g(ccdh_gp_rfc3526group05()) , exponent); -} - // // Random Number Generation // diff --git a/OSX/sec/Security/SecOTRSession.c b/OSX/sec/Security/SecOTRSession.c index a3e5e482..07244b17 100644 --- a/OSX/sec/Security/SecOTRSession.c +++ b/OSX/sec/Security/SecOTRSession.c @@ -1065,7 +1065,8 @@ static OSStatus SecOTRVerifyAndExposeRaw_locked(SecOTRSessionRef session, SecOTRPublicDHKeyRef newKey = NULL; const uint8_t* bytes; size_t size; - + SecOTRFullDHKeyRef myKeyForMessage = NULL; + SecOTRPublicDHKeyRef theirKeyForMessage = NULL; bytes = CFDataGetBytePtr(decodedBytes); size = CFDataGetLength(decodedBytes); @@ -1098,8 +1099,8 @@ static OSStatus SecOTRVerifyAndExposeRaw_locked(SecOTRSessionRef session, uint8_t *macKey; uint64_t *theirCounter; - SecOTRFullDHKeyRef myKeyForMessage = (myID == session->_keyID) ? session->_myKey : session->_myNextKey; - SecOTRPublicDHKeyRef theirKeyForMessage = (theirID == session->_theirKeyID) ? session->_theirKey : session->_theirPreviousKey; + myKeyForMessage = (myID == session->_keyID) ? session->_myKey : session->_myNextKey; + theirKeyForMessage = (theirID == session->_theirKeyID) ? session->_theirKey : session->_theirPreviousKey; SecOTRSFindKeysForMessage(session, myKeyForMessage, theirKeyForMessage, false, &messageKey, &macKey, &theirCounter); @@ -1155,6 +1156,19 @@ static OSStatus SecOTRVerifyAndExposeRaw_locked(SecOTRSessionRef session, SecOTRSPrecalculateNextKeysInternal(session); fail: + if(result != errSecSuccess){ + CFDataPerformWithHexString(decodedBytes, ^(CFStringRef decodedBytesString) { + SecOTRPublicIdentityRef myPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, session->_me, NULL); + SecOTRPIPerformWithSerializationString(myPublicID, ^(CFStringRef myIDString) { + SecOTRPIPerformWithSerializationString(session->_them, ^(CFStringRef theirIDString) { + secnotice("OTR","session[%p] failed to decrypt, session: %@, mk: %@, mpk: %@, tpk: %@, tk: %@, chose tktu: %@", session, session, + session->_myKey, session->_myNextKey, session->_theirPreviousKey, session->_theirKey, theirKeyForMessage); + secnotice("OTR","session[%p] failed to decrypt, mktu: %@, mpi: %@, tpi: %@, m: %@", session, myKeyForMessage, myIDString, theirIDString, decodedBytesString); + }); + }); + CFReleaseNull(myPublicID); + }); + } CFReleaseNull(newKey); return result; } @@ -1278,14 +1292,19 @@ static OSStatus SecOTRVerifyAndExposeRawCompact_locked(SecOTRSessionRef session, SecOTRSPrecalculateNextKeysInternal(session); fail: -#if DEBUG if(result != errSecSuccess){ CFDataPerformWithHexString(decodedBytes, ^(CFStringRef decodedBytesString) { - secdebug("OTR","session[%p] failed to decrypt, session: %@, mk: %@, mpk: %@, tpk: %@, tk: %@, chose tktu: %@, mktu: %@, m: %@, tP: %@, tb: %hhx", session, session, - session->_myKey, session->_myNextKey, session->_theirPreviousKey, session->_theirKey, theirKeyForMessage, myKeyForMessage, decodedBytesString, theirProposal, type_byte); + SecOTRPublicIdentityRef myPublicID = SecOTRPublicIdentityCopyFromPrivate(kCFAllocatorDefault, session->_me, NULL); + SecOTRPIPerformWithSerializationString(myPublicID, ^(CFStringRef myIDString) { + SecOTRPIPerformWithSerializationString(session->_them, ^(CFStringRef theirIDString) { + secnotice("OTR","session[%p] failed to decrypt, session: %@, mk: %@, mpk: %@, tpk: %@, tk: %@, chose tktu: %@", session, session, + session->_myKey, session->_myNextKey, session->_theirPreviousKey, session->_theirKey, theirKeyForMessage); + secnotice("OTR","session[%p] failed to decrypt, mktu: %@, mpi: %@, tpi: %@, m: %@, tP: %@, tb: %hhx", session, myKeyForMessage, myIDString, theirIDString, decodedBytesString, theirProposal, type_byte); + }); + }); + CFReleaseNull(myPublicID); }); } -#endif CFReleaseNull(theirProposal); return result; } @@ -1397,3 +1416,4 @@ bool SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPack }); return result; } + diff --git a/OSX/sec/Security/SecOTRSession.h b/OSX/sec/Security/SecOTRSession.h index 0814e2b9..652a8000 100644 --- a/OSX/sec/Security/SecOTRSession.h +++ b/OSX/sec/Security/SecOTRSession.h @@ -130,6 +130,7 @@ const char *SecOTRPacketTypeString(CFDataRef message); CFDataRef SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error); bool SecOTRSessionProcessPacketRemote(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef *error); +bool SecOTRSessionIsSessionInAwaitingState(SecOTRSessionRef session); __END_DECLS diff --git a/OSX/sec/Security/SecOTRSessionAKE.c b/OSX/sec/Security/SecOTRSessionAKE.c index 55ed9c61..5c1f1107 100644 --- a/OSX/sec/Security/SecOTRSessionAKE.c +++ b/OSX/sec/Security/SecOTRSessionAKE.c @@ -64,6 +64,25 @@ static void SecOTRInitMyDHKeys(SecOTRSessionRef session) secnotice("otr", "%@ Reinitializing DH Keys, first: %@", session, session->_myKey); } +bool SecOTRSessionIsSessionInAwaitingState(SecOTRSessionRef session) +{ + bool isInAwaitingState = false; + SecOTRAuthState currentCoderState = session->_state; + switch (currentCoderState){ + case kIdle: + case kAwaitingDHKey: + case kAwaitingSignature: + case kAwaitingRevealSignature: + isInAwaitingState = true; + break; + case kDone: + break; + default: + secnotice("otrtimer", "unknown otr auth state"); + } + return isInAwaitingState; +} + OSStatus SecOTRSAppendStartPacket(SecOTRSessionRef session, CFMutableDataRef appendPacket) { __block OSStatus result = errSecSuccess; @@ -204,7 +223,7 @@ static OSStatus SecOTRSProcessDHMessage(SecOTRSessionRef session, result = errSecSuccess; break; } // Else intentionally fall through to idle - messageMessage = CFSTR("Our GX is bigger, resending DH"); + messageMessage = CFSTR("Our GX is smaller, sending DHKey"); case kAwaitingSignature: case kIdle: case kDone: diff --git a/OSX/sec/Security/SecOTRUtils.c b/OSX/sec/Security/SecOTRUtils.c index 7b18c583..56937405 100644 --- a/OSX/sec/Security/SecOTRUtils.c +++ b/OSX/sec/Security/SecOTRUtils.c @@ -26,6 +26,7 @@ #include "SecOTRIdentityPriv.h" #include "SecOTRSessionPriv.h" #include +#include #include #include @@ -183,7 +184,7 @@ SecKeyRef CreateECPublicKeyFrom(CFAllocatorRef allocator, const uint8_t** data, CFDataRef SecOTRCopyIncomingBytes(CFDataRef incomingMessage) { - CFDataRef result = NULL; + __block CFDataRef result = NULL; CFDataRef header = CFStringCreateExternalRepresentation(kCFAllocatorDefault, CFSTR("?OTR:"), kCFStringEncodingUTF8, '?'); CFRange headerLoc = CFDataFind(incomingMessage, header, CFRangeMake(0, CFDataGetLength(header)), 0); @@ -195,10 +196,14 @@ CFDataRef SecOTRCopyIncomingBytes(CFDataRef incomingMessage) CFRange footerLoc = CFDataFind(incomingMessage, footer, CFRangeMake(0, CFDataGetLength(incomingMessage)), 0); CFDataRef bodyData = CFDataCreateReferenceFromRange(kCFAllocatorDefault, incomingMessage, CFRangeMake(headerLoc.length, footerLoc.location - headerLoc.length)); - size_t size = SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), NULL, 0); - uint8_t decodedByteArray[size]; - SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), decodedByteArray, size); - result = CFDataCreate(kCFAllocatorDefault, decodedByteArray, size); + + size_t expectedSize = SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), NULL, 0); + PerformWithBuffer(expectedSize, ^(size_t size, uint8_t *decodedByteArray) { + size_t usedSize = SecBase64Decode((char*)CFDataGetBytePtr(bodyData), CFDataGetLength(bodyData), decodedByteArray, size); + if (usedSize > 0 && usedSize <= size ) { + result = CFDataCreate(kCFAllocatorDefault, decodedByteArray, usedSize); + } + }); CFRelease(bodyData); CFRelease(footer); diff --git a/OSX/sec/Security/SecPasswordGenerate.c b/OSX/sec/Security/SecPasswordGenerate.c index 5a99e0cb..4d4e87d9 100644 --- a/OSX/sec/Security/SecPasswordGenerate.c +++ b/OSX/sec/Security/SecPasswordGenerate.c @@ -1689,20 +1689,32 @@ CFDictionaryRef SecPasswordCopyDefaultPasswordLength(SecPasswordType type, CFErr bool SecPasswordValidatePasswordFormat(SecPasswordType type, CFStringRef password, CFErrorRef *error) { - CFIndex tupleLengthInt = 0, numOfTuplesInt = 0, checkSumChars = 3; + CFIndex tupleLengthInt = 0, numOfTuplesInt = 0, checkSumChars = 0; CFStringRef checksum = NULL, madeChecksum = NULL, passwordNoChecksum = NULL; CFMutableStringRef randomChars = NULL; CFStringRef allowedChars = NULL; bool res = false; - if (type != kSecPasswordTypeiCloudRecoveryKey) { - return false; + switch (type) { + case kSecPasswordTypeiCloudRecoveryKey: + tupleLengthInt = 4; + numOfTuplesInt = 7; + checkSumChars = 2; + allowedChars = defaultiCloudCharacters; + break; + case kSecPasswordTypeiCloudRecovery: + tupleLengthInt = 4; + numOfTuplesInt = 6; + break; + case(kSecPasswordTypePIN): + tupleLengthInt = 4; + numOfTuplesInt = 1; + break; + default: + SecError(errSecBadReq, error, CFSTR("Password type does not exist.")); + return false; } - tupleLengthInt = 4; - numOfTuplesInt = 7; - checkSumChars = 2; - allowedChars = defaultiCloudCharacters; if (numOfTuplesInt < 1) return false; @@ -1734,24 +1746,26 @@ SecPasswordValidatePasswordFormat(SecPasswordType type, CFStringRef password, CF CFReleaseNull(substr); } - /* - * Pull apart and password and checksum - */ + if (checkSumChars) { + /* + * Pull apart and password and checksum + */ - checksum = CFStringCreateWithSubstring(SecCFAllocatorZeroize(), randomChars, CFRangeMake((numOfTuplesInt * tupleLengthInt) - checkSumChars, checkSumChars)); - require(checksum, out); + checksum = CFStringCreateWithSubstring(SecCFAllocatorZeroize(), randomChars, CFRangeMake((numOfTuplesInt * tupleLengthInt) - checkSumChars, checkSumChars)); + require(checksum, out); - passwordNoChecksum = CFStringCreateWithSubstring(SecCFAllocatorZeroize(), randomChars, CFRangeMake(0, (numOfTuplesInt * tupleLengthInt) - checkSumChars)); - require(passwordNoChecksum, out); + passwordNoChecksum = CFStringCreateWithSubstring(SecCFAllocatorZeroize(), randomChars, CFRangeMake(0, (numOfTuplesInt * tupleLengthInt) - checkSumChars)); + require(passwordNoChecksum, out); - /* - * Validate checksum - */ + /* + * Validate checksum + */ - madeChecksum = CreateChecksum(type, passwordNoChecksum, checkSumChars, allowedChars); - require(madeChecksum, out); + madeChecksum = CreateChecksum(type, passwordNoChecksum, checkSumChars, allowedChars); + require(madeChecksum, out); - require(CFEqual(madeChecksum, checksum), out); + require(CFEqual(madeChecksum, checksum), out); + } res = true; out: diff --git a/OSX/sec/Security/SecPolicy.c b/OSX/sec/Security/SecPolicy.c index f8779042..56eb9426 100644 --- a/OSX/sec/Security/SecPolicy.c +++ b/OSX/sec/Security/SecPolicy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2007-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -176,6 +176,10 @@ SEC_CONST_DECL (kSecPolicyCheckBlackListedKey, "BlackListedKey"); SEC_CONST_DECL (kSecPolicyCheckUsageConstraints, "UsageConstraints"); SEC_CONST_DECL (kSecPolicyCheckSystemTrustedWeakHash, "SystemTrustedWeakHash"); +SEC_CONST_DECL (kSecPolicyCheckSystemTrustedWeakKey, "SystemTrustedWeakKey"); + +/* Binary requires pinning. */ +SEC_CONST_DECL (kSecPolicyCheckPinningRequired, "PinningRequired"); /******************************************************** ******************* Feature toggles ******************** @@ -268,6 +272,13 @@ SEC_CONST_DECL (kSecPolicyAppleSecureIOStaticAsset, "1.2.840.113635.100.1.75"); SEC_CONST_DECL (kSecPolicyAppleWarsaw, "1.2.840.113635.100.1.76"); SEC_CONST_DECL (kSecPolicyAppleiCloudSetupServerAuth, "1.2.840.113635.100.1.77"); SEC_CONST_DECL (kSecPolicyAppleiCloudSetupCompatibilityServerAuth, "1.2.840.113635.100.1.78"); +SEC_CONST_DECL (kSecPolicyAppleAppTransportSecurity, "1.2.840.113635.100.1.80"); +SEC_CONST_DECL (kSecPolicyAppleMacOSProfileApplicationSigning, "1.2.840.113635.100.1.81"); +SEC_CONST_DECL (kSecPolicyAppleMobileSoftwareUpdate, "1.2.840.113635.100.1.82"); +SEC_CONST_DECL (kSecPolicyAppleMobileAssetDevelopment, "1.2.840.113635.100.1.83"); +SEC_CONST_DECL (kSecPolicyAppleBasicAttestationSystem, "1.2.840.113635.100.1.84"); +SEC_CONST_DECL (kSecPolicyAppleBasicAttestationUser, "1.2.840.113635.100.1.85"); +SEC_CONST_DECL (kSecPolicyAppleiPhoneVPNApplicationSigning, "1.2.840.113635.100.1.86"); SEC_CONST_DECL (kSecPolicyOid, "SecPolicyOid"); SEC_CONST_DECL (kSecPolicyName, "SecPolicyName"); @@ -290,7 +301,7 @@ SEC_CONST_DECL (kSecPolicyKU_CRLSign, "CE_KU_CRLSign"); SEC_CONST_DECL (kSecPolicyKU_EncipherOnly, "CE_KU_EncipherOnly"); SEC_CONST_DECL (kSecPolicyKU_DecipherOnly, "CE_KU_DecipherOnly"); -/* Private policy names */ +/* Internal policy names */ static CFStringRef kSecPolicyNameBasicX509 = CFSTR("basicX509"); static CFStringRef kSecPolicyNameSSLServer = CFSTR("sslServer"); static CFStringRef kSecPolicyNameSSLClient = CFSTR("sslClient"); @@ -339,10 +350,6 @@ static CFStringRef kSecPolicyNameAppleIDValidationRecordSigningPolicy = CFSTR("A static CFStringRef kSecPolicyNameApplePayIssuerEncryption = CFSTR("ApplePayIssuerEncryption"); static CFStringRef kSecPolicyNameAppleOSXProvisioningProfileSigning = CFSTR("AppleOSXProvisioningProfileSigning"); static CFStringRef kSecPolicyNameAppleATVVPNProfileSigning = CFSTR("AppleATVVPNProfileSigning"); -static CFStringRef kSecPolicyNameAppleAST2Service = CFSTR("AST2"); -static CFStringRef kSecPolicyNameAppleEscrowProxyService = CFSTR("Escrow"); -static CFStringRef kSecPolicyNameAppleFMiPService = CFSTR("FMiP"); -static CFStringRef kSecPolicyNameAppleHomeKitServerAuth = CFSTR("HomeKit"); static CFStringRef kSecPolicyNameAppleExternalDeveloper = CFSTR("Developer"); static CFStringRef kSecPolicyNameAppleSoftwareSigning = CFSTR("SoftwareSigning"); static CFStringRef kSecPolicyNameAppleSMPEncryption = CFSTR("AppleSMPEncryption"); @@ -351,155 +358,29 @@ static CFStringRef kSecPolicyNameApplePPQSigning = CFSTR("ApplePPQSigning"); static CFStringRef kSecPolicyNameAppleTestPPQSigning = CFSTR("AppleTestPPQSigning"); static CFStringRef kSecPolicyNameAppleLegacyPushService = CFSTR("AppleLegacyPushService"); static CFStringRef kSecPolicyNameAppleSSLService = CFSTR("AppleSSLService"); -static CFStringRef kSecPolicyNameApplePushService = CFSTR("APN"); -static CFStringRef kSecPolicyNameAppleIDSServiceContext = CFSTR("IDS"); -static CFStringRef kSecPolicyNameAppleGSService = CFSTR("GS"); -static CFStringRef kSecPolicyNameAppleMMCSService = CFSTR("MMCS"); -static CFStringRef kSecPolicyNameApplePPQService = CFSTR("PPQ"); +static CFStringRef kSecPolicyNameAppleIDSBag = CFSTR("IDSBag"); static CFStringRef kSecPolicyNameAppleUniqueDeviceCertificate = CFSTR("UCRT"); static CFStringRef kSecPolicyNameAppleSecureIOStaticAsset = CFSTR("SecureIOStaticAsset"); static CFStringRef kSecPolicyNameAppleWarsaw = CFSTR("Warsaw"); -static CFStringRef kSecPolicyNameAppleiCloudSetupService = CFSTR("iCloudSetup"); - - -/* Policies will now change to multiple categories of checks. - - IDEA Store partial valid policy tree in each chain? Result tree pruning might make this not feasible unless you can pretend to prune the tree without actually deleting nodes and somehow still have shable nodes with parent chains (this assumes that chains will be built as cached things from the root down), and we can build something equivalent to rfc5280 in a tree of certs. So we need to maintain a cache of leaf->chain with this certificate as any_ca_cert->tree. Revocation status caching can be done in this cache as well, so maybe the cache should be in sqlite3, or at least written there before exit and querying of the cache could be done first on the in core (possibly CF or custom tree like structure) and secondarly on the sqlite3 backed store. We should choose the lowest memory footprint solution in my mind, while choosing a sqlite3 cache size that gives us a resonable io usage pattern. - NOTE no certificate can be an intermediate unless it is X.509V3 and it has a basicConstraints extension with isCA set to true. This can be used to classify certs for caching purposes. - - kSecPolicySLCheck Static Subscriber Certificate Checks - kSecPolicySICheck Static Subsidiary CA Checks - kSecPolicySACheck Static Anchor Checks - - kSecPolicyDLCheck Dynamic Subscriber Certificate Checks - kSecPolicyDICheck Dynamic Subsidiary CA Checks - kSecPolicyDACheck Dynamic Anchor Checks ? not yet needed other than to - possibly exclude in a exception template (but those should still be per - certificate --- i.o.w. exceptions (or a database backed multiple role/user - trust store of some sort) and policies are 2 different things and this - text is about policies. - - All static checks are only allowed to consider the certificate in isolation, - just given the position in the chain or the cert (leaf, intermidate, root). - dynamic checks can make determinations about the chain as a whole. - - Static Subscriber Certificate Checks will be done up front before the - chainbuilder is even instantiated. If they fail and details aren't required - by the client (if no exceptions were present for this certificate) we could - short circuit fail the evaluation. - IDEA: These checks can dynamically add new checks...[needs work] - ALTERNATIVE: A policy can have one or more sub-policies. Each sub-policy will be evaluated only after the parent policy succeeds. Subpolicies can be either required (making the parent policy fail) or optional making the parent policy succeed, but allowing the chainbuilder to continue building chains after an optional subpolicy failure in search of a chain for which the subpolicy also succeeded. Subpolicies can be dynamically added to the policy evaluation context tree (a tree with a node for every node in the certificate path. This tree however is from the leaf up stored in the SecCertificatePathRef objects themselves possibly - requiring a separate shared subtree of nodes for the underlying certificate state tree.) by a parent policy at any stage, since the subpolicy evaluation only starts after - will have a key in the info (or even details and make info client side generated from info to indicate the success or failure of optional subpolicies) tree the value of which is an - equivalent subtree from that level down. So SSL has EV as a subpolicy, but - EV dynamically enables the ocsp or crl or dcrl or any combination thereof subpolicies. - - Static Subsidiary CA Checks will be used by the chain-builder to choose the - best parents to evaluate first. This feature is currently already implemented - but with a hardcoded is_valid(verifyTime) check. Instead we will evaluate all - Static Subsidiary CA Checks. The results of these checks for purposes of - generating details could be cached in the SecCertificatePathRefs themselves, or we can short circuit fail and recalc details on demand later. - - Static Anchor Checks can do things like populate the chainbuilder level context value of the initial_valid_policy_tree with a particular anchors list of ev policies it represents or modify inputs to the policy itself. - - Dynamic Subscriber Certificate Checks These can do things like check for EV policy conformance based on the valid_policy_tree at the end of the certificate evaluation, or based on things like the pathlen, etc. in the chain validation context. - - Dynamic Subsidiary CA Checks might not be needed to have custom - implementations, since they are all done as part of the rfc5280 checks now. - This assumes that checks like issuer common name includes 'foo' are - implmented as Static Subscriber Certificate Checks instead. - - Dynamic Anchor Checks might include EV type checks or chain validation context seeding as well, allthough we might be able to do them as static checks to seed the chain validation context instead. - - - Questions/Notes: Do we need to dynamically add new policies? If policy static checks fail and policy is optional we don't even run policy dynamic checks nor do we compute subpolicy values. So if the static check of the leaf for EV fails we skip the rest of the EV style checks and instead don't run the revocation subpolicy of the ev policy. - - If an optional subpolicy s_p has a required subpolicy r_s_p. Then success of s_p will cause the entire chain evaluation to fail if r_s_p fails. - - All policies static revocation checks are run at the appropriate phase in the evaluation. static leaf checks are done before chainbuilding even starts. static intermediate checks are done in the chainbuilder for each cadidate parent certificate. If all policies pass we check the signatures. We reject the whole chain if that step fails. Otherwise we add the path to builder->candidatePaths. If the top level policy or a required subpolicy or a required subpolicy of a successful subpolicy fails we stick the chain at the end of the expiredPaths, if one of the optional subpolicies fail, we stick the chain at the start of expiredPaths so it's considered first after all real candidatePaths have been processed. - - Static revocation policy checks could check the passed in ocspresponses or even the local cache, though the latter is probably best left for the dynamic phase. - - The same rules that apply above to the adding paths to candidatePaths v/s expiredPaths apply to dynamicpolicy checks, except that we don't remember failures anymore, we reject them. - - We need to remember the best successful chain we find, where best is defined by: satisfies as many optional policies as possible. - - Chain building ends when either we find a chain that matches all optional and required policies, or we run out of chains to build. Another case is if we run out of candiate paths but we already have a chain that matches at least the top level and required subpolicies. In that case we don't even consider any expiredPaths. Example: we find a valid SSL chain (top level policy), but no partial chain we constructed satisfied the static checks of the ev subpolicy, or the required revocation sub-subpolicy of the ev policy. - - In order for this to work well with exceptions on subpolicies, we'd need to move the validation of exceptions to the server, something we'd do anyway if we had full on truststore. In this case exceptions would be live in the failure callback for a trust check. - -Example sectrust operation in psuedocode: - */ -/* -{ - new builder(verifyTime, certificates, anchors, anchorsOnly, policies); - chain = builder.subscriber_only_chain; - foreach (policy in policies{kSecPolicySLCheck}) { - foreach(check in policy) - SecPolicyRunCheck(builder, chain, check, details); - foreach (subpolicy in policy) { - check_policy(builder, chain, subpolicy, details{subpolicy.name}) - } - propagate_subpolicy_results(builder, chain, details); - } - while (chain = builder.next) { - for (depth = 0; p_d = policies.at_depth(depth), - d_p_d = dynamic_policies.at_depth(depth), p_d || d_p_d; ++depth) - { - // Modify SecPathBuilderIsPartial() to - // run builder_check(buildier, policies, kSecPolicySICheck) instead - // of SecCertificateIsValid. Also rename considerExpired to - // considerSIFailures. - foreach (policy in p_d) { - check_policy(builder, chain, policy, kSecPolicySICheck, depth); - } - /// Recalculate since the static checks might have added new dynamic - // policies. - d_p_d = dynamic_policies.at_depth(depth); - foreach (policy in d_p_d) { - check_policy(builder, chain, policy, kSecPolicySICheck, depth); - } - if (chain.is_anchored) { - foreach (policy in p_d) { - check_policy(builder, chain, policy, kSecPolicySACheck, depth); - } - foreach (policy in d_p_d) { - check_policy(builder, chain, policy, kSecPolicySACheck, depth); - } - foreach (policy in p_d) { - check_policy(builder, chain, policy, kSecPolicyDACheck, depth); - } - foreach (policy in d_p_d) { - check_policy(builder, chain, policy, kSecPolicyDACheck, depth); - } - } - foreach (policy in policies) { - check_policy(builder, chain, policy, kSecPolicySACheck, depth); - check_policy(builder, chain, policy, kSecPolicyDACheck, depth); - } - foreach (policy in policies{kSecPolicySDCheck}) { - } - } -} - -check_policy(builder, chain, policy, check_class, details, depth) { - if (depth == 0) { - foreach(check in policy{check_class}) { - SecPolicyRunCheck(builder, chain, check, details); - } - } else { - depth--; - foreach (subpolicy in policy) { - if (!check_policy(builder, chain, subpolicy, check_class, - details{subpolicy.name}) && subpolicy.is_required, depth) - secpvcsetresult() - } - } - propagate_subpolicy_results(builder, chain, details); -} - -*/ - - +static CFStringRef kSecPolicyNameAppleAppTransportSecurity = CFSTR("ATS"); +static CFStringRef kSecPolicyNameMobileSoftwareUpdate = CFSTR("MobileSoftwareUpdate"); +static CFStringRef kSecPolicyNameAppleMacOSProfileApplicationSigning = CFSTR("macOSProfileApplicationSigning"); +static CFStringRef kSecPolicyNameAppleBasicAttestationSystem = CFSTR("BAA-SCRT"); +static CFStringRef kSecPolicyNameAppleBasicAttestationUser = CFSTR("BAA-UCRT"); +static CFStringRef kSecPolicyNameiPhoneVPNApplicationSigning = CFSTR("iPhoneVPNApplicationSigning"); + +/* Private policy names (SSL Pinned Services) */ +SEC_CONST_DECL (kSecPolicyNameAppleiCloudSetupService, "iCloudSetup"); +SEC_CONST_DECL (kSecPolicyNameAppleGSService, "GS"); +SEC_CONST_DECL (kSecPolicyNameAppleMMCSService, "MMCS"); +SEC_CONST_DECL (kSecPolicyNameApplePPQService, "PPQ"); +SEC_CONST_DECL (kSecPolicyNameAppleIDSService, "IDS"); +SEC_CONST_DECL (kSecPolicyNameApplePushService, "APN"); +SEC_CONST_DECL (kSecPolicyNameAppleAST2Service, "AST2"); +SEC_CONST_DECL (kSecPolicyNameAppleEscrowProxyService, "Escrow"); +SEC_CONST_DECL (kSecPolicyNameAppleFMiPService, "FMiP"); +SEC_CONST_DECL (kSecPolicyNameAppleHomeKitService, "HomeKit"); +SEC_CONST_DECL (kSecPolicyNameAppleGalaxyProviderService, "GalaxyProvider"); #define kSecPolicySHA1Size 20 #define kSecPolicySHA256Size 32 @@ -929,6 +810,27 @@ SecPolicyRef SecPolicyCreateWithProperties(CFTypeRef policyIdentifier, } else { secerror("policy \"%@\" requires kSecPolicyName input", policyIdentifier); } + } + else if (CFEqual(policyIdentifier, kSecPolicyAppleAppTransportSecurity)) { + policy = SecPolicyCreateAppleAppTransportSecurity(); + } + else if (CFEqual(policyIdentifier, kSecPolicyAppleMobileAssetDevelopment)) { + policy = SecPolicyCreateMobileAssetDevelopment(); + } + else if (CFEqual(policyIdentifier, kSecPolicyAppleMobileSoftwareUpdate)) { + policy = SecPolicyCreateMobileSoftwareUpdate(); + } + else if (CFEqual(policyIdentifier, kSecPolicyAppleMacOSProfileApplicationSigning)) { + policy = SecPolicyCreateMacOSProfileApplicationSigning(); + } + else if (CFEqual(policyIdentifier, kSecPolicyAppleBasicAttestationSystem)) { + policy = SecPolicyCreateAppleBasicAttestationSystem(NULL); + } + else if (CFEqual(policyIdentifier, kSecPolicyAppleBasicAttestationUser)) { + policy = SecPolicyCreateAppleBasicAttestationUser(NULL); + } + else if (CFEqual(policyIdentifier, kSecPolicyAppleiPhoneVPNApplicationSigning)) { + policy = SecPolicyCreateiPhoneVPNApplicationSigning(); } else { secerror("ERROR: policy \"%@\" is unsupported", policyIdentifier); @@ -937,6 +839,9 @@ SecPolicyRef SecPolicyCreateWithProperties(CFTypeRef policyIdentifier, #ifdef TARGET_OS_OSX set_ku_from_properties(policy, properties); #endif + + SecPolicySetName(policy, policyName); + errOut: return policy; } @@ -1005,7 +910,7 @@ static void SecPolicySetOid(SecPolicyRef policy, CFStringRef oid) { CFReleaseSafe(temp); } -static void SecPolicySetName(SecPolicyRef policy, CFStringRef policyName) { +void SecPolicySetName(SecPolicyRef policy, CFStringRef policyName) { if (!policy || !policyName) return; CFStringRef temp = policy->_name; CFRetain(policyName); @@ -1811,40 +1716,10 @@ static bool isAppleOid(CFStringRef oid) { } static bool isCFPreferenceInSecurityDomain(CFStringRef setting) { - /* For backwards compatibility reasons we have to check both "com.apple.security" - and "com.apple.Security". */ - if (CFPreferencesGetAppBooleanValue(setting, CFSTR("com.apple.Security"), NULL)) { - secwarning("DEPRECATION WARNING: Preference set in \"com.apple.Security\" domain. This domain is deprecated. Please use \"com.apple.security\" instead"); - } - return (CFPreferencesGetAppBooleanValue(setting, CFSTR("com.apple.security"), NULL) || - CFPreferencesGetAppBooleanValue(setting, CFSTR("com.apple.Security"), NULL)); -} - -static bool allowTestHierarchyForPolicy(CFStringRef policyName, bool isSSL) { - bool allow = false; - - CFStringRef setting = CFStringCreateWithFormat(NULL, NULL, CFSTR("ApplePinningAllowTestCerts%@"), policyName); - require(setting, fail); - if (isCFPreferenceInSecurityDomain(setting)) { - allow = true; - } else { - secnotice("pinningQA", "could not enable test hierarchy: %@ not true", setting); - } - CFRelease(setting); - - if (!allow && isSSL) { - if (isCFPreferenceInSecurityDomain(CFSTR("AppleServerAuthenticationAllowUAT"))) { - allow = true; - } else { - secnotice("pinningQA", "could not enable test hierarchy: AppleServerAuthenticationAllowUAT not true"); - } - } - -fail: - return allow; + return (CFPreferencesGetAppBooleanValue(setting, CFSTR("com.apple.security"), NULL)); } -static bool SecPolicyAddAppleAnchorOptions(CFMutableDictionaryRef options, CFStringRef policyName) +static bool SecPolicyAddAppleAnchorOptions(CFMutableDictionaryRef options, CFStringRef __unused policyName) { CFMutableDictionaryRef appleAnchorOptions = NULL; appleAnchorOptions = CFDictionaryCreateMutableForCFTypes(NULL); @@ -1852,15 +1727,26 @@ static bool SecPolicyAddAppleAnchorOptions(CFMutableDictionaryRef options, CFStr return false; } - if (allowTestHierarchyForPolicy(policyName, false)) { - CFDictionarySetValue(appleAnchorOptions, - kSecPolicyAppleAnchorIncludeTestRoots, kCFBooleanTrue); - } + /* Currently no Apple Anchor options */ add_element(options, kSecPolicyCheckAnchorApple, appleAnchorOptions); CFReleaseSafe(appleAnchorOptions); return true; } +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); + } + } else { + return false; + } + return true; +} + // // MARK: Policy Creation Functions // @@ -1900,6 +1786,8 @@ SecPolicyRef SecPolicyCreateSSL(Boolean server, CFStringRef hostname) { if (server) { CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue); + CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakKey, kCFBooleanTrue); + require_quiet(SecPolicyAddPinningRequiredIfInfoSpecified(options), errOut); } set_ssl_ekus(options, server); @@ -2009,12 +1897,7 @@ SecPolicyRef SecPolicyCreateAppleSSLPinned(CFStringRef policyName, CFStringRef h SecPolicyAddBasicX509Options(options); /* Anchored to the Apple Roots */ - require_quiet(appleAnchorOptions = CFDictionaryCreateMutableForCFTypes(NULL), errOut); - if (allowTestHierarchyForPolicy(policyName, true)) { - CFDictionarySetValue(appleAnchorOptions, - kSecPolicyAppleAnchorIncludeTestRoots, kCFBooleanTrue); - } - add_element(options, kSecPolicyCheckAnchorApple, appleAnchorOptions); + require(SecPolicyAddAppleAnchorOptions(options, policyName), errOut); /* Exactly 3 certs in the chain */ require(SecPolicyAddChainLengthOptions(options, 3), errOut); @@ -2059,6 +1942,7 @@ SecPolicyRef SecPolicyCreateAppleSSLPinned(CFStringRef policyName, CFStringRef h } else { result = SecPolicyCreateSSL(true, hostname); SecPolicySetOid(result, kSecPolicyAppleGenericAppleSSLPinned); + SecPolicySetName(result, policyName); } errOut: @@ -2242,6 +2126,7 @@ SecPolicyRef SecPolicyCreateEAP(Boolean server, CFArrayRef trustedServerNames) { if (server) { /* Check for weak hashes */ CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue); + CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakKey, kCFBooleanTrue); } /* We need to check for EKU per rdar://22206018 */ @@ -2294,7 +2179,7 @@ errOut: } SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void) { - CFMutableDictionaryRef options = NULL, appleAnchorOptions = NULL; + CFMutableDictionaryRef options = NULL; SecPolicyRef result = NULL; require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, @@ -2302,14 +2187,8 @@ SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void) { SecPolicyAddBasicCertOptions(options); - appleAnchorOptions = CFDictionaryCreateMutableForCFTypes(NULL); - require(appleAnchorOptions, errOut); - - if (allowTestHierarchyForPolicy(kSecPolicyNameiPhoneApplicationSigning, false)) { - /* Allow a test hierarchy-signed cert with prod name/OIDs */ - CFDictionarySetValue(appleAnchorOptions, - kSecPolicyAppleAnchorIncludeTestRoots, kCFBooleanTrue); - } + /* Anchored to the Apple Roots */ + require(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameiPhoneApplicationSigning), errOut); /* Leaf checks */ if (SecIsInternalRelease()) { @@ -2317,18 +2196,12 @@ SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void) { CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonNameTEST, CFSTR("Apple iPhone OS Application Signing")); add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.3.1")); - add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.6.1")); - - /* or a test hierarchy-signed test cert */ - CFDictionarySetValue(appleAnchorOptions, - kSecPolicyAppleAnchorIncludeTestRoots, kCFBooleanTrue); } else { CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonName, CFSTR("Apple iPhone OS Application Signing")); } add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.3")); - add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.6")); add_eku(options, NULL); /* eku extension is optional */ add_eku(options, &oidAnyExtendedKeyUsage); @@ -2341,27 +2214,97 @@ SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void) { /* Chain length check */ require(SecPolicyAddChainLengthOptions(options, 3), errOut); - /* Anchored to the Apple Roots */ - add_element(options, kSecPolicyCheckAnchorApple, appleAnchorOptions); - require(result = SecPolicyCreate(kSecPolicyAppleiPhoneApplicationSigning, kSecPolicyNameiPhoneApplicationSigning, options), errOut); errOut: CFReleaseSafe(options); - CFReleaseSafe(appleAnchorOptions); return result; } +SecPolicyRef SecPolicyCreateiPhoneVPNApplicationSigning(void) { + CFMutableDictionaryRef options = NULL; + SecPolicyRef result = NULL; + + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); + + SecPolicyAddBasicCertOptions(options); + + /* Anchored to the Apple Roots */ + require(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameiPhoneVPNApplicationSigning), errOut); + + /* Leaf checks */ + if (SecIsInternalRelease()) { + /* Allow a prod hierarchy-signed test cert */ + CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonNameTEST, + CFSTR("Apple iPhone OS Application Signing")); + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.6.1")); + } + else { + CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonName, + CFSTR("Apple iPhone OS Application Signing")); + } + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.6")); + + add_eku(options, NULL); /* eku extension is optional */ + add_eku(options, &oidAnyExtendedKeyUsage); + add_eku(options, &oidExtendedKeyUsageCodeSigning); + + /* Intermediate check */ + CFDictionaryAddValue(options, kSecPolicyCheckIssuerCommonName, + CFSTR("Apple iPhone Certification Authority")); + + /* Chain length check */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + require(result = SecPolicyCreate(kSecPolicyAppleiPhoneVPNApplicationSigning, + kSecPolicyNameiPhoneVPNApplicationSigning, options), + errOut); + +errOut: + CFReleaseSafe(options); + return result; +} + SecPolicyRef SecPolicyCreateiPhoneProfileApplicationSigning(void) { CFMutableDictionaryRef options = NULL; SecPolicyRef result = NULL; require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); - CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny); - CFDictionaryAddValue(options, kSecPolicyCheckValidLeaf, kCFBooleanFalse); + + SecPolicyAddBasicX509Options(options); // With expiration checking + + /* Apple Anchor */ + require_quiet(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameiPhoneProfileApplicationSigning), + errOut); + + /* Chain Len: 3 */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + /* Leaf has CodeSigning EKU */ + add_eku_string(options, CFSTR("1.3.6.1.5.5.7.3.3")); + + /* On iOS, the cert in the provisioning profile may be one of: + leaf OID intermediate OID + iPhone Developer .6.1.2 .6.2.1 + iPhone Distribution .6.1.4 .6.2.1 + TestFlight (Prod) .6.1.25.1 .6.2.1 + TestFlight (QA) .6.1.25.2 .6.2.1 + */ + add_element(options, kSecPolicyCheckIntermediateMarkerOid, CFSTR("1.2.840.113635.100.6.2.1")); + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.2")); + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.4")); + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.25.1")); + if (SecIsInternalRelease()) { + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.25.2")); + } + + /* Revocation via any available method */ + CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny); + require(result = SecPolicyCreate(kSecPolicyAppleiPhoneProfileApplicationSigning, kSecPolicyNameiPhoneProfileApplicationSigning, @@ -2372,6 +2315,51 @@ errOut: return result; } +SecPolicyRef SecPolicyCreateMacOSProfileApplicationSigning(void) { + CFMutableDictionaryRef options = NULL; + SecPolicyRef result = NULL; + + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); + + SecPolicyAddBasicCertOptions(options); // Without expiration checking + + /* Apple Anchor */ + require_quiet(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameiPhoneProfileApplicationSigning), + errOut); + + /* Chain Len: 3 */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + /* Leaf has CodeSigning EKU */ + add_eku_string(options, CFSTR("1.3.6.1.5.5.7.3.3")); + + + /* On macOS, the cert in the provisioning profile may be one of: + leaf OID intermediate OID + MAS Development .6.1.12 .6.2.1 + MAS Submission .6.1.7 .6.2.1 + Developer ID .6.1.13 .6.2.6 + B&I .6.22 None - "Apple Code Signing Certification Authority" + */ + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.12")); + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.7")); + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.1.13")); + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.22")); + + /* Revocation via any available method */ + CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny); + + + require(result = SecPolicyCreate(kSecPolicyAppleMacOSProfileApplicationSigning, + kSecPolicyNameAppleMacOSProfileApplicationSigning, + options), errOut); + +errOut: + CFReleaseSafe(options); + return result; +} + SecPolicyRef SecPolicyCreateiPhoneProvisioningProfileSigning(void) { CFMutableDictionaryRef options = NULL; SecPolicyRef result = NULL; @@ -2471,8 +2459,6 @@ errOut: return result; } -const CFOptionFlags kSecRevocationOnlineCheck = (1 << 5); - SecPolicyRef SecPolicyCreateRevocation(CFOptionFlags revocationFlags) { CFMutableDictionaryRef options = NULL; SecPolicyRef result = NULL; @@ -2529,7 +2515,11 @@ SecPolicyRef SecPolicyCreateSMIME(CFIndex smimeUsage, CFStringRef email) { require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); - SecPolicyAddBasicX509Options(options); + if (smimeUsage & kSecIgnoreExpirationSMIMEUsage) { + SecPolicyAddBasicCertOptions(options); + } else { + SecPolicyAddBasicX509Options(options); + } /* We call add_ku for each combination of bits we are willing to allow. */ if (smimeUsage & kSecSignSMIMEUsage) { @@ -2720,39 +2710,38 @@ errOut: return result; } -static bool SecPolicyAddAppleCertificationAuthorityOptions(CFMutableDictionaryRef options, bool honorValidity, CFStringRef policyName) +SecPolicyRef SecPolicyCreateOTATasking(void) { - bool success = false; + CFMutableDictionaryRef options = NULL; + SecPolicyRef result = NULL; - if (honorValidity) - SecPolicyAddBasicX509Options(options); - else - SecPolicyAddBasicCertOptions(options); + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); -#if 0 - CFDictionaryAddValue(options, kSecPolicyCheckKeyUsage, - kCFBooleanTrue); - CFDictionaryAddValue(options, kSecPolicyCheckExtendedKeyUsage, - kCFBooleanTrue); -#endif + SecPolicyAddBasicX509Options(options); - /* Basic X.509 policy with the additional requirements that the chain - length is 3, it's anchored at the AppleCA and the leaf certificate - has issuer "Apple iPhone Certification Authority". */ + /* Apple Anchor */ + require(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameMobileAsset), errOut); + + /* Chain length of 3 */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + /* Intermediate has common name "Apple iPhone Certification Authority". */ CFDictionaryAddValue(options, kSecPolicyCheckIssuerCommonName, CFSTR("Apple iPhone Certification Authority")); - require(SecPolicyAddChainLengthOptions(options, 3), errOut); - require(SecPolicyAddAppleAnchorOptions(options, policyName), errOut); + /* Leaf has common name "Asset Manifest Signing" */ + CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonName, CFSTR("OTA Task Signing")); - success = true; + require(result = SecPolicyCreate(kSecPolicyAppleOTATasking, kSecPolicyNameOTATasking, options), + errOut); errOut: - return success; + CFReleaseSafe(options); + return result; } -static SecPolicyRef SecPolicyCreateAppleCertificationAuthorityPolicy(CFStringRef policyOID, CFStringRef policyName, - CFStringRef leafName, bool honorValidity) +SecPolicyRef SecPolicyCreateMobileAsset(void) { CFMutableDictionaryRef options = NULL; SecPolicyRef result = NULL; @@ -2760,11 +2749,23 @@ static SecPolicyRef SecPolicyCreateAppleCertificationAuthorityPolicy(CFStringRef require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); - require(SecPolicyAddAppleCertificationAuthorityOptions(options, honorValidity, policyName), errOut); + /* No expiration check */ + SecPolicyAddBasicCertOptions(options); + + /* Apple Anchor */ + require(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameMobileAsset), errOut); + + /* Chain length of 3 */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + /* Intermediate has common name "Apple iPhone Certification Authority". */ + CFDictionaryAddValue(options, kSecPolicyCheckIssuerCommonName, + CFSTR("Apple iPhone Certification Authority")); - CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonName, leafName); + /* Leaf has common name "Asset Manifest Signing" */ + CFDictionaryAddValue(options, kSecPolicyCheckSubjectCommonName, CFSTR("Asset Manifest Signing")); - require(result = SecPolicyCreate(policyOID, policyName, options), + require(result = SecPolicyCreate(kSecPolicyAppleMobileAsset, kSecPolicyNameMobileAsset, options), errOut); errOut: @@ -2772,19 +2773,34 @@ errOut: return result; } +SecPolicyRef SecPolicyCreateMobileAssetDevelopment(void) { + CFMutableDictionaryRef options = NULL; + SecPolicyRef result = NULL; -SecPolicyRef SecPolicyCreateOTATasking(void) -{ - return SecPolicyCreateAppleCertificationAuthorityPolicy(kSecPolicyAppleOTATasking, - kSecPolicyNameOTATasking, - CFSTR("OTA Task Signing"), true); -} + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); -SecPolicyRef SecPolicyCreateMobileAsset(void) -{ - return SecPolicyCreateAppleCertificationAuthorityPolicy(kSecPolicyAppleMobileAsset, - kSecPolicyNameMobileAsset, - CFSTR("Asset Manifest Signing"), false); + /* No expiration check */ + SecPolicyAddBasicCertOptions(options); + + /* Apple Anchor */ + require(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameMobileAsset), errOut); + + /* Chain length of 3 */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + /* Intermediate has the iPhone CA Marker extension */ + add_element(options, kSecPolicyCheckIntermediateMarkerOid, CFSTR("1.2.840.113635.100.6.2.18")); + + /* Leaf has ProdQA Mobile Asset Marker extension */ + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.55.1")); + + require(result = SecPolicyCreate(kSecPolicyAppleMobileAssetDevelopment, kSecPolicyNameMobileAsset, options), + errOut); + +errOut: + CFReleaseSafe(options); + return result; } SecPolicyRef SecPolicyCreateAppleIDAuthorityPolicy(void) @@ -2863,7 +2879,7 @@ static SecPolicyRef _SecPolicyCreatePassbookCardSigner(CFStringRef cardIssuer, C &kCFTypeDictionaryValueCallBacks), out); SecPolicyAddBasicX509Options(options); - SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameApplePassbook); + require(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameApplePassbook), out); // Chain length of 3 require(SecPolicyAddChainLengthOptions(options, 3), out); @@ -2912,9 +2928,9 @@ static SecPolicyRef CreateMobileStoreSigner(Boolean forTest) &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); SecPolicyAddBasicX509Options(options); - SecPolicyAddAppleAnchorOptions(options, + require(SecPolicyAddAppleAnchorOptions(options, ((forTest) ? kSecPolicyNameAppleTestMobileStore : - kSecPolicyNameAppleMobileStore)); + kSecPolicyNameAppleMobileStore)), errOut); require(SecPolicyAddChainLengthOptions(options, 3), errOut); @@ -2962,7 +2978,8 @@ CF_RETURNS_RETAINED SecPolicyRef SecPolicyCreateEscrowServiceSigner(void) add_ku(options, kSecKeyUsageKeyEncipherment); - //add_leaf_marker(options, &oidApplePolicyEscrowService); + /* Leaf has marker OID with value that can't be pre-determined */ + add_element(options, kSecPolicyCheckLeafMarkerOidWithoutValueCheck, CFSTR("1.2.840.113635.100.6.23.1")); require(SecPolicyAddChainLengthOptions(options, 2), errOut); @@ -3024,7 +3041,8 @@ CF_RETURNS_RETAINED SecPolicyRef SecPolicyCreatePCSEscrowServiceSigner(void) add_ku(options, kSecKeyUsageKeyEncipherment); - //add_leaf_marker(options, &oidApplePolicyEscrowService); + /* Leaf has marker OID with value that can't be pre-determined */ + add_element(options, kSecPolicyCheckLeafMarkerOidWithoutValueCheck, CFSTR("1.2.840.113635.100.6.23.1")); require(SecPolicyAddChainLengthOptions(options, 2), errOut); @@ -3079,7 +3097,7 @@ static SecPolicyRef CreateConfigurationProfileSigner(bool forTest) { &kCFTypeDictionaryValueCallBacks), errOut); SecPolicyAddBasicX509Options(options); - SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameAppleProfileSigner); + require(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameAppleProfileSigner), errOut); //Chain length 3 require(SecPolicyAddChainLengthOptions(options, 3), errOut); @@ -3309,46 +3327,6 @@ errOut: return result; } -static bool -allowUATRoot(CFStringRef service, CFDictionaryRef context) -{ - bool UATAllowed = false; - CFStringRef setting = NULL; - setting = CFStringCreateWithFormat(NULL, NULL, CFSTR("AppleServerAuthenticationAllowUAT%@"), service); - CFTypeRef value = NULL; - require(setting, fail); - - if (context && - CFDictionaryGetValueIfPresent(context, setting, &value) && - isBoolean(value) && - CFBooleanGetValue(value)) - { - UATAllowed = true; - } - - /* CFPreference for this service */ - if (isCFPreferenceInSecurityDomain(setting)) { - UATAllowed = true; - } - - if (!UATAllowed) { - secnotice("pinningQA", "could not enable test cert: %@ not true", setting); - } else { - goto fail; - } - - /* Generic CFPreference */ - if (isCFPreferenceInSecurityDomain(CFSTR("AppleServerAuthenticationAllowUAT"))) { - UATAllowed = true; - } else { - secnotice("pinningQA", "could not enable test hierarchy: AppleServerAuthenticationAllowUAT not true"); - } - -fail: - CFReleaseNull(setting); - return UATAllowed; -} - /*! @function SecPolicyCreateAppleServerAuthCommon @abstract Generic policy for server authentication Sub CAs @@ -3359,7 +3337,7 @@ fail: No pinning is for developer/QA that needs to use proxy to debug the protocol, while UAT environment is for QA/internal developer that have no need allow fake servers. - Both the noPinning and allowUAT are gated on that you run on internal hardware. + Both the noPinning and UAT are gated on that you run on internal hardware. */ @@ -3389,42 +3367,27 @@ SecPolicyCreateAppleServerAuthCommon(CFStringRef hostname, add_eku(options, &oidExtendedKeyUsageServerAuth); if (requireUATPinning(service)) { - bool allowUAT = allowUATRoot(service, context); - - /* - * Require pinning to the Apple CA's (and if UAT environment, - * include the Apple Test CA's as anchors). - */ - appleAnchorOptions = CFDictionaryCreateMutableForCFTypes(NULL); - require(appleAnchorOptions, errOut); - - if (allowUAT || allowTestHierarchyForPolicy(service, true)) { - /* Note: SecPolicyServer won't allow the test roots for non-internal devices */ - CFDictionarySetValue(appleAnchorOptions, - kSecPolicyAppleAnchorIncludeTestRoots, kCFBooleanTrue); - } - add_element(options, kSecPolicyCheckAnchorApple, appleAnchorOptions); + /* + * Require pinning to the Apple CA's. + */ + SecPolicyAddAppleAnchorOptions(options, service); - /* - * Check if we also should allow the UAT variant of the leafs - * as some variants of the UAT environment uses that instead - * of the test Apple CA's. - */ - if (allowUAT && UATLeafMarkerOID) { + /* old-style leaf marker OIDs */ + if (UATLeafMarkerOID) { add_leaf_prod_qa_markers(options, leafMarkerOID, UATLeafMarkerOID); } else { add_leaf_marker(options, leafMarkerOID); } - /* new-style leaf marker OIDs */ + /* new-style leaf marker OIDs */ CFStringRef leafMarkerOIDStr = NULL, UATLeafMarkerOIDStr = NULL; leafMarkerOIDStr = SecDERItemCopyOIDDecimalRepresentation(NULL, leafMarkerOID); if (UATLeafMarkerOID) { UATLeafMarkerOIDStr = SecDERItemCopyOIDDecimalRepresentation(NULL, UATLeafMarkerOID); } - if (allowUAT && leafMarkerOIDStr && UATLeafMarkerOIDStr) { + if (leafMarkerOIDStr && UATLeafMarkerOIDStr) { add_leaf_prod_qa_markers_value_string(options, CFSTR("1.2.840.113635.100.6.48.1"), leafMarkerOIDStr, CFSTR("1.2.840.113635.100.6.48.1"), UATLeafMarkerOIDStr); @@ -3438,8 +3401,9 @@ SecPolicyCreateAppleServerAuthCommon(CFStringRef hostname, add_oid(options, kSecPolicyCheckIntermediateMarkerOid, &oidAppleIntmMarkerAppleServerAuthentication); } - /* Check for weak hashes */ + /* Check for weak hashes and keys */ CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue); + require(SecPolicyAddStrongKeySizeOptions(options), errOut); CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny); @@ -3463,7 +3427,7 @@ SecPolicyRef SecPolicyCreateAppleIDSService(CFStringRef hostname) SecPolicyRef result = SecPolicyCreateSSL(true, hostname); SecPolicySetOid(result, kSecPolicyAppleIDSService); - SecPolicySetName(result, kSecPolicyNameAppleIDSServiceContext); + SecPolicySetName(result, kSecPolicyNameAppleIDSBag); return result; } @@ -3475,7 +3439,7 @@ SecPolicyRef SecPolicyCreateAppleIDSService(CFStringRef hostname) SecPolicyRef SecPolicyCreateAppleIDSServiceContext(CFStringRef hostname, CFDictionaryRef context) { return SecPolicyCreateAppleServerAuthCommon(hostname, context, kSecPolicyAppleIDSServiceContext, - kSecPolicyNameAppleIDSServiceContext, + kSecPolicyNameAppleIDSService, &oidAppleCertExtAppleServerAuthenticationIDSProd, &oidAppleCertExtAppleServerAuthenticationIDSProdQA); } @@ -3580,7 +3544,7 @@ static SecPolicyRef SecPolicyCreateAppleGeoTrustServerAuthCommon(CFStringRef hos require_action(SecPolicyAddChainLengthOptions(options, 3), errOut, CFReleaseNull(result)); /* Marker OIDs in both formats */ - if (qaLeafMarkerOid && allowUATRoot(policyName, NULL)) { + if (qaLeafMarkerOid) { add_leaf_prod_qa_markers_string(options, leafMarkerOid, qaLeafMarkerOid); add_leaf_prod_qa_markers_value_string(options, CFSTR("1.2.840.113635.100.6.48.1"), leafMarkerOid, @@ -3593,6 +3557,7 @@ static SecPolicyRef SecPolicyCreateAppleGeoTrustServerAuthCommon(CFStringRef hos /* Check for weak hashes */ CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue); + CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakKey, kCFBooleanTrue); /* See for more details */ @@ -3659,6 +3624,10 @@ SecPolicyRef SecPolicyCreateApplePushServiceLegacy(CFStringRef hostname) add_eku(options, &oidExtendedKeyUsageServerAuth); + /* Check for weak hashes and keys */ + CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue); + CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakKey, kCFBooleanTrue); + CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny); result = SecPolicyCreate(kSecPolicyAppleLegacyPushService, @@ -3732,6 +3701,7 @@ SecPolicyRef SecPolicyCreateAppleSSLService(CFStringRef hostname) /* Check for weak hashes */ CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue); + require(SecPolicyAddStrongKeySizeOptions(options), errOut); CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny); @@ -3953,20 +3923,13 @@ SecPolicyRef SecPolicyCreateAppleHomeKitServerAuth(CFStringRef hostname) { add_eku(options, &oidExtendedKeyUsageServerAuth); - if (requireUATPinning(kSecPolicyNameAppleHomeKitServerAuth)) { - bool allowUAT = allowUATRoot(kSecPolicyNameAppleHomeKitServerAuth, NULL); + if (requireUATPinning(kSecPolicyNameAppleHomeKitService)) { // Cert chain length 3 require(SecPolicyAddChainLengthOptions(options, 3), errOut); - // Apple anchors, allowing test anchors for internal releases properly configured - appleAnchorOptions = CFDictionaryCreateMutableForCFTypes(NULL); - require(appleAnchorOptions, errOut); - if (allowUAT || allowTestHierarchyForPolicy(kSecPolicyNameAppleHomeKitServerAuth, true)) { - CFDictionarySetValue(appleAnchorOptions, - kSecPolicyAppleAnchorIncludeTestRoots, kCFBooleanTrue); - } - add_element(options, kSecPolicyCheckAnchorApple, appleAnchorOptions); + // Apple anchors, allowing test anchors for internal release + SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameAppleHomeKitService); add_leaf_marker(options, &oidAppleCertExtHomeKitServerAuth); @@ -3975,11 +3938,12 @@ SecPolicyRef SecPolicyCreateAppleHomeKitServerAuth(CFStringRef hostname) { /* Check for weak hashes */ CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue); + require(SecPolicyAddStrongKeySizeOptions(options), errOut); CFDictionaryAddValue(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny); result = SecPolicyCreate(kSecPolicyAppleHomeKitServerAuth, - kSecPolicyNameAppleHomeKitServerAuth, options); + kSecPolicyNameAppleHomeKitService, options); require(result, errOut); errOut: @@ -4100,9 +4064,7 @@ SecPolicyRef SecPolicyCreateAppleUniqueDeviceCertificate(CFDataRef testRootHash) /* Anchored to the SEP Root CA. Allow alternative root for developers */ require(SecPolicyAddAnchorSHA256Options(options, SEPRootCA_SHA256),errOut); - if (testRootHash && SecIsInternalRelease() && - allowTestHierarchyForPolicy(kSecPolicyNameAppleUniqueDeviceCertificate, false) - && (kSecPolicySHA256Size == CFDataGetLength(testRootHash))) { + if (testRootHash && SecIsInternalRelease() && (kSecPolicySHA256Size == CFDataGetLength(testRootHash))) { add_element(options, kSecPolicyCheckAnchorSHA256, testRootHash); } @@ -4136,8 +4098,6 @@ errOut: SecPolicyRef SecPolicyCreateAppleWarsaw(void) { CFMutableDictionaryRef options = NULL; - CFDictionaryRef keySizes = NULL; - CFNumberRef rsaSize = NULL, ecSize = NULL; SecPolicyRef result = NULL; #if TARGET_OS_BRIDGE CFMutableDictionaryRef appleAnchorOptions = NULL; @@ -4150,17 +4110,8 @@ SecPolicyRef SecPolicyCreateAppleWarsaw(void) { SecPolicyAddBasicX509Options(options); /* Anchored to the Apple Roots. */ -#if TARGET_OS_BRIDGE - /* On the bridge, test roots are gated in the trust and policy servers. */ - require_quiet(appleAnchorOptions = CFDictionaryCreateMutableForCFTypes(NULL), errOut); - CFDictionarySetValue(appleAnchorOptions, - kSecPolicyAppleAnchorIncludeTestRoots, kCFBooleanTrue); - add_element(options, kSecPolicyCheckAnchorApple, appleAnchorOptions); - CFReleaseSafe(appleAnchorOptions); -#else require_quiet(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameAppleWarsaw), errOut); -#endif /* Exactly 3 certs in the chain */ require(SecPolicyAddChainLengthOptions(options, 3), errOut); @@ -4182,16 +4133,11 @@ SecPolicyRef SecPolicyCreateAppleWarsaw(void) { errOut: CFReleaseSafe(options); - CFReleaseSafe(keySizes); - CFReleaseSafe(rsaSize); - CFReleaseSafe(ecSize); return result; } SecPolicyRef SecPolicyCreateAppleSecureIOStaticAsset(void) { CFMutableDictionaryRef options = NULL; - CFDictionaryRef keySizes = NULL; - CFNumberRef rsaSize = NULL, ecSize = NULL; SecPolicyRef result = NULL; #if TARGET_OS_BRIDGE CFMutableDictionaryRef appleAnchorOptions = NULL; @@ -4220,10 +4166,10 @@ SecPolicyRef SecPolicyCreateAppleSecureIOStaticAsset(void) { /* Exactly 3 certs in the chain */ require(SecPolicyAddChainLengthOptions(options, 3), errOut); - /* Intermediate marker OID matches input OID */ + /* Intermediate marker OID matches ASI CA */ add_element(options, kSecPolicyCheckIntermediateMarkerOid, CFSTR("1.2.840.113635.100.6.2.10")); - /* Leaf marker OID matches input OID */ + /* Leaf marker OID matches static IO OID */ add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.50")); /* RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. */ @@ -4232,10 +4178,157 @@ SecPolicyRef SecPolicyCreateAppleSecureIOStaticAsset(void) { require(result = SecPolicyCreate(kSecPolicyAppleSecureIOStaticAsset, kSecPolicyNameAppleSecureIOStaticAsset, options), errOut); +errOut: + CFReleaseSafe(options); + return result; +} + +SecPolicyRef SecPolicyCreateAppleAppTransportSecurity(void) { + CFMutableDictionaryRef options = NULL; + SecPolicyRef result = NULL; + CFMutableSetRef disallowedHashes = NULL; + + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); + + /* RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. */ + require(SecPolicyAddStrongKeySizeOptions(options), errOut); + + /* Hash algorithm is SHA-256 or better */ + require(disallowedHashes = CFSetCreateMutable(NULL, 5, &kCFTypeSetCallBacks), errOut); + CFSetAddValue(disallowedHashes, kSecSignatureDigestAlgorithmMD2); + CFSetAddValue(disallowedHashes, kSecSignatureDigestAlgorithmMD4); + CFSetAddValue(disallowedHashes, kSecSignatureDigestAlgorithmMD5); + CFSetAddValue(disallowedHashes, kSecSignatureDigestAlgorithmSHA1); + CFSetAddValue(disallowedHashes, kSecSignatureDigestAlgorithmSHA224); + + add_element(options, kSecPolicyCheckSignatureHashAlgorithms, disallowedHashes); + + require_quiet(result = SecPolicyCreate(kSecPolicyAppleAppTransportSecurity, + kSecPolicyNameAppleAppTransportSecurity, + options), errOut); + +errOut: + CFReleaseSafe(options); + return result; +} + +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); + + /* No expiration check. */ + SecPolicyAddBasicCertOptions(options); + + /* Apple Anchor */ + require_quiet(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameMobileSoftwareUpdate), + errOut); + + /* Exactly 3 certs in the chain */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + /* Intermediate marker OID is iPhone CA OID */ + add_element(options, kSecPolicyCheckIntermediateMarkerOid, CFSTR("1.2.840.113635.100.6.2.18")); + + /* Leaf marker OID is either the prod MSU OID, or, on internal builds, the prodQA OID */ + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.57.2")); + if (SecIsInternalRelease()) { + add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.6.57.1")); + } + + /* RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. */ + require(SecPolicyAddStrongKeySizeOptions(options), errOut); + + require(result = SecPolicyCreate(kSecPolicyAppleMobileSoftwareUpdate, + kSecPolicyNameMobileSoftwareUpdate, options), errOut); + +errOut: + CFReleaseNull(options); + return result; +} + +/* subject:/CN=Basic Attestation System Root CA/O=Apple Inc./ST=California */ +/* SKID: FE:D1:D1:C2:08:07:03:D5:B9:3C:34:B2:BB:FD:7C:3A:99:25:1B:8F */ +/* Not Before: Apr 20 00:22:09 2017 GMT, Not After : Mar 22 00:00:00 2032 GMT */ +/* Signature Algorithm: ecdsa-with-SHA384 */ +const uint8_t BASystemRootCA_SHA256[kSecPolicySHA256Size] = { + 0x29, 0x75, 0x9b, 0x53, 0x8a, 0xd1, 0xcb, 0x4f, 0x3b, 0xa5, 0x20, 0x4d, 0x60, 0x4b, 0x25, 0x81, + 0x8d, 0x18, 0x9f, 0x62, 0xe3, 0x94, 0x2d, 0x99, 0x52, 0x54, 0x22, 0x5a, 0xe5, 0x7f, 0x42, 0xca +}; + +/* subject:/CN=Basic Attestation User Root CA/O=Apple Inc./ST=California */ +/* SKID: 83:E5:A3:21:9E:B0:74:C3:F9:61:90:FD:97:4E:23:10:76:A4:A3:F2 */ +/* Not Before: Apr 19 21:41:56 2017 GMT, Not After : Mar 22 00:00:00 2032 GMT */ +/* Signature Algorithm: ecdsa-with-SHA384 */ +const uint8_t BAUserRootCA_SHA256[kSecPolicySHA256Size] = { + 0x29, 0x75, 0x9b, 0x53, 0x8a, 0xd1, 0xcb, 0x4f, 0x3b, 0xa5, 0x20, 0x4d, 0x60, 0x4b, 0x25, 0x81, + 0x8d, 0x18, 0x9f, 0x62, 0xe3, 0x94, 0x2d, 0x99, 0x52, 0x54, 0x22, 0x5a, 0xe5, 0x7f, 0x42, 0xca +}; + +SecPolicyRef SecPolicyCreateAppleBasicAttestationSystem(CFDataRef testRootHash) { + CFMutableDictionaryRef options = NULL; + CFDictionaryRef keySizes = NULL; + CFNumberRef ecSize = NULL; + SecPolicyRef result = NULL; + + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), errOut); + /* BAA certs expire */ + SecPolicyAddBasicX509Options(options); + + /* Anchored to one of the Basic Attestation roots. Allow alternative root for developers */ + SecPolicyAddAnchorSHA256Options(options, BASystemRootCA_SHA256); + if (testRootHash && SecIsInternalRelease() && (kSecPolicySHA256Size == CFDataGetLength(testRootHash))) { + add_element(options, kSecPolicyCheckAnchorSHA256, testRootHash); + } + + /* Exactly 3 certs in the chain */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + require(result = SecPolicyCreate(kSecPolicyAppleBasicAttestationSystem, + kSecPolicyNameAppleBasicAttestationSystem, options), errOut); + +errOut: + CFReleaseSafe(options); + CFReleaseSafe(keySizes); + CFReleaseSafe(ecSize); + return result; +} + +SecPolicyRef SecPolicyCreateAppleBasicAttestationUser(CFDataRef testRootHash) { + CFMutableDictionaryRef options = NULL; + CFDictionaryRef keySizes = NULL; + CFNumberRef ecSize = NULL; + SecPolicyRef result = NULL; + + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), errOut); + /* BAA certs expire */ + SecPolicyAddBasicX509Options(options); + + /* Anchored to one of the Basic Attestation roots. Allow alternative root for developers */ + SecPolicyAddAnchorSHA256Options(options, BAUserRootCA_SHA256); + if (testRootHash && SecIsInternalRelease() && (kSecPolicySHA256Size == CFDataGetLength(testRootHash))) { + add_element(options, kSecPolicyCheckAnchorSHA256, testRootHash); + } + + /* Exactly 3 certs in the chain */ + require(SecPolicyAddChainLengthOptions(options, 3), errOut); + + require(result = SecPolicyCreate(kSecPolicyAppleBasicAttestationUser, + kSecPolicyNameAppleBasicAttestationUser, options), errOut); + errOut: CFReleaseSafe(options); CFReleaseSafe(keySizes); - CFReleaseSafe(rsaSize); CFReleaseSafe(ecSize); return result; } diff --git a/OSX/sec/Security/SecPolicyInternal.h b/OSX/sec/Security/SecPolicyInternal.h index 6e71ad96..8285054c 100644 --- a/OSX/sec/Security/SecPolicyInternal.h +++ b/OSX/sec/Security/SecPolicyInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2008-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -92,8 +92,10 @@ struct __SecPolicy { @constant kSecPolicyCheckBlackListedLeaf @@@. @constant kSecPolicyCheckUsageConstraints @@@. @constant kSecPolicyCheckSystemTrustedWeakHash Check whether the leaf or intermediates are using a weak hash in chains that end with a system-trusted anchor. + @constant kSecPolicyCheckSystemTrustedWeakKey Check whether the leaf or intermediates are using a weak key in chains that end with a system-trusted anchor. @constant kSecPolicyCheckIntermediateOrganization Fails if any (non-leaf and non-root) certificates in the chain do not have a matching Organization string. @constant kSecPolicyCheckIntermediateCountry Fails if any (non-leaf and non-root) certificates in the chain do not have a matching Country string. + @constant kSecPolicyCheckPinningRequired Fails if the binary Info plist required pinning but no pinning policies were used. */ extern const CFStringRef kSecPolicyCheckBasicConstraints; extern const CFStringRef kSecPolicyCheckCriticalExtensions; @@ -148,8 +150,10 @@ extern const CFStringRef kSecPolicyCheckGrayListedKey; extern const CFStringRef kSecPolicyCheckCertificateTransparency; extern const CFStringRef kSecPolicyCheckUsageConstraints; extern const CFStringRef kSecPolicyCheckSystemTrustedWeakHash; +extern const CFStringRef kSecPolicyCheckSystemTrustedWeakKey; extern const CFStringRef kSecPolicyCheckIntermediateOrganization; extern const CFStringRef kSecPolicyCheckIntermediateCountry; +extern const CFStringRef kSecPolicyCheckPinningRequired; /* Special option for checking Apple Anchors */ extern const CFStringRef kSecPolicyAppleAnchorIncludeTestRoots; @@ -162,6 +166,7 @@ SecPolicyRef SecPolicyCreate(CFStringRef oid, CFStringRef name, CFDictionaryRef CFDictionaryRef SecPolicyGetOptions(SecPolicyRef policy); void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef value); +void SecPolicySetName(SecPolicyRef policy, CFStringRef policyName); xpc_object_t SecPolicyArrayCopyXPCArray(CFArrayRef policies, CFErrorRef *error); CFArrayRef SecPolicyXPCArrayCopyArray(xpc_object_t xpc_policies, CFErrorRef *error); @@ -174,6 +179,7 @@ CFArrayRef SecPolicyArrayCreateSerialized(CFArrayRef policies); */ bool SecPolicyCheckCertKeyUsage(SecCertificateRef cert, CFTypeRef pvcValue); bool SecPolicyCheckCertExtendedKeyUsage(SecCertificateRef cert, CFTypeRef pvcValue); +bool SecPolicyCheckCertNonEmptySubject(SecCertificateRef cert, CFTypeRef pvcValue); bool SecPolicyCheckCertSSLHostname(SecCertificateRef cert, CFTypeRef pvcValue); bool SecPolicyCheckCertEmail(SecCertificateRef cert, CFTypeRef pvcValue); bool SecPolicyCheckCertSubjectCommonNamePrefix(SecCertificateRef cert, CFTypeRef pvcValue); diff --git a/OSX/sec/Security/SecPolicyLeafCallbacks.c b/OSX/sec/Security/SecPolicyLeafCallbacks.c index eb337104..c8c4f6d7 100644 --- a/OSX/sec/Security/SecPolicyLeafCallbacks.c +++ b/OSX/sec/Security/SecPolicyLeafCallbacks.c @@ -133,22 +133,20 @@ bool SecPolicyCheckCertExtendedKeyUsage(SecCertificateRef cert, CFTypeRef pvcVal return match; } -static bool SecPolicyCheckCertNonEmptySubject(SecCertificateRef cert, CFTypeRef pvcValue) { +bool SecPolicyCheckCertNonEmptySubject(SecCertificateRef cert, CFTypeRef __unused pvcValue) { /* If the certificate has a subject, or - if it doesn't, and it's the leaf and not self signed, + if it doesn't, and it's the leaf and not a CA, and also has a critical subjectAltName extension it's valid. */ if (!SecCertificateHasSubject(cert)) { - Boolean isSelfSigned = true; - SecCertificateIsSelfSigned(cert, &isSelfSigned); - if (!isSelfSigned) { + if (SecCertificateIsCA(cert)) { + /* CA certificate has empty subject. */ + return false; + } else { if (!SecCertificateHasCriticalSubjectAltName(cert)) { /* Leaf certificate with empty subject does not have a critical subject alt name extension. */ return false; } - } else { - /* CA certificate has empty subject. */ - return false; } } return true; diff --git a/OSX/sec/Security/SecRSAKey.c b/OSX/sec/Security/SecRSAKey.c index 842ad6c8..0998b0eb 100644 --- a/OSX/sec/Security/SecRSAKey.c +++ b/OSX/sec/Security/SecRSAKey.c @@ -78,9 +78,8 @@ static void SecRSAPublicKeyDestroy(SecKeyRef key) { /* Zero out the public key */ if (key->key) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - cc_clear(ccrsa_pub_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(pubkey))), pubkey.pub); + ccrsa_pub_ctx_t pubkey = key->key; + cc_clear(ccrsa_pub_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(pubkey))), pubkey); free(key->key); key->key = NULL; } @@ -170,7 +169,7 @@ static OSStatus SecRSAPublicKeyInit(SecKeyRef key, key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); require_action_quiet(key->key, errOut, result = errSecAllocate); - pubkey.pub = key->key; + pubkey = key->key; ccrsa_ctx_n(pubkey) = size_n; require_noerr_quiet(ccrsa_import_pub(pubkey, keyDataLength, keyData), errOut); @@ -186,7 +185,7 @@ static OSStatus SecRSAPublicKeyInit(SecKeyRef key, key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); require_action_quiet(key->key, errOut, result = errSecAllocate); - pubkey.pub = key->key; + pubkey = key->key; ccrsa_ctx_n(pubkey) = size_n; result = ccrsa_pub_decode_apple(pubkey, keyDataLength, keyData); @@ -200,7 +199,7 @@ static OSStatus SecRSAPublicKeyInit(SecKeyRef key, key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); require_action_quiet(key->key, errOut, result = errSecAllocate); - pubkey.pub = key->key; + pubkey = key->key; ccrsa_ctx_n(pubkey) = size_n; require_noerr_quiet(ccrsa_pub_init(pubkey, @@ -212,18 +211,17 @@ static OSStatus SecRSAPublicKeyInit(SecKeyRef key, } case kSecExtractPublicFromPrivate: { - ccrsa_full_ctx_t fullKey; - fullKey.full = (ccrsa_full_ctx*) keyData; - + ccrsa_full_ctx_t fullKey = (ccrsa_full_ctx_t) keyData; + size_n = ccrsa_ctx_n(fullKey); key->key = calloc(1, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); require_action_quiet(key->key, errOut, result = errSecAllocate); - pubkey.pub = key->key; + pubkey = key->key; ccrsa_ctx_n(pubkey) = size_n; - memcpy(pubkey.pub, ccrsa_ctx_public(fullKey).pub, ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); + memcpy(pubkey, ccrsa_ctx_public(fullKey), ccrsa_pub_ctx_size(ccn_sizeof_n(size_n))); result = errSecSuccess; break; } @@ -241,8 +239,7 @@ static CFTypeRef SecRSAPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperati CFTypeRef result; require_action_quiet(CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRawCCUnit), out, result = kCFNull); - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccrsa_pub_ctx_t pubkey = key->key; result = kCFBooleanTrue; int ccerr = 0; switch (operation) { @@ -275,14 +272,13 @@ static CFTypeRef SecRSAPublicKeyCopyOperationResult(SecKeyRef key, SecKeyOperati } require_noerr_action_quiet(ccerr, out, (CFReleaseNull(result), - SecError(errSecParam, error, CFSTR("rsa_pub_crypt failed, ccerr=%d"), error))); + SecError(errSecParam, error, CFSTR("rsa_pub_crypt failed, ccerr=%d"), ccerr))); out: return result; } static size_t SecRSAPublicKeyBlockSize(SecKeyRef key) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccrsa_pub_ctx_t pubkey = key->key; return ccrsa_block_size(pubkey); } @@ -314,8 +310,7 @@ static CFDataRef SecRSAPublicKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_pub_ static OSStatus SecRSAPublicKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccrsa_pub_ctx_t pubkey = key->key; CFAllocatorRef allocator = CFGetAllocator(key); *serialized = SecRSAPublicKeyCreatePKCS1(allocator, pubkey); @@ -336,8 +331,7 @@ static CFDictionaryRef SecRSAPublicKeyCopyAttributeDictionary(SecKeyRef key) { } static CFDataRef SecRSAPublicKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccrsa_pub_ctx_t pubkey = key->key; return SecRSAPublicKeyCreatePKCS1(CFGetAllocator(key), pubkey); } @@ -346,8 +340,7 @@ static CFStringRef SecRSAPublicKeyCopyDescription(SecKeyRef key) { CFStringRef keyDescription = NULL; CFDataRef modRef = SecKeyCopyModulus(key); - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccrsa_pub_ctx_t pubkey = key->key; CFStringRef modulusString = CFDataCopyHexString(modRef); require_quiet(modulusString, fail); @@ -395,8 +388,7 @@ SecKeyRef SecKeyCreateRSAPublicKey(CFAllocatorRef allocator, CFDataRef SecKeyCopyModulus(SecKeyRef key) { CFDataRef modulus = NULL; if (key->key_class == &kSecRSAPublicKeyDescriptor) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccrsa_pub_ctx_t pubkey = key->key; size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); @@ -424,8 +416,7 @@ CFDataRef SecKeyCopyModulus(SecKeyRef key) { CFDataRef SecKeyCopyExponent(SecKeyRef key) { CFDataRef exponent = NULL; if (key->key_class == &kSecRSAPublicKeyDescriptor) { - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; + ccrsa_pub_ctx_t pubkey = key->key; size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); @@ -461,9 +452,8 @@ CFDataRef SecKeyCopyExponent(SecKeyRef key) { static void SecRSAPrivateKeyDestroy(SecKeyRef key) { /* Zero out the public key */ if (key->key) { - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; - cc_clear(ccrsa_full_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(fullkey))), fullkey.full); + ccrsa_full_ctx_t fullkey = key->key; + cc_clear(ccrsa_full_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(fullkey))), fullkey); free(key->key); key->key = NULL; } @@ -485,7 +475,7 @@ static OSStatus SecRSAPrivateKeyInit(SecKeyRef key, const uint8_t *keyData, CFIn key->key = calloc(1, ccrsa_full_ctx_size(ccn_sizeof_n(size_n))); require_action_quiet(key->key, errOut, result = errSecAllocate); - fullkey.full = key->key; + fullkey = key->key; ccrsa_ctx_n(fullkey) = size_n; require_quiet(ccrsa_import_priv(fullkey, keyDataLength, keyData)==0, errOut); @@ -511,12 +501,12 @@ static OSStatus SecRSAPrivateKeyInit(SecKeyRef key, const uint8_t *keyData, CFIn key->key = calloc(1, ccrsa_full_ctx_size(ccn_sizeof_n(size_n))); require_action_quiet(key->key, errOut, result = errSecAllocate); - fullkey.full = key->key; + fullkey = key->key; ccrsa_ctx_n(fullkey) = size_n; /* TODO: Add support for kSecPublicExponent parameter. */ static uint8_t e[] = { 0x01, 0x00, 0x01 }; // Default is 65537 - if (!ccrsa_generate_fips186_key(keyLengthInBits, fullkey.full, sizeof(e), e, ccrng_seckey,ccrng_seckey)) + if (!ccrsa_generate_fips186_key(keyLengthInBits, fullkey, sizeof(e), e, ccrng_seckey,ccrng_seckey)) result = errSecSuccess; break; } @@ -532,7 +522,7 @@ static CFTypeRef SecRSAPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperat CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { CFTypeRef result = kCFNull; - ccrsa_full_ctx_t fullkey = { .full = key->key }; + ccrsa_full_ctx_t fullkey = key->key; int ccerr = 0; switch (operation) { case kSecKeyOperationTypeSign: @@ -543,7 +533,7 @@ static CFTypeRef SecRSAPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperat require_action_quiet(ccn_cmpn(ccn_nof_size(CFDataGetLength(in1)), (const cc_unit *)CFDataGetBytePtr(in1), ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)) < 0, out, (result = NULL, - SecError(errSecParam, error, CFSTR("%@: sign - digest too big (%d bytes)"), + SecError(errSecParam, error, CFSTR("%@: sign - digest too big (%d bytes)"), key, (int)CFDataGetLength(in1)))); // Encrypt buffer and write it to output data. @@ -560,7 +550,7 @@ static CFTypeRef SecRSAPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperat if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRawCCUnit)) { if (mode == kSecKeyOperationModePerform) { // Decrypt buffer and write it to output data. - result = CFDataCreateMutableWithScratch(NULL, ccrsa_block_size(fullkey)); + result = CFDataCreateMutableWithScratch(NULL, ccrsa_block_size(ccrsa_ctx_public(fullkey))); ccerr = ccrsa_priv_crypt(fullkey, (cc_unit *)CFDataGetMutableBytePtr((CFMutableDataRef)result), (const cc_unit *)CFDataGetBytePtr(in1)); } else { @@ -574,14 +564,13 @@ static CFTypeRef SecRSAPrivateKeyCopyOperationResult(SecKeyRef key, SecKeyOperat } require_noerr_action_quiet(ccerr, out, (CFReleaseNull(result), - SecError(errSecParam, error, CFSTR("rsa_priv_crypt failed, ccerr=%d"), error))); + SecError(errSecParam, error, CFSTR("rsa_priv_crypt failed, ccerr=%d"), ccerr))); out: return result; } static size_t SecRSAPrivateKeyBlockSize(SecKeyRef key) { - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; + ccrsa_full_ctx_t fullkey = key->key; return ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); } @@ -610,8 +599,7 @@ static CFDataRef SecRSAPrivateKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_ful static CFDataRef SecRSAPrivateKeyCopyPKCS1(SecKeyRef key) { - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; + ccrsa_full_ctx_t fullkey = key->key; CFAllocatorRef allocator = CFGetAllocator(key); return SecRSAPrivateKeyCreatePKCS1(allocator, fullkey); @@ -619,11 +607,10 @@ static CFDataRef SecRSAPrivateKeyCopyPKCS1(SecKeyRef key) static OSStatus SecRSAPrivateKeyCopyPublicSerialization(SecKeyRef key, CFDataRef* serialized) { - ccrsa_full_ctx_t fullkey; - fullkey.full = key->key; + ccrsa_full_ctx_t fullkey = key->key; CFAllocatorRef allocator = CFGetAllocator(key); - *serialized = SecRSAPublicKeyCreatePKCS1(allocator, fullkey); + *serialized = SecRSAPublicKeyCreatePKCS1(allocator, ccrsa_ctx_public(fullkey)); if (NULL == *serialized) return errSecDecode; diff --git a/OSX/sec/Security/SecRecoveryKey.h b/OSX/sec/Security/SecRecoveryKey.h index 65fb59ee..15340051 100644 --- a/OSX/sec/Security/SecRecoveryKey.h +++ b/OSX/sec/Security/SecRecoveryKey.h @@ -19,9 +19,23 @@ SecRKRegisterBackupPublicKey(SecRecoveryKey *rk, CFErrorRef *error); #if __OBJC__ +/* + * Constants for the verifier dictionary returned from SecRKCopyAccountRecoveryVerifier + */ + +extern NSString *const kSecRVSalt; +extern NSString *const kSecRVIterations; +extern NSString *const kSecRVProtocol; +extern NSString *const kSecRVVerifier; +extern NSString *const kSecRVMasterID; + + SecRecoveryKey * SecRKCreateRecoveryKey(NSString *recoveryKey); +SecRecoveryKey * +SecRKCreateRecoveryKeyWithError(NSString *masterKey, NSError **error); + NSString * SecRKCreateRecoveryKeyString(NSError **error); @@ -34,6 +48,10 @@ SecRKCopyBackupFullKey(SecRecoveryKey *rk); NSData * SecRKCopyBackupPublicKey(SecRecoveryKey *rk); +NSDictionary * +SecRKCopyAccountRecoveryVerifier(NSString *recoveryKey, + NSError **error); + #else SecRecoveryKey * diff --git a/OSX/sec/Security/SecRecoveryKey.m b/OSX/sec/Security/SecRecoveryKey.m index d379a19e..0c8455b0 100644 --- a/OSX/sec/Security/SecRecoveryKey.m +++ b/OSX/sec/Security/SecRecoveryKey.m @@ -3,6 +3,8 @@ // #import "SecRecoveryKey.h" +#import + #import #import @@ -12,7 +14,15 @@ #import #import + #import +#import + +#if !TARGET_OS_BRIDGE +#include +#include +#define PATH_FOR_APPLEIDAUTHSUPPORTFRAMEWORK "/System/Library/PrivateFrameworks/AppleIDAuthSupport.framework/AppleIDAuthSupport" +#endif #import "SecCFAllocator.h" #import "SecPasswordGenerate.h" @@ -23,6 +33,9 @@ typedef struct _CFSecRecoveryKey *CFSecRecoveryKeyRef; static uint8_t backupPublicKey[] = { 'B', 'a', 'c', 'k', 'u', ' ', 'P', 'u', 'b', 'l', 'i', 'c', 'k', 'e', 'y' }; static uint8_t passwordInfoKey[] = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', ' ', 's', 'e', 'c', 'r', 'e', 't' }; +#if !(defined(__i386__) || TARGET_IPHONE_SIMULATOR || TARGET_OS_BRIDGE) +static uint8_t masterkeyIDSalt[] = { 'M', 'a', 's', 't', 'e', 'r', ' ', 'K', 'e', 'y', ' ', 'I', 'd', 'e', 't' }; +#endif #define RK_BACKUP_HKDF_SIZE 128 #define RK_PASSWORD_HKDF_SIZE 32 @@ -50,10 +63,18 @@ CFSecRecoveryKeyCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOption static bool -ValidateRecoveryKey(CFStringRef recoveryKey) +ValidateRecoveryKey(CFStringRef masterkey, NSError **error) { - - return SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, recoveryKey, NULL); + CFErrorRef cferror = NULL; + bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, masterkey, &cferror); + if (!res) { + if (error) { + *error = CFBridgingRelease(cferror); + } else { + CFReleaseNull(cferror); + } + } + return res; } @@ -71,7 +92,7 @@ SecRKCreateRecoveryKeyString(NSError **error) } return NULL; } - if (!ValidateRecoveryKey(recoveryKey)) { + if (!ValidateRecoveryKey(recoveryKey, error)) { CFRelease(recoveryKey); return NULL; } @@ -79,12 +100,18 @@ SecRKCreateRecoveryKeyString(NSError **error) return (__bridge NSString *)recoveryKey; } - SecRecoveryKey * SecRKCreateRecoveryKey(NSString *masterKey) { - if (!ValidateRecoveryKey((__bridge CFStringRef)masterKey)) + return SecRKCreateRecoveryKeyWithError(masterKey, NULL); +} + +SecRecoveryKey * +SecRKCreateRecoveryKeyWithError(NSString *masterKey, NSError **error) +{ + if (!ValidateRecoveryKey((__bridge CFStringRef)masterKey, error)) { return NULL; + } CFSecRecoveryKeyRef rk = CFTypeAllocate(CFSecRecoveryKey, struct _CFSecRecoveryKey, NULL); if (rk == NULL) @@ -160,29 +187,105 @@ fail: return (__bridge NSString *)base64Data; } -#if 0 -NSString * -SecRKCopyAccountRecoveryVerifier(SecRecoveryKey *rk, - NSString *type, - NSData *salt, - NSNumber *iterations, - NSError **error) -{ - /* use verifier create function from AppleIDAuthSupport with dlopen/dlsym +// We should gen salt/iteration - use S2K for kdf for the time being +// Pass back a dictionary of the parms +// +// Need companion call to respond with MRK on the "iforgot" sequence. + +NSString *const kSecRVSalt = @"s"; +NSString *const kSecRVIterations = @"i"; +NSString *const kSecRVProtocol = @"p"; +NSString *const kSecRVVerifier = @"v"; +NSString *const kSecRVMasterID = @"mkid"; + +#if !TARGET_OS_BRIDGE + +CFStringRef localProtocolSRPGROUP; +CFDataRef (*localAppleIDauthSupportCreateVerifierPtr) (CFStringRef proto, + CFStringRef username, + CFDataRef salt, + CFNumberRef iter, + CFStringRef password, + CFErrorRef *error); + +#if !(defined(__i386__) || TARGET_IPHONE_SIMULATOR) +static CFStringRef getdlsymforString(void *framework, const char *symbol) { + CFStringRef retval = NULL; + void *tmpptr = dlsym(framework, symbol); + if(tmpptr) { + retval = *(CFStringRef*) tmpptr; + } + return retval; +} - CFDataRef - AppleIDAuthSupportCreateVerifier(CFStringRef proto, - CFStringRef username, - CFDataRef salt, - CFNumberRef iter, - CFStringRef password, - CFErrorRef *error); - */ +static bool connectAppleIDFrameworkSymbols(void) { + static dispatch_once_t onceToken; + static void* framework = NULL; + dispatch_once(&onceToken, ^{ + localAppleIDauthSupportCreateVerifierPtr = NULL; + localProtocolSRPGROUP = NULL; + framework = dlopen(PATH_FOR_APPLEIDAUTHSUPPORTFRAMEWORK, RTLD_NOW); + if(framework) { + localProtocolSRPGROUP = getdlsymforString(framework, + "kAppleIDAuthSupportProtocolSRPGROUP2048SHA256PBKDF"); + localAppleIDauthSupportCreateVerifierPtr = + dlsym(framework, "AppleIDAuthSupportCreateVerifier"); + } + }); + return (framework != NULL && localProtocolSRPGROUP != NULL && + localAppleIDauthSupportCreateVerifierPtr != NULL); +} +#endif +#endif +NSDictionary * +SecRKCopyAccountRecoveryVerifier(NSString *recoveryKey, + NSError **error) { + +#if defined(__i386__) || TARGET_IPHONE_SIMULATOR || TARGET_OS_BRIDGE + abort(); return NULL; -} +#else + CFErrorRef localError = NULL; + CFStringRef username = CFSTR("foo"); + NSDictionary *retval = nil; + if(!connectAppleIDFrameworkSymbols()) { + SOSCreateError(kSOSErrorUnsupported, CFSTR("Recovery Key Creation Not Supported on this platform"), NULL, &localError); + if(error) *error = (__bridge_transfer NSError *) localError; + return NULL; + } + + NSData *salt = (__bridge_transfer NSData*) CFDataCreateWithRandomBytes(32); + NSNumber *iterations = @40000; + NSString *protocol = (__bridge NSString*) localProtocolSRPGROUP; + NSData *verifier = (__bridge_transfer NSData*) localAppleIDauthSupportCreateVerifierPtr( + localProtocolSRPGROUP, + username, + (__bridge CFDataRef) salt, + (__bridge CFNumberRef) iterations, + (__bridge CFStringRef) (recoveryKey), + &localError); + SecRecoveryKey *srk = SecRKCreateRecoveryKey(recoveryKey); + NSData *masterKeyID = (__bridge_transfer NSData*) SecRKCreateDerivedSecret( + (__bridge CFSecRecoveryKeyRef) srk, + RK_PASSWORD_HKDF_SIZE, + masterkeyIDSalt, + sizeof(masterkeyIDSalt)); + if(verifier && masterKeyID) { + retval = @{ kSecRVSalt: salt, + kSecRVIterations: iterations, + kSecRVProtocol: protocol, + kSecRVVerifier: verifier, + kSecRVMasterID: masterKeyID }; + + } else { + if(error && localError) *error = (__bridge NSError *) localError; + } + return retval; #endif +} + static NSData * RKBackupCreateECKey(SecRecoveryKey *rk, bool fullkey) { @@ -205,7 +308,7 @@ RKBackupCreateECKey(SecRecoveryKey *rk, bool fullkey) fullKey); require_noerr(status, fail); - size_t space = ccec_compact_export_size(fullkey, fullKey); + size_t space = ccec_compact_export_size(fullkey, ccec_ctx_pub(fullKey)); publicKeyData = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), space); require_quiet(publicKeyData, fail); @@ -241,6 +344,7 @@ SecRKRegisterBackupPublicKey(SecRecoveryKey *rk, CFErrorRef *error) require(backupKey, fail); res = SOSCCRegisterRecoveryPublicKey(backupKey, error); + fail: CFReleaseNull(backupKey); diff --git a/OSX/sec/Security/SecServerEncryptionSupport.c b/OSX/sec/Security/SecServerEncryptionSupport.c index f8152b51..b2bee3e0 100644 --- a/OSX/sec/Security/SecServerEncryptionSupport.c +++ b/OSX/sec/Security/SecServerEncryptionSupport.c @@ -41,7 +41,9 @@ static void InitServerECIES(ccecies_gcm_t ecies, const struct ccmode_gcm *gcm_mo gcm_mode, kBlobCipherKeySize, kBlobMacSize, - ECIES_EXPORT_PUB_STANDARD+ECIES_EPH_PUBKEY_IN_SHAREDINFO1); + ECIES_EXPORT_PUB_STANDARD + +ECIES_EPH_PUBKEY_IN_SHAREDINFO1 + +ECIES_LEGACY_IV); } // @@ -189,7 +191,7 @@ fail: static size_t ccec_x963_pub_export_size(ccec_pub_ctx_t key) { - return ccec_x963_export_size(0,(ccec_full_ctx_t)key.body); // We lie since the API is broken. + return ccec_x963_export_size(0,key); } CFDataRef SecCopyEncryptedToServerKey(SecKeyRef publicKey, CFDataRef dataToEncrypt, CFErrorRef *error) @@ -226,7 +228,7 @@ CFDataRef SecCopyEncryptedToServerKey(SecKeyRef publicKey, CFDataRef dataToEncry size_t tag_size = kBlobMacSize; uint8_t *tag = NULL; - require_action_quiet(public_key_size + ciphertext_size + tag_size == encrypted_size, errout, SecError(errSecInternal, error, CFSTR("Allocation mismatch"), encrypt_result)); + require_action_quiet(public_key_size + ciphertext_size + tag_size == encrypted_size, errout, SecError(errSecInternal, error, CFSTR("Allocation mismatch"))); encrypted = CreateDataForEncodeEncryptedBlobOf(public_key, public_key_size, &public_key_data, diff --git a/OSX/sec/Security/SecServerEncryptionSupport.h b/OSX/sec/Security/SecServerEncryptionSupport.h index 54dedc5a..4f12baee 100644 --- a/OSX/sec/Security/SecServerEncryptionSupport.h +++ b/OSX/sec/Security/SecServerEncryptionSupport.h @@ -11,17 +11,24 @@ #include #include +// Deprecating for security motives (28715251). +// Compatible implementation still available in SecKey with +// kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM but should also be +// deprecated for the same reason (28496795). + CFDataRef SecCopyEncryptedToServer(SecTrustRef trustedEvaluation, CFDataRef dataToEncrypt, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_8_0); + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_12, __MAC_10_13, __IPHONE_8_0, __IPHONE_11_0, "Migrate to SecKeyCreateEncryptedData with kSecKeyAlgorithmECIESEncryptionStandardVariableIV* or Security Foundation SFIESOperation for improved security (encryption is not compatible)"); // // For testing // /* Caution: These functions take an iOS SecKeyRef. Careful use is required on OS X. */ CFDataRef SecCopyDecryptedForServer(SecKeyRef serverFullKey, CFDataRef encryptedData, CFErrorRef* error) - __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0); + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_NA, __MAC_NA, __IPHONE_8_0, __IPHONE_11_0,"Migrate to SecKeyCreateEncryptedData with kSecKeyAlgorithmECIESEncryptionStandardVariableIV* or Security Foundation SFIESOperation for improved security (encryption is not compatible)"); +// SFIESCiphertext + CFDataRef SecCopyEncryptedToServerKey(SecKeyRef publicKey, CFDataRef dataToEncrypt, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_8_0); + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_12, __MAC_10_13, __IPHONE_8_0, __IPHONE_11_0,"Migrate to SecKeyCreateEncryptedData with kSecKeyAlgorithmECIESEncryptionStandardVariableIV* or Security Foundation SFIESOperation for improved security (encryption is not compatible)"); #endif diff --git a/OSX/sec/Security/SecSharedCredential.c b/OSX/sec/Security/SecSharedCredential.c index 97c43792..3faa8f6f 100644 --- a/OSX/sec/Security/SecSharedCredential.c +++ b/OSX/sec/Security/SecSharedCredential.c @@ -105,7 +105,7 @@ void SecAddSharedWebCredential(CFStringRef fqdn, errStr = CFSTR("non-nil password was not of type CFString"); } if (errStr) { - SecError(errSecParam, &error, errStr); + SecError(errSecParam, &error, CFSTR("%@"), errStr); dispatch_async(dst_queue, ^{ if (completionHandler) { completionHandler(error); @@ -212,7 +212,7 @@ void SecRequestSharedWebCredential(CFStringRef fqdn, errStr = CFSTR("account was empty or not a CFString"); } if (errStr) { - SecError(errSecParam, &error, errStr); + SecError(errSecParam, &error, CFSTR("%@"), errStr); dispatch_async(dst_queue, ^{ if (completionHandler) { completionHandler(result, error); diff --git a/OSX/sec/Security/SecTrust.c b/OSX/sec/Security/SecTrust.c index 6768a063..a4c839a7 100644 --- a/OSX/sec/Security/SecTrust.c +++ b/OSX/sec/Security/SecTrust.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -67,12 +67,14 @@ #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); +SEC_CONST_DECL (kSecCertificateDetailSHA1Digest, "SHA1Digest"); +SEC_CONST_DECL (kSecCertificateDetailStatusCodes, "StatusCodes"); + SEC_CONST_DECL (kSecTrustInfoExtendedValidationKey, "ExtendedValidation"); SEC_CONST_DECL (kSecTrustInfoCompanyNameKey, "CompanyName"); SEC_CONST_DECL (kSecTrustInfoRevocationKey, "Revocation"); SEC_CONST_DECL (kSecTrustInfoRevocationValidUntilKey, "RevocationValidUntil"); SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyKey, "CertificateTransparency"); -SEC_CONST_DECL (kSecTrustInfoCertificateTransparencyWhiteListKey, "CertificateTransparencyWhiteList"); /* Public trust result constants */ SEC_CONST_DECL (kSecTrustEvaluationDate, "TrustEvaluationDate"); @@ -128,11 +130,6 @@ struct __SecTrust { void* _legacy_info_array; void* _legacy_status_array; - /* The trust result as determined by the trust server, - * before the caller's exceptions are applied. - */ - SecTrustResultType _trustResultBeforeExceptions; - /* Dispatch queue for thread-safety */ dispatch_queue_t _trustQueue; @@ -189,14 +186,26 @@ OSStatus SecTrustCreateWithCertificates(CFTypeRef certificates, CFAllocatorRef allocator = kCFAllocatorDefault; CFArrayRef l_certs = NULL, l_policies = NULL; SecTrustRef result = NULL; + dispatch_queue_t queue = NULL; - check(certificates); - check(trust); + check(certificates); + check(trust); CFTypeID certType = CFGetTypeID(certificates); if (certType == CFArrayGetTypeID()) { + CFIndex idx, count = CFArrayGetCount(certificates); /* We need at least 1 certificate. */ - require_quiet(CFArrayGetCount(certificates) > 0, errOut); - l_certs = CFArrayCreateCopy(allocator, certificates); + require_quiet(count > 0, errOut); + l_certs = (CFArrayRef) CFArrayCreateMutable(allocator, count, + &kCFTypeArrayCallBacks); + if (!l_certs) { + status = errSecAllocate; + goto errOut; + } + for (idx = 0; idx < count; idx++) { + CFTypeRef val = CFArrayGetValueAtIndex(certificates, idx); + if (val) { CFArrayAppendValue((CFMutableArrayRef)l_certs, val); } + } + require_quiet(count == CFArrayGetCount(l_certs), errOut); } else if (certType == SecCertificateGetTypeID()) { l_certs = CFArrayCreate(allocator, &certificates, 1, &kCFTypeArrayCallBacks); @@ -208,18 +217,31 @@ OSStatus SecTrustCreateWithCertificates(CFTypeRef certificates, goto errOut; } - if (!policies) { - CFTypeRef policy = SecPolicyCreateBasicX509(); - l_policies = CFArrayCreate(allocator, &policy, 1, - &kCFTypeArrayCallBacks); - CFRelease(policy); - } - else if (CFGetTypeID(policies) == CFArrayGetTypeID()) { - l_policies = CFArrayCreateCopy(allocator, policies); - } - else if (CFGetTypeID(policies) == SecPolicyGetTypeID()) { - l_policies = CFArrayCreate(allocator, &policies, 1, - &kCFTypeArrayCallBacks); + if (!policies) { + CFTypeRef policy = SecPolicyCreateBasicX509(); + l_policies = CFArrayCreate(allocator, &policy, 1, + &kCFTypeArrayCallBacks); + CFRelease(policy); + } + else if (CFGetTypeID(policies) == CFArrayGetTypeID()) { + CFIndex idx, count = CFArrayGetCount(policies); + /* We need at least 1 policy. */ + require_quiet(count > 0, errOut); + l_policies = (CFArrayRef) CFArrayCreateMutable(allocator, count, + &kCFTypeArrayCallBacks); + if (!l_policies) { + status = errSecAllocate; + goto errOut; + } + for (idx = 0; idx < count; idx++) { + CFTypeRef val = CFArrayGetValueAtIndex(policies, idx); + if (val) { CFArrayAppendValue((CFMutableArrayRef)l_policies, val); } + } + require_quiet(count == CFArrayGetCount(l_policies), errOut); + } + else if (CFGetTypeID(policies) == SecPolicyGetTypeID()) { + l_policies = CFArrayCreate(allocator, &policies, 1, + &kCFTypeArrayCallBacks); } else { goto errOut; } @@ -228,6 +250,12 @@ OSStatus SecTrustCreateWithCertificates(CFTypeRef certificates, goto errOut; } + queue = dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL); + if (!queue) { + status = errSecAllocate; + goto errOut; + } + CFIndex size = sizeof(struct __SecTrust); require_quiet(result = (SecTrustRef)_CFRuntimeCreateInstance(allocator, SecTrustGetTypeID(), size - sizeof(CFRuntimeBase), 0), errOut); @@ -240,11 +268,12 @@ errOut: CFReleaseSafe(result); CFReleaseSafe(l_certs); CFReleaseSafe(l_policies); + dispatch_release_null(queue); } else { result->_certificates = l_certs; result->_policies = l_policies; result->_keychainsAllowed = true; - result->_trustQueue = dispatch_queue_create("trust", DISPATCH_QUEUE_SERIAL); + result->_trustQueue = queue; if (trust) *trust = result; else @@ -300,7 +329,6 @@ static void SecTrustSetNeedsEvaluation(SecTrustRef trust) { if (trust) { dispatch_sync(trust->_trustQueue, ^{ trust->_trustResult = kSecTrustResultInvalid; - trust->_trustResultBeforeExceptions = kSecTrustResultInvalid; }); } } @@ -322,12 +350,31 @@ OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, return errSecParam; } SecTrustSetNeedsEvaluation(trust); - if (anchorCertificates) - CFRetain(anchorCertificates); + __block CFArrayRef anchorsArray = NULL; + if (anchorCertificates) { + if (CFGetTypeID(anchorCertificates) == CFArrayGetTypeID()) { + CFIndex idx, count = CFArrayGetCount(anchorCertificates); + anchorsArray = (CFArrayRef) CFArrayCreateMutable(NULL, count, + &kCFTypeArrayCallBacks); + if (!anchorsArray) { + return errSecAllocate; + } + for (idx = 0; idx < count; idx++) { + CFTypeRef val = CFArrayGetValueAtIndex(anchorCertificates, idx); + if (val) { CFArrayAppendValue((CFMutableArrayRef)anchorsArray, val); } + } + if (count != CFArrayGetCount(anchorsArray)) { + CFReleaseSafe(anchorsArray); + return errSecParam; + } + } else { + return errSecParam; + } + } + dispatch_sync(trust->_trustQueue, ^{ - if (trust->_anchors) - CFRelease(trust->_anchors); - trust->_anchors = anchorCertificates; + CFReleaseSafe(trust->_anchors); + trust->_anchors = anchorsArray; }); trust->_anchorsOnly = (anchorCertificates != NULL); @@ -336,10 +383,10 @@ OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust, CFArrayRef *anchors) { - if (!trust|| !anchors) { - return errSecParam; - } - __block CFArrayRef anchorsArray = NULL; + if (!trust|| !anchors) { + return errSecParam; + } + __block CFArrayRef anchorsArray = NULL; dispatch_sync(trust->_trustQueue, ^{ if (trust->_anchors) { anchorsArray = CFArrayCreateCopy(kCFAllocatorDefault, trust->_anchors); @@ -354,11 +401,24 @@ OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) { if (!trust) { return errSecParam; } - SecTrustSetNeedsEvaluation(trust); - CFArrayRef responseArray = NULL; - if (responseData) { - if (CFGetTypeID(responseData) == CFArrayGetTypeID()) { - responseArray = CFArrayCreateCopy(kCFAllocatorDefault, responseData); + SecTrustSetNeedsEvaluation(trust); + __block CFArrayRef responseArray = NULL; + if (responseData) { + if (CFGetTypeID(responseData) == CFArrayGetTypeID()) { + CFIndex idx, count = CFArrayGetCount(responseData); + responseArray = (CFArrayRef) CFArrayCreateMutable(NULL, count, + &kCFTypeArrayCallBacks); + if (!responseArray) { + return errSecAllocate; + } + for (idx = 0; idx < count; idx++) { + CFTypeRef val = CFArrayGetValueAtIndex(responseData, idx); + if (val) { CFArrayAppendValue((CFMutableArrayRef)responseArray, val); } + } + if (count != CFArrayGetCount(responseArray)) { + CFReleaseSafe(responseArray); + return errSecParam; + } } else if (CFGetTypeID(responseData) == CFDataGetTypeID()) { responseArray = CFArrayCreate(kCFAllocatorDefault, &responseData, 1, &kCFTypeArrayCallBacks); @@ -366,12 +426,13 @@ OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) { return errSecParam; } } + dispatch_sync(trust->_trustQueue, ^{ - if (trust->_responses) - CFRelease(trust->_responses); + CFReleaseSafe(trust->_responses); trust->_responses = responseArray; }); - return errSecSuccess; + + return errSecSuccess; } OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef sctArray) { @@ -417,10 +478,27 @@ OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef newPolicies) { __block CFArrayRef policyArray = NULL; if (CFGetTypeID(newPolicies) == CFArrayGetTypeID()) { - policyArray = CFArrayCreateCopy(kCFAllocatorDefault, newPolicies); - } else if (CFGetTypeID(newPolicies) == SecPolicyGetTypeID()) { - policyArray = CFArrayCreate(kCFAllocatorDefault, &newPolicies, 1, - &kCFTypeArrayCallBacks); + CFIndex idx, count = CFArrayGetCount(newPolicies); + /* We need at least 1 policy. */ + if (!(count > 0)) { + return errSecParam; + } + policyArray = (CFArrayRef) CFArrayCreateMutable(NULL, count, + &kCFTypeArrayCallBacks); + if (!policyArray) { + return errSecAllocate; + } + for (idx = 0; idx < count; idx++) { + CFTypeRef val = CFArrayGetValueAtIndex(newPolicies, idx); + if (val) { CFArrayAppendValue((CFMutableArrayRef)policyArray, val); } + } + if (count != CFArrayGetCount(policyArray)) { + CFReleaseSafe(policyArray); + return errSecParam; + } + } else if (CFGetTypeID(newPolicies) == SecPolicyGetTypeID()) { + policyArray = CFArrayCreate(kCFAllocatorDefault, &newPolicies, 1, + &kCFTypeArrayCallBacks); } else { return errSecParam; } @@ -433,6 +511,22 @@ OSStatus SecTrustSetPolicies(SecTrustRef trust, CFTypeRef newPolicies) { return errSecSuccess; } +OSStatus SecTrustSetPinningPolicyName(SecTrustRef trust, CFStringRef policyName) { + if (!trust || !policyName) { + return errSecParam; + } + + SecTrustSetNeedsEvaluation(trust); + + dispatch_sync(trust->_trustQueue, ^{ + CFArrayForEach(trust->_policies, ^(const void *value) { + SecPolicyRef policy = (SecPolicyRef)value; + SecPolicySetName(policy, policyName); + }); + }); + return errSecSuccess; +} + OSStatus SecTrustSetKeychainsAllowed(SecTrustRef trust, Boolean allowed) { if (!trust) { return errSecParam; @@ -558,6 +652,15 @@ OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch) return errSecSuccess; } +OSStatus SecTrustSetPinningException(SecTrustRef trust) { + if (!trust) { return errSecParam; } + __block OSStatus status = errSecSuccess; + dispatch_sync(trust->_trustQueue, ^{ + status = SecTrustRemoveOptionInPolicies(trust->_policies, kSecPolicyCheckPinningRequired); + }); + return status; +} + CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) { __block CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent(); if (!trust) { @@ -575,26 +678,25 @@ CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) { } CFArrayRef SecTrustGetDetails(SecTrustRef trust) { - if (!trust) { - return NULL; - } + if (!trust) { + return NULL; + } SecTrustEvaluateIfNecessary(trust); return trust->_details; } OSStatus SecTrustGetTrustResult(SecTrustRef trust, SecTrustResultType *result) { - if (!trust || !result) { - return errSecParam; - } + if (!trust || !result) { + return errSecParam; + } + SecTrustEvaluateIfNecessary(trust); dispatch_sync(trust->_trustQueue, ^{ *result = trust->_trustResult; }); - return errSecSuccess; + return errSecSuccess; } -static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest"); - static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) { CFDictionaryRef exception = NULL; __block CFArrayRef exceptions = NULL; @@ -628,26 +730,6 @@ out: return exception; } -struct SecTrustFilteredDetailContext { - CFDictionaryRef exception; - CFMutableDictionaryRef filteredDetail; -}; - -static void SecTrustFilterDetail(const void *key, const void *value, void *context) { - struct SecTrustFilteredDetailContext *ctx = (struct SecTrustFilteredDetailContext *)context; - if (!key || !value || !ctx->exception || !ctx->filteredDetail) { - return; - } - if (CFEqual(kSecCertificateDetailSHA1Digest, key)) { - return; /* ignore SHA1 hash entry */ - } - CFTypeRef exceptionValue = CFDictionaryGetValue(ctx->exception, key); - if (exceptionValue && CFEqual(exceptionValue, value)) { - /* both key and value match the exception */ - CFDictionaryRemoveValue(ctx->filteredDetail, key); - } -} - CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust) { if (!trust) { return NULL; @@ -657,48 +739,44 @@ CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust) { dispatch_sync(trust->_trustQueue, ^{ details = CFRetainSafe(trust->_details); }); - CFIndex ix, pathLength = details ? CFArrayGetCount(details) : 0; - CFMutableArrayRef filteredDetails = CFArrayCreateMutable(kCFAllocatorDefault, pathLength, &kCFTypeArrayCallBacks); - if (!filteredDetails) { - CFReleaseNull(details); - return NULL; - } - for (ix = 0; ix < pathLength; ++ix) { - CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); - CFIndex count = (detail) ? CFDictionaryGetCount(detail) : 0; - CFMutableDictionaryRef filteredDetail = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, count, detail); - CFDictionaryRef exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix); - if (exception) { - /* for each entry in the detail dictionary, remove from filteredDetail - if it also appears in the corresponding exception dictionary. */ - struct SecTrustFilteredDetailContext context = { exception, filteredDetail }; - CFDictionaryApplyFunction(detail, SecTrustFilterDetail, &context); - } - if (filteredDetail) { - CFArrayAppendValue(filteredDetails, filteredDetail); - CFReleaseSafe(filteredDetail); - } - } - CFReleaseNull(details); - return filteredDetails; -} -struct SecTrustCheckExceptionContext { - CFDictionaryRef exception; - bool exceptionNotFound; + /* Done automatically by the Policy Server with SecPVCIsExceptedError */ + return details; +} -}; +Boolean SecTrustIsExpiredOnly(SecTrustRef trust) { + /* Returns true if one or more certificates in the chain have expired, + * expiration is an error (i.e. is not covered by existing trust settings), + * and it is the only error encountered. + * Returns false if the certificate is valid, or if the trust chain has + * other errors beside expiration. + */ + Boolean result = false; + Boolean foundExpired = false; + CFArrayRef details = SecTrustCopyFilteredDetails(trust); + require(details != NULL, out); -static void SecTrustCheckException(const void *key, const void *value, void *context) { - struct SecTrustCheckExceptionContext *cec = (struct SecTrustCheckExceptionContext *)context; - if (cec->exception) { - CFTypeRef exceptionValue = CFDictionaryGetValue(cec->exception, key); - if (!exceptionValue || !CFEqual(value, exceptionValue)) { - cec->exceptionNotFound = true; + CFIndex ix, pathLength = CFArrayGetCount(details); + for (ix = 0; ix < pathLength; ++ix) { + CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); + CFIndex count = (detail) ? CFDictionaryGetCount(detail) : 0; + require(count <= 1, out); + if (count) { + CFStringRef key = CFSTR("ValidIntermediates"); + if (ix == 0) { + key = CFSTR("ValidLeaf"); + } else if (ix == pathLength-1) { + key = CFSTR("ValidRoot"); + } + CFBooleanRef valid = (CFBooleanRef)CFDictionaryGetValue(detail, key); + require(isBoolean(valid) && CFEqual(valid, kCFBooleanFalse), out); + foundExpired = true; } - } else { - cec->exceptionNotFound = true; } + result = foundExpired; +out: + CFReleaseSafe(details); + return result; } #if TARGET_OS_IPHONE @@ -730,7 +808,7 @@ static void SecTrustAddPolicyAnchors(SecTrustRef trust) for (ix = 0; ix < count; ++ix) { SecPolicyRef policy = (SecPolicyRef) CFArrayGetValueAtIndex(policies, ix); if (policy) { - #if TARGET_OS_IPHONE + #if TARGET_OS_IPHONE if (CFEqual(policy->_oid, kSecPolicyAppleTestSMPEncryption)) { __block CFArrayRef policyAnchors = SecTrustCreatePolicyAnchorsArray(_SEC_TestAppleRootCAECC, sizeof(_SEC_TestAppleRootCAECC)); dispatch_sync(trust->_trustQueue, ^{ @@ -740,13 +818,12 @@ static void SecTrustAddPolicyAnchors(SecTrustRef trust) trust->_anchorsOnly = true; break; } - #endif + #endif } } CFReleaseSafe(policies); } - // uncomment for verbose debug logging (debug builds only) //#define CERT_TRUST_DUMP 1 @@ -825,6 +902,9 @@ static void cert_trust_dump(SecTrustRef trust) {} OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) { + if (result) { + *result = kSecTrustResultInvalid; + } if (!trust) { return errSecParam; } @@ -837,48 +917,9 @@ OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *result) { dispatch_sync(trust->_trustQueue, ^{ trustResult = trust->_trustResult; }); - if (trustResult == kSecTrustResultUnspecified) { - /* If leaf is in exceptions -> proceed, otherwise unspecified. */ - if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) - trustResult = kSecTrustResultProceed; - } else if (trustResult == kSecTrustResultRecoverableTrustFailure) { - /* If we have exceptions get details and match to exceptions. */ - __block CFArrayRef details = NULL; - dispatch_sync(trust->_trustQueue, ^{ - details = CFRetainSafe(trust->_details); - }); - CFIndex pathLength = details ? CFArrayGetCount(details) : 0; - struct SecTrustCheckExceptionContext context = {}; - CFIndex ix; - for (ix = 0; ix < pathLength; ++ix) { - CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); - context.exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix); - CFDictionaryApplyFunction(detail, SecTrustCheckException, &context); - if (context.exceptionNotFound) { - break; - } - } - CFReleaseSafe(details); - __block bool done = false; - dispatch_sync(trust->_trustQueue, ^{ - if (!trust->_exceptions || !CFArrayGetCount(trust->_exceptions)) { - done = true; - } - }); - if (done) { - goto DoneCheckingTrust; - } - if (!context.exceptionNotFound) - trustResult = kSecTrustResultProceed; - } -DoneCheckingTrust: - dispatch_sync(trust->_trustQueue, ^{ - trust->_trustResult = trustResult; - }); /* log to syslog when there is a trust failure */ if (trustResult != kSecTrustResultProceed && - trustResult != kSecTrustResultConfirm && trustResult != kSecTrustResultUnspecified) { CFStringRef failureDesc = SecTrustCopyFailureDescription(trust); secerror("%{public}@", failureDesc); @@ -1028,7 +1069,12 @@ static int SecXPCDictionaryGetNonZeroInteger(xpc_object_t message, const char *k return (int)value; } -static SecTrustResultType certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request(enum SecXPCOperation op, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error) +static SecTrustResultType handle_trust_evaluate_xpc(enum SecXPCOperation op, CFArrayRef certificates, + CFArrayRef anchors, bool anchorsOnly, + bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, + CFArrayRef SCTs, CFArrayRef trustedLogs, + CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, + CFArrayRef *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error) { __block SecTrustResultType tr = kSecTrustResultInvalid; securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { @@ -1048,6 +1094,8 @@ static SecTrustResultType certs_anchors_bool_bool_policies_responses_scts_logs_d if (trustedLogs && !SecXPCDictionarySetPList(message, kSecTrustTrustedLogsKey, trustedLogs, error)) return false; xpc_dictionary_set_double(message, kSecTrustVerifyDateKey, verifyTime); + if (exceptions && !SecXPCDictionarySetPList(message, kSecTrustExceptionsKey, exceptions, error)) + return false; return true; }, ^bool(xpc_object_t response, CFErrorRef *error) { secdebug("trust", "response: %@", response); @@ -1130,25 +1178,6 @@ static OSStatus SecTrustValidateInput(SecTrustRef trust) { return result; } - -static void SecTrustPostEvaluate(SecTrustRef trust) { - if (!trust) { return; } - - CFIndex pathLength = (trust->_details) ? CFArrayGetCount(trust->_details) : 0; - CFIndex ix; - for (ix = 0; ix < pathLength; ++ix) { - CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(trust->_details, ix); - if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf)) { - trust->_trustResult = kSecTrustResultFatalTrustFailure; - return; - } - if (CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedKey)) { - trust->_trustResult = kSecTrustResultFatalTrustFailure; - return; - } - } -} - static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) { __block OSStatus result; check(trust); @@ -1182,11 +1211,11 @@ static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) { /* @@@ Consider an optimization where we keep a side dictionary with the SHA1 hash of ever SecCertificateRef we send, so we only send potential duplicates once, and have the server respond with either just the SHA1 hash of a certificate, or the complete certificate in the response depending on whether the client already sent it, so we don't send back certificates to the client it already has. */ result = SecOSStatusWith(^bool (CFErrorRef *error) { - trust->_trustResult = SECURITYD_XPC(sec_trust_evaluate, - certs_anchors_bool_bool_policies_responses_scts_logs_date_ag_to_details_info_chain_int_error_request, + trust->_trustResult = TRUSTD_XPC(sec_trust_evaluate, + handle_trust_evaluate_xpc, trust->_certificates, trust->_anchors, trust->_anchorsOnly, trust->_keychainsAllowed, trust->_policies, trust->_responses, trust->_SCTs, trust->_trustedLogs, - verifyTime, SecAccessGroupsGetCurrent(), + verifyTime, SecAccessGroupsGetCurrent(), trust->_exceptions, &trust->_details, &trust->_info, &trust->_chain, error); if (trust->_trustResult == kSecTrustResultInvalid /* TODO check domain */ && SecErrorGetOSStatus(*error) == errSecNotAvailable && @@ -1198,13 +1227,14 @@ static OSStatus SecTrustEvaluateIfNecessary(SecTrustRef trust) { _chain and return success with a failure as the trustResult, to make it seem like we did a cert evaluation, so ASR can extract the public key from the leaf. */ - trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0), NULL); + SecCertificateRef leafCert = (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0); + CFArrayRef leafCertArray = CFArrayCreate(NULL, (const void**)&leafCert, 1, &kCFTypeArrayCallBacks); + trust->_chain = SecCertificatePathCreateWithCertificates(leafCertArray, NULL); + CFReleaseNull(leafCertArray); if (error) CFReleaseNull(*error); return true; } - SecTrustPostEvaluate(trust); - trust->_trustResultBeforeExceptions = trust->_trustResult; return trust->_trustResult != kSecTrustResultInvalid; }); }); @@ -1348,10 +1378,28 @@ CFDictionaryRef SecTrustCopyInfo(SecTrustRef trust) { } CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) { - return trust->_exceptions; + if (!trust) { + return NULL; + } + __block CFArrayRef exceptions = NULL; + dispatch_sync(trust->_trustQueue, ^{ + exceptions = trust->_exceptions; + }); + return exceptions; } CFDataRef SecTrustCopyExceptions(SecTrustRef trust) { + /* Stash the old exceptions and run an evaluation with no exceptions filtered. */ + __block CFArrayRef oldExceptions = NULL; + dispatch_sync(trust->_trustQueue, ^{ + if (trust->_exceptions) { + oldExceptions = trust->_exceptions; + trust->_exceptions = NULL; + } + }); + SecTrustSetNeedsEvaluation(trust); + + /* Create the new exceptions based on an unfiltered eval. */ __block CFArrayRef details = NULL; SecTrustEvaluateIfNecessary(trust); dispatch_sync(trust->_trustQueue, ^{ @@ -1375,7 +1423,15 @@ CFDataRef SecTrustCopyExceptions(SecTrustRef trust) { &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } CFArrayAppendValue(exceptions, exception); - CFRelease(exception); + CFReleaseNull(exception); + } + + /* Restore the stashed exceptions. */ + if (oldExceptions) { + dispatch_sync(trust->_trustQueue, ^{ + trust->_exceptions = oldExceptions; + }); + SecTrustSetNeedsEvaluation(trust); } /* Remove any trailing empty dictionaries to save even more space (we skip the leaf @@ -1413,15 +1469,13 @@ bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) { } dispatch_sync(trust->_trustQueue, ^{ - if (trust->_exceptions && !exceptions) { - /* Exceptions are currently set and now we are clearing them. */ - trust->_trustResult = trust->_trustResultBeforeExceptions; - } - CFReleaseSafe(trust->_exceptions); trust->_exceptions = exceptions; }); + /* We changed the exceptions -- so we need to re-evaluate */ + SecTrustSetNeedsEvaluation(trust); + /* If there is a valid exception entry for our current leaf we're golden. */ if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) return true; @@ -1433,6 +1487,87 @@ bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) { return false; } +#if TARGET_OS_OSX +OSStatus +SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options) +{ + /* bridge to support API functionality for legacy callers */ + OSStatus status = errSecSuccess; + + /* No options or none that trigger the exceptions behavior */ + if (!options || + 0 == (options & (kSecTrustOptionAllowExpired | + kSecTrustOptionImplicitAnchors | + kSecTrustOptionAllowExpiredRoot))) { + return status; + } + + __block CFMutableArrayRef exceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!exceptions) { return errSecAllocate; } + + /* Add the new options to the old_exceptions when those exceptions are tied to a particular cert. + * If not tied to a particular cert, we reset the exceptions based on the input options. */ + CFArrayRef old_exceptions = SecTrustGetTrustExceptionsArray(trustRef); + if (old_exceptions && SecTrustGetExceptionForCertificateAtIndex(trustRef, 0)) { + CFIndex ix, count = CFArrayGetCount(old_exceptions); + for (ix = 0; ix < count; ix++) { + CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)CFArrayGetValueAtIndex(old_exceptions, ix)); + if (!exception_dictionary) { status = errSecAllocate; goto out; } + if ((options & kSecTrustOptionAllowExpired) != 0) { + if (ix == 0) { CFDictionaryAddValue(exception_dictionary, CFSTR("ValidLeaf"), kCFBooleanFalse); } + if (ix == (count - 1)) { CFDictionaryAddValue(exception_dictionary, CFSTR("ValidRoot"), kCFBooleanFalse); } + if (ix > 0 && ix < (count - 1)) { + CFDictionaryAddValue(exception_dictionary, CFSTR("ValidIntermediates"), kCFBooleanFalse); } + } + if ((options & kSecTrustOptionAllowExpiredRoot) != 0) { + if (ix == (count - 1)) { CFDictionaryAddValue(exception_dictionary, CFSTR("ValidRoot"), kCFBooleanFalse); } + } + if ((options & kSecTrustOptionImplicitAnchors) != 0) { + /* Check that root is self-signed. (Done by trustd for other case.) */ + Boolean isSelfSigned = false; + SecCertificateRef cert = SecTrustGetCertificateAtIndex(trustRef, ix); + if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) && + isSelfSigned) { + CFDictionaryAddValue(exception_dictionary, CFSTR("AnchorTrusted"), kCFBooleanFalse); + } + } + CFArrayAppendValue(exceptions, exception_dictionary); + CFReleaseNull(exception_dictionary); + } + } else { + /* Create a new exceptions array. Warning, this takes advantage of implementation details of the exceptions mechanism. */ + CFMutableDictionaryRef exception_dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!exception_dictionary) { status = errSecAllocate; goto out; } + if ((options & kSecTrustOptionAllowExpired) != 0) { + CFDictionaryAddValue(exception_dictionary, CFSTR("ValidLeaf"), kCFBooleanFalse); + CFDictionaryAddValue(exception_dictionary, CFSTR("ValidIntermediates"), kCFBooleanFalse); + CFDictionaryAddValue(exception_dictionary, CFSTR("ValidRoot"), kCFBooleanFalse); + } + if ((options & kSecTrustOptionAllowExpiredRoot) != 0) { + CFDictionaryAddValue(exception_dictionary, CFSTR("ValidRoot"), kCFBooleanFalse); + } + if ((options & kSecTrustOptionImplicitAnchors) != 0) { + CFDictionaryAddValue(exception_dictionary, CFSTR("AnchorTrusted"), kCFBooleanFalse); + } + CFArrayAppendValue(exceptions, exception_dictionary); + CFReleaseNull(exception_dictionary); + } + + /* Set exceptions */ + dispatch_sync(trustRef->_trustQueue, ^{ + CFReleaseSafe(trustRef->_exceptions); + trustRef->_exceptions = CFRetainSafe(exceptions); + }); + /* We changed the exceptions -- so we need to re-evaluate */ + SecTrustSetNeedsEvaluation(trustRef); + +out: + CFReleaseNull(exceptions); + return status; +} +#endif + CFArrayRef SecTrustCopySummaryPropertiesAtIndex(SecTrustRef trust, CFIndex ix) { CFMutableArrayRef summary; SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix); @@ -1618,10 +1753,10 @@ static void applyDetailProperty(const void *_key, const void *_value, static void appendError(CFMutableArrayRef properties, CFStringRef error) { CFStringRef localizedError = SecFrameworkCopyLocalizedString(error, CFSTR("SecCertificate")); - if (!localizedError) { - //secerror("WARNING: localized error string was not found in Security.framework"); - localizedError = CFRetain(error); - } + if (!localizedError) { + //secerror("WARNING: localized error string was not found in Security.framework"); + localizedError = CFRetain(error); + } appendProperty(properties, kSecPropertyTypeError, NULL, NULL, localizedError); CFReleaseNull(localizedError); @@ -1695,20 +1830,85 @@ CFArrayRef SecTrustCopyProperties(SecTrustRef trust) return properties; } +#if TARGET_OS_OSX +static void _AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode) { + if (!array) { + return; + } + SInt32 num = statusCode; + CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num); + if (!numRef) { + return; + } + CFArrayAppendValue(array, numRef); + CFRelease(numRef); +} +#endif + +static CFArrayRef _SecTrustCopyDetails(SecTrustRef trust) { + if (!trust) { + return NULL; + } + __block CFArrayRef details = NULL; + dispatch_sync(trust->_trustQueue, ^{ + details = CFRetainSafe(trust->_details); + }); +#if TARGET_OS_OSX + // Include status codes in the per-certificate details (rdar://27930542) + CFMutableArrayRef newDetails = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!newDetails) { + CFReleaseSafe(details); + return NULL; + } + CFIndex index, chainLen = (details) ? CFArrayGetCount(details) : 0; + for (index = 0; index < chainLen; index++) { + CFDictionaryRef detailDict = CFArrayGetValueAtIndex(details, index); + CFMutableDictionaryRef newDict = CFDictionaryCreateMutableCopy(NULL, 0, detailDict); + CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault, + 0, &kCFTypeArrayCallBacks); + if (statusCodes) { + CFIndex i, numCodes = 0; + SInt32 *codes = SecTrustCopyStatusCodes(trust, index, &numCodes); + if (codes) { + for (i = 0; i < numCodes; i++) { + OSStatus scode = (OSStatus)codes[i]; + _AppendStatusCode(statusCodes, scode); + } + free(codes); + } + if (CFArrayGetCount(statusCodes) > 0) { + CFDictionarySetValue(newDict, kSecCertificateDetailStatusCodes, statusCodes); + } + CFRelease(statusCodes); + } + if (newDict) { + CFArrayAppendValue(newDetails, newDict); + CFRelease(newDict); + } + } + CFReleaseSafe(details); + return newDetails; +#else + return details; +#endif +} + CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) { - // Builds and returns a dictionary of evaluation results. - if (!trust) { - return NULL; - } - __block CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + // Builds and returns a dictionary of evaluation results. + if (!trust) { + return NULL; + } + __block CFMutableDictionaryRef results = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); SecTrustEvaluateIfNecessary(trust); + __block CFArrayRef details = _SecTrustCopyDetails(trust); + dispatch_sync(trust->_trustQueue, ^{ // kSecTrustResultDetails (per-cert results) - CFArrayRef details = trust->_details; if (details) { CFDictionarySetValue(results, (const void *)kSecTrustResultDetails, (const void *)details); + CFRelease(details); } // kSecTrustResultValue (overall trust result) @@ -1734,12 +1934,6 @@ CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) { CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparency, (const void *)ctValue); } - // kSecTrustCertificateTransparencyWhiteList - CFBooleanRef ctWhiteListValue; - if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoCertificateTransparencyWhiteListKey, (const void **)&ctWhiteListValue)) { - CFDictionarySetValue(results, (const void *)kSecTrustCertificateTransparencyWhiteList, (const void *)ctWhiteListValue); - } - // kSecTrustExtendedValidation CFBooleanRef evValue; if (CFDictionaryGetValueIfPresent(info, kSecTrustInfoExtendedValidationKey, (const void **)&evValue)) { @@ -1771,7 +1965,7 @@ CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) { } }); - return results; + return results; } // Return 0 upon error. @@ -1795,14 +1989,14 @@ OSStatus SecTrustGetOTAPKIAssetVersionNumber(int* versionNumber) if (!versionNumber) return SecError(errSecParam, error, CFSTR("versionNumber is NULL")); - return (*versionNumber = SECURITYD_XPC(sec_ota_pki_asset_version, to_int_error_request, error)) != 0; + return (*versionNumber = TRUSTD_XPC(sec_ota_pki_asset_version, to_int_error_request, error)) != 0; }); os_activity_end(trace_activity); return result; } -#define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); } +#define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); } static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type) { @@ -1874,7 +2068,9 @@ OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType *result) trust->_info = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - trust->_chain = SecCertificatePathCreate(NULL, (SecCertificateRef)CFArrayGetValueAtIndex(trust->_certificates, 0), NULL); + CFMutableArrayRef leafCert = CFArrayCreateMutableCopy(NULL, 1, trust->_certificates); + trust->_chain = SecCertificatePathCreateWithCertificates(leafCert, NULL); + CFReleaseNull(leafCert); }); SecLeafPVCDelete(&pvc); diff --git a/OSX/sec/Security/SecTrustInternal.h b/OSX/sec/Security/SecTrustInternal.h index 42515a25..51b174f8 100644 --- a/OSX/sec/Security/SecTrustInternal.h +++ b/OSX/sec/Security/SecTrustInternal.h @@ -51,6 +51,8 @@ __BEGIN_DECLS #define kSecTrustResultKey "result" #define kSecTrustInfoKey "info" +extern const CFStringRef kSecCertificateDetailSHA1Digest; + #if TARGET_OS_MAC && !TARGET_OS_IPHONE SecKeyRef SecTrustCopyPublicKey_ios(SecTrustRef trust); CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust); diff --git a/OSX/sec/Security/SecTrustStatusCodes.c b/OSX/sec/Security/SecTrustStatusCodes.c new file mode 100644 index 00000000..4f9f6d5a --- /dev/null +++ b/OSX/sec/Security/SecTrustStatusCodes.c @@ -0,0 +1,145 @@ +/* + * 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@ + * + * SecTrustStatusCodes.c - map trust result details to status codes + * + */ + +#include +#include +#include +#include + +struct resultmap_entry_s { + const CFStringRef checkstr; + const int32_t resultcode; +}; +typedef struct resultmap_entry_s resultmap_entry_t; + +const resultmap_entry_t resultmap[] = { + { CFSTR("SSLHostname"), 0x80012400, /* CSSMERR_APPLETP_HOSTNAME_MISMATCH */}, + { CFSTR("email"), 0x80012418, /* CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND */}, + { CFSTR("IssuerCommonName"), 0x8001243B /* CSSMERR_APPLETP_IDENTIFIER_MISSING */}, + { CFSTR("SubjectCommonName"), 0x8001243B /* CSSMERR_APPLETP_IDENTIFIER_MISSING */}, + { CFSTR("SubjectCommonNamePrefix"), 0x8001243B /* CSSMERR_APPLETP_IDENTIFIER_MISSING */}, + { CFSTR("SubjectCommonNameTEST"), 0x8001243B /* CSSMERR_APPLETP_IDENTIFIER_MISSING */}, + { CFSTR("SubjectOrganization"), 0x8001243B /* CSSMERR_APPLETP_IDENTIFIER_MISSING */}, + { CFSTR("SubjectOrganizationalUnit"), 0x8001243B /* CSSMERR_APPLETP_IDENTIFIER_MISSING */}, + { CFSTR("EAPTrustedServerNames"), 0x80012400 /* CSSMERR_APPLETP_HOSTNAME_MISMATCH */}, + { CFSTR("CertificatePolicy"), 0x80012439 /* CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION */}, + { CFSTR("KeyUsage"), 0x80012406 /* CSSMERR_APPLETP_INVALID_KEY_USAGE */}, + { CFSTR("ExtendedKeyUsage"), 0x80012407 /* CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE */}, + { CFSTR("BasicConstraints"), 0x80012402 /* CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS */}, + { CFSTR("QualifiedCertStatements"), 0x80012438 /* CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT */}, + { CFSTR("IntermediateSPKISHA256"), 0x8001243B /* CSSMERR_APPLETP_IDENTIFIER_MISSING */}, + { CFSTR("IntermediateEKU"), 0x80012407 /* CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE */}, + { CFSTR("AnchorSHA1"), 0x8001212A /* CSSMERR_TP_NOT_TRUSTED */}, + { CFSTR("AnchorSHA256"), 0x8001212A /* CSSMERR_TP_NOT_TRUSTED */}, + { CFSTR("AnchorTrusted"), 0x8001212A /* CSSMERR_TP_NOT_TRUSTED */}, + { CFSTR("AnchorApple"), 0x8001243C /* CSSMERR_APPLETP_CA_PIN_MISMATCH */}, + { CFSTR("NonEmptySubject"), 0x80012437 /* CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT */}, + { CFSTR("IdLinkage"), 0x80012404 /* CSSMERR_APPLETP_INVALID_AUTHORITY_ID */}, + { CFSTR("WeakIntermediates"), 0x80012115 /* CSSMERR_TP_INVALID_CERTIFICATE */}, + { CFSTR("WeakLeaf"), 0x80012115 /* CSSMERR_TP_INVALID_CERTIFICATE */}, + { CFSTR("WeakRoot"), 0x80012115 /* CSSMERR_TP_INVALID_CERTIFICATE */}, + { CFSTR("KeySize"), 0x80010918 /* CSSMERR_CSP_UNSUPPORTED_KEY_SIZE */}, + { CFSTR("SignatureHashAlgorithms"), 0x80010913 /* CSSMERR_CSP_ALGID_MISMATCH */}, + { CFSTR("SystemTrustedWeakHash"), 0x80010955 /* CSSMERR_CSP_INVALID_DIGEST_ALGORITHM */}, + { CFSTR("CriticalExtensions"), 0x80012401 /* CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN */}, + { CFSTR("ChainLength"), 0x80012409 /* CSSMERR_APPLETP_PATH_LEN_CONSTRAINT */}, + { CFSTR("BasicCertificateProcessing"), 0x80012115 /* CSSMERR_TP_INVALID_CERTIFICATE */}, + { CFSTR("ExtendedValidation"), 0x8001212A /* CSSMERR_TP_NOT_TRUSTED */}, + { CFSTR("Revocation"), 0x8001210C /* CSSMERR_TP_CERT_REVOKED */}, + { CFSTR("RevocationResponseRequired"), 0x80012423 /* CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK */}, + { CFSTR("CertificateTransparency"), 0x8001212A /* CSSMERR_TP_NOT_TRUSTED */}, + { CFSTR("BlackListedLeaf"), 0x8001210C /* CSSMERR_TP_CERT_REVOKED */}, + { CFSTR("GrayListedLeaf"), 0x8001212A /* CSSMERR_TP_NOT_TRUSTED */}, + { CFSTR("GrayListedKey"), 0x8001212A /* CSSMERR_TP_NOT_TRUSTED */}, + { CFSTR("BlackListedKey"), 0x8001210C /* CSSMERR_TP_CERT_REVOKED */}, + { CFSTR("CheckLeafMarkerOid"), 0x80012439 /* CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION */}, + { CFSTR("CheckLeafMarkerOidNoValueCheck"), 0x80012439 /* CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION */}, + { CFSTR("CheckIntermediateMarkerOid"), 0x80012439 /* CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION */}, + { CFSTR("UsageConstraints"), 0x80012436 /* CSSMERR_APPLETP_TRUST_SETTING_DENY */}, + { CFSTR("NotValidBefore"), 0x8001210B /* CSSMERR_TP_CERT_NOT_VALID_YET */}, + { CFSTR("ValidIntermediates"), 0x8001210A /* CSSMERR_TP_CERT_EXPIRED */}, + { CFSTR("ValidLeaf"), 0x8001210A /* CSSMERR_TP_CERT_EXPIRED */}, + { CFSTR("ValidRoot"), 0x8001210A /* CSSMERR_TP_CERT_EXPIRED */}, +}; + +// +// Returns a malloced array of SInt32 values, with the length in numStatusCodes, +// for the certificate specified by chain index in the given SecTrustRef. +// +// To match legacy behavior, the array actually allocates one element more than the +// value of numStatusCodes; if the certificate is revoked, the additional element +// at the end contains the CrlReason value. +// +// Caller must free the returned pointer. +// +SInt32 *SecTrustCopyStatusCodes(SecTrustRef trust, + CFIndex index, CFIndex *numStatusCodes) +{ + if (!trust || !numStatusCodes) { + return NULL; + } + *numStatusCodes = 0; + CFArrayRef details = SecTrustCopyFilteredDetails(trust); + CFIndex chainLength = (details) ? CFArrayGetCount(details) : 0; + if (!(index < chainLength)) { + CFReleaseSafe(details); + return NULL; + } + CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, index); + CFIndex ix, detailCount = CFDictionaryGetCount(detail); + *numStatusCodes = (unsigned int)detailCount; + + // Allocate one more entry than we need; this is used to store a CrlReason + // at the end of the array. + SInt32 *statusCodes = (SInt32*)malloc((detailCount+1) * sizeof(SInt32)); + statusCodes[*numStatusCodes] = 0; + + const unsigned int resultmaplen = sizeof(resultmap) / sizeof(resultmap_entry_t); + const void *keys[detailCount]; + CFDictionaryGetKeysAndValues(detail, &keys[0], NULL); + for (ix = 0; ix < detailCount; ix++) { + CFStringRef key = (CFStringRef)keys[ix]; + SInt32 statusCode = 0; + for (unsigned int mapix = 0; mapix < resultmaplen; mapix++) { + CFStringRef str = (CFStringRef) resultmap[mapix].checkstr; + if (CFStringCompare(str, key, 0) == kCFCompareEqualTo) { + statusCode = (SInt32) resultmap[mapix].resultcode; + break; + } + } + if (statusCode == (SInt32)0x8001210C) { /* CSSMERR_TP_CERT_REVOKED */ + SInt32 reason; + CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(detail, key); + if (number && CFNumberGetValue(number, kCFNumberSInt32Type, &reason)) { + statusCodes[*numStatusCodes] = (SInt32)reason; + } + } + statusCodes[ix] = statusCode; + } + + CFReleaseSafe(details); + return statusCodes; +} diff --git a/OSX/sec/Security/SecTrustStatusCodes.h b/OSX/sec/Security/SecTrustStatusCodes.h new file mode 100644 index 00000000..ffd0c0c8 --- /dev/null +++ b/OSX/sec/Security/SecTrustStatusCodes.h @@ -0,0 +1,53 @@ +/* + * 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@ + */ + +/*! + @header SecTrustStatusCodes +*/ + +#ifndef _SECURITY_SECTRUSTSTATUSCODES_H_ +#define _SECURITY_SECTRUSTSTATUSCODES_H_ + +#include + +__BEGIN_DECLS + +/*! + @function SecTrustCopyStatusCodes + @abstract Returns a malloced array of SInt32 values, with the length in numStatusCodes, + for the certificate specified by chain index in the given SecTrustRef. + @param trust A reference to a trust object. + @param index The index of the certificate whose status codes should be returned. + @param numStatusCodes On return, the number of status codes allocated, or 0 if none. + @result A pointer to an array of status codes, or NULL if no status codes exist. + If the result is non-NULL, the caller must free() this pointer. + @discussion This function returns an array of evaluation status codes for a certificate + specified by its chain index in a trust reference. If NULL is returned, the certificate + has no status codes. + */ +SInt32 *SecTrustCopyStatusCodes(SecTrustRef trust, + CFIndex index, + CFIndex *numStatusCodes); +__END_DECLS + +#endif /* !_SECURITY_SECTRUSTSTATUSCODES_H_ */ diff --git a/OSX/sec/Security/SecTrustStore.c b/OSX/sec/Security/SecTrustStore.c index 6b5c1049..e308ffb6 100644 --- a/OSX/sec/Security/SecTrustStore.c +++ b/OSX/sec/Security/SecTrustStore.c @@ -55,8 +55,8 @@ SecTrustStoreRef SecTrustStoreForDomain(SecTrustStoreDomain domain) { return NULL; } - if (gSecurityd) { - return gSecurityd->sec_trust_store_for_domain(domainName, NULL); + if (gTrustd) { + return gTrustd->sec_trust_store_for_domain(domainName, NULL); } else { return (SecTrustStoreRef)domainName; } @@ -94,7 +94,7 @@ Boolean SecTrustStoreContains(SecTrustStoreRef ts, ok = (SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_trust_store_contains, string_data_to_bool_bool_error, ts, digest, &contains, error); + return TRUSTD_XPC(sec_trust_store_contains, string_data_to_bool_bool_error, ts, digest, &contains, error); }) == errSecSuccess); errOut: @@ -206,7 +206,7 @@ OSStatus SecTrustStoreSetTrustSettings(SecTrustStoreRef ts, os_activity_initiate("SecTrustStoreSetTrustSettings", OS_ACTIVITY_FLAG_DEFAULT, ^{ result = SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_trust_store_set_trust_settings, string_cert_cftype_to_error, ts, certificate, validatedTrustSettings, error); + return TRUSTD_XPC(sec_trust_store_set_trust_settings, string_cert_cftype_to_error, ts, certificate, validatedTrustSettings, error); }); }); @@ -224,10 +224,10 @@ OSStatus SecTrustStoreRemoveCertificate(SecTrustStoreRef ts, os_activity_t trace_activity = os_activity_start("SecTrustStoreRemoveCertificate", OS_ACTIVITY_FLAG_DEFAULT); require(ts, errOut); require(digest = SecCertificateGetSHA1Digest(certificate), errOut); - require(gSecurityd || ts == (SecTrustStoreRef)kSecTrustStoreUserName, errOut); + require(gTrustd || ts == (SecTrustStoreRef)kSecTrustStoreUserName, errOut); status = SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_trust_store_remove_certificate, string_data_to_bool_error, ts, digest, error); + return TRUSTD_XPC(sec_trust_store_remove_certificate, string_data_to_bool_error, ts, digest, error); }); errOut: @@ -287,7 +287,7 @@ OSStatus SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContent require(ts, errOut); status = SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_trust_store_copy_all, string_to_array_error, ts, &results, error); + return TRUSTD_XPC(sec_trust_store_copy_all, string_to_array_error, ts, &results, error); }); *trustStoreContents = results; @@ -320,7 +320,7 @@ OSStatus SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, SecCertificateRe require(usageConstraints, errOut); status = SecOSStatusWith(^bool (CFErrorRef *error) { - return SECURITYD_XPC(sec_trust_store_copy_usage_constraints, string_data_to_array_error, ts, digest, &results, error); + return TRUSTD_XPC(sec_trust_store_copy_usage_constraints, string_data_to_array_error, ts, digest, &results, error); }); *usageConstraints = results; diff --git a/OSX/sec/Security/SecTrustStore.h b/OSX/sec/Security/SecTrustStore.h index c47632fa..bc47013b 100644 --- a/OSX/sec/Security/SecTrustStore.h +++ b/OSX/sec/Security/SecTrustStore.h @@ -1,15 +1,15 @@ /* * Copyright (c) 2007-2008,2012-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, @@ -17,13 +17,13 @@ * 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 SecTrustStore - CertificateSource API to a system root certificate store + CertificateSource API to a system root certificate store */ #ifndef _SECURITY_SECTRUSTSTORE_H_ @@ -49,7 +49,7 @@ SecTrustStoreRef SecTrustStoreForDomain(SecTrustStoreDomain domain); Boolean SecTrustStoreContains(SecTrustStoreRef source, SecCertificateRef certificate); -/* Only allowed for writeble trust stores. */ +/* Only allowed for writable trust stores. */ OSStatus SecTrustStoreSetTrustSettings(SecTrustStoreRef ts, SecCertificateRef certificate, CFTypeRef trustSettingsDictOrArray); diff --git a/OSX/sec/Security/SecuritydXPC.c b/OSX/sec/Security/SecuritydXPC.c index 225a6d65..721659a1 100644 --- a/OSX/sec/Security/SecuritydXPC.c +++ b/OSX/sec/Security/SecuritydXPC.c @@ -33,6 +33,7 @@ // TODO Shorten these string values to save ipc bandwidth. const char *kSecXPCKeyOperation = "operation"; const char *kSecXPCKeyResult = "status"; +const char *kSecXPCKeyEndpoint = "endpoint"; const char *kSecXPCKeyError = "error"; const char *kSecXPCKeyClientToken = "client"; const char *kSecXPCKeyPeerInfoArray = "peer-infos"; @@ -75,7 +76,11 @@ const char *kSecXPCKeyTriesLabel = "tries"; const char *kSecXPCKeyFileDescriptor = "fileDescriptor"; const char *kSecXPCKeyAccessGroups = "accessGroups"; const char *kSecXPCKeyClasses = "classes"; - +const char *kSecXPCKeyNormalizedIssuer = "normIssuer"; +const char *kSecXPCKeySerialNumber = "serialNum"; +const char *kSecXPCKeyBackupKeybagIdentifier = "backupKeybagID"; +const char *kSecXPCKeyBackupKeybagPath = "backupKeybagPath"; +const char *kSecXPCVersion = "version"; // // XPC Functions for both client and server. @@ -91,8 +96,6 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op) return CFSTR("OTAGetEscrowCertificates"); case kSecXPCOpOTAPKIGetNewAsset: return CFSTR("OTAPKIGetNewAsset"); - case kSecXPCOpSetHSA2AutoAcceptInfo: - return CFSTR("SetHSA2AutoAcceptInfo"); case kSecXPCOpAcceptApplicants: return CFSTR("AcceptApplicants"); case kSecXPCOpApplyToARing: @@ -287,12 +290,24 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op) return CFSTR("GetRecoveryPublicKey"); case kSecXPCOpCopyBackupInformation: return CFSTR("CopyBackupInformation"); - case sec_device_is_internal_id: - return CFSTR("DeviceIsInternal"); case kSecXPCOpMessageFromPeerIsPending: return CFSTR("MessageFromPeerIsPending"); case kSecXPCOpSendToPeerIsPending: return CFSTR("SendToPeerIsPending"); + case sec_item_copy_parent_certificates_id: + return CFSTR("copy_parent_certificates"); + case sec_item_certificate_exists_id: + return CFSTR("certificate_exists"); + case kSecXPCOpCKKSEndpoint: + return CFSTR("CKKSEndpoint"); + case kSecXPCOpSOSEndpoint: + return CFSTR("SOSEndpoint"); + case kSecXPCOpSecuritydXPCServerEndpoint: + return CFSTR("XPCServerEndpoint"); + case kSecXPCOpBackupKeybagAdd: + return CFSTR("KeybagAdd"); + case kSecXPCOpBackupKeybagDelete: + return CFSTR("KeybagDelete"); default: return CFSTR("Unknown xpc operation"); } @@ -435,6 +450,14 @@ bool SecXPCDictionaryGetBool(xpc_object_t message, const char *key, CFErrorRef * return xpc_dictionary_get_bool(message, key); } +bool SecXPCDictionaryGetDouble(xpc_object_t message, const char *key, double *pvalue, CFErrorRef *error) { + *pvalue = xpc_dictionary_get_double(message, key); + if (*pvalue == NAN) { + return SecError(errSecParam, error, CFSTR("object for key %s bad double"), key); + } + return true; +} + bool SecXPCDictionaryCopyDataOptional(xpc_object_t message, const char *key, CFDataRef *pdata, CFErrorRef *error) { size_t size = 0; if (!xpc_dictionary_get_data(message, key, &size)) { @@ -445,6 +468,20 @@ bool SecXPCDictionaryCopyDataOptional(xpc_object_t message, const char *key, CFD return *pdata; } +bool SecXPCDictionaryCopyURLOptional(xpc_object_t message, const char *key, CFURLRef *purl, CFErrorRef *error) { + size_t size = 0; + if (!xpc_dictionary_get_data(message, key, &size)) { + *purl = NULL; + return true; + } + CFDataRef data = SecXPCDictionaryCopyData(message, key, error); + if (data) { + *purl = CFURLCreateWithBytes(kCFAllocatorDefault, CFDataGetBytePtr(data), CFDataGetLength(data), kCFStringEncodingUTF8, NULL); + } + CFReleaseNull(data); + return *purl; +} + CFDictionaryRef SecXPCDictionaryCopyDictionary(xpc_object_t message, const char *key, CFErrorRef *error) { CFTypeRef dict = SecXPCDictionaryCopyPList(message, key, error); if (dict) { @@ -525,3 +562,50 @@ bool SecXPCDictionaryCopyStringOptional(xpc_object_t message, const char *key, C *pstring = SecXPCDictionaryCopyString(message, key, error); return *pstring; } + +static CFDataRef CFDataCreateWithXPCArrayAtIndex(xpc_object_t xpc_data_array, size_t index, CFErrorRef *error) { + CFDataRef data = NULL; + size_t length = 0; + const uint8_t *bytes = xpc_array_get_data(xpc_data_array, index, &length); + if (bytes) { + data = CFDataCreate(kCFAllocatorDefault, bytes, length); + } + if (!data) + SecError(errSecParam, error, CFSTR("data_array[%zu] failed to decode"), index); + + return data; +} + +static CFArrayRef CFDataXPCArrayCopyArray(xpc_object_t xpc_data_array, CFErrorRef *error) { + CFMutableArrayRef data_array = NULL; + require_action_quiet(xpc_get_type(xpc_data_array) == XPC_TYPE_ARRAY, exit, + SecError(errSecParam, error, CFSTR("data_array xpc value is not an array"))); + size_t count = xpc_array_get_count(xpc_data_array); + require_action_quiet(data_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, + SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count)); + + size_t ix; + for (ix = 0; ix < count; ++ix) { + CFDataRef data = CFDataCreateWithXPCArrayAtIndex(xpc_data_array, ix, error); + if (!data) { + CFRelease(data_array); + return NULL; + } + CFArraySetValueAtIndex(data_array, ix, data); + CFRelease(data); + } + +exit: + return data_array; +} + +bool SecXPCDictionaryCopyCFDataArrayOptional(xpc_object_t message, const char *key, CFArrayRef *data_array, CFErrorRef *error) { + xpc_object_t xpc_data_array = xpc_dictionary_get_value(message, key); + if (!xpc_data_array) { + if (data_array) + *data_array = NULL; + return true; + } + *data_array = CFDataXPCArrayCopyArray(xpc_data_array, error); + return *data_array != NULL; +} diff --git a/OSX/sec/Security/SecuritydXPC.h b/OSX/sec/Security/SecuritydXPC.h index 8dcf9d8d..da93c9fa 100644 --- a/OSX/sec/Security/SecuritydXPC.h +++ b/OSX/sec/Security/SecuritydXPC.h @@ -54,8 +54,12 @@ bool SecXPCDictionaryCopyArrayOptional(xpc_object_t message, const char *key, CF CFDataRef SecXPCDictionaryCopyData(xpc_object_t message, const char *key, CFErrorRef *error); bool SecXPCDictionaryCopyDataOptional(xpc_object_t message, const char *key, CFDataRef *pdata, CFErrorRef *error); +bool SecXPCDictionaryCopyURLOptional(xpc_object_t message, const char *key, CFURLRef *purl, CFErrorRef *error); + bool SecXPCDictionaryGetBool(xpc_object_t message, const char *key, CFErrorRef *error); +bool SecXPCDictionaryGetDouble(xpc_object_t message, const char *key, double *pvalue, CFErrorRef *error) ; + CFDictionaryRef SecXPCDictionaryCopyDictionary(xpc_object_t message, const char *key, CFErrorRef *error); bool SecXPCDictionaryCopyDictionaryOptional(xpc_object_t message, const char *key, CFDictionaryRef *pdictionary, CFErrorRef *error); @@ -66,4 +70,7 @@ bool SecXPCDictionaryCopyStringOptional(xpc_object_t message, const char *key, C CFSetRef SecXPCDictionaryCopySet(xpc_object_t message, const char *key, CFErrorRef *error); +/* For an xpc_array of datas */ +bool SecXPCDictionaryCopyCFDataArrayOptional(xpc_object_t message, const char *key, CFArrayRef *data_array, CFErrorRef *error); + #endif diff --git a/OSX/sec/Security/Tool/SecurityCommands.h b/OSX/sec/Security/Tool/SecurityCommands.h index c016e5a0..ee7dfdd0 100644 --- a/OSX/sec/Security/Tool/SecurityCommands.h +++ b/OSX/sec/Security/Tool/SecurityCommands.h @@ -2,6 +2,13 @@ #include +#if TARGET_OS_IPHONE +#define USE_SECURITY_ITEM "By default the synchronizable keys is not searched/update/deleted, use \"security item\" for that.\n" +#else +#define USE_SECURITY_ITEM +#endif + + SECURITY_COMMAND("add-internet-password", keychain_add_internet_password, "[-a accountName] [-d securityDomain] [-p path] [-P port] [-r protocol] [-s serverName] [-t authenticationType] [-w passwordData] [keychain]\n" " -a Use \"accountName\".\n" @@ -24,14 +31,20 @@ SECURITY_COMMAND("item", keychain_item, "-D Delete item from keychain\n" "Add, query, update or delete items from the keychain. Extra attr=value pairs after options always apply to the query\n" "class=[genp|inet|cert|keys] is required for the query\n" + "To search the synchronizable items (not searched by default) use sync=1 as an attr=value pair.\n" "Security Access Control object can be passed as attribute accc with following syntax:\n" "accc=\"[;operation[:constraint type(constraint parameters)]...]\"" "\nExample:\naccc=\"ak;od(cpo(DeviceOwnerAuthentication));odel(true);oe(true)\"" "\naccc=\"ak;od(cpo(DeviceOwnerAuthentication));odel(true);oe(true);prp(true)\"" - "\naccc=\"ak;od(cup(true)pkofn(1)cbio(pbioc(<>)pbioh(<>)));odel(true);oe(true)\"", - "SAC object for deleting item added by default\n" + "\naccc=\"ak;od(cup(true)pkofn(1)cbio(pbioc(<>)pbioh(<>)));odel(true);oe(true)\"" + "SAC object for deleting item added by default\n", "Manipulate keychain items.") +SECURITY_COMMAND("keychain-item-digest", keychain_item_digest, + "itemClass keychainAccessGroup\n" + "Dump items reported by _SecItemDigest command\n", + "Show keychain item digest.") + SECURITY_COMMAND_IOS("add-certificates", keychain_add_certificates, "[-k keychain] file...\n" "If no keychains is specified the certificates are added to the default keychain.\n" @@ -61,6 +74,7 @@ SECURITY_COMMAND("find-internet-password", keychain_find_internet_password, " -r Match on \"protocol\" when searching.\n" " -s Match on \"serverName\" when searching.\n" " -t Match on \"authenticationType\" when searching.\n" + USE_SECURITY_ITEM "If no keychains are specified the default search list is used.", "Find an internet password item.") @@ -82,6 +96,7 @@ SECURITY_COMMAND("delete-internet-password", keychain_delete_internet_password, " -r Match on \"protocol\" when searching.\n" " -s Match on \"serverName\" when searching.\n" " -t Match on \"authenticationType\" when searching.\n" + USE_SECURITY_ITEM "If no keychains are specified the default search list is used.", "Delete one or more internet password items.") @@ -90,6 +105,7 @@ SECURITY_COMMAND("delete-generic-password", keychain_delete_generic_password, " -a Match on \"accountName\" when searching.\n" " -g Display the password for the item found.\n" " -s Match on \"serviceName\" when searching.\n" + USE_SECURITY_ITEM "If no keychains are specified the default search list is used.", "Delete one or more generic password items.") @@ -150,14 +166,20 @@ SECURITY_COMMAND_IOS("verify-cert", verify_cert, " -c certFile Certificate to verify. Can be specified multiple times.\n" " -r rootCertFile Root Certificate. Can be specified multiple times.\n" " -p policy Verify policy (basic, ssl, smime, eap, IPSec, appleID,\n" - " codeSign, timestamp, revocation).\n" + " codeSign, timestamp, revocation).\n" + " -C Set client policy to true. Default is server policy. (ssl, IPSec, eap)\n" " -d date Set date and time to use when verifying certificate,\n" " provided in the form of YYYY-MM-DD-hh:mm:ss (time optional) in GMT.\n" " e.g: 2016-04-25-15:59:59 for April 25, 2016 at 3:59:59 pm in GMT\n" " -L Local certs only.\n" - " -n Name of the host (ssl, IPSec, smime)\n" + " -n name Name to be verified. (ssl, IPSec, smime)\n" " -q Quiet.\n" - " -C Set client to true. Otherwise, verify-cert defaults to server (ssl, IPSec, eap).\n", + " -R revOption Perform revocation checking with one of the following options:\n" + " ocsp Check revocation status using OCSP method.\n" + " require Require a positive response for successful verification.\n" + " offline Consult cached responses only (no network requests).\n" + " Can be specified multiple times; e.g. to check revocation via OCSP\n" + " and require a positive response, use \"-R ocsp -R require\".\n", "Verify certificate(s).") SECURITY_COMMAND_IOS("trust-store", trust_store_show_certificates, diff --git a/OSX/sec/Security/Tool/keychain_find.c b/OSX/sec/Security/Tool/keychain_find.m similarity index 94% rename from OSX/sec/Security/Tool/keychain_find.c rename to OSX/sec/Security/Tool/keychain_find.m index 0d4f132b..6b7f039c 100644 --- a/OSX/sec/Security/Tool/keychain_find.c +++ b/OSX/sec/Security/Tool/keychain_find.m @@ -153,7 +153,7 @@ static void display_results(CFTypeRef results) { CFArrayRef r_a = (CFArrayRef)results; CFArrayApplyFunction(r_a, CFRangeMake(0, CFArrayGetCount(r_a)), display_item, NULL); - } else if (CFGetTypeID(results) == CFArrayGetTypeID()) { + } else if (CFGetTypeID(results) == CFDictionaryGetTypeID()) { display_item(results, NULL); } else { fprintf(stderr, "SecItemCopyMatching returned unexpected results:"); @@ -384,6 +384,10 @@ int keychain_item(int argc, char * const *argv) { int limit = 0; query = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); +#if TARGET_OS_OSX + CFDictionarySetValue(query, kSecAttrNoLegacy, kCFBooleanTrue); +#endif + while ((ch = getopt(argc, argv, "ad:Df:gq:u:vl:")) != -1) { switch (ch) @@ -561,6 +565,34 @@ keychain_delete_generic_password(int argc, char * const *argv) { return keychain_find_or_delete_generic_password(1, argc, argv); } +int keychain_item_digest(int argc, char * const *argv) { + NSString *itemClass = @"inet"; + NSString *accessGroup = @"com.apple.ProtectedCloudStorage"; + + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + if (argc == 3) { + itemClass = [NSString stringWithUTF8String:argv[1]]; + accessGroup = [NSString stringWithUTF8String:argv[2]]; + } + + _SecItemFetchDigests(itemClass, accessGroup, ^(NSArray *items, NSError *error) { + for (NSDictionary *item in items) { + for (NSString *key in item) { + printf("%s\n", [[NSString stringWithFormat:@"%@\t\t%@", key, item[key]] UTF8String]); + } + } + if (error) { + printf("%s\n", [[NSString stringWithFormat:@"Failed to find items (%@/%@): %@", itemClass, accessGroup, error] UTF8String]); + } + dispatch_semaphore_signal(sema); + }); + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + + return 0; +} + + #if TARGET_OS_EMBEDDED int diff --git a/OSX/sec/Security/Tool/scep.c b/OSX/sec/Security/Tool/scep.c index 415543b7..a254b419 100644 --- a/OSX/sec/Security/Tool/scep.c +++ b/OSX/sec/Security/Tool/scep.c @@ -163,13 +163,10 @@ static void _query_string_apply(CFMutableStringRef query_string, const void *key CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)value, NULL, CFSTR("+/="), kCFStringEncodingUTF8); - CFStringRef format; if (CFStringGetLength(query_string) > 1) - format = CFSTR("&%@=%@"); - else - format = CFSTR("%@=%@"); + CFStringAppend(query_string, CFSTR("&")); - CFStringAppendFormat(query_string, NULL, format, escaped_key, escaped_value); + CFStringAppendFormat(query_string, NULL, CFSTR("%@=%@"), escaped_key, escaped_value); CFRelease(escaped_key); CFRelease(escaped_value); } diff --git a/OSX/sec/Security/Tool/spc.c b/OSX/sec/Security/Tool/spc.c index c9cd9288..848811d2 100644 --- a/OSX/sec/Security/Tool/spc.c +++ b/OSX/sec/Security/Tool/spc.c @@ -216,13 +216,10 @@ static void _query_string_apply(const void *key, const void *value, void *contex (CFStringRef)value, NULL, NULL, kCFStringEncodingUTF8); CFMutableStringRef query_string = (CFMutableStringRef)context; - CFStringRef format; if (CFStringGetLength(query_string) > 1) - format = CFSTR("&%@=%@"); - else - format = CFSTR("%@=%@"); + CFStringAppend(query_string, CFSTR("&")); - CFStringAppendFormat(query_string, NULL, format, escaped_key, escaped_value); + CFStringAppendFormat(query_string, NULL, CFSTR("%@=%@"), escaped_key, escaped_value); CFRelease(escaped_key); CFRelease(escaped_value); } @@ -449,7 +446,10 @@ static SecIdentityRef perform_scep(CFDictionaryRef scep_dict) SecIdentityRef identity = NULL; CFDictionaryRef parameters = NULL, csr_parameters = NULL; CFStringRef scep_base_url = NULL, scep_instance_name = NULL, - scep_challenge = NULL, scep_subject = NULL, scep_subject_requested = NULL; + scep_challenge = NULL; +#if 0 + CFStringRef scep_subject = NULL, scep_subject_requested = NULL; +#endif CFTypeRef scep_key_bitsize = NULL; CFNumberRef key_usage_num = NULL; SecCertificateRef ca_cert = NULL; @@ -463,16 +463,6 @@ static SecIdentityRef perform_scep(CFDictionaryRef scep_dict) dict_get_value_of_type(scep_dict, CFSTR("NAME"), CFStringGetTypeID()), out); require(scep_challenge = dict_get_value_of_type(scep_dict, CFSTR("CHALLENGE"), CFStringGetTypeID()), out); - - scep_subject_requested = - dict_get_value_of_type(scep_dict, CFSTR("SUBJECT"), CFStringGetTypeID()); - if (scep_subject_requested) { - CFArrayRef scep_subject_components = - CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, - scep_subject_requested, CFSTR("=")); - if (CFArrayGetCount(scep_subject_components) == 2) - scep_subject = CFArrayGetValueAtIndex(scep_subject_components, 1); - } scep_key_bitsize = dict_get_value_of_type(scep_dict, CFSTR("KEYSIZE"), CFNumberGetTypeID()); @@ -488,29 +478,25 @@ static SecIdentityRef perform_scep(CFDictionaryRef scep_dict) int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment; key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage); - const void *key[] = { kSecCSRChallengePassword, kSecCertificateKeyUsage }; - const void *val[] = { scep_challenge ? scep_challenge : CFSTR("magic"), key_usage_num }; - csr_parameters = CFDictionaryCreate(kCFAllocatorDefault, key, val, array_size(key), NULL, NULL); ca_cert = get_ca_cert(scep_base_url, scep_instance_name ? scep_instance_name : CFSTR("test")); if (!ca_cert) errx(1, "no ca cert returned from scep server."); - identity = NULL; // enroll_scep(scep_base_url, scep_subject, csr_parameters, parameters, ca_cert); + identity = NULL; if (!identity) errx(1, "failed to get identity from scep server."); out: CFReleaseSafe(ca_cert); - CFReleaseSafe(scep_subject); CFReleaseSafe(key_usage_num); CFReleaseSafe(csr_parameters); CFReleaseSafe(parameters); return identity; } -static CFDataRef CF_RETURNS_RETAINED get_profile(CFStringRef url_cfstring, SecIdentityRef identity) +static CFDataRef copy_profile(CFStringRef url_cfstring, SecIdentityRef identity) { CFURLRef url = NULL; CFHTTPMessageRef request = NULL; @@ -704,7 +690,7 @@ extern int command_spc(int argc, char * const *argv) require(profile_url = dict_get_value_of_type(payload_content, CFSTR("URL"), CFStringGetTypeID()), out); - require(profile_data = get_profile(profile_url, identity), out); + require(profile_data = copy_profile(profile_url, identity), out); if (debug) write_data("/tmp/profile.mobileconfig", profile_data); diff --git a/OSX/sec/Security/Tool/verify_cert.c b/OSX/sec/Security/Tool/verify_cert.c index d75876bb..6ecc2aea 100644 --- a/OSX/sec/Security/Tool/verify_cert.c +++ b/OSX/sec/Security/Tool/verify_cert.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -114,105 +115,135 @@ CFStringRef policyToConstant(const char *policy) { } } +static CFOptionFlags revCheckOptionStringToFlags( + const char *revCheckOption) +{ + CFOptionFlags result = 0; + if(revCheckOption == NULL) { + return result; + } + else if(!strcmp(revCheckOption, "ocsp")) { + result |= kSecRevocationOCSPMethod; + } + else if(!strcmp(revCheckOption, "crl")) { + result |= kSecRevocationCRLMethod; + } + else if(!strcmp(revCheckOption, "require")) { + result |= kSecRevocationRequirePositiveResponse; + } + else if(!strcmp(revCheckOption, "offline")) { + result |= kSecRevocationNetworkAccessDisabled; + } + else if(!strcmp(revCheckOption, "online")) { + result |= kSecRevocationOnlineCheck; + } + return result; +} + int verify_cert(int argc, char * const *argv) { - extern char *optarg; + extern char *optarg; extern int optind; - int arg; + int arg; CFMutableArrayRef certs = NULL; CFMutableArrayRef roots = NULL; + CFMutableArrayRef policies = NULL; - CFMutableDictionaryRef dict = NULL; - CFStringRef name = NULL; - CFBooleanRef client = kCFBooleanFalse; + CFMutableDictionaryRef dict = NULL; + CFStringRef name = NULL; + CFBooleanRef client = kCFBooleanFalse; + CFOptionFlags revOptions = 0; - OSStatus ortn; - int ourRtn = 0; + OSStatus ortn; + int ourRtn = 0; bool quiet = false; - struct tm time; - CFGregorianDate gregorianDate; - CFDateRef dateRef = NULL; + struct tm time; + CFGregorianDate gregorianDate; + CFDateRef dateRef = NULL; - CFStringRef policy = NULL; + CFStringRef policy = NULL; SecPolicyRef policyRef = NULL; - Boolean fetch = true; - SecTrustRef trustRef = NULL; + SecPolicyRef revPolicyRef = NULL; + Boolean fetch = true; + SecTrustRef trustRef = NULL; SecTrustResultType resultType; if (argc < 2) { - /* Return 2 triggers usage message. */ + /* Return 2 triggers usage message. */ return 2; } optind = 1; - while ((arg = getopt(argc, argv, "c:r:p:d:n:LqC")) != -1) { + while ((arg = getopt(argc, argv, "Cc:r:p:d:n:LqR:")) != -1) { switch (arg) { case 'c': /* Can be specified multiple times */ if (addCertFile(optarg, &certs)) { - fprintf(stderr, "Cert file error\n"); - ourRtn = 1; + fprintf(stderr, "Cert file error\n"); + ourRtn = 1; goto errOut; } break; case 'r': /* Can be specified multiple times */ if (addCertFile(optarg, &roots)) { - fprintf(stderr, "Root file error\n"); + fprintf(stderr, "Root file error\n"); ourRtn = 1; - goto errOut; + goto errOut; } break; case 'p': - policy = policyToConstant(optarg); + policy = policyToConstant(optarg); if (policy == NULL) { - fprintf(stderr, "Policy processing error\n"); - ourRtn = 2; + fprintf(stderr, "Policy processing error\n"); + ourRtn = 2; goto errOut; } break; case 'L': - /* Force no network fetch of certs */ - fetch = false; + /* Force no network fetch of certs */ + fetch = false; break; case 'n': - if (name == NULL) { - name = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); - } + if (name == NULL) { + name = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); + } break; case 'q': quiet = true; break; - case 'C': - /* Set to client */ - client = kCFBooleanTrue; - break; - case 'd': - memset(&time, 0, sizeof(struct tm)); - if (strptime(optarg, "%Y-%m-%d-%H:%M:%S", &time) == NULL) { - if (strptime(optarg, "%Y-%m-%d", &time) == NULL) { - fprintf(stderr, "Date processing error\n"); - ourRtn = 2; - goto errOut; - } - } - - gregorianDate.second = time.tm_sec; - gregorianDate.minute = time.tm_min; - gregorianDate.hour = time.tm_hour; - gregorianDate.day = time.tm_mday; - gregorianDate.month = time.tm_mon + 1; - gregorianDate.year = time.tm_year + 1900; - - if (dateRef == NULL) { - dateRef = CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(gregorianDate, NULL)); - } - break; + case 'C': + /* Set to client */ + client = kCFBooleanTrue; + break; + case 'd': + memset(&time, 0, sizeof(struct tm)); + if (strptime(optarg, "%Y-%m-%d-%H:%M:%S", &time) == NULL) { + if (strptime(optarg, "%Y-%m-%d", &time) == NULL) { + fprintf(stderr, "Date processing error\n"); + ourRtn = 2; + goto errOut; + } + } + gregorianDate.second = time.tm_sec; + gregorianDate.minute = time.tm_min; + gregorianDate.hour = time.tm_hour; + gregorianDate.day = time.tm_mday; + gregorianDate.month = time.tm_mon + 1; + gregorianDate.year = time.tm_year + 1900; + + if (dateRef == NULL) { + dateRef = CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(gregorianDate, NULL)); + } + break; + case 'R': + revOptions |= revCheckOptionStringToFlags(optarg); + break; default: - fprintf(stderr, "Usage error\n"); - ourRtn = 2; + fprintf(stderr, "Usage error\n"); + ourRtn = 2; goto errOut; } } @@ -222,18 +253,18 @@ int verify_cert(int argc, char * const *argv) { goto errOut; } - if (policy == NULL) { - policy = kSecPolicyAppleX509Basic; - } + if (policy == NULL) { + policy = kSecPolicyAppleX509Basic; + } if (certs == NULL) { - if (roots == NULL) { - fprintf(stderr, "No certs specified.\n"); + if (roots == NULL) { + fprintf(stderr, "No certificates specified.\n"); ourRtn = 2; goto errOut; } if (CFArrayGetCount(roots) != 1) { - fprintf(stderr, "Multiple roots and no certs not allowed.\n"); + fprintf(stderr, "Multiple roots and no certificates not allowed.\n"); ourRtn = 2; goto errOut; } @@ -243,40 +274,49 @@ int verify_cert(int argc, char * const *argv) { CFArrayAppendValue(certs, CFArrayGetValueAtIndex(roots, 0)); } - /* Per-policy options */ - if (!CFStringCompare(policy, kSecPolicyAppleSSL, 0) || !CFStringCompare(policy, kSecPolicyAppleIPsec, 0)) { - dict = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + /* Per-policy options */ + if (!CFStringCompare(policy, kSecPolicyAppleSSL, 0) || !CFStringCompare(policy, kSecPolicyAppleIPsec, 0)) { + dict = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (name == NULL) { - fprintf(stderr, "Name not specified for IPsec or SSL policy. '-n' is a required option for these policies."); - ourRtn = 2; - goto errOut; - } - CFDictionaryAddValue(dict, kSecPolicyName, name); - CFDictionaryAddValue(dict, kSecPolicyClient, client); - } - else if (!CFStringCompare(policy, kSecPolicyAppleEAP, 0)) { - dict = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (name == NULL) { + fprintf(stderr, "Name not specified for IPsec or SSL policy. '-n' is a required option for these policies."); + ourRtn = 2; + goto errOut; + } + CFDictionaryAddValue(dict, kSecPolicyName, name); + CFDictionaryAddValue(dict, kSecPolicyClient, client); + } + else if (!CFStringCompare(policy, kSecPolicyAppleEAP, 0)) { + dict = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(dict, kSecPolicyClient, client); - } - else if (!CFStringCompare(policy, kSecPolicyAppleSMIME, 0)) { - dict = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(dict, kSecPolicyClient, client); + } + else if (!CFStringCompare(policy, kSecPolicyAppleSMIME, 0)) { + dict = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (name == NULL) { - fprintf(stderr, "Name not specified for SMIME policy. '-n' is a required option for this policy."); - ourRtn = 2; - goto errOut; - } - CFDictionaryAddValue(dict, kSecPolicyName, name); - } + if (name == NULL) { + fprintf(stderr, "Name not specified for SMIME policy. '-n' is a required option for this policy."); + ourRtn = 2; + goto errOut; + } + CFDictionaryAddValue(dict, kSecPolicyName, name); + } - policyRef = SecPolicyCreateWithProperties(policy, dict); + policyRef = SecPolicyCreateWithProperties(policy, dict); - /* Now create a SecTrustRef and set its options */ - ortn = SecTrustCreateWithCertificates(certs, policyRef, &trustRef); + /* create policies array */ + policies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(policies, policyRef); + /* add optional SecPolicyRef for revocation, if specified */ + if(revOptions != 0) { + revPolicyRef = SecPolicyCreateRevocation(revOptions); + CFArrayAppendValue(policies, revPolicyRef); + } + + /* create trust reference from certs and policies */ + ortn = SecTrustCreateWithCertificates(certs, policies, &trustRef); if (ortn) { - fprintf(stderr, "SecTrustCreateWithCertificates\n"); + fprintf(stderr, "SecTrustCreateWithCertificates\n"); ourRtn = 1; goto errOut; } @@ -285,35 +325,35 @@ int verify_cert(int argc, char * const *argv) { if (roots != NULL) { ortn = SecTrustSetAnchorCertificates(trustRef, roots); if (ortn) { - fprintf(stderr, "SecTrustSetAnchorCertificates\n"); + fprintf(stderr, "SecTrustSetAnchorCertificates\n"); + ourRtn = 1; + goto errOut; + } + } + if (fetch == false) { + ortn = SecTrustSetNetworkFetchAllowed(trustRef, fetch); + if (ortn) { + fprintf(stderr, "SecTrustSetNetworkFetchAllowed\n"); ourRtn = 1; goto errOut; } } - if (fetch == false) { - ortn = SecTrustSetNetworkFetchAllowed(trustRef, fetch); - if (ortn) { - fprintf(stderr, "SecTrustSetNetworkFetchAllowed\n"); - ourRtn = 1; - goto errOut; - } - } - /* Set verification time for trust object */ - if (dateRef != NULL) { - ortn = SecTrustSetVerifyDate(trustRef, dateRef); - if (ortn) { - fprintf(stderr, "SecTrustSetVerifyDate\n"); - ourRtn = 1; - goto errOut; - } - } + /* Set verification time for trust object */ + if (dateRef != NULL) { + ortn = SecTrustSetVerifyDate(trustRef, dateRef); + if (ortn) { + fprintf(stderr, "SecTrustSetVerifyDate\n"); + ourRtn = 1; + goto errOut; + } + } /* Evaluate certs */ ortn = SecTrustEvaluate(trustRef, &resultType); if (ortn) { /* Should never fail - error doesn't mean the cert verified badly */ - fprintf(stderr, "SecTrustEvaluate\n"); + fprintf(stderr, "SecTrustEvaluate\n"); ourRtn = 1; goto errOut; } @@ -324,54 +364,46 @@ int verify_cert(int argc, char * const *argv) { /* Cert chain valid AND user explicitly trusts this */ break; case kSecTrustResultDeny: - /* User-configured denial */ + /* User-configured denial */ if (!quiet) { fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultDeny\n"); } ourRtn = 1; break; - case kSecTrustResultConfirm: - /* Cert chain may well have verified OK, but user has flagged - one of these certs as untrustable. */ + case kSecTrustResultInvalid: + /* SecTrustEvaluate not called yet */ + if (!quiet) { + fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultInvalid\n"); + } + ourRtn = 1; + break; + case kSecTrustResultRecoverableTrustFailure: + /* Failure, can be user-overridden */ + if (!quiet) { + fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n"); + } + ourRtn = 1; + break; + case kSecTrustResultFatalTrustFailure: + /* Complete failure */ + if (!quiet) { + fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n"); + } + ourRtn = 1; + break; + case kSecTrustResultOtherError: + /* Failure unrelated to trust evaluation */ if (!quiet) { - fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultConfirm\n"); + fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultOtherError\n"); } ourRtn = 1; break; - case kSecTrustResultInvalid: - /* SecTrustEvaluate not called yet */ - if (!quiet) { - fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultInvalid\n"); - } - ourRtn = 1; - break; - case kSecTrustResultRecoverableTrustFailure: - /* Failure, can be user-overridden */ - if (!quiet) { - fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultRecoverableTrustFailure\n"); - } - ourRtn = 1; - break; - case kSecTrustResultFatalTrustFailure: - /* Complete failure */ - if (!quiet) { - fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultFatalTrustFailure\n"); - } - ourRtn = 1; - break; - case kSecTrustResultOtherError: - /* Failure unrelated to trust evaluation */ - if (!quiet) { - fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultOtherError\n"); - } - ourRtn = 1; - break; default: - /* Error is not a defined SecTrustResultType */ + /* Error is not a defined SecTrustResultType */ if (!quiet) { fprintf(stderr, "Cert Verify Result: %u\n", resultType); } - ourRtn = 1; + ourRtn = 1; break; } @@ -382,10 +414,12 @@ errOut: /* Cleanup */ CFRELEASE(certs); CFRELEASE(roots); - CFRELEASE(dateRef); - CFRELEASE(dict); + CFRELEASE(dateRef); + CFRELEASE(dict); + CFRELEASE(policies); + CFRELEASE(revPolicyRef); CFRELEASE(policyRef); CFRELEASE(trustRef); - CFRELEASE(name); + CFRELEASE(name); return ourRtn; } diff --git a/OSX/sec/Security/so_01_serverencryption.c b/OSX/sec/Security/so_01_serverencryption.c index 64542ce1..fb637de8 100644 --- a/OSX/sec/Security/so_01_serverencryption.c +++ b/OSX/sec/Security/so_01_serverencryption.c @@ -86,7 +86,7 @@ unsigned char public_cert_der[] = { const char *testbytes = "funky"; CFIndex testbytes_size = 5; -static int kTestTestCount = 8; +static int kTestTestCount = 9; static void tests(void) { CFErrorRef error = NULL; @@ -104,6 +104,9 @@ static void tests(void) CFReleaseNull(basic); status = SecTrustSetAnchorCertificates(trust, certInArray); ok_status(status, "Anchors"); + CFDateRef verifyDate = CFDateCreate(NULL, 500000000.0); // November 4, 2016 at 5:53:20 PM PDT + status = SecTrustSetVerifyDate(trust, verifyDate); + ok_status(status, "verifyDate"); SecTrustResultType result; status = SecTrustEvaluate(trust, &result); @@ -124,6 +127,7 @@ static void tests(void) CFReleaseNull(cert); CFReleaseNull(certInArray); CFReleaseNull(trust); + CFReleaseNull(verifyDate); CFReleaseNull(testData); CFReleaseNull(encrypted); CFReleaseNull(decrypted); diff --git a/OSX/sec/SecurityTool/SecurityTool.c b/OSX/sec/SecurityTool/SecurityTool.c index 9e0d0346..c5cb9750 100644 --- a/OSX/sec/SecurityTool/SecurityTool.c +++ b/OSX/sec/SecurityTool/SecurityTool.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2003-2010,2013 Apple Inc. All Rights Reserved. + * Copyright (c) 2003-2010,2013-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, @@ -17,19 +17,21 @@ * 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@ * * security.c */ #include "SecurityTool.h" +#include "SecInternalReleasePriv.h" #include #include "leaks.h" #include +#include #include #include #include @@ -50,10 +52,6 @@ /* The default prompt. */ const char *prompt_string = "security> "; -/* The name of this program. */ -const char *prog_name; - - /* Forward declarations of static functions. */ @@ -228,12 +226,12 @@ usage(void) " -p Set the prompt to \"prompt\" (implies -i).\n" " -q Be less verbose.\n" " -v Be more verbose about what's going on.\n" - "%s commands are:\n", prog_name, prog_name); + "%s commands are:\n", getprogname(), getprogname()); help(0, NULL); return 2; } -/* Execute a single command. */ +/* Execute a single command. */ static int execute_command(int argc, char * const *argv) { @@ -279,7 +277,7 @@ execute_command(int argc, char * const *argv) } else { - fprintf(stderr, "unknown command \"%s\"", argv[0]); + warnx("unknown command: %s", argv[0]); return 1; } } @@ -300,9 +298,9 @@ main(int argc, char * const *argv) int do_leaks = 0; int ch; - /* Remember my name. */ - prog_name = strrchr(argv[0], '/'); - prog_name = prog_name ? prog_name + 1 : argv[0]; + if (!SecIsInternalRelease()) { + errx(1, "command unavailable"); + } /* Do getopt stuff for global options. */ optind = 1; diff --git a/OSX/sec/SecurityTool/SecurityTool.h b/OSX/sec/SecurityTool/SecurityTool.h index 20b0b116..36f1de75 100644 --- a/OSX/sec/SecurityTool/SecurityTool.h +++ b/OSX/sec/SecurityTool/SecurityTool.h @@ -59,8 +59,6 @@ extern int do_quiet; /* If 1 attempt to be as verbose as possible. */ extern int do_verbose; -extern const char* prog_name; - __END_DECLS #endif /* _SECURITY_H_ */ diff --git a/OSX/sec/SecurityTool/builtin_commands.h b/OSX/sec/SecurityTool/builtin_commands.h index aa526c1e..4e6415c5 100644 --- a/OSX/sec/SecurityTool/builtin_commands.h +++ b/OSX/sec/SecurityTool/builtin_commands.h @@ -40,6 +40,23 @@ SECURITY_COMMAND("whoami", command_whoami, "", "Ask securityd who you are.") +SECURITY_COMMAND("sos-stats", command_sos_stats, + "", + "SOS for performance numbers.") + +SECURITY_COMMAND("sos-control", command_sos_control, + "", + "SOS control.") + SECURITY_COMMAND("bubble", command_bubble, "", "Transfer to sync bubble") + +SECURITY_COMMAND("watchdog", command_watchdog, + "[parameter ...]\n" + "Where parameter is one of:\n" + " allowed-runtime \n" + " reset-period \n" + " check-period \n" + " graceful-exit-time \n", + "Show current watchdog parameters or set an individual parameter") diff --git a/OSX/sec/SecurityTool/security.1 b/OSX/sec/SecurityTool/security.1 index f8578761..2b440afd 100644 --- a/OSX/sec/SecurityTool/security.1 +++ b/OSX/sec/SecurityTool/security.1 @@ -2,7 +2,7 @@ .\"See Also: .\"man mdoc.samples for a complete listing of options .\"man mdoc for the short list of editing options -.Dd Tue May 06 2003 \" DATE +.Dd March 15, 2017 \" DATE .Dt security 1 \" Program name and manual section number .Os Darwin .Sh NAME \" Section Header - required - don't modify @@ -559,11 +559,12 @@ Ignore leaks called from .Op Fl c Ar certFile .Op Fl r Ar rootCertFile .Op Fl p Ar policy +.Op Fl C .Op Fl d Ar date .Op Fl n Ar name .Op Fl L .Op Fl q -.Op Fl C +.Op Fl R Ar revCheckOption .Bl -item -offset -indent Verify one or more certificates. .It @@ -575,21 +576,24 @@ Certificate to verify, in DER or PEM format. Can be specified more than once; le Root certificate, in DER or PEM format. Can be specified more than once. If not specified, the system anchor certificates are used. .It Fl p Ar policy Specify verification policy (ssl, smime, codeSign, IPSec, basic, eap, appleID, timestamping, revocation). Default is basic. +.It Fl C +Specify this evaluation is for client usage, if the verification policy (e.g. ssl) distinguishes between client and server usage. Default is server usage. .It Fl d Ar date Date to set for verification. Specified in the format of YYYY-MM-DD-hh:mm:ss (time optional). e.g: 2016-04-25-15:59:59 for April 25, 2016 at 3:59:59 pm in GMT .It Fl n Ar name -Specify name for the policy (ssl, IPSec, smime). +Specify a name to be verified, e.g. the SSL host name for the ssl policy, or RFC822 email address for the smime policy. .It Fl L Use local certificates only. If an issuing CA certificate is missing, this option will avoid accessing the network to fetch it. .It Fl q Quiet, no stdout or stderr. -.It Fl C -Set to client-side. Otherwise, defaults to server. +.It Fl R Ar revCheckOption +Specify a revocation checking option for this evaluation (ocsp, require, offline). Can be specified multiple times; e.g. to check revocation via OCSP and require a positive response, use "-R ocsp -R require". The offline option will consult previously cached responses, but will not make a request to a revocation server. .El .It .Sy Examples .Bl -tag -width -indent -.Dl security> verify-cert -r serverbasic.crt +.It security> verify-cert -c applestore0.cer -c applestore1.cer -p ssl -n store.apple.com +.It security> verify-cert -r serverbasic.crt .El .Sh ENVIRONMENT \" May not be needed .Bl -tag -width -indent diff --git a/OSX/sec/SecurityTool/sos.m b/OSX/sec/SecurityTool/sos.m new file mode 100644 index 00000000..a57ad86c --- /dev/null +++ b/OSX/sec/SecurityTool/sos.m @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2015 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 + * interface that doesn't work since we don't have unified headers + * between iOS and OS X. rdar://23405418/ + */ +#define __KEYCHAINCORE__ 1 + +#import +#import +#import +#import +#import +#import +#import +#import + +#include "builtin_commands.h" + + +@interface SOSStatus : NSObject +@property NSXPCConnection *connection; + +- (void)printPerformanceCounters:(bool)asPList; +@end + +@implementation SOSStatus + +- (instancetype) initWithEndpoint:(xpc_endpoint_t)endpoint +{ + if ((self = [super init]) == NULL) + return NULL; + + NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SOSControlProtocol)]; + _SOSControlSetupInterface(interface); + NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; + + [listenerEndpoint _setEndpoint:endpoint]; + + self.connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; + if (self.connection == NULL) + return NULL; + + self.connection.remoteObjectInterface = interface; + + [self.connection resume]; + + + return self; +} + +- (void)printPerformanceCounters:(bool)asPList +{ + dispatch_semaphore_t sema1 = dispatch_semaphore_create(0); + dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); + dispatch_semaphore_t sema3 = dispatch_semaphore_create(0); + + NSMutableDictionary *merged = [NSMutableDictionary dictionary]; + __block NSMutableDictionary *diagnostics = [NSMutableDictionary dictionary]; + + [[self.connection remoteObjectProxy] kvsPerformanceCounters:^(NSDictionary *counters){ + if (counters == NULL){ + printf("no KVS counters!"); + return; + } + + [merged addEntriesFromDictionary:counters]; + dispatch_semaphore_signal(sema1); + }]; + + + [[self.connection remoteObjectProxy] idsPerformanceCounters:^(NSDictionary *counters){ + if (counters == NULL){ + printf("no IDS counters!"); + return; + } + [merged addEntriesFromDictionary:counters]; + dispatch_semaphore_signal(sema2); + }]; + + [[self.connection remoteObjectProxy] rateLimitingPerformanceCounters:^(NSDictionary *returnedDiagnostics){ + if (returnedDiagnostics == NULL){ + printf("no rate limiting counters!"); + return; + } + diagnostics = [[NSMutableDictionary alloc]initWithDictionary:returnedDiagnostics]; + dispatch_semaphore_signal(sema3); + }]; + dispatch_semaphore_wait(sema1, DISPATCH_TIME_FOREVER); + dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER); + dispatch_semaphore_wait(sema3, DISPATCH_TIME_FOREVER); + + if (asPList) { + NSData *data = [NSPropertyListSerialization dataWithPropertyList:merged format:NSPropertyListXMLFormat_v1_0 options:0 error:NULL]; + + printf("%.*s\n", (int)[data length], [data bytes]); + } else { + [merged enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSNumber * obj, BOOL *stop) { + printf("%s - %lld\n", [key UTF8String], [obj longLongValue]); + }]; + } + if(diagnostics){ + [diagnostics enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSString * obj, BOOL * stop) { + printf("%s - %s\n", [key UTF8String], [obj UTF8String]); + }]; + } +} + +@end + +static void +usage(const char *command, struct option *options) +{ + printf("%s %s [...options]\n", getprogname(), command); + for (unsigned n = 0; options[n].name; n++) { + printf("\t [-%c|--%s\n", options[n].val, options[n].name); + } + +} + +int +command_sos_stats(__unused int argc, __unused char * const * argv) +{ + @autoreleasepool { + int option_index = 0, ch; + + xpc_endpoint_t endpoint = _SecSecuritydCopySOSStatusEndpoint(NULL); + if (endpoint == NULL) + errx(1, "no SOS endpoint"); + + SOSStatus *control = [[SOSStatus alloc] initWithEndpoint:endpoint]; + + bool asPlist = false; + struct option long_options[] = + { + /* These options set a flag. */ + {"plist", no_argument, NULL, 'p'}, + {0, 0, 0, 0} + }; + + while ((ch = getopt_long(argc, argv, "p", long_options, &option_index)) != -1) { + switch (ch) { + case 'p': { + asPlist = true; + break; + } + case '?': + default: + { + usage("sos-stats", long_options); + return 2; + } + } + } + + [control printPerformanceCounters:asPlist]; + } + + return 0; +} + +int +command_sos_control(__unused int argc, __unused char * const * argv) +{ + @autoreleasepool { + int option_index = 0, ch; + + bool assertStashAccountKey = false; + bool triggerSync = false; + NSString *syncingPeer = NULL; + + static struct option long_options[] = + { + /* These options set a flag. */ + {"assertStashAccountKey", no_argument, NULL, 'A'}, + {"trigger-sync", optional_argument, NULL, 's'}, + {0, 0, 0, 0} + }; + + while ((ch = getopt_long(argc, argv, "A", long_options, &option_index)) != -1) { + switch (ch) { + case 'A': { + assertStashAccountKey = true; + break; + } + case 's': { + triggerSync = true; + if (optarg) { + syncingPeer = [NSString stringWithUTF8String:optarg]; + } + break; + } + case '?': + default: + { + usage("sos-control", long_options); + return 2; + } + } + } + + xpc_endpoint_t endpoint = _SecSecuritydCopySOSStatusEndpoint(NULL); + if (endpoint == NULL) + errx(1, "no SOS endpoint"); + + SOSStatus *control = [[SOSStatus alloc] initWithEndpoint:endpoint]; + if (control == NULL) + errx(1, "no SOS control object"); + + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + if (triggerSync) { + NSMutableArray *peers = [NSMutableArray array]; + if (syncingPeer) { + [peers addObject:syncingPeer]; + } + + [[control.connection remoteObjectProxyWithErrorHandler:^(NSError *error) { + printf("%s", [[NSString stringWithFormat:@"Failed to sending messages to soscontrol object: %@\n", error] UTF8String]); + dispatch_semaphore_signal(sema); + }] triggerSync:peers complete:^(bool res, NSError *error) { + if (res) { + printf("starting to sync was successful\n"); + } else { + printf("%s", [[NSString stringWithFormat:@"Failed to start sync: %@\n", error] UTF8String]); + } + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + } else if (assertStashAccountKey) { + [[control.connection remoteObjectProxyWithErrorHandler:^(NSError *error) { + printf("%s", [[NSString stringWithFormat:@"Failed to sending messages to soscontrol object: %@\n", error] UTF8String]); + dispatch_semaphore_signal(sema); + }] assertStashedAccountCredential:^(BOOL res, NSError *error) { + if (res) { + printf("successfully asserted stashed credential\n"); + } else { + printf("%s", [[NSString stringWithFormat:@"failed to assert stashed credential: %@\n", error] UTF8String]); + } + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + + } else { + + [[control.connection remoteObjectProxyWithErrorHandler:^(NSError *error) { + printf("%s", [[NSString stringWithFormat:@"Failed to sending messages to soscontrol object: %@\n", error] UTF8String]); + dispatch_semaphore_signal(sema); + }] userPublicKey:^(BOOL trusted, NSData *spki, NSError *error) { + printf("trusted: %s\n", trusted ? "yes" : "no"); + printf("userPublicKey: %s\n", [[spki base64EncodedStringWithOptions:0] UTF8String]); + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + + [[control.connection remoteObjectProxyWithErrorHandler:^(NSError *error) { + printf("%s", [[NSString stringWithFormat:@"Failed to sending messages to soscontrol object: %@\n", error] UTF8String]); + dispatch_semaphore_signal(sema); + }] stashedCredentialPublicKey:^(NSData *spki, NSError *error) { + NSString *pkey = [spki base64EncodedStringWithOptions:0]; + if (pkey == NULL) + pkey = @"no available"; + printf("cachedCredentialPublicKey: %s\n", [pkey UTF8String]); + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + } + + } + return 0; +} + +int command_watchdog(int argc, char* const * argv) +{ + xpc_endpoint_t endpoint = _SecSecuritydCopySOSStatusEndpoint(NULL); + if (!endpoint) { + errx(1, "no SOS endpoint"); + return 0; + } + + SOSStatus* control = [[SOSStatus alloc] initWithEndpoint:endpoint]; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + if (argc < 3) { + printf("getting watchdog parameters...\n"); + [[control.connection remoteObjectProxyWithErrorHandler:^(NSError* error) { + printf("%s", [[NSString stringWithFormat:@"Failed to sending messages to soscontrol object: %@\n", error] UTF8String]); + dispatch_semaphore_signal(semaphore); + }] getWatchdogParameters:^(NSDictionary* parameters, NSError* error) { + if (error) { + printf("error getting watchdog parameters: %s", error.localizedDescription.UTF8String); + } + else { + printf("watchdog parameters:\n"); + [parameters enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSObject* value, BOOL* stop) { + printf("\t%s - %s\n", key.description.UTF8String, value.description.UTF8String); + }]; + } + + dispatch_semaphore_signal(semaphore); + }]; + } + else { + printf("attempting to set watchdog parameters...\n"); + NSString* parameter = [[NSString alloc] initWithUTF8String:argv[1]]; + NSInteger value = [[[NSString alloc] initWithUTF8String:argv[2]] integerValue]; + [[control.connection remoteObjectProxyWithErrorHandler:^(NSError* error) { + printf("%s", [[NSString stringWithFormat:@"Failed to sending messages to soscontrol object: %@\n", error] UTF8String]); + dispatch_semaphore_signal(semaphore); + }] setWatchdogParmeters:@{parameter : @(value)} complete:^(NSError* error) { + if (error) { + printf("error attempting to set watchdog parameters: %s\n", error.localizedDescription.UTF8String); + } + else { + printf("successfully set watchdog parameter\n"); + } + + dispatch_semaphore_signal(semaphore); + }]; + } + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + return 0; +} diff --git a/OSX/sec/SecurityTool/syncbubble.m b/OSX/sec/SecurityTool/syncbubble.m index 5865de0a..2f0d8722 100644 --- a/OSX/sec/SecurityTool/syncbubble.m +++ b/OSX/sec/SecurityTool/syncbubble.m @@ -23,7 +23,7 @@ /* * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers + * interface that doesn't work since we don't have unified headers * between iOS and OS X. rdar://23405418/ */ #define __KEYCHAINCORE__ 1 diff --git a/OSX/sec/SecurityTool/tool_errors.h b/OSX/sec/SecurityTool/tool_errors.h index db62c0a4..8c8ef6eb 100644 --- a/OSX/sec/SecurityTool/tool_errors.h +++ b/OSX/sec/SecurityTool/tool_errors.h @@ -34,7 +34,7 @@ #include #include "SecurityTool/SecurityTool.h" -static inline const char * +static const char * sec_errstr(int err) { const char *errString; @@ -51,12 +51,15 @@ sec_errstr(int err) return errString; } -static inline void +static void +sec_error(const char *msg, ...) __attribute__((format(printf, 1, 2))); + +static void sec_error(const char *msg, ...) { va_list args; - fprintf(stderr, "%s: ", prog_name); + fprintf(stderr, "%s: ", getprogname()); va_start(args, msg); vfprintf(stderr, msg, args); diff --git a/OSX/sec/SecurityTool/whoami.m b/OSX/sec/SecurityTool/whoami.m index 9e1f80d3..f5957110 100644 --- a/OSX/sec/SecurityTool/whoami.m +++ b/OSX/sec/SecurityTool/whoami.m @@ -23,7 +23,7 @@ /* * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers + * interface that doesn't work since we don't have unified headers * between iOS and OS X. rdar://23405418/ */ #define __KEYCHAINCORE__ 1 diff --git a/OSX/sec/SharedWebCredential/swcagent-entitlements.plist b/OSX/sec/SharedWebCredential/swcagent-entitlements.plist index ab1db4af..f6fbb897 100644 --- a/OSX/sec/SharedWebCredential/swcagent-entitlements.plist +++ b/OSX/sec/SharedWebCredential/swcagent-entitlements.plist @@ -3,24 +3,8 @@ application-identifier - com.apple.securityd - com.apple.keystore.access-keychain-keys - - com.apple.keystore.lockassertion - + com.apple.swcagent com.apple.private.associated-domains - com.apple.private.necp.match - - com.apple.private.network.socket-delegate - - com.apple.mkb.usersession.info - - com.apple.private.applecredentialmanager.allow - - com.apple.private.MobileGestalt.AllowedProtectedKeys - - SerialNumber - diff --git a/OSX/sec/SharedWebCredential/swcagent.m b/OSX/sec/SharedWebCredential/swcagent.m index 0ecbeda3..071eb041 100644 --- a/OSX/sec/SharedWebCredential/swcagent.m +++ b/OSX/sec/SharedWebCredential/swcagent.m @@ -38,8 +38,7 @@ #if TARGET_OS_IPHONE #include -#endif -#if !TARGET_OS_IPHONE +#else #include #endif @@ -55,7 +54,6 @@ typedef WBSAutoFillDataClasses (*WBUAutoFillGetEnabledDataClasses_f)(void); #endif -#include #include #include #include @@ -74,14 +72,7 @@ typedef WBSAutoFillDataClasses (*WBUAutoFillGetEnabledDataClasses_f)(void); #include #include -// TODO: Make this include work on both platforms. -#if TARGET_OS_EMBEDDED #include -#else -/* defines from */ -#define kSecEntitlementAssociatedDomains CFSTR("com.apple.developer.associated-domains") -#define kSecEntitlementPrivateAssociatedDomains CFSTR("com.apple.private.associated-domains") -#endif #include @@ -90,13 +81,10 @@ typedef WBSAutoFillDataClasses (*WBUAutoFillGetEnabledDataClasses_f)(void); #include #include -#if TARGET_IPHONE_SIMULATOR -#define CHECK_ENTITLEMENTS 0 -#else -#define CHECK_ENTITLEMENTS 0 /* %%% TODO: re-enable when entitlements are available */ -#endif +#import + +static NSString *swca_string_table = @"SharedWebCredentials"; -#if CHECK_ENTITLEMENTS static bool SecTaskGetBooleanValueForEntitlement(SecTaskRef task, CFStringRef entitlement) { CFStringRef canModify = (CFStringRef)SecTaskCopyValueForEntitlement(task, entitlement, NULL); @@ -132,9 +120,6 @@ static CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task, CFStr return value; } -#endif /* CHECK_ENTITLEMENTS */ - - /* Identify a client */ enum { CLIENT_TYPE_BUNDLE_IDENTIFIER, @@ -169,7 +154,7 @@ static Client *identify_client(pid_t pid) #else size_t path_len = sizeof(path_buf); if (responsibility_get_responsible_for_pid(pid, NULL, NULL, &path_len, path_buf) != 0) { - asl_log(NULL, NULL, ASL_LEVEL_NOTICE, "Refusing client without path (pid %d)", pid); + secnotice("swcagent", "Refusing client without path (pid %d)", pid); [client release]; return nil; } @@ -226,37 +211,28 @@ static Client *identify_client(pid_t pid) struct __SecTask { CFRuntimeBase base; - pid_t pid_self; audit_token_t token; /* Track whether we've loaded entitlements independently since after the * load, entitlements may legitimately be NULL */ Boolean entitlementsLoaded; CFDictionaryRef entitlements; + + /* for debugging only, shown by debugDescription */ + int lastFailure; }; static Client* SecTaskCopyClient(SecTaskRef task) { // SecTaskCopyDebugDescription is not sufficient to get the localized client name pid_t pid; - if (task->pid_self==-1) { - audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); - } else { - pid = task->pid_self; - } + audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); Client *client = identify_client(pid); - return client; } static CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task) { -#if CHECK_ENTITLEMENTS - CFArrayRef groups = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementAssociatedDomains); -#else - CFArrayRef groups = SecAccessGroupsGetCurrent(); - CFRetainSafe(groups); -#endif - return groups; + return SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementAssociatedDomains); } // Local function declarations @@ -331,13 +307,24 @@ static bool SWCAIsAutofillEnabled(void) #endif } +static NSBundle* swca_get_security_bundle() +{ + static NSBundle *security_bundle; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *security_path = @"/System/Library/Frameworks/Security.framework"; +#if TARGET_IPHONE_SIMULATOR + security_path = [NSString stringWithFormat:@"%s%@", getenv("IPHONE_SIMULATOR_ROOT"), security_path]; +#endif + security_bundle = [NSBundle bundleWithPath:security_path]; + }); + return security_bundle; +} + static CFOptionFlags swca_handle_request(enum SWCAXPCOperation operation, Client* client, CFArrayRef domains) { CFUserNotificationRef notification = NULL; NSMutableDictionary *notification_dictionary = NULL; - NSString *security_path = @"/System/Library/Frameworks/Security.framework"; - NSString *swc_table = @"SharedWebCredentials"; - NSBundle *security_bundle; NSString *request_key; NSString *request_format; NSString *default_button_key; @@ -366,16 +353,12 @@ check_database: alert_sem_held = YES; if (dispatch_semaphore_wait(alert_sem, DISPATCH_TIME_NOW)) { /* Wait for the active alert, then recheck the database in case both alerts are for the same client. */ - //asl_log(NULL, NULL, ASL_LEVEL_NOTICE, "Delaying prompt for pid %d", pid); + //secnotice("swcagent", "Delaying prompt for pid %d", pid); dispatch_semaphore_wait(alert_sem, DISPATCH_TIME_FOREVER); goto check_database; } } -#if TARGET_IPHONE_SIMULATOR - security_path = [NSString stringWithFormat:@"%s%@", getenv("IPHONE_SIMULATOR_ROOT"), security_path]; -#endif - security_bundle = [NSBundle bundleWithPath:security_path]; notification_dictionary = [NSMutableDictionary dictionary]; domain = nil; if (1 == [(__bridge NSArray *)domains count]) { @@ -402,21 +385,24 @@ check_database: goto out; } request_key = [NSString stringWithFormat:@"SWC_REQUEST_%s", op]; - request_format = NSLocalizedStringFromTableInBundle(request_key, swc_table, security_bundle, nil); + request_format = NSLocalizedStringFromTableInBundle(request_key, swca_string_table, swca_get_security_bundle(), nil); alternate_button_key = (op) ? [NSString stringWithFormat:@"SWC_ALLOW_%s", op] : nil; default_button_key = @"SWC_NEVER"; other_button_key = @"SWC_DENY"; info_message_key = @"SWC_INFO_MESSAGE"; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" notification_dictionary[(__bridge NSString *)kCFUserNotificationAlertHeaderKey] = [NSString stringWithFormat:request_format, client.client_name, domain]; - notification_dictionary[(__bridge NSString *)kCFUserNotificationAlertMessageKey] = NSLocalizedStringFromTableInBundle(info_message_key, swc_table, security_bundle, nil); - notification_dictionary[(__bridge NSString *)kCFUserNotificationDefaultButtonTitleKey] = NSLocalizedStringFromTableInBundle(default_button_key, swc_table, security_bundle, nil); - notification_dictionary[(__bridge NSString *)kCFUserNotificationAlternateButtonTitleKey] = NSLocalizedStringFromTableInBundle(alternate_button_key, swc_table, security_bundle, nil); +#pragma clang diagnostic pop + notification_dictionary[(__bridge NSString *)kCFUserNotificationAlertMessageKey] = NSLocalizedStringFromTableInBundle(info_message_key, swca_string_table, swca_get_security_bundle(), nil); + notification_dictionary[(__bridge NSString *)kCFUserNotificationDefaultButtonTitleKey] = NSLocalizedStringFromTableInBundle(default_button_key, swca_string_table, swca_get_security_bundle(), nil); + notification_dictionary[(__bridge NSString *)kCFUserNotificationAlternateButtonTitleKey] = NSLocalizedStringFromTableInBundle(alternate_button_key, swca_string_table, swca_get_security_bundle(), nil); if (other_button_key) { // notification_dictionary[(__bridge NSString *)kCFUserNotificationOtherButtonTitleKey] = NSLocalizedStringFromTableInBundle(other_button_key, swc_table, security_bundle, nil); } - notification_dictionary[(__bridge NSString *)kCFUserNotificationLocalizationURLKey] = [security_bundle bundleURL]; + notification_dictionary[(__bridge NSString *)kCFUserNotificationLocalizationURLKey] = [swca_get_security_bundle() bundleURL]; notification_dictionary[(__bridge NSString *)SBUserNotificationAllowedApplicationsKey] = client.client; SInt32 error; @@ -478,9 +464,6 @@ static bool swca_select_item(CFArrayRef items, Client* client, CFArrayRef access { CFUserNotificationRef notification = NULL; NSMutableDictionary *notification_dictionary = NULL; - NSString *security_path = @"/System/Library/Frameworks/Security.framework"; - NSString *swc_table = @"SharedWebCredentials"; - NSBundle *security_bundle; NSString *request_title_format; NSString *info_message_key; NSString *default_button_key; @@ -519,23 +502,21 @@ entry: //gActiveItem = CFArrayGetValueAtIndex(items, 0); //CFRetainSafe(gActiveItem); -#if TARGET_IPHONE_SIMULATOR - security_path = [NSString stringWithFormat:@"%s%@", getenv("IPHONE_SIMULATOR_ROOT"), security_path]; -#endif - security_bundle = [NSBundle bundleWithPath:security_path]; notification_dictionary = [NSMutableDictionary dictionary]; - - request_title_format = NSLocalizedStringFromTableInBundle(@"SWC_ALERT_TITLE", swc_table, security_bundle, nil); + request_title_format = NSLocalizedStringFromTableInBundle(@"SWC_ALERT_TITLE", swca_string_table, swca_get_security_bundle(), nil); default_button_key = @"SWC_ALLOW_USE"; alternate_button_key = @"SWC_CANCEL"; info_message_key = @"SWC_INFO_MESSAGE"; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" notification_dictionary[(__bridge NSString *)kCFUserNotificationAlertHeaderKey] = [NSString stringWithFormat: request_title_format, client.client_name]; - notification_dictionary[(__bridge NSString *)kCFUserNotificationAlertMessageKey] = NSLocalizedStringFromTableInBundle(info_message_key, swc_table, security_bundle, nil); - notification_dictionary[(__bridge NSString *)kCFUserNotificationDefaultButtonTitleKey] = NSLocalizedStringFromTableInBundle(default_button_key, swc_table, security_bundle, nil); - notification_dictionary[(__bridge NSString *)kCFUserNotificationAlternateButtonTitleKey] = NSLocalizedStringFromTableInBundle(alternate_button_key, swc_table, security_bundle, nil); +#pragma clang diagnostic pop + notification_dictionary[(__bridge NSString *)kCFUserNotificationAlertMessageKey] = NSLocalizedStringFromTableInBundle(info_message_key, swca_string_table, swca_get_security_bundle(), nil); + notification_dictionary[(__bridge NSString *)kCFUserNotificationDefaultButtonTitleKey] = NSLocalizedStringFromTableInBundle(default_button_key, swca_string_table, swca_get_security_bundle(), nil); + notification_dictionary[(__bridge NSString *)kCFUserNotificationAlternateButtonTitleKey] = NSLocalizedStringFromTableInBundle(alternate_button_key, swca_string_table, swca_get_security_bundle(), nil); - notification_dictionary[(__bridge NSString *)kCFUserNotificationLocalizationURLKey] = [security_bundle bundleURL]; + notification_dictionary[(__bridge NSString *)kCFUserNotificationLocalizationURLKey] = [swca_get_security_bundle() bundleURL]; notification_dictionary[(__bridge NSString *)kCFUserNotificationAlertTopMostKey] = [NSNumber numberWithBool:YES]; // additional keys for remote view controller @@ -569,6 +550,50 @@ out: return (result && *result); } +/* + * Return a SecTaskRef iff orignal client have the entitlement kSecEntitlementAssociatedDomains + */ + +static SecTaskRef +swcaCopyClientFromMessage(xpc_object_t event, CFErrorRef *error) +{ + SecTaskRef clientTask = NULL; + audit_token_t auditToken = {}; + + // fetch audit token for process which called securityd + size_t length = 0; + const uint8_t *bytes = xpc_dictionary_get_data(event, kSecXPCKeyClientToken, &length); + if (length != sizeof(audit_token_t)) { + SecError(errSecMissingEntitlement, error, CFSTR("swcagent_xpc - wrong length for client id")); + return NULL; + } + + memcpy(&auditToken, bytes, sizeof(audit_token_t)); + + // identify original client + clientTask = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); + if (clientTask == NULL) { + pid_t pid = 0; + audit_token_to_au32(auditToken, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); + SecError(errSecMissingEntitlement, error, CFSTR("can't get entitlement of original client pid %d"), (int)pid); + return NULL; + } + + + // check for presence of original client's shared credential entitlement + CFArrayRef domains = SecTaskCopyArrayOfStringsForEntitlement(clientTask, kSecEntitlementAssociatedDomains); + if (domains == NULL) { + SecError(errSecMissingEntitlement, error, CFSTR("%@ lacks entitlement %@"), + clientTask, kSecEntitlementAssociatedDomains); + CFReleaseNull(clientTask); + return NULL; + } else { + CFReleaseNull(domains); + } + + return clientTask; +} + static void swca_xpc_dictionary_handler(const xpc_connection_t connection, xpc_object_t event) { xpc_type_t type = xpc_get_type(event); @@ -581,58 +606,33 @@ static void swca_xpc_dictionary_handler(const xpc_connection_t connection, xpc_o secdebug("swcagent_xpc", "entering"); if (type == XPC_TYPE_DICTIONARY) { + bool entitlementOK = false; replyMessage = xpc_dictionary_create_reply(event); uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation); - secdebug("swcagent_xpc", "operation: %@ (%" PRIu64 ")", SWCAGetOperationDescription((enum SWCAXPCOperation)operation), operation); + secinfo("swcagent_xpc", "operation: %@ (%" PRIu64 ")", SWCAGetOperationDescription((enum SWCAXPCOperation)operation), operation); - bool hasEntitlement; - audit_token_t auditToken = {}; -#if !CHECK_ENTITLEMENTS - hasEntitlement = true; -#else - // check our caller's private entitlement to invoke swcagent - // TODO: on iOS it's enough to have the entitlement; will need to check code requirement on OS X - xpc_connection_get_audit_token(connection, &auditToken); - clientTask = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); - hasEntitlement = (clientTask && SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementPrivateAssociatedDomains)); - if (!hasEntitlement) { - CFErrorRef entitlementError = NULL; - SecError(errSecMissingEntitlement, &entitlementError, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SWCAXPCOperation)operation), clientTask, kSecEntitlementPrivateAssociatedDomains); - CFReleaseSafe(entitlementError); - } - CFReleaseNull(clientTask); -#endif - if (hasEntitlement) { - // fetch audit token for process which called securityd - size_t length = 0; - const uint8_t *bytes = xpc_dictionary_get_data(event, kSecXPCKeyClientToken, &length); - if (length == sizeof(audit_token_t)) { - memcpy(&auditToken, bytes, sizeof(audit_token_t)); - } else { - secerror("swcagent_xpc - wrong length for client id"); - hasEntitlement = false; - } - } - if (hasEntitlement) { - // identify original client - clientTask = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); - accessGroups = SecTaskCopyAccessGroups(clientTask); - client = SecTaskCopyClient(clientTask); -#if CHECK_ENTITLEMENTS - // check for presence of original client's shared credential entitlement - hasEntitlement = (clientTask && SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementAssociatedDomains)); - if (!hasEntitlement) { - CFErrorRef entitlementError = NULL; - SecError(errSecMissingEntitlement, &entitlementError, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SWCAXPCOperation)operation), clientTask, kSecEntitlementAssociatedDomains); - CFReleaseSafe(entitlementError); + if (operation == swca_copy_pairs_request_id || operation == swca_set_selection_request_id) { + /* check entitlement */ + xpc_object_t ent = xpc_connection_copy_entitlement_value(connection, "com.apple.private.associated-domains"); + if (ent) + entitlementOK = true; + + } else { + clientTask = swcaCopyClientFromMessage(event, &error); + if (clientTask) { + accessGroups = SecTaskCopyAccessGroups(clientTask); + client = SecTaskCopyClient(clientTask); + CFReleaseNull(clientTask); } -#endif - CFReleaseNull(clientTask); + + if (accessGroups && client) + entitlementOK = true; + } - if (hasEntitlement) { + if (entitlementOK) { switch (operation) { case swca_add_request_id: @@ -703,7 +703,15 @@ static void swca_xpc_dictionary_handler(const xpc_connection_t connection, xpc_o CFTypeRef result = NULL; // select a dictionary from an input array of dictionaries if (swca_select_item(items, client, accessGroups, &result, &error) && result) { - SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, result, &error); + LAContext *ctx = [LAContext new]; + NSString *subTitle = NSLocalizedStringFromTableInBundle(@"SWC_FILLPWD", swca_string_table, swca_get_security_bundle(), nil); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + [ctx evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:subTitle reply:^(BOOL success, NSError * _Nullable laError) { + if (success || ([laError.domain isEqual:LAErrorDomain] && laError.code == LAErrorPasscodeNotSet)) + SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, result, &error); + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); CFRelease(result); } CFRelease(items); @@ -781,6 +789,29 @@ static void swca_xpc_init() xpc_connection_set_event_handler(swclistener, ^(xpc_object_t connection) { if (xpc_get_type(connection) == XPC_TYPE_CONNECTION) { + audit_token_t auditToken = {}; + SecTaskRef clientTask = NULL; + + /* + * check that our caller have the private entitlement to invoke swcagent + */ + + xpc_connection_get_audit_token(connection, &auditToken); + clientTask = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); + if (clientTask == NULL) { + secerror("can't get sectask of connection %@", connection); + xpc_connection_cancel(connection); + return; + } + + if (!SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementPrivateAssociatedDomains)) { + secerror("client %@ lacks entitlement %@", clientTask, kSecEntitlementPrivateAssociatedDomains); + CFReleaseNull(clientTask); + xpc_connection_cancel(connection); + return; + } + CFReleaseNull(clientTask); + xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ diff --git a/OSX/sec/SharedWebCredential/swcagent_client.h b/OSX/sec/SharedWebCredential/swcagent_client.h index fdb1f2e8..485e76b7 100644 --- a/OSX/sec/SharedWebCredential/swcagent_client.h +++ b/OSX/sec/SharedWebCredential/swcagent_client.h @@ -47,6 +47,7 @@ extern CFStringRef sSWCAXPCErrorDomain; extern const char *kSecXPCKeyOperation; extern const char *kSecXPCKeyResult; +extern const char *kSecXPCKeyEndpoint; extern const char *kSecXPCKeyError; extern const char *kSecXPCKeyClientToken; extern const char *kSecXPCKeyPeerInfoArray; @@ -68,6 +69,7 @@ extern const char *kSecXPCKeyEscrowLabel; extern const char *kSecXPCKeyTriesLabel; extern const char *kSecXPCKeyViewName; extern const char *kSecXPCKeyViewActionCode; + // // MARK: Mach port request IDs // diff --git a/OSX/sec/ipc/SecdWatchdog.h b/OSX/sec/ipc/SecdWatchdog.h new file mode 100644 index 00000000..caa889a5 --- /dev/null +++ b/OSX/sec/ipc/SecdWatchdog.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#ifdef __OBJC2__ +#import + +extern NSString* const SecdWatchdogAllowedRuntime; +extern NSString* const SecdWatchdogResetPeriod; +extern NSString* const SecdWatchdogCheckPeriod; +extern NSString* const SecdWatchdogGracefulExitTime; + +@interface SecdWatchdog : NSObject + ++ (instancetype)watchdog; + +- (NSDictionary*)watchdogParameters; +- (BOOL)setWatchdogParameters:(NSDictionary*)parameters error:(NSError**)error; + +@end +#endif + +void SecdLoadWatchDog(void); diff --git a/OSX/sec/ipc/SecdWatchdog.m b/OSX/sec/ipc/SecdWatchdog.m new file mode 100644 index 00000000..762e7f9e --- /dev/null +++ b/OSX/sec/ipc/SecdWatchdog.m @@ -0,0 +1,191 @@ +/* + * 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 "SecdWatchdog.h" +#include +#include + +#if !TARGET_OS_MAC +#import +#endif + +#define CPU_RUNTIME_SECONDS_BEFORE_WATCHDOG (60 * 20) +#define WATCHDOG_RESET_PERIOD (60 * 60 * 24) +#define WATCHDOG_CHECK_PERIOD (60 * 60) +#define WATCHDOG_CHECK_PERIOD_LEEWAY (60 * 10) +#define WATCHDOG_GRACEFUL_EXIT_LEEWAY (60 * 5) + +NSString* const SecdWatchdogAllowedRuntime = @"allowed-runtime"; +NSString* const SecdWatchdogResetPeriod = @"reset-period"; +NSString* const SecdWatchdogCheckPeriod = @"check-period"; +NSString* const SecdWatchdogGracefulExitTime = @"graceful-exit-time"; + +void SecdLoadWatchDog() +{ + (void)[SecdWatchdog watchdog]; +} + +@implementation SecdWatchdog { + long _rusageBaseline; + CFTimeInterval _lastCheckTime; + dispatch_source_t _timer; + + long _runtimeSecondsBeforeWatchdog; + long _resetPeriod; + long _checkPeriod; + long _checkPeriodLeeway; + long _gracefulExitLeeway; +} + ++ (instancetype)watchdog +{ + static SecdWatchdog* watchdog = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + watchdog = [[self alloc] init]; + }); + + return watchdog; +} + +- (instancetype)init +{ + if (self = [super init]) { + _runtimeSecondsBeforeWatchdog = CPU_RUNTIME_SECONDS_BEFORE_WATCHDOG; + _resetPeriod = WATCHDOG_RESET_PERIOD; + _checkPeriod = WATCHDOG_CHECK_PERIOD; + _checkPeriodLeeway = WATCHDOG_CHECK_PERIOD_LEEWAY; + _gracefulExitLeeway = WATCHDOG_GRACEFUL_EXIT_LEEWAY; + + [self activateTimer]; + } + + return self; +} + +- (void)activateTimer +{ + @synchronized (self) { + struct rusage initialRusage; + getrusage(RUSAGE_SELF, &initialRusage); + _rusageBaseline = initialRusage.ru_utime.tv_sec; + _lastCheckTime = CFAbsoluteTimeGetCurrent(); + + __weak __typeof(self) weakSelf = self; + _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); + dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, _checkPeriod * NSEC_PER_SEC, _checkPeriodLeeway * NSEC_PER_SEC); // run once every hour, but give the timer lots of leeway to be power friendly + dispatch_source_set_event_handler(_timer, ^{ + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + struct rusage currentRusage; + getrusage(RUSAGE_SELF, ¤tRusage); + + @synchronized (self) { + if (currentRusage.ru_utime.tv_sec > strongSelf->_rusageBaseline + strongSelf->_runtimeSecondsBeforeWatchdog) { + seccritical("SecWatchdog: watchdog has detected securityd/secd is using too much CPU - attempting to exit gracefully"); +#if !TARGET_OS_MAC + WriteStackshotReport(@"securityd watchdog triggered", __sec_exception_code_Watchdog); +#endif + xpc_transaction_exit_clean(); // we've used too much CPU - try to exit gracefully + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(strongSelf->_gracefulExitLeeway * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + // if we still haven't exited gracefully after 5 minutes, time to die unceremoniously + seccritical("SecWatchdog: watchdog has failed to exit securityd/secd gracefully - exiting ungracefully"); + exit(EXIT_FAILURE); + }); + } + else { + CFTimeInterval currentTime = CFAbsoluteTimeGetCurrent(); + if (currentTime > strongSelf->_lastCheckTime + strongSelf->_resetPeriod) { + // we made it through a 24 hour period - reset our timeout to 24 hours from now, and our cpu usage threshold to another 20 minutes + secinfo("SecWatchdog", "resetting watchdog monitoring interval ahead another 24 hours"); + strongSelf->_lastCheckTime = currentTime; + strongSelf->_rusageBaseline = currentRusage.ru_utime.tv_sec; + } + } + } + }); + dispatch_resume(_timer); + } +} + +- (NSDictionary*)watchdogParameters +{ + @synchronized (self) { + return @{ SecdWatchdogAllowedRuntime : @(_runtimeSecondsBeforeWatchdog), + SecdWatchdogResetPeriod : @(_resetPeriod), + SecdWatchdogCheckPeriod : @(_checkPeriod), + SecdWatchdogGracefulExitTime : @(_gracefulExitLeeway) }; + } +} + +- (BOOL)setWatchdogParameters:(NSDictionary*)parameters error:(NSError**)error +{ + NSMutableArray* failedParameters = [NSMutableArray array]; + @synchronized (self) { + __weak __typeof(self) weakSelf = self; + [parameters enumerateKeysAndObjectsUsingBlock:^(NSString* parameter, NSNumber* value, BOOL* stop) { + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + if ([parameter isEqualToString:SecdWatchdogAllowedRuntime] && [value isKindOfClass:[NSNumber class]]) { + strongSelf->_runtimeSecondsBeforeWatchdog = value.longValue; + } + else if ([parameter isEqualToString:SecdWatchdogResetPeriod] && [value isKindOfClass:[NSNumber class]]) { + strongSelf->_resetPeriod = value.longValue; + } + else if ([parameter isEqualToString:SecdWatchdogCheckPeriod] && [value isKindOfClass:[NSNumber class]]) { + strongSelf->_checkPeriod = value.longValue; + } + else if ([parameter isEqualToString:SecdWatchdogGracefulExitTime] && [value isKindOfClass:[NSNumber class]]) { + strongSelf->_gracefulExitLeeway = value.longValue; + } + else { + [failedParameters addObject:parameter]; + } + }]; + + dispatch_source_cancel(_timer); + _timer = NULL; + } + + [self activateTimer]; + + if (failedParameters.count > 0) { + if (error) { + *error = [NSError errorWithDomain:@"com.apple.securityd.watchdog" code:0 userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"failed to set parameters: %@", failedParameters]}]; + } + + return NO; + } + else { + return YES; + } +} + +@end diff --git a/OSX/sec/ipc/client.c b/OSX/sec/ipc/client.c index 24eea6af..58272aa6 100644 --- a/OSX/sec/ipc/client.c +++ b/OSX/sec/ipc/client.c @@ -21,6 +21,19 @@ * @APPLE_LICENSE_HEADER_END@ */ +#include + +// client.c is from the iOS world and must compile with an iOS view of the headers +#ifndef SEC_IOS_ON_OSX +#define SEC_IOS_ON_OSX 1 +#endif // SEC_IOS_ON_OSX + +#if TARGET_OS_OSX +#ifndef SECITEM_SHIM_OSX +#define SECITEM_SHIM_OSX 1 +#endif // SECITEM_SHIM_OSX +#endif // TARGET_OS_OSX + #include #include #include @@ -40,9 +53,11 @@ #include #include #include // TODO Fixme this gets us SecError(). +#include #include struct securityd *gSecurityd; +struct trustd *gTrustd; // // MARK: XPC IPC. @@ -61,6 +76,8 @@ static CFArrayRef SecServerCopyAccessGroups(void) { CFSTR("sync"), #endif CFSTR("com.apple.security.sos"), + CFSTR("com.apple.security.ckks"), + CFSTR("com.apple.security.sos-usercredential"), CFSTR("com.apple.sbd"), CFSTR("com.apple.lakitu"), kSecAttrAccessGroupToken, @@ -149,9 +166,7 @@ static xpc_connection_t securityd_create_connection(const char *name, uint64_t f } static xpc_connection_t sSecuritydConnection; -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) static xpc_connection_t sTrustdConnection; -#endif static xpc_connection_t securityd_connection(void) { static dispatch_once_t once; @@ -172,8 +187,11 @@ static xpc_connection_t trustd_connection(void) { }); return sTrustdConnection; #else - // on iOS all operations are still handled by securityd - return securityd_connection(); + static dispatch_once_t once; + dispatch_once(&once, ^{ + sTrustdConnection = securityd_create_connection(kTrustdXPCServiceName, 0); + }); + return sTrustdConnection; #endif } @@ -185,7 +203,9 @@ static bool is_trust_operation(enum SecXPCOperation op) { case sec_trust_evaluate_id: case sec_trust_store_copy_all_id: case sec_trust_store_copy_usage_constraints_id: - case sec_device_is_internal_id: + case sec_ota_pki_asset_version_id: + case kSecXPCOpOTAGetEscrowCertificates: + case kSecXPCOpOTAPKIGetNewAsset: return true; default: break; @@ -209,14 +229,15 @@ static xpc_connection_t securityd_connection_for_operation(enum SecXPCOperation // NOTE: This is not thread safe, but this SPI is for testing only. void SecServerSetMachServiceName(const char *name) { // Make sure sSecXPCServer.queue exists. - securityd_connection(); + trustd_connection(); - xpc_connection_t oldConection = sSecuritydConnection; - sSecuritydConnection = securityd_create_connection(name, 0); + xpc_connection_t oldConection = sTrustdConnection; + sTrustdConnection = securityd_create_connection(name, 0); if (oldConection) xpc_release(oldConection); } +XPC_RETURNS_RETAINED xpc_object_t securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error) { @@ -236,14 +257,14 @@ securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error) CFIndex code = 0; if (reply == XPC_ERROR_CONNECTION_INTERRUPTED || reply == XPC_ERROR_CONNECTION_INVALID) { code = kSecXPCErrorConnectionFailed; + seccritical("Failed to talk to %s after %d attempts.", + (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" : #if TARGET_OS_IPHONE - seccritical("Failed to talk to %s after %d attempts.", "securityd", - max_tries); + "securityd", #else - seccritical("Failed to talk to %s after %d attempts.", - (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" : "secd", - max_tries); + "secd", #endif + max_tries); } else if (reply == XPC_ERROR_TERMINATION_IMMINENT) code = kSecXPCErrorUnknown; else @@ -260,7 +281,9 @@ securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error) return reply; } -xpc_object_t securityd_create_message(enum SecXPCOperation op, CFErrorRef* error) +XPC_RETURNS_RETAINED +xpc_object_t +securityd_create_message(enum SecXPCOperation op, CFErrorRef* error) { xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); if (message) { @@ -274,12 +297,28 @@ xpc_object_t securityd_create_message(enum SecXPCOperation op, CFErrorRef* error // Return true if there is no error in message, return false and set *error if there is. bool securityd_message_no_error(xpc_object_t message, CFErrorRef *error) { - xpc_object_t xpc_error = xpc_dictionary_get_value(message, kSecXPCKeyError); + xpc_object_t xpc_error = NULL; + if (message == NULL) + return false; + + xpc_error = xpc_dictionary_get_value(message, kSecXPCKeyError); if (xpc_error == NULL) return true; + CFErrorRef localError = SecCreateCFErrorWithXPCObject(xpc_error); + +#if TARGET_OS_IPHONE + secdebug("xpc", "Talking to securityd failed with error: %@", localError); +#else + uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation); + secdebug("xpc", "Talking to %s failed with error: %@", + (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" : "secd", localError); +#endif + if (error) { - *error = SecCreateCFErrorWithXPCObject(xpc_error); + *error = localError; + } else { + CFReleaseSafe(localError); } return false; } @@ -317,7 +356,8 @@ _SecSecuritydCopyWhoAmI(CFErrorRef *error) reply = _CFXPCCreateCFObjectFromXPCObject(response); xpc_release(response); } else { - securityd_message_no_error(response, error); + secerror("Securityd failed getting whoamid with error: %@", + error ? *error : NULL); } xpc_release(message); } @@ -389,6 +429,48 @@ _SecSyncDeleteUserViews(uid_t uid, CFErrorRef *error) return reply; } +XPC_RETURNS_RETAINED xpc_endpoint_t +_SecSecuritydCopyEndpoint(enum SecXPCOperation op, CFErrorRef *error) +{ + xpc_endpoint_t endpoint = NULL; + xpc_object_t message = securityd_create_message(op, error); + if (message) { + xpc_object_t response = securityd_message_with_reply_sync(message, error); + if (response) { + endpoint = xpc_dictionary_get_value(response, kSecXPCKeyEndpoint); + if (endpoint) { + if(xpc_get_type(endpoint) != XPC_TYPE_ENDPOINT) { + secerror("endpoint was not an endpoint"); + endpoint = NULL; + } else { + xpc_retain(endpoint); + } + } else { + secerror("endpoint was null"); + } + xpc_release(response); + } else { + secerror("Securityd failed getting endpoint with error: %@", error ? *error : NULL); + } + xpc_release(message); + } + return endpoint; +} + + +XPC_RETURNS_RETAINED xpc_endpoint_t +_SecSecuritydCopyCKKSEndpoint(CFErrorRef *error) +{ + return _SecSecuritydCopyEndpoint(kSecXPCOpCKKSEndpoint, error); +} + +XPC_RETURNS_RETAINED xpc_endpoint_t +_SecSecuritydCopySOSStatusEndpoint(CFErrorRef *error) +{ + return _SecSecuritydCopyEndpoint(kSecXPCOpSOSEndpoint, error); +} + + /* vi:set ts=4 sw=4 et: */ diff --git a/OSX/sec/ipc/client_endpoint.m b/OSX/sec/ipc/client_endpoint.m new file mode 100644 index 00000000..a846d682 --- /dev/null +++ b/OSX/sec/ipc/client_endpoint.m @@ -0,0 +1,187 @@ +/* + * 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 +#import +#import +#import +#import + +#include + +@implementation SecuritydXPCClient +@synthesize connection = _connection; + +- (instancetype) initWithEndpoint:(xpc_endpoint_t)endpoint +{ + if ((self = [super init])) { + NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SecuritydXPCProtocol)]; + NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; + + [listenerEndpoint _setEndpoint:endpoint]; + + self.connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; + if (self.connection == NULL) { + return NULL; + } + + self.connection.remoteObjectInterface = interface; + [SecuritydXPCClient configureSecuritydXPCProtocol: self.connection.remoteObjectInterface]; + } + + return self; +} + ++(void)configureSecuritydXPCProtocol: (NSXPCInterface*) interface { + NSXPCInterface *rpcCallbackInterface = [NSXPCInterface interfaceWithProtocol: @protocol(SecuritydXPCCallbackProtocol)]; + [interface setInterface:rpcCallbackInterface + forSelector:@selector(SecItemAddAndNotifyOnSync:syncCallback:complete:) + argumentIndex:1 + 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]; + } + } + }); + + @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: + identifier: + viewHint: + oldCurrentItemReference: + oldCurrentItemHash: + complete:) argumentIndex:0 ofReply:YES]; + } + @catch(NSException* e) { + secerror("Could not configure SecuritydXPCProtocol: %@", e); +#if DEBUG + @throw e; +#endif // DEBUG + } +#endif // OCTAGON +} +@end + +@implementation SecuritydXPCCallback +@synthesize callback = _callback; + +-(instancetype)initWithCallback: (SecBoolNSErrorCallback) callback { + if((self = [super init])) { + _callback = callback; + } + return self; +} + +- (void)callCallback: (bool) result error:(NSError*) error { + self.callback(result, error); +} +@end + +id SecuritydXPCProxyObject(void (^rpcErrorHandler)(NSError *)) +{ + if (gSecurityd && gSecurityd->secd_xpc_server) { + return (__bridge id)gSecurityd->secd_xpc_server; + } + + static SecuritydXPCClient* rpc; + static dispatch_once_t onceToken; + static CFErrorRef cferror = NULL; + static dispatch_queue_t queue; + __block SecuritydXPCClient *result = nil; + + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("SecuritydXPCProxyObject", DISPATCH_QUEUE_SERIAL); + }); + + dispatch_sync(queue, ^{ + if (rpc) { + result = rpc; + return; + } + + xpc_endpoint_t endpoint = _SecSecuritydCopyEndpoint(kSecXPCOpSecuritydXPCServerEndpoint, &cferror); + if (endpoint == NULL) { + return; + } + rpc = [[SecuritydXPCClient alloc] initWithEndpoint:endpoint]; + rpc.connection.invalidationHandler = ^{ + dispatch_sync(queue, ^{ + rpc = nil; + }); + }; + [rpc.connection resume]; + + result = rpc; + }); + + if (result == NULL) { + rpcErrorHandler((__bridge NSError *)cferror); + return NULL; + } else { + return [result.connection remoteObjectProxyWithErrorHandler: rpcErrorHandler]; + } +} + diff --git a/OSX/sec/ipc/com.apple.secd.plist b/OSX/sec/ipc/com.apple.secd.plist index 8a782acd..2837c47d 100644 --- a/OSX/sec/ipc/com.apple.secd.plist +++ b/OSX/sec/ipc/com.apple.secd.plist @@ -18,6 +18,8 @@ com.apple.securityd.xpc + com.apple.securityd.aps + ProgramArguments @@ -32,5 +34,18 @@ WAIT4DEBUGGER NO + LaunchEvents + + com.apple.xpc.activity + + com.apple.securityd.daily + + Priority + Utility + Interval + 86400 + + + diff --git a/OSX/sec/ipc/com.apple.securityd.plist b/OSX/sec/ipc/com.apple.securityd.plist index a894b471..4cc3c7ce 100644 --- a/OSX/sec/ipc/com.apple.securityd.plist +++ b/OSX/sec/ipc/com.apple.securityd.plist @@ -21,6 +21,8 @@ com.apple.securityd + com.apple.securityd.aps + ProgramArguments @@ -36,6 +38,16 @@ LaunchEvents + com.apple.xpc.activity + + com.apple.securityd.daily + + Priority + Utility + Interval + 86400 + + com.apple.notifyd.matching kSOSCCHoldLockForInitialSync diff --git a/OSX/sec/ipc/secd.8 b/OSX/sec/ipc/secd.8 new file mode 100644 index 00000000..0fa1bb29 --- /dev/null +++ b/OSX/sec/ipc/secd.8 @@ -0,0 +1,10 @@ +.Dd November 02, 2016 +.Dt secd 8 +.Os +.Sh NAME +.Nm secd +.Nd centralised keychain agent +.Sh DESCRIPTION +.Nm +controls access to and modification of keychain items. +Anyone who needs to use the keychain will be talking to this LaunchAgent. diff --git a/OSX/sec/ipc/securityd_client.h b/OSX/sec/ipc/securityd_client.h index 29d841ac..15f45496 100644 --- a/OSX/sec/ipc/securityd_client.h +++ b/OSX/sec/ipc/securityd_client.h @@ -25,6 +25,8 @@ #include +#include + #include #include #ifndef MINIMIZE_INCLUDES @@ -55,16 +57,18 @@ typedef struct SecCertificatePath *SecCertificatePathRef; #include #include -// TODO: This should be in client of XPC code locations... -#if SECITEM_SHIM_OSX +#include + +#if TARGET_OS_OSX #define kSecuritydXPCServiceName "com.apple.securityd.xpc" +#define kSecuritydSystemXPCServiceName "com.apple.securityd.system.xpc" #define kTrustdAgentXPCServiceName "com.apple.trustd.agent" #define kTrustdXPCServiceName "com.apple.trustd" #else #define kSecuritydXPCServiceName "com.apple.securityd" -#define kTrustdAgentXPCServiceName "com.apple.securityd" -#define kTrustdXPCServiceName "com.apple.securityd" -#endif // *** END SECITEM_SHIM_OSX *** +#define kTrustdAgentXPCServiceName "com.apple.trustd" +#define kTrustdXPCServiceName "com.apple.trustd" +#endif // *** END TARGET_OS_OSX *** // // MARK: XPC Information. @@ -74,6 +78,7 @@ extern CFStringRef sSecXPCErrorDomain; extern const char *kSecXPCKeyOperation; extern const char *kSecXPCKeyResult; +extern const char *kSecXPCKeyEndpoint; extern const char *kSecXPCKeyError; extern const char *kSecXPCKeyPeerInfoArray; extern const char *kSecXPCKeyUserLabel; @@ -93,12 +98,17 @@ extern const char *kSecXPCKeyTriesLabel; extern const char *kSecXPCKeyFileDescriptor; extern const char *kSecXPCKeyAccessGroups; extern const char *kSecXPCKeyClasses; +extern const char *kSecXPCKeyNormalizedIssuer; +extern const char *kSecXPCKeySerialNumber; +extern const char *kSecXPCKeyBackupKeybagIdentifier; +extern const char *kSecXPCKeyBackupKeybagPath; // // MARK: Dispatch macros // #define SECURITYD_XPC(sdp, wrapper, ...) ((gSecurityd && gSecurityd->sdp) ? gSecurityd->sdp(__VA_ARGS__) : wrapper(sdp ## _id, __VA_ARGS__)) +#define TRUSTD_XPC(sdp, wrapper, ...) ((gTrustd && gTrustd->sdp) ? gTrustd->sdp(__VA_ARGS__) : wrapper(sdp ## _id, __VA_ARGS__)) // // MARK: Object to XPC format conversion. @@ -140,6 +150,7 @@ extern const char *kSecXPCKeyString; extern const char *kSecXPCKeyArray; extern const char *kSecXPCKeySet; extern const char *kSecXPCKeySet2; +extern const char *kSecXPCVersion; extern const char *kSecXPCKeyReason; @@ -233,7 +244,6 @@ enum SecXPCOperation { kSecXPCOpCopyEngineState, kSecXPCOpCopyMyPeerInfo, kSecXPCOpAccountSetToNew, - kSecXPCOpSetHSA2AutoAcceptInfo, kSecXPCOpSetNewPublicBackupKey, kSecXPCOpSetBagForAllSlices, kSecXPCOpWaitForInitialSync, @@ -248,12 +258,15 @@ enum SecXPCOperation { kSecXPCOpCopyApplication, kSecXPCOpCopyCircleJoiningBlob, kSecXPCOpJoinWithCircleJoiningBlob, + kSecXPCOpKVSKeyCleanup, + kSecXPCOpPopulateKVS, kSecXPCOpAccountHasPublicKey, kSecXPCOpAccountIsNew, kSecXPCOpClearKVSPeerMessage, kSecXPCOpRegisterRecoveryPublicKey, kSecXPCOpGetRecoveryPublicKey, kSecXPCOpCopyBackupInformation, + kSecXPCOpCopyInitialSyncBlob, /* after this is free for all */ kSecXPCOpWhoAmI, kSecXPCOpTransmogrifyToSyncBubble, @@ -268,18 +281,25 @@ enum SecXPCOperation { sec_keychain_backup_keybag_uuid_id, kSecXPCOpPeersHaveViewsEnabled, kSecXPCOpProcessSyncWithPeers, - sec_device_is_internal_id, kSecXPCOpMessageFromPeerIsPending, kSecXPCOpSendToPeerIsPending, + sec_item_copy_parent_certificates_id, + sec_item_certificate_exists_id, + kSecXPCOpCKKSEndpoint, + kSecXPCOpSOSEndpoint, + kSecXPCOpSecuritydXPCServerEndpoint, + kSecXPCOpBackupKeybagAdd, + kSecXPCOpBackupKeybagDelete, }; -typedef struct { +typedef struct SecurityClient { SecTaskRef task; CFArrayRef accessGroups; bool allowSystemKeychain; bool allowSyncBubbleKeychain; bool isNetworkExtension; + bool canAccessNetworkExtensionAccessGroups; uid_t uid; CFDataRef musr; #if TARGET_OS_EMBEDDED && TARGET_HAS_KEYSTORE @@ -304,14 +324,9 @@ struct securityd { bool (*sec_item_delete)(CFDictionaryRef query, SecurityClient *client, CFErrorRef* error); bool (*sec_add_shared_web_credential)(CFDictionaryRef attributes, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error); bool (*sec_copy_shared_web_credential)(CFDictionaryRef query, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error); - SecTrustStoreRef (*sec_trust_store_for_domain)(CFStringRef domainName, CFErrorRef* error); // TODO: remove, has no msg id - bool (*sec_trust_store_contains)(SecTrustStoreRef ts, CFDataRef digest, bool *contains, CFErrorRef* error); - bool (*sec_trust_store_set_trust_settings)(SecTrustStoreRef ts, SecCertificateRef certificate, CFTypeRef trustSettingsDictOrArray, CFErrorRef* error); - bool (*sec_trust_store_remove_certificate)(SecTrustStoreRef ts, CFDataRef digest, CFErrorRef* error); - bool (*sec_truststore_remove_all)(SecTrustStoreRef ts, CFErrorRef* error); // TODO: remove, has no msg id bool (*sec_item_delete_all)(CFErrorRef* error); - SecTrustResultType (*sec_trust_evaluate)(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error); - bool (*sec_device_is_internal)(CFErrorRef* error); + CFArrayRef (*sec_item_copy_parent_certificates)(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error); + bool (*sec_item_certificate_exists)(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error); CFDataRef (*sec_keychain_backup)(SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef* error); bool (*sec_keychain_restore)(CFDataRef backup, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef* error); CFDictionaryRef (*sec_keychain_backup_syncable)(CFDictionaryRef backup_in, CFDataRef keybag, CFDataRef passcode, CFErrorRef* error); @@ -320,7 +335,6 @@ struct securityd { 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); - int (*sec_ota_pki_asset_version)(CFErrorRef* error); CFDataRef (*sec_otr_session_create_remote)(CFDataRef publicPeerId, CFErrorRef* error); bool (*sec_otr_session_process_packet_remote)(CFDataRef sessionData, CFDataRef inputPacket, CFDataRef* outputSessionData, CFDataRef* outputPacket, bool *readyForMessages, CFErrorRef* error); bool (*soscc_TryUserCredentials)(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error); @@ -373,8 +387,6 @@ struct securityd { CFStringRef (*soscc_CopyIncompatibilityInfo)(CFErrorRef* error); enum DepartureReason (*soscc_GetLastDepartureReason)(CFErrorRef* error); bool (*soscc_SetLastDepartureReason)(enum DepartureReason, CFErrorRef* error); - CFArrayRef (*ota_CopyEscrowCertificates)(uint32_t escrowRootType, CFErrorRef* error); - int (*sec_ota_pki_get_new_asset)(CFErrorRef* error); CFSetRef (*soscc_ProcessSyncWithPeers)(CFSetRef peerIDs, CFSetRef backupPeerIDs, CFErrorRef* error); SyncWithAllPeersReason (*soscc_ProcessSyncWithAllPeers)(CFErrorRef* error); bool (*soscc_EnsurePeerRegistration)(CFErrorRef* error); @@ -384,7 +396,6 @@ struct securityd { bool (*sec_set_xpc_log_settings)(CFTypeRef type, CFErrorRef* error); bool (*sec_set_circle_log_settings)(CFTypeRef type, CFErrorRef* error); SOSPeerInfoRef (*soscc_CopyMyPeerInfo)(CFErrorRef*); - bool (*soscc_SetHSA2AutoAcceptInfo)(CFDataRef, CFErrorRef*); bool (*soscc_WaitForInitialSync)(CFErrorRef*); CFArrayRef (*soscc_CopyYetToSyncViewsList)(CFErrorRef*); bool (*soscc_SetEscrowRecords)(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error); @@ -398,12 +409,13 @@ struct securityd { bool (*soscc_DeleteEngineState)(CFErrorRef *error); SOSPeerInfoRef (*soscc_CopyApplicant)(CFErrorRef *error); CFDataRef (*soscc_CopyCircleJoiningBlob)(SOSPeerInfoRef applicant, CFErrorRef *error); - bool (*soscc_JoinWithCircleJoiningBlob)(CFDataRef joiningBlob, CFErrorRef *error); + CFDataRef (*soscc_CopyInitialSyncData)(CFErrorRef *error); + bool (*soscc_JoinWithCircleJoiningBlob)(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); + bool (*soscc_SOSCCCleanupKVSKeys)(CFErrorRef *error); + bool (*soscc_SOSCCTestPopulateKVSWithBadKeys)(CFErrorRef *error); bool (*soscc_AccountHasPublicKey)(CFErrorRef *error); bool (*soscc_AccountIsNew)(CFErrorRef *error); bool (*sec_item_update_token_items)(CFStringRef tokenID, CFArrayRef query, SecurityClient *client, CFErrorRef* error); - bool (*sec_trust_store_copy_all)(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error); - bool (*sec_trust_store_copy_usage_constraints)(SecTrustStoreRef ts, CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error); bool (*sec_delete_items_with_access_groups)(CFArrayRef bundleIDs, SecurityClient *client, CFErrorRef *error); bool (*soscc_IsThisDeviceLastBackup)(CFErrorRef *error); bool (*soscc_requestSyncWithPeerOverKVS)(CFStringRef peerID, CFDataRef message, CFErrorRef *error); @@ -413,16 +425,34 @@ struct securityd { bool (*soscc_requestSyncWithPeerOverKVSIDOnly)(CFStringRef peerID, CFErrorRef *error); bool (*soscc_SOSCCMessageFromPeerIsPending)(SOSPeerInfoRef peer, CFErrorRef* error); bool (*soscc_SOSCCSendToPeerIsPending)(SOSPeerInfoRef peer, CFErrorRef* error); + CFTypeRef (*soscc_status)(void); + CFTypeRef secd_xpc_server; }; extern struct securityd *gSecurityd; +struct trustd { + SecTrustStoreRef (*sec_trust_store_for_domain)(CFStringRef domainName, CFErrorRef* error); + bool (*sec_trust_store_contains)(SecTrustStoreRef ts, CFDataRef digest, bool *contains, CFErrorRef* error); + bool (*sec_trust_store_set_trust_settings)(SecTrustStoreRef ts, SecCertificateRef certificate, CFTypeRef trustSettingsDictOrArray, CFErrorRef* error); + bool (*sec_trust_store_remove_certificate)(SecTrustStoreRef ts, CFDataRef digest, CFErrorRef* error); + bool (*sec_truststore_remove_all)(SecTrustStoreRef ts, CFErrorRef* error); + SecTrustResultType (*sec_trust_evaluate)(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, CFArrayRef *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error); + int (*sec_ota_pki_asset_version)(CFErrorRef* error); + CFArrayRef (*ota_CopyEscrowCertificates)(uint32_t escrowRootType, CFErrorRef* error); + int (*sec_ota_pki_get_new_asset)(CFErrorRef* error); + bool (*sec_trust_store_copy_all)(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error); + bool (*sec_trust_store_copy_usage_constraints)(SecTrustStoreRef ts, CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error); +}; + +extern struct trustd *gTrustd; + CFArrayRef SecAccessGroupsGetCurrent(void); // TODO Rename me CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op); -xpc_object_t securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error); -xpc_object_t securityd_create_message(enum SecXPCOperation op, CFErrorRef *error); +XPC_RETURNS_RETAINED xpc_object_t securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error); +XPC_RETURNS_RETAINED xpc_object_t securityd_create_message(enum SecXPCOperation op, CFErrorRef *error); bool securityd_message_no_error(xpc_object_t message, CFErrorRef *error); @@ -433,5 +463,78 @@ bool securityd_send_sync_and_do(enum SecXPCOperation op, CFErrorRef *error, // For testing only, never call this in a threaded program! void SecServerSetMachServiceName(const char *name); +XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopyEndpoint(enum SecXPCOperation op, CFErrorRef *error); + +#if __OBJC__ +#import +#import +typedef void (^SecBoolNSErrorCallback) (bool, NSError*); + +@protocol SecuritydXPCCallbackProtocol +- (void)callCallback: (bool) result error:(NSError*) error; +@end + +@protocol SecuritydXPCProtocol +- (void) SecItemAddAndNotifyOnSync:(NSDictionary*) attributes + syncCallback:(id) callback + complete:(void (^) (NSDictionary* opDictResult, NSArray* opArrayResult, NSError* operror)) complete; + +// For the given item (specified exactly by its hash (currently SHA1)), attempt to set the CloudKit 'current' pointer +// to point to the given item. +// This can fail if: +// 1. your knowledge of the old current item is out of date +// 2. either the new item or old item has changed (checked by hash) +// 3. If this device can't talk with CloudKit for any reason +- (void)secItemSetCurrentItemAcrossAllDevices:(NSData*)newItemPersistentRef + newCurrentItemHash:(NSData*)newItemSHA1 + accessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + viewHint:(NSString*)viewHint + oldCurrentItemReference:(NSData*)oldCurrentItemPersistentRef + oldCurrentItemHash:(NSData*)oldItemSHA1 + complete:(void (^) (NSError* operror)) complete; + +// For the given access group and identifier, check the current local idea of the 'current' item +-(void)secItemFetchCurrentItemAcrossAllDevices:(NSString*)accessGroup + identifier:(NSString*)identifier + viewHint:(NSString*)viewHint + fetchCloudValue:(bool)fetchCloudValue + complete:(void (^) (NSData* persistentref, NSError* operror)) complete; + + +// For each item in the keychainClass, return a persistant reference and the digest of the value +// The digest is not stable, and can change any time, the only promise is that if the digest +// value didn't change, the item didn't change. If digest change, the value MIGHT have changed,/ +// but it could also just have stayed the same. +// The this interface bypass SEP/AKS and for that reason is a higher performance then SecItemCopyMatching(). +- (void) secItemDigest:(NSString *)keychainClass + accessGroup:(NSString *)accessGroup + complete:(void (^)(NSArray *digest, NSError* error))complete; +@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 SecuritydXPCProxyObject(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 SecCreateLocalSecuritydXPCServer(void); + +// Make a SecBoolNSErrorCallback block into an Objective-C object (for proxying across NSXPC) +@interface SecuritydXPCCallback : NSObject { + SecBoolNSErrorCallback _callback; +} +@property SecBoolNSErrorCallback callback; +- (instancetype)initWithCallback: (SecBoolNSErrorCallback) callback; +@end + +@interface SecuritydXPCClient : NSObject { + NSXPCConnection* _connection; +} +@property NSXPCConnection* connection; + ++(void)configureSecuritydXPCProtocol: (NSXPCInterface*) interface; +@end + +#endif // OBJC #endif /* _SECURITYD_CLIENT_H_ */ diff --git a/OSX/sec/ipc/server.c b/OSX/sec/ipc/server.c index 73b00523..69dedc79 100644 --- a/OSX/sec/ipc/server.c +++ b/OSX/sec/ipc/server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2007-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,11 +26,14 @@ #include #include #include +#include #include #include #include #include +#include #include /* For SecItemDeleteAll */ +#include #include #include #include @@ -52,18 +55,18 @@ #include #include #include +#include #include #include +#include + +#include #include #include #include // 13B104+Roots:Device never moved past spinner after using approval to ENABLE icdp -#if __has_include() && TARGET_HAS_KEYSTORE -#include -#define HAVE_MOBILE_KEYBAG_SUPPORT 1 -#endif #if TARGET_OS_OSX #include #include @@ -82,184 +85,59 @@ #include #include -#if TARGET_OS_IPHONE -static int inMultiUser = 0; -#endif - - -static CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task, - CFStringRef entitlement) -{ - CFStringRef value = (CFStringRef)SecTaskCopyValueForEntitlement(task, - entitlement, NULL); - if (value && CFGetTypeID(value) != CFStringGetTypeID()) { - CFRelease(value); - value = NULL; - } - - return value; -} +#include +#include -static CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task, - CFStringRef entitlement) -{ - CFArrayRef value = (CFArrayRef)SecTaskCopyValueForEntitlement(task, - entitlement, NULL); - if (value) { - if (CFGetTypeID(value) == CFArrayGetTypeID()) { - CFIndex ix, count = CFArrayGetCount(value); - for (ix = 0; ix < count; ++ix) { - CFStringRef string = (CFStringRef)CFArrayGetValueAtIndex(value, ix); - if (CFGetTypeID(string) != CFStringGetTypeID()) { - CFRelease(value); - value = NULL; - break; - } - } - } else { - CFRelease(value); - value = NULL; - } - } +#if TARGET_OS_OSX +#include +#include +#include +#endif - return value; -} +static bool accessGroupPermitted(SecurityClient* client, CFArrayRef accessGroups, CFStringRef accessGroup) { + /* NULL accessGroups is wildcard. */ + if (!accessGroups) + return true; + /* Make sure we have a string. */ + if (!isString(accessGroup)) + return false; -static CFStringRef SecTaskCopyApplicationIdentifier(SecTaskRef task) { - return SecTaskCopyStringForEntitlement(task, - kSecEntitlementApplicationIdentifier); -} + /* Having the special accessGroup "*" allows access to all accessGroups. */ + CFRange range = { 0, CFArrayGetCount(accessGroups) }; + if (range.length && + (CFArrayContainsValue(accessGroups, range, accessGroup) || + CFArrayContainsValue(accessGroups, range, CFSTR("*")))) + return true; -#if TARGET_OS_IOS -static CFArrayRef SecTaskCopySharedWebCredentialDomains(SecTaskRef task) { - return SecTaskCopyArrayOfStringsForEntitlement(task, - kSecEntitlementAssociatedDomains); + return false; } -#endif -static CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task) { - CFMutableArrayRef groups = NULL; - CFArrayRef keychainAccessGroups = SecTaskCopyArrayOfStringsForEntitlement(task, - kSecEntitlementKeychainAccessGroups); - CFArrayRef appleSecurityApplicationGroups = SecTaskCopyArrayOfStringsForEntitlement(task, - kSecEntitlementAppleSecurityApplicationGroups); - CFStringRef appID = SecTaskCopyApplicationIdentifier(task); - CFIndex kagLen = keychainAccessGroups ? CFArrayGetCount(keychainAccessGroups) : 0; - CFIndex asagLen = appleSecurityApplicationGroups ? CFArrayGetCount(appleSecurityApplicationGroups) : 0; - bool entitlementsValidated = true; - bool hasEntitlements = (kagLen + asagLen + (appID ? 1 : 0)) > 0; -#if TARGET_OS_OSX - entitlementsValidated = SecTaskEntitlementsValidated(task); - if ((appID || asagLen) && !entitlementsValidated) { - CFReleaseNull(appID); - asagLen = 0; - } -#endif - CFIndex len = kagLen + asagLen + (appID ? 1 : 0); - // Always allow access to com.apple.token access group, unless entitlement validation explicitly failed. - CFIndex tokenLen = (!hasEntitlements || entitlementsValidated) ? 1 : 0; -#if TARGET_OS_IPHONE - if (len + tokenLen) -#endif - { - groups = CFArrayCreateMutable(kCFAllocatorDefault, len + tokenLen, &kCFTypeArrayCallBacks); - if (kagLen) - CFArrayAppendArray(groups, keychainAccessGroups, CFRangeMake(0, kagLen)); - if (appID) - CFArrayAppendValue(groups, appID); - if (asagLen) - CFArrayAppendArray(groups, appleSecurityApplicationGroups, CFRangeMake(0, asagLen)); - if (tokenLen) - CFArrayAppendValue(groups, kSecAttrAccessGroupToken); -#if TARGET_IPHONE_SIMULATOR +static bool extractAccessGroup(SecurityClient *client, CFStringRef requestedAgrp, CFStringRef *resolvedAgrp, CFErrorRef *error) { + bool ok = true; + + /* Access group sanity checking. + Similar to accessGroupsAllows, but ignores accessGroupIsNetworkExtensionAndClientIsEntitled */ + CFArrayRef accessGroups = client->accessGroups; + CFStringRef agrp = requestedAgrp; + /* Having the special accessGroup "*" allows access to all accessGroups. */ + if (CFArrayContainsValue(accessGroups, CFRangeMake(0,CFArrayGetCount(accessGroups)), CFSTR("*"))) + accessGroups = NULL; + + if (requestedAgrp) { + /* The user specified an explicit access group, validate it. */ + if (!accessGroupPermitted(client, accessGroups, requestedAgrp)) + ok = SecError(errSecMissingEntitlement, error, CFSTR("explicit accessGroup %@ not in client access %@"), requestedAgrp, accessGroups); } else { - secwarning("No keychain access group specified while running in simulator, falling back to default set"); - groups = (CFMutableArrayRef)CFRetainSafe(SecAccessGroupsGetCurrent()); -#endif - } - - CFReleaseSafe(appID); - CFReleaseSafe(keychainAccessGroups); - CFReleaseSafe(appleSecurityApplicationGroups); - return groups; -} - -#if TARGET_OS_IPHONE -static pthread_key_t taskThreadKey; -static void secTaskDiagnoseEntitlements(CFArrayRef accessGroups) { - SecTaskRef taskRef = pthread_getspecific(taskThreadKey); - if (taskRef == NULL) - return; - - CFErrorRef error = NULL; - CFArrayRef entitlementNames = CFArrayCreateForCFTypes(NULL, - kSecEntitlementApplicationIdentifier, - kSecEntitlementKeychainAccessGroups, - kSecEntitlementAppleSecurityApplicationGroups, - NULL); - CFDictionaryRef rawEntitlements = SecTaskCopyValuesForEntitlements(taskRef, entitlementNames, &error); - CFReleaseNull(entitlementNames); - - // exclude some error types because they're accounted-for and not the reason we're here - if (rawEntitlements == NULL && error) { - CFErrorDomain domain = CFErrorGetDomain(error); - if (domain && CFEqual(domain, kCFErrorDomainPOSIX)) { - CFIndex c = CFErrorGetCode(error); - int err = (int) c; - - switch (err) { - case ESRCH: // no such process (bad pid or process died) - return; - default: - break; - } - } + // We are using an implicit access group + // Add it as if the user specified it as an attribute. + agrp = (CFStringRef)CFArrayGetValueAtIndex(client->accessGroups, 0); } - - uint32_t cs_flags = SecTaskGetCodeSignStatus(taskRef); - CFStringRef identifier = SecTaskCopySigningIdentifier(taskRef, NULL); - CFStringRef message = NULL; - - if (rawEntitlements == NULL) { // NULL indicates failure-to-fetch (SecTask entitlements not initialized) - message = CFStringCreateWithFormat(NULL, NULL, CFSTR("failed to fetch keychain client entitlements. task=%@ procid=%@ cs_flags=0x%08.8x error=%@"), - taskRef, identifier, cs_flags, error); - secerror("MISSING keychain entitlements: retrieve-entitlements error %@", error); - } else { - // non-NULL entitlement return => SecTaskCopyEntitlements succeeeded, no error - // but note that kernel EINVAL => no entitlements, no error to deal with unsigned code - message = CFStringCreateWithFormat(NULL, NULL, CFSTR("found no keychain client entitlements. task=%@ procid=%@ cs_flags=0x%08.8x"), - taskRef, identifier, cs_flags); - secerror("MISSING keychain entitlements: raw entitlement values: %@", rawEntitlements); - secerror("MISSING keychain entitlements: original ag: %@", accessGroups); - CFArrayRef newAccessGroups = SecTaskCopyAccessGroups(taskRef); - secerror("MISSING keychain entitlements: newly parsed ag: %@", newAccessGroups); - CFReleaseNull(newAccessGroups); - } - char buffer[1000] = "?"; - CFStringGetCString(message, buffer, sizeof(buffer), kCFStringEncodingUTF8); - syslog(LOG_NOTICE, "%s", buffer); - __security_simulatecrash(message, __sec_exception_code_MissingEntitlements); - - CFReleaseNull(rawEntitlements); - CFReleaseNull(message); - CFReleaseNull(identifier); - CFReleaseNull(error); -} -#endif -static bool SecTaskGetBooleanValueForEntitlement(SecTaskRef task, - CFStringRef entitlement) { - CFStringRef canModify = (CFStringRef)SecTaskCopyValueForEntitlement(task, - entitlement, NULL); - if (!canModify) - return false; - CFTypeID canModifyType = CFGetTypeID(canModify); - bool ok = (CFBooleanGetTypeID() == canModifyType) && CFBooleanGetValue((CFBooleanRef)canModify); - CFRelease(canModify); + if (agrp && resolvedAgrp) + *resolvedAgrp = agrp; return ok; } -#if !TRUSTD_SERVER static void with_label_and_password(xpc_object_t message, void (^action)(CFStringRef label, CFDataRef password)) { const char *label_utf8 = xpc_dictionary_get_string(message, kSecXPCKeyUserLabel); @@ -305,122 +183,11 @@ static void with_label_and_number(xpc_object_t message, void (^action)(CFStringR action(user_label, number); CFReleaseNull(user_label); } -#endif /* !TRUSTD_SERVER */ - -static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, SecCertificatePathRef path, CFErrorRef *error) { - if (!path) - return true; - xpc_object_t xpc_chain = SecCertificatePathCopyXPCArray(path, error); - if (!xpc_chain) - return false; - - xpc_dictionary_set_value(message, key, xpc_chain); - xpc_release(xpc_chain); - return true; -} - -static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) { - size_t length = 0; - const void *bytes = xpc_dictionary_get_data(message, key, &length); - if (bytes) { - SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length); - if (certificate) - return certificate; - SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key); - } else { - SecError(errSecParam, error, CFSTR("object for key %s missing"), key); - } - return NULL; -} - -static bool SecXPCDictionaryCopyCertificates(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) { - xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key); - if (!xpc_certificates) - return SecError(errSecAllocate, error, CFSTR("no certs for key %s"), key); - *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error); - return *certificates; -} - -static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) { - xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key); - if (!xpc_certificates) { - *certificates = NULL; - return true; - } - *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error); - return *certificates; -} - -static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message, const char *key, CFArrayRef *policies, CFErrorRef *error) { - xpc_object_t xpc_policies = xpc_dictionary_get_value(message, key); - if (!xpc_policies) { - if (policies) - *policies = NULL; - return true; - } - *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error); - return *policies != NULL; -} - -static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) { - SecTrustStoreRef ts = NULL; - CFStringRef domain = SecXPCDictionaryCopyString(message, key, error); - if (domain) { - ts = SecTrustStoreForDomainName(domain, error); - CFRelease(domain); - } - return ts; -} - -static bool SecXPCDictionaryGetDouble(xpc_object_t message, const char *key, double *pvalue, CFErrorRef *error) { - *pvalue = xpc_dictionary_get_double(message, key); - if (*pvalue == NAN) { - return SecError(errSecParam, error, CFSTR("object for key %s bad double"), key); - } - return true; -} static CFArrayRef SecXPCDictionaryCopyPeerInfoArray(xpc_object_t dictionary, const char *key, CFErrorRef *error) { return CreateArrayOfPeerInfoWithXPCObject(xpc_dictionary_get_value(dictionary, key), error); } -static CFDataRef CFDataCreateWithXPCArrayAtIndex(xpc_object_t xpc_data_array, size_t index, CFErrorRef *error) { - CFDataRef data = NULL; - size_t length = 0; - const uint8_t *bytes = xpc_array_get_data(xpc_data_array, index, &length); - if (bytes) { - data = CFDataCreate(kCFAllocatorDefault, bytes, length); - } - if (!data) - SecError(errSecParam, error, CFSTR("data_array[%zu] failed to decode"), index); - - return data; -} - -static CFArrayRef CFDataXPCArrayCopyArray(xpc_object_t xpc_data_array, CFErrorRef *error) { - CFMutableArrayRef data_array = NULL; - require_action_quiet(xpc_get_type(xpc_data_array) == XPC_TYPE_ARRAY, exit, - SecError(errSecParam, error, CFSTR("data_array xpc value is not an array"))); - size_t count = xpc_array_get_count(xpc_data_array); - require_action_quiet(data_array = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, - SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count)); - - size_t ix; - for (ix = 0; ix < count; ++ix) { - CFDataRef data = CFDataCreateWithXPCArrayAtIndex(xpc_data_array, ix, error); - if (!data) { - CFRelease(data_array); - return NULL; - } - CFArraySetValueAtIndex(data_array, ix, data); - CFRelease(data); - } - -exit: - return data_array; -} - - static CFDataRef SecXPCDictionaryCopyCFDataRef(xpc_object_t message, const char *key, CFErrorRef *error) { CFDataRef retval = NULL; const uint8_t *bytes = NULL; @@ -434,25 +201,30 @@ errOut: return retval; } -static bool SecXPCDictionaryCopyCFDataArrayOptional(xpc_object_t message, const char *key, CFArrayRef *data_array, CFErrorRef *error) { - xpc_object_t xpc_data_array = xpc_dictionary_get_value(message, key); - if (!xpc_data_array) { - if (data_array) - *data_array = NULL; - return true; +static CFSetRef CreateCFSetRefFromXPCObject(xpc_object_t xpcSetDER, CFErrorRef* error) { + CFSetRef retval = NULL; + require_action_quiet(xpcSetDER, errOut, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Unexpected Null Set to decode"))); + + require_action_quiet(xpc_get_type(xpcSetDER) == XPC_TYPE_DATA, errOut, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("xpcSetDER not data, got %@"), xpcSetDER)); + + 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); + if (der != der_end) { + SecError(errSecDecode, error, CFSTR("trailing garbage at end of SecAccessControl data")); + goto errOut; } - *data_array = CFDataXPCArrayCopyArray(xpc_data_array, error); - return *data_array != NULL; + return retval; +errOut: + CFReleaseNull(retval); + return NULL; } static SOSPeerInfoRef SecXPCDictionaryCopyPeerInfo(xpc_object_t message, const char *key, CFErrorRef *error) { size_t length = 0; const uint8_t *der = xpc_dictionary_get_data(message, key, &length); - SecRequirementError(der != NULL, error, CFSTR("No data for key %s"), key); - - return der ? SOSPeerInfoCreateFromDER(kCFAllocatorDefault, error, &der, der + length) : NULL; - + return SecRequirementError(der != NULL, error, CFSTR("No data for key %s"), key) ? SOSPeerInfoCreateFromDER(kCFAllocatorDefault, error, &der, der + length) : NULL; } static CFSetRef SecXPCSetCreateFromXPCDictionaryElement(xpc_object_t event, const char *key) { @@ -580,9 +352,7 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, .allowSystemKeychain = false, .allowSyncBubbleKeychain = false, .isNetworkExtension = false, -#if TARGET_OS_IPHONE - .inMultiUser = inMultiUser, -#endif + .canAccessNetworkExtensionAccessGroups = false, }; secdebug("serverxpc", "entering"); @@ -590,77 +360,46 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, // TODO: Find out what we're dispatching. replyMessage = xpc_dictionary_create_reply(event); -#if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_EMBEDDED - - if (inMultiUser) { - client.activeUser = MKBForegroundUserSessionID(&error); - if (client.activeUser == -1 || client.activeUser == 0) { - assert(0); - client.activeUser = 0; - } - - /* - * If we are a edu mode user, and its not the active user, - * then the request is coming from inside the syncbubble. - * - * otherwise we are going to execute the request as the - * active user. - */ - - if (client.uid > 501 && (uid_t)client.activeUser != client.uid) { - secinfo("serverxpc", "securityd client: sync bubble user"); - client.musr = SecMUSRCreateSyncBubbleUserUUID(client.uid); - client.keybag = KEYBAG_DEVICE; - } else { - secinfo("serverxpc", "securityd client: active user"); - client.musr = SecMUSRCreateActiveUserUUID(client.activeUser); - client.uid = (uid_t)client.activeUser; - client.keybag = KEYBAG_DEVICE; - } - } -#endif - uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation); audit_token_t auditToken = {}; xpc_connection_get_audit_token(connection, &auditToken); - - client.task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); clientAuditToken = CFDataCreate(kCFAllocatorDefault, (const UInt8*)&auditToken, sizeof(auditToken)); -#if TARGET_OS_IPHONE - pthread_setspecific(taskThreadKey, client.task); -#endif - client.accessGroups = SecTaskCopyAccessGroups(client.task); + + fill_security_client(&client, xpc_connection_get_euid(connection), auditToken); #if TARGET_OS_IOS if (operation == sec_add_shared_web_credential_id || operation == sec_copy_shared_web_credential_id) { domains = SecTaskCopySharedWebCredentialDomains(client.task); } #endif - -#if TARGET_OS_IPHONE - client.allowSystemKeychain = SecTaskGetBooleanValueForEntitlement(client.task, kSecEntitlementPrivateSystemKeychain); - client.isNetworkExtension = SecTaskGetBooleanValueForEntitlement(client.task, kSecEntitlementPrivateNetworkExtension); -#endif -#if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_EMBEDDED - if (client.inMultiUser) { - client.allowSyncBubbleKeychain = SecTaskGetBooleanValueForEntitlement(client.task, kSecEntitlementPrivateKeychainSyncBubble); - } -#endif secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64 ")", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation); switch (operation) { -#if !TRUSTD_SERVER case sec_item_add_id: { if (EntitlementAbsentOrFalse(sec_item_add_id, client.task, kSecEntitlementKeychainDeny, &error)) { CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error); if (query) { + // Check for any entitlement-required attributes + bool entitlementsCorrect = true; + if(CFDictionaryGetValue(query, kSecAttrDeriveSyncIDFromItemAttributes) || + CFDictionaryGetValue(query, kSecAttrPCSPlaintextServiceIdentifier) || + CFDictionaryGetValue(query, kSecAttrPCSPlaintextPublicKey) || + CFDictionaryGetValue(query, kSecAttrPCSPlaintextPublicIdentity)) { + entitlementsCorrect = EntitlementPresentAndTrue(sec_item_add_id, client.task, kSecEntitlementPrivateCKKSPlaintextFields, &error); + } + if (entitlementsCorrect && CFDictionaryGetValue(query, kSecAttrSysBound)) { + entitlementsCorrect = EntitlementPresentAndTrue(sec_item_add_id, client.task, kSecEntitlementPrivateSysBound, &error); + } + CFTypeRef result = NULL; - if (_SecItemAdd(query, &client, &result, &error) && result) { - SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, result, &error); - CFReleaseNull(result); + if(entitlementsCorrect) { + if (_SecItemAdd(query, &client, &result, &error) && result) { + SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, result, &error); + CFReleaseNull(result); + } } CFReleaseNull(query); } @@ -684,13 +423,27 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, } case sec_item_update_id: { - if (EntitlementAbsentOrFalse(sec_item_add_id, client.task, kSecEntitlementKeychainDeny, &error)) { + if (EntitlementAbsentOrFalse(sec_item_update_id, client.task, kSecEntitlementKeychainDeny, &error)) { CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error); if (query) { CFDictionaryRef attributesToUpdate = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyAttributesToUpdate, &error); if (attributesToUpdate) { - bool result = _SecItemUpdate(query, attributesToUpdate, &client, &error); - xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result); + // Check for any entitlement-required attributes + bool entitlementsCorrect = true; + if(CFDictionaryGetValue(query, kSecAttrDeriveSyncIDFromItemAttributes) || + CFDictionaryGetValue(attributesToUpdate, kSecAttrPCSPlaintextServiceIdentifier) || + CFDictionaryGetValue(attributesToUpdate, kSecAttrPCSPlaintextPublicKey) || + CFDictionaryGetValue(attributesToUpdate, kSecAttrPCSPlaintextPublicIdentity)) { + entitlementsCorrect = EntitlementPresentAndTrue(sec_item_update_id, client.task, kSecEntitlementPrivateCKKSPlaintextFields, &error); + } + if (entitlementsCorrect && CFDictionaryGetValue(query, kSecAttrSysBound)) { + entitlementsCorrect = EntitlementPresentAndTrue(sec_item_update_id, client.task, kSecEntitlementPrivateSysBound, &error); + } + + if(entitlementsCorrect) { + bool result = _SecItemUpdate(query, attributesToUpdate, &client, &error); + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result); + } CFReleaseNull(attributesToUpdate); } CFReleaseNull(query); @@ -724,158 +477,9 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, } break; } - case sec_trust_store_contains_id: - { - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, &error); - if (ts) { - CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, &error); - if (digest) { - bool contains; - if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, &error)) - xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, contains); - CFReleaseNull(digest); - } - } - break; - } - case sec_trust_store_set_trust_settings_id: - { - if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementModifyAnchorCertificates, &error)) { - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, &error); - if (ts) { - SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, &error); - if (certificate) { - CFTypeRef trustSettingsDictOrArray = NULL; - if (SecXPCDictionaryCopyPListOptional(event, kSecXPCKeySettings, &trustSettingsDictOrArray, &error)) { - bool result = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray, &error); - xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result); - CFReleaseSafe(trustSettingsDictOrArray); - } - CFReleaseNull(certificate); - } - } - } - break; - } - case sec_trust_store_remove_certificate_id: - { - if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementModifyAnchorCertificates, &error)) { - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, &error); - if (ts) { - CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, &error); - if (digest) { - bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, &error); - xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result); - CFReleaseNull(digest); - } - } - } - break; - } - case sec_trust_store_copy_all_id: - { - if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementModifyAnchorCertificates, &error)) { - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, &error); - if (ts) { - CFArrayRef trustStoreContents = NULL; - if(_SecTrustStoreCopyAll(ts, &trustStoreContents, &error) && trustStoreContents) { - SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, trustStoreContents, &error); - CFReleaseNull(trustStoreContents); - } - } - } - break; - } - case sec_trust_store_copy_usage_constraints_id: - { - if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementModifyAnchorCertificates, &error)) { - SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, &error); - if (ts) { - CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, &error); - if (digest) { - CFArrayRef usageConstraints = NULL; - if(_SecTrustStoreCopyUsageConstraints(ts, digest, &usageConstraints, &error) && usageConstraints) { - SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, usageConstraints, &error); - CFReleaseNull(usageConstraints); - } - CFReleaseNull(digest); - } - } - } - break; - } case sec_delete_all_id: xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, _SecItemDeleteAll(&error)); break; -#endif /* !TRUSTD_SERVER */ - case sec_trust_evaluate_id: - { - CFArrayRef certificates = NULL, anchors = NULL, policies = NULL, responses = NULL, scts = NULL, trustedLogs = NULL; - bool anchorsOnly = xpc_dictionary_get_bool(event, kSecTrustAnchorsOnlyKey); - bool keychainsAllowed = xpc_dictionary_get_bool(event, kSecTrustKeychainsAllowedKey); - double verifyTime; - if (SecXPCDictionaryCopyCertificates(event, kSecTrustCertificatesKey, &certificates, &error) && - SecXPCDictionaryCopyCertificatesOptional(event, kSecTrustAnchorsKey, &anchors, &error) && - SecXPCDictionaryCopyPoliciesOptional(event, kSecTrustPoliciesKey, &policies, &error) && - SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustResponsesKey, &responses, &error) && - SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustSCTsKey, &scts, &error) && - SecXPCDictionaryCopyArrayOptional(event, kSecTrustTrustedLogsKey, &trustedLogs, &error) && - SecXPCDictionaryGetDouble(event, kSecTrustVerifyDateKey, &verifyTime, &error)) { - // If we have no error yet, capture connection and reply in block and properly retain them. - xpc_retain(connection); - CFRetainSafe(client.task); - CFRetainSafe(clientAuditToken); - - // Clear replyMessage so we don't send a synchronous reply. - xpc_object_t asyncReply = replyMessage; - replyMessage = NULL; - - SecTrustServerEvaluateBlock(clientAuditToken, - certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, scts, trustedLogs, verifyTime, client.accessGroups, - ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef replyError) { - // Send back reply now - if (replyError) { - CFRetain(replyError); - } else { - xpc_dictionary_set_int64(asyncReply, kSecTrustResultKey, tr); - SecXPCDictionarySetPListOptional(asyncReply, kSecTrustDetailsKey, details, &replyError) && - SecXPCDictionarySetPListOptional(asyncReply, kSecTrustInfoKey, info, &replyError) && - SecXPCDictionarySetChainOptional(asyncReply, kSecTrustChainKey, chain, &replyError); - } - if (replyError) { - secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError); - xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError); - if (xpcReplyError) { - xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError); - xpc_release(xpcReplyError); - } - CFReleaseNull(replyError); - } else { - secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply); - } - - xpc_connection_send_message(connection, asyncReply); - xpc_release(asyncReply); - xpc_release(connection); - CFReleaseSafe(client.task); - CFReleaseSafe(clientAuditToken); - }); - } - CFReleaseSafe(policies); - CFReleaseSafe(anchors); - CFReleaseSafe(certificates); - CFReleaseSafe(responses); - CFReleaseSafe(scts); - CFReleaseSafe(trustedLogs); - break; - } - case sec_device_is_internal_id: - { - bool retval = SecIsDeviceInternal(NULL); - xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, retval); - break; - } -#if !TRUSTD_SERVER case sec_keychain_backup_id: { if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementRestoreKeychain, &error)) { @@ -1092,15 +696,9 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, } break; } - case sec_ota_pki_asset_version_id: - { - xpc_dictionary_set_int64(replyMessage, kSecXPCKeyResult, - SecOTAPKIGetCurrentAssetVersion(&error)); - break; - } case sec_add_shared_web_credential_id: { -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error); if (query) { CFTypeRef result = NULL; @@ -1120,7 +718,7 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, } case sec_copy_shared_web_credential_id: { -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error); if (query) { CFTypeRef result = NULL; @@ -1692,22 +1290,6 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, CFReleaseSafe(iis); } break; - case kSecXPCOpOTAGetEscrowCertificates: - { - uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType"); - CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, &error); - if (array) { - xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array); - xpc_dictionary_set_value(replyMessage, kSecXPCKeyResult, xpc_array); - xpc_release(xpc_array); - } - CFReleaseNull(array); - } - break; - case kSecXPCOpOTAPKIGetNewAsset: - xpc_dictionary_set_int64(replyMessage, kSecXPCKeyResult, - SecOTAPKISignalNewAsset(&error)); - break; case kSecXPCOpRollKeys: { bool force = xpc_dictionary_get_bool(event, "force"); @@ -1715,34 +1297,6 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, _SecServerRollKeys(force, &client, &error)); } break; - case kSecXPCOpSetHSA2AutoAcceptInfo: - if (EntitlementPresentOrWhine(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) { - CFDataRef cfbytes = NULL; - const uint8_t *bytes = NULL; - size_t len = 0; - - bytes = xpc_dictionary_get_data(event, - kSecXPCKeyHSA2AutoAcceptInfo, &len); - if (!bytes) { - SOSCreateError(kSOSErrorBadKey, - CFSTR("missing autoaccept info"), NULL, &error); - break; - } - - cfbytes = CFDataCreate(NULL, bytes, len); - if (!cfbytes) { - SOSCreateError(kSOSErrorAllocationFailure, - CFSTR("could not allocate autoaccept info"), - NULL, &error); - break; - } - - xpc_dictionary_set_bool(replyMessage, - kSecXPCKeyResult, - SOSCCSetHSA2AutoAcceptInfo_Server(cfbytes, &error)); - CFReleaseNull(cfbytes); - } - break; case kSecXPCOpWaitForInitialSync: if (EntitlementPresentOrWhine(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) { xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, @@ -1933,15 +1487,39 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, CFReleaseNull(appBlob); } break; + case kSecXPCOpCopyInitialSyncBlob: + if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementCircleJoin, &error)) { + CFDataRef initialblob = SOSCCCopyInitialSyncData_Server(&error); + if (initialblob) { + xpc_object_t xpc_object = _CFXPCCreateXPCObjectFromCFObject(initialblob); + xpc_dictionary_set_value(replyMessage, kSecXPCKeyResult, xpc_object); + xpc_release(xpc_object); + } + CFReleaseNull(initialblob); + } + break; case kSecXPCOpJoinWithCircleJoiningBlob: if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementCircleJoin, &error)) { CFDataRef joiningBlob = SecXPCDictionaryCopyCFDataRef(event, kSecXPCData, &error); - - bool retval = SOSCCJoinWithCircleJoiningBlob_Server(joiningBlob, &error); + uint64_t version = xpc_dictionary_get_uint64(event, kSecXPCVersion); + bool retval = SOSCCJoinWithCircleJoiningBlob_Server(joiningBlob, (PiggyBackProtocolVersion) version, &error); xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, retval); CFReleaseNull(joiningBlob); } break; + + case kSecXPCOpKVSKeyCleanup: + if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) { + bool retval = SOSCCCleanupKVSKeys_Server(&error); + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, retval); + } + break; + case kSecXPCOpPopulateKVS: + if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) { + bool retval = SOSCCTestPopulateKVSWithBadKeys_Server(&error); + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, retval); + } + break; case kSecXPCOpMessageFromPeerIsPending: { SOSPeerInfoRef peer = SecXPCDictionaryCopyPeerInfo(event, kSecXPCKeyPeerInfo, &error); @@ -1978,7 +1556,129 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, retval); } break; -#endif /* !TRUSTD_SERVER */ + case sec_item_copy_parent_certificates_id: + { + CFArrayRef results = NULL; + if(EntitlementPresentAndTrue(operation, client.task, kSecEntitlementPrivateCertificateAllAccess, &error)) { + CFDataRef issuer = SecXPCDictionaryCopyData(event, kSecXPCKeyNormalizedIssuer, &error); + CFArrayRef accessGroups = SecXPCDictionaryCopyArray(event, kSecXPCKeyAccessGroups, &error); + if (issuer && accessGroups) { + results = _SecItemCopyParentCertificates(issuer, accessGroups, &error); + } + CFReleaseNull(issuer); + CFReleaseNull(accessGroups); + } + SecXPCDictionarySetPListOptional(replyMessage, kSecXPCKeyResult, results, &error); + CFReleaseNull(results); + } + break; + case sec_item_certificate_exists_id: + { + bool result = false; + if(EntitlementPresentAndTrue(operation, client.task, kSecEntitlementPrivateCertificateAllAccess, &error)) { + CFDataRef issuer = SecXPCDictionaryCopyData(event, kSecXPCKeyNormalizedIssuer, &error); + CFDataRef serialNum = SecXPCDictionaryCopyData(event, kSecXPCKeySerialNumber, &error); + CFArrayRef accessGroups = SecXPCDictionaryCopyArray(event, kSecXPCKeyAccessGroups, &error); + if (issuer && serialNum && accessGroups) { + result = _SecItemCertificateExists(issuer, serialNum, accessGroups, &error); + } + CFReleaseNull(issuer); + CFReleaseNull(serialNum); + CFReleaseNull(accessGroups); + } + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result); + } + break; + case kSecXPCOpCKKSEndpoint: { + if(EntitlementPresentAndTrue(operation, client.task, kSecEntitlementPrivateCKKS, &error)) { + xpc_endpoint_t endpoint = SecServerCreateCKKSEndpoint(); + if (endpoint) { + xpc_dictionary_set_value(replyMessage, kSecXPCKeyEndpoint, endpoint); + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, true); + xpc_release(endpoint); + } else { + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, false); + } + } + break; + } + case kSecXPCOpSOSEndpoint: { + if(EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) { + xpc_endpoint_t endpoint = SOSCCCreateSOSEndpoint_server(&error); + if (endpoint) { + xpc_dictionary_set_value(replyMessage, kSecXPCKeyEndpoint, endpoint); + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, true); + xpc_release(endpoint); + } else { + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, false); + } + } + break; + } + case kSecXPCOpSecuritydXPCServerEndpoint: { + xpc_endpoint_t endpoint = SecCreateSecuritydXPCServerEndpoint(&error); + if (endpoint) { + xpc_dictionary_set_value(replyMessage, kSecXPCKeyEndpoint, endpoint); + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, true); + xpc_release(endpoint); + } else { + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, false); + } + break; + } + case kSecXPCOpBackupKeybagAdd: { + if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementBackupTableOperations, &error)) { + CFDataRef keybag = NULL, passcode = NULL; + if (SecXPCDictionaryCopyDataOptional(event, kSecXPCKeyUserPassword, &passcode, &error)) { + CFDataRef identifier = NULL; + CFDataRef pathinfo = NULL; // really a CFURLRef + bool added = _SecServerBackupKeybagAdd(&client, passcode, &identifier, &pathinfo, &error); + if (added) { + added &= SecXPCDictionarySetDataOptional(replyMessage, kSecXPCKeyBackupKeybagIdentifier, identifier, &error); + added &= SecXPCDictionarySetDataOptional(replyMessage, kSecXPCKeyBackupKeybagPath, pathinfo, &error); + SecXPCDictionarySetBool(replyMessage, kSecXPCKeyResult, added, NULL); + } else { + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, false); + } + } + CFReleaseSafe(passcode); + CFReleaseSafe(keybag); + } + break; + } + case kSecXPCOpBackupKeybagDelete: { + // >>> + if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementBackupTableOperations, &error)) { + bool deleted = false; + CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error); + if (query) { + CFTypeRef matchLimit = CFDictionaryGetValue(query, kSecMatchLimit); + bool deleteAll = matchLimit && CFEqualSafe(matchLimit, kSecMatchLimitAll); + + if (deleteAll && !EntitlementPresentAndTrue(operation, client.task, kSecEntitlementBackupTableOperationsDeleteAll, &error)) { + // require special entitlement to delete all backup keybags + } else { + CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query); + CFStringRef requestedAgrp = CFDictionaryGetValue(attributes, kSecAttrAccessGroup); + CFStringRef resolvedAgrp = NULL; + if (client.musr) { + CFDictionarySetValue(attributes, kSecAttrMultiUser, client.musr); + } + if (extractAccessGroup(&client, requestedAgrp, &resolvedAgrp, &error)) { + if (resolvedAgrp) { + CFDictionarySetValue(attributes, kSecAttrAccessGroup, resolvedAgrp); + } + deleted = _SecServerBackupKeybagDelete(attributes, deleteAll, &error); + } + CFReleaseNull(resolvedAgrp); + CFReleaseNull(attributes); + } + } + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, deleted); + CFReleaseNull(query); + } + break; + } default: break; } @@ -2054,6 +1754,15 @@ static void securityd_xpc_init(const char *service_name) } }); xpc_connection_resume(listener); + +#if OCTAGON + xpc_activity_register("com.apple.securityd.daily", XPC_ACTIVITY_CHECK_IN, ^(xpc_activity_t activity) { + xpc_activity_state_t activityState = xpc_activity_get_state(activity); + if (activityState == XPC_ACTIVITY_STATE_RUN) { + SecCKKS24hrNotification(); + } + }); +#endif } @@ -2099,13 +1808,27 @@ static void securityd_soscc_lock_hack() { } #endif -#if TRUSTD_SERVER -#include -static void trustd_init_server(void) { - SecTrustLegacySourcesEventRunloopCreate(); +#if TARGET_OS_OSX + +static char * +homedirPath(void) +{ + static char homeDir[PATH_MAX] = {}; + + if (homeDir[0] == '\0') { + struct passwd* pwd = getpwuid(getuid()); + if (pwd == NULL) + return NULL; + + if (realpath(pwd->pw_dir, homeDir) == NULL) { + strlcpy(homeDir, pwd->pw_dir, sizeof(homeDir)); + } + } + return homeDir; } #endif + int main(int argc, char *argv[]) { char *wait4debugger = getenv("WAIT4DEBUGGER"); @@ -2116,23 +1839,11 @@ int main(int argc, char *argv[]) kill(getpid(), SIGSTOP); } -#if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_EMBEDDED - { - CFDictionaryRef deviceMode = MKBUserTypeDeviceMode(NULL, NULL); - CFTypeRef value = NULL; - - if (deviceMode && CFDictionaryGetValueIfPresent(deviceMode, kMKBDeviceModeKey, &value) && CFEqual(value, kMKBDeviceModeMultiUser)) { - inMultiUser = 1; - } - CFReleaseNull(deviceMode); - } -#endif - /* Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites Secd doesn't realize DB connections get invalidated when network home directory users logout and their home gets unmounted. Exit secd, start fresh when user logs back in. */ -#if !TARGET_OS_IPHONE +#if TARGET_OS_OSX int sessionstatechanged_tok; notify_register_dispatch(kSA_SessionStateChangedNotification, &sessionstatechanged_tok, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int token __unused) { // we could be a process running as root. @@ -2145,20 +1856,29 @@ int main(int argc, char *argv[]) }); #endif +#if TARGET_OS_OSX +#define SECD_PROFILE_NAME "com.apple.secd" + const char *homedir = homedirPath(); + 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); +#endif /* TARGET_OS_OSX */ + const char *serviceName = kSecuritydXPCServiceName; -#if TRUSTD_SERVER - serviceName = kTrustdXPCServiceName; - if (argc > 1 && (!strcmp(argv[1], "--agent"))) { - serviceName = kTrustdAgentXPCServiceName; - } -#endif /* setup SQDLite before some other component have a chance to create a database connection */ - _SecServerDatabaseSetup(); + _SecDbServerSetup(); securityd_init_server(); -#if TRUSTD_SERVER - trustd_init_server(); -#endif securityd_xpc_init(serviceName); // 13B104+Roots:Device never moved past spinner after using approval to ENABLE icdp diff --git a/OSX/sec/ipc/server_endpoint.h b/OSX/sec/ipc/server_endpoint.h new file mode 100644 index 00000000..0604c726 --- /dev/null +++ b/OSX/sec/ipc/server_endpoint.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007-2009,2012-2015 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 server_endpoint_h +#define server_endpoint_h + + +#import +#import + +// A 'server' object, spun up for each client. +// Contains details of the far end's connection. +@interface SecuritydXPCServer : NSObject { + SecurityClient _client; +} +@property (weak) NSXPCConnection * connection; + +- (instancetype)initWithConnection:(NSXPCConnection *)connection; +- (bool)clientHasBooleanEntitlement: (NSString*) entitlement; +@end + +#endif /* server_endpoint_h */ diff --git a/OSX/sec/ipc/server_endpoint.m b/OSX/sec/ipc/server_endpoint.m new file mode 100644 index 00000000..2ad415ad --- /dev/null +++ b/OSX/sec/ipc/server_endpoint.m @@ -0,0 +1,194 @@ +/* + * 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 +#import +#import +#include +#include + +#include +#include +#include +#include + +#include +#include + +#pragma mark - Securityd Server + +@implementation SecuritydXPCServer +@synthesize connection = _connection; + +- (instancetype)initWithConnection:(NSXPCConnection *)connection +{ + if ((self = [super init])) { + _connection = connection; + + fill_security_client(&self->_client, connection.effectiveUserIdentifier, connection.auditToken); + } + return self; +} + +- (instancetype)initWithSecurityClient:(SecurityClient*) existingClient +{ + if(!existingClient) { + return nil; + } + if((self = [super init])) { + _connection = nil; + + self->_client.task = CFRetainSafe(existingClient->task); + self->_client.accessGroups = CFRetainSafe(existingClient->accessGroups); + self->_client.allowSystemKeychain = existingClient->allowSystemKeychain; + self->_client.allowSyncBubbleKeychain = existingClient->allowSyncBubbleKeychain; + self->_client.isNetworkExtension = existingClient->isNetworkExtension; + self->_client.canAccessNetworkExtensionAccessGroups = existingClient->canAccessNetworkExtensionAccessGroups; + self->_client.uid = existingClient->uid; + self->_client.musr = CFRetainSafe(existingClient->musr); +#if TARGET_OS_EMBEDDED && TARGET_HAS_KEYSTORE + self->_client.keybag = existingClient->keybag; +#endif +#if TARGET_OS_IPHONE + self->_client.inMultiUser = existingClient->inMultiUser; + self->_client.activeUser = existingClient->activeUser; +#endif + } + return self; +} + + +- (bool)clientHasBooleanEntitlement: (NSString*) entitlement { + return SecTaskGetBooleanValueForEntitlement(self->_client.task, (__bridge CFStringRef) entitlement); +} + +-(void)dealloc { + CFReleaseNull(self->_client.task); + CFReleaseNull(self->_client.accessGroups); + CFReleaseNull(self->_client.musr); +} +@end + + +// Class to use for local dispatching of securityd xpcs. Adds capability of fake entitlements, because you don't have a real task on the other end. +@interface LocalSecuritydXPCServer : SecuritydXPCServer +@property NSMutableDictionary* fakeEntitlements; +- (instancetype)initWithSecurityClient:(SecurityClient*) existingClient fakeEntitlements:(NSDictionary*)fakeEntitlements; +@end + +@implementation LocalSecuritydXPCServer +- (instancetype)initWithSecurityClient:(SecurityClient*) existingClient fakeEntitlements:(NSDictionary*)fakeEntitlements { + if((self = [super initWithSecurityClient: existingClient])) { + _fakeEntitlements = [fakeEntitlements mutableCopy]; + } + return self; +} + +- (bool)clientHasBooleanEntitlement: (NSString*) entitlement { + if(self.fakeEntitlements) { + return [self.fakeEntitlements[entitlement] isEqual: @YES]; + } else { + return false; + } +} +@end + + +#pragma mark - SecuritydXPCServerListener + +// Responsible for bringing up new SecuritydXPCServer objects, and configuring them with their remote connection +@interface SecuritydXPCServerListener : NSObject +@property (retain,nonnull) NSXPCListener *listener; +- (xpc_endpoint_t)xpcControlEndpoint; +@end + +@implementation SecuritydXPCServerListener +-(instancetype)init +{ + if((self = [super init])){ + self.listener = [NSXPCListener anonymousListener]; + self.listener.delegate = self; + [self.listener resume]; + } + return self; +} + +- (xpc_endpoint_t)xpcControlEndpoint { + return [self.listener.endpoint _endpoint]; +} + +- (BOOL)listener:(__unused NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection +{ + // Anyone is allowed to get a connection to securityd, except if you have kSecEntitlementKeychainDeny entitlement + // The SecuritydClient class _must_ check for required entitlements in each XPC handler. + + if([newConnection valueForEntitlement: (__bridge NSString*) kSecEntitlementKeychainDeny]) { + return NO; + } + + newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SecuritydXPCProtocol)]; + // Configure the interface on the server side, too + [SecuritydXPCClient configureSecuritydXPCProtocol: newConnection.exportedInterface]; + + newConnection.exportedObject = [[SecuritydXPCServer alloc] initWithConnection:newConnection]; + [newConnection resume]; + + return YES; +} +@end + +XPC_RETURNS_RETAINED xpc_endpoint_t SecCreateSecuritydXPCServerEndpoint(CFErrorRef *error) +{ + static SecuritydXPCServerListener* listener = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + listener = [[SecuritydXPCServerListener alloc] init]; + }); + return [listener xpcControlEndpoint]; +} + +id SecCreateLocalSecuritydXPCServer(void) { + // Create a fake securitydxpcserver using the access groups of securityd and some number of fake entitlements + SecurityClient* client = SecSecurityClientGet(); + + // We know that SecuritydXPCServerListener will comply with SecuritydXPCProtocol via category, so help the compiler out + return (id) [[LocalSecuritydXPCServer alloc] initWithSecurityClient: client fakeEntitlements: @{}]; +} + +CFTypeRef SecCreateLocalCFSecuritydXPCServer(void) { + return (CFTypeRef) CFBridgingRetain(SecCreateLocalSecuritydXPCServer()); +} + +void SecResetLocalSecuritydXPCFakeEntitlements(void) { + if([(__bridge id) gSecurityd->secd_xpc_server isKindOfClass: [LocalSecuritydXPCServer class]]) { + LocalSecuritydXPCServer* server = (__bridge LocalSecuritydXPCServer*)gSecurityd->secd_xpc_server; + server.fakeEntitlements = [[NSMutableDictionary alloc] init]; + } +} + +void SecAddLocalSecuritydXPCFakeEntitlement(CFStringRef entitlement, CFTypeRef value) { + if([(__bridge id) gSecurityd->secd_xpc_server isKindOfClass: [LocalSecuritydXPCServer class]]) { + LocalSecuritydXPCServer* server = (__bridge LocalSecuritydXPCServer*)gSecurityd->secd_xpc_server; + server.fakeEntitlements[(__bridge NSString*)entitlement] = (__bridge id)value; + } +} diff --git a/OSX/sec/ipc/server_entitlement_helpers.c b/OSX/sec/ipc/server_entitlement_helpers.c new file mode 100644 index 00000000..68b9d1c9 --- /dev/null +++ b/OSX/sec/ipc/server_entitlement_helpers.c @@ -0,0 +1,205 @@ +/* + * 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@ + */ + +#include + +#include "server_entitlement_helpers.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task, + CFStringRef entitlement) +{ + CFStringRef value = (CFStringRef)SecTaskCopyValueForEntitlement(task, + entitlement, NULL); + if (value && CFGetTypeID(value) != CFStringGetTypeID()) { + CFRelease(value); + value = NULL; + } + + return value; +} + +CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task, + CFStringRef entitlement) +{ + CFArrayRef value = (CFArrayRef)SecTaskCopyValueForEntitlement(task, + entitlement, NULL); + if (value) { + if (CFGetTypeID(value) == CFArrayGetTypeID()) { + CFIndex ix, count = CFArrayGetCount(value); + for (ix = 0; ix < count; ++ix) { + CFStringRef string = (CFStringRef)CFArrayGetValueAtIndex(value, ix); + if (CFGetTypeID(string) != CFStringGetTypeID()) { + CFRelease(value); + value = NULL; + break; + } + } + } else { + CFRelease(value); + value = NULL; + } + } + + return value; +} + +CFStringRef SecTaskCopyApplicationIdentifier(SecTaskRef task) { + return SecTaskCopyStringForEntitlement(task, + kSecEntitlementApplicationIdentifier); +} +#if TARGET_OS_IOS +CFArrayRef SecTaskCopySharedWebCredentialDomains(SecTaskRef task) { + return SecTaskCopyArrayOfStringsForEntitlement(task, + kSecEntitlementAssociatedDomains); +} +#endif +CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task) { + CFMutableArrayRef groups = NULL; + CFArrayRef keychainAccessGroups = SecTaskCopyArrayOfStringsForEntitlement(task, + kSecEntitlementKeychainAccessGroups); + CFArrayRef appleSecurityApplicationGroups = SecTaskCopyArrayOfStringsForEntitlement(task, + kSecEntitlementAppleSecurityApplicationGroups); + CFStringRef appID = SecTaskCopyApplicationIdentifier(task); + CFIndex kagLen = keychainAccessGroups ? CFArrayGetCount(keychainAccessGroups) : 0; + CFIndex asagLen = appleSecurityApplicationGroups ? CFArrayGetCount(appleSecurityApplicationGroups) : 0; + bool entitlementsValidated = true; + bool hasEntitlements = (kagLen + asagLen + (appID ? 1 : 0)) > 0; +#if TARGET_OS_OSX + entitlementsValidated = SecTaskEntitlementsValidated(task); + if ((appID || asagLen) && !entitlementsValidated) { + CFReleaseNull(appID); + asagLen = 0; + } +#endif + CFIndex len = kagLen + asagLen + (appID ? 1 : 0); + // Always allow access to com.apple.token access group, unless entitlement validation explicitly failed. + CFIndex tokenLen = (!hasEntitlements || entitlementsValidated) ? 1 : 0; +#if TARGET_OS_IPHONE + if (len + tokenLen) +#endif + { + groups = CFArrayCreateMutable(kCFAllocatorDefault, len + tokenLen, &kCFTypeArrayCallBacks); + if (kagLen) + CFArrayAppendArray(groups, keychainAccessGroups, CFRangeMake(0, kagLen)); + if (appID) + CFArrayAppendValue(groups, appID); + if (asagLen) + CFArrayAppendArray(groups, appleSecurityApplicationGroups, CFRangeMake(0, asagLen)); + if (tokenLen) + CFArrayAppendValue(groups, kSecAttrAccessGroupToken); +#if TARGET_IPHONE_SIMULATOR + } else { + secwarning("No keychain access group specified while running in simulator, falling back to default set"); + groups = (CFMutableArrayRef)CFRetainSafe(SecAccessGroupsGetCurrent()); +#endif + } + + CFReleaseSafe(appID); + CFReleaseSafe(keychainAccessGroups); + CFReleaseSafe(appleSecurityApplicationGroups); + return groups; +} + +#if TARGET_OS_IPHONE +pthread_key_t taskThreadKey; +void secTaskDiagnoseEntitlements(CFArrayRef accessGroups) { + SecTaskRef taskRef = pthread_getspecific(taskThreadKey); + if (taskRef == NULL) + return; + + CFErrorRef error = NULL; + CFArrayRef entitlementNames = CFArrayCreateForCFTypes(NULL, + kSecEntitlementApplicationIdentifier, + kSecEntitlementKeychainAccessGroups, + kSecEntitlementAppleSecurityApplicationGroups, + NULL); + CFDictionaryRef rawEntitlements = SecTaskCopyValuesForEntitlements(taskRef, entitlementNames, &error); + CFReleaseNull(entitlementNames); + + // exclude some error types because they're accounted-for and not the reason we're here + if (rawEntitlements == NULL && error) { + CFErrorDomain domain = CFErrorGetDomain(error); + if (domain && CFEqual(domain, kCFErrorDomainPOSIX)) { + CFIndex c = CFErrorGetCode(error); + int err = (int) c; + + switch (err) { + case ESRCH: // no such process (bad pid or process died) + return; + default: + break; + } + } + } + + uint32_t cs_flags = SecTaskGetCodeSignStatus(taskRef); + CFStringRef identifier = SecTaskCopySigningIdentifier(taskRef, NULL); + CFStringRef message = NULL; + + if (rawEntitlements == NULL) { // NULL indicates failure-to-fetch (SecTask entitlements not initialized) + message = CFStringCreateWithFormat(NULL, NULL, CFSTR("failed to fetch keychain client entitlements. task=%@ procid=%@ cs_flags=0x%08.8x error=%@"), + taskRef, identifier, cs_flags, error); + secerror("MISSING keychain entitlements: retrieve-entitlements error %@", error); + } else { + // non-NULL entitlement return => SecTaskCopyEntitlements succeeeded, no error + // but note that kernel EINVAL => no entitlements, no error to deal with unsigned code + message = CFStringCreateWithFormat(NULL, NULL, CFSTR("found no keychain client entitlements. task=%@ procid=%@ cs_flags=0x%08.8x"), + taskRef, identifier, cs_flags); + secerror("MISSING keychain entitlements: raw entitlement values: %@", rawEntitlements); + secerror("MISSING keychain entitlements: original ag: %@", accessGroups); + CFArrayRef newAccessGroups = SecTaskCopyAccessGroups(taskRef); + secerror("MISSING keychain entitlements: newly parsed ag: %@", newAccessGroups); + CFReleaseNull(newAccessGroups); + } + char buffer[1000] = "?"; + CFStringGetCString(message, buffer, sizeof(buffer), kCFStringEncodingUTF8); + secerror("%s", buffer); + __security_simulatecrash(message, __sec_exception_code_MissingEntitlements); + + CFReleaseNull(rawEntitlements); + CFReleaseNull(message); + CFReleaseNull(identifier); + CFReleaseNull(error); +} +#endif + +bool SecTaskGetBooleanValueForEntitlement(SecTaskRef task, + CFStringRef entitlement) { + CFTypeRef canModify = SecTaskCopyValueForEntitlement(task, entitlement, NULL); + if (!canModify) + return false; + CFTypeID canModifyType = CFGetTypeID(canModify); + bool ok = (CFBooleanGetTypeID() == canModifyType) && CFBooleanGetValue((CFBooleanRef)canModify); + CFRelease(canModify); + return ok; +} + diff --git a/OSX/sec/ipc/server_entitlement_helpers.h b/OSX/sec/ipc/server_entitlement_helpers.h new file mode 100644 index 00000000..2aeb3411 --- /dev/null +++ b/OSX/sec/ipc/server_entitlement_helpers.h @@ -0,0 +1,48 @@ +/* + * 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 server_entitlement_helpers_h +#define server_entitlement_helpers_h + +#include +#include + +CFStringRef SecTaskCopyApplicationIdentifier(SecTaskRef task); +CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task); +bool SecTaskGetBooleanValueForEntitlement(SecTaskRef task, + CFStringRef entitlement); +CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task, + CFStringRef entitlement); +CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task, + CFStringRef entitlement); + +#if TARGET_OS_IPHONE +void secTaskDiagnoseEntitlements(CFArrayRef accessGroups); +extern pthread_key_t taskThreadKey; +#endif +#if TARGET_OS_IOS +CFArrayRef SecTaskCopySharedWebCredentialDomains(SecTaskRef task); +#endif + +#endif /* server_entitlement_helpers_h */ + diff --git a/OSX/sec/ipc/server_security_helpers.c b/OSX/sec/ipc/server_security_helpers.c new file mode 100644 index 00000000..a982bbb1 --- /dev/null +++ b/OSX/sec/ipc/server_security_helpers.c @@ -0,0 +1,124 @@ +/* + * 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@ + */ + +#include + +#include "server_security_helpers.h" +#include "server_entitlement_helpers.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __has_include() && TARGET_HAS_KEYSTORE +#include +#define HAVE_MOBILE_KEYBAG_SUPPORT 1 +#endif + +#if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_EMBEDDED +static bool +device_is_multiuser(void) +{ + static dispatch_once_t once; + static bool result; + + dispatch_once(&once, ^{ + CFDictionaryRef deviceMode = MKBUserTypeDeviceMode(NULL, NULL); + CFTypeRef value = NULL; + + if (deviceMode && CFDictionaryGetValueIfPresent(deviceMode, kMKBDeviceModeKey, &value) && CFEqual(value, kMKBDeviceModeMultiUser)) { + result = true; + } + CFReleaseNull(deviceMode); + }); + + return result; +} +#endif /* HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_EMBEDDED */ + +void fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t auditToken) { + if(!client) { + return; + } + + client->uid = uid; + +#if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_EMBEDDED + + if (device_is_multiuser()) { + CFErrorRef error = NULL; + + client->inMultiUser = true; + client->activeUser = MKBForegroundUserSessionID(&error); + if (client->activeUser == -1 || client->activeUser == 0) { + assert(0); + client->activeUser = 0; + } + + /* + * If we are a edu mode user, and its not the active user, + * then the request is coming from inside the syncbubble. + * + * otherwise we are going to execute the request as the + * active user. + */ + + if (client->uid > 501 && (uid_t)client->activeUser != client->uid) { + secinfo("serverxpc", "securityd client: sync bubble user"); + client->musr = SecMUSRCreateSyncBubbleUserUUID(client->uid); + client->keybag = KEYBAG_DEVICE; + } else { + secinfo("serverxpc", "securityd client: active user"); + client->musr = SecMUSRCreateActiveUserUUID(client->activeUser); + client->uid = (uid_t)client->activeUser; + client->keybag = KEYBAG_DEVICE; + } + } +#endif + + client->task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); + +#if TARGET_OS_IPHONE + pthread_setspecific(taskThreadKey, client->task); +#endif + + client->accessGroups = SecTaskCopyAccessGroups(client->task); + +#if TARGET_OS_IPHONE + client->allowSystemKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateSystemKeychain); + client->isNetworkExtension = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateNetworkExtension); + client->canAccessNetworkExtensionAccessGroups = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementNetworkExtensionAccessGroups); +#endif +#if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_EMBEDDED + if (client->inMultiUser) { + client->allowSyncBubbleKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateKeychainSyncBubble); + } +#endif +} + diff --git a/OSX/sec/ipc/server_security_helpers.h b/OSX/sec/ipc/server_security_helpers.h new file mode 100644 index 00000000..180d3aea --- /dev/null +++ b/OSX/sec/ipc/server_security_helpers.h @@ -0,0 +1,38 @@ +/* + * 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 server_security_helpers_h +#define server_security_helpers_h + +#include +#include + +CFTypeRef SecCreateLocalCFSecuritydXPCServer(void); +void SecAddLocalSecuritydXPCFakeEntitlement(CFStringRef entitlement, CFTypeRef value); +void SecResetLocalSecuritydXPCFakeEntitlements(void); +XPC_RETURNS_RETAINED xpc_endpoint_t SecCreateSecuritydXPCServerEndpoint(CFErrorRef *error); + +void fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t auditToken); +CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task); + +#endif /* server_security_helpers_h */ diff --git a/OSX/sec/ipc/server_xpc.m b/OSX/sec/ipc/server_xpc.m new file mode 100644 index 00000000..1b302fda --- /dev/null +++ b/OSX/sec/ipc/server_xpc.m @@ -0,0 +1,359 @@ +/* + * 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 + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "keychain/ckks/CKKSViewManager.h" + +@implementation SecuritydXPCServer (SecuritydXPCProtocol) + +- (void) SecItemAddAndNotifyOnSync:(NSDictionary*) attributes + syncCallback:(id) callback + complete:(void (^) (NSDictionary* opDictResult, NSArray* opArrayResult, NSError* operror)) complete +{ + CFErrorRef cferror = NULL; + if([self clientHasBooleanEntitlement: (__bridge NSString*) kSecEntitlementKeychainDeny]) { + SecError(errSecNotAvailable, &cferror, CFSTR("SecItemAddAndNotifyOnSync: %@ has entitlement %@"), _client.task, kSecEntitlementKeychainDeny); + //TODO: ensure cferror can transit xpc + complete(NULL, NULL, (__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + if(attributes[(id)kSecAttrDeriveSyncIDFromItemAttributes] || + attributes[(id)kSecAttrPCSPlaintextServiceIdentifier] || + attributes[(id)kSecAttrPCSPlaintextPublicKey] || + attributes[(id)kSecAttrPCSPlaintextPublicIdentity]) { + + if(![self clientHasBooleanEntitlement: (__bridge NSString*) kSecEntitlementPrivateCKKSPlaintextFields]) { + SecError(errSecMissingEntitlement, &cferror, CFSTR("SecItemAddAndNotifyOnSync: %@ does not have entitlement %@, but is using SPI anyway"), _client.task, kSecEntitlementPrivateCKKSPlaintextFields); + complete(NULL, NULL, (__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + } + + CFTypeRef cfresult = NULL; + + NSMutableDictionary* callbackQuery = [attributes mutableCopy]; + callbackQuery[@"f_ckkscallback"] = ^void (bool didSync, CFErrorRef syncerror) { + [callback callCallback: didSync error: (__bridge NSError*)syncerror]; + }; + + _SecItemAdd((__bridge CFDictionaryRef) callbackQuery, &_client, &cfresult, &cferror); + + //TODO: ensure cferror can transit xpc + + // SecItemAdd returns Some CF Object, but NSXPC is pretty adamant that everything be a specific NS type. Split it up here: + if(!cfresult) { + complete(NULL, NULL, (__bridge NSError *)(cferror)); + } else if( CFGetTypeID(cfresult) == CFDictionaryGetTypeID()) { + complete((__bridge NSDictionary *)(cfresult), NULL, (__bridge NSError *)(cferror)); + } else if( CFGetTypeID(cfresult) == CFArrayGetTypeID()) { + complete(NULL, (__bridge NSArray *)cfresult, (__bridge NSError *)(cferror)); + } else { + // TODO: actually error here + complete(NULL, NULL, NULL); + } + CFReleaseNull(cfresult); + CFReleaseNull(cferror); +} + +- (void)secItemSetCurrentItemAcrossAllDevices:(NSData* _Nonnull)newItemPersistentRef + newCurrentItemHash:(NSData* _Nonnull)newItemSHA1 + accessGroup:(NSString* _Nonnull)accessGroup + identifier:(NSString* _Nonnull)identifier + viewHint:(NSString* _Nonnull)viewHint + oldCurrentItemReference:(NSData* _Nullable)oldCurrentItemPersistentRef + oldCurrentItemHash:(NSData* _Nullable)oldItemSHA1 + complete:(void (^) (NSError* _Nullable operror)) complete +{ +#if OCTAGON + __block CFErrorRef cferror = NULL; + if([self clientHasBooleanEntitlement: (__bridge NSString*) kSecEntitlementKeychainDeny]) { + SecError(errSecNotAvailable, &cferror, CFSTR("SecItemSetCurrentItemAcrossAllDevices: %@ has entitlement %@"), _client.task, kSecEntitlementKeychainDeny); + complete((__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + if(![self clientHasBooleanEntitlement: (__bridge NSString*) kSecEntitlementPrivateCKKSWriteCurrentItemPointers]) { + SecError(errSecMissingEntitlement, &cferror, CFSTR("SecItemSetCurrentItemAcrossAllDevices: %@ does not have entitlement %@"), _client.task, kSecEntitlementPrivateCKKSWriteCurrentItemPointers); + complete((__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + if (!accessGroupsAllows(self->_client.accessGroups, (__bridge CFStringRef)accessGroup, &_client)) { + SecError(errSecMissingEntitlement, &cferror, CFSTR("SecItemSetCurrentItemAcrossAllDevices: client is missing access-group %@: %@"), accessGroup, _client.task); + complete((__bridge NSError*)cferror); + CFReleaseNull(cferror); + return; + } + + __block SecDbItemRef newItem = NULL; + __block SecDbItemRef oldItem = NULL; + + bool ok = kc_with_dbt(false, &cferror, ^bool (SecDbConnectionRef dbt) { + Query *q = query_create_with_limit( (__bridge CFDictionaryRef) @{ + (__bridge NSString *)kSecValuePersistentRef : newItemPersistentRef, + (__bridge NSString *)kSecAttrAccessGroup : accessGroup, + }, + NULL, + 1, + &cferror); + if(cferror) { + secerror("couldn't create query: %@", cferror); + return false; + } + + if(!SecDbItemQuery(q, NULL, dbt, &cferror, ^(SecDbItemRef item, bool *stop) { + newItem = CFRetainSafe(item); + })) { + query_destroy(q, NULL); + return false; + } + + if(!query_destroy(q, &cferror)) { + return false; + }; + + if(oldCurrentItemPersistentRef) { + q = query_create_with_limit( (__bridge CFDictionaryRef) @{ + (__bridge NSString *)kSecValuePersistentRef : oldCurrentItemPersistentRef, + (__bridge NSString *)kSecAttrAccessGroup : accessGroup, + }, + NULL, + 1, + &cferror); + if(cferror) { + secerror("couldn't create query: %@", cferror); + return false; + } + + if(!SecDbItemQuery(q, NULL, dbt, &cferror, ^(SecDbItemRef item, bool *stop) { + oldItem = CFRetainSafe(item); + })) { + query_destroy(q, NULL); + return false; + } + + if(!query_destroy(q, &cferror)) { + return false; + }; + } + + CKKSViewManager* manager = [CKKSViewManager manager]; + if(!manager) { + secerror("SecItemSetCurrentItemAcrossAllDevices: no view manager?"); + cferror = (CFErrorRef) CFBridgingRetain([NSError errorWithDomain:@"securityd" code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"No view manager, cannot forward request"}]); + return false; + } + [manager setCurrentItemForAccessGroup:newItem + hash:newItemSHA1 + accessGroup:accessGroup + identifier:identifier + viewHint:viewHint + replacing:oldItem + hash:oldItemSHA1 + complete:complete]; + return true; + }); + + CFReleaseNull(newItem); + CFReleaseNull(oldItem); + + if(!ok) { + secnotice("ckks", "SecItemSetCurrentItemAcrossAllDevices failed due to: %@", cferror); + complete((__bridge NSError*) cferror); + } + CFReleaseNull(cferror); +#else // ! OCTAGON + complete([NSError errorWithDomain:@"securityd" code:errSecParam userInfo:@{NSLocalizedDescriptionKey: @"SecItemSetCurrentItemAcrossAllDevices not implemented on this platform"}]); +#endif // OCTAGON +} + +-(void)secItemFetchCurrentItemAcrossAllDevices:(NSString*)accessGroup + identifier:(NSString*)identifier + viewHint:(NSString*)viewHint + fetchCloudValue:(bool)fetchCloudValue + complete:(void (^) (NSData* persistentref, NSError* operror)) complete +{ +#if OCTAGON + CFErrorRef cferror = NULL; + if([self clientHasBooleanEntitlement: (__bridge NSString*) kSecEntitlementKeychainDeny]) { + SecError(errSecNotAvailable, &cferror, CFSTR("SecItemFetchCurrentItemAcrossAllDevices: %@ has entitlement %@"), _client.task, kSecEntitlementKeychainDeny); + complete(NULL, (__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + if(![self clientHasBooleanEntitlement: (__bridge NSString*) kSecEntitlementPrivateCKKSReadCurrentItemPointers]) { + SecError(errSecNotAvailable, &cferror, CFSTR("SecItemFetchCurrentItemAcrossAllDevices: %@ does not have entitlement %@"), _client.task, kSecEntitlementPrivateCKKSReadCurrentItemPointers); + complete(NULL, (__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + if (!accessGroupsAllows(self->_client.accessGroups, (__bridge CFStringRef)accessGroup, &_client)) { + SecError(errSecMissingEntitlement, &cferror, CFSTR("SecItemFetchCurrentItemAcrossAllDevices: client is missing access-group %@: %@"), accessGroup, _client.task); + complete(NULL, (__bridge NSError*)cferror); + CFReleaseNull(cferror); + return; + } + + [[CKKSViewManager manager] getCurrentItemForAccessGroup:accessGroup + identifier:identifier + viewHint:viewHint + fetchCloudValue:fetchCloudValue + complete:^(NSString* uuid, NSError* error) { + if(error || !uuid) { + complete(NULL, error); + return; + } + + // Find the persisent ref and return it. + [self findItemPersistentRefByUUID:uuid complete:complete]; + }]; +#else // ! OCTAGON + complete(NULL, [NSError errorWithDomain:@"securityd" code:errSecParam userInfo:@{NSLocalizedDescriptionKey: @"SecItemFetchCurrentItemAcrossAllDevices not implemented on this platform"}]); +#endif // OCTAGON +} + +-(void)findItemPersistentRefByUUID:(NSString*)uuid + complete:(void (^) (NSData* persistentref, NSError* operror)) complete +{ + CFErrorRef cferror = NULL; + CFTypeRef result = NULL; + + // Must query per-class, so: + const SecDbSchema *newSchema = current_schema(); + for (const SecDbClass *const *class = newSchema->classes; *class != NULL; class++) { + CFReleaseNull(result); + CFReleaseNull(cferror); + + if(!((*class)->itemclass)) { + //Don't try to search non-item 'classes' + continue; + } + + _SecItemCopyMatching((__bridge CFDictionaryRef) @{ + (__bridge NSString*) kSecClass: (__bridge NSString*) (*class)->name, + (id)kSecAttrSynchronizable: (id)kSecAttrSynchronizableAny, + (id)kSecMatchLimit : (id)kSecMatchLimitOne, + (id)kSecAttrUUID: uuid, + (id)kSecReturnPersistentRef: @YES, + }, + &self->_client, + &result, + &cferror); + + if(cferror && CFErrorGetCode(cferror) != errSecItemNotFound) { + break; + } + + if(result) { + // Found the persistent ref! Quit searching. + break; + } + } + + complete((__bridge NSData*) result, (__bridge NSError*) cferror); + CFReleaseNull(result); + CFReleaseNull(cferror); +} + +- (void) secItemDigest:(NSString *)itemClass + accessGroup:(NSString *)accessGroup + complete:(void (^)(NSArray *digest, NSError* error))complete +{ + CFArrayRef accessGroups = self->_client.accessGroups; + __block CFErrorRef cferror = NULL; + __block CFArrayRef result = NULL; + + if (itemClass == NULL || accessGroup == NULL) { + SecError(errSecParam, &cferror, CFSTR("parameter missing: %@"), _client.task); + complete(NULL, (__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + if (![itemClass isEqualToString:@"inet"] && ![itemClass isEqualToString:@"genp"]) { + SecError(errSecParam, &cferror, CFSTR("class %@ is not supported: %@"), itemClass, _client.task); + complete(NULL, (__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + if (!accessGroupsAllows(accessGroups, (__bridge CFStringRef)accessGroup, &_client)) { + SecError(errSecMissingEntitlement, &cferror, CFSTR("Client is missing access-group %@: %@"), accessGroup, _client.task); + complete(NULL, (__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + if (CFArrayContainsValue(accessGroups, CFRangeMake(0, CFArrayGetCount(accessGroups)), CFSTR("*"))) { + /* Having the special accessGroup "*" allows access to all accessGroups. */ + accessGroups = NULL; + } + + NSDictionary *attributes = @{ + (__bridge NSString *)kSecClass : itemClass, + (__bridge NSString *)kSecAttrAccessGroup : accessGroup, + (__bridge NSString *)kSecAttrSynchronizable : (__bridge NSString *)kSecAttrSynchronizableAny, + }; + + Query *q = query_create_with_limit((__bridge CFDictionaryRef)attributes, _client.musr, 0, &cferror); + if (q == NULL) { + SecError(errSecParam, &cferror, CFSTR("failed to build query: %@"), _client.task); + complete(NULL, (__bridge NSError*) cferror); + CFReleaseNull(cferror); + return; + } + + bool ok = kc_with_dbt(false, &cferror, ^(SecDbConnectionRef dbt) { + return (bool)s3dl_copy_digest(dbt, q, &result, accessGroups, &cferror); + }); + + (void)ok; + + complete((__bridge NSArray *)result, (__bridge NSError *)cferror); + + (void)query_destroy(q, &cferror); + + CFReleaseNull(result); + CFReleaseNull(cferror); +} + + +@end diff --git a/OSX/sec/securityd/AsymKeybagBackup.h b/OSX/sec/securityd/AsymKeybagBackup.h new file mode 100644 index 00000000..1ae8c5fc --- /dev/null +++ b/OSX/sec/securityd/AsymKeybagBackup.h @@ -0,0 +1,45 @@ +/* + * 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@ + */ + +/*! + @header SecBackupServer + The functions provided in SecBackupServer provide an interface to + the backend for SecBackup SPIs in the server. + */ + +#ifndef SecBackupServer_h +#define SecBackupServer_h + +#include +#include +#include +#include + +__BEGIN_DECLS + +bool _SecServerBackupKeybagAdd(SecurityClient *client, CFDataRef passcode, CFDataRef *identifier, CFDataRef *pathinfo, CFErrorRef *error); +bool _SecServerBackupKeybagDelete(CFDictionaryRef attributes, bool deleteAll, CFErrorRef *error); + +__END_DECLS + +#endif /* SecBackupServer_h */ diff --git a/OSX/sec/securityd/AsymKeybagBackup.m b/OSX/sec/securityd/AsymKeybagBackup.m new file mode 100644 index 00000000..bf21ed08 --- /dev/null +++ b/OSX/sec/securityd/AsymKeybagBackup.m @@ -0,0 +1,147 @@ +/* + * 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@ + */ + +#include +#import +#include +#import "AsymKeybagBackup.h" +#import + +#if USE_KEYSTORE +#include +#endif + +#include +#include +#include "sec/ipc/securityd_client.h" + +#if OCTAGON +#import "SecBackupKeybagEntry.h" +#endif + +#if OCTAGON +#if USE_KEYSTORE + +static bool writeKeybagPublicKey(CFDataRef keybag, CFDataRef identifier, CFErrorRef *error) { + bool ok = true; + NSData* publickeyHash = (__bridge NSData *)(identifier); + NSData* musr = [[NSData alloc] init]; + NSError *localError = NULL; + + SecBackupKeybagEntry *kbe = [[SecBackupKeybagEntry alloc] initWithPublicKey: (__bridge NSData*)keybag publickeyHash: (NSData*) publickeyHash user: musr]; + ok = [kbe saveToDatabase: &localError]; + CFErrorPropagate((__bridge CFErrorRef)(localError), error); + return ok; +} + +static bool deleteKeybagViaPublicKeyHash(CFDataRef publickeyHash, CFStringRef agrp, CFDataRef musr, CFErrorRef *error) { + bool ok = true; + NSData* keybag = nil; + NSError *localError = NULL; + + SecBackupKeybagEntry *kbe = [[SecBackupKeybagEntry alloc] initWithPublicKey: keybag publickeyHash: (__bridge NSData*)publickeyHash user: (__bridge NSData *)(musr)]; + ok = [kbe deleteFromDatabase: &localError]; + + CFErrorPropagate((__bridge CFErrorRef)(localError), error); + return ok; +} + +static bool deleteAllKeybags(CFErrorRef *error) { + NSError *localError = NULL; + + bool ok = [SecBackupKeybagEntry deleteAll: &localError]; + + CFErrorPropagate((__bridge CFErrorRef)(localError), error); + return ok; +} + +#endif +#endif + +bool _SecServerBackupKeybagAdd(SecurityClient *client, CFDataRef passcode, CFDataRef *identifier, CFDataRef *pathinfo, CFErrorRef *error) { + bool ok = true; +#if OCTAGON +#if USE_KEYSTORE + CFURLRef upathinfo = NULL; + CFDataRef keybagData = NULL; + uuid_t uuid; + char uuidstr[37]; + CFDataRef tidentifier = NULL; + + secerror("_SecServerBackupKeybagAdd: passlen: %ld", CFDataGetLength(passcode) ); + + require_action(passcode && CFDataGetLength(passcode), xit, ok = SecError(errSecParam, error, CFSTR("passcode is required"))); + keybag_handle_t handle = bad_keybag_handle; + + kern_return_t kr = aks_create_bag(CFDataGetBytePtr(passcode), (int)CFDataGetLength(passcode), kAppleKeyStoreAsymmetricBackupBag, &handle); + require_action(kr == kIOReturnSuccess, xit, ok = SecError(errSecParam, error, CFSTR("could not create keybag: %d"), kr)); + + void *keybag = NULL; + int keybag_size = 0; + kr = aks_save_bag(handle, &keybag, &keybag_size); + require_action(kr == kIOReturnSuccess, xit, ok = SecError(errSecParam, error, CFSTR("could not save keybag: %d"), kr)); + keybagData = CFDataCreate(kCFAllocatorDefault, keybag, keybag_size); + + // For now, use uuid as key in db; will use publicKey hash later + kr = aks_get_bag_uuid(handle, uuid); + require_action(kr == kIOReturnSuccess, xit, ok = SecError(errSecParam, error, CFSTR("could not get keybag uuid: %d"), kr)); + + tidentifier = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)uuidstr, sizeof(uuidstr)); + uuid_unparse_lower(uuid, uuidstr); + if (identifier) + *identifier = CFRetainSafe(tidentifier); + + require_action(writeKeybagPublicKey(keybagData, tidentifier, error), xit, ok = SecError(errSecParam, error, CFSTR("passcode is required"))); + + if (pathinfo) + *pathinfo = NULL; +xit: + CFReleaseNull(tidentifier); + CFReleaseNull(upathinfo); + CFReleaseNull(keybagData); +#endif /* USE_KEYSTORE */ +#endif + return ok; +} + +bool _SecServerBackupKeybagDelete(CFDictionaryRef attributes, bool deleteAll, CFErrorRef *error) { + bool ok = true; +#if OCTAGON +#if USE_KEYSTORE + // Look for matching publicKeyHash + + if (deleteAll) { + deleteAllKeybags(error); + } else { + CFDataRef publickeyHash = (CFDataRef)CFDictionaryGetValue(attributes, kSecAttrPublicKeyHash); + CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributes, kSecAttrAccessGroup); + CFDataRef musr = (CFDataRef)CFDictionaryGetValue(attributes, kSecAttrMultiUser); + + require_action(publickeyHash, xit, ok = SecError(errSecParam, error, CFSTR("publickeyHash is required"))); + ok = deleteKeybagViaPublicKeyHash(publickeyHash, agrp, musr, error); + } +xit: +#endif /* USE_KEYSTORE */ +#endif /* OCTAGON */ + return ok; +} diff --git a/OSX/sec/securityd/Info-macOS.plist b/OSX/sec/securityd/Info-macOS.plist new file mode 100644 index 00000000..db4a61ea --- /dev/null +++ b/OSX/sec/securityd/Info-macOS.plist @@ -0,0 +1,26 @@ + + + + + CFBundleAllowMixedLocalizations + + CFBundleDevelopmentRegion + English + CFBundleExecutable + secd + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + securityd + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/OSX/sec/securityd/OTATrustUtilities.c b/OSX/sec/securityd/OTATrustUtilities.c index 4fd57bc5..8b4f990f 100644 --- a/OSX/sec/securityd/OTATrustUtilities.c +++ b/OSX/sec/securityd/OTATrustUtilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004,2006-2010,2013-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2003-2004,2006-2010,2013-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -130,7 +130,7 @@ struct _OpaqueSecOTAPKI CFSetRef _grayListSet; CFDictionaryRef _allowList; CFArrayRef _trustedCTLogs; - CFDataRef _CTWhiteListData; + CFArrayRef _pinningList; CFArrayRef _escrowCertificates; CFArrayRef _escrowPCSCertificates; CFDictionaryRef _evPolicyToAnchorMapping; @@ -138,6 +138,10 @@ struct _OpaqueSecOTAPKI const char* _anchorTable; const char* _assetPath; int _assetVersion; + const char* _validUpdateSnapshot; + const char* _validDatabaseSnapshot; + CFIndex _validSnapshotVersion; + CFIndex _validSnapshotFormat; }; CFGiblisFor(SecOTAPKI) @@ -161,7 +165,7 @@ static void SecOTAPKIDestroy(CFTypeRef cf) CFReleaseNull(otapkiref->_anchorLookupTable); CFReleaseNull(otapkiref->_trustedCTLogs); - CFReleaseNull(otapkiref->_CTWhiteListData); + CFReleaseNull(otapkiref->_pinningList); if (otapkiref->_anchorTable) { free((void *)otapkiref->_anchorTable); @@ -171,6 +175,14 @@ static void SecOTAPKIDestroy(CFTypeRef cf) free((void *)otapkiref->_assetPath); otapkiref->_assetPath = NULL; } + if (otapkiref->_validUpdateSnapshot) { + free((void *)otapkiref->_validUpdateSnapshot); + otapkiref->_validUpdateSnapshot = NULL; + } + if (otapkiref->_validDatabaseSnapshot) { + free((void *)otapkiref->_validDatabaseSnapshot); + otapkiref->_validDatabaseSnapshot = NULL; + } } static CFDataRef SecOTACopyFileContents(const char *path) @@ -179,13 +191,13 @@ static CFDataRef SecOTACopyFileContents(const char *path) int fd = open(path, O_RDONLY, 0666); if (fd == -1) - { + { goto badFile; } off_t fsize = lseek(fd, 0, SEEK_END); if (fsize == (off_t)-1) - { + { goto badFile; } @@ -243,7 +255,8 @@ badFile: static Boolean PathExists(const char* path, size_t* pFileSize) { - TestOTALog("In PathExists: checking path %s\n", path); + const char *checked_path = (path) ? path : ""; + TestOTALog("In PathExists: checking path \"%s\"\n", checked_path); Boolean result = false; struct stat sb; @@ -252,74 +265,75 @@ static Boolean PathExists(const char* path, size_t* pFileSize) *pFileSize = 0; } - int stat_result = stat(path, &sb); + int stat_result = stat(checked_path, &sb); result = (stat_result == 0); - if (result) - { - TestOTALog("In PathExists: stat returned 0 for %s\n", path); - if (S_ISDIR(sb.st_mode)) - { - TestOTALog("In PathExists: %s is a directory\n", path); - // It is a directory - ; - } - else - { - TestOTALog("In PathExists: %s is a file\n", path); - // It is a file - if (NULL != pFileSize) - { - *pFileSize = (size_t)sb.st_size; - } - } - } + if (result) + { + TestOTALog("In PathExists: stat returned 0 for \"%s\"\n", checked_path); + if (S_ISDIR(sb.st_mode)) + { + TestOTALog("In PathExists: \"%s\" is a directory\n", checked_path); + // It is a directory + ; + } + else + { + TestOTALog("In PathExists: \"%s\" is a file\n", checked_path); + // It is a file + if (NULL != pFileSize) + { + *pFileSize = (size_t)sb.st_size; + } + } + } #if VERBOSE_LOGGING else { - TestOTALog("In PathExists: stat returned %d for %s\n", stat_result, path); + const char *stat_prefix = "In PathExists: stat error"; + TestOTALog("%s %d for \"%s\"\n", stat_prefix, stat_result, checked_path); int local_errno = errno; switch(local_errno) { case EACCES: - TestOTALog("In PathExists: stat failed because of EACCES\n"); + TestOTALog("%s EACCES\n", stat_prefix); break; case EBADF: - TestOTALog("In PathExists: stat failed because of EBADF (Not likely)\n"); + TestOTALog("%s EBADF\n", stat_prefix); break; case EFAULT: - TestOTALog("In PathExists: stat failed because of EFAULT (huh?)\n"); + TestOTALog("%s EFAULT\n", stat_prefix); break; case ELOOP: - TestOTALog("In PathExists: stat failed because of ELOOP (huh?)\n"); + TestOTALog("%s ELOOP\n", stat_prefix); break; case ENAMETOOLONG: - TestOTALog("In PathExists: stat failed because of ENAMETOOLONG (huh?)\n"); + TestOTALog("%s ENAMETOOLONG\n", stat_prefix); break; case ENOENT: - TestOTALog("In PathExists: stat failed because of ENOENT (missing?)\n"); + TestOTALog("%s ENOENT (missing?)\n", stat_prefix); break; case ENOMEM: - TestOTALog("In PathExists: stat failed because of ENOMEM (really?)\n"); + TestOTALog("%s ENOMEM\n", stat_prefix); break; case ENOTDIR: - TestOTALog("In PathExists: stat failed because of ENOTDIR (really?)\n"); + TestOTALog("%s ENOTDIR\n", stat_prefix); break; case EOVERFLOW: - TestOTALog("In PathExists: stat failed because of EOVERFLOW (really?)\n"); + TestOTALog("%s EOVERFLOW\n", stat_prefix); break; default: - TestOTALog("In PathExists: unknown errno of %d\n", local_errno); + TestOTALog("%s %d\n", stat_prefix, local_errno); break; } } @@ -341,7 +355,7 @@ static int rmrf(char *path) memset(path_buffer, 0, sizeof(path_buffer)); p1 = realpath(path, path_buffer); - if (!strncmp(path, p1, PATH_MAX)) + if (p1 && !strncmp(path, p1, PATH_MAX)) { return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); } @@ -505,21 +519,23 @@ static const char* InitOTADirectory(int* pAssetVersion) bool assetDirectoryExists = PathExists(kBaseAssetDirectory, NULL); if (assetDirectoryExists) { - TestOTALog("InitOTADirectory: %s exists\n", kBaseAssetDirectory); + TestOTALog("InitOTADirectory: \"%s\" exists\n", kBaseAssetDirectory); dp = opendir (kBaseAssetDirectory); if (NULL != dp) { - TestOTALog("InitOTADirectory: opendir sucessfully open %s\n", kBaseAssetDirectory); + TestOTALog("InitOTADirectory: opendir sucessfully open \"%s\"\n", kBaseAssetDirectory); while ((ep = readdir(dp))) { - TestOTALog("InitOTADirectory: processing name %s\n", ep->d_name); + TestOTALog("InitOTADirectory: processing name \"%s\"\n", ep->d_name); if (strstr(ep->d_name, kVersionDirectoryNamePrefix)) { - TestOTALog("InitOTADirectory: %s matches\n", ep->d_name); + TestOTALog("InitOTADirectory: \"%s\" matches\n", ep->d_name); memset(buffer, 0, sizeof(buffer)); snprintf(buffer, sizeof(buffer), "%s%s", kVersionDirectoryNamePrefix, kNumberString); - +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" sscanf(ep->d_name, buffer, &version); +#pragma clang diagnostic pop TestOTALog("InitOTADirectory: version = %d\n", version); @@ -607,14 +623,14 @@ static CF_RETURNS_RETAINED CFSetRef InitializeGrayList(const char* path_ptr) return result; } -static CF_RETURNS_RETAINED CFDataRef InitializeCTWhiteListData(const char* path_ptr) +static CF_RETURNS_RETAINED CFArrayRef InitializePinningList(const char* path_ptr) { - CFPropertyListRef data = CFPropertyListCopyFromAsset(path_ptr, CFSTR("CTWhiteListData")); + CFPropertyListRef list = CFPropertyListCopyFromAsset(path_ptr, CFSTR("CertificatePinning")); - if (data && (CFGetTypeID(data) == CFDataGetTypeID())) { - return data; + if (isArray(list)) { + return list; } else { - CFReleaseNull(data); + CFReleaseNull(list); return NULL; } } @@ -664,6 +680,84 @@ static CF_RETURNS_RETAINED CFDictionaryRef InitializeEVPolicyToAnchorDigestsTabl return result; } +static CFIndex InitializeValidSnapshotVersion(CFIndex *outFormat) +{ + CFIndex validVersion = 0; + CFIndex validFormat = 0; + CFDataRef validVersionData = SecSystemTrustStoreCopyResourceContents(CFSTR("ValidUpdate"), CFSTR("plist"), NULL); + if (NULL != validVersionData) + { + CFPropertyListFormat propFormat; + CFDictionaryRef versionPlist = CFPropertyListCreateWithData(kCFAllocatorDefault, validVersionData, 0, &propFormat, NULL); + if (NULL != versionPlist && CFDictionaryGetTypeID() == CFGetTypeID(versionPlist)) + { + CFNumberRef versionNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("Version")); + if (NULL != versionNumber) + { + CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &validVersion); + } + CFNumberRef formatNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("Format")); + if (NULL != formatNumber) + { + CFNumberGetValue(formatNumber, kCFNumberCFIndexType, &validFormat); + } + } + CFReleaseSafe(versionPlist); + CFReleaseSafe(validVersionData); + } + if (outFormat) { + *outFormat = validFormat; + } + return validVersion; +} + +static const char* InitializeValidSnapshotData(CFStringRef filename_str) +{ + char *result = NULL; + const char *base_error_str = "could not get valid snapshot"; + + CFURLRef valid_url = SecSystemTrustStoreCopyResourceURL(filename_str, CFSTR("sqlite3"), NULL); + if (NULL == valid_url) { + secerror("%s", base_error_str); + } else { + CFStringRef valid_str = CFURLCopyFileSystemPath(valid_url, kCFURLPOSIXPathStyle); + char file_path_buffer[PATH_MAX]; + memset(file_path_buffer, 0, PATH_MAX); + if (NULL == valid_str) { + secerror("%s path", base_error_str); + } else { + const char *valid_cstr = CFStringGetCStringPtr(valid_str, kCFStringEncodingUTF8); + if (NULL == valid_cstr) { + if (CFStringGetCString(valid_str, file_path_buffer, PATH_MAX, kCFStringEncodingUTF8)) { + valid_cstr = file_path_buffer; + } + } + if (NULL == valid_cstr) { + secerror("%s path as UTF8 string", base_error_str); + } else { + asprintf(&result, "%s", valid_cstr); + } + } + CFReleaseSafe(valid_str); + } + CFReleaseSafe(valid_url); + if (result && !PathExists(result, NULL)) { + free(result); + result = NULL; + } + return (const char*)result; +} + +static const char* InitializeValidUpdateSnapshot() +{ + return InitializeValidSnapshotData(CFSTR("update-full")); +} + +static const char* InitializeValidDatabaseSnapshot() +{ + return InitializeValidSnapshotData(CFSTR("valid")); +} + static void* MapFile(const char* path, int* out_fd, size_t* out_file_size) { void* result = NULL; @@ -986,7 +1080,7 @@ static SecOTAPKIRef SecOTACreate() otapkiref->_grayListSet = NULL; otapkiref->_allowList = NULL; otapkiref->_trustedCTLogs = NULL; - otapkiref->_CTWhiteListData = NULL; + otapkiref->_pinningList = NULL; otapkiref->_escrowCertificates = NULL; otapkiref->_escrowPCSCertificates = NULL; otapkiref->_evPolicyToAnchorMapping = NULL; @@ -994,6 +1088,10 @@ static SecOTAPKIRef SecOTACreate() otapkiref->_anchorTable = NULL; otapkiref->_assetPath = NULL; otapkiref->_assetVersion = 0; + otapkiref->_validUpdateSnapshot = NULL; + otapkiref->_validDatabaseSnapshot = NULL; + otapkiref->_validSnapshotVersion = 0; + otapkiref->_validSnapshotFormat = 0; // Start off by getting the correct asset directory info int asset_version = 0; @@ -1001,7 +1099,7 @@ static SecOTAPKIRef SecOTACreate() otapkiref->_assetPath = path_ptr; otapkiref->_assetVersion = asset_version; - TestOTALog("SecOTACreate: asset_path = %s\n", path_ptr); + TestOTALog("SecOTACreate: asset_path = \"%s\"\n", (path_ptr) ? path_ptr : ""); TestOTALog("SecOTACreate: asset_version = %d\n", asset_version); // Get the set of black listed keys @@ -1028,8 +1126,19 @@ static SecOTAPKIRef SecOTACreate() // Get the trusted Certificate Transparency Logs otapkiref->_trustedCTLogs = InitializeTrustedCTLogs(path_ptr); - // Get the EV whitelist - otapkiref->_CTWhiteListData = InitializeCTWhiteListData(path_ptr); + // Get the pinning list + otapkiref->_pinningList = InitializePinningList(path_ptr); + + // Get the valid update snapshot version and format + CFIndex update_format = 0; + otapkiref->_validSnapshotVersion = InitializeValidSnapshotVersion(&update_format); + otapkiref->_validSnapshotFormat = update_format; + + // Get the valid update snapshot path (if it exists, NULL otherwise) + otapkiref->_validUpdateSnapshot = InitializeValidUpdateSnapshot(); + + // Get the valid database snapshot path (if it exists, NULL otherwise) + otapkiref->_validDatabaseSnapshot = InitializeValidDatabaseSnapshot(); CFArrayRef escrowCerts = NULL; CFArrayRef escrowPCSCerts = NULL; @@ -1185,15 +1294,14 @@ CFArrayRef SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef) return result; } -CFDataRef SecOTAPKICopyCTWhiteList(SecOTAPKIRef otapkiRef) -{ - CFDataRef result = NULL; +CFArrayRef SecOTAPKICopyPinningList(SecOTAPKIRef otapkiRef) { + CFArrayRef result = NULL; if (NULL == otapkiRef) { return result; } - result = otapkiRef->_CTWhiteListData; + result = otapkiRef->_pinningList; CFRetainSafe(result); return result; } @@ -1283,7 +1391,7 @@ CFDictionaryRef SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef) return result; } -const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef) +const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef) { const char* result = NULL; if (NULL == otapkiRef) @@ -1295,6 +1403,54 @@ const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef) return result; } +const char* SecOTAPKIGetValidUpdateSnapshot(SecOTAPKIRef otapkiRef) +{ + const char* result = NULL; + if (NULL == otapkiRef) + { + return result; + } + + result = otapkiRef->_validUpdateSnapshot; + return result; +} + +const char* SecOTAPKIGetValidDatabaseSnapshot(SecOTAPKIRef otapkiRef) +{ + const char* result = NULL; + if (NULL == otapkiRef) + { + return result; + } + + result = otapkiRef->_validDatabaseSnapshot; + return result; +} + +CFIndex SecOTAPKIGetValidSnapshotVersion(SecOTAPKIRef otapkiRef) +{ + CFIndex result = 0; + if (NULL == otapkiRef) + { + return result; + } + + result = otapkiRef->_validSnapshotVersion; + return result; +} + +CFIndex SecOTAPKIGetValidSnapshotFormat(SecOTAPKIRef otapkiRef) +{ + CFIndex result = 0; + if (NULL == otapkiRef) + { + return result; + } + + result = otapkiRef->_validSnapshotFormat; + return result; +} + int SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef) { int result = 0; diff --git a/OSX/sec/securityd/OTATrustUtilities.h b/OSX/sec/securityd/OTATrustUtilities.h index 81b3f920..6240d158 100644 --- a/OSX/sec/securityd/OTATrustUtilities.h +++ b/OSX/sec/securityd/OTATrustUtilities.h @@ -65,32 +65,56 @@ CFArrayRef SecOTAPKICopyAllowListForAuthKeyID(SecOTAPKIRef otapkiRef, CFStringRe CF_EXPORT CFArrayRef SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef); -// Accessor to retrieve a copy of the current CT whitelist. -// Caller is responsible for releasing the returned CFSetRef +// Accessor to retrieve a copy of the current pinning list. +// Caller is responsible for releasing the returned CFArrayRef CF_EXPORT -CFDataRef SecOTAPKICopyCTWhiteList(SecOTAPKIRef otapkiRef); +CFArrayRef SecOTAPKICopyPinningList(SecOTAPKIRef otapkiRef); -// Accessor to retrieve the array of Escrow certificates +// Accessor to retrieve the array of Escrow certificates. // Caller is responsible for releasing the returned CFArrayRef CF_EXPORT CFArrayRef SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType, SecOTAPKIRef otapkiRef); -// Accessor to retrieve the dictionary of EV Policy OIDs to Anchor digest +// Accessor to retrieve the dictionary of EV Policy OIDs to Anchor digest. // Caller is responsible for releasing the returned CFDictionaryRef CF_EXPORT CFDictionaryRef SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef); -// Accessor to retrieve the dictionary of anchor digest to file offest +// Accessor to retrieve the dictionary of anchor digest to file offset. // Caller is responsible for releasing the returned CFDictionaryRef CF_EXPORT CFDictionaryRef SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef); -// Accessor to retrieve the ponter to the top of the anchor certs file +// Accessor to retrieve the pointer to the top of the anchor certs file. +// Caller should NOT free the returned pointer. The caller should hold +// a reference to the SecOTAPKIRef object until finished with +// the returned pointer. +CF_EXPORT +const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the full path to the valid update snapshot resource. +// The return value may be NULL if the resource does not exist. +// Caller should NOT free the returned pointer. The caller should hold +// a reference to the SecOTAPKIRef object until finished with +// the returned pointer. +CF_EXPORT +const char* SecOTAPKIGetValidUpdateSnapshot(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the full path to the valid database snapshot resource. +// The return value may be NULL if the resource does not exist. // Caller should NOT free the returned pointer. The caller should hold -// a reference to the SecOTAPKIRef object until finishing processing with -// the returned const char* +// a reference to the SecOTAPKIRef object until finished with +// the returned pointer. +CF_EXPORT +const char* SecOTAPKIGetValidDatabaseSnapshot(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the current valid snapshot version. +CF_EXPORT +CFIndex SecOTAPKIGetValidSnapshotVersion(SecOTAPKIRef otapkiRef); + +// Accessor to retrieve the current valid snapshot format. CF_EXPORT -const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef); +CFIndex SecOTAPKIGetValidSnapshotFormat(SecOTAPKIRef otapkiRef); // Accessor to retrieve the current OTA PKI asset version number CF_EXPORT diff --git a/OSX/sec/securityd/Regressions/SOSAccountTesting.h b/OSX/sec/securityd/Regressions/SOSAccountTesting.h index 80b5619f..d3943d81 100644 --- a/OSX/sec/securityd/Regressions/SOSAccountTesting.h +++ b/OSX/sec/securityd/Regressions/SOSAccountTesting.h @@ -26,97 +26,102 @@ #define SEC_SOSAccountTesting_h #include -#include #include #include #include #include #include +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import +#import +#import #include "SOSTestDataSource.h" #include "SOSRegressionUtilities.h" #include "SOSTransportTestTransports.h" - +#include "testmore.h" #include - // // Implicit transaction helpers // -static inline bool SOSAccountResetToOffering_wTxn(SOSAccountRef account, CFErrorRef* error) +static inline bool SOSAccountResetToOffering_wTxn(SOSAccount* acct, CFErrorRef* error) { __block bool result = false; - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { - result = SOSAccountResetToOffering(txn, error); - }); + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error); + if (!user_key) + return; + result = [acct.trust resetToOffering:txn key:user_key err:error]; + }]; return result; } -static inline bool SOSAccountJoinCirclesAfterRestore_wTxn(SOSAccountRef account, CFErrorRef* error) +static inline bool SOSAccountJoinCirclesAfterRestore_wTxn(SOSAccount* acct, CFErrorRef* error) { __block bool result = false; - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { result = SOSAccountJoinCirclesAfterRestore(txn, error); - }); + }]; return result; } -static inline bool SOSAccountJoinCircles_wTxn(SOSAccountRef account, CFErrorRef* error) +static inline bool SOSAccountJoinCircles_wTxn(SOSAccount* acct, CFErrorRef* error) { __block bool result = false; - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { result = SOSAccountJoinCircles(txn, error); - }); + }]; return result; } -static inline bool SOSAccountCheckHasBeenInSync_wTxn(SOSAccountRef account) +static inline bool SOSAccountCheckHasBeenInSync_wTxn(SOSAccount* account) { return SOSAccountHasCompletedInitialSync(account); } -static inline void SOSAccountPeerGotInSync_wTxn(SOSAccountRef account, SOSPeerInfoRef peer) +static inline void SOSAccountPeerGotInSync_wTxn(SOSAccount* acct, SOSPeerInfoRef peer) { - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { CFMutableSetRef views = SOSPeerInfoCopyEnabledViews(peer); SOSAccountPeerGotInSync(txn, SOSPeerInfoGetPeerID(peer), views); CFReleaseNull(views); - }); + }]; } -static inline bool SOSAccountSetBackupPublicKey_wTxn(SOSAccountRef account, CFDataRef backupKey, CFErrorRef* error) +static inline bool SOSAccountSetBackupPublicKey_wTxn(SOSAccount* acct, CFDataRef backupKey, CFErrorRef* error) { __block bool result = false; - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { result = SOSAccountSetBackupPublicKey(txn, backupKey, error); - }); + }]; return result; } -static inline bool SOSAccountRemoveBackupPublickey_wTxn(SOSAccountRef account, CFErrorRef* error) +static inline bool SOSAccountRemoveBackupPublickey_wTxn(SOSAccount* acct, CFErrorRef* error) { __block bool result = false; - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { result = SOSAccountRemoveBackupPublickey(txn, error); - }); + }]; return result; } -static inline SOSViewResultCode SOSAccountUpdateView_wTxn(SOSAccountRef account, CFStringRef viewname, SOSViewActionCode actionCode, CFErrorRef *error) { +static inline SOSViewResultCode SOSAccountUpdateView_wTxn(SOSAccount* acct, CFStringRef viewname, SOSViewActionCode actionCode, CFErrorRef *error) { __block SOSViewResultCode result = false; - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { - result = SOSAccountUpdateView(account, viewname, actionCode, error); - }); + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = [acct.trust updateView:acct name:viewname code:actionCode err:error]; + }]; return result; } -static inline bool SOSAccountSetMyDSID_wTxn(SOSAccountRef account, CFStringRef dsid, CFErrorRef* error) +static inline bool SOSAccountSetMyDSID_wTxn(SOSAccount* acct, CFStringRef dsid, CFErrorRef* error) { __block bool result = false; - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { result = SOSAccountSetMyDSID(txn, dsid, error); - }); + }]; return result; } @@ -128,42 +133,59 @@ static inline bool SOSAccountSetMyDSID_wTxn(SOSAccountRef account, CFStringRef d #define kAccountsAgreeTestPerPeer 1 #define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x)) -static void SOSAccountResetToTest(SOSAccountRef a, CFStringRef accountName) { - SOSUnregisterTransportKeyParameter(a->key_transport); +static void SOSAccountResetToTest(SOSAccount* a, CFStringRef accountName) { + SOSUnregisterTransportKeyParameter(a.key_transport); + SOSUnregisterTransportCircle((SOSCircleStorageTransport*)a.circle_transport); + SOSUnregisterTransportMessage((SOSMessage*)a.kvs_message_transport); + SOSUnregisterTransportMessage((SOSMessage*)a.ids_message_transport); + + if(key_transports) + CFArrayRemoveAllValue(key_transports, (__bridge CFTypeRef)(a.key_transport)); + if(message_transports){ + CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)a.ids_message_transport); + CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)a.kvs_message_transport); + } + if(circle_transports) + CFArrayRemoveAllValue(circle_transports, (__bridge CFTypeRef)a.circle_transport); - CFReleaseNull(a->circle_transport); - CFReleaseNull(a->kvs_message_transport); - CFReleaseNull(a->key_transport); + a.circle_transport = nil; + a.key_transport = nil; + a.ids_message_transport = nil; + a.kvs_message_transport = nil; SOSAccountEnsureFactoryCirclesTest(a, accountName); } -static SOSAccountRef SOSAccountCreateBasicTest(CFAllocatorRef allocator, +static SOSAccount* SOSAccountCreateBasicTest(CFAllocatorRef allocator, CFStringRef accountName, CFDictionaryRef gestalt, SOSDataSourceFactoryRef factory) { - SOSAccountRef a = SOSAccountCreateBasic(allocator, gestalt, factory); + SOSAccount* a; + a = SOSAccountCreate(kCFAllocatorDefault, gestalt, factory); return a; } -static SOSAccountRef SOSAccountCreateTest(CFAllocatorRef allocator, +static SOSAccount* SOSAccountCreateTest(CFAllocatorRef allocator, CFStringRef accountName, CFDictionaryRef gestalt, SOSDataSourceFactoryRef factory) { - SOSAccountRef a = SOSAccountCreateBasicTest(allocator, accountName, gestalt, factory); + SOSAccount* a = SOSAccountCreateBasicTest(allocator, accountName, gestalt, factory); SOSAccountResetToTest(a, accountName); - + if(a) + SOSAccountInflateTestTransportsForCircle(a, SOSCircleGetName([a.trust getCircle:NULL]), accountName, NULL); return a; } -static SOSAccountRef SOSAccountCreateTestFromData(CFAllocatorRef allocator, +static SOSAccount* SOSAccountCreateTestFromData(CFAllocatorRef allocator, CFDataRef data, CFStringRef accountName, SOSDataSourceFactoryRef factory) { - SOSAccountRef a = SOSAccountCreateFromData(allocator, data, factory, NULL); + SOSAccount* a = [SOSAccount accountFromData:(__bridge NSData*) data + factory:factory + error:nil]; if (!a) { CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(accountName); a = SOSAccountCreate(allocator, gestalt, factory); @@ -171,12 +193,14 @@ static SOSAccountRef SOSAccountCreateTestFromData(CFAllocatorRef allocator, } SOSAccountResetToTest(a, accountName); + if(a) + SOSAccountInflateTestTransportsForCircle(a, SOSCircleGetName([a.trust getCircle:NULL]), accountName, NULL); return a; } -static inline bool SOSAccountAssertUserCredentialsAndUpdate(SOSAccountRef account, +static inline bool SOSAccountAssertUserCredentialsAndUpdate(SOSAccount* account, CFStringRef user_account, CFDataRef user_password, CFErrorRef *error) { @@ -207,7 +231,7 @@ static void unretired_peers_is_subset(const char* label, CFArrayRef peers, CFSet }); } -static void accounts_agree_internal(char *label, SOSAccountRef left, SOSAccountRef right, bool check_peers) +static void accounts_agree_internal(char *label, SOSAccount* left, SOSAccount* right, bool check_peers) { CFErrorRef error = NULL; { @@ -224,20 +248,17 @@ static void accounts_agree_internal(char *label, SOSAccountRef left, SOSAccountR if (check_peers) { CFMutableSetRef allowed_identities = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); - SOSFullPeerInfoRef leftFullPeer = SOSAccountCopyAccountIdentityPeerInfo(left, kCFAllocatorDefault, NULL); + SOSFullPeerInfoRef leftFullPeer = [left.trust CopyAccountIdentityPeerInfo]; if (leftFullPeer) CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(leftFullPeer)); - CFReleaseNull(leftFullPeer); - SOSFullPeerInfoRef rightFullPeer = SOSAccountCopyAccountIdentityPeerInfo(right, kCFAllocatorDefault, NULL); + SOSFullPeerInfoRef rightFullPeer = [right.trust CopyAccountIdentityPeerInfo]; if (rightFullPeer) CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(rightFullPeer)); - CFReleaseNull(rightFullPeer); - unretired_peers_is_subset(label, leftPeers, allowed_identities); CFReleaseNull(allowed_identities); @@ -272,7 +293,7 @@ static void accounts_agree_internal(char *label, SOSAccountRef left, SOSAccountR } } -static inline void accounts_agree(char *label, SOSAccountRef left, SOSAccountRef right) +static inline void accounts_agree(char *label, SOSAccount* left, SOSAccount* right) { accounts_agree_internal(label, left, right, true); } @@ -301,8 +322,8 @@ static inline CFStringRef CFArrayCopyCompactDescription(CFArrayRef array) { return result; } -static inline CFStringRef SOSAccountCopyName(SOSAccountRef account) { - SOSPeerInfoRef pi = SOSAccountGetMyPeerInfo(account); +static inline CFStringRef SOSAccountCopyName(SOSAccount* account) { + SOSPeerInfoRef pi = account.peerInfo; return pi ? CFStringCreateCopy(kCFAllocatorDefault, SOSPeerInfoGetPeerName(pi)) : CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%@"), account); } @@ -317,7 +338,7 @@ static inline CFStringRef CopyChangesDescription(CFDictionaryRef changes) { CFDictionaryForEach(changes, ^(const void *key, const void *value) { if (CFGetTypeID(key) == SOSAccountGetTypeID()) { - CFStringRef accountName = SOSAccountCopyName((SOSAccountRef) key); + CFStringRef accountName = SOSAccountCopyName((__bridge SOSAccount*)key); CFStringRef arrayDescription = CFArrayCopyCompactDescription(value); CFStringAppendFormat(peerTable, NULL, CFSTR("%@%@:%@"), separator, accountName, arrayDescription); @@ -362,7 +383,7 @@ static void CFArrayAppendKeys(CFMutableArrayRef keys, CFDictionaryRef newKeysToA }); } -static bool AddNewChanges(CFMutableDictionaryRef changesRecord, CFMutableDictionaryRef newKeysAndValues, SOSAccountRef sender) +static bool AddNewChanges(CFMutableDictionaryRef changesRecord, CFMutableDictionaryRef newKeysAndValues, SOSAccount* sender) { __block bool changes_added = false; CFMutableDictionaryRef emptyDictionary = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); @@ -393,37 +414,37 @@ static bool FillAllChanges(CFMutableDictionaryRef changes) { CFMutableSetRef changedAccounts = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL); CFArrayForEach(key_transports, ^(const void *value) { - SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value; + CKKeyParameterTest* tpt = (__bridge CKKeyParameterTest*) value; if (AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt))) { changed |= true; - CFSetAddValue(changedAccounts, SOSTransportKeyParameterTestGetAccount(tpt)); + CFSetAddValue(changedAccounts, (__bridge CFTypeRef)(SOSTransportKeyParameterTestGetAccount(tpt))); } SOSTransportKeyParameterTestClearChanges(tpt); }); CFArrayForEach(circle_transports, ^(const void *value) { - SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value; - if (AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt))) { + SOSCircleStorageTransportTest *tpt = (__bridge SOSCircleStorageTransportTest *) value; + if (AddNewChanges(changes, [tpt SOSTransportCircleTestGetChanges], [tpt getAccount])) { changed |= true; - CFSetAddValue(changedAccounts, SOSTransportCircleTestGetAccount(tpt)); + CFSetAddValue(changedAccounts, (__bridge CFTypeRef)SOSTransportCircleTestGetAccount(tpt)); } SOSTransportCircleTestClearChanges(tpt); }); CFArrayForEach(message_transports, ^(const void *value) { - if(SOSTransportMessageGetTransportType((SOSTransportMessageRef)value, NULL) == kKVSTest){ - SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value; - CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt), kCFNull); - if (AddNewChanges(changes, SOSTransportMessageTestGetChanges(tpt), SOSTransportMessageTestGetAccount((SOSTransportMessageRef)tpt))) { + if([(__bridge SOSMessage*)value SOSTransportMessageGetTransportType] == kKVSTest){ + SOSMessageKVSTest* tpt = (__bridge SOSMessageKVSTest*) value; + CFDictionaryRemoveValue(SOSTransportMessageKVSTestGetChanges(tpt), kCFNull); + if (AddNewChanges(changes, SOSTransportMessageKVSTestGetChanges(tpt), SOSTransportMessageKVSTestGetAccount(tpt))) { changed |= true; - CFSetAddValue(changedAccounts, SOSTransportMessageTestGetAccount((SOSTransportMessageRef)tpt)); + CFSetAddValue(changedAccounts, (__bridge CFTypeRef)(SOSTransportMessageKVSTestGetAccount(tpt))); } SOSTransportMessageTestClearChanges(tpt); } - else if(SOSTransportMessageGetTransportType((SOSTransportMessageRef)value, NULL) == kIDSTest){ - SOSTransportMessageRef ids = (SOSTransportMessageRef) value; + else if([(__bridge SOSMessage*)value SOSTransportMessageGetTransportType] == kIDSTest){ + SOSMessageIDSTest* ids = (__bridge SOSMessageIDSTest*) value; CFDictionaryRemoveValue(SOSTransportMessageIDSTestGetChanges(ids), kCFNull); - if (AddNewChanges(changes, SOSTransportMessageIDSTestGetChanges(ids), SOSTransportMessageTestGetAccount(ids))) { + if (AddNewChanges(changes, SOSTransportMessageIDSTestGetChanges(ids), SOSTransportMessageIDSTestGetAccount(ids))) { changed |= true; - CFSetAddValue(changedAccounts, SOSTransportMessageTestGetAccount(ids)); + CFSetAddValue(changedAccounts, (__bridge CFTypeRef)(SOSTransportMessageIDSTestGetAccount(ids))); } SOSTransportMessageIDSTestClearChanges(ids); } @@ -436,36 +457,36 @@ static bool FillAllChanges(CFMutableDictionaryRef changes) { return changed; } -static void FillChanges(CFMutableDictionaryRef changes, SOSAccountRef forAccount) +static void FillChanges(CFMutableDictionaryRef changes, SOSAccount* forAccount) { CFArrayForEach(key_transports, ^(const void *value) { - SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value; - if(CFEqualSafe(forAccount, SOSTransportKeyParameterTestGetAccount(tpt))){ + CKKeyParameterTest* tpt = (__bridge CKKeyParameterTest*) value; + if(CFEqualSafe((__bridge CFTypeRef)(forAccount), (__bridge CFTypeRef)(SOSTransportKeyParameterTestGetAccount(tpt)))){ AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt)); SOSTransportKeyParameterTestClearChanges(tpt); } }); CFArrayForEach(circle_transports, ^(const void *value) { - SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value; - if(CFEqualSafe(forAccount, SOSTransportCircleTestGetAccount(tpt))){ - AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt)); + SOSCircleStorageTransportTest* tpt = (__bridge SOSCircleStorageTransportTest*) value; + if([forAccount isEqual: SOSTransportCircleTestGetAccount(tpt)]){ + AddNewChanges(changes, [tpt SOSTransportCircleTestGetChanges], SOSTransportCircleTestGetAccount(tpt)); SOSTransportCircleTestClearChanges(tpt); } }); CFArrayForEach(message_transports, ^(const void *value) { - if(SOSTransportMessageGetTransportType((SOSTransportMessageRef)value, NULL) == kKVSTest){ - SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value; - if(CFEqualSafe(forAccount, SOSTransportMessageTestGetAccount((SOSTransportMessageRef)tpt))){ - CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt), kCFNull); - AddNewChanges(changes, SOSTransportMessageTestGetChanges(tpt), SOSTransportMessageTestGetAccount((SOSTransportMessageRef)tpt)); + if([(__bridge SOSMessage*)value SOSTransportMessageGetTransportType] == kKVSTest){ + SOSMessageKVSTest* tpt = (__bridge SOSMessageKVSTest*) value; + if(CFEqualSafe((__bridge CFTypeRef)(forAccount), (__bridge CFTypeRef)(SOSTransportMessageKVSTestGetAccount(tpt)))){ + CFDictionaryRemoveValue(SOSTransportMessageKVSTestGetChanges(tpt), kCFNull); + AddNewChanges(changes, SOSTransportMessageKVSTestGetChanges(tpt), SOSTransportMessageKVSTestGetAccount(tpt)); SOSTransportMessageTestClearChanges(tpt); } } else{ - SOSTransportMessageRef tpt = (SOSTransportMessageRef) value; - if(CFEqualSafe(forAccount, SOSTransportMessageTestGetAccount((SOSTransportMessageRef)tpt))){ + SOSMessageIDSTest* tpt = (__bridge SOSMessageIDSTest*) value; + if(CFEqualSafe((__bridge CFTypeRef)(forAccount), (__bridge CFTypeRef)(SOSTransportMessageIDSTestGetAccount(tpt)))){ CFDictionaryRemoveValue(SOSTransportMessageIDSTestGetChanges(tpt), kCFNull); - AddNewChanges(changes, SOSTransportMessageIDSTestGetChanges(tpt), SOSTransportMessageTestGetAccount((SOSTransportMessageRef)tpt)); + AddNewChanges(changes, SOSTransportMessageIDSTestGetChanges(tpt), SOSTransportMessageIDSTestGetAccount(tpt)); SOSTransportMessageIDSTestClearChanges(tpt); } } @@ -473,14 +494,14 @@ static void FillChanges(CFMutableDictionaryRef changes, SOSAccountRef forAccount } -static inline void FillChangesMulti(CFMutableDictionaryRef changes, SOSAccountRef account, ...) +static inline void FillChangesMulti(CFMutableDictionaryRef changes, SOSAccount* account, ...) { - SOSAccountRef next_account = account; + SOSAccount* next_account = account; va_list argp; va_start(argp, account); while(next_account != NULL) { FillChanges(changes, next_account); - next_account = va_arg(argp, SOSAccountRef); + next_account = va_arg(argp, SOSAccount*); } } @@ -494,18 +515,18 @@ static inline CFMutableArrayRef CFDictionaryCopyKeys(CFDictionaryRef dictionary) } #define kFeedChangesToTestCount 1 -static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccountRef account) +static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccount* acct) { CFDictionaryRef full_list = (CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull); if (!isDictionary(full_list)) return; // Nothing recorded to send! - CFMutableArrayRef account_pending_keys = (CFMutableArrayRef)CFDictionaryGetValue(changes, account); + CFMutableArrayRef account_pending_keys = (CFMutableArrayRef)CFDictionaryGetValue(changes, (__bridge CFTypeRef)(acct)); if (!isArray(account_pending_keys)) { account_pending_keys = CFDictionaryCopyKeys(full_list); - CFDictionaryAddValue(changes, account, account_pending_keys); + CFDictionaryAddValue(changes, (__bridge CFTypeRef)(acct), account_pending_keys); CFReleaseSafe(account_pending_keys); // The dictionary keeps it, we don't retain it here. } @@ -514,18 +535,21 @@ static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccountRef a CFDictionaryAddValue(account_pending_messages, value, CFDictionaryGetValue(full_list, value)); }); - secnotice("changes", "Changes for %@:", SOSTransportKeyParameterTestGetName((SOSTransportKeyParameterTestRef) account->key_transport)); + secnotice("changes", "Changes for %@:", SOSTransportKeyParameterTestGetName((CKKeyParameterTest*) acct.key_transport)); CFDictionaryForEach(account_pending_messages, ^(const void *key, const void *value) { secnotice("changes", " %@", key); }); + if(CFDictionaryGetCount(account_pending_messages) == 0) + return; + __block CFMutableArrayRef handled = NULL; - SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) { + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { __block CFErrorRef error = NULL; ok(handled = SOSTransportDispatchMessages(txn, account_pending_messages, &error), "SOSTransportHandleMessages failed (%@)", error); CFReleaseNull(error); - }); + }]; if (isArray(handled)) { CFArrayForEach(handled, ^(const void *value) { @@ -540,8 +564,8 @@ static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccountRef a static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes, va_list argp) { - SOSAccountRef account = NULL; - while((account = va_arg(argp, SOSAccountRef)) != NULL) { + SOSAccount* account = NULL; + while((account = va_arg(argp, SOSAccount*)) != NULL) { FeedChangesTo(changes, account); } } @@ -632,7 +656,7 @@ static CFStringRef modelFromType(SOSPeerInfoDeviceClass cls) { } } -static inline SOSAccountRef CreateAccountForLocalChangesWithStartingAttributes(CFStringRef name, CFStringRef data_source_name, SOSPeerInfoDeviceClass devclass, CFStringRef serial, CFBooleanRef preferIDS, CFBooleanRef preferIDSFragmentation, CFBooleanRef preferIDSACKModel, CFStringRef transportType, CFStringRef deviceID) { +static inline SOSAccount* CreateAccountForLocalChangesWithStartingAttributes(CFStringRef name, CFStringRef data_source_name, SOSPeerInfoDeviceClass devclass, CFStringRef serial, CFBooleanRef preferIDS, CFBooleanRef preferIDSFragmentation, CFBooleanRef preferIDSACKModel, CFStringRef transportType, CFStringRef deviceID) { SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate(); SOSDataSourceRef ds = SOSTestDataSourceCreate(); @@ -652,8 +676,8 @@ static inline SOSAccountRef CreateAccountForLocalChangesWithStartingAttributes(C CFDictionaryAddValue(testV2dict, sPreferIDSACKModel, preferIDSACKModel); CFDictionaryAddValue(testV2dict, sTransportType, transportType); CFDictionaryAddValue(testV2dict, sDeviceID, deviceID); - SOSAccountRef result = SOSAccountCreateTest(kCFAllocatorDefault, name, gestalt, factory); - SOSAccountUpdateV2Dictionary(result, testV2dict); + SOSAccount* result = SOSAccountCreateTest(kCFAllocatorDefault, name, gestalt, factory); + [result.trust updateV2Dictionary:result v2:testV2dict]; CFReleaseSafe(SOSAccountCopyUUID(result)); @@ -665,7 +689,7 @@ static inline SOSAccountRef CreateAccountForLocalChangesWithStartingAttributes(C static CFStringRef sGestaltTest = CFSTR("GestaltTest"); static CFStringRef sV2Test = CFSTR("V2Test"); -static inline CFDictionaryRef SOSTestSaveStaticAccountState(SOSAccountRef account) { +static inline CFDictionaryRef SOSTestSaveStaticAccountState(SOSAccount* account) { CFMutableDictionaryRef retval = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFDictionaryRef gestalt = SOSAccountCopyGestalt(account); CFDictionaryRef v2dictionary = SOSAccountCopyV2Dictionary(account); @@ -676,9 +700,9 @@ static inline CFDictionaryRef SOSTestSaveStaticAccountState(SOSAccountRef accoun return retval; } -static inline void SOSTestRestoreAccountState(SOSAccountRef account, CFDictionaryRef saved) { - SOSAccountUpdateGestalt(account, CFDictionaryGetValue(saved, sGestaltTest)); - SOSAccountUpdateV2Dictionary(account, CFDictionaryGetValue(saved, sV2Test)); +static inline void SOSTestRestoreAccountState(SOSAccount* account, CFDictionaryRef saved) { + [account.trust updateGestalt:account newGestalt:CFDictionaryGetValue(saved, sGestaltTest)]; + [account.trust updateV2Dictionary:account v2:CFDictionaryGetValue(saved, sV2Test)]; } static CFStringRef CFStringCreateRandomHexWithLength(size_t len) { @@ -690,18 +714,19 @@ static CFStringRef CFStringCreateRandomHexWithLength(size_t len) { return retval; } -static inline SOSAccountRef CreateAccountForLocalChanges(CFStringRef name, CFStringRef data_source_name) +static inline SOSAccount* CreateAccountForLocalChanges(CFStringRef name, CFStringRef data_source_name) { CFStringRef randomSerial = CFStringCreateRandomHexWithLength(8); CFStringRef randomDevID = CFStringCreateRandomHexWithLength(16); - SOSAccountRef retval = CreateAccountForLocalChangesWithStartingAttributes(name, data_source_name, SOSPeerInfo_iOS, randomSerial, + SOSAccount* retval = CreateAccountForLocalChangesWithStartingAttributes(name, data_source_name, SOSPeerInfo_iOS, randomSerial, kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue, SOSTransportMessageTypeIDSV2, randomDevID); + CFReleaseNull(randomSerial); CFReleaseNull(randomDevID); return retval; } -static inline SOSAccountRef CreateAccountForLocalChangesFromData(CFDataRef flattenedData, CFStringRef name, CFStringRef data_source_name) +static inline SOSAccount* CreateAccountForLocalChangesFromData(CFDataRef flattenedData, CFStringRef name, CFStringRef data_source_name) { SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate(); SOSDataSourceRef ds = SOSTestDataSourceCreate(); @@ -709,47 +734,53 @@ static inline SOSAccountRef CreateAccountForLocalChangesFromData(CFDataRef flatt SOSEngineRef engine = SOSEngineCreate(ds, NULL); ds->engine = engine; - SOSAccountRef result = SOSAccountCreateTestFromData(kCFAllocatorDefault, flattenedData, name, factory); + SOSAccount* result = SOSAccountCreateTestFromData(kCFAllocatorDefault, flattenedData, name, factory); return result; } -static inline int countPeers(SOSAccountRef account) { +static inline int countPeers(SOSAccount* account) { CFErrorRef error = NULL; CFArrayRef peers; - + peers = SOSAccountCopyPeers(account, &error); + if(!peers) + return 0; int retval = (int) CFArrayGetCount(peers); CFReleaseNull(error); CFReleaseNull(peers); return retval; } -static inline int countActivePeers(SOSAccountRef account) { +static inline int countActivePeers(SOSAccount* account) { CFErrorRef error = NULL; CFArrayRef peers; peers = SOSAccountCopyActivePeers(account, &error); + if(!peers) + return 0; int retval = (int) CFArrayGetCount(peers); CFReleaseNull(error); CFReleaseNull(peers); return retval; } -static inline int countActiveValidPeers(SOSAccountRef account) { +static inline int countActiveValidPeers(SOSAccount* account) { CFErrorRef error = NULL; CFArrayRef peers; peers = SOSAccountCopyActiveValidPeers(account, &error); + if(!peers) + return 0; int retval = (int) CFArrayGetCount(peers); CFReleaseNull(error); CFReleaseNull(peers); return retval; } -static inline int countApplicants(SOSAccountRef account) { +static inline int countApplicants(SOSAccount* account) { CFErrorRef error = NULL; CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); int retval = 0; @@ -761,7 +792,7 @@ static inline int countApplicants(SOSAccountRef account) { } -static inline void showActiveValidPeers(SOSAccountRef account) { +static inline void showActiveValidPeers(SOSAccount* account) { CFErrorRef error = NULL; CFArrayRef peers; @@ -775,66 +806,69 @@ static inline void showActiveValidPeers(SOSAccountRef account) { #define ok_or_quit(COND,MESSAGE,LABEL) ok(COND, MESSAGE); if(!(COND)) goto LABEL -static inline bool testAccountPersistence(SOSAccountRef account) { +static inline bool testAccountPersistence(SOSAccount* account) { SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); SOSDataSourceRef test_source = SOSTestDataSourceCreate(); SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - CFErrorRef error = NULL; + NSError* error = nil; + bool retval = false; - SOSAccountRef reinflatedAccount = NULL; - CFDataRef accountDER = NULL; + SOSAccount* reinflatedAccount = NULL; + NSData* accountDER = NULL; SOSAccountCheckHasBeenInSync_wTxn(account); // DER encode account to accountData - this allows checking discreet DER functions - size_t size = SOSAccountGetDEREncodedSize(account, &error); - CFReleaseNull(error); + size_t size = [account.trust getDEREncodedSize:account err:&error]; + error = nil; uint8_t buffer[size]; - uint8_t* start = SOSAccountEncodeToDER(account, &error, buffer, buffer + sizeof(buffer)); - CFReleaseNull(error); + uint8_t* start = [account.trust encodeToDER:account err:&error start:buffer end:buffer + sizeof(buffer)]; + error = nil; ok_or_quit(start, "successful encoding", errOut); ok_or_quit(start == buffer, "Used whole buffer", errOut); - accountDER = CFDataCreate(kCFAllocatorDefault, buffer, size); + accountDER = [NSData dataWithBytes:buffer length:size]; ok_or_quit(accountDER, "Made CFData for Account", errOut); // Re-inflate to "inflated" - reinflatedAccount = SOSAccountCreateFromData(kCFAllocatorDefault, accountDER, test_factory, &error); - CFReleaseNull(error); - CFReleaseNull(accountDER); + reinflatedAccount = [SOSAccount accountFromData:accountDER + factory:test_factory + error:&error]; + error = nil; ok(reinflatedAccount, "inflated"); - ok(CFEqualSafe(reinflatedAccount, account), "Compares"); + ok(CFEqualSafe((__bridge CFTypeRef)reinflatedAccount, (__bridge CFTypeRef)account), "Compares"); // Repeat through SOSAccountCopyEncodedData() interface - this is the normally called combined interface - accountDER = SOSAccountCopyEncodedData(reinflatedAccount, kCFAllocatorDefault, &error); - CFReleaseNull(error); - CFReleaseNull(reinflatedAccount); - reinflatedAccount = SOSAccountCreateFromData(kCFAllocatorDefault, accountDER, test_factory, &error); - ok(reinflatedAccount, "inflated2"); - ok(CFEqual(account, reinflatedAccount), "Compares"); + accountDER = [reinflatedAccount encodedData:&error]; + error = nil; + reinflatedAccount = [SOSAccount accountFromData:accountDER factory:test_factory error:&error]; + ok(reinflatedAccount, "inflated2: %@", error); + ok(CFEqual((__bridge CFTypeRef)account, (__bridge CFTypeRef)reinflatedAccount), "Compares"); + error = nil; retval = true; + errOut: - CFReleaseNull(reinflatedAccount); - CFReleaseNull(accountDER); return retval; } -static inline bool SOSTestStartCircleWithAccount(SOSAccountRef account, CFMutableDictionaryRef changes, CFStringRef cfaccount, CFDataRef cfpassword) { +static inline bool SOSTestStartCircleWithAccount(SOSAccount* account, CFMutableDictionaryRef changes, CFStringRef cfaccount, CFDataRef cfpassword) { bool retval = false; - require(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, NULL), retOut); + if(!SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, NULL)) + return retval; is(ProcessChangesUntilNoChange(changes, account, NULL), 1, "updates"); - require(SOSAccountResetToOffering_wTxn(account, NULL), retOut); + if(!SOSAccountResetToOffering_wTxn(account, NULL)) + return retval; is(ProcessChangesUntilNoChange(changes, account, NULL), 1, "updates"); retval = true; -retOut: + return retval; } -static inline bool SOSTestApproveRequest(SOSAccountRef approver, CFIndex napplicants) { +static inline bool SOSTestApproveRequest(SOSAccount* approver, CFIndex napplicants) { bool retval = false; CFErrorRef error = NULL; CFArrayRef applicants = SOSAccountCopyApplicants(approver, &error); @@ -852,7 +886,7 @@ static inline bool SOSTestApproveRequest(SOSAccountRef approver, CFIndex napplic #define DROP_USERKEY true #define KEEP_USERKEY false -static inline bool SOSTestJoinWith(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccountRef joiner) { +static inline bool SOSTestJoinWith(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccount* joiner) { CFErrorRef error = NULL; // retval will return op failures, not count failures - we'll still report those from in here. bool retval = false; @@ -869,7 +903,7 @@ static inline bool SOSTestJoinWith(CFDataRef cfpassword, CFStringRef cfaccount, return retval; } -static inline bool SOSTestJoinWithApproval(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccountRef approver, SOSAccountRef joiner, bool dropUserKey, int expectedCount, bool expectCleanup) { +static inline bool SOSTestJoinWithApproval(CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, SOSAccount* approver, SOSAccount* joiner, bool dropUserKey, int expectedCount, bool expectCleanup) { //CFErrorRef error = NULL; // retval will return op failures, not count failures - we'll still report those from in here. bool retval = false; @@ -893,30 +927,29 @@ static inline bool SOSTestJoinWithApproval(CFDataRef cfpassword, CFStringRef cfa } -static inline SOSAccountRef SOSTestCreateAccountAsSerialClone(CFStringRef name, SOSPeerInfoDeviceClass devClass, CFStringRef serial, CFStringRef idsID) { +static inline SOSAccount* SOSTestCreateAccountAsSerialClone(CFStringRef name, SOSPeerInfoDeviceClass devClass, CFStringRef serial, CFStringRef idsID) { return CreateAccountForLocalChangesWithStartingAttributes(name, CFSTR("TestSource"), devClass, serial, kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue, SOSTransportMessageTypeIDSV2, idsID); } static inline bool SOSTestMakeGhostInCircle(CFStringRef name, SOSPeerInfoDeviceClass devClass, CFStringRef serial, CFStringRef idsID, CFDataRef cfpassword, CFStringRef cfaccount, CFMutableDictionaryRef changes, - SOSAccountRef approver, int expectedCount) { + SOSAccount* approver, int expectedCount) { bool retval = false; - SOSAccountRef ghostAccount = SOSTestCreateAccountAsSerialClone(name, devClass, serial, idsID); + SOSAccount* ghostAccount = SOSTestCreateAccountAsSerialClone(name, devClass, serial, idsID); ok(ghostAccount, "Created Ghost Account"); require_quiet(ghostAccount, retOut); if(!ghostAccount) return false; ok(retval = SOSTestJoinWithApproval(cfpassword, cfaccount, changes, approver, ghostAccount, DROP_USERKEY, expectedCount, true), "Ghost Joined Circle with expected result"); - CFReleaseNull(ghostAccount); retOut: return retval; } -static inline bool SOSTestChangeAccountDeviceName(SOSAccountRef account, CFStringRef name) { +static inline bool SOSTestChangeAccountDeviceName(SOSAccount* account, CFStringRef name) { bool retval = false; - CFMutableDictionaryRef mygestalt = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerGetGestalt(SOSAccountGetMyPeerInfo(account))); + CFMutableDictionaryRef mygestalt = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerGetGestalt(account.peerInfo)); require_quiet(mygestalt, retOut); CFDictionarySetValue(mygestalt, kPIUserDefinedDeviceNameKey, name); - retval = SOSAccountUpdateGestalt(account, mygestalt); + retval = [account.trust updateGestalt:account newGestalt:mygestalt]; retOut: CFReleaseNull(mygestalt); return retval; diff --git a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.c b/OSX/sec/securityd/Regressions/SOSTransportTestTransports.c deleted file mode 100644 index 8be5b636..00000000 --- a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.c +++ /dev/null @@ -1,949 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "SOSTransportTestTransports.h" - -static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error); -static bool syncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error); -static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error); -static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error); -static CF_RETURNS_RETAINED -CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error); -static void destroyMessageTransport(SOSTransportMessageRef transport); -static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport, CFDictionaryRef updates); - -static bool flushMessageChanges(SOSTransportMessageRef transport, CFErrorRef *error); -static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error); -static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport, CFDataRef newParameters, CFErrorRef *error); - -static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error); -static void destroy(SOSTransportCircleRef transport); -static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error); -static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error); -static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error); -static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error); - -static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error); -static CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error); -static bool setToNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef account); -static void destroyKeyParameters(SOSTransportKeyParameterRef transport); - -static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport, CFDictionaryRef updates); -static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport, CFStringRef message_key, CFDataRef message_data); -static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport, CFDictionaryRef changes, CFErrorRef *error); - -static bool sendPeerInfo(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error); -static bool flushRingChanges(SOSTransportCircleRef transport, CFErrorRef* error); -static bool postRing(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error); -static bool sendDebugInfo(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error); - -CFMutableArrayRef key_transports = NULL; -CFMutableArrayRef circle_transports = NULL; -CFMutableArrayRef message_transports = NULL; - -void SOSAccountUpdateTestTransports(SOSAccountRef account, CFDictionaryRef gestalt){ - CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceNameKey); - - SOSTransportKeyParameterTestSetName((SOSTransportKeyParameterTestRef)account->key_transport, new_name); - SOSTransportCircleTestSetName((SOSTransportCircleTestRef)account->circle_transport, new_name); - SOSTransportMessageTestSetName((SOSTransportMessageTestRef)account->kvs_message_transport, new_name); - -} - -static SOSCircleRef SOSAccountEnsureCircleTest(SOSAccountRef a, CFStringRef name, CFStringRef accountName, CFErrorRef *error) -{ - CFErrorRef localError = NULL; - - SOSCircleRef circle = SOSAccountGetCircle(a, &localError); - - require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail, - if (error) { *error = localError; localError = NULL; }); - - if(NULL == circle){ - circle = SOSCircleCreate(NULL, name, NULL); - if (circle){ - CFRetainAssign(a->trusted_circle, circle); - CFRelease(circle); - circle = SOSAccountGetCircle(a, &localError); - } - } - require_quiet(SOSAccountInflateTestTransportsForCircle(a, name, accountName, &localError), fail); - require_quiet(SOSAccountHasFullPeerInfo(a, &localError), fail); - -fail: - CFReleaseNull(localError); - return circle; -} - -bool SOSAccountEnsureFactoryCirclesTest(SOSAccountRef a, CFStringRef accountName) -{ - bool result = false; - if (a) - { - require(a->factory, xit); - CFStringRef circle_name = SOSDataSourceFactoryCopyName(a->factory); - require(circle_name, xit); - - SOSAccountEnsureCircleTest(a, (CFStringRef)circle_name, accountName, NULL); - - CFReleaseNull(circle_name); - result = true; - } -xit: - return result; -} - -bool SOSAccountInflateTestTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error){ - bool success = false; - SOSTransportCircleTestRef tCircle = NULL; - SOSTransportMessageTestRef tMessage = NULL; - - if(account->key_transport == NULL){ - account->key_transport = (SOSTransportKeyParameterRef)SOSTransportTestCreateKeyParameter(account, accountName, circleName); - require_quiet(account->key_transport, fail); - } - if(account->circle_transport == NULL){ - tCircle = SOSTransportTestCreateCircle(account, accountName, circleName); - require_quiet(tCircle, fail); - CFRetainAssign(account->circle_transport, (SOSTransportCircleRef)tCircle); - } - if(account->kvs_message_transport == NULL){ - tMessage = SOSTransportTestCreateMessage(account, accountName, circleName); - require_quiet(tMessage, fail); - CFRetainAssign(account->kvs_message_transport, (SOSTransportMessageRef)tMessage); - } - - success = true; -fail: - CFReleaseNull(tCircle); - CFReleaseNull(tMessage); - return success; -} - -/// -//Mark Test Key Parameter Transport -/// - -struct SOSTransportKeyParameterTest{ - struct __OpaqueSOSTransportKeyParameter k; - CFMutableDictionaryRef changes; - CFStringRef name; - CFStringRef circleName; -}; - -SOSTransportKeyParameterTestRef SOSTransportTestCreateKeyParameter(SOSAccountRef account, CFStringRef name, CFStringRef circleName){ - - SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) SOSTransportKeyParameterCreateForSubclass(sizeof(struct SOSTransportKeyParameterTest) - sizeof(CFRuntimeBase), account, NULL); - - tpt->name = CFRetainSafe(name); - tpt->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - tpt->k.account = CFRetainSafe(account); - tpt->k.destroy = destroyKeyParameters; - tpt->circleName = CFRetainSafe(circleName); - tpt->k.publishCloudParameters = publishCloudParameters; - tpt->k.handleKeyParameterChanges = handleKeyParameterChanges; - tpt->k.setToNewAccount = setToNewAccount; - if(!key_transports) - key_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - CFArrayAppendValue(key_transports, (SOSTransportKeyParameterRef)tpt); - - SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef)tpt); - return tpt; -} - -static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error){ - SOSAccountRef account = transport->account; - return SOSAccountHandleParametersChange(account, data, &error); -} - -static void destroyKeyParameters(SOSTransportKeyParameterRef transport){ - SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef)transport; - - CFArrayRemoveAllValue(key_transports, tpt); - SOSUnregisterTransportKeyParameter(transport); - - CFReleaseNull(tpt->changes); - CFReleaseNull(tpt->name); - CFReleaseNull(tpt->circleName); -} - - -static bool setToNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef a){ - SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef)transport; - CFStringRef accountName = SOSTransportKeyParameterTestGetName(tpt); - - SOSAccountSetToNew(a); - - CFReleaseNull(a->key_transport); - CFReleaseNull(a->circle_transport); - CFReleaseNull(a->kvs_message_transport); - CFReleaseNull(a->ids_message_transport); - - SOSAccountEnsureFactoryCirclesTest(a, accountName); - - return true; -} -CFStringRef SOSTransportKeyParameterTestGetName(SOSTransportKeyParameterTestRef transport){ - return transport->name; -} - -void SOSTransportKeyParameterTestSetName(SOSTransportKeyParameterTestRef transport, CFStringRef accountName){ - CFReleaseNull(transport->name); - transport->name = CFRetain(accountName); -} - -SOSAccountRef SOSTransportKeyParameterTestGetAccount(SOSTransportKeyParameterTestRef transport){ - return ((SOSTransportKeyParameterRef)transport)->account; -} - -CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(SOSTransportKeyParameterTestRef transport){ - return transport->changes; -} - -void SOSTransportKeyParameterTestClearChanges(SOSTransportKeyParameterTestRef transport){ - CFReleaseNull(transport->changes); - transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); -} - -static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error) -{ - return SOSTransportKeyParameterTestPublishCloudParameters((SOSTransportKeyParameterTestRef)transport, data, error); -} - -static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport, CFDataRef newParameters, CFErrorRef *error) -{ - if(!transport->changes) - transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFDictionarySetValue(transport->changes, kSOSKVSKeyParametersKey, newParameters); - - return true; -} - -/// -//MARK: Test Circle Transport -/// -struct SOSTransportCircleTest{ - struct __OpaqueSOSTransportCircle c; - CFMutableDictionaryRef changes; - CFStringRef name; - CFStringRef circleName; -}; -static CFStringRef SOSTransportCircleCopyDescription(SOSTransportCircleTestRef transport) { - - return CFStringCreateWithFormat(NULL, NULL, CFSTR(""), transport); -} - -static CFStringRef copyDescription(SOSTransportCircleRef transport){ - return SOSTransportCircleCopyDescription((SOSTransportCircleTestRef)transport); -} - -CFStringRef SOSTransportCircleTestGetName(SOSTransportCircleTestRef transport){ - return transport->name; -} -void SOSTransportCircleTestSetName(SOSTransportCircleTestRef transport, CFStringRef accountName){ - CFReleaseNull(transport->name); - transport->name = CFRetain(accountName); -} - -CFMutableDictionaryRef SOSTransportCircleTestGetChanges(SOSTransportCircleTestRef transport){ - return transport->changes; -} - -void SOSTransportCircleTestClearChanges(SOSTransportCircleTestRef transport){ - CFReleaseNull(transport->changes); - transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); -} - -SOSTransportCircleTestRef SOSTransportTestCreateCircle(SOSAccountRef account, CFStringRef name, CFStringRef circleName){ - SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) SOSTransportCircleCreateForSubclass(sizeof(struct SOSTransportCircleTest) - sizeof(CFRuntimeBase), account, NULL); - - if(tpt){ - tpt->c.account = CFRetainSafe(account); - tpt->c.copyDescription = copyDescription; - tpt->c.expireRetirementRecords = expireRetirementRecords; - tpt->c.postCircle = postCircle; - tpt->c.postRetirement = postRetirement; - tpt->c.flushChanges = flushChanges; - tpt->c.handleRetirementMessages = handleRetirementMessages; - tpt->c.handleCircleMessages = handleCircleMessages; - tpt->c.destroy = destroy; - tpt->c.flushRingChanges = flushRingChanges; - tpt->c.postRing = postRing; - tpt->c.sendDebugInfo = sendDebugInfo; - tpt->c.sendPeerInfo = sendPeerInfo; - tpt->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - tpt->name = CFRetainSafe(name); - tpt->circleName = CFRetainSafe(circleName); - if(!circle_transports) - circle_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - CFArrayAppendValue(circle_transports, (SOSTransportCircleRef)tpt); - - SOSRegisterTransportCircle((SOSTransportCircleRef)tpt); - } - - return tpt; -} - -static void destroy(SOSTransportCircleRef transport){ - SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport; - CFArrayRemoveAllValue(circle_transports, tkvs); - - SOSUnregisterTransportCircle(transport); - - CFReleaseNull(tkvs->changes); - CFReleaseNull(tkvs->name); - CFReleaseNull(tkvs->circleName); -} - -static bool sendPeerInfo(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error){ - SOSTransportCircleTestRef testTransport = (SOSTransportCircleTestRef)transport; - CFMutableDictionaryRef changes = SOSTransportCircleTestGetChanges(testTransport); - CFDictionaryAddValue(changes, peerID, peerInfoData); - return true; -} -static bool flushRingChanges(SOSTransportCircleRef transport, CFErrorRef* error){ - return true; -} -static bool postRing(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error){ - SOSTransportCircleTestRef testTransport = (SOSTransportCircleTestRef)transport; - CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error); - CFMutableDictionaryRef changes = SOSTransportCircleTestGetChanges(testTransport); - CFDictionaryAddValue(changes, ringKey, ring); - CFReleaseNull(ringKey); - return true; -} - -static bool sendDebugInfo(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error){ - SOSTransportCircleTestRef testTransport = (SOSTransportCircleTestRef)transport; - CFMutableDictionaryRef changes = SOSTransportCircleTestGetChanges(testTransport); - CFDictionaryAddValue(changes, type, debugInfo); - return true; -} - -static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error) -{ - CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circleName, peer_id); - if (retirement_key) - SOSTransportCircleTestAddToChanges((SOSTransportCircleTestRef)transport, retirement_key, retirement_data); - - CFReleaseNull(retirement_key); - return true; -} - -static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error) -{ - return true; -} - -static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport, CFStringRef message_key, CFDataRef message_data){ - - if (transport->changes == NULL) { - transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - } - if (message_data == NULL) { - CFDictionarySetValue(transport->changes, message_key, kCFNull); - } else { - CFDictionarySetValue(transport->changes, message_key, message_data); - } - secnotice("circle-changes", "Adding circle change %@ %@->%@", transport->name, message_key, message_data); -} - -static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport, CFDictionaryRef updates){ - - if (transport->changes == NULL) { - transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates); - - } - else{ - CFDictionaryForEach(updates, ^(const void *key, const void *value) { - CFDictionarySetValue(transport->changes, key, value); - }); - } -} - - -static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error) { - - bool success = true; - SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef)transport; - CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - CFDictionaryForEach(retirements, ^(const void *key, const void *value) { - if (isString(key) && isArray(value)) { - CFStringRef circle_name = (CFStringRef) key; - CFArrayRef retirees = (CFArrayRef) value; - - CFArrayForEach(retirees, ^(const void *value) { - if (isString(value)) { - CFStringRef retiree_id = (CFStringRef) value; - - CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id); - - CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull); - - CFReleaseSafe(kvsKey); - } - }); - } - }); - - if(CFDictionaryGetCount(keysToWrite)) { - SOSTransportCircleTestAddBulkToChanges(tpt, keysToWrite); - } - CFReleaseNull(keysToWrite); - - return success; -} - -__unused static bool SOSTransportCircleTestUpdateRetirementRecords(SOSTransportCircleTestRef transport, CFDictionaryRef updates, CFErrorRef* error){ - CFErrorRef updateError = NULL; - bool success = false; - if (SOSTransportCircleTestSendChanges((SOSTransportCircleTestRef)transport, updates, &updateError)){ - success = true; - } else { - SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL, - CFSTR("update parameters key failed [%@]"), updates); - } - return success; -} - -bool SOSTransportCircleTestRemovePendingChange(SOSTransportCircleRef transport, CFStringRef circleName, CFErrorRef *error){ - SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport; - CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error); - if (circle_key) - CFDictionaryRemoveValue(tkvs->changes, circle_key); - CFReleaseNull(circle_key); - return true; -} - -static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error){ - SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport; - CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error); - if (circle_key) - SOSTransportCircleTestAddToChanges(tkvs, circle_key, circle_data); - CFReleaseNull(circle_key); - - return true; -} - -static CF_RETURNS_RETAINED CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error){ - SOSAccountRef account = transport->account; - - return SOSAccountHandleRetirementMessages(account, circle_retirement_messages_table, error); -} - -static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error){ - CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) { - CFErrorRef circleMessageError = NULL; - if (!SOSAccountHandleCircleMessage(transport->account, key, value, &circleMessageError)) { - secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError); - } - else{ - CFStringRef circle_id = (CFStringRef) key; - CFArrayAppendValue(handledKeys, circle_id); - } - CFReleaseNull(circleMessageError); - }); - - return handledKeys; -} - -static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport, CFDictionaryRef changes, CFErrorRef *error){ - if(!transport->changes) - transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(changes), changes); - else{ - CFDictionaryForEach(changes, ^(const void *key, const void *value) { - CFDictionarySetValue(transport->changes, key, value); - }); - } - return true; -} - -SOSAccountRef SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport) { - return ((SOSTransportCircleRef)transport)->account; -} - -/// -//MARK Message Test Transport -/// - -static CFIndex getKVSTestTransportType(SOSTransportMessageRef transport, CFErrorRef *error); - - -struct SOSTransportMessageTest{ - struct __OpaqueSOSTransportMessage m; - CFMutableDictionaryRef changes; - CFStringRef name; - CFStringRef circleName; -}; - -SOSTransportMessageTestRef SOSTransportTestCreateMessage(SOSAccountRef account, CFStringRef name, CFStringRef circleName){ - SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageTest) - sizeof(CFRuntimeBase), account, circleName, NULL); - - SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, circleName, NULL); - - tpt->m.engine = CFRetainSafe(engine); - if(tpt){ - tpt->m.sendMessages = sendMessages; - tpt->m.syncWithPeers = syncWithPeers; - tpt->m.flushChanges = flushMessageChanges; - tpt->m.cleanupAfterPeerMessages = cleanupAfterPeer; - tpt->m.destroy = destroyMessageTransport; - tpt->m.handleMessages = handleMessages; - // Initialize ourselves - tpt->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - tpt->m.account = CFRetainSafe(account); - tpt->name = CFRetainSafe(name); - tpt->circleName = CFRetainSafe(circleName); - tpt->m.getTransportType = getKVSTestTransportType; - - - if(!message_transports) - message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - CFArrayAppendValue(message_transports, (SOSTransportMessageRef)tpt); - SOSRegisterTransportMessage((SOSTransportMessageRef)tpt); - } - - return tpt; -} - -static CFIndex getKVSTestTransportType(SOSTransportMessageRef transport, CFErrorRef *error){ - return kKVSTest; -} -CFStringRef SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport){ - return transport->name; -} - -void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport, CFStringRef accountName){ - CFReleaseNull(transport->name); - transport->name = CFRetain(accountName); -} - -CFMutableDictionaryRef SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport){ - return transport->changes; -} - -void SOSTransportMessageTestClearChanges(SOSTransportMessageTestRef transport){ - CFReleaseNull(transport->changes); - transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - -} - -static void destroyMessageTransport(SOSTransportMessageRef transport){ - SOSTransportMessageTestRef tkvs = (SOSTransportMessageTestRef)transport; - - SOSUnregisterTransportMessage(transport); - - CFArrayRemoveAllValue(message_transports, tkvs); - - CFReleaseNull(tkvs->circleName); - CFReleaseNull(tkvs->changes); - CFReleaseNull(tkvs->name); - -} - -static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport, CFDictionaryRef updates){ - - if (transport->changes == NULL) { - transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates); - - } - else{ - CFDictionaryForEach(updates, ^(const void *key, const void *value) { - CFDictionarySetValue(transport->changes, key, value); - }); - } -} - -static void SOSTransportMessageTestAddToChanges(SOSTransportMessageTestRef transport, CFStringRef message_key, CFDataRef message_data){ - if (transport->changes == NULL) { - transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - } - if (message_data == NULL) { - CFDictionarySetValue(transport->changes, message_key, kCFNull); - } else { - CFDictionarySetValue(transport->changes, message_key, message_data); - } -} - -static bool SOSTransportMessageTestCleanupAfterPeerMessages(SOSTransportMessageTestRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error) -{ - SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport); - require_quiet(engine, fail); - - CFArrayRef enginePeers = SOSEngineGetPeerIDs(engine); - - CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) { - if (isString(key) && isArray(value)) { - CFStringRef circle_name = (CFStringRef) key; - CFArrayRef peers_to_cleanup_after = (CFArrayRef) value; - - CFArrayForEach(peers_to_cleanup_after, ^(const void *value) { - if (isString(value)) { - CFStringRef cleanup_id = (CFStringRef) value; - // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers - if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) { - if (isString(value)) { - CFStringRef in_circle_id = (CFStringRef) value; - - CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id); - SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL); - CFReleaseSafe(kvsKey); - - kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id); - SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL); - CFReleaseSafe(kvsKey); - } - }); - - } - }); - } - }); - - return SOSTransportMessageFlushChanges((SOSTransportMessageRef)transport, error); -fail: - return true; -} - -static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) { - SOSTransportMessageTestRef testTransport = (SOSTransportMessageTestRef) transport; - bool result = true; - CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, peerID); - CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL); - - SOSTransportMessageTestAddBulkToChanges((SOSTransportMessageTestRef)testTransport, a_message_to_a_peer); - CFReleaseNull(a_message_to_a_peer); - CFReleaseNull(message_to_peer_key); - - return result; -} - -static bool syncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error){ - // Each entry is keyed by circle name and contains a list of peerIDs - - __block bool result = true; - - CFStringRef circleName = transport->circleName; - CFSetForEach(peers, ^(const void *value) { - CFStringRef peerID = asString(value, NULL); - - if (peerID) { - SOSEngineRef engine = SOSTransportMessageGetEngine(transport); - SOSEngineWithPeerID(engine, peerID, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { - SOSEnginePeerMessageSentBlock sent = NULL; - CFDataRef message_to_send = NULL; - bool ok = SOSPeerCoderSendMessageIfNeeded(engine, txn, peer, coder, &message_to_send, peerID, &sent, error); - if (message_to_send) { - CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message_to_send, NULL); - CFDictionarySetValue(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef)transport), circleName, peer_dict); - SOSPeerCoderConsume(&sent, ok); - CFReleaseSafe(peer_dict); - } - Block_release(sent); - CFReleaseSafe(message_to_send); - }); - } - }); - - return result; -} - -static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef peersToMessage, CFErrorRef *error) { - __block bool result = true; - - CFStringRef circleName = transport->circleName; - CFDictionaryForEach(peersToMessage, ^(const void *key, const void *value) { - if (isString(key) && isData(value)) { - CFStringRef peerID = (CFStringRef) key; - CFDataRef message = (CFDataRef) value; - bool rx = sendToPeer(transport, circleName, peerID, message, error); - result &= rx; - } - }); - - return result; -} - -static CF_RETURNS_RETAINED -CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error) { - SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef)transport; - CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryRef peerToMessage = CFDictionaryGetValue(circle_peer_messages_table, tpt->circleName); - CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(handled, tpt->circleName, handled_peers); - - if(peerToMessage){ - CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) { - CFStringRef peer_id = (CFStringRef) key; - CFDataRef peer_message = (CFDataRef) value; - CFErrorRef localError = NULL; - - if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef) transport, peer_id, peer_message, &localError)) { - CFArrayAppendValue(handled_peers, key); - } else { - secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError); - } - CFReleaseNull(localError); - }); - } - CFReleaseNull(handled_peers); - - return handled; -} - -static bool flushMessageChanges(SOSTransportMessageRef transport, CFErrorRef *error) -{ - return true; -} - -static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error) -{ - return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef) transport, circle_to_peer_ids, error); -} - -SOSAccountRef SOSTransportMessageTestGetAccount(SOSTransportMessageRef transport) { - return ((SOSTransportMessageRef)transport)->account; -} - - -/// -//MARK Message Test Transport -/// - -struct SOSTransportMessageIDSTest { - struct __OpaqueSOSTransportMessage m; - CFBooleanRef useFragmentation; - CFMutableDictionaryRef changes; - CFStringRef name; - CFStringRef circleName; -}; - -// -// V-table implementation forward declarations -// -static bool sendDataToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error); -static bool sendDictionaryToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDictionaryRef message, CFErrorRef *error); - -static bool syncWithPeersIDSTest(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error); -static bool sendMessagesIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error); -static void destroyIDSTest(SOSTransportMessageRef transport); -static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error); -static bool flushChangesIDSTest(SOSTransportMessageRef transport, CFErrorRef *error); -static CF_RETURNS_RETAINED CFDictionaryRef handleMessagesIDSTest(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error); -static CFStringRef copyIDSTestDescription(SOSTransportMessageRef object); -static CFIndex getIDSTestTransportType(SOSTransportMessageRef transport, CFErrorRef *error); - - - -SOSTransportMessageIDSTestRef SOSTransportMessageIDSTestCreate(SOSAccountRef account, CFStringRef accountName, CFStringRef circleName, CFErrorRef *error) -{ - - SOSTransportMessageIDSTestRef ids = (SOSTransportMessageIDSTestRef) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageIDSTest) - sizeof(CFRuntimeBase), account, circleName, NULL); - - - if (ids) { - // Fill in vtable: - ids->m.sendMessages = sendMessagesIDSTest; - ids->m.syncWithPeers = syncWithPeersIDSTest; - ids->m.flushChanges = flushChangesIDSTest; - ids->m.cleanupAfterPeerMessages = cleanupAfterPeerIDSTest; - ids->m.destroy = destroyIDSTest; - ids->m.handleMessages = handleMessagesIDSTest; - ids->m.copyDescription = copyIDSTestDescription; - ids->m.getName = SOSTransportMessageIDSTestGetName; - ids->m.getTransportType = getIDSTestTransportType; - ids->useFragmentation = kCFBooleanTrue; - - // Initialize ourselves - ids->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - ids->circleName = CFRetainSafe(circleName); - ids->name = CFRetainSafe(accountName); - - if(!message_transports) - message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); - CFArrayAppendValue(message_transports, (SOSTransportMessageRef)ids); - SOSRegisterTransportMessage((SOSTransportMessageRef)ids); - } - - return ids; -} -CFMutableDictionaryRef SOSTransportMessageIDSTestGetChanges(SOSTransportMessageRef transport){ - return ((SOSTransportMessageIDSTestRef)transport)->changes; -} - -static CFStringRef copyIDSTestDescription(SOSTransportMessageRef transport){ - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@,%@,%@,%ld"),transport->circleName, transport->account, transport->getName(transport), transport->getTransportType(transport, NULL)); -} - -CFStringRef SOSTransportMessageIDSTestGetName(SOSTransportMessageRef transport){ - return ((SOSTransportMessageIDSTestRef)transport)->name; -} - -static CFIndex getIDSTestTransportType(SOSTransportMessageRef transport, CFErrorRef *error){ - return kIDSTest; -} - -static void destroyIDSTest(SOSTransportMessageRef transport){ - SOSUnregisterTransportMessage(transport); -} - -void SOSTransportMessageIDSTestSetName(SOSTransportMessageRef transport, CFStringRef accountName){ - SOSTransportMessageIDSTestRef t = (SOSTransportMessageIDSTestRef)transport; - t->name = accountName; -} - -static CF_RETURNS_RETAINED -CFDictionaryRef handleMessagesIDSTest(SOSTransportMessageRef transport, CFMutableDictionaryRef message, CFErrorRef *error) { - - CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryRef peerToMessage = CFDictionaryGetValue(message, transport->circleName); - CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); - - secerror("Received IDS message!"); - if(peerToMessage){ - CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) { - CFStringRef peer_id = asString(key, NULL); - CFDataRef peer_message = asData(value, NULL); - CFErrorRef localError = NULL; - - if (peer_id && peer_message && SOSTransportMessageHandlePeerMessage(transport, peer_id, peer_message, &localError)) { - CFArrayAppendValue(handled_peers, key); - } else { - secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError); - } - CFReleaseNull(localError); - }); - } - CFDictionaryAddValue(handled, transport->circleName, handled_peers); - CFReleaseNull(handled_peers); - - return handled; -} - -static void SOSTransportMessageIDSTestAddBulkToChanges(SOSTransportMessageIDSTestRef transport, CFDictionaryRef updates){ - - if (transport->changes == NULL) { - transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates); - - } - else{ - CFDictionaryForEach(updates, ^(const void *key, const void *value) { - CFDictionaryAddValue(transport->changes, key, value); - }); - } -} -static bool sendDataToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error) -{ - SOSTransportMessageIDSTestRef testTransport = (SOSTransportMessageIDSTestRef)transport; - - secerror("sending message through test transport: %@", message); - CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, peerID); - CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL); - - SOSTransportMessageIDSTestAddBulkToChanges(testTransport, a_message_to_a_peer); - - CFReleaseNull(message_to_peer_key); - CFReleaseNull(a_message_to_a_peer); - return true; - -} -static bool sendDictionaryToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDictionaryRef message, CFErrorRef *error) -{ - SOSTransportMessageIDSTestRef testTransport = (SOSTransportMessageIDSTestRef)transport; - - secerror("sending message through test transport: %@", message); - CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, peerID); - CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL); - - SOSTransportMessageIDSTestAddBulkToChanges(testTransport, a_message_to_a_peer); - - CFReleaseNull(message_to_peer_key); - CFReleaseNull(a_message_to_a_peer); - return true; - -} - -static bool syncWithPeersIDSTest(SOSTransportMessageRef transport, CFSetRef peerIDs, CFErrorRef *error){ - // Each entry is keyed by circle name and contains a list of peerIDs - __block bool result = true; - - CFSetForEach(peerIDs, ^(const void *value) { - CFStringRef peerID = asString(value, NULL); - if (peerID) { - secnotice("transport", "IDS sync with peerIDs %@", peerID); - result &= SOSTransportMessageSendMessageIfNeeded(transport, transport->circleName, peerID, error); - } - }); - - return result; -} - -static bool sendMessagesIDSTest(SOSTransportMessageRef transport, CFDictionaryRef peersToMessage, CFErrorRef *error) { - - __block bool result = true; - SOSAccountRef account = transport->account; - - CFDictionaryForEach(peersToMessage, ^(const void *key, const void *value) { - CFStringRef idsDeviceID = NULL;; - CFStringRef peerID = asString(key, NULL); - SOSPeerInfoRef pi = NULL; - require(peerID, done); - require(!CFEqualSafe(peerID, SOSAccountGetMyPeerID(account)), done); - - pi = SOSAccountCopyPeerWithID(account, peerID, NULL); - require(pi, done); - - idsDeviceID = SOSPeerInfoCopyDeviceID(pi); - require(idsDeviceID, done); - - CFDictionaryRef messageDictionary = asDictionary(value, NULL); - if (messageDictionary) { - result &= sendDictionaryToPeerIDSTest(transport, transport->circleName, idsDeviceID, peerID, messageDictionary, error); - } else { - CFDataRef messageData = asData(value, NULL); - if (messageData) { - result &= sendDataToPeerIDSTest(transport, transport->circleName, idsDeviceID, peerID, messageData, error); - } - } - done: - CFReleaseNull(idsDeviceID); - CFReleaseNull(pi); - - }); - - return result; -} - -static bool flushChangesIDSTest(SOSTransportMessageRef transport, CFErrorRef *error) -{ - return true; -} - -static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error) -{ - return true; -} - -void SOSTransportMessageIDSTestClearChanges(SOSTransportMessageRef transport){ - SOSTransportMessageIDSTestRef ids = (SOSTransportMessageIDSTestRef)transport; - CFReleaseNull(ids->changes); - - ids->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - -} - - diff --git a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.h b/OSX/sec/securityd/Regressions/SOSTransportTestTransports.h index 9bb2016a..f05c42ab 100644 --- a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.h +++ b/OSX/sec/securityd/Regressions/SOSTransportTestTransports.h @@ -1,57 +1,94 @@ #ifndef SEC_SOSTransportTestTransports_h #define SEC_SOSTransportTestTransports_h -typedef struct SOSTransportKeyParameterTest *SOSTransportKeyParameterTestRef; -typedef struct SOSTransportCircleTest *SOSTransportCircleTestRef; -typedef struct SOSTransportMessageTest *SOSTransportMessageTestRef; -typedef struct SOSTransportMessageIDSTest *SOSTransportMessageIDSTestRef; - -CF_RETURNS_RETAINED -CFDictionaryRef SOSTransportMessageTestHandleMessages(SOSTransportMessageTestRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error); - -void SOSAccountUpdateTestTransports(SOSAccountRef account, CFDictionaryRef gestalt); - -SOSTransportKeyParameterTestRef SOSTransportTestCreateKeyParameter(SOSAccountRef account, CFStringRef name, CFStringRef circleName); -SOSTransportCircleTestRef SOSTransportTestCreateCircle(SOSAccountRef account, CFStringRef name, CFStringRef circleName); -SOSTransportMessageTestRef SOSTransportTestCreateMessage(SOSAccountRef account, CFStringRef name, CFStringRef circleName); -bool SOSTransportCircleTestRemovePendingChange(SOSTransportCircleRef transport, CFStringRef circleName, CFErrorRef *error); +#import "Security/SecureObjectSync/SOSTransportCircleKVS.h" +#import "Security/SecureObjectSync/SOSTransportMessageKVS.h" +#import "Security/SecureObjectSync/SOSTransportMessageIDS.h" extern CFMutableArrayRef key_transports; extern CFMutableArrayRef circle_transports; extern CFMutableArrayRef message_transports; -CFStringRef SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport); -CFStringRef SOSTransportCircleTestGetName(SOSTransportCircleTestRef transport); -CFStringRef SOSTransportKeyParameterTestGetName(SOSTransportKeyParameterTestRef transport); - -void SOSTransportKeyParameterTestSetName(SOSTransportKeyParameterTestRef transport, CFStringRef accountName); -void SOSTransportCircleTestSetName(SOSTransportCircleTestRef transport, CFStringRef accountName); -void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport, CFStringRef accountName); - - -CFMutableDictionaryRef SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport); -CFMutableDictionaryRef SOSTransportCircleTestGetChanges(SOSTransportCircleTestRef transport); -CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(SOSTransportKeyParameterTestRef transport); - -SOSAccountRef SOSTransportMessageTestGetAccount(SOSTransportMessageRef transport); -SOSAccountRef SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport); -SOSAccountRef SOSTransportKeyParameterTestGetAccount(SOSTransportKeyParameterTestRef transport); - -bool SOSAccountInflateTestTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error); -bool SOSAccountEnsureFactoryCirclesTest(SOSAccountRef a, CFStringRef accountName); -void SOSTransportKeyParameterTestClearChanges(SOSTransportKeyParameterTestRef transport); -void SOSTransportCircleTestClearChanges(SOSTransportCircleTestRef transport); -void SOSTransportMessageTestClearChanges(SOSTransportMessageTestRef transport); - - - - -//Test IDS transport -SOSTransportMessageIDSTestRef SOSTransportMessageIDSTestCreate(SOSAccountRef account, CFStringRef accountName, CFStringRef circleName, CFErrorRef *error); -CFMutableDictionaryRef SOSTransportMessageIDSTestGetChanges(SOSTransportMessageRef transport); -void SOSTransportMessageIDSTestSetName(SOSTransportMessageRef transport, CFStringRef accountName); -CFStringRef SOSTransportMessageIDSTestGetName(SOSTransportMessageRef transport); -void SOSTransportMessageIDSTestClearChanges(SOSTransportMessageRef transport); - - +void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt); + +@interface SOSMessageIDSTest : SOSMessageIDS + +@property (nonatomic) CFMutableDictionaryRef changes; +@property (nonatomic) CFStringRef accountName; + +-(SOSMessageIDSTest*) initWithAccount:(SOSAccount*)acct andAccountName:(CFStringRef) aN andCircleName:(CFStringRef) cN err:(CFErrorRef *)error; +-(CFIndex) SOSTransportMessageGetTransportType; +-(CFStringRef) SOSTransportMessageGetCircleName; +-(CFTypeRef) SOSTransportMessageGetEngine; +-(SOSAccount*) SOSTransportMessageGetAccount; +void SOSTransportMessageIDSTestSetName(SOSMessageIDSTest* transport, CFStringRef acctName); +-(bool) SOSTransportMessageSendMessages:(SOSMessageIDSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error; +-(bool) SOSTransportMessageIDSGetIDSDeviceID:(SOSAccount*)acct; +-(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessageIDSTest*) transport peerMessages:(CFMutableDictionaryRef)message err:(CFErrorRef *)error; +-(HandleIDSMessageReason) SOSTransportMessageIDSHandleMessage:(SOSAccount*)acct m:(CFDictionaryRef) message err:(CFErrorRef *)error; + +@end + +@interface CKKeyParameterTest : CKKeyParameter + +@property (nonatomic) CFMutableDictionaryRef changes; +@property (nonatomic) CFStringRef name; +@property (nonatomic) CFStringRef circleName; +-(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) name andCircleName:(CFStringRef) circleName; +-(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameterTest*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error; +-(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameter*) transport data:(CFDataRef) data err:(CFErrorRef) error; + +@end + +@interface SOSMessageKVSTest : SOSMessageKVS +@property (nonatomic) CFMutableDictionaryRef changes; +@property (nonatomic) CFStringRef name; + +-(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) name andCircleName:(CFStringRef) circleName; +-(bool) SOSTransportMessageSendMessages:(SOSMessageKVSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error; +-(CFIndex) SOSTransportMessageGetTransportType; +-(CFStringRef) SOSTransportMessageGetCircleName; +-(CFTypeRef) SOSTransportMessageGetEngine; +-(SOSAccount*) SOSTransportMessageGetAccount; +@end + +@interface SOSCircleStorageTransportTest : SOSKVSCircleStorageTransport +{ + NSString *accountName; +} +@property (nonatomic) NSString *accountName; + +-(id) init; +-(id) initWithAccount:(SOSAccount*)account andWithAccountName:(CFStringRef)accountName andCircleName:(CFStringRef)circleName; + +bool SOSTransportCircleTestRemovePendingChange(SOSCircleStorageTransportTest* transport, CFStringRef circleName, CFErrorRef *error); +CFStringRef SOSTransportCircleTestGetName(SOSCircleStorageTransportTest* transport); +bool SOSAccountEnsureFactoryCirclesTest(SOSAccount* a, CFStringRef accountName); +SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* transport); +void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport); +void SOSTransportCircleTestSetName(SOSCircleStorageTransportTest* transport, CFStringRef accountName); +bool SOSAccountInflateTestTransportsForCircle(SOSAccount* account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error); +-(void) SOSTransportCircleTestAddBulkToChanges:(CFDictionaryRef) updates; +-(void) testAddToChanges:(CFStringRef) message_key data:(CFDataRef)message_data; +-(CFMutableDictionaryRef) SOSTransportCircleTestGetChanges; +@end + +void SOSTransportMessageIDSTestSetName(SOSMessageIDSTest* transport, CFStringRef n); +void SOSTransportMessageTestClearChanges(SOSMessageKVSTest* transport); + +void SOSTransportMessageKVSTestSetName(SOSMessageKVSTest* transport, CFStringRef n); +CFMutableDictionaryRef SOSTransportMessageKVSTestGetChanges(SOSMessageKVSTest* transport); +CFStringRef SOSTransportMessageKVSTestGetName(SOSMessageKVSTest* transport); + +CFStringRef SOSTransportKeyParameterTestGetName(CKKeyParameterTest* transport); +CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(CKKeyParameterTest* transport); +void SOSTransportKeyParameterTestSetName(CKKeyParameterTest* transport, CFStringRef accountName); +void SOSTransportKeyParameterTestClearChanges(CKKeyParameterTest* transport); +SOSAccount* SOSTransportKeyParameterTestGetAccount(CKKeyParameterTest* transport); +SOSAccount* SOSTransportMessageKVSTestGetAccount(SOSMessageKVSTest* transport); +void SOSTransportMessageIDSTestClearChanges(SOSMessageIDSTest* transport); + +CFMutableDictionaryRef SOSTransportMessageIDSTestGetChanges(SOSMessageIDSTest* transport); +SOSAccount* SOSTransportMessageIDSTestGetAccount(SOSMessageIDSTest* transport); +CFStringRef SOSTransportMessageIDSTestGetName(SOSMessageIDSTest* transport); #endif diff --git a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.m b/OSX/sec/securityd/Regressions/SOSTransportTestTransports.m new file mode 100644 index 00000000..2adcb1d3 --- /dev/null +++ b/OSX/sec/securityd/Regressions/SOSTransportTestTransports.m @@ -0,0 +1,918 @@ +#include +#include + +#include +#include +#include +#import +#import +#import +#import +#include +#include +#include +#include +#import +#import + +#include "SOSTransportTestTransports.h" +#include "SOSAccountTesting.h" + +CFMutableArrayRef key_transports = NULL; +CFMutableArrayRef circle_transports = NULL; +CFMutableArrayRef message_transports = NULL; + +/// +//Mark Test Key Parameter Transport +/// + +@implementation CKKeyParameterTest + +-(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) n andCircleName:(CFStringRef) cN +{ + self = [super init]; + if(self){ + self.name = CFRetainSafe(n); + self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + self.account = acct; + self.circleName = CFRetainSafe(cN); + + if(!key_transports) + key_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); + CFArrayAppendValue(key_transports, (__bridge CFTypeRef)((CKKeyParameter*)self)); + + SOSRegisterTransportKeyParameter((CKKeyParameter*)self); + } + return self; +} + +-(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameterTest*) transport data:(CFDataRef) data err:(CFErrorRef) error +{ + SOSAccount* acct = transport.account; + return SOSAccountHandleParametersChange(acct, data, &error); +} + + +-(void) SOSTransportKeyParameterHandleNewAccount:(CKKeyParameterTest*) transport acct:(SOSAccount*) acct +{ + + if(key_transports){ + CFArrayRemoveAllValue(key_transports, (__bridge CFTypeRef)(acct.key_transport)); + } + if(message_transports){ + CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)acct.ids_message_transport); + CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)acct.kvs_message_transport); + } + if(circle_transports) + CFArrayRemoveAllValue(circle_transports, (__bridge CFTypeRef)(acct.circle_transport)); + + SOSAccountSetToNew(acct); + SOSAccountResetToTest(acct, transport.name); +} + +CFStringRef SOSTransportKeyParameterTestGetName(CKKeyParameterTest* transport){ + return transport.name; +} + +void SOSTransportKeyParameterTestSetName(CKKeyParameterTest* transport, CFStringRef accountName){ + transport.name = accountName; +} + +SOSAccount* SOSTransportKeyParameterTestGetAccount(CKKeyParameterTest* transport){ + return ((CKKeyParameter*)transport).account; +} + +CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(CKKeyParameterTest* transport){ + return transport.changes; +} + +void SOSTransportKeyParameterTestClearChanges(CKKeyParameterTest* transport){ + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); +} + +-(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameterTest*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error +{ + if(!transport.changes) + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFDictionarySetValue(transport.changes, kSOSKVSKeyParametersKey, newParameters); + + return true; +} +@end + + +/// +//MARK: Test Circle Transport +/// +@implementation SOSCircleStorageTransportTest +@synthesize accountName = accountName; + +-(id)init +{ + return [super init]; +} + +CFStringRef SOSTransportCircleTestGetName(SOSCircleStorageTransportTest* transport){ + return (__bridge CFStringRef)(transport.accountName); +} +void SOSTransportCircleTestSetName(SOSCircleStorageTransportTest* transport, CFStringRef name){ + transport.accountName = nil; + transport.accountName = (__bridge NSString *)(name); +} + +-(CFMutableDictionaryRef) SOSTransportCircleTestGetChanges +{ + return (__bridge CFMutableDictionaryRef)(self.pending_changes); +} + +void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport){ + transport.pending_changes = [NSMutableDictionary dictionary]; +} + +-(id) initWithAccount:(SOSAccount *)acct andWithAccountName:(CFStringRef)acctName andCircleName:(CFStringRef)cName +{ + self = [super init]; + if(self){ + self.account = acct; + self.accountName = (__bridge NSString *)(acctName); + self.circleName = (__bridge NSString*)cName; + self.pending_changes = [NSMutableDictionary dictionary]; + if(!circle_transports) + circle_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); + CFArrayAppendValue(circle_transports, (__bridge CFTypeRef)self); + + SOSRegisterTransportCircle((SOSCircleStorageTransportTest*)self); + } + return self; +} + +-(bool) kvsRingFlushChanges:(CFErrorRef*) error +{ + return true; +} + +-(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error +{ + CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error); + CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges]; + CFDictionaryAddValue(changes, ringKey, ring); + CFReleaseNull(ringKey); + return true; +} + +-(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error +{ + CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges]; + CFDictionaryAddValue(changes, type, debugInfo); + return true; +} + +-(bool) postRetirement:(CFStringRef)cName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error +{ + CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(cName, SOSPeerInfoGetPeerID(peer)); + CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error); + + if (retirement_key) + [self testAddToChanges:retirement_key data:retirement_data]; + + CFReleaseNull(retirement_key); + CFReleaseNull(retirement_data); + return true; +} + +-(bool) flushChanges:(CFErrorRef *)error +{ + return true; +} + +-(void) testAddToChanges:(CFStringRef) message_key data:(CFDataRef) message_data +{ + if (self.pending_changes == NULL) { + self.pending_changes = [NSMutableDictionary dictionary]; + } + if (message_data == NULL) { + [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)(message_key)]; + } else { + [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key]; + } + secnotice("circle-changes", "Adding circle change %@ %@->%@", self.accountName, message_key, message_data); +} + +-(void) SOSTransportCircleTestAddBulkToChanges:(CFDictionaryRef) updates +{ + if (self.pending_changes == NULL) { + self.pending_changes = [[NSMutableDictionary alloc]initWithDictionary:(__bridge NSDictionary * _Nonnull)(updates)]; + + } + else{ + CFDictionaryForEach(updates, ^(const void *key, const void *value) { + [self.pending_changes setObject:(__bridge id _Nonnull)value forKey:(__bridge id _Nonnull)key]; + }); + } +} + + +-(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error +{ + bool success = true; + CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + CFDictionaryForEach(retirements, ^(const void *key, const void *value) { + if (isString(key) && isArray(value)) { + CFStringRef circle_name = (CFStringRef) key; + CFArrayRef retirees = (CFArrayRef) value; + + CFArrayForEach(retirees, ^(const void *value) { + if (isString(value)) { + CFStringRef retiree_id = (CFStringRef) value; + + CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id); + + CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull); + + CFReleaseSafe(kvsKey); + } + }); + } + }); + + if(CFDictionaryGetCount(keysToWrite)) { + [self SOSTransportCircleTestAddBulkToChanges:keysToWrite]; + } + CFReleaseNull(keysToWrite); + + return success; +} + +bool SOSTransportCircleTestRemovePendingChange(SOSCircleStorageTransportTest* transport, CFStringRef circleName, CFErrorRef *error){ + CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error); + if (circle_key) + [transport.pending_changes removeObjectForKey:(__bridge NSString*)circle_key]; + CFReleaseNull(circle_key); + return true; +} + +-(bool) postCircle:(CFStringRef)cName circleData:(CFDataRef)circle_data err:(CFErrorRef *)error +{ + CFStringRef circle_key = SOSCircleKeyCreateWithName(cName, error); + if (circle_key) + [self testAddToChanges:circle_key data:circle_data]; + CFReleaseNull(circle_key); + + return true; +} + +-(CFDictionaryRef)handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error +{ + return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error); +} + +-(CFArrayRef) handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error +{ +CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) { + CFErrorRef circleMessageError = NULL; + if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) { + secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError); + } + else{ + CFStringRef circle_id = (CFStringRef) key; + CFArrayAppendValue(handledKeys, circle_id); + } + CFReleaseNull(circleMessageError); + }); + + return handledKeys; +} + +SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* transport) { + return transport.account; +} + +@end + +/// +//MARK KVS Message Test Transport +/// + + + +@implementation SOSMessageKVSTest + + +-(id) initWithAccount:(SOSAccount*)acct andName:(CFStringRef)n andCircleName:(CFStringRef) cN +{ + self = [super init]; + if(self){ + self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL); + self.account = acct; + self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + self.name = CFRetainSafe(n); + self.circleName = (__bridge NSString*)cN; + + if(!message_transports) + message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); + CFArrayAppendValue(message_transports, (__bridge const void *)((SOSMessageKVSTest*)self)); + SOSRegisterTransportMessage((SOSMessageKVSTest*)self); + } + + return self; +} + +-(CFIndex) SOSTransportMessageGetTransportType +{ + return kKVSTest; +} +-(CFStringRef) SOSTransportMessageGetCircleName +{ + return (__bridge CFStringRef)circleName; +} +-(CFTypeRef) SOSTransportMessageGetEngine +{ + return engine; +} +-(SOSAccount*) SOSTransportMessageGetAccount +{ + return self.account; +} + +void SOSTransportMessageKVSTestSetName(SOSMessageKVSTest* transport, CFStringRef n) +{ + transport.name = n; +} + +CFStringRef SOSTransportMessageKVSTestGetName(SOSMessageKVSTest* transport) +{ + return transport.name; +} + +CFMutableDictionaryRef SOSTransportMessageKVSTestGetChanges(SOSMessageKVSTest* transport) +{ + return transport.changes; +} + +void SOSTransportMessageTestClearChanges(SOSMessageKVSTest* transport) +{ + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); +} + +static void SOSTransportMessageTestAddBulkToChanges(SOSMessageKVSTest* transport, CFDictionaryRef updates) +{ +#ifndef __clang_analyzer__ // The analyzer thinks transport.changes is a leak, but I don't know why. + if (transport.changes == NULL) { + transport.changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates); + } + else{ + CFDictionaryForEach(updates, ^(const void *key, const void *value) { + CFDictionarySetValue(transport.changes, key, value); + }); + } +#endif // __clang_analyzer__ +} + +static void SOSTransportMessageTestAddToChanges(SOSMessageKVSTest* transport, CFStringRef message_key, CFDataRef message_data) +{ + if (transport.changes == NULL) { + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + } + if (message_data == NULL) { + CFDictionarySetValue(transport.changes, message_key, kCFNull); + } else { + CFDictionarySetValue(transport.changes, message_key, message_data); + } +} + +-(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageKVSTest*) transport peers:(CFDictionaryRef)circle_to_peer_ids err:(CFErrorRef*) error +{ + if(!transport.engine) + return true; + CFArrayRef enginePeers = SOSEngineGetPeerIDs((SOSEngineRef)transport.engine); + + CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) { + if (isString(key) && isArray(value)) { + CFStringRef circle_name = (CFStringRef) key; + CFArrayRef peers_to_cleanup_after = (CFArrayRef) value; + + CFArrayForEach(peers_to_cleanup_after, ^(const void *value) { + if (isString(value)) { + CFStringRef cleanup_id = (CFStringRef) value; + // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers + if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) { + if (isString(value)) { + CFStringRef in_circle_id = (CFStringRef) value; + + CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id); + SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL); + CFReleaseSafe(kvsKey); + + kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id); + SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL); + CFReleaseSafe(kvsKey); + } + }); + + } + }); + } + }); + + return [transport SOSTransportMessageFlushChanges:transport err:error]; + return true; +} + +static bool sendToPeer(SOSMessageKVSTest* transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) { + bool result = true; + NSString* myID = transport.account.peerID; + CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer((SOSMessage*)transport, (__bridge CFStringRef) myID, peerID); + CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL); + + SOSTransportMessageTestAddBulkToChanges(transport, a_message_to_a_peer); + CFReleaseNull(a_message_to_a_peer); + CFReleaseNull(message_to_peer_key); + + return result; +} + +-(bool) SOSTransportMessageSyncWithPeers:(SOSMessageKVSTest*) transport p:(CFSetRef) peers err:(CFErrorRef *)error +{ + // Each entry is keyed by circle name and contains a list of peerIDs + + __block bool result = true; + + CFSetForEach(peers, ^(const void *value) { + CFStringRef peerID = asString(value, NULL); + + if (peerID) { + SOSEngineWithPeerID((SOSEngineRef)transport.engine, peerID, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + SOSEnginePeerMessageSentBlock sent = NULL; + CFDataRef message_to_send = NULL; + bool ok = SOSPeerCoderSendMessageIfNeeded([transport SOSTransportMessageGetAccount], (SOSEngineRef)transport.engine, txn, peer, coder, &message_to_send, peerID, false, &sent, error); + if (message_to_send) { + CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message_to_send, NULL); + CFDictionarySetValue(SOSTransportMessageKVSTestGetChanges(transport), (__bridge CFStringRef)self->circleName, peer_dict); + SOSPeerCoderConsume(&sent, ok); + CFReleaseSafe(peer_dict); + } + CFReleaseSafe(message_to_send); + }); + } + }); + return result; +} + +-(bool) SOSTransportMessageSendMessages:(SOSMessageKVSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error +{ + __block bool result = true; + + CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) { + if (isString(key) && isData(value)) { + CFStringRef peerID = (CFStringRef) key; + CFDataRef message = (CFDataRef) value; + bool rx = sendToPeer(transport, (__bridge CFStringRef)transport->circleName, peerID, message, error); + result &= rx; + } + }); + + return result; +} + +-(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessageIDSTest*) transport peerMessages:(CFMutableDictionaryRef) circle_peer_messages_table err:(CFErrorRef *)error{ + CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryRef peerToMessage = CFDictionaryGetValue(circle_peer_messages_table, (__bridge CFStringRef)transport.circleName); + CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryAddValue(handled, (__bridge CFStringRef)transport.circleName, handled_peers); + + if(peerToMessage){ + CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) { + CFStringRef peer_id = (CFStringRef) key; + CFDataRef peer_message = (CFDataRef) value; + CFErrorRef localError = NULL; + + if ([transport SOSTransportMessageHandlePeerMessage:transport id:peer_id cm:peer_message err:&localError]){ + CFArrayAppendValue(handled_peers, key); + } else { + secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError); + } + CFReleaseNull(localError); + }); + } + CFReleaseNull(handled_peers); + + return handled; +} + +-(bool) SOSTransportMessageFlushChanges:(SOSMessageKVSTest*) transport err:(CFErrorRef *)error +{ + return true; +} + +SOSAccount* SOSTransportMessageKVSTestGetAccount(SOSMessageKVSTest* transport) { + return transport.account; +} +@end + +/// +//MARK IDS Message Test Transport +/// + +@implementation SOSMessageIDSTest +-(SOSMessageIDSTest*) initWithAccount:(SOSAccount*)acct andAccountName:(CFStringRef) aN andCircleName:(CFStringRef) cN err:(CFErrorRef *)error +{ + self = [super init]; + if(self){ + self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL); + self.useFragmentation = kCFBooleanTrue; + self.account = acct; + self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + self.circleName = (__bridge NSString*)cN; + self.accountName = CFRetainSafe(aN); + + if(!message_transports) + message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); + CFArrayAppendValue(message_transports, (__bridge CFTypeRef)self); + SOSRegisterTransportMessage((SOSMessageIDSTest*)self); + } + + return self; +} + +-(bool) SOSTransportMessageIDSGetIDSDeviceID:(SOSAccount*)acct{ + return true; +} + +-(CFIndex) SOSTransportMessageGetTransportType +{ + return kIDSTest; +} +-(CFStringRef) SOSTransportMessageGetCircleName +{ + return (__bridge CFStringRef)circleName; +} +-(CFTypeRef) SOSTransportMessageGetEngine +{ + return engine; +} +-(SOSAccount*) SOSTransportMessageGetAccount +{ + return self.account; +} + +void SOSTransportMessageIDSTestSetName(SOSMessageIDSTest* transport, CFStringRef acctName){ + transport.accountName = acctName; +} + + +static HandleIDSMessageReason checkMessageValidity(SOSAccount* account, CFStringRef fromDeviceID, CFStringRef fromPeerID, CFStringRef *peerID, SOSPeerInfoRef *theirPeerInfo){ + SOSAccountTrustClassic *trust = account.trust; + __block HandleIDSMessageReason reason = kHandleIDSMessageDontHandle; + + SOSCircleForEachPeer(trust.trustedCircle, ^(SOSPeerInfoRef peer) { + CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); + CFStringRef pID = SOSPeerInfoGetPeerID(peer); + + if( deviceID && pID && fromPeerID && fromDeviceID && CFStringGetLength(fromPeerID) != 0 ){ + if(CFStringCompare(pID, fromPeerID, 0) == 0){ + if(CFStringGetLength(deviceID) == 0){ + secnotice("ids transport", "device ID was empty in the peer list, holding on to message"); + CFReleaseNull(deviceID); + reason = kHandleIDSMessageNotReady; + return; + } + else if(CFStringCompare(fromDeviceID, deviceID, 0) != 0){ //IDSids do not match, ghost + reason = kHandleIDSmessageDeviceIDMismatch; + CFReleaseNull(deviceID); + return; + } + else if(CFStringCompare(deviceID, fromDeviceID, 0) == 0){ + *peerID = pID; + *theirPeerInfo = peer; + CFReleaseNull(deviceID); + reason = kHandleIDSMessageSuccess; + return; + } + } + } + CFReleaseNull(deviceID); + }); + + return reason; +} +const char *kMessageKeyIDSDataMessage = "idsDataMessage"; +const char *kMessageKeyDeviceID = "deviceID"; +const char *kMessageKeyPeerID = "peerID"; +const char *kMessageKeySendersPeerID = "sendersPeerID"; + +-(HandleIDSMessageReason) SOSTransportMessageIDSHandleMessage:(SOSAccount*)acct m:(CFDictionaryRef) message err:(CFErrorRef *)error +{ + secnotice("IDS Transport", "SOSTransportMessageIDSHandleMessage!"); + + CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII); + CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII); + CFStringRef sendersPeerIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeySendersPeerID, kCFStringEncodingASCII); + CFStringRef ourPeerIdKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyPeerID, kCFStringEncodingASCII); + + HandleIDSMessageReason result = kHandleIDSMessageSuccess; + + CFDataRef messageData = asData(CFDictionaryGetValue(message, dataKey), NULL); + __block CFStringRef fromDeviceID = asString(CFDictionaryGetValue(message, deviceIDKey), NULL); + __block CFStringRef fromPeerID = (CFStringRef)CFDictionaryGetValue(message, sendersPeerIDKey); + CFStringRef ourPeerID = asString(CFDictionaryGetValue(message, ourPeerIdKey), NULL); + + CFStringRef peerID = NULL; + SOSPeerInfoRef theirPeer = NULL; + + require_action_quiet(fromDeviceID, exit, result = kHandleIDSMessageDontHandle); + require_action_quiet(fromPeerID, exit, result = kHandleIDSMessageDontHandle); + require_action_quiet(messageData && CFDataGetLength(messageData) != 0, exit, result = kHandleIDSMessageDontHandle); + require_action_quiet(SOSAccountHasFullPeerInfo(account, error), exit, result = kHandleIDSMessageNotReady); + require_action_quiet(ourPeerID && [account.peerID isEqual: (__bridge NSString*) ourPeerID], exit, result = kHandleIDSMessageDontHandle; secnotice("IDS Transport","ignoring message for: %@", ourPeerID)); + + require_quiet((result = checkMessageValidity( account, fromDeviceID, fromPeerID, &peerID, &theirPeer)) == kHandleIDSMessageSuccess, exit); + + if ([account.ids_message_transport SOSTransportMessageHandlePeerMessage:account.ids_message_transport id:peerID cm:messageData err:error]) { + CFMutableDictionaryRef peersToSyncWith = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(peerIDs, peerID); + SOSAccountTrustClassic* trust = account.trust; + //sync using fragmentation? + if(SOSPeerInfoShouldUseIDSMessageFragmentation(trust.peerInfo, theirPeer)){ + //set useFragmentation bit + [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref: kCFBooleanTrue]; + } + else{ + [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref: kCFBooleanFalse]; + } + + if(![account.ids_message_transport SOSTransportMessageSyncWithPeers:account.ids_message_transport p:peerIDs err:error]){ + secerror("SOSTransportMessageIDSHandleMessage Could not sync with all peers: %@", *error); + }else{ + secnotice("IDS Transport", "Synced with all peers!"); + } + + CFReleaseNull(peersToSyncWith); + CFReleaseNull(peerIDs); + }else{ + if(error && *error != NULL){ + CFStringRef errorMessage = CFErrorCopyDescription(*error); + if (-25308 == CFErrorGetCode(*error)) { // tell KeychainSyncingOverIDSProxy to call us back when device unlocks + result = kHandleIDSMessageLocked; + }else{ //else drop it, couldn't handle the message + result = kHandleIDSMessageDontHandle; + } + secerror("IDS Transport Could not handle message: %@, %@", messageData, *error); + CFReleaseNull(errorMessage); + + } + else{ //no error but failed? drop it, log message + secerror("IDS Transport Could not handle message: %@", messageData); + result = kHandleIDSMessageDontHandle; + + } + } + +exit: + CFReleaseNull(ourPeerIdKey); + CFReleaseNull(sendersPeerIDKey); + CFReleaseNull(deviceIDKey); + CFReleaseNull(dataKey); + return result; +} + +-(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessageIDSTest*) transport peerMessages:(CFMutableDictionaryRef)message err:(CFErrorRef *)error +{ + + CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDictionaryRef peerToMessage = CFDictionaryGetValue(message, (__bridge CFTypeRef)(transport.circleName)); + CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + secerror("Received IDS message!"); + if(peerToMessage){ + CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) { + CFStringRef peer_id = asString(key, NULL); + CFDataRef peer_message = asData(value, NULL); + CFErrorRef localError = NULL; + + if (peer_id && peer_message && [transport SOSTransportMessageHandlePeerMessage:transport id:peer_id cm:peer_message err:&localError]) { + CFArrayAppendValue(handled_peers, key); + } else { + secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError); + } + CFReleaseNull(localError); + }); + } + CFDictionaryAddValue(handled, (__bridge CFStringRef)(transport.circleName), handled_peers); + CFReleaseNull(handled_peers); + + return handled; +} + +static void SOSTransportMessageIDSTestAddBulkToChanges(SOSMessageIDSTest* transport, CFDictionaryRef updates){ +#ifndef __clang_analyzer__ // The analyzer thinks transport.changes is a leak, but I don't know why. + if (transport.changes == NULL) { + transport.changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates); + + } + else{ + CFDictionaryForEach(updates, ^(const void *key, const void *value) { + CFDictionaryAddValue(transport.changes, key, value); + }); + } +#endif +} +static bool sendDataToPeerIDSTest(SOSMessageIDSTest* transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error) +{ + secerror("sending message through test transport: %@", message); + NSString* myID = transport.account.peerID; + CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, (__bridge CFStringRef) myID, peerID); + CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL); + + SOSTransportMessageIDSTestAddBulkToChanges(transport, a_message_to_a_peer); + + CFReleaseNull(message_to_peer_key); + CFReleaseNull(a_message_to_a_peer); + return true; + +} +static bool sendDictionaryToPeerIDSTest(SOSMessageIDSTest* transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDictionaryRef message, CFErrorRef *error) +{ + secerror("sending message through test transport: %@", message); + NSString* myID = transport.account.peerID; + CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, (__bridge CFStringRef) myID, peerID); + CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL); + + SOSTransportMessageIDSTestAddBulkToChanges(transport, a_message_to_a_peer); + + CFReleaseNull(message_to_peer_key); + CFReleaseNull(a_message_to_a_peer); + return true; + +} + +-(bool) SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*) transport p:(CFSetRef)peers err:(CFErrorRef *)error +{ + // Each entry is keyed by circle name and contains a list of peerIDs + __block bool result = true; + + CFSetForEach(peers, ^(const void *value) { + CFStringRef peerID = asString(value, NULL); + if (peerID) { + secnotice("transport", "IDS sync with peerIDs %@", peerID); + result &= [transport SOSTransportMessageSendMessageIfNeeded:transport id:(__bridge CFStringRef)transport.circleName pID:peerID err:error]; + } + }); + + return result; +} + +-(bool) SOSTransportMessageSendMessages:(SOSMessageIDSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error +{ + __block bool result = true; + CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) { + CFStringRef idsDeviceID = NULL;; + CFStringRef peerID = asString(key, NULL); + SOSPeerInfoRef pi = NULL; + if(peerID){ + if(!CFEqualSafe(peerID, (__bridge CFStringRef) transport.account.peerID)){ + + pi = SOSAccountCopyPeerWithID(transport.account, peerID, NULL); + if(pi){ + idsDeviceID = SOSPeerInfoCopyDeviceID(pi); + if(idsDeviceID != NULL){ + + CFDictionaryRef messageDictionary = asDictionary(value, NULL); + if (messageDictionary) { + result &= sendDictionaryToPeerIDSTest(transport, (__bridge CFStringRef)transport.circleName, idsDeviceID, peerID, messageDictionary, error); + } else { + CFDataRef messageData = asData(value, NULL); + if (messageData) { + result &= sendDataToPeerIDSTest(transport, (__bridge CFStringRef)transport.circleName, idsDeviceID, peerID, messageData, error); + } + } + } + } + } + } + CFReleaseNull(idsDeviceID); + CFReleaseNull(pi); + }); + + return result; +} + +-(bool) SOSTransportMessageFlushChanges:(SOSMessageIDSTest*) transport err:(CFErrorRef *)error +{ + return true; +} + +-(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageIDSTest*) transport peers:(CFDictionaryRef) peers err:(CFErrorRef*) error +{ + return true; +} + +void SOSTransportMessageIDSTestClearChanges(SOSMessageIDSTest* transport) +{ + transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); +} + +CFMutableDictionaryRef SOSTransportMessageIDSTestGetChanges(SOSMessageIDSTest* transport) +{ + return transport.changes; +} + +SOSAccount* SOSTransportMessageIDSTestGetAccount(SOSMessageIDSTest* transport) +{ + return transport.account; +} + +CFStringRef SOSTransportMessageIDSTestGetName(SOSMessageIDSTest* transport){ + return transport.accountName; +} + +@end + + +void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt){ + CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceNameKey); + + SOSTransportKeyParameterTestSetName((CKKeyParameterTest*)account.key_transport, new_name); + SOSTransportCircleTestSetName((SOSCircleStorageTransportTest*)account.circle_transport, new_name); + SOSTransportMessageKVSTestSetName((SOSMessageKVSTest*)account.kvs_message_transport, new_name); + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)account.ids_message_transport, new_name); + +} + +static SOSCircleRef SOSAccountEnsureCircleTest(SOSAccount* a, CFStringRef name, CFStringRef accountName) +{ + CFErrorRef localError = NULL; + SOSAccountTrustClassic *trust = a.trust; + + SOSCircleRef circle = [a.trust getCircle:&localError]; + if(!circle || isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)){ + secnotice("circle", "Error retrieving the circle: %@", localError); + CFReleaseNull(localError); + + circle = SOSCircleCreate(kCFAllocatorDefault, name, &localError); + if (circle){ + [trust setTrustedCircle:circle]; + } + else{ + secnotice("circle", "Could not create circle: %@", localError); + } + CFReleaseNull(localError); + } + + if(![trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(a.gestalt) deviceID:(__bridge CFStringRef)(a.deviceID) backupKey:(__bridge CFDataRef)(a.backup_key) err:&localError]) + { + secnotice("circle", "had an error building full peer: %@", localError); + CFReleaseNull(localError); + return circle; + } + + CFReleaseNull(localError); + return circle; +} + +bool SOSAccountEnsureFactoryCirclesTest(SOSAccount* a, CFStringRef accountName) +{ + bool result = false; + if (a) + { + if(!a.factory) + return result; + CFStringRef circle_name = SOSDataSourceFactoryCopyName(a.factory); + if(!circle_name) + return result; + SOSAccountEnsureCircleTest(a, (CFStringRef)circle_name, accountName); + + CFReleaseNull(circle_name); + result = true; + } + return result; +} + +bool SOSAccountInflateTestTransportsForCircle(SOSAccount* account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error){ + bool success = false; + + if(account.key_transport == nil){ + account.key_transport = (CKKeyParameter*)[[CKKeyParameterTest alloc] initWithAccount:account andName:accountName andCircleName:circleName]; + require_quiet(account.key_transport, fail); + } + + if(account.circle_transport == nil){ + account.circle_transport = (SOSKVSCircleStorageTransport*)[[SOSCircleStorageTransportTest alloc] initWithAccount:account andWithAccountName:accountName andCircleName:circleName]; + require_quiet(account.circle_transport, fail); + } + if(account.kvs_message_transport == nil){ + account.kvs_message_transport = (SOSMessageKVS*)[[SOSMessageKVSTest alloc] initWithAccount:account andName:accountName andCircleName:circleName]; + } + if(account.ids_message_transport == nil){ + account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:account andAccountName:accountName andCircleName:circleName err:NULL]; + } + + success = true; +fail: + return success; +} + + diff --git a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c b/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c index 2efc3bbf..ad748d66 100644 --- a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c +++ b/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c @@ -24,7 +24,7 @@ #include "SecdTestKeychainUtilities.h" -#include +#include #include #include #include diff --git a/OSX/sec/securityd/Regressions/sd-10-policytree.c b/OSX/sec/securityd/Regressions/sd-10-policytree.m similarity index 100% rename from OSX/sec/securityd/Regressions/sd-10-policytree.c rename to OSX/sec/securityd/Regressions/sd-10-policytree.m diff --git a/OSX/sec/securityd/Regressions/secd-01-items.c b/OSX/sec/securityd/Regressions/secd-01-items.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-01-items.c rename to OSX/sec/securityd/Regressions/secd-01-items.m diff --git a/OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.c b/OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.c rename to OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.m diff --git a/OSX/sec/securityd/Regressions/secd-03-corrupted-items.c b/OSX/sec/securityd/Regressions/secd-03-corrupted-items.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-03-corrupted-items.c rename to OSX/sec/securityd/Regressions/secd-03-corrupted-items.m diff --git a/OSX/sec/securityd/Regressions/secd-04-corrupted-items.c b/OSX/sec/securityd/Regressions/secd-04-corrupted-items.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-04-corrupted-items.c rename to OSX/sec/securityd/Regressions/secd-04-corrupted-items.m diff --git a/OSX/sec/securityd/Regressions/secd-100-initialsync.c b/OSX/sec/securityd/Regressions/secd-100-initialsync.m similarity index 87% rename from OSX/sec/securityd/Regressions/secd-100-initialsync.c rename to OSX/sec/securityd/Regressions/secd-100-initialsync.m index c8620ab0..5cf56e51 100644 --- a/OSX/sec/securityd/Regressions/secd-100-initialsync.c +++ b/OSX/sec/securityd/Regressions/secd-100-initialsync.m @@ -67,8 +67,8 @@ static void tests(void) SOSDataSourceRef test_source = SOSTestDataSourceCreate(); SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("AliceAccount"),CFSTR("TestType") ); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("BobAccount"),CFSTR("TestType") ); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("AliceAccount"),CFSTR("TestType") ); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("BobAccount"),CFSTR("TestType") ); ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -101,17 +101,22 @@ static void tests(void) accounts_agree("bob&alice pair", bob_account, alice_account); ok(!SOSAccountCheckHasBeenInSync_wTxn(bob_account), "Bob should not be initially synced"); - CFSetRef bob_viewSet = SOSPeerInfoCopyEnabledViews(SOSAccountGetMyPeerInfo(bob_account)); + CFSetRef bob_viewSet = SOSPeerInfoCopyEnabledViews(bob_account.peerInfo); is(CFSetGetCount(bob_viewSet), 14, "bob's initial view set should be just the 14 views"); CFReleaseNull(bob_viewSet); ok(!SOSAccountCheckHasBeenInSync_wTxn(bob_account), "Bob should not be initially synced"); - SOSAccountPeerGotInSync_wTxn(bob_account, SOSAccountGetMyPeerInfo(alice_account)); + SOSAccountPeerGotInSync_wTxn(bob_account, alice_account.peerInfo); - bob_viewSet = SOSPeerInfoCopyEnabledViews(SOSAccountGetMyPeerInfo(bob_account)); - is(CFSetGetCount(bob_viewSet), 18, "bob's initial view set should be just the back up"); + bob_viewSet = SOSPeerInfoCopyEnabledViews(bob_account.peerInfo); + is(CFSetGetCount(bob_viewSet), 20, "bob's initial view set should be just the back up"); CFReleaseNull(bob_viewSet); + bob_account = nil; + alice_account = nil; + SOSDataSourceFactoryRelease(test_factory); + + SOSTestCleanup(); } int secd_100_initialsync(int argc, char *const *argv) diff --git a/OSX/sec/securityd/Regressions/secd-130-other-peer-views.c b/OSX/sec/securityd/Regressions/secd-130-other-peer-views.m similarity index 88% rename from OSX/sec/securityd/Regressions/secd-130-other-peer-views.c rename to OSX/sec/securityd/Regressions/secd-130-other-peer-views.m index 33b21321..8cc3349d 100644 --- a/OSX/sec/securityd/Regressions/secd-130-other-peer-views.c +++ b/OSX/sec/securityd/Regressions/secd-130-other-peer-views.m @@ -21,8 +21,6 @@ #include -#define kTestTestCount 109 - #define kAccountPasswordString ((uint8_t*) "FooFooFoo") #define kAccountPasswordStringLen 10 @@ -34,10 +32,10 @@ static void tests(void) { CFStringRef cfaccount = CFSTR("test@test.org"); CFMutableDictionaryRef cfchanges = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - SOSAccountRef david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); CFArrayRef aView = CFArrayCreateForCFTypes(kCFAllocatorDefault, kSOSViewPCSMasterKey, @@ -109,9 +107,9 @@ static void tests(void) { is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 5, "updates"); // Make all views work buy finishing initial sync. - SOSAccountPeerGotInSync_wTxn(bob_account, SOSAccountGetMyPeerInfo(alice_account)); - SOSAccountPeerGotInSync_wTxn(carole_account, SOSAccountGetMyPeerInfo(alice_account)); - SOSAccountPeerGotInSync_wTxn(david_account, SOSAccountGetMyPeerInfo(alice_account)); + SOSAccountPeerGotInSync_wTxn(bob_account, alice_account.peerInfo); + SOSAccountPeerGotInSync_wTxn(carole_account, alice_account.peerInfo); + SOSAccountPeerGotInSync_wTxn(david_account, alice_account.peerInfo); is(ProcessChangesUntilNoChange(cfchanges, alice_account, bob_account, carole_account, david_account, NULL), 4, "updates"); @@ -161,17 +159,12 @@ static void tests(void) { CFReleaseNull(otherView); CFReleaseNull(otherAndWifiViews); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); - CFReleaseNull(david_account); - SOSTestCleanup(); } int secd_130_other_peer_views(int argc, char *const *argv) { - plan_tests(kTestTestCount); + plan_tests(107); secd_test_setup_temp_keychain(__FUNCTION__, NULL); diff --git a/OSX/sec/securityd/Regressions/secd-154-engine-backoff.c b/OSX/sec/securityd/Regressions/secd-154-engine-backoff.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-154-engine-backoff.c rename to OSX/sec/securityd/Regressions/secd-154-engine-backoff.m diff --git a/OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m b/OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m new file mode 100644 index 00000000..7508b9de --- /dev/null +++ b/OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m @@ -0,0 +1,390 @@ +// +// secd-155-otrnegotiationmonitor.m +// secdtests_ios +// +// Created by Michelle Auricchio on 6/5/17. +// + +#import +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#import "SOSAccountTesting.h" +#import "SOSTransportTestTransports.h" + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include "SecRecoveryKey.h" + +#include +#include + +#include +#include "SecdTestKeychainUtilities.h" +#include "SOSAccountTesting.h" +#import "SOSTransportTestTransports.h" +#include "SOSTestDevice.h" +#include "SOSTestDataSource.h" +#include +#include +static int kTestTestCount = 114; + +static bool SOSAccountIsThisPeerIDMe(SOSAccount* account, CFStringRef peerID) { + SOSAccountTrustClassic* trust = account.trust; + SOSPeerInfoRef mypi = trust.peerInfo; + ok(mypi); + CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi); + ok(myPeerID); + return myPeerID && CFEqualSafe(myPeerID, peerID); +} + +static void ids_test_sync(SOSAccount* alice_account, SOSAccount* bob_account){ + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + __block bool SyncingCompletedOverIDS = false; + __block CFErrorRef localError = NULL; + + SOSAccountTrustClassic* aliceTrust = alice_account.trust; + SOSAccountTrustClassic* bobTrust = bob_account.trust; + SOSDataSourceRef bob_ds = SOSDataSourceFactoryCreateDataSource(bob_account.factory, CFSTR("ak"), NULL); + SOSEngineRef bob_engine = bob_ds ? SOSDataSourceGetSharedEngine(bob_ds, NULL) : (SOSEngineRef) NULL; + SOSDataSourceRef alice_ds = SOSDataSourceFactoryCreateDataSource(alice_account.factory, CFSTR("ak"), NULL); + SOSEngineRef alice_engine = alice_ds ? SOSDataSourceGetSharedEngine(alice_ds, NULL) : (SOSEngineRef) NULL; + + /* new routines to test */ + __block NSString *bobID = bob_account.peerID; + __block NSString *aliceID = alice_account.peerID; + + + /////////////////////////// + //second exchange// + /////////////////////////// + + SOSCircleForEachValidPeer(aliceTrust.trustedCircle, alice_account.accountKey, ^(SOSPeerInfoRef peer) { + if (!SOSAccountIsThisPeerIDMe(alice_account, SOSPeerInfoGetPeerID(peer))) { + if(SOSPeerInfoShouldUseIDSTransport(aliceTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(aliceTrust.peerInfo, peer)){ + secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); + + CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); + + SyncingCompletedOverIDS = [alice_account.ids_message_transport SOSTransportMessageSyncWithPeers:alice_account.ids_message_transport p:ids err:&localError]; + CFReleaseNull(ids); + } + } + }); + + SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID)); + ok(false == SOSPeerTimerForPeerExist(bob_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID)); + ok(true == SOSCoderIsCoderInAwaitingState(coder)); + }); + + ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); + + SOSCircleForEachValidPeer(bobTrust.trustedCircle, bob_account.accountKey, ^(SOSPeerInfoRef peer) { + if (!SOSAccountIsThisPeerIDMe(bob_account, SOSPeerInfoGetPeerID(peer))) { + if(SOSPeerInfoShouldUseIDSTransport(bobTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(bobTrust.peerInfo, peer)){ + secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); + + CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); + + SyncingCompletedOverIDS = [(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)bob_account.ids_message_transport p:ids err:&localError]; + CFReleaseNull(ids); + } + } + }); + + ok(SyncingCompletedOverIDS, "synced items over IDS"); + + SOSEngineWithPeerID(bob_engine, (__bridge CFStringRef)aliceID, NULL, ^(SOSPeerRef alice_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(bob_account , aliceID)); + ok(false == SOSPeerTimerForPeerExist(alice_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(bob_account, aliceID)); + }); + + ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); + + SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID)); + ok(false == SOSPeerTimerForPeerExist(bob_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID)); + ok(true == SOSCoderIsCoderInAwaitingState(coder)); + }); + + /////////////////////////// + //second sync exchange // + /////////////////////////// + + SOSCircleForEachValidPeer(aliceTrust.trustedCircle, alice_account.accountKey, ^(SOSPeerInfoRef peer) { + if (!SOSAccountIsThisPeerIDMe(alice_account, SOSPeerInfoGetPeerID(peer))) { + if(SOSPeerInfoShouldUseIDSTransport(aliceTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(aliceTrust.peerInfo, peer)){ + secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); + + CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); + + SyncingCompletedOverIDS = [alice_account.ids_message_transport SOSTransportMessageSyncWithPeers:alice_account.ids_message_transport p:ids err:&localError]; + CFReleaseNull(ids); + } + } + }); + + SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID)); + ok(false == SOSPeerTimerForPeerExist(bob_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID)); + ok(true == SOSCoderIsCoderInAwaitingState(coder)); + }); + + ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); + + SOSCircleForEachValidPeer(bobTrust.trustedCircle, bob_account.accountKey, ^(SOSPeerInfoRef peer) { + if (!SOSAccountIsThisPeerIDMe(bob_account, SOSPeerInfoGetPeerID(peer))) { + if(SOSPeerInfoShouldUseIDSTransport(bobTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(bobTrust.peerInfo, peer)){ + secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); + + CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); + + SyncingCompletedOverIDS = [(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)bob_account.ids_message_transport p:ids err:&localError]; + CFReleaseNull(ids); + } + } + }); + + ok(SyncingCompletedOverIDS, "synced items over IDS"); + + SOSEngineWithPeerID(bob_engine, (__bridge CFStringRef)aliceID, NULL, ^(SOSPeerRef alice_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(bob_account , aliceID)); + ok(false == SOSPeerTimerForPeerExist(alice_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(bob_account, aliceID)); + }); + + ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); + + SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID)); + ok(false == SOSPeerTimerForPeerExist(bob_peer)); + ok(true == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID)); + ok(false == SOSCoderIsCoderInAwaitingState(coder)); + }); + + CFReleaseNull(changes); +} + + +static void tests(void) +{ + CFErrorRef error = NULL; + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("ak")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("ak")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(cfpassword); + CFReleaseNull(error); + + ok(NULL != alice_account, "Alice Created"); + ok(NULL != bob_account, "Bob Created"); + + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); + CFReleaseNull(error); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + { + CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); + + ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); + ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); + CFReleaseNull(error); + CFReleaseNull(applicants); + } + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + accounts_agree("bob&alice pair", bob_account, alice_account); + + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); + ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); + CFReleaseNull(peers); + + SOSDataSourceRef alice_ds = SOSDataSourceFactoryCreateDataSource(alice_account.factory, CFSTR("ak"), NULL); + SOSEngineRef alice_engine = alice_ds ? SOSDataSourceGetSharedEngine(alice_ds, NULL) : (SOSEngineRef) NULL; + + ok(false == SOSEngineHandleCodedMessage(alice_account, alice_engine, (__bridge CFStringRef)bob_account.peerID, NULL, NULL)); + + SOSDataSourceRef bob_ds = SOSDataSourceFactoryCreateDataSource(bob_account.factory, CFSTR("ak"), NULL); + SOSEngineRef bob_engine = bob_ds ? SOSDataSourceGetSharedEngine(bob_ds, NULL) : (SOSEngineRef) NULL; + + ok(false == SOSEngineHandleCodedMessage(bob_account, bob_engine, (__bridge CFStringRef)alice_account.peerID, NULL, NULL)); + + /* new routines to test */ + __block NSString *bobID = bob_account.peerID; + __block NSString *aliceID = alice_account.peerID; + + SOSEngineWithPeerID(bob_engine, (__bridge CFStringRef)aliceID, NULL, ^(SOSPeerRef alice_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(bob_account , aliceID)); + ok(false == SOSPeerTimerForPeerExist(alice_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(bob_account, aliceID)); + }); + + SOSEngineWithPeerID(alice_engine, (__bridge CFStringRef)bobID, NULL, ^(SOSPeerRef bob_peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) { + ok(false == SOSPeerOTRTimerHaveReachedMaxRetryAllowance(alice_account , bobID)); + ok(false == SOSPeerTimerForPeerExist(bob_peer)); + ok(false == SOSPeerOTRTimerHaveAnRTTAvailable(alice_account, bobID)); + }); + + //creating test devices + CFIndex version = 0; + + // Optionally prefix each peer with name to make them more unique. + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); + CFSetRef views = SOSViewsCopyTestV2Default(); + CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + CFStringRef deviceID; + CFArrayForEachC(deviceIDs, deviceID) { + SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(deviceID, views, NULL); + CFArrayAppendValue(peerMetas, peerMeta); + CFReleaseNull(peerMeta); + } + + CFReleaseNull(views); + CFArrayForEachC(deviceIDs, deviceID) { + SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); + SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); + + if([alice_account.peerID isEqual: (__bridge id)(deviceID)]){ + alice_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); + } + else{ + bob_account.factory = device->dsf; + SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); + } + + CFReleaseNull(device); + } + CFReleaseNull(deviceIDs); + CFReleaseNull(peerMetas); + + SOSUnregisterAllTransportMessages(); + CFArrayRemoveAllValues(message_transports); + + SOSAccountTrustClassic* aliceTrust = alice_account.trust; + SOSAccountTrustClassic* bobTrust = bob_account.trust; + + alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:SOSCircleGetName(aliceTrust.trustedCircle) err:&error ]; + + bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:SOSCircleGetName(bobTrust.trustedCircle) err:&error]; + + ok(alice_account.ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); + ok(bob_account.ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); + + bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^bool(SOSCircleRef circle) { + CFErrorRef localError = NULL; + + SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + + return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL); + }]; + + ok(result, "Alice account update circle with transport type"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + result = [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^bool(SOSCircleRef circle) { + CFErrorRef localError = NULL; + + SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + + return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL); + }]; + + ok(result, "Bob account update circle with transport type"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + + CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo); + CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo); + ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS"); + ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS"); + + CFReleaseNull(alice_transportType); + CFReleaseNull(bob_accountTransportType); + + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); + ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); + + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name"); + ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); + + + ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("Alice"),&error), "Setting IDS device ID"); + CFStringRef alice_dsid = SOSAccountCopyDeviceID(alice_account, &error); + ok(CFEqualSafe(alice_dsid, CFSTR("Alice")), "Getting IDS device ID"); + CFReleaseNull(alice_dsid); + + ok(SOSAccountSetMyDSID_wTxn(bob_account, CFSTR("Bob"),&error), "Setting IDS device ID"); + CFStringRef bob_dsid = SOSAccountCopyDeviceID(bob_account, &error); + ok(CFEqualSafe(bob_dsid, CFSTR("Bob")), "Getting IDS device ID"); + CFReleaseNull(bob_dsid); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); + + ok(SOSAccountEnsurePeerRegistration(alice_account, NULL), "ensure peer registration - alice"); + + ok(SOSAccountEnsurePeerRegistration(bob_account, NULL), "ensure peer registration - bob"); + + ids_test_sync(alice_account, bob_account); +} + +int secd_155_otr_negotiation_monitor(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/OSX/sec/securityd/Regressions/secd-156-timers.m b/OSX/sec/securityd/Regressions/secd-156-timers.m new file mode 100644 index 00000000..e5c49050 --- /dev/null +++ b/OSX/sec/securityd/Regressions/secd-156-timers.m @@ -0,0 +1,100 @@ +// +// secd-156-timers.m +// secdRegressions +// + +#import + +#include +#include + +#include +#include +#include + +#include "secd_regressions.h" +#include + +#include + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static int kTestTestCount = 3; + + +static void testPeerRateLimiterSendNextMessageWithRetain(CFStringRef peerid, CFStringRef accessGroup) +{ + ok(CFStringCompare(peerid, CFSTR("imretainedpeerid"), 0) == kCFCompareEqualTo); +} + +static void testOTRTimer() +{ + dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); + + CFStringRef peeridRetained = CFRetainSafe(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), CFSTR("imretainedpeerid"))); + dispatch_queue_t test_queue2 = dispatch_queue_create("com.apple.security.keychain-otrtimer2", DISPATCH_QUEUE_SERIAL); + __block dispatch_source_t timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, test_queue2); + + dispatch_source_set_timer(timer2, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); + dispatch_source_set_event_handler(timer2, ^{ + testPeerRateLimiterSendNextMessageWithRetain(peeridRetained, CFSTR("NoAttribute")); + dispatch_semaphore_signal(sema2); + }); + dispatch_resume(timer2); + dispatch_source_set_cancel_handler(timer2, ^{ + CFReleaseSafe(peeridRetained); + }); + + CFReleaseNull(peeridRetained); + dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER); + +} + +static void testOTRTimerWithRetain(CFStringRef peerid) +{ + ok(CFStringCompare(peerid, CFSTR("imretainedpeerid"), 0) == kCFCompareEqualTo); +} + +static void testRateLimitingTimer() + +{ + dispatch_semaphore_t sema2 = dispatch_semaphore_create(0); + + CFStringRef peeridRetained = CFRetainSafe(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), CFSTR("imretainedpeerid"))); + + dispatch_queue_t test_queue2 = dispatch_queue_create("com.apple.security.keychain-ratelimit12", DISPATCH_QUEUE_SERIAL); + __block dispatch_source_t timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, test_queue2); + + dispatch_source_set_timer(timer2, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); + dispatch_source_set_event_handler(timer2, ^{ + testOTRTimerWithRetain(peeridRetained); + dispatch_semaphore_signal(sema2); + }); + dispatch_resume(timer2); + + dispatch_source_set_cancel_handler(timer2, ^{ + CFReleaseSafe(peeridRetained); + }); + + CFReleaseNull(peeridRetained); + dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER); + +} +static void tests(){ + + testOTRTimer(); + testRateLimitingTimer(); +} + +int secd_156_timers(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m b/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m index d4ecd92f..3e758520 100644 --- a/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m +++ b/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m @@ -44,7 +44,18 @@ #include "secd_regressions.h" #include "SecdTestKeychainUtilities.h" +static int ckmirror_row_exists = 0; +static int ckmirror_row_callback(void* unused, int count, char **data, char **columns) +{ + ckmirror_row_exists = 1; + for (int i = 0; i < count; i++) { + if(strcmp(columns[i], "ckzone") == 0) { + is(strcmp(data[i], "ckzone"), 0, "Data is expected 'ckzone'"); + } + } + return 0; +} static void keychain_upgrade(bool musr, const char *dbname) @@ -81,17 +92,25 @@ keychain_upgrade(bool musr, const char *dbname) }, NULL); is(res, 0, "SecItemAdd(user)"); + NSString *keychain_path = CFBridgingRelease(__SecKeychainCopyPath()); + + // Add a row to a non-item table + /* Create a new keychain sqlite db */ + sqlite3 *db = NULL; + + is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "open db"); + is(sqlite3_exec(db, "INSERT into ckmirror VALUES(\"ckzone\", \"importantuuid\", \"keyuuid\", 0, \"asdf\", \"qwer\", \"ckrecord\", 0, 0, NULL, NULL, NULL);", NULL, NULL, NULL), SQLITE_OK, "row added to ckmirror table"); + is(sqlite3_close(db), SQLITE_OK, "close db"); + SecKeychainDbReset(^{ - NSString *keychain_path = CFBridgingRelease(__SecKeychainCopyPath()); /* Create a new keychain sqlite db */ sqlite3 *db; is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "create keychain"); - is(sqlite3_exec(db, "UPDATE tversion SET version = version - 1", NULL, NULL, NULL), SQLITE_OK, + is(sqlite3_exec(db, "UPDATE tversion SET minor = minor - 1", NULL, NULL, NULL), SQLITE_OK, "\"downgrade\" keychain"); is(sqlite3_close(db), SQLITE_OK, "close db"); - }); #if TARGET_OS_IPHONE @@ -109,6 +128,13 @@ keychain_upgrade(bool musr, const char *dbname) }, NULL); is(res, 0, "SecItemCopyMatching(user)"); + char* err = NULL; + + is(sqlite3_open([keychain_path UTF8String], &db), SQLITE_OK, "open db"); + is(sqlite3_exec(db, "select * from ckmirror;", ckmirror_row_callback, NULL, &err), SQLITE_OK, "row added to ckmirror table"); + is(sqlite3_close(db), SQLITE_OK, "close db"); + is(ckmirror_row_exists, 1, "SQLite found a row in the ckmirror table"); + #if TARGET_OS_IOS if (musr) SecSecuritySetMusrMode(false, 501, -1); @@ -127,7 +153,7 @@ secd_20_keychain_upgrade(int argc, char *const *argv) #define have_system_keychain_tests 0 #endif - plan_tests((kSecdTestSetupTestCount + 5 + have_system_keychain_tests) * 2); + plan_tests((kSecdTestSetupTestCount + 5 + have_system_keychain_tests + 8) * 2); CFArrayRef currentACL = SecAccessGroupsGetCurrent(); diff --git a/OSX/sec/securityd/Regressions/secd-200-logstate.c b/OSX/sec/securityd/Regressions/secd-200-logstate.m similarity index 73% rename from OSX/sec/securityd/Regressions/secd-200-logstate.c rename to OSX/sec/securityd/Regressions/secd-200-logstate.m index 88ebadb7..ac1d8f34 100644 --- a/OSX/sec/securityd/Regressions/secd-200-logstate.c +++ b/OSX/sec/securityd/Regressions/secd-200-logstate.m @@ -59,22 +59,22 @@ #define HOW_MANY_MINIONS 4 -static int kTestTestCount = (5+(HOW_MANY_MINIONS+1)*20); +static int kTestTestCount = ((HOW_MANY_MINIONS+1)*20); -static bool SOSArrayForEachAccount(CFArrayRef accounts, bool (^operation)(SOSAccountRef account)) { +static bool SOSArrayForEachAccount(CFArrayRef accounts, bool (^operation)(SOSAccount* account)) { __block bool retval = true; CFArrayForEach(accounts, ^(const void *value) { - SOSAccountRef account = (SOSAccountRef) value; + SOSAccount* account = (__bridge SOSAccount*) value; retval &= operation(account); }); return retval; } -static inline void FeedChangesToMasterMinions(CFMutableDictionaryRef changes, SOSAccountRef master_account, CFArrayRef minion_accounts) { +static inline void FeedChangesToMasterMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { FeedChangesTo(changes, master_account); - SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccountRef account) { + SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { FeedChangesTo(changes, account); return true; }); @@ -83,13 +83,13 @@ static inline void FeedChangesToMasterMinions(CFMutableDictionaryRef changes, SO } -static inline bool ProcessChangesOnceMasterMinions(CFMutableDictionaryRef changes, SOSAccountRef master_account, CFArrayRef minion_accounts) { +static inline bool ProcessChangesOnceMasterMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { bool result = FillAllChanges(changes); FeedChangesToMasterMinions(changes, master_account, minion_accounts); return result; } -static inline int ProcessChangesForMasterAndMinions(CFMutableDictionaryRef changes, SOSAccountRef master_account, CFArrayRef minion_accounts) { +static inline int ProcessChangesForMasterAndMinions(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts) { int result = 0; bool new_data = false; do { @@ -99,11 +99,12 @@ static inline int ProcessChangesForMasterAndMinions(CFMutableDictionaryRef chang return result; } -static bool MakeTheBigCircle(CFMutableDictionaryRef changes, SOSAccountRef master_account, CFArrayRef minion_accounts, CFErrorRef *error) { +static bool MakeTheBigCircle(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts, CFErrorRef *error) { bool retval = SOSAccountResetToOffering_wTxn(master_account, error); - require_quiet(retval, errOut); + if(!retval) + return retval; ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); - retval = SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccountRef account) { + retval = SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { bool localret = SOSAccountJoinCircles_wTxn(account, error); ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); return localret; @@ -111,29 +112,32 @@ static bool MakeTheBigCircle(CFMutableDictionaryRef changes, SOSAccountRef maste require_quiet(retval, errOut); CFArrayRef applicants = SOSAccountCopyApplicants(master_account, error); retval = SOSAccountAcceptApplicants(master_account , applicants, error); + CFReleaseNull(applicants); ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); errOut: return retval; } -static CFArrayRef CreateManyAccountsForLocalChanges(CFStringRef namefmt, CFStringRef data_source_name, size_t howmany) { +static CFArrayRef CreateManyAccountsForLocalChanges(CFStringRef namefmt, CFStringRef data_source_name, size_t howmany) + CF_FORMAT_FUNCTION(1, 0); + +static CFArrayRef CreateManyAccountsForLocalChanges(CFStringRef name, CFStringRef data_source_name, size_t howmany) { CFMutableArrayRef accounts = CFArrayCreateMutable(kCFAllocatorDefault, howmany, &kCFTypeArrayCallBacks); for(size_t i = 0; i < howmany; i++) { - CFStringRef tmpname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, namefmt, i); - SOSAccountRef tmp = CreateAccountForLocalChanges(tmpname, CFSTR("TestSource")); - CFArraySetValueAtIndex(accounts, i, tmp); + CFStringRef tmpname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%ld"), name, (long)i); + SOSAccount* tmp = CreateAccountForLocalChanges(tmpname, CFSTR("TestSource")); + CFArraySetValueAtIndex(accounts, i, (__bridge const void *)(tmp)); CFReleaseNull(tmpname); - CFReleaseNull(tmp); } return accounts; } -static bool AssertAllCredentialsAndUpdate(CFMutableDictionaryRef changes, SOSAccountRef master_account, CFArrayRef minion_accounts, CFStringRef user_account, CFDataRef user_password, CFErrorRef *error) { +static bool AssertAllCredentialsAndUpdate(CFMutableDictionaryRef changes, SOSAccount* master_account, CFArrayRef minion_accounts, CFStringRef user_account, CFDataRef user_password, CFErrorRef *error) { __block bool retval = SOSAccountAssertUserCredentialsAndUpdate(master_account, user_account, user_password, error); ProcessChangesForMasterAndMinions(changes, master_account, minion_accounts); - retval &= SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccountRef account) { + retval &= SOSArrayForEachAccount(minion_accounts, ^bool(SOSAccount* account) { CFReleaseNull(*error); return SOSAccountAssertUserCredentialsAndUpdate(account, user_account, user_password, error); }); @@ -144,17 +148,19 @@ static bool AssertAllCredentialsAndUpdate(CFMutableDictionaryRef changes, SOSAcc static void tests(void) { + NSError* ns_error = nil; CFErrorRef error = NULL; CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); CFStringRef cfaccount = CFSTR("test@test.org"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef master_account = CreateAccountForLocalChanges(CFSTR("master"), CFSTR("TestSource")); - CFArrayRef minion_accounts = CreateManyAccountsForLocalChanges(CFSTR("minion%d"), CFSTR("TestSource"), HOW_MANY_MINIONS); + SOSAccount* master_account = CreateAccountForLocalChanges(CFSTR("master"), CFSTR("TestSource")); + CFArrayRef minion_accounts = CreateManyAccountsForLocalChanges(CFSTR("minion"), CFSTR("TestSource"), HOW_MANY_MINIONS); ok(AssertAllCredentialsAndUpdate(changes, master_account, minion_accounts, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - + CFReleaseNull(cfpassword); + secLogEnable(); SOSAccountLogState(master_account); secLogDisable(); @@ -167,23 +173,22 @@ static void tests(void) SOSAccountLogViewState(master_account); secLogDisable(); - CFDataRef acctData = SOSAccountCopyEncodedData(master_account, kCFAllocatorDefault, &error); - diag("Account DER Size is %d for %d peers", CFDataGetLength(acctData), HOW_MANY_MINIONS+1); - CFReleaseNull(acctData); - CFReleaseNull(error); - - CFDataRef circleData = SOSCircleCopyEncodedData(master_account->trusted_circle, kCFAllocatorDefault, &error); - diag("Circle DER Size is %d for %d peers", CFDataGetLength(circleData), HOW_MANY_MINIONS+1); + NSData* acctData = [master_account encodedData:&ns_error]; + diag("Account DER Size is %lu for %d peers", (unsigned long)[acctData length], HOW_MANY_MINIONS+1); + ns_error = nil; + + SOSAccountTrustClassic* trust = master_account.trust; + CFDataRef circleData = SOSCircleCopyEncodedData(trust.trustedCircle, kCFAllocatorDefault, &error); + diag("Circle DER Size is %ld for %d peers", CFDataGetLength(circleData), HOW_MANY_MINIONS+1); CFReleaseNull(circleData); CFReleaseNull(error); - CFDataRef peerData = SOSPeerInfoCopyEncodedData(SOSAccountGetMyPeerInfo(master_account), kCFAllocatorDefault, &error); - diag("Peer DER Size is %d", CFDataGetLength(peerData)); + CFDataRef peerData = SOSPeerInfoCopyEncodedData(master_account.peerInfo, kCFAllocatorDefault, &error); + diag("Peer DER Size is %ld", CFDataGetLength(peerData)); CFReleaseNull(peerData); CFReleaseNull(error); CFReleaseNull(error); - CFReleaseNull(master_account); CFReleaseNull(minion_accounts); SOSTestCleanup(); diff --git a/OSX/sec/securityd/Regressions/secd-201-coders.c b/OSX/sec/securityd/Regressions/secd-201-coders.m similarity index 64% rename from OSX/sec/securityd/Regressions/secd-201-coders.c rename to OSX/sec/securityd/Regressions/secd-201-coders.m index c85ea555..1f386a25 100644 --- a/OSX/sec/securityd/Regressions/secd-201-coders.c +++ b/OSX/sec/securityd/Regressions/secd-201-coders.m @@ -40,8 +40,8 @@ #include #include #include -#include - +#include +#import #include #include @@ -59,27 +59,14 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 124; - -static void TestSOSEngineDoOnQueue(SOSEngineRef engine, dispatch_block_t action) -{ - dispatch_sync(engine->queue, action); -} - -static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account, CFStringRef peerID) { - SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(account->my_identity); +static bool SOSAccountIsThisPeerIDMe(SOSAccount* account, CFStringRef peerID) { + SOSAccountTrustClassic*trust = account.trust; + SOSPeerInfoRef mypi = trust.peerInfo; CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi); return myPeerID && CFEqualSafe(myPeerID, peerID); } -static bool TestSOSEngineDoTxnOnQueue(SOSEngineRef engine, CFErrorRef *error, void(^transaction)(SOSTransactionRef txn, bool *commit)) -{ - return SOSDataSourceWithCommitQueue(engine->dataSource, error, ^(SOSTransactionRef txn, bool *commit) { - TestSOSEngineDoOnQueue(engine, ^{ transaction(txn, commit); }); - }); -} - static void compareCoders(CFMutableDictionaryRef beforeCoders, CFMutableDictionaryRef afterCoderState) { CFDictionaryForEach(beforeCoders, ^(const void *key, const void *value) { @@ -90,48 +77,50 @@ static void compareCoders(CFMutableDictionaryRef beforeCoders, CFMutableDictiona }); } -static void ids_test_sync(SOSAccountRef alice_account, SOSAccountRef bob_account){ +static void ids_test_sync(SOSAccount* alice_account, SOSAccount* bob_account){ CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); __block bool SyncingCompletedOverIDS = false; __block CFErrorRef localError = NULL; __block bool done = false; + SOSAccountTrustClassic *aliceTrust = alice_account.trust; + SOSAccountTrustClassic *bobTrust = bob_account.trust; + do{ - SOSCircleForEachValidPeer(alice_account->trusted_circle, alice_account->user_public, ^(SOSPeerInfoRef peer) { + SOSCircleForEachValidPeer(aliceTrust.trustedCircle, alice_account.accountKey, ^(SOSPeerInfoRef peer) { if (!SOSAccountIsThisPeerIDMe(alice_account, SOSPeerInfoGetPeerID(peer))) { - if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(alice_account->my_identity), peer) && - SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(alice_account->my_identity), peer)){ + if(SOSPeerInfoShouldUseIDSTransport(aliceTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(aliceTrust.peerInfo, peer)){ secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); - SOSEngineRef alice_engine = SOSTransportMessageGetEngine(alice_account->ids_message_transport); + CFTypeRef alice_engine = [(SOSMessageIDSTest*)alice_account.ids_message_transport SOSTransportMessageGetEngine]; //testing loading and saving coders - ok(alice_engine->coders); - CFMutableDictionaryRef beforeCoders = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(alice_engine->coders), alice_engine->coders); + ok(TestSOSEngineGetCoders(alice_engine)); + CFMutableDictionaryRef beforeCoders = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(TestSOSEngineGetCoders(alice_engine)), TestSOSEngineGetCoders(alice_engine)); TestSOSEngineDoTxnOnQueue(alice_engine, &localError, ^(SOSTransactionRef txn, bool *commit) { - ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(alice_account->ids_message_transport), txn, &localError)); + ok(TestSOSEngineLoadCoders((SOSEngineRef)[(SOSMessageIDSTest*)alice_account.ids_message_transport SOSTransportMessageGetEngine], txn, &localError)); }); - ok(alice_engine->coders); + ok(TestSOSEngineGetCoders(alice_engine)); TestSOSEngineDoTxnOnQueue(alice_engine, &localError, ^(SOSTransactionRef txn, bool *commit) { ok(SOSTestEngineSaveCoders(alice_engine, txn, &localError)); }); - compareCoders(beforeCoders, alice_engine->coders); + compareCoders(beforeCoders, TestSOSEngineGetCoders(alice_engine)); //syncing with all peers - SyncingCompletedOverIDS = SOSTransportMessageSyncWithPeers(alice_account->ids_message_transport, ids, &localError); - + SyncingCompletedOverIDS = [(SOSMessageIDSTest*)alice_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)alice_account.ids_message_transport p:ids err:&localError]; //testing load after sync with all peers - CFMutableDictionaryRef codersAfterSyncBeforeLoad = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(alice_engine->coders), alice_engine->coders); + CFMutableDictionaryRef codersAfterSyncBeforeLoad = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(TestSOSEngineGetCoders(alice_engine)), TestSOSEngineGetCoders(alice_engine)); TestSOSEngineDoTxnOnQueue(alice_engine, &localError, ^(SOSTransactionRef txn, bool *commit) { - ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(alice_account->ids_message_transport), txn, &localError)); + ok(TestSOSEngineLoadCoders((SOSEngineRef)[(SOSMessageIDSTest*)alice_account.ids_message_transport SOSTransportMessageGetEngine], txn, &localError)); }); - compareCoders(codersAfterSyncBeforeLoad, alice_engine->coders); + compareCoders(codersAfterSyncBeforeLoad, TestSOSEngineGetCoders(alice_engine)); CFReleaseNull(codersAfterSyncBeforeLoad); CFReleaseNull(beforeCoders); @@ -142,48 +131,50 @@ static void ids_test_sync(SOSAccountRef alice_account, SOSAccountRef bob_account ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); - SOSCircleForEachValidPeer(bob_account->trusted_circle, bob_account->user_public, ^(SOSPeerInfoRef peer) { + SOSCircleForEachValidPeer(bobTrust.trustedCircle, bob_account.accountKey, ^(SOSPeerInfoRef peer) { if (!SOSAccountIsThisPeerIDMe(bob_account, SOSPeerInfoGetPeerID(peer))) { - if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), peer) && - SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), peer)){ + if(SOSPeerInfoShouldUseIDSTransport(bobTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(bobTrust.peerInfo, peer)){ secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); - SOSEngineRef bob_engine = SOSTransportMessageGetEngine(bob_account->ids_message_transport); + SOSEngineRef bob_engine = (SOSEngineRef)[(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageGetEngine]; //testing loading and saving coders - ok(bob_engine->coders); - CFMutableDictionaryRef beforeCoders = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(bob_engine->coders), bob_engine->coders); + ok(TestSOSEngineGetCoders(bob_engine)); + CFMutableDictionaryRef beforeCoders = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(TestSOSEngineGetCoders(bob_engine)), TestSOSEngineGetCoders(bob_engine)); TestSOSEngineDoTxnOnQueue(bob_engine, &localError, ^(SOSTransactionRef txn, bool *commit) { - ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(bob_account->ids_message_transport), txn, &localError)); + ok(TestSOSEngineLoadCoders((SOSEngineRef)[(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageGetEngine], txn, &localError)); }); - ok(bob_engine->coders); + ok((SOSEngineRef)TestSOSEngineGetCoders(bob_engine)); TestSOSEngineDoTxnOnQueue(bob_engine, &localError, ^(SOSTransactionRef txn, bool *commit) { ok(SOSTestEngineSaveCoders(bob_engine, txn, &localError)); }); - compareCoders(beforeCoders, bob_engine->coders); + compareCoders(beforeCoders, TestSOSEngineGetCoders(bob_engine)); - SyncingCompletedOverIDS &= SOSTransportMessageSyncWithPeers(bob_account->ids_message_transport, ids, &localError); + SyncingCompletedOverIDS &= [(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)bob_account.ids_message_transport p:ids err:&localError]; //testing load after sync with all peers - CFMutableDictionaryRef codersAfterSyncBeforeLoad = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(bob_engine->coders), bob_engine->coders); + CFMutableDictionaryRef codersAfterSyncBeforeLoad = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(TestSOSEngineGetCoders(bob_engine)), TestSOSEngineGetCoders(bob_engine)); TestSOSEngineDoTxnOnQueue(bob_engine, &localError, ^(SOSTransactionRef txn, bool *commit) { - ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(bob_account->ids_message_transport), txn, &localError)); + ok(TestSOSEngineLoadCoders((SOSEngineRef)[(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageGetEngine], txn, &localError)); }); - compareCoders(codersAfterSyncBeforeLoad, bob_engine->coders); + compareCoders(codersAfterSyncBeforeLoad, TestSOSEngineGetCoders(bob_engine)); CFReleaseNull(codersAfterSyncBeforeLoad); CFReleaseNull(beforeCoders); CFReleaseNull(ids); } } }); + if(!SyncingCompletedOverIDS) + return; - if(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(alice_account->ids_message_transport)) == 0 && CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(bob_account->ids_message_transport)) == 0){ + if(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) == 0 && CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)bob_account.ids_message_transport)) == 0){ done = true; break; } @@ -206,8 +197,8 @@ static void tests(void) CFStringRef cfaccount = CFSTR("test@test.org"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -217,6 +208,8 @@ static void tests(void) ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); CFReleaseNull(error); ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); + CFReleaseNull(cfpassword); + CFReleaseNull(error); ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); CFReleaseNull(cfwrong_password); @@ -256,7 +249,7 @@ static void tests(void) CFIndex version = 0; // Optionally prefix each peer with name to make them more unique. - CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,SOSAccountGetMyPeerID(alice_account), SOSAccountGetMyPeerID(bob_account), NULL); + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); CFSetRef views = SOSViewsCopyTestV2Default(); CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFStringRef deviceID; @@ -271,12 +264,12 @@ static void tests(void) SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); - if(CFEqualSafe(deviceID, SOSAccountGetMyPeerID(alice_account))){ - alice_account->factory = device->dsf; + if([alice_account.peerID isEqual: (__bridge id) deviceID]){ + alice_account.factory = device->dsf; SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); } else{ - bob_account->factory = device->dsf; + bob_account.factory = device->dsf; SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); } @@ -287,63 +280,70 @@ static void tests(void) SOSUnregisterAllTransportMessages(); CFArrayRemoveAllValues(message_transports); - - alice_account->ids_message_transport = (SOSTransportMessageRef)SOSTransportMessageIDSTestCreate(alice_account, CFSTR("Alice"), CFSTR("TestSource"), &error); - bob_account->ids_message_transport = (SOSTransportMessageRef)SOSTransportMessageIDSTestCreate(bob_account, CFSTR("Bob"), CFSTR("TestSource"), &error); - bool result = SOSAccountModifyCircle(alice_account, &error, ^bool(SOSCircleRef circle) { + SOSAccountTrustClassic *aliceTrust = alice_account.trust; + SOSAccountTrustClassic *bobTrust = bob_account.trust; + + alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:CFSTR("TestSource") err:&error]; + + bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:CFSTR("TestSource") err:&error]; + + bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^(SOSCircleRef circle) { + CFErrorRef localError = NULL; - SOSFullPeerInfoUpdateTransportType(alice_account->my_identity, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(alice_account->my_identity, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(alice_account->my_identity, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(alice_account->my_identity, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); - return SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(alice_account->my_identity), NULL); - }); + return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL); + }]; ok(result, "Alice account update circle with transport type"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - result = SOSAccountModifyCircle(bob_account, &error, ^bool(SOSCircleRef circle) { + result = [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^(SOSCircleRef circle) { CFErrorRef localError = NULL; - SOSFullPeerInfoUpdateTransportType(bob_account->my_identity, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(bob_account->my_identity, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(bob_account->my_identity, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(bob_account->my_identity, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); - return SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), NULL); - }); + return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL); + }]; ok(result, "Bob account update circle with transport type"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(alice_account)); - CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(bob_account)); + CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo); + CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo); ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS"); ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS"); CFReleaseNull(alice_transportType); CFReleaseNull(bob_accountTransportType); - SOSTransportMessageIDSTestSetName(alice_account->ids_message_transport, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSTestGetName(alice_account->ids_message_transport) != NULL, "retrieved getting account name"); + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); - SOSTransportMessageIDSTestSetName(bob_account->ids_message_transport, CFSTR("Bob Account")); - ok(SOSTransportMessageIDSTestGetName(bob_account->ids_message_transport) != NULL, "retrieved getting account name"); + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name"); ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("Alice"),&error), "Setting IDS device ID"); CFStringRef alice_dsid = SOSAccountCopyDeviceID(alice_account, &error); ok(CFEqualSafe(alice_dsid, CFSTR("Alice")), "Getting IDS device ID"); + CFReleaseNull(alice_dsid); ok(SOSAccountSetMyDSID_wTxn(bob_account, CFSTR("Bob"),&error), "Setting IDS device ID"); CFStringRef bob_dsid = SOSAccountCopyDeviceID(bob_account, &error); ok(CFEqualSafe(bob_dsid, CFSTR("Bob")), "Getting IDS device ID"); + CFReleaseNull(bob_dsid); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); @@ -352,20 +352,18 @@ static void tests(void) ids_test_sync(alice_account, bob_account); - SOSUnregisterAllTransportMessages(); - SOSUnregisterAllTransportCircles(); - SOSUnregisterAllTransportKeyParameters(); - CFArrayRemoveAllValues(key_transports); - CFArrayRemoveAllValues(circle_transports); - CFArrayRemoveAllValues(message_transports); - CFReleaseNull(alice_account); - CFReleaseNull(bob_account); + alice_account = nil; + bob_account = nil; + + SOSTestCleanup(); + + CFReleaseNull(changes); } int secd_201_coders(int argc, char *const *argv) { - plan_tests(kTestTestCount); + plan_tests(166); secd_test_setup_temp_keychain(__FUNCTION__, NULL); diff --git a/OSX/sec/securityd/Regressions/secd-202-recoverykey.m b/OSX/sec/securityd/Regressions/secd-202-recoverykey.m index b44533ac..e00d57af 100644 --- a/OSX/sec/securityd/Regressions/secd-202-recoverykey.m +++ b/OSX/sec/securityd/Regressions/secd-202-recoverykey.m @@ -30,7 +30,7 @@ static void testRecoveryKey(void) { SecRecoveryKey *recoveryKey = NULL; - recoveryKey = SecRKCreateRecoveryKey(@"AAAA-AAAA-AAAA-AAAA-AAAA-AAAA-AAGW"); + recoveryKey = SecRKCreateRecoveryKeyWithError(@"AAAA-AAAA-AAAA-AAAA-AAAA-AAAA-AAGW", NULL); ok(recoveryKey, "got recovery key"); NSData *publicKey = SecRKCopyBackupPublicKey(recoveryKey); diff --git a/OSX/sec/SOSCircle/Regressions/secd-210-keyinterest.m b/OSX/sec/securityd/Regressions/secd-210-keyinterest.m similarity index 95% rename from OSX/sec/SOSCircle/Regressions/secd-210-keyinterest.m rename to OSX/sec/securityd/Regressions/secd-210-keyinterest.m index a3d9989b..82e7c890 100644 --- a/OSX/sec/SOSCircle/Regressions/secd-210-keyinterest.m +++ b/OSX/sec/securityd/Regressions/secd-210-keyinterest.m @@ -1,5 +1,5 @@ // -// sc-160-keyinterest.m +// secd-210-keyinterest.m // Security // // Created by Mitch Adler on 10/31/16. @@ -62,11 +62,14 @@ } - (void) notifyListener { - if (self.listener) { + // Take a strong reference: + __strong __typeof(self.listener) listener = self.listener; + + if (listener) { if (self.locked) { - [self.listener locked]; + [listener locked]; } else { - [self.listener unlocked]; + [listener unlocked]; } } } diff --git a/OSX/sec/securityd/Regressions/secd-230-keybagtable.m b/OSX/sec/securityd/Regressions/secd-230-keybagtable.m new file mode 100644 index 00000000..afc16948 --- /dev/null +++ b/OSX/sec/securityd/Regressions/secd-230-keybagtable.m @@ -0,0 +1,253 @@ +/* + * 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 "secd_regressions.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#import "SecBackupKeybagEntry.h" + +#if 0 + + Add test for keybag table add SPI + Create an SPI to add a keybag to the keychain database (Keybag Table) + +// original secd_35_keychain_migrate_inet + +sudo defaults write /Library/Preferences/com.apple.security V10SchemaUpgradeTest -bool true +sudo defaults read /Library/Preferences/com.apple.security V10SchemaUpgradeTest + +#endif + +#if USE_KEYSTORE +#include + +#include "SecdTestKeychainUtilities.h" + +static const bool kTestCustomKeybag = false; +static const bool kTestLocalKeybag = false; + +void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); +CFArrayRef SecAccessGroupsGetCurrent(); + +#define kSecdTestCreateCustomKeybagTestCount 6 +#define kSecdTestLocalKeybagTestCount 1 +#define kSecdTestKeybagtableTestCount 5 +#define kSecdTestAddItemTestCount 2 + +#define DATA_ARG(x) (x) ? CFDataGetBytePtr((x)) : NULL, (x) ? (int)CFDataGetLength((x)) : 0 + +// copied from si-33-keychain-backup.c +static CFDataRef create_keybag(keybag_handle_t bag_type, CFDataRef password) +{ + keybag_handle_t handle = bad_keybag_handle; + + if (aks_create_bag(DATA_ARG(password), bag_type, &handle) == 0) { + void * keybag = NULL; + int keybag_size = 0; + if (aks_save_bag(handle, &keybag, &keybag_size) == 0) { + return CFDataCreate(kCFAllocatorDefault, keybag, keybag_size); + } + } + + return CFDataCreate(kCFAllocatorDefault, NULL, 0); +} + +static bool createCustomKeybag() { + /* custom keybag */ + keybag_handle_t keybag; + keybag_state_t state; + char *passcode="password"; + int passcode_len=(int)strlen(passcode); + const bool kTestLockedKeybag = false; + + ok(kIOReturnSuccess==aks_create_bag(passcode, passcode_len, kAppleKeyStoreDeviceBag, &keybag), "create keybag"); + ok(kIOReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(!(state&keybag_state_locked), "keybag unlocked"); + SecItemServerSetKeychainKeybag(keybag); + + if (kTestLockedKeybag) { + /* lock */ + ok(kIOReturnSuccess==aks_lock_bag(keybag), "lock keybag"); + ok(kIOReturnSuccess==aks_get_lock_state(keybag, &state), "get keybag state"); + ok(state&keybag_state_locked, "keybag locked"); + } + + return true; +} + +static int keychainTestEnvironment(const char *environmentName, dispatch_block_t do_in_reset, dispatch_block_t do_in_environment) { + // + // Setup phase + // + CFArrayRef old_ag = SecAccessGroupsGetCurrent(); + CFMutableArrayRef test_ag = CFArrayCreateMutableCopy(NULL, 0, old_ag); + CFArrayAppendValue(test_ag, CFSTR("test")); + SecAccessGroupsSetCurrent(test_ag); + + secd_test_setup_temp_keychain(environmentName, do_in_reset); + bool haveCustomKeybag = kTestCustomKeybag && createCustomKeybag(); + + // Perform tasks in the test keychain environment + if (do_in_environment) + do_in_environment(); + + // + // Cleanup phase + // + + // Reset keybag + if (haveCustomKeybag) + SecItemServerResetKeychainKeybag(); + + // Reset server accessgroups + SecAccessGroupsSetCurrent(old_ag); + CFReleaseSafe(test_ag); + // Reset custom $HOME + SetCustomHomePath(NULL); + SecKeychainDbReset(NULL); + return 0; +} + +static int addOneItemTest(NSString *account) { + /* Creating a password */ + const char *v_data = "test"; + CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); + + NSDictionary *item = @{ + (__bridge NSString *)kSecClass : (__bridge NSString *)kSecClassInternetPassword, + (__bridge NSString *)kSecAttrServer : @"members.spamcop.net", + (__bridge NSString *)kSecAttrAccount : account, // e.g. @"smith", + (__bridge NSString *)kSecAttrPort : @80, + (__bridge NSString *)kSecAttrProtocol : @"http", + (__bridge NSString *)kSecAttrAuthenticationType : @"dflt", + (__bridge NSString *)kSecValueData : (__bridge NSData *)pwdata + }; + + ok_status(SecItemAdd((CFDictionaryRef)item, NULL), "add internet password, while unlocked"); + CFReleaseSafe(pwdata); + return 0; +} + +static int localKeybagTest() { + const char *pass = "sup3rsekretpassc0de"; + CFDataRef password = CFDataCreate(NULL, (UInt8 *)pass, strlen(pass)); + CFDataRef keybag = create_keybag(kAppleKeyStoreAsymmetricBackupBag, password); + ok(keybag != NULL); + CFReleaseNull(keybag); + CFReleaseNull(password); + return 0; +} + +static int test_keybagtable() { + CFErrorRef error = NULL; + const char *pass = "sup3rsekretpassc0de"; + CFDataRef password = CFDataCreate(NULL, (UInt8 *)pass, strlen(pass)); + CFDataRef identifier = NULL; + CFURLRef pathinfo = NULL; + + ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); + CFReleaseNull(error); + + NSDictionary *deleteQuery = @{(__bridge NSString *)kSecAttrPublicKeyHash:(__bridge NSData *)identifier}; + ok(SecBackupKeybagDelete((__bridge CFDictionaryRef)deleteQuery, &error)); + + ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); + CFReleaseNull(error); + + ok(SecBackupKeybagAdd(password, &identifier, &pathinfo, &error)); + CFReleaseNull(error); + + NSDictionary *deleteAllQuery = @{(id)kSecMatchLimit: (id)kSecMatchLimitAll}; + ok(SecBackupKeybagDelete((__bridge CFDictionaryRef)deleteAllQuery, &error)); + + CFReleaseNull(identifier); + CFReleaseNull(pathinfo); + CFReleaseNull(password); + CFReleaseNull(error); + return 0; +} + +static void showHomeURL() { +#if DEBUG + CFURLRef homeURL = SecCopyHomeURL(); + NSLog(@"Home URL for test : %@", homeURL); + CFReleaseSafe(homeURL); +#endif +} + +int secd_230_keybagtable(int argc, char *const *argv) +{ + int testcount = kSecdTestSetupTestCount + kSecdTestKeybagtableTestCount + kSecdTestAddItemTestCount; + if (kTestLocalKeybag) + testcount += kSecdTestLocalKeybagTestCount; + if (kTestCustomKeybag) + testcount += kSecdTestCreateCustomKeybagTestCount; + plan_tests(testcount); + + dispatch_block_t run_tests = ^{ + showHomeURL(); + if (kTestLocalKeybag) + localKeybagTest(); + addOneItemTest(@"smith"); + test_keybagtable(); + addOneItemTest(@"jones"); + }; + + dispatch_block_t do_in_reset = NULL; + dispatch_block_t do_in_environment = run_tests; + + keychainTestEnvironment("secd_230_keybagtable", do_in_reset, do_in_environment); + + return 0; +} + +#else + +int secd_230_keybagtable(int argc, char *const *argv) +{ + plan_tests(1); + secLogDisable(); + + todo("Not yet working in simulator"); + + TODO: { + ok(false); + } + /* not implemented in simulator (no keybag) */ + return 0; +} +#endif diff --git a/OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.c b/OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.c rename to OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.m diff --git a/OSX/sec/securityd/Regressions/secd-31-keychain-bad.c b/OSX/sec/securityd/Regressions/secd-31-keychain-bad.m similarity index 93% rename from OSX/sec/securityd/Regressions/secd-31-keychain-bad.c rename to OSX/sec/securityd/Regressions/secd-31-keychain-bad.m index c5b2d582..bac3a4b5 100644 --- a/OSX/sec/securityd/Regressions/secd-31-keychain-bad.c +++ b/OSX/sec/securityd/Regressions/secd-31-keychain-bad.m @@ -69,10 +69,12 @@ static void tests(void) int fd; ok_unix(fd = open(keychain_path, O_RDWR | O_CREAT | O_TRUNC, 0644), "create keychain file"); - is(write(fd, keychain_data, sizeof(keychain_data)), - (ssize_t)sizeof(keychain_data), "write garbage to keychain file"); - ok_unix(close(fd), "close keychain file"); - + SKIP: { + skip("Cannot write to keychain file with invalid fd", 2, fd > -1); + is(write(fd, keychain_data, sizeof(keychain_data)), + (ssize_t)sizeof(keychain_data), "write garbage to keychain file"); + ok_unix(close(fd), "close keychain file"); + } }); CFReleaseSafe(keychain_path_cf); diff --git a/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.c b/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m similarity index 94% rename from OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.c rename to OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m index 343a83a7..3ff7543a 100644 --- a/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.c +++ b/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m @@ -66,9 +66,11 @@ int secd_31_keychain_unreadable(int argc, char *const *argv) int fd; ok_unix(fd = open(keychain_path, O_RDWR | O_CREAT | O_TRUNC, 0644), "create keychain file '%s'", keychain_path); - ok_unix(fchmod(fd, 0), " keychain file '%s'", keychain_path); - ok_unix(close(fd), "close keychain file '%s'", keychain_path); - + SKIP: { + skip("Cannot fchmod keychain file with invalid fd", 2, fd > -1); + ok_unix(fchmod(fd, 0), " keychain file '%s'", keychain_path); + ok_unix(close(fd), "close keychain file '%s'", keychain_path); + } }); CFReleaseSafe(keychain_path_cf); diff --git a/OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.c b/OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.c rename to OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.m diff --git a/OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m b/OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m index 0ff05b44..991f5a80 100644 --- a/OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m +++ b/OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m @@ -21,12 +21,6 @@ * @APPLE_LICENSE_HEADER_END@ */ -/* - * This is to fool os services to not provide the Keychain manager - * interface tht doens't work since we don't have unified headers - * between iOS and OS X. rdar://23405418/ - */ -#define __KEYCHAINCORE__ 1 #import #include @@ -100,7 +94,7 @@ static void test_item_add(void) { phase++; SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); CFDataRef acData = SecAccessControlCopyData(ac); CFRelease(ac); return acData; @@ -144,7 +138,6 @@ static void test_item_add(void) { CFRelease(valueData); CFRelease(oidData); } -static const int kItemAddTestCount = 31; static void test_item_query() { static const UInt8 oid[] = { 0x05, 0x06, 0x07, 0x08 }; @@ -223,7 +216,6 @@ static void test_item_query() { CFRelease(valueData2); CFRelease(oidData); } -static const int kItemQueryTestCount = 21; static void test_item_update() { static const UInt8 data[] = { 0x01, 0x02, 0x03, 0x04 }; @@ -252,7 +244,7 @@ static void test_item_update() { phase++; SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); CFDataRef acData = SecAccessControlCopyData(ac); CFRelease(ac); return acData; @@ -317,7 +309,6 @@ static void test_item_update() { CFRelease(attrs); CFRelease(valueData2); } -static const int kItemUpdateTestCount = 26; static void test_item_delete(void) { @@ -334,7 +325,7 @@ static void test_item_delete(void) { phase++; SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); CFDataRef acData = SecAccessControlCopyData(ac); CFRelease(ac); return acData; @@ -390,105 +381,147 @@ static void test_item_delete(void) { CFRelease(query); CFReleaseSafe(deleteError); } -#if LA_CONTEXT_IMPLEMENTED -static const int kItemDeleteTestCount = 15; -#else -static const int kItemDeleteTestCount = 14; -#endif - -static void test_key_generate(void) { +static void test_key_generate(int globalPersistence, int privatePersistence, int publicPersistence, + bool privateIsPersistent, bool publicIsPersistent) { __block int phase = 0; TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { - phase++; + phase |= 0x01; blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - phase++; - is(objectID, NULL); + id privateKey; + CFTypeRef keyClass = CFDictionaryGetValue(at, kSecAttrKeyClass) ?: kSecAttrKeyClassPrivate; + eq_cf(keyClass, kSecAttrKeyClassPrivate, "only private keys can be created on token"); + NSDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate }; + if (objectID != NULL) { + phase |= 0x20; + privateKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)objectID, (CFDictionaryRef)params, NULL)); + } else { + phase |= 0x02; + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, error)); + } + NSDictionary *privKeyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)privateKey)); CFDictionarySetValue(at, kSecClass, kSecClassKey); - SecKeyRef publicKey = NULL, privateKey = NULL; - CFMutableDictionaryRef params = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecAttrKeyType, kSecAttrKeyTypeEC, - kSecAttrKeySizeInBits, CFSTR("256"), - NULL); - ok_status(SecKeyGeneratePair(params, &publicKey, &privateKey)); - CFDictionaryRef privKeyAttrs = SecKeyCopyAttributeDictionary(privateKey); - CFRelease(privateKey); - CFRelease(publicKey); - CFRelease(params); - CFDataRef oid = CFRetainSafe(CFDictionaryGetValue(privKeyAttrs, kSecValueData)); - CFRelease(privKeyAttrs); - return oid; + CFDictionarySetValue(at, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom); + CFDictionarySetValue(at, kSecAttrKeySizeInBits, CFSTR("256")); + CFDictionarySetValue(at, kSecAttrKeyClass, kSecAttrKeyClassPrivate); + return CFBridgingRetain(privKeyAttrs[(id)kSecValueData]); }; blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { - phase++; + phase |= 0x04; SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); CFDataRef acData = SecAccessControlCopyData(ac); CFRelease(ac); return acData; }; blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) { - phase++; + phase |= 0x08; SecKeyRef privKey = SecKeyCreateECPrivateKey(NULL, CFDataGetBytePtr(objectID), CFDataGetLength(objectID), kSecKeyEncodingBytes); CFDataRef publicData; - ok_status(SecKeyCopyPublicBytes(privKey, &publicData)); + SecKeyCopyPublicBytes(privKey, &publicData); CFRelease(privKey); return publicData; }; blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) { - phase++; + phase |= 0x10; return kCFNull; }; }); - CFDictionaryRef prk_params = CFDictionaryCreateForCFTypes(NULL, - kSecAttrIsPermanent, kCFBooleanTrue, - NULL); - - CFMutableDictionaryRef params = CFDictionaryCreateMutableForCFTypesWith(NULL, - kSecAttrKeyType, kSecAttrKeyTypeEC, - kSecAttrKeySizeInBits, CFSTR("256"), - kSecAttrTokenID, CFSTR("tokenid"), - kSecPrivateKeyAttrs, prk_params, - NULL); - CFRelease(prk_params); + NSMutableDictionary *params = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC, + (id)kSecAttrKeySizeInBits: @"256", + (id)kSecAttrTokenID: @"tokenid", + }.mutableCopy; + if (globalPersistence >= 0) { + params[(id)kSecAttrIsPermanent] = globalPersistence ? @YES : @NO; + } + if (publicPersistence >= 0) { + params[(id)kSecPublicKeyAttrs] = @{ (id)kSecAttrIsPermanent: publicPersistence ? @YES : @NO }; + } + if (privatePersistence >= 0) { + params[(id)kSecPrivateKeyAttrs] = @{ (id)kSecAttrIsPermanent: privatePersistence ? @YES : @NO }; + } - SecKeyRef publicKey = NULL, privateKey = NULL; + NSError *error; phase = 0; - ok_status(SecKeyGeneratePair(params, &publicKey, &privateKey)); - is(phase, 6); - - CFDictionaryRef query = CFDictionaryCreateForCFTypes(NULL, - kSecValueRef, privateKey, - kSecReturnAttributes, kCFBooleanTrue, - kSecReturnRef, kCFBooleanTrue, - kSecReturnData, kCFBooleanTrue, - NULL); + id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + isnt(privateKey, nil, "failed to generate token key, error %@", error); + is(phase, privateIsPersistent ? 0x3f : 0x1f); + id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey)); + isnt(publicKey, nil, "failed to get public key from private key"); + + NSDictionary *query = @{ (id)kSecValueRef: privateKey, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnRef: @YES, + (id)kSecReturnData: @YES }; phase = 0; - CFDictionaryRef result = NULL, keyAttrs = NULL; - ok_status(SecItemCopyMatching(query, (CFTypeRef *)&result)); - is(phase, 3); - is(CFDictionaryGetValue(result, kSecValueData), NULL); - eq_cf(CFDictionaryGetValue(result, kSecAttrTokenID), CFSTR("tokenid")); - keyAttrs = SecKeyCopyAttributeDictionary((SecKeyRef)CFDictionaryGetValue(result, kSecValueRef)); - eq_cf(CFDictionaryGetValue(keyAttrs, kSecAttrApplicationLabel), CFDictionaryGetValue(result, kSecAttrApplicationLabel)); - CFAssignRetained(keyAttrs, SecKeyCopyAttributeDictionary(publicKey)); - eq_cf(CFDictionaryGetValue(keyAttrs, kSecAttrApplicationLabel), CFDictionaryGetValue(result, kSecAttrApplicationLabel)); + NSDictionary *result; + if (privateIsPersistent) { + ok_status(SecItemCopyMatching((CFDictionaryRef)query, (void *)&result), "persistent private key not found in kc"); + is(phase, 0x19); + is(result[(id)kSecValueData], nil); + eq_cf((__bridge CFTypeRef)result[(id)kSecAttrTokenID], @"tokenid"); + NSDictionary *keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)result[(id)kSecValueRef])); + eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); + keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)publicKey)); + eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); + } else { + is_status(SecItemCopyMatching((CFDictionaryRef)query, (void *)&result), errSecItemNotFound, "ephemeral private key found in kc"); + is(phase, 0x08); + + // Balancing test count from the branch above + ok(true); + ok(true); + ok(true); + ok(true); + } - CFRelease(result); - CFRelease(keyAttrs); - CFRelease(publicKey); - CFRelease(privateKey); + query = @{ (id)kSecValueRef: publicKey, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnRef: @YES, + (id)kSecReturnData: @YES }; + phase = 0; + result = nil; + if (publicIsPersistent) { + ok_status(SecItemCopyMatching((CFDictionaryRef)query, (void *)&result), "persistent public key not found in kc"); + NSDictionary *keyAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)publicKey)); + eq_cf((__bridge CFTypeRef)keyAttrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)result[(id)kSecAttrApplicationLabel]); + } else { + is_status(SecItemCopyMatching((CFDictionaryRef)query, (void *)&result), errSecItemNotFound, "ephemeral public key found in kc"); + + // Balancing test count from the branch above + ok(true); + } - CFRelease(query); - CFRelease(params); + // Get OID from the private key and try to create duplicate of the key using its OID and attributes. + NSDictionary *attrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)privateKey)); + NSData *oid = attrs[(id)kSecAttrTokenOID]; + ok(oid != nil, "private key attributes need OID"); + phase = 0; + id copyKey = CFBridgingRelease(SecKeyCreateWithData((CFDataRef)[NSData data], + (CFDictionaryRef)@{ (id)kSecAttrTokenID: @"tokenid", (id)kSecAttrTokenOID: oid }, + (void *)&error)); + ok(copyKey != nil, "copied key is created"); + is(phase, 0x21); + attrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)copyKey)); + is(phase, 0x29); + phase = 0; + eq_cf((__bridge CFTypeRef)attrs[(id)kSecClass], kSecClassKey); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeyClass], kSecAttrKeyClassPrivate); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeyType], kSecAttrKeyTypeECSECPrimeRandom); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrKeySizeInBits], CFSTR("256")); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], CFSTR("tokenid")); + id copyPublicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)copyKey)); + ok(copyPublicKey != nil); + is(phase, 0x08); + NSDictionary *pubAttrs = CFBridgingRelease(SecKeyCopyAttributes((SecKeyRef)copyPublicKey)); + eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrApplicationLabel], (__bridge CFTypeRef)pubAttrs[(id)kSecAttrApplicationLabel]); } -static const int kKeyGenerateTestCount = 14; static void test_key_sign(void) { @@ -515,7 +548,7 @@ static void test_key_sign(void) { phase++; SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); CFDataRef acData = SecAccessControlCopyData(ac); CFRelease(ac); return acData; @@ -616,12 +649,6 @@ static void test_key_sign(void) { CFRelease(privateKey); } -#if LA_CONTEXT_IMPLEMENTED -static const int kKeySignTestCount = 20; -#else -static const int kKeySignTestCount = 15; -#endif - static void test_key_generate_with_params(void) { const UInt8 data[] = "foo"; @@ -657,7 +684,6 @@ static void test_key_generate_with_params(void) { SecKeyRef publicKey = NULL, privateKey = NULL; phase = 0; - diag("This will produce an internal assert - on purpose"); is_status(SecKeyGeneratePair(params, &publicKey, &privateKey), errSecUserCanceled); is(phase, 2); @@ -666,7 +692,6 @@ static void test_key_generate_with_params(void) { CFRelease(params); CFRelease(cred_ref); } -static const int kKeyGenerateWithParamsTestCount = 5; static void test_error_codes(void) { @@ -694,7 +719,6 @@ static void test_error_codes(void) { CFRelease(attrs); } -static const int kErrorCodesCount = 3; static CFDataRef copy_certificate_data(const char *base64Cert) { @@ -920,15 +944,13 @@ static void test_propagate_token_items() CFReleaseNull(queryResult); CFRelease(query); } -static const int kPropagateCount = 66; static void test_identity_on_two_tokens() { CFStringRef cert3OID = CFSTR("oid1"); TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - is(objectID, NULL); - return (__bridge_retained CFDataRef)[[NSData alloc] initWithBase64EncodedString:@"BAcrF9iBupEeZOE+c73JBfkqsv8Q9rp1lTnZbKzmALf8yTR02310uGlZuUBVp4HOSiziO43dzFuegH0ywLhu+gtJj81RD8Rt+nLR6oTARkL+0l2/fzrIouleaEYpYmEp0A==" options:NSDataBase64DecodingIgnoreUnknownCharacters]; + return CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:@"BAcrF9iBupEeZOE+c73JBfkqsv8Q9rp1lTnZbKzmALf8yTR02310uGlZuUBVp4HOSiziO43dzFuegH0ywLhu+gtJj81RD8Rt+nLR6oTARkL+0l2/fzrIouleaEYpYmEp0A==" options:NSDataBase64DecodingIgnoreUnknownCharacters]); }; blocks->copyPublicKeyData = ^CFDataRef(CFDataRef objectID, CFErrorRef *error) { @@ -950,7 +972,7 @@ static void test_identity_on_two_tokens() { blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); CFDataRef acData = SecAccessControlCopyData(ac); CFRelease(ac); return acData; @@ -1003,13 +1025,11 @@ static void test_identity_on_two_tokens() { CFReleaseSafe(resultRef); } } -static const int kIdentityonTwoTokensCount = 20; static void test_ies(SecKeyRef privateKey, SecKeyAlgorithm algorithm) { TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) { blocks->createOrUpdateObject = ^CFDataRef(CFDataRef objectID, CFMutableDictionaryRef at, CFErrorRef *error) { - is(objectID, NULL); return CFBridgingRetain([@"oid" dataUsingEncoding:NSUTF8StringEncoding]); }; @@ -1027,7 +1047,7 @@ static void test_ies(SecKeyRef privateKey, SecKeyAlgorithm algorithm) { blocks->copyObjectAccessControl = ^CFDataRef(CFDataRef oid, CFErrorRef *error) { SecAccessControlRef ac = SecAccessControlCreate(NULL, NULL); SecAccessControlSetProtection(ac, kSecAttrAccessibleAlwaysPrivate, NULL); - SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL); + test_IsTrue(SecAccessControlAddConstraintForOperation(ac, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL)); CFDataRef acData = SecAccessControlCopyData(ac); CFRelease(ac); return acData; @@ -1093,7 +1113,6 @@ static void test_ies(SecKeyRef privateKey, SecKeyAlgorithm algorithm) { CFReleaseNull(tokenKey); CFReleaseNull(tokenPublicKey); } -static const int kIESCount = 4; static void test_ecies() { NSError *error; @@ -1104,7 +1123,6 @@ static void test_ecies() { CFReleaseNull(privateKey); } -static const int kECIESCount = kIESCount + 1; static void test_rsawrap() { NSError *error; @@ -1115,7 +1133,6 @@ static void test_rsawrap() { CFReleaseNull(privateKey); } -static const int kRSAWrapCount = kIESCount + 1; static void tests(void) { /* custom keychain dir */ @@ -1125,7 +1142,18 @@ static void tests(void) { test_item_query(); test_item_update(); test_item_delete(); - test_key_generate(); + + // params: int globalPersistence, int privatePersistence, int publicPersistence, bool privateIsPersistent, bool publicIsPersistent + test_key_generate(-1, -1, -1, true, false); + test_key_generate(0, -1, -1, false, false); + test_key_generate(1, -1, -1, true, true); + test_key_generate(-1, 0, 0, false, false); + test_key_generate(-1, 1, 0, true, false); + test_key_generate(-1, 0, 1, false, true); + test_key_generate(-1, 1, 1, true, true); + test_key_generate(0, 1, 1, true, true); + test_key_generate(1, 1, 1, true, true); + test_key_sign(); test_key_generate_with_params(); test_error_codes(); @@ -1136,19 +1164,7 @@ static void tests(void) { } int secd_33_keychain_ctk(int argc, char *const *argv) { - plan_tests(kItemAddTestCount + - kItemQueryTestCount + - kItemUpdateTestCount + - kItemDeleteTestCount + - kKeyGenerateTestCount + - kKeySignTestCount + - kKeyGenerateWithParamsTestCount + - kErrorCodesCount + - kPropagateCount + - kIdentityonTwoTokensCount + - kECIESCount + - kRSAWrapCount + - kSecdTestSetupTestCount); + plan_tests(484); tests(); return 0; diff --git a/OSX/sec/securityd/Regressions/secd-34-backup-der-parse.c b/OSX/sec/securityd/Regressions/secd-34-backup-der-parse.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-34-backup-der-parse.c rename to OSX/sec/securityd/Regressions/secd-34-backup-der-parse.m diff --git a/OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.c b/OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.c rename to OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.m diff --git a/OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m b/OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m new file mode 100644 index 00000000..72604f5c --- /dev/null +++ b/OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m @@ -0,0 +1,157 @@ +/* + * 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@ + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "secd_regressions.h" + +#include + +#include "SecdTestKeychainUtilities.h" + +void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); +CFArrayRef SecAccessGroupsGetCurrent(); + + +static void AddItem(NSDictionary *attr) +{ + NSMutableDictionary *mattr = [attr mutableCopy]; + mattr[(__bridge id)kSecValueData] = [NSData dataWithBytes:"foo" length:3]; + mattr[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlock; + ok_status(SecItemAdd((__bridge CFDictionaryRef)mattr, NULL)); +} + +int secd_37_pairing_initial_sync(int argc, char *const *argv) +{ + CFErrorRef error = NULL; + CFTypeRef stuff = NULL; + OSStatus res = 0; + + plan_tests(16); + + /* custom keychain dir */ + secd_test_setup_temp_keychain("secd_37_pairing_initial_sync", NULL); + + CFArrayRef currentACL = SecAccessGroupsGetCurrent(); + + NSMutableArray *newACL = [NSMutableArray arrayWithArray:(__bridge NSArray *)currentACL]; + [newACL addObjectsFromArray:@[ + @"com.apple.ProtectedCloudStorage", + ]]; + + SecAccessGroupsSetCurrent((__bridge CFArrayRef)newACL); + + + NSDictionary *pcsinetattrs = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", + (__bridge id)kSecAttrAccount : @"1", + (__bridge id)kSecAttrServer : @"current", + (__bridge id)kSecAttrType : @(0x10001), + (__bridge id)kSecAttrSynchronizable : @YES, + (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, + }; + NSDictionary *pcsinetattrsNotCurrent = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", + (__bridge id)kSecAttrAccount : @"1", + (__bridge id)kSecAttrServer : @"noncurrent", + (__bridge id)kSecAttrType : @(0x00001), + (__bridge id)kSecAttrSynchronizable : @YES, + (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, + }; + NSDictionary *pcsgenpattrs = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, + (__bridge id)kSecAttrAccessGroup : @"com.apple.ProtectedCloudStorage", + (__bridge id)kSecAttrAccount : @"2", + (__bridge id)kSecAttrSynchronizable : @YES, + (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, + }; + NSDictionary *ckksattrs = @{ + (__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword, + (__bridge id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (__bridge id)kSecAttrAccount : @"2", + (__bridge id)kSecAttrSynchronizable : @YES, + (__bridge id)kSecAttrSyncViewHint : (__bridge id)kSecAttrViewHintPCSMasterKey, + }; + AddItem(pcsinetattrs); + AddItem(pcsinetattrsNotCurrent); + AddItem(pcsgenpattrs); + AddItem(ckksattrs); + + CFArrayRef items = _SecServerCopyInitialSyncCredentials(SecServerInitialSyncCredentialFlagTLK | SecServerInitialSyncCredentialFlagPCS, &error); + ok(items, "_SecServerCopyInitialSyncCredentials: %@", error); + CFReleaseNull(error); + + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrsNotCurrent, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsgenpattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)ckksattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + + + ok(_SecItemDeleteAll(&error), "SecItemServerDeleteAll: %@", error); + CFReleaseNull(error); + + ok(_SecServerImportInitialSyncCredentials(items, &error), "_SecServerImportInitialSyncCredentials: %@", error); + CFReleaseNull(error); + CFReleaseNull(items); + + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + is_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsinetattrsNotCurrent, &stuff)), errSecItemNotFound, + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)pcsgenpattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + ok_status((res = SecItemCopyMatching((__bridge CFDictionaryRef)ckksattrs, &stuff)), + "SecItemCopyMatching: %d", (int)res); + CFReleaseNull(stuff); + + SecAccessGroupsSetCurrent(currentACL); + + + return 0; +} diff --git a/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.c b/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m similarity index 97% rename from OSX/sec/securityd/Regressions/secd-40-cc-gestalt.c rename to OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m index 52bb9b09..8278bf8c 100644 --- a/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.c +++ b/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m @@ -24,7 +24,7 @@ #include - +#include #include "secd_regressions.h" static int kTestTestCount = 1; diff --git a/OSX/sec/securityd/Regressions/secd-49-manifests.c b/OSX/sec/securityd/Regressions/secd-49-manifests.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-49-manifests.c rename to OSX/sec/securityd/Regressions/secd-49-manifests.m diff --git a/OSX/sec/securityd/Regressions/secd-50-account.c b/OSX/sec/securityd/Regressions/secd-50-account.m similarity index 66% rename from OSX/sec/securityd/Regressions/secd-50-account.c rename to OSX/sec/securityd/Regressions/secd-50-account.m index dda4cc6d..66d3e631 100644 --- a/OSX/sec/securityd/Regressions/secd-50-account.c +++ b/OSX/sec/securityd/Regressions/secd-50-account.m @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -46,7 +48,8 @@ static int kTestTestCount = 9 + kSecdTestSetupTestCount; static void tests(void) { - CFErrorRef error = NULL; + NSError* error = nil; + CFErrorRef cfError = NULL; CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); CFStringRef cfaccount = CFSTR("test@test.org"); @@ -54,49 +57,53 @@ static void tests(void) SOSDataSourceRef test_source = SOSTestDataSourceCreate(); SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - SOSAccountRef account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); + SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); - ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); + ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &cfError), "Credential setting (%@)", cfError); + CFReleaseNull(cfError); CFReleaseNull(cfpassword); ok(NULL != account, "Created"); - size_t size = SOSAccountGetDEREncodedSize(account, &error); - CFReleaseNull(error); + size_t size = [account.trust getDEREncodedSize:account err:&error]; + + error = nil; uint8_t buffer[size]; - uint8_t* start = SOSAccountEncodeToDER(account, &error, buffer, buffer + sizeof(buffer)); - CFReleaseNull(error); + + uint8_t* start = [account.trust encodeToDER:account err:&error start:buffer end:buffer + sizeof(buffer)]; + error = nil; ok(start, "successful encoding"); ok(start == buffer, "Used whole buffer"); const uint8_t *der = buffer; - SOSAccountRef inflated = SOSAccountCreateFromDER(kCFAllocatorDefault, test_factory, - &error, &der, buffer + sizeof(buffer)); - - SOSAccountEnsureFactoryCirclesTest(inflated, CFSTR("Test Device")); - ok(inflated, "inflated"); - ok(CFEqual(inflated, account), "Compares"); - CFReleaseNull(inflated); - + SOSAccount* inflated = [SOSAccount accountFromDER:&der end:buffer + sizeof(buffer) + factory:test_factory error:&error]; + + ok(inflated, "inflated %@", error); + ok([inflated isEqual:account], "Compares"); + + error = nil; + CFDictionaryRef new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("New Device")); - ok(SOSAccountResetToOffering_wTxn(account, &error), "Reset to Offering (%@)", error); - CFReleaseNull(error); - is(SOSAccountGetCircleStatus(account, &error), kSOSCCInCircle, "Was in Circle (%@)", error); - CFReleaseNull(error); + ok(SOSAccountResetToOffering_wTxn(account, &cfError), "Reset to Offering (%@)", error); + CFReleaseNull(cfError); - SOSAccountUpdateGestalt(account, new_gestalt); + is([account getCircleStatus:&cfError], kSOSCCInCircle, "Was in Circle (%@)", error); + CFReleaseNull(cfError); - is(SOSAccountGetCircleStatus(account, &error), kSOSCCInCircle, "Still in Circle (%@)", error); - CFReleaseNull(error); + [account.trust updateGestalt:account newGestalt:new_gestalt]; + is([account getCircleStatus:&cfError], kSOSCCInCircle, "Still in Circle (%@)", error); + CFReleaseNull(cfError); CFReleaseNull(new_gestalt); - CFReleaseNull(account); - + SOSDataSourceFactoryRelease(test_factory); SOSDataSourceRelease(test_source, NULL); - + + account = nil; + inflated = nil; + SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-50-message.c b/OSX/sec/securityd/Regressions/secd-50-message.m similarity index 96% rename from OSX/sec/securityd/Regressions/secd-50-message.c rename to OSX/sec/securityd/Regressions/secd-50-message.m index 9a9bc999..14d92407 100644 --- a/OSX/sec/securityd/Regressions/secd-50-message.c +++ b/OSX/sec/securityd/Regressions/secd-50-message.m @@ -32,8 +32,6 @@ #include #include -static int kTestTestCount = 68; - static void testNullMessage(uint64_t msgid) { SOSMessageRef sentMessage = NULL; @@ -238,18 +236,11 @@ static void tests(void) testNullMessage(++msgid); // v2 testFlaggedMessage(test_directive, test_reason, ++msgid, 0x865); testFlaggedMessage(test_directive, test_reason, ++msgid, 0xdeadbeef); - TODO: { - todo("V2 doesn't work"); - testDeltaManifestMessage(test_directive, test_reason, 0); - testDeltaManifestMessage(test_directive, test_reason, ++msgid); - testObjectsMessage(test_directive, test_reason, 0); - testObjectsMessage(test_directive, test_reason, ++msgid); - } } int secd_50_message(int argc, char *const *argv) { - plan_tests(kTestTestCount); + plan_tests(26); tests(); diff --git a/OSX/sec/securityd/Regressions/secd-51-account-inflate.c b/OSX/sec/securityd/Regressions/secd-51-account-inflate.m similarity index 97% rename from OSX/sec/securityd/Regressions/secd-51-account-inflate.c rename to OSX/sec/securityd/Regressions/secd-51-account-inflate.m index e5f9f016..d9214a47 100644 --- a/OSX/sec/securityd/Regressions/secd-51-account-inflate.c +++ b/OSX/sec/securityd/Regressions/secd-51-account-inflate.m @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -208,12 +209,12 @@ static void test_v6(void) { const uint8_t *der_p = v6_der; - SOSAccountRef convertedAccount = SOSAccountCreateFromDER(kCFAllocatorDefault, ak_factory, &error, &der_p, v6_der + sizeof(v6_der)); + SOSAccount* convertedAccount = SOSAccountCreateFromDER(kCFAllocatorDefault, ak_factory, &error, &der_p, v6_der + sizeof(v6_der)); ok(convertedAccount, "inflate v6 account (%@)", error); CFReleaseSafe(error); - is(kSOSCCInCircle, SOSAccountGetCircleStatus(convertedAccount, &error), "in the circle"); + is(kSOSCCInCircle, [convertedAccount.trust getCircleStatus:&error], "in the circle"); CFReleaseSafe(convertedAccount); ak_factory->release(ak_factory); @@ -233,7 +234,7 @@ static void tests(void) SOSDataSourceRef test_source = SOSTestDataSourceCreate(); SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - SOSAccountRef account = CreateAccountForLocalChanges(CFSTR("Test Device"), CFSTR("TestType")); + SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"), CFSTR("TestType")); ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); CFReleaseNull(error); CFReleaseNull(cfpassword); @@ -244,7 +245,6 @@ static void tests(void) CFReleaseNull(error); ok(testAccountPersistence(account), "Test Account->DER->Account Equivalence"); - CFReleaseNull(account); SOSTestCleanup(); diff --git a/OSX/sec/securityd/Regressions/secd-52-account-changed.c b/OSX/sec/securityd/Regressions/secd-52-account-changed.m similarity index 78% rename from OSX/sec/securityd/Regressions/secd-52-account-changed.c rename to OSX/sec/securityd/Regressions/secd-52-account-changed.m index 791558f9..838f859d 100644 --- a/OSX/sec/securityd/Regressions/secd-52-account-changed.c +++ b/OSX/sec/securityd/Regressions/secd-52-account-changed.m @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,7 @@ #include "SecdTestKeychainUtilities.h" #include "SOSAccountTesting.h" -static int kTestTestCount = 157; +static int kTestTestCount = 152; static void tests(void) { @@ -55,9 +56,9 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges( CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges( CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -66,7 +67,7 @@ static void tests(void) CFDictionaryRef new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("New Device")); - ok (SOSAccountUpdateGestalt(bob_account, new_gestalt), "did we send a null circle?"); + ok ([bob_account.trust updateGestalt:bob_account newGestalt:new_gestalt], "did we send a null circle?"); CFReleaseNull(new_gestalt); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "nothing published"); @@ -115,44 +116,42 @@ static void tests(void) /* ==================== Three Accounts in circle =============================================*/ InjectChangeToMulti(changes, CFSTR("^AccountChanged"), CFSTR("none"), alice_account, bob_account, carol_account, NULL); - + SOSAccountInflateTestTransportsForCircle(alice_account, CFSTR("TestSource"), CFSTR("Alice"), &error); + SOSAccountInflateTestTransportsForCircle(bob_account, CFSTR("TestSource"), CFSTR("Bob"), &error); + SOSAccountInflateTestTransportsForCircle(carol_account, CFSTR("TestSource"), CFSTR("Carol"), &error); + SOSTestRestoreAccountState(alice_account, alice_devstate); SOSTestRestoreAccountState(bob_account, bob_devstate); SOSTestRestoreAccountState(carol_account, carol_devstate); - CFReleaseNull(alice_devstate); - CFReleaseNull(bob_devstate); - CFReleaseNull(carol_devstate); + is([alice_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); + CFReleaseNull(error); + is([bob_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); + CFReleaseNull(error); + is([carol_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); + CFReleaseNull(error); - SOSAccountEnsureFactoryCirclesTest(alice_account, CFSTR("Alice")); - SOSAccountEnsureFactoryCirclesTest(bob_account, CFSTR("Bob")); - SOSAccountEnsureFactoryCirclesTest(carol_account, CFSTR("Carol")); - - is(SOSAccountGetCircleStatus(alice_account, &error), kSOSCCError, "Account reset - no user keys - error"); - is(SOSAccountGetCircleStatus(bob_account, &error), kSOSCCError, "Account reset - no user keys - error"); - is(SOSAccountGetCircleStatus(carol_account, &error), kSOSCCError, "Account reset - no user keys - error"); - CFDataRef cfpassword2 = CFDataCreate(NULL, (uint8_t *) "ooFooFooF", 10); CFStringRef cfaccount2 = CFSTR("test2@test.org"); - + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); CFReleaseNull(error); - is(SOSAccountGetCircleStatus(alice_account, &error), kSOSCCCircleAbsent, "Account reset - circle is absent"); - is(SOSAccountGetCircleStatus(bob_account, &error), kSOSCCError, "Account reset - no user keys - error"); + is([alice_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); + is([bob_account getCircleStatus:&error], kSOSCCError, "Account reset - no user keys - error"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); CFReleaseNull(error); - + ok(SOSAccountAssertUserCredentialsAndUpdate(carol_account, cfaccount2, cfpassword2, &error), "Credential setting (%@)", error); CFReleaseNull(error); - + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 1, "updates"); - is(SOSAccountGetCircleStatus(bob_account, &error), kSOSCCCircleAbsent, "Account reset - circle is absent"); - is(SOSAccountGetCircleStatus(carol_account, &error), kSOSCCCircleAbsent, "Account reset - circle is absent"); + is([bob_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); + is([carol_account getCircleStatus:&error], kSOSCCCircleAbsent, "Account reset - circle is absent"); // Now everyone is playing the same account. /* ==================== Three Accounts setup =============================================*/ @@ -163,9 +162,9 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - is(SOSAccountGetCircleStatus(alice_account, &error), kSOSCCInCircle, "Alice is in circle"); - is(SOSAccountGetCircleStatus(bob_account, &error), kSOSCCNotInCircle, "Bob is not in circle"); - is(SOSAccountGetCircleStatus(carol_account, &error), kSOSCCNotInCircle, "Carol is not in circle"); + is([alice_account getCircleStatus:&error], kSOSCCInCircle, "Alice is in circle"); + is([bob_account getCircleStatus:&error], kSOSCCNotInCircle, "Bob is not in circle"); + is([carol_account getCircleStatus:&error], kSOSCCNotInCircle, "Carol is not in circle"); ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); CFReleaseNull(error); @@ -177,7 +176,7 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); - is(SOSAccountGetCircleStatus(carol_account, &error), kSOSCCRequestPending, "Carol has a pending request"); + is([carol_account getCircleStatus:&error], kSOSCCRequestPending, "Carol has a pending request"); { CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); @@ -196,9 +195,10 @@ static void tests(void) CFReleaseSafe(cfpassword2); CFReleaseNull(changes); - CFReleaseNull(alice_account); - CFReleaseNull(bob_account); - CFReleaseNull(carol_account); + alice_account = nil; + bob_account = nil; + carol_account = nil; + SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.c b/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m similarity index 76% rename from OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.c rename to OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m index c4b3820f..2368bba2 100644 --- a/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.c +++ b/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -51,7 +52,7 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 81; +static int kTestTestCount = 79; static void tests(void) { @@ -61,10 +62,11 @@ static void tests(void) CFStringRef cfaccount = CFSTR("test@test.org"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); - + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); + + SOSAccountTrustClassic *carolTrust = carol_account.trust; ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); // Bob wins writing at this point, feed the changes back to alice. @@ -108,7 +110,7 @@ static void tests(void) //bob now goes def while Alice does some stuff. - ok(SOSAccountLeaveCircle(alice_account, &error), "ALICE LEAVES THE CIRCLE (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "ALICE LEAVES THE CIRCLE (%@)", error); ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Alice resets to offering again (%@)", error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); @@ -124,22 +126,25 @@ static void tests(void) int64_t valuePtr = 0; CFNumberRef gencount = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &valuePtr); - SOSCircleSetGeneration(carol_account->trusted_circle, gencount); + + SOSCircleSetGeneration(carolTrust.trustedCircle, gencount); - SecKeyRef user_privkey = SOSUserKeygen(cfpassword, carol_account->user_key_parameters, &error); - CFNumberRef genCountTest = SOSCircleGetGeneration(carol_account->trusted_circle); + SecKeyRef user_privkey = SOSUserKeygen(cfpassword, (__bridge CFDataRef)(carol_account.accountKeyDerivationParamters), &error); + CFNumberRef genCountTest = SOSCircleGetGeneration(carolTrust.trustedCircle); CFIndex testPtr; CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr); ok(testPtr== 0); - SOSCircleSignOldStyleResetToOfferingCircle(carol_account->trusted_circle, carol_account->my_identity, user_privkey, &error); - SOSTransportCircleTestRemovePendingChange(carol_account->circle_transport, SOSCircleGetName(carol_account->trusted_circle), NULL); - CFDataRef circle_data = SOSCircleCopyEncodedData(carol_account->trusted_circle, kCFAllocatorDefault, &error); + SOSCircleSignOldStyleResetToOfferingCircle(carolTrust.trustedCircle, carolTrust.fullPeerInfo, user_privkey, &error); + + SOSTransportCircleTestRemovePendingChange((SOSCircleStorageTransportTest*)carol_account.circle_transport, SOSCircleGetName(carolTrust.trustedCircle), NULL); + CFDataRef circle_data = SOSCircleCopyEncodedData(carolTrust.trustedCircle, kCFAllocatorDefault, &error); if (circle_data) { - SOSTransportCirclePostCircle(carol_account->circle_transport, SOSCircleGetName(carol_account->trusted_circle), circle_data, &error); + [carol_account.circle_transport postCircle:SOSCircleGetName(carolTrust.trustedCircle) circleData:circle_data err:&error]; } + CFReleaseNull(circle_data); - genCountTest = SOSCircleGetGeneration(carol_account->trusted_circle); + genCountTest = SOSCircleGetGeneration(carolTrust.trustedCircle); CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr); ok(testPtr== 0); @@ -151,14 +156,16 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, carol_account, alice_account, bob_account, NULL), 2, "updates"); - ok(kSOSCCNotInCircle == SOSAccountGetCircleStatus(alice_account, &error), "alice is not in the account (%@)", error); - ok(kSOSCCNotInCircle == SOSAccountGetCircleStatus(bob_account, &error), "bob is not in the account (%@)", error); - ok(kSOSCCInCircle == SOSAccountGetCircleStatus(carol_account, &error), "carol is in the account (%@)", error); + 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); CFReleaseNull(gencount); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); CFReleaseNull(cfpassword); + alice_account = nil; + bob_account = nil; + carol_account = nil; + SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-55-account-circle.c b/OSX/sec/securityd/Regressions/secd-55-account-circle.m similarity index 89% rename from OSX/sec/securityd/Regressions/secd-55-account-circle.c rename to OSX/sec/securityd/Regressions/secd-55-account-circle.m index fb13f9f4..da395b8e 100644 --- a/OSX/sec/securityd/Regressions/secd-55-account-circle.c +++ b/OSX/sec/securityd/Regressions/secd-55-account-circle.m @@ -34,6 +34,8 @@ #include #include #include +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h" #include #include @@ -51,7 +53,7 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 326; +static int kTestTestCount = 324; static void tests(void) { @@ -61,9 +63,9 @@ static void tests(void) CFStringRef cfaccount = CFSTR("test@test.org"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -112,7 +114,7 @@ static void tests(void) CFDictionaryRef alice_new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice, but different")); - ok(SOSAccountUpdateGestalt(alice_account, alice_new_gestalt), "Update gestalt %@ (%@)", alice_account, error); + ok([alice_account.trust updateGestalt:alice_account newGestalt:alice_new_gestalt], "Update gestalt %@ (%@)", alice_account, error); SOSAccountUpdateTestTransports(alice_account, alice_new_gestalt); CFReleaseNull(alice_new_gestalt); @@ -120,7 +122,7 @@ static void tests(void) accounts_agree("Alice's name changed", bob_account, alice_account); - ok(SOSAccountLeaveCircle(alice_account, &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); @@ -150,7 +152,7 @@ static void tests(void) accounts_agree("Alice accepts' Bob", bob_account, alice_account); - ok(SOSAccountLeaveCircle(alice_account, &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); CFReleaseNull(error); @@ -179,7 +181,7 @@ static void tests(void) // // - ok(SOSAccountLeaveCircle(alice_account, &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); FeedChangesTo(changes, bob_account); // Bob sees Alice leaving and rejoining FeedChangesTo(changes, alice_account); // Alice sees bob concurring @@ -203,7 +205,7 @@ static void tests(void) CFMutableDictionaryRef bobAcceptanceChanges = ExtractPendingChanges(changes); // Alice re-applies without seeing that she was accepted. - ok(SOSAccountLeaveCircles(alice_account, &error), "Alice Leaves again (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves again (%@)", error); CFReleaseNull(error); ok(SOSAccountJoinCircles(alice_account, &error), "Alice re-applies (%@)", error); CFReleaseNull(error); @@ -224,7 +226,7 @@ static void tests(void) // We want Alice to leave circle while an Applicant on a full concordance signed circle with old-Alice as an Alum and Bob a peer. // ZZZ - ok(SOSAccountLeaveCircle(alice_account, &error), "Alice leaves once more (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice leaves once more (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "updates"); @@ -233,12 +235,12 @@ static void tests(void) ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); CFReleaseNull(error); - ok(SOSAccountLeaveCircle(alice_account, &error), "Alice leaves while applying (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice leaves while applying (%@)", error); FeedChangesTo(changes, bob_account); // Bob sees Alice become an Alum. CFReleaseNull(error); - is(SOSAccountGetCircleStatus(alice_account, &error), kSOSCCNotInCircle, "Alice isn't applying any more"); + is([alice_account getCircleStatus:&error], kSOSCCNotInCircle, "Alice isn't applying any more"); accounts_agree("Alice leaves & some fancy concordance stuff happens", bob_account, alice_account); ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Alice re-applies (%@)", error); @@ -318,26 +320,26 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 2, "carol request"); CFArrayRef peers_to_remove_array = CFArrayCreateForCFTypes(kCFAllocatorDefault, - SOSAccountGetMyPeerInfo(bob_account), - SOSAccountGetMyPeerInfo(carol_account), + bob_account.peerInfo, + carol_account.peerInfo, NULL); ok(SOSAccountRemovePeersFromCircle(bob_account, peers_to_remove_array, NULL)); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "Remove peers"); - ok(SOSAccountIsInCircle(alice_account, NULL), "Alice still here"); - ok(!SOSAccountIsInCircle(bob_account, NULL), "Bob not in circle"); + ok([alice_account.trust isInCircle:&error], "Alice still here"); + ok(![bob_account.trust isInCircle:&error], "Bob not in circle"); // Carol's not in circle, but reapplied, as she's persistent until positive rejection. - ok(!SOSAccountIsInCircle(carol_account, NULL), "carol not in circle"); + ok(![carol_account.trust isInCircle:NULL], "carol not in circle"); CFReleaseNull(peers_to_remove_array); CFReleaseNull(alice_new_gestalt); + alice_account = nil; + bob_account = nil; + carol_account = nil; - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carol_account); SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.c b/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.c deleted file mode 100644 index 63aa17ee..00000000 --- a/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2012-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 -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 11; - -static void tests(void) -{ - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - CFStringRef data_name = CFSTR("TestSource"); - CFStringRef circle_key_name = SOSCircleKeyCreateWithName(data_name, NULL); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_name); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_name); - SOSAccountRef carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), data_name); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - FillAllChanges(changes); - FeedChangesToMulti(changes, alice_account, carol_account, NULL); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - - ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); - CFReleaseNull(cfwrong_password); - is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); - CFReleaseNull(error); - - CFDataRef incompatibleDER = SOSCircleCreateIncompatibleCircleDER(&error); - - InjectChangeToMulti(changes, circle_key_name, incompatibleDER, alice_account, NULL); - CFReleaseNull(circle_key_name); - CFReleaseNull(incompatibleDER); - - is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - -#if 0 - is(SOSAccountGetCircleStatus(alice_account, &error), kSOSCCError, "Is in circle"); - CFReleaseNull(error); - -//#if 0 - ok(SOSAccountResetToOffering(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - FillChanges(changes, CFSTR("Alice")); - FeedChangesTo(changes, bob_account, transport_bob); - - ok(SOSAccountJoinCircles(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - FeedChangesTo(changes, alice_account, transport_alice); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - FillChanges(changes, CFSTR("Alice")); - FeedChangesTo(changes, bob_account, transport_bob); // Bob sees he's accepted - - FillChanges(changes, CFSTR("Bob")); - FeedChangesTo(changes, alice_account, transport_alice); // Alice sees bob-concurring - - ok(CFDictionaryGetCount(changes) == 0, "We converged. (%@)", changes); - - FillChanges(changes, CFSTR("Alice")); - accounts_agree("bob&alice pair", bob_account, alice_account); - - CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); - CFReleaseNull(peers); - - CFDictionaryRef alice_new_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice, but different")); - - ok(SOSAccountUpdateGestalt(alice_account, alice_new_gestalt), "Update gestalt %@ (%@)", alice_account, error); - CFReleaseNull(alice_new_gestalt); - - FillChanges(changes, CFSTR("Alice")); - FeedChangesTo(changes, bob_account, transport_bob); // Bob sees alice change her name. - - FillChanges(changes, CFSTR("Bob")); - FeedChangesTo(changes, alice_account, transport_alice); // Alice sees the fallout. - - accounts_agree("Alice's name changed", bob_account, alice_account); - - ok(SOSAccountLeaveCircles(alice_account, &error), "Alice Leaves (%@)", error); - CFReleaseNull(error); - - FillChanges(changes, CFSTR("Alice")); - FeedChangesTo(changes, bob_account, transport_bob); // Bob sees alice bail. - - FillChanges(changes, CFSTR("Bob")); - FeedChangesTo(changes, alice_account), transport_alice; // Alice sees the fallout. - - FillChanges(changes, CFSTR("Alice")); - FillChanges(changes, CFSTR("Bob")); - accounts_agree("Alice bails", bob_account, alice_account); - - peers = SOSAccountCopyPeers(alice_account, &error); - ok(peers && CFArrayGetCount(peers) == 1, "See one peer %@ (%@)", peers, error); - CFReleaseNull(peers); - - ok(SOSAccountJoinCircles(alice_account, &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - FillChanges(changes, CFSTR("Alice")); - FeedChangesTo(changes, bob_account, transport_bob); - - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - FillChanges(changes, CFSTR("Bob")); - FeedChangesTo(changes, alice_account, transport_alice); // Alice sees bob accepting - - FillChanges(changes, CFSTR("Alice")); - FeedChangesTo(changes, bob_account, transport_bob); // Bob sees Alice concurring - - accounts_agree("Alice accepts' Bob", bob_account, alice_account); - - ok(SOSAccountLeaveCircles(alice_account, &error), "Alice Leaves (%@)", error); - CFReleaseNull(error); - ok(SOSAccountJoinCircles(alice_account, &error), "Alice re-applies (%@)", error); - CFReleaseNull(error); - - FillChanges(changes, CFSTR("Alice")); - FeedChangesTo(changes, bob_account, transport_bob); // Bob sees Alice leaving and rejoining - FillChanges(changes, CFSTR("Bob")); - FeedChangesTo(changes, alice_account, transport_alice); // Alice sees bob concurring - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - FillChanges(changes, CFSTR("Bob")); - FeedChangesTo(changes, alice_account, transport_alice); // Alice sees bob accepting - FillChanges(changes, CFSTR("Alice")); - FeedChangesTo(changes, bob_account, transport_bob); // Bob sees Alice concurring - - accounts_agree("Bob accepts Alice", bob_account, alice_account); - - - CFReleaseNull(alice_new_gestalt); -#endif - - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carol_account); - - SOSTestCleanup(); -} - -int secd_55_account_incompatibility(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m b/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m new file mode 100644 index 00000000..d4177ade --- /dev/null +++ b/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012-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 +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "secd_regressions.h" +#include "SOSTestDataSource.h" + +#include "SOSRegressionUtilities.h" +#include +#include + +#include + +#include "SOSAccountTesting.h" + +#include "SecdTestKeychainUtilities.h" + +static int kTestTestCount = 10; + +static void tests(void) +{ + CFErrorRef error = NULL; + CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); + CFDataRef cfwrong_password = CFDataCreate(NULL, (uint8_t *) "NotFooFooFoo", 10); + CFStringRef cfaccount = CFSTR("test@test.org"); + CFStringRef data_name = CFSTR("TestSource"); + CFStringRef circle_key_name = SOSCircleKeyCreateWithName(data_name, NULL); + + CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); + + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_name); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_name); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), data_name); + + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + + // Bob wins writing at this point, feed the changes back to alice. + FillAllChanges(changes); + FeedChangesToMulti(changes, alice_account, carol_account, NULL); + + ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + CFReleaseNull(error); + ok(SOSAccountTryUserCredentials(alice_account, cfaccount, cfpassword, &error), "Credential trying (%@)", error); + CFReleaseNull(error); + CFReleaseNull(cfpassword); + + ok(!SOSAccountTryUserCredentials(alice_account, cfaccount, cfwrong_password, &error), "Credential failing (%@)", error); + CFReleaseNull(cfwrong_password); + is(error ? CFErrorGetCode(error) : 0, kSOSErrorWrongPassword, "Expected SOSErrorWrongPassword"); + CFReleaseNull(error); + + CFDataRef incompatibleDER = SOSCircleCreateIncompatibleCircleDER(&error); + + InjectChangeToMulti(changes, circle_key_name, incompatibleDER, alice_account, NULL); + CFReleaseNull(circle_key_name); + CFReleaseNull(incompatibleDER); + + is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); + + alice_account = nil; + bob_account = nil; + carol_account = nil; + SOSTestCleanup(); +} + +int secd_55_account_incompatibility(int argc, char *const *argv) +{ + plan_tests(kTestTestCount); + + secd_test_setup_temp_keychain(__FUNCTION__, NULL); + + tests(); + + return 0; +} diff --git a/OSX/sec/securityd/Regressions/secd-56-account-apply.c b/OSX/sec/securityd/Regressions/secd-56-account-apply.m similarity index 92% rename from OSX/sec/securityd/Regressions/secd-56-account-apply.c rename to OSX/sec/securityd/Regressions/secd-56-account-apply.m index da6d8e6d..3dc630a3 100644 --- a/OSX/sec/securityd/Regressions/secd-56-account-apply.c +++ b/OSX/sec/securityd/Regressions/secd-56-account-apply.m @@ -51,7 +51,7 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 230; +static int kTestTestCount = 181; #define kAccountPasswordString ((uint8_t*) "FooFooFoo") #define kAccountPasswordStringLen 10 @@ -64,10 +64,10 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - SOSAccountRef david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -134,7 +134,7 @@ static void tests(void) CFReleaseSafe(applicants); } - ok(SOSAccountLeaveCircle(carole_account, &error), "Carole bails (%@)", error); + ok([carole_account.trust leaveCircle:carole_account err:&error], "Carole bails (%@)", error); CFReleaseNull(error); // Everyone but bob sees that carole bails. @@ -207,11 +207,8 @@ static void tests(void) is(countPeers(carole_account), 3, "Carole sees 3 valid peers after sliding in"); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); - CFReleaseNull(david_account); - + alice_account = nil; + bob_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.c b/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m similarity index 85% rename from OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.c rename to OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m index 0b5c6445..3ffddba9 100644 --- a/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.c +++ b/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -56,10 +57,10 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 66; +static int kTestTestCount = 61; -static bool acceptApplicants(SOSAccountRef account, CFIndex count) { +static bool acceptApplicants(SOSAccount* account, CFIndex count) { bool retval = false; CFErrorRef error = NULL; CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); @@ -68,8 +69,8 @@ static bool acceptApplicants(SOSAccountRef account, CFIndex count) { require_quiet(CFArrayGetCount(applicants) == count, xit); ok((retval=SOSAccountAcceptApplicants(account, applicants, &error)), "Accept applicants into the fold"); CFReleaseNull(error); - CFReleaseSafe(applicants); xit: + CFReleaseNull(applicants); return retval; } @@ -82,7 +83,7 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -93,7 +94,7 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - ok(SOSAccountLeaveCircle(alice_account , &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); @@ -106,15 +107,15 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates"); - ok(SOSAccountIsInCircle(alice_account, &error), "Alice is back in the circle (%@)", error); + ok([alice_account.trust isInCircle:&error], "Alice is back in the circle (%@)", error); CFReleaseNull(error); is(countActivePeers(alice_account), 2, "Alice sees 2 active peers"); is(countPeers(alice_account), 1, "Alice sees 1 valid peer"); // Have Alice leave the circle just as Bob tries to join. - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 1, "updates"); ok(SOSAccountTryUserCredentials(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -129,11 +130,11 @@ static void tests(void) ok(acceptApplicants(alice_account, 1), "Alice accepts Carole"); is(ProcessChangesUntilNoChange(changes, bob_account, alice_account, carole_account, NULL), 3, "updates"); - ok(SOSAccountLeaveCircle(alice_account , &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, NULL), 2, "updates"); - ok(SOSAccountLeaveCircle(carole_account , &error), "Carole Leaves (%@)", error); + ok([carole_account.trust leaveCircle:carole_account err:&error], "Carole Leaves (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, NULL), 2, "updates"); @@ -146,9 +147,8 @@ static void tests(void) CFReleaseNull(cfpassword); - CFReleaseNull(alice_account); - CFReleaseNull(bob_account); - + + alice_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-57-account-leave.c b/OSX/sec/securityd/Regressions/secd-57-account-leave.m similarity index 90% rename from OSX/sec/securityd/Regressions/secd-57-account-leave.c rename to OSX/sec/securityd/Regressions/secd-57-account-leave.m index cbc8ea71..ed672f79 100644 --- a/OSX/sec/securityd/Regressions/secd-57-account-leave.c +++ b/OSX/sec/securityd/Regressions/secd-57-account-leave.m @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -52,10 +53,10 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 253; +static int kTestTestCount = 251; /* - static void trim_retirements_from_circle(SOSAccountRef account) { + static void trim_retirements_from_circle(SOSAccount* account) { SOSAccountForEachCircle(account, ^(SOSCircleRef circle) { SOSCircleRemoveRetired(circle, NULL); }); @@ -71,10 +72,10 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - SOSAccountRef david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account , cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -122,7 +123,7 @@ static void tests(void) SOSAccountPurgePrivateCredential(alice_account); - ok(SOSAccountLeaveCircle(alice_account , &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); @@ -194,10 +195,10 @@ static void tests(void) // Now test lost circle change when two leave simultaneously, needing us to see the retirement tickets - ok(SOSAccountLeaveCircle(alice_account , &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); - ok(SOSAccountLeaveCircle(carole_account , &error), "carole Leaves (%@)", error); + ok([carole_account.trust leaveCircle:carole_account err:&error], "carole Leaves (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 2, "updates"); @@ -240,17 +241,14 @@ static void tests(void) // Now see that bob can call leave without his private key SOSAccountPurgeIdentity(bob_account); // Hopefully this actually purges, no errors to process - ok(SOSAccountLeaveCircle(bob_account, &error), "bob Leaves w/o credentials (%@)", error); + ok([bob_account.trust leaveCircle:bob_account err:&error], "bob Leaves w/o credentials (%@)", error); CFReleaseNull(error); - ok(!SOSAccountIsInCircle(bob_account, &error), "bob knows he's out (%@)", error); + ok(![bob_account.trust isInCircle:&error], "bob knows he's out (%@)", error); CFReleaseNull(error); - - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); - CFReleaseNull(david_account); - + alice_account = nil; + bob_account = nil; + SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-58-password-change.c b/OSX/sec/securityd/Regressions/secd-58-password-change.m similarity index 93% rename from OSX/sec/securityd/Regressions/secd-58-password-change.c rename to OSX/sec/securityd/Regressions/secd-58-password-change.m index b48fcc86..26aa9486 100644 --- a/OSX/sec/securityd/Regressions/secd-58-password-change.c +++ b/OSX/sec/securityd/Regressions/secd-58-password-change.m @@ -50,9 +50,9 @@ #include "SOSAccountTesting.h" #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 259; +static int kTestTestCount = 257; -static bool AssertCreds(SOSAccountRef account,CFStringRef acct_name, CFDataRef password) { +static bool AssertCreds(SOSAccount* account,CFStringRef acct_name, CFDataRef password) { CFErrorRef error = NULL; bool retval; ok((retval = SOSAccountAssertUserCredentialsAndUpdate(account, acct_name, password, &error)), "Credential setting (%@)", error); @@ -60,7 +60,7 @@ static bool AssertCreds(SOSAccountRef account,CFStringRef acct_name, CFDataRef p return retval; } -static bool ResetToOffering(SOSAccountRef account) { +static bool ResetToOffering(SOSAccount* account) { CFErrorRef error = NULL; bool retval; ok((retval = SOSAccountResetToOffering_wTxn(account, &error)), "Reset to offering (%@)", error); @@ -68,7 +68,7 @@ static bool ResetToOffering(SOSAccountRef account) { return retval; } -static bool JoinCircle(SOSAccountRef account) { +static bool JoinCircle(SOSAccount* account) { CFErrorRef error = NULL; bool retval; ok((retval = SOSAccountJoinCircles_wTxn(account, &error)), "Join Circle (%@)", error); @@ -76,7 +76,7 @@ static bool JoinCircle(SOSAccountRef account) { return retval; } -static bool AcceptApplicants(SOSAccountRef account, CFIndex cnt) { +static bool AcceptApplicants(SOSAccount* account, CFIndex cnt) { CFErrorRef error = NULL; bool retval = false; CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); @@ -94,9 +94,9 @@ static void tests(void) CFStringRef cfaccount = CFSTR("test@test.org"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carol_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); /* Set Initial Credentials and Parameters for the Syncing Circles ---------------------------------------*/ ok(AssertCreds(bob_account, cfaccount, cfpassword), "Setting credentials for Bob"); @@ -215,14 +215,10 @@ static void tests(void) is(countActivePeers(alice_account), 4, "There are four active peers - bob, alice, carol and iCloud"); is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); - - - - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carol_account); CFReleaseNull(cfnewpassword); - + alice_account = nil; + bob_account = nil; + carol_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-59-account-cleanup.c b/OSX/sec/securityd/Regressions/secd-59-account-cleanup.m similarity index 75% rename from OSX/sec/securityd/Regressions/secd-59-account-cleanup.c rename to OSX/sec/securityd/Regressions/secd-59-account-cleanup.m index 5269da45..4dc43f3f 100644 --- a/OSX/sec/securityd/Regressions/secd-59-account-cleanup.c +++ b/OSX/sec/securityd/Regressions/secd-59-account-cleanup.m @@ -35,7 +35,7 @@ #include #include #include - +#include #include #include @@ -52,7 +52,7 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 123; +static int kTestTestCount = 121; static void tests(void) { @@ -63,9 +63,9 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), circle_name); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), circle_name); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), circle_name); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), circle_name); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), circle_name); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), circle_name); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -104,10 +104,7 @@ static void tests(void) ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); CFReleaseNull(peers); - SOSFullPeerInfoRef fpiAlice = SOSAccountGetMyFullPeerInfo(alice_account); - CFStringRef alice_id = CFStringCreateCopy(NULL, SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(fpiAlice))); - - ok(SOSAccountLeaveCircle(alice_account, &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); CFReleaseNull(cfpassword); @@ -116,11 +113,9 @@ static void tests(void) accounts_agree("Alice bails", bob_account, alice_account); accounts_agree("Alice bails", bob_account, carole_account); - SOSAccountCleanupRetirementTickets(bob_account, 0, &error); + [bob_account.trust cleanupRetirementTickets:bob_account circle:bob_account.trust.trustedCircle time:0 err:&error]; is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - //is(CFDictionaryGetCountOfValue(BobChanges, kCFNull),0, "0 Keys Nulled Out"); ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies (%@)", error); CFReleaseNull(error); @@ -136,40 +131,20 @@ static void tests(void) CFReleaseNull(error); CFReleaseNull(applicants); } - - // Bob should not yet cleanup Alice's retirment here on his own since it hasn't been long enough - // by default. - //is(CFDictionaryGetCountOfValue(BobChanges, kCFNull),0, "0 Keys Nulled Out"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); accounts_agree("Carole joins", bob_account, carole_account); - SOSAccountCleanupRetirementTickets(bob_account, 0, &error); + [bob_account.trust cleanupRetirementTickets:bob_account circle:bob_account.trust.trustedCircle time:0 err:&error]; is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); is(countPeers(bob_account), 2, "Active peers after forced cleanup"); is(countActivePeers(bob_account), 3, "Inactive peers after forced cleanup"); - - //is(CFDictionaryGetCountOfValue(BobChanges, kCFNull), 1, "1 Keys Nulled Out"); - -// CFDictionaryForEach(BobChanges, ^(const void *key, const void *value) { -// if(isNull(value)) { -// CFStringRef circle_name = NULL, retiree = NULL; -// SOSKVSKeyType keytype = SOSKVSKeyGetKeyTypeAndParse(key, &circle_name, &retiree, NULL); -// is(keytype, kRetirementKey, "Expect only a retirement key"); -// ok(CFEqualSafe(alice_id, retiree), "Alice (%@) is retiree (%@)", alice_id, retiree); -// CFReleaseNull(circle_name); -// CFReleaseNull(retiree); -// } -// }); - - CFReleaseNull(alice_id); - CFReleaseNull(carole_account); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - + + alice_account = nil; + bob_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.c b/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m similarity index 62% rename from OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.c rename to OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m index b9591b74..09d267ae 100644 --- a/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.c +++ b/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -51,11 +52,11 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 215; +static int kTestTestCount = 213; -static bool purgeICloudIdentity(SOSAccountRef account) { +static bool purgeICloudIdentity(SOSAccount* account) { bool retval = false; - SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef(SOSAccountGetCircle(account, NULL), NULL); + SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef([account.trust getCircle:NULL], NULL); if(!icfpi) return false; retval = SOSFullPeerInfoPurgePersistentKey(icfpi, NULL); return retval; @@ -69,9 +70,9 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -120,7 +121,7 @@ static void tests(void) accounts_agree_internal("Carole's in", bob_account, alice_account, false); accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); - ok(SOSAccountLeaveCircle(carole_account, &error), "Carol Leaves again"); + ok([carole_account.trust leaveCircle:carole_account err:&error], "Carol Leaves again"); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); @@ -161,7 +162,7 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); - ok(SOSAccountLeaveCircle(carole_account, &error), "Carol Leaves again"); + ok([carole_account.trust leaveCircle:carole_account err:&error], "Carol Leaves again"); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); @@ -190,11 +191,87 @@ static void tests(void) accounts_agree_internal("Carole's in", bob_account, alice_account, false); accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); + //join after piggybacking the icloud identity?? + CFMutableArrayRef identityArray = SOSAccountCopyiCloudIdentities(alice_account); + + NSMutableArray *encodedIdenities = [NSMutableArray array]; + CFIndex i, count = CFArrayGetCount(identityArray); + for (i = 0; i < count; i++) { + SOSPeerInfoRef fpi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(identityArray, i); + NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(fpi, NULL)); + if (data) + [encodedIdenities addObject:data]; + } + + //store in keychain as the piggy icloud + [encodedIdenities enumerateObjectsUsingBlock:^(NSData *v_data, NSUInteger idx, BOOL *stop) { + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassKey, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup: @"com.apple.security.sos", + (id)kSecAttrLabel : @"Cloud Identity - piggy", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecUseTombstones : (id)kCFBooleanTrue, + (id)kSecValueData : v_data, + } mutableCopy]; + + OSStatus status = SecItemAdd((__bridge CFDictionaryRef) query, NULL); + + if(status == errSecDuplicateItem) { + // Sure, okay, fine, we'll update. + NSMutableDictionary* update = [@{ + (id)kSecValueData: v_data, + } mutableCopy]; + query[(id)kSecValueData] = nil; + + status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef)update); + ok(status == 0, "Grabbed icloud identity from the keychain %@", error); + } + }]; + + + //now grab this grom the keychain + NSMutableDictionary* query2 = [@{ + (id)kSecClass : (id)kSecClassKey, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup: @"com.apple.security.sos", + (id)kSecAttrLabel : @"Cloud Identity - piggy", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecUseTombstones : (id)kCFBooleanTrue, + (id)kSecReturnData : (id)kCFBooleanTrue, + } mutableCopy]; + CFTypeRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query2, &result); + ok(status == 0, "Grabbed icloud identity from the keychain %@", error); + ok(result != NULL, "result from sec item copy matching query %@", error); + + NSDictionary *keyAttributes = @{ + (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, + (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC, + }; + + + SecKeyRef privKey = SecKeyCreateWithData(result, (__bridge CFDictionaryRef)keyAttributes, NULL); + + ok(privKey != NULL, "Private key is NULL"); + SecKeyRef publicKey = SecKeyCreatePublicFromPrivate(privKey); + ok(publicKey != NULL, "Private key is NULL"); + + CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey); + ok(public_key_hash != NULL, "hash is not null"); + + SOSAccount* margaret_account = CreateAccountForLocalChanges(CFSTR("margaret"), CFSTR("TestSource")); + + ok(SOSAccountAssertUserCredentialsAndUpdate(margaret_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); + ok(SOSAccountJoinCirclesAfterRestore_wTxn(margaret_account, &error), "Carole cloud identity joins (%@)", error); + + CFReleaseNull(public_key_hash); CFReleaseNull(cfpassword); + CFReleaseNull(privKey); + alice_account = nil; + bob_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.c b/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m similarity index 84% rename from OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.c rename to OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m index 1348d96b..c526a5dd 100644 --- a/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.c +++ b/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -50,16 +51,16 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 118; +static int kTestTestCount = 116; /* - static void trim_retirements_from_circle(SOSAccountRef account) { + static void trim_retirements_from_circle(SOSAccount* account) { SOSAccountForEachCircle(account, ^(SOSCircleRef circle) { SOSCircleRemoveRetired(circle, NULL); }); } */ -static bool accept_applicants(SOSAccountRef account, int count) { +static bool accept_applicants(SOSAccount* account, int count) { CFErrorRef error = NULL; CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); bool retval = false; @@ -83,10 +84,10 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges ( CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges ( CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges ( CFSTR("Carole"), CFSTR("TestSource")); - SOSAccountRef david_account = CreateAccountForLocalChanges ( CFSTR("David"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges ( CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges ( CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges ( CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* david_account = CreateAccountForLocalChanges ( CFSTR("David"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -140,7 +141,7 @@ static void tests(void) // SOSAccountPurgePrivateCredential(alice_account); - ok(SOSAccountLeaveCircle(alice_account, &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, carole_account, david_account, NULL), 2, "updates"); @@ -160,26 +161,22 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, david_account, NULL), 3, "updates"); CFReleaseNull(error); - is(SOSAccountGetCircleStatus(carole_account, &error), kSOSCCInCircle, "Carole still in Circle (%@)", error); + is([carole_account getCircleStatus:&error], kSOSCCInCircle, "Carole still in Circle (%@)", error); CFReleaseNull(error); - is(SOSAccountGetCircleStatus(david_account, &error), kSOSCCInCircle, "David still in Circle (%@)", error); + is([david_account getCircleStatus:&error], kSOSCCInCircle, "David still in Circle (%@)", error); CFReleaseNull(error); - is(SOSAccountGetCircleStatus(bob_account, &error), kSOSCCNotInCircle, "Bob is not in Circle (%@)", error); + is([bob_account getCircleStatus:&error], kSOSCCNotInCircle, "Bob is not in Circle (%@)", error); CFReleaseNull(error); is(SOSAccountGetLastDepartureReason(bob_account, &error), kSOSLeftUntrustedCircle, "Bob affirms he left because he doesn't know anyone."); CFReleaseNull(error); - is(SOSAccountGetCircleStatus(alice_account, &error), kSOSCCNotInCircle, "Alice is not in Circle (%@)", error); + is([alice_account getCircleStatus:&error], kSOSCCNotInCircle, "Alice is not in Circle (%@)", error); CFReleaseNull(error); is(SOSAccountGetLastDepartureReason(alice_account, &error), kSOSWithdrewMembership, "Alice affirms she left by request."); CFReleaseNull(error); - - CFReleaseNull(carole_account); - CFReleaseNull(david_account); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); CFReleaseNull(cfpassword); - + alice_account = nil; + bob_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-62-account-backup.c b/OSX/sec/securityd/Regressions/secd-62-account-backup.m similarity index 80% rename from OSX/sec/securityd/Regressions/secd-62-account-backup.c rename to OSX/sec/securityd/Regressions/secd-62-account-backup.m index ba094efc..2012835c 100644 --- a/OSX/sec/securityd/Regressions/secd-62-account-backup.c +++ b/OSX/sec/securityd/Regressions/secd-62-account-backup.m @@ -1,3 +1,4 @@ + /* * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. * @@ -35,6 +36,10 @@ #include #include #include +#include + +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" #include #include @@ -64,7 +69,7 @@ static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error) return result; } -static int kTestTestCount = 133; +static int kTestTestCount = 129; #else static int kTestTestCount = 1; #endif @@ -80,8 +85,8 @@ static void tests(void) secd_test_setup_testviews(); // for running this test solo CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); CFDataRef alice_backup_key = CopyBackupKeyForString(CFSTR("Alice Backup Entropy"), &error); CFDataRef bob_backup_key = CopyBackupKeyForString(CFSTR("Bob Backup Entropy"), &error); @@ -117,52 +122,52 @@ static void tests(void) } is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - + CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); CFReleaseNull(peers); - is(SOSAccountUpdateView(alice_account, kTestView1, kSOSCCViewEnable, &error), kSOSCCViewMember, "Enable view (%@)", error); + is([alice_account.trust updateView:alice_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); CFReleaseNull(error); - ok(SOSAccountCheckForRings(alice_account, &error), "Alice_account is good"); + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); - is(SOSAccountUpdateView(bob_account, kTestView1, kSOSCCViewEnable, &error), kSOSCCViewMember, "Enable view (%@)", error); + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); CFReleaseNull(error); - ok(SOSAccountCheckForRings(bob_account, &error), "Alice_account is good"); + ok([bob_account.trust checkForRings:&error], "Bob_account is good"); CFReleaseNull(error); ok(SOSAccountSetBackupPublicKey_wTxn(alice_account, alice_backup_key, &error), "Set backup public key, alice (%@)", error); CFReleaseNull(error); - ok(SOSAccountCheckForRings(alice_account, &error), "Alice_account is good"); + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); - ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, alice (%@)", error); + ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); CFReleaseNull(error); - ok(SOSAccountCheckForRings(bob_account, &error), "Alice_account is good"); + ok([bob_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice is in backup before sync?"); + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice's key in backup before sync?"); - ok(SOSAccountCheckForRings(alice_account, &error), "Alice_account is good"); + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); - + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Is bob in the backup after sync? - 1"); - ok(SOSAccountCheckForRings(bob_account, &error), "Alice_account is good"); + ok([bob_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); - ok(SOSAccountCheckForRings(alice_account, &error), "Alice_account is good"); + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); - ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice is in backup after sync?"); + ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice in backup after sync?"); ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "IS bob in the backup after sync"); @@ -172,7 +177,7 @@ static void tests(void) // //Bob leaves the circle // - ok(SOSAccountLeaveCircle(bob_account, &error), "Bob Leaves (%@)", error); + ok([bob_account.trust leaveCircle:bob_account err:&error], "Bob Leaves (%@)", error); CFReleaseNull(error); //Alice should kick Bob out of the backup! @@ -187,7 +192,8 @@ static void tests(void) ok(testAccountPersistence(alice_account), "Test Account->DER->Account Equivalence"); - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), kTestView1), "Bob is still in the backup!"); + SOSAccountTrustClassic *bobTrust = bob_account.trust; + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is still in the backup!"); //Bob gets back into the circle ok(SOSAccountJoinCircles_wTxn(bob_account, &error)); @@ -205,7 +211,7 @@ static void tests(void) //enables view - is(SOSAccountUpdateView(bob_account, kTestView1, kSOSCCViewEnable, &error), kSOSCCViewMember, "Enable view (%@)", error); + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); CFReleaseNull(error); ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob isn't in the backup yet"); @@ -228,7 +234,7 @@ static void tests(void) is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is in the backup - should not be so!"); - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), kTestView1), "Bob is up to date in the backup!"); + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup!"); // // Setting new backup public key for Bob @@ -237,29 +243,29 @@ static void tests(void) ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, alice (%@)", error); CFReleaseNull(error); - is(SOSAccountUpdateView(bob_account, kTestView1, kSOSCCViewEnable, &error), kSOSCCViewMember, "Enable view (%@)", error); + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); ok(SOSAccountNewBKSBForView(bob_account, kTestView1, &error), "Setting new backup public key for bob account failed: (%@)", error); //bob is in his own backup ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is not in the backup"); //alice does not have bob in her backup - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), kTestView1), "Bob is up to date in the backup - should not be so!"); + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup - should not be so!"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 5, "updates"); ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key should be in the backup"); ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Alice is in the backup"); - - ok(SOSAccountResetToEmpty(alice_account, &error), "Reset circle to empty"); + ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); + ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset circle to empty"); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); ok(SOSAccountIsBackupRingEmpty(bob_account, kTestView1), "Bob should not be in the backup"); ok(SOSAccountIsBackupRingEmpty(alice_account, kTestView1), "Alice should not be in the backup"); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(cfpassword); + CFReleaseNull(cfpassword); + alice_account = nil; + bob_account = nil; SOSTestCleanup(); #endif diff --git a/OSX/sec/securityd/Regressions/secd-62-account-hsa-join.c b/OSX/sec/securityd/Regressions/secd-62-account-hsa-join.c deleted file mode 100644 index 304ef092..00000000 --- a/OSX/sec/securityd/Regressions/secd-62-account-hsa-join.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2013-2015 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 -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 102; - -static void tests(void) -{ - secd_test_setup_temp_keychain("secd_60_account_cloud_identity", NULL); - - CFErrorRef error = NULL; - CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); - CFStringRef cfaccount = CFSTR("test@test.org"); - - CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - - SOSAccountRef alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - CFReleaseNull(cfpassword); - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - { - CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); - - ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); - ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); - CFReleaseNull(error); - CFReleaseNull(applicants); - } - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies (%@)", error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - SOSPeerInfoRef carolePeerInfo = SOSAccountGetMyPeerInfo(carole_account); - - ok(carolePeerInfo, "got carole's peerinfo"); - - SecKeyRef carolePubKey = SOSPeerInfoCopyPubKey(carolePeerInfo, &error); - - ok(carolePubKey, "got carole's pubkey (%@)", error); - CFReleaseNull(error); - - CFDataRef pubKeyData = NULL; - OSStatus stat = SecKeyCopyPublicBytes(carolePubKey, &pubKeyData); - - ok(stat == 0, "got carole's pubkey data "); - - ok(SOSAccountSetHSAPubKeyExpected(bob_account, pubKeyData, &error), "Bob arms to allow Carole to join (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - is(countApplicants(alice_account), 1, "See one applicant"); - - is(countPeers(carole_account), 2, "Carole sees 2 valid peers still"); - - SOSAccountClientPing(carole_account); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 5, "updates"); - - is(countApplicants(alice_account), 0, "See no applicants"); - - is(countPeers(carole_account), 3, "Carole sees 3 valid peers"); - - accounts_agree_internal("Carole's in", bob_account, alice_account, false); - accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); - - - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); - - SOSTestCleanup(); -} - -int secd_62_account_hsa_join(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-63-account-resurrection.c b/OSX/sec/securityd/Regressions/secd-63-account-resurrection.m similarity index 86% rename from OSX/sec/securityd/Regressions/secd-63-account-resurrection.c rename to OSX/sec/securityd/Regressions/secd-63-account-resurrection.m index ea55c716..89aae049 100644 --- a/OSX/sec/securityd/Regressions/secd-63-account-resurrection.c +++ b/OSX/sec/securityd/Regressions/secd-63-account-resurrection.m @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 109; +static int kTestTestCount = 107; typedef void (^stir_block)(int expected_iterations); typedef int (^execute_block)(); @@ -67,7 +68,7 @@ static void stirBetween(stir_block stir, ...) { stir(execute()); } -static void VerifyCountAndAcceptAllApplicants(SOSAccountRef account, int expected) +static void VerifyCountAndAcceptAllApplicants(SOSAccount* account, int expected) { CFErrorRef error = NULL; CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); @@ -96,11 +97,11 @@ static void tests(void) const CFStringRef data_source_name = CFSTR("TestSource"); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_source_name); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_source_name); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), data_source_name); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_source_name); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_source_name); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), data_source_name); - SOSAccountRef alice_resurrected = NULL; + SOSAccount* alice_resurrected = NULL; __block CFDataRef frozen_alice = NULL; @@ -142,13 +143,14 @@ static void tests(void) return 1; }, ^{ - frozen_alice = SOSAccountCopyEncodedData(alice_account, kCFAllocatorNull, &error); - ok(frozen_alice, "Copy encoded %@", error); - CFReleaseNull(error); + NSError *ns_error = nil; + frozen_alice = (CFDataRef) CFBridgingRetain([alice_account encodedData:&ns_error]); + ok(frozen_alice, "Copy encoded %@", ns_error); + ns_error = nil; SOSAccountPurgePrivateCredential(alice_account); - ok(SOSAccountLeaveCircle(alice_account , &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); return 2; @@ -181,7 +183,7 @@ static void tests(void) CFReleaseNull(error); return 1; }, ^{ - ok(!SOSAccountIsInCircle(alice_resurrected, &error), "Ressurrected not in circle: %@", error); + ok(![alice_resurrected.trust isInCircle:&error], "Ressurrected not in circle: %@", error); CFReleaseNull(error); ok(SOSAccountJoinCircles_wTxn(alice_resurrected, &error), "Risen-alice Applies (%@)", error); @@ -193,12 +195,9 @@ static void tests(void) }, NULL); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); - CFReleaseNull(alice_resurrected); CFReleaseNull(frozen_alice); - + alice_account = nil; + bob_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-64-circlereset.c b/OSX/sec/securityd/Regressions/secd-64-circlereset.m similarity index 79% rename from OSX/sec/securityd/Regressions/secd-64-circlereset.c rename to OSX/sec/securityd/Regressions/secd-64-circlereset.m index 88ceb4d3..79ef5e62 100644 --- a/OSX/sec/securityd/Regressions/secd-64-circlereset.c +++ b/OSX/sec/securityd/Regressions/secd-64-circlereset.m @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -35,27 +36,29 @@ #include "SecdTestKeychainUtilities.h" -static int64_t getCurrentGenCount(SOSAccountRef account) { - return SOSCircleGetGenerationSint(account->trusted_circle); +static int64_t getCurrentGenCount(SOSAccount* account) { + SOSAccountTrustClassic* trust = account.trust; + return SOSCircleGetGenerationSint(trust.trustedCircle); } -static bool SOSAccountResetWithGenCountValue(SOSAccountRef account, int64_t gcount, CFErrorRef* error) { +static bool SOSAccountResetWithGenCountValue(SOSAccount* account, int64_t gcount, CFErrorRef* error) { if (!SOSAccountHasPublicKey(account, error)) return false; __block bool result = true; - - result &= SOSAccountResetAllRings(account, error); - - CFReleaseNull(account->my_identity); - - account->departure_code = kSOSWithdrewMembership; - result &= SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle) { + SOSAccountTrustClassic* trust = account.trust; + + result &= [account.trust resetAllRings:account err:error]; + + trust.fullPeerInfo = nil; + [trust setDepartureCode:kSOSWithdrewMembership]; + + result &= [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { SOSGenCountRef gencount = SOSGenerationCreateWithValue(gcount); result = SOSCircleResetToEmpty(circle, error); SOSCircleSetGeneration(circle, gencount); CFReleaseNull(gencount); return result; - }); + }]; if (!result) { secerror("error: %@", error ? *error : NULL); @@ -72,7 +75,7 @@ static SOSCircleRef SOSCircleCreateWithGenCount(int64_t gcount) { return c; } -static int kTestTestCount = 47; +static int kTestTestCount = 45; static void tests(void) { @@ -88,8 +91,8 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); // Setup Circle with Bob and Alice in it ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -122,12 +125,12 @@ static void tests(void) CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); - is(SOSAccountGetCircleStatus(bob_account, NULL), 0, "Bob Survives bad circle post"); - is(SOSAccountGetCircleStatus(alice_account, NULL), 1, "Alice does not survive bad circle post"); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); + is([bob_account getCircleStatus:&error], 0, "Bob Survives bad circle post"); + is([alice_account getCircleStatus:&error], 1, "Alice does not survive bad circle post"); + CFReleaseNull(cfpassword); - + alice_account = nil; + bob_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.c b/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m similarity index 84% rename from OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.c rename to OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m index b6c17414..7a4e2f21 100644 --- a/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.c +++ b/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 47; +static int kTestTestCount = 43; typedef void (^stir_block)(int expected_iterations); typedef int (^execute_block)(); @@ -67,7 +68,7 @@ static void stirBetween(stir_block stir, ...) { stir(execute()); } -__unused static void VerifyCountAndAcceptAllApplicants(SOSAccountRef account, int expected) +__unused static void VerifyCountAndAcceptAllApplicants(SOSAccount* account, int expected) { CFErrorRef error = NULL; CFArrayRef applicants = SOSAccountCopyApplicants(account, &error); @@ -96,11 +97,11 @@ static void tests(void) const CFStringRef data_source_name = CFSTR("TestSource"); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_source_name); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_source_name); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), data_source_name); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), data_source_name); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), data_source_name); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), data_source_name); - SOSAccountRef alice_resurrected = NULL; + SOSAccount* alice_resurrected = NULL; __block CFDataRef frozen_alice = NULL; @@ -123,14 +124,14 @@ static void tests(void) return 2; }, ^{ - - frozen_alice = SOSAccountCopyEncodedData(alice_account, kCFAllocatorNull, &error); - ok(frozen_alice, "Copy encoded %@", error); - CFReleaseNull(error); + NSError *ns_error = nil; + frozen_alice = (CFDataRef) CFBridgingRetain([alice_account encodedData:&ns_error]); + ok(frozen_alice, "Copy encoded %@", ns_error); + ns_error = nil; SOSAccountPurgePrivateCredential(alice_account); - ok(SOSAccountLeaveCircle(alice_account , &error), "Alice Leaves (%@)", error); + ok([alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error); CFReleaseNull(error); return 2; @@ -155,22 +156,19 @@ static void tests(void) CFReleaseNull(error); return 1; }, ^{ - ok(!SOSAccountIsInCircle(alice_resurrected, &error), "Ressurrected not in circle: %@", error); + ok(![alice_resurrected.trust isInCircle:&error], "Ressurrected not in circle: %@", error); CFReleaseNull(error); - ok(SOSAccountIsInCircle(bob_account, &error), "Should be in circle: %@", error); + ok([bob_account.trust isInCircle:&error], "Should be in circle: %@", error); CFReleaseNull(error); return 1; }, NULL); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); - CFReleaseNull(alice_resurrected); CFReleaseNull(frozen_alice); - + alice_account = nil; + bob_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd-66-account-recovery.c b/OSX/sec/securityd/Regressions/secd-66-account-recovery.m similarity index 71% rename from OSX/sec/securityd/Regressions/secd-66-account-recovery.c rename to OSX/sec/securityd/Regressions/secd-66-account-recovery.m index 6a7fc8cb..31c244d3 100644 --- a/OSX/sec/securityd/Regressions/secd-66-account-recovery.c +++ b/OSX/sec/securityd/Regressions/secd-66-account-recovery.m @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -73,7 +74,6 @@ int secd_66_account_recovery(int argc, char *const *argv) { #include "SOSAccountTesting.h" - static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error) { __block CFDataRef result = NULL; @@ -83,26 +83,53 @@ static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error) return result; } + +static inline bool SOSAccountSetRecoveryKey_wTxn(SOSAccount* acct, CFDataRef recoveryPub, CFErrorRef* error) { + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountSetRecoveryKey(txn.account, recoveryPub, error); + }]; + return result; +} + +static inline bool SOSAccountSOSAccountRemoveRecoveryKey_wTxn(SOSAccount* acct, CFErrorRef* error) { + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountRemoveRecoveryKey(txn.account, error); + }]; + return result; +} + // 6 test cases -static void registerRecoveryKeyNow(CFMutableDictionaryRef changes, SOSAccountRef registrar, SOSAccountRef observer, CFDataRef recoveryPub, bool recKeyFirst) { +static void registerRecoveryKeyNow(CFMutableDictionaryRef changes, SOSAccount* registrar, SOSAccount* observer, CFDataRef recoveryPub, bool recKeyFirst) { CFErrorRef error = NULL; - ok(SOSAccountSetRecoveryKey(registrar, recoveryPub, &error), "Set Recovery Key"); + if(recoveryPub) { + ok(SOSAccountSetRecoveryKey_wTxn(registrar, recoveryPub, &error), "Set Recovery Key"); + CFReleaseNull(error); + } else { + ok(SOSAccountSOSAccountRemoveRecoveryKey_wTxn(registrar, &error), "Clear Recovery Key"); + CFReleaseNull(error); + } + ok(error == NULL, "Error shouldn't be %@", error); CFReleaseNull(error); - - int nchanges = (recKeyFirst) ? 3: 4; + int nchanges = (recKeyFirst) ? 3: 5; + nchanges = (recoveryPub) ? nchanges: 5; is(ProcessChangesUntilNoChange(changes, registrar, observer, NULL), nchanges, "updates"); CFDataRef registrar_recKey = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, registrar, &error); - ok(registrar_recKey, "Registrar retrieved recKey"); CFReleaseNull(error); - CFDataRef observer_recKey = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, observer, &error); - ok(observer_recKey, "Observer retrieved recKey"); CFReleaseNull(error); - - ok(CFEqualSafe(registrar_recKey, observer_recKey), "recKeys are the same"); - ok(CFEqualSafe(registrar_recKey, recoveryPub), "recKeys are as expected"); + + if(recoveryPub) { + ok(registrar_recKey, "Registrar retrieved recKey"); + ok(observer_recKey, "Observer retrieved recKey"); + ok(CFEqualSafe(registrar_recKey, observer_recKey), "recKeys are the same"); + ok(CFEqualSafe(registrar_recKey, recoveryPub), "recKeys are as expected"); + } else { + ok((!registrar_recKey && !observer_recKey), "recKeys are NULL"); + } CFReleaseNull(observer_recKey); CFReleaseNull(registrar_recKey); } @@ -115,11 +142,11 @@ static void tests(bool recKeyFirst) CFDataRef fullKeyBytes = NULL; CFDataRef pubKeyBytes = NULL; - sRecKey = SecRKCreateRecoveryKey(sock_drawer_key); + sRecKey = SecRKCreateRecoveryKeyWithError((__bridge NSString*)sock_drawer_key, NULL); ok(sRecKey, "Create SecRecoveryKey from String"); if(sRecKey) { - fullKeyBytes = SecRKCopyBackupFullKey(sRecKey); - pubKeyBytes = SecRKCopyBackupPublicKey(sRecKey); + fullKeyBytes = (__bridge CFDataRef)(SecRKCopyBackupFullKey(sRecKey)); + pubKeyBytes = (__bridge CFDataRef)(SecRKCopyBackupPublicKey(sRecKey)); ok(fullKeyBytes && pubKeyBytes, "Got KeyPair from SecRecoveryKey"); } if(!(fullKeyBytes && pubKeyBytes)) { @@ -136,9 +163,9 @@ static void tests(bool recKeyFirst) secd_test_setup_testviews(); // for running this test solo CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); SOSAccountAssertDSID(alice_account, cfdsid); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); SOSAccountAssertDSID(bob_account, cfdsid); CFDataRef alice_backup_key = CopyBackupKeyForString(CFSTR("Alice Backup Entropy"), &error); @@ -155,28 +182,29 @@ static void tests(bool recKeyFirst) if(recKeyFirst) registerRecoveryKeyNow(changes, alice_account, bob_account, pubKeyBytes, recKeyFirst); - is(SOSAccountUpdateView(alice_account, kTestView1, kSOSCCViewEnable, &error), kSOSCCViewMember, "Enable view (%@)", error); + + is([alice_account.trust updateView:alice_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); CFReleaseNull(error); - ok(SOSAccountCheckForRings(alice_account, &error), "Alice_account is good"); + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); - is(SOSAccountUpdateView(bob_account, kTestView1, kSOSCCViewEnable, &error), kSOSCCViewMember, "Enable view (%@)", error); + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); CFReleaseNull(error); - ok(SOSAccountCheckForRings(bob_account, &error), "Bob_account is good"); + ok([bob_account.trust checkForRings:&error], "Bob_account is good"); CFReleaseNull(error); ok(SOSAccountSetBackupPublicKey_wTxn(alice_account, alice_backup_key, &error), "Set backup public key, alice (%@)", error); CFReleaseNull(error); - ok(SOSAccountCheckForRings(alice_account, &error), "Alice_account is good"); + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, bob (%@)", error); CFReleaseNull(error); - ok(SOSAccountCheckForRings(bob_account, &error), "Bob_account is good"); + ok([bob_account.trust checkForRings:&error], "Bob_account is good"); CFReleaseNull(error); ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice is in backup before sync?"); @@ -188,18 +216,18 @@ static void tests(bool recKeyFirst) CFReleaseNull(bskb); } - ok(SOSAccountCheckForRings(alice_account, &error), "Alice_account is good"); + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Is bob in the backup after sync? - 1"); - ok(SOSAccountCheckForRings(bob_account, &error), "Alice_account is good"); + ok([bob_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); - ok(SOSAccountCheckForRings(alice_account, &error), "Alice_account is good"); + ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); ok(SOSAccountIsMyPeerInBackupAndCurrentInView(alice_account, kTestView1), "Is alice is in backup after sync?"); @@ -212,7 +240,7 @@ static void tests(bool recKeyFirst) // //Bob leaves the circle // - ok(SOSAccountLeaveCircle(bob_account, &error), "Bob Leaves (%@)", error); + ok([bob_account.trust leaveCircle:bob_account err:&error], "Bob Leaves (%@)", error); CFReleaseNull(error); //Alice should kick Bob out of the backup! @@ -226,14 +254,14 @@ static void tests(bool recKeyFirst) CFReleaseNull(error); ok(testAccountPersistence(alice_account), "Test Account->DER->Account Equivalence"); - - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), kTestView1), "Bob is still in the backup!"); + SOSAccountTrustClassic* bobTrust = bob_account.trust; + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is still in the backup!"); //Bob gets back into the circle ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Re-Joins"); //enables view - is(SOSAccountUpdateView(bob_account, kTestView1, kSOSCCViewEnable, &error), kSOSCCViewMember, "Enable view (%@)", error); + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); CFReleaseNull(error); ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob isn't in the backup yet"); @@ -255,9 +283,9 @@ static void tests(bool recKeyFirst) ok(SOSAccountRemoveBackupPublickey_wTxn(bob_account, &error), "Removing Bob's backup key (%@)", error); int nchanges = (recKeyFirst) ? 4: 3; is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), nchanges, "updates"); - + ok(!SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is in the backup - should not be so!"); - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), kTestView1), "Bob is up to date in the backup!"); + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup!"); // // Setting new backup public key for Bob @@ -266,13 +294,13 @@ static void tests(bool recKeyFirst) ok(SOSAccountSetBackupPublicKey_wTxn(bob_account, bob_backup_key, &error), "Set backup public key, alice (%@)", error); CFReleaseNull(error); - is(SOSAccountUpdateView(bob_account, kTestView1, kSOSCCViewEnable, &error), kSOSCCViewMember, "Enable view (%@)", error); + is([bob_account.trust updateView:bob_account name:kTestView1 code:kSOSCCViewEnable err:&error], kSOSCCViewMember, "Enable view (%@)", error); ok(SOSAccountNewBKSBForView(bob_account, kTestView1, &error), "Setting new backup public key for bob account failed: (%@)", error); //bob is in his own backup ok(SOSAccountIsMyPeerInBackupAndCurrentInView(bob_account, kTestView1), "Bob's backup key is not in the backup"); //alice does not have bob in her backup - ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), kTestView1), "Bob is up to date in the backup - should not be so!"); + ok(!SOSAccountIsPeerInBackupAndCurrentInView(alice_account, bobTrust.peerInfo, kTestView1), "Bob is up to date in the backup - should not be so!"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 5, "updates"); @@ -293,8 +321,27 @@ static void tests(bool recKeyFirst) ok(wrappingKey, "Made wrapping key from with sock drawer key"); bskb_keybag_handle_t bskbHandle = SOSBSKBLoadAndUnlockWithWrappingSecret(bskb, wrappingKey, &error); ok(bskbHandle, "Made bskbHandle with recover key"); + ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); + + // Testing reset (Null) recoveryKey ========= + + CFReleaseNull(bskb); + CFReleaseNull(wrappingKey); + + registerRecoveryKeyNow(changes, alice_account, bob_account, NULL, recKeyFirst); - ok(SOSAccountResetToEmpty(alice_account, &error), "Reset circle to empty"); + ok(!SOSAccountRecoveryKeyIsInBackupAndCurrentInView(alice_account, kTestView1), "Recovery Key is not in the backup"); + ok(!SOSAccountRecoveryKeyIsInBackupAndCurrentInView(bob_account, kTestView1), "Recovery Key is not in the backup"); + + bskb = SOSAccountBackupSliceKeyBagForView(alice_account, kTestView1, &error); + CFReleaseNull(error); + + ok(!SOSBSKBHasRecoveryKey(bskb), "BSKB should not have recovery key"); + + //========= + + + ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset circle to empty"); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); ok(SOSAccountIsBackupRingEmpty(bob_account, kTestView1), "Bob should not be in the backup"); @@ -304,16 +351,16 @@ static void tests(bool recKeyFirst) CFReleaseNull(pubKeyBytes); CFReleaseNull(bskb); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); CFReleaseNull(cfpassword); CFReleaseNull(wrappingKey); - + bob_account = nil; + alice_account = nil; + SOSTestCleanup(); } int secd_66_account_recovery(int argc, char *const *argv) { - plan_tests(358); + plan_tests(396); secd_test_setup_temp_keychain(__FUNCTION__, NULL); diff --git a/OSX/sec/securityd/Regressions/secd-668-ghosts.c b/OSX/sec/securityd/Regressions/secd-668-ghosts.m similarity index 83% rename from OSX/sec/securityd/Regressions/secd-668-ghosts.c rename to OSX/sec/securityd/Regressions/secd-668-ghosts.m index 5e3e29cb..77cefbb7 100644 --- a/OSX/sec/securityd/Regressions/secd-668-ghosts.c +++ b/OSX/sec/securityd/Regressions/secd-668-ghosts.m @@ -30,12 +30,13 @@ #include #include +#include #include "secd_regressions.h" #include "SOSAccountTesting.h" #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 538; +static int kTestTestCount = 530; /* Make a circle with two peers - alice and bob(bob is iOS and serial#"abababababab") @@ -55,8 +56,8 @@ static void hauntedCircle(SOSPeerInfoDeviceClass devClass, bool expectGhostBuste CFStringRef ghostIdsID = CFSTR("targetIDS"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), devClass, ghostSerialID, ghostIdsID); + 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"); @@ -64,33 +65,34 @@ static void hauntedCircle(SOSPeerInfoDeviceClass devClass, bool expectGhostBuste ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins"); // Alice Leaves - ok(SOSAccountLeaveCircle(alice_account, &error), "Alice Leaves (%@)", error); + 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 - CFReleaseNull(alice_account); - CFReleaseNull(bob_account); // Make new bob - same as the old bob except peerID - SOSAccountRef bobFinal = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID); + SOSAccount* bobFinal = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID); 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(SOSAccountIsInCircle(bobFinal, NULL), "Bob is in"); + ok([bobFinal.trust isInCircle:NULL], "Bob is in"); } else { - ok(!SOSAccountIsInCircle(bobFinal, NULL), "Bob is not in"); + ok(![bobFinal.trust isInCircle:NULL], "Bob is not in"); } is(countPeers(bobFinal), 1, "There should only be 1 valid peer"); - CFReleaseNull(bobFinal); CFReleaseNull(changes); - + + bob_account = nil; + alice_account = nil; + bobFinal = nil; SOSTestCleanup(); } @@ -102,7 +104,7 @@ static void multiBob(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted, bo CFStringRef ghostIdsID = CFSTR("targetIDS"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); // Start Circle ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -118,7 +120,7 @@ static void multiBob(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted, bo SOSTestMakeGhostInCircle(CFSTR("Bob3"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 4); SOSTestMakeGhostInCircle(CFSTR("Bob4"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 5); - SOSAccountRef bobFinal_account = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID); + SOSAccount* bobFinal_account = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID); if(delayedPrivKey) { SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, DROP_USERKEY, 6, true); is(countPeers(bobFinal_account), 6, "Expect ghosts still in circle"); @@ -128,15 +130,17 @@ static void multiBob(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted, bo } else { SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, KEEP_USERKEY, 2, true); } + CFReleaseNull(cfpassword); 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(bobFinal_account); - CFReleaseNull(alice_account); CFReleaseNull(changes); + alice_account = nil; + bobFinal_account = nil; + SOSTestCleanup(); } @@ -147,12 +151,12 @@ static void iosICloudIdentity() { CFStringRef ghostIdsID = CFSTR("targetIDS"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); // Start Circle ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle"); - SOSCircleRef circle = SOSAccountGetCircle(alice_account, &error); + SOSCircleRef circle = [alice_account.trust getCircle:NULL]; __block CFStringRef serial = NULL; SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { if(SOSPeerInfoIsCloudIdentity(peer)) { @@ -160,12 +164,13 @@ static void iosICloudIdentity() { } }); - SOSAccountRef bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), SOSPeerInfo_iOS, serial, ghostIdsID); + 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 = SOSAccountGetCircle(alice_account, &error); + circle = [alice_account.trust getCircle:&error]; __block bool hasiCloudIdentity = false; SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) { if(SOSPeerInfoIsCloudIdentity(peer)) { @@ -175,14 +180,12 @@ static void iosICloudIdentity() { ok(hasiCloudIdentity, "GhostBusting didn't mess with the iCloud Identity"); - CFReleaseNull(alice_account); - CFReleaseNull(bob_account); CFReleaseNull(changes); - + alice_account = nil; SOSTestCleanup(); } -int secd_668_ghosts(int argc, char *const *argv) +int secd_68_ghosts(int argc, char *const *argv) { plan_tests(kTestTestCount); diff --git a/OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.c b/OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.c rename to OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.m index 2661e38c..93809dfd 100644 --- a/OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.c +++ b/OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.m @@ -106,8 +106,8 @@ static void tests() { ok(pkiddata, "made string"); ok(CFEqualSafe(pkiddata, pkidseckey), "strings match"); - diag("pkiddata %@", pkiddata); - diag("retPref %@", retPref); + //diag("pkiddata %@", pkiddata); + //diag("retPref %@", retPref); CFReleaseNull(retHpub); CFReleaseNull(key); CFReleaseNull(pubKey); diff --git a/OSX/sec/securityd/Regressions/secd-70-engine-corrupt.c b/OSX/sec/securityd/Regressions/secd-70-engine-corrupt.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-70-engine-corrupt.c rename to OSX/sec/securityd/Regressions/secd-70-engine-corrupt.m diff --git a/OSX/sec/securityd/Regressions/secd-70-engine-smash.c b/OSX/sec/securityd/Regressions/secd-70-engine-smash.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-70-engine-smash.c rename to OSX/sec/securityd/Regressions/secd-70-engine-smash.m diff --git a/OSX/sec/securityd/Regressions/secd-70-engine.c b/OSX/sec/securityd/Regressions/secd-70-engine.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-70-engine.c rename to OSX/sec/securityd/Regressions/secd-70-engine.m index 58728a48..ac7aa29d 100644 --- a/OSX/sec/securityd/Regressions/secd-70-engine.c +++ b/OSX/sec/securityd/Regressions/secd-70-engine.m @@ -44,7 +44,7 @@ #include #include -static int kTestTestCount = 1306; +static int kTestTestCount = 2478; __unused static bool SOSCircleHandleCircleWithLock(SOSEngineRef engine, CFStringRef myID, CFDataRef message, CFErrorRef *error) { diff --git a/OSX/sec/securityd/Regressions/secd-70-otr-remote.c b/OSX/sec/securityd/Regressions/secd-70-otr-remote.m similarity index 91% rename from OSX/sec/securityd/Regressions/secd-70-otr-remote.c rename to OSX/sec/securityd/Regressions/secd-70-otr-remote.m index 64d52847..7da445b5 100644 --- a/OSX/sec/securityd/Regressions/secd-70-otr-remote.c +++ b/OSX/sec/securityd/Regressions/secd-70-otr-remote.m @@ -74,6 +74,7 @@ static void RegressionsLogError(CFErrorRef error) { static int kTestTestCount = 11; static void tests(void) { + NSError* ns_testError = nil; __block CFErrorRef testError = NULL; CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); @@ -93,8 +94,8 @@ static void tests(void) CFDictionaryRef alice_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice Device")); CFDictionaryRef bob_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Bob Device")); - SOSAccountRef alice_account = SOSAccountCreate(kCFAllocatorDefault, alice_gestalt, aliceDsf); - SOSAccountRef bob_account = SOSAccountCreate(kCFAllocatorDefault, bob_gestalt, bobDsf); + SOSAccount* alice_account = SOSAccountCreate(kCFAllocatorDefault, alice_gestalt, aliceDsf); + SOSAccount* bob_account = SOSAccountCreate(kCFAllocatorDefault, bob_gestalt, bobDsf); SOSAccountAssertUserCredentialsAndUpdate(alice_account, CFSTR("alice"), cfpassword, &testError); SOSAccountAssertUserCredentialsAndUpdate(bob_account, CFSTR("bob"), cfpassword, &testError); @@ -104,8 +105,8 @@ static void tests(void) SOSAccountJoinCircles_wTxn(alice_account, &testError); SOSAccountJoinCircles_wTxn(bob_account, &testError); - CFDataRef alice_account_data = SOSAccountCopyEncodedData(alice_account, kCFAllocatorDefault, &testError); - CFDataRef bob_account_data = SOSAccountCopyEncodedData(bob_account, kCFAllocatorDefault, &testError); + NSData* alice_account_data = [alice_account encodedData:&ns_testError]; + NSData* bob_account_data = [bob_account encodedData:&ns_testError];; CFArrayRef alice_peers = SOSAccountCopyPeers(alice_account, &testError); CFArrayRef bob_peers = SOSAccountCopyPeers(bob_account, &testError); @@ -122,13 +123,13 @@ static void tests(void) bool aliceReady = false; bool bobReady = false; - CFDataRef aliceSideSession = SecOTRSessionCreateRemote_internal(bob_account_data, bob_peer_external_form, alice_account_data, &testError); + CFDataRef aliceSideSession = SecOTRSessionCreateRemote_internal((__bridge CFDataRef) bob_account_data, bob_peer_external_form, (__bridge CFDataRef) alice_account_data, &testError); RegressionsLogError(testError); CFReleaseNull(testError); ok(aliceSideSession != NULL, "Make Alice side remote session"); - CFDataRef bobSideSession = SecOTRSessionCreateRemote_internal(alice_account_data, alice_peer_external_form, bob_account_data, &testError); + CFDataRef bobSideSession = SecOTRSessionCreateRemote_internal((__bridge CFDataRef) alice_account_data, alice_peer_external_form, (__bridge CFDataRef) bob_account_data, &testError); RegressionsLogError(testError); CFReleaseNull(testError); @@ -173,8 +174,6 @@ static void tests(void) RegressionsLogError(testError); CFReleaseNull(bob_peer_external_form); CFReleaseNull(alice_peer_external_form); - CFReleaseNull(alice_account_data); - CFReleaseNull(bob_account_data); CFReleaseNull(alice_peers); CFReleaseNull(bob_peers); CFReleaseNull(aliceSideSession); diff --git a/OSX/sec/securityd/Regressions/secd-71-engine-save.c b/OSX/sec/securityd/Regressions/secd-71-engine-save.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-71-engine-save.c rename to OSX/sec/securityd/Regressions/secd-71-engine-save.m index f7fd6701..2266ae2d 100644 --- a/OSX/sec/securityd/Regressions/secd-71-engine-save.c +++ b/OSX/sec/securityd/Regressions/secd-71-engine-save.m @@ -29,7 +29,7 @@ #include "secd_regressions.h" #include "SecdTestKeychainUtilities.h" -#include +#include #include #include #include diff --git a/OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.c b/OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.c rename to OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.m diff --git a/OSX/sec/securityd/Regressions/secd-75-engine-views.c b/OSX/sec/securityd/Regressions/secd-75-engine-views.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-75-engine-views.c rename to OSX/sec/securityd/Regressions/secd-75-engine-views.m diff --git a/OSX/sec/securityd/Regressions/secd-76-idstransport.c b/OSX/sec/securityd/Regressions/secd-76-idstransport.m similarity index 66% rename from OSX/sec/securityd/Regressions/secd-76-idstransport.c rename to OSX/sec/securityd/Regressions/secd-76-idstransport.m index 64c8e636..5ab0c1aa 100644 --- a/OSX/sec/securityd/Regressions/secd-76-idstransport.c +++ b/OSX/sec/securityd/Regressions/secd-76-idstransport.m @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -48,13 +49,15 @@ #include #include "SecdTestKeychainUtilities.h" -#include "SOSAccountTesting.h" -#include "SOSTransportTestTransports.h" +#import "SOSAccountTesting.h" +#import "SOSTransportTestTransports.h" #include #include #include "SOSTestDevice.h" -static int kTestTestCount = 92; + + +static int kTestTestCount = 90; static void tests() { @@ -64,9 +67,11 @@ static void tests() CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); CFStringRef cfaccount = CFSTR("test@test.org"); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("ak")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("ak")); - + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("ak")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("ak")); + SOSAccountTrustClassic *aliceTrust = alice_account.trust; + SOSAccountTrustClassic *bobTrust = bob_account.trust; + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); // Bob wins writing at this point, feed the changes back to alice. @@ -110,7 +115,7 @@ static void tests() CFIndex version = 0; // Optionally prefix each peer with name to make them more unique. - CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,SOSAccountGetMyPeerID(alice_account), SOSAccountGetMyPeerID(bob_account), NULL); + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); CFSetRef views = SOSViewsCopyTestV2Default(); CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFStringRef deviceID; @@ -125,12 +130,12 @@ static void tests() SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); - if(CFEqualSafe(deviceID, SOSAccountGetMyPeerID(alice_account))){ - alice_account->factory = device->dsf; + if(CFEqualSafe(deviceID, (__bridge CFTypeRef)(alice_account.peerID))){ + alice_account.factory = device->dsf; SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); } else{ - bob_account->factory = device->dsf; + bob_account.factory = device->dsf; SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); } CFReleaseNull(device); @@ -140,56 +145,57 @@ static void tests() SOSUnregisterAllTransportMessages(); CFArrayRemoveAllValues(message_transports); + + alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:SOSCircleGetName(aliceTrust.trustedCircle) err:&error]; + + + bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:SOSCircleGetName(bobTrust.trustedCircle) err:&error]; + ok(alice_account.ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); + ok(bob_account.ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); - alice_account->ids_message_transport = (SOSTransportMessageRef)SOSTransportMessageIDSTestCreate(alice_account, CFSTR("Alice"), SOSCircleGetName(alice_account->trusted_circle), &error); - bob_account->ids_message_transport = (SOSTransportMessageRef)SOSTransportMessageIDSTestCreate(bob_account, CFSTR("Bob"), SOSCircleGetName(bob_account->trusted_circle), &error); - - ok(alice_account->ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); - ok(bob_account->ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); - - bool result = SOSAccountModifyCircle(alice_account, &error, ^bool(SOSCircleRef circle) { + bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^(SOSCircleRef circle) { CFErrorRef localError = NULL; - SOSFullPeerInfoUpdateTransportType(alice_account->my_identity, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(alice_account->my_identity, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(alice_account->my_identity, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(alice_account->my_identity, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); - return SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(alice_account->my_identity), NULL); - }); + return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL); + }]; ok(result, "Alice account update circle with transport type"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - result = SOSAccountModifyCircle(bob_account, &error, ^bool(SOSCircleRef circle) { + result &= [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^(SOSCircleRef circle) { CFErrorRef localError = NULL; - SOSFullPeerInfoUpdateTransportType(bob_account->my_identity, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(bob_account->my_identity, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(bob_account->my_identity, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(bob_account->my_identity, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); - return SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), NULL); - }); + return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL); + }]; ok(result, "Bob account update circle with transport type"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(alice_account)); - CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(bob_account)); + CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo); + CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo); ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS"); ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS"); CFReleaseNull(alice_transportType); CFReleaseNull(bob_accountTransportType); - SOSTransportMessageIDSTestSetName(alice_account->ids_message_transport, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSTestGetName(alice_account->ids_message_transport) != NULL, "retrieved getting account name"); + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); - - SOSTransportMessageIDSTestSetName(bob_account->ids_message_transport, CFSTR("Bob Account")); - ok(SOSTransportMessageIDSTestGetName(bob_account->ids_message_transport) != NULL, "retrieved getting account name"); + + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name"); ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("Alice"),&error), "Setting IDS device ID"); @@ -202,8 +208,8 @@ static void tests() is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 3, "updates"); - SOSTransportMessageIDSTestSetName(alice_account->ids_message_transport, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSTestGetName(alice_account->ids_message_transport) != NULL, "retrieved getting account name"); + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); ok(SOSAccountSetMyDSID_wTxn(alice_account, CFSTR("DSID"),&error), "Setting IDS device ID"); @@ -212,11 +218,11 @@ static void tests() CFReleaseNull(dsid); ok(SOSAccountStartPingTest(alice_account, CFSTR("hai there!"), &error), "Ping test"); - ok(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(alice_account->ids_message_transport)) != 0, "ping message made it to transport"); - SOSTransportMessageIDSTestClearChanges(alice_account->ids_message_transport); + ok(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) != 0, "ping message made it to transport"); + SOSTransportMessageIDSTestClearChanges((SOSMessageIDSTest*)alice_account.ids_message_transport); ok(SOSAccountSendIDSTestMessage(alice_account, CFSTR("hai again!"), &error), "Send Test Message"); - ok(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(alice_account->ids_message_transport)) != 0, "ping message made it to transport"); + ok(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) != 0, "ping message made it to transport"); CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII); CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII); @@ -224,21 +230,23 @@ static void tests() //test IDS message handling CFMutableDictionaryRef messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending empty message dictionary"); + + ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] + == kHandleIDSMessageDontHandle, "sending empty message dictionary"); CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending device ID only"); + ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending device ID only"); CFReleaseNull(messageDict); messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending peer ID only"); - + ok([alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending peer ID only"); + CFReleaseNull(messageDict); messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFDataRef data = CFDataCreate(kCFAllocatorDefault, 0, 0); CFDictionaryAddValue(messageDict, dataKey, data); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending data only"); + ok( [alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending data only"); CFReleaseNull(messageDict); CFReleaseNull(data); @@ -246,7 +254,7 @@ static void tests() data = CFDataCreate(kCFAllocatorDefault, 0, 0); CFDictionaryAddValue(messageDict, dataKey, data); CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending data and peerid only"); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending data and peerid only"); CFReleaseNull(messageDict); CFReleaseNull(data); @@ -254,14 +262,14 @@ static void tests() data = CFDataCreate(kCFAllocatorDefault, 0, 0); CFDictionaryAddValue(messageDict, dataKey, data); CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending data and deviceid only"); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending data and deviceid only"); CFReleaseNull(messageDict); CFReleaseNull(data); messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending peerid and deviceid only"); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error] == kHandleIDSMessageDontHandle, "sending peerid and deviceid only"); CFReleaseNull(messageDict); CFReleaseNull(data); @@ -269,8 +277,8 @@ static void tests() data = CFDataCreate(kCFAllocatorDefault, 0, 0); CFDictionaryAddValue(messageDict, dataKey, data); CFDictionaryAddValue(messageDict, deviceIDKey, CFSTR("Alice Account")); - CFDictionaryAddValue(messageDict, sendersPeerIDKey, SOSPeerInfoGetPeerID(SOSAccountGetMyPeerInfo(bob_account))); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending peerid and deviceid and data"); + CFDictionaryAddValue(messageDict, sendersPeerIDKey, SOSPeerInfoGetPeerID(bob_account.peerInfo)); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending peerid and deviceid and data"); CFReleaseNull(messageDict); CFReleaseNull(data); @@ -278,19 +286,17 @@ static void tests() messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); data = CFDataCreate(kCFAllocatorDefault, 0, 0); CFDictionaryAddValue(messageDict, dataKey, data); - CFStringRef BobDeviceID = SOSPeerInfoCopyDeviceID(SOSAccountGetMyPeerInfo(bob_account)); + CFStringRef BobDeviceID = SOSPeerInfoCopyDeviceID(bob_account.peerInfo); CFDictionaryAddValue(messageDict, deviceIDKey, BobDeviceID); CFReleaseNull(BobDeviceID); CFDictionaryAddValue(messageDict, sendersPeerIDKey, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSHandleMessage(alice_account, messageDict, &error) == kHandleIDSMessageDontHandle, "sending peerid and deviceid and data"); + ok([(SOSMessageIDS*)alice_account.ids_message_transport SOSTransportMessageIDSHandleMessage:alice_account m:messageDict err:&error]== kHandleIDSMessageDontHandle, "sending peerid and deviceid and data"); CFReleaseNull(data); CFReleaseNull(dataKey); CFReleaseNull(deviceIDKey); CFReleaseNull(sendersPeerIDKey); - CFReleaseNull(alice_account); - CFReleaseNull(bob_account); CFReleaseNull(alice_dsid); CFReleaseNull(bob_dsid); CFReleaseNull(changes); diff --git a/OSX/sec/securityd/Regressions/secd-80-views-alwayson.c b/OSX/sec/securityd/Regressions/secd-80-views-alwayson.m similarity index 85% rename from OSX/sec/securityd/Regressions/secd-80-views-alwayson.c rename to OSX/sec/securityd/Regressions/secd-80-views-alwayson.m index d786ddc9..2d8337b4 100644 --- a/OSX/sec/securityd/Regressions/secd-80-views-alwayson.c +++ b/OSX/sec/securityd/Regressions/secd-80-views-alwayson.m @@ -38,19 +38,16 @@ #include "SOSAccountTesting.h" #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 46; - - -static void testView(SOSAccountRef account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) { +static void testView(SOSAccount* account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) { CFErrorRef error = NULL; SOSViewResultCode vcode = 9999; switch(action) { case kSOSCCViewQuery: - vcode = SOSAccountViewStatus(account, view, &error); + vcode = [account.trust viewStatus:account name:view err:&error]; break; case kSOSCCViewEnable: case kSOSCCViewDisable: // fallthrough - vcode = SOSAccountUpdateView(account, view, action, &error); + vcode = [account.trust updateView:account name:view code:action err:&error]; break; default: break; @@ -75,24 +72,24 @@ static void alwaysOnTest() CFStringRef cfaccount = CFSTR("test@test.org"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); // 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"); - + CFReleaseNull(cfpassword); + testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected view capability for kSOSViewContinuityUnlock"); testView(alice_account, kSOSCCViewNotMember, kSOSViewContinuityUnlock, kSOSCCViewDisable, "Expected to disable kSOSViewContinuityUnlock"); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpasswordNew, NULL), "Bob changes the password"); testView(alice_account, kSOSCCViewNotMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected kSOSViewContinuityUnlock is off for alice still"); ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpasswordNew, NULL), "Alice sets the new password"); + CFReleaseNull(cfpasswordNew); testView(alice_account, kSOSCCViewMember, kSOSViewContinuityUnlock, kSOSCCViewQuery, "Expected view capability for kSOSViewContinuityUnlock"); - CFReleaseNull(alice_account); - CFReleaseNull(bob_account); CFReleaseNull(changes); SOSTestCleanup(); @@ -100,7 +97,7 @@ static void alwaysOnTest() int secd_80_views_alwayson(int argc, char *const *argv) { - plan_tests(kTestTestCount); + plan_tests(44); secd_test_setup_temp_keychain(__FUNCTION__, NULL); alwaysOnTest(); diff --git a/OSX/sec/securityd/Regressions/secd-80-views-basic.c b/OSX/sec/securityd/Regressions/secd-80-views-basic.m similarity index 86% rename from OSX/sec/securityd/Regressions/secd-80-views-basic.c rename to OSX/sec/securityd/Regressions/secd-80-views-basic.m index 9887f572..f81f7fba 100644 --- a/OSX/sec/securityd/Regressions/secd-80-views-basic.c +++ b/OSX/sec/securityd/Regressions/secd-80-views-basic.m @@ -56,16 +56,16 @@ #include "SOSAccountTesting.h" -static void testView(SOSAccountRef account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) { +static void testView(SOSAccount* account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) { CFErrorRef error = NULL; SOSViewResultCode vcode = 9999; switch(action) { case kSOSCCViewQuery: - vcode = SOSAccountViewStatus(account, view, &error); + vcode = [account.trust viewStatus:account name:view err:&error]; break; case kSOSCCViewEnable: case kSOSCCViewDisable: // fallthrough - vcode = SOSAccountUpdateView(account, view, action, &error); + vcode = [account.trust updateView:account name:view code:action err:&error]; break; default: break; @@ -82,10 +82,10 @@ static void testViewLists(void) { CFSetRef backupRequiredViews = SOSViewCopyViewSet(kViewSetRequiredForBackup); CFSetRef V0Views = SOSViewCopyViewSet(kViewSetV0); - is(CFSetGetCount(allViews), 22, "make sure count of allViews is correct"); - is(CFSetGetCount(defaultViews), 18, "make sure count of defaultViews is correct"); + is(CFSetGetCount(allViews), 24, "make sure count of allViews is correct"); + is(CFSetGetCount(defaultViews), 20, "make sure count of defaultViews is correct"); is(CFSetGetCount(initialViews), 14, "make sure count of initialViews is correct"); - is(CFSetGetCount(alwaysOnViews), 18, "make sure count of alwaysOnViews is correct"); + is(CFSetGetCount(alwaysOnViews), 20, "make sure count of alwaysOnViews is correct"); is(CFSetGetCount(backupRequiredViews), 3, "make sure count of backupRequiredViews is correct"); is(CFSetGetCount(V0Views), 6, "make sure count of V0Views is correct"); @@ -109,7 +109,7 @@ static void tests(void) SOSDataSourceRef test_source = SOSTestDataSourceCreate(); SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - SOSAccountRef account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); + SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); CFReleaseNull(error); @@ -142,29 +142,25 @@ static void tests(void) testView(account, kSOSCCViewMember, kSOSViewPCSiCloudDrive, kSOSCCViewQuery, "Expected view capability for kSOSViewPCSiCloudDrive"); testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected view capability for kSOSViewKeychainV0"); testView(account, kSOSCCViewMember, kSOSViewAppleTV, kSOSCCViewQuery, "Expected view capability for kSOSViewAppleTV"); - - ok(SOSAccountUpdateViewSets(account, SOSViewsGetV0ViewSet(), nullSet), "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(SOSAccountUpdateViewSets(account, SOSViewsGetV0ViewSet(), nullSet), "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 = SOSAccountGetMyPeerInfo(account); + SOSPeerInfoRef pi = account.peerInfo; ok(pi, "should have the peerInfo"); SOSViewResultCode vr = SOSViewsEnable(pi, kSOSViewKeychainV0, NULL); ok(vr == kSOSCCViewMember, "Set Virtual View manually"); - ok(!SOSAccountUpdateViewSets(account, nullSet, SOSViewsGetV0ViewSet()), "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(!SOSAccountUpdateViewSets(account, nullSet, SOSViewsGetV0ViewSet()), "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"); - - - CFReleaseNull(account); - SOSDataSourceRelease(test_source, NULL); SOSDataSourceFactoryRelease(test_factory); diff --git a/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.c b/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-81-item-acl-stress.c rename to OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m index 99d49c19..54163ddc 100644 --- a/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.c +++ b/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m @@ -62,7 +62,7 @@ static bool changePasscode(const char *old_passcode, const char *new_passcode) if (new_passcode) new_passcode_len = strlen(new_passcode); - kern_return_t status = aks_change_secret(test_keybag, old_passcode, (int)old_passcode_len, new_passcode, (int)new_passcode_len, NULL, NULL); + kern_return_t status = aks_change_secret(test_keybag, old_passcode, (int)old_passcode_len, new_passcode, (int)new_passcode_len, generation_noop, NULL); return status == 0; } #endif diff --git a/OSX/sec/securityd/Regressions/secd-81-item-acl.c b/OSX/sec/securityd/Regressions/secd-81-item-acl.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-81-item-acl.c rename to OSX/sec/securityd/Regressions/secd-81-item-acl.m index bdd5209d..a1fb2dae 100644 --- a/OSX/sec/securityd/Regressions/secd-81-item-acl.c +++ b/OSX/sec/securityd/Regressions/secd-81-item-acl.m @@ -49,7 +49,7 @@ static bool changePasscode(const char *old_passcode, const char *new_passcode) if (new_passcode) new_passcode_len = strlen(new_passcode); - kern_return_t status = aks_change_secret(test_keybag, old_passcode, (int)old_passcode_len, new_passcode, (int)new_passcode_len, NULL, NULL); + kern_return_t status = aks_change_secret(test_keybag, old_passcode, (int)old_passcode_len, new_passcode, (int)new_passcode_len, generation_noop, NULL); return status == 0; } @@ -434,7 +434,7 @@ static void item_with_akpu(uint32_t *item_num) ok_status(SecItemCopyMatching(item, NULL), "find item with akpu"); changePasscode(passcode1, NULL); is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find item with akpu"); - is_status(SecItemAdd(item, NULL), errSecAuthFailed, "cannot add item with akpu without passcode"); + is_status(SecItemAdd(item, NULL), errSecNotAvailable, "cannot add item with akpu without passcode"); changePasscode(NULL, passcode2); is_status(SecItemCopyMatching(item, NULL), errSecItemNotFound, "do not find item with akpu"); ok_status(SecItemAdd(item, NULL), "add item with akpu"); diff --git a/OSX/sec/securityd/Regressions/secd-82-persistent-ref.c b/OSX/sec/securityd/Regressions/secd-82-persistent-ref.m similarity index 71% rename from OSX/sec/securityd/Regressions/secd-82-persistent-ref.c rename to OSX/sec/securityd/Regressions/secd-82-persistent-ref.m index 6099f335..3d033767 100644 --- a/OSX/sec/securityd/Regressions/secd-82-persistent-ref.c +++ b/OSX/sec/securityd/Regressions/secd-82-persistent-ref.m @@ -8,6 +8,7 @@ #include #include +#include #include "secd_regressions.h" #include "SecdTestKeychainUtilities.h" @@ -19,13 +20,13 @@ int secd_82_persistent_ref(int argc, char *const *argv) /* custom keychain dir */ secd_test_setup_temp_keychain("secd_82_persistent_ref", NULL); - CFMutableDictionaryRef attrs; - CFMutableDictionaryRef query; - CFDataRef data; - CFTypeRef result; - CFArrayRef array; + CFMutableDictionaryRef attrs = NULL; + CFMutableDictionaryRef query = NULL; + CFDataRef data = NULL; + CFTypeRef result = NULL; + CFArrayRef array = NULL; CFIndex i, n; - CFDictionaryRef item; + CFDictionaryRef item = NULL; attrs = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); CFDictionarySetValue( attrs, kSecClass, kSecClassGenericPassword ); @@ -36,10 +37,10 @@ int secd_82_persistent_ref(int argc, char *const *argv) CFDictionarySetValue( attrs, kSecAttrService, CFSTR( "TestService" ) ); data = CFDataCreate( NULL, (const uint8_t *) "\x00\x01\x02", 3 ); CFDictionarySetValue( attrs, kSecValueData, data ); - CFRelease( data ); + CFReleaseNull( data ); is(SecItemAdd(attrs, NULL), errSecSuccess); - CFRelease( attrs ); + CFReleaseNull( attrs ); query = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); CFDictionarySetValue( query, kSecClass, kSecClassGenericPassword ); @@ -50,18 +51,21 @@ int secd_82_persistent_ref(int argc, char *const *argv) CFDictionarySetValue( query, kSecMatchLimit, kSecMatchLimitAll ); is(SecItemCopyMatching(query, &result), errSecSuccess); - CFRelease( query ); + CFReleaseNull( query ); array = (CFArrayRef) result; - n = CFArrayGetCount( array ); - is(n, 1); - for( i = 0; i < n; ++i ) - { - item = (CFDictionaryRef) CFArrayGetValueAtIndex(array, i); + SKIP: { + skip("No results from SecItemCopyMatching", 2, array && (CFArrayGetTypeID() == CFGetTypeID(array))); + n = CFArrayGetCount( array ); + is(n, 1); + for( i = 0; i < n; ++i ) + { + item = (CFDictionaryRef) CFArrayGetValueAtIndex(array, i); - ok((CFDataRef) CFDictionaryGetValue(item, kSecValuePersistentRef)); + ok((CFDataRef) CFDictionaryGetValue(item, kSecValuePersistentRef)); + } } - CFRelease( result ); + CFReleaseNull( result ); return 0; diff --git a/OSX/sec/securityd/Regressions/secd-82-secproperties-basic.c b/OSX/sec/securityd/Regressions/secd-82-secproperties-basic.m similarity index 90% rename from OSX/sec/securityd/Regressions/secd-82-secproperties-basic.c rename to OSX/sec/securityd/Regressions/secd-82-secproperties-basic.m index 8f6b7188..791024ca 100644 --- a/OSX/sec/securityd/Regressions/secd-82-secproperties-basic.c +++ b/OSX/sec/securityd/Regressions/secd-82-secproperties-basic.m @@ -63,16 +63,16 @@ #include "SOSAccountTesting.h" -static void testSecurityProperties(SOSAccountRef account, SOSSecurityPropertyResultCode expected, CFStringRef property, SOSSecurityPropertyActionCode action, char *label) { +static void testSecurityProperties(SOSAccount* account, SOSSecurityPropertyResultCode expected, CFStringRef property, SOSSecurityPropertyActionCode action, char *label) { CFErrorRef error = NULL; SOSSecurityPropertyResultCode pcode = 9999; switch(action) { case kSOSCCSecurityPropertyQuery: - pcode = SOSAccountSecurityPropertyStatus(account, property, &error); + pcode = [account.trust SecurityPropertyStatus:property err:&error]; break; case kSOSCCSecurityPropertyEnable: case kSOSCCSecurityPropertyDisable: // fallthrough - pcode = SOSAccountUpdateSecurityProperty(account, property, action, &error); + pcode = [account.trust UpdateSecurityProperty:account property:property code:action err:&error]; break; default: break; @@ -92,7 +92,7 @@ static void tests(void) SOSDataSourceRef test_source = SOSTestDataSourceCreate(); SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - SOSAccountRef account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); + SOSAccount* account = CreateAccountForLocalChanges(CFSTR("Test Device"),CFSTR("TestType") ); ok(SOSAccountAssertUserCredentialsAndUpdate(account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); CFReleaseNull(error); @@ -111,9 +111,6 @@ static void tests(void) testSecurityProperties(account, kSOSCCSecurityPropertyNotValid, kSOSSecPropertyIOS, kSOSCCSecurityPropertyDisable, "Expected to disable property: kSOSSecPropertyIOS"); testSecurityProperties(account, kSOSCCSecurityPropertyNotValid, kSOSSecPropertyIOS, kSOSCCSecurityPropertyQuery, "Expected no property: kSOSSecPropertyIOS"); testSecurityProperties(account, kSOSCCNoSuchSecurityProperty, CFSTR("FOO"), kSOSCCSecurityPropertyQuery, "Expected no such property for FOO"); - - CFReleaseNull(account); - SOSDataSourceRelease(test_source, NULL); SOSDataSourceFactoryRelease(test_factory); diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match-policy.m b/OSX/sec/securityd/Regressions/secd-83-item-match-policy.m index 00448438..76040252 100644 --- a/OSX/sec/securityd/Regressions/secd-83-item-match-policy.m +++ b/OSX/sec/securityd/Regressions/secd-83-item-match-policy.m @@ -87,6 +87,7 @@ static void test(id returnKeyName) { ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecMatchLimit : (id)kSecMatchLimitAll, (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, returnKeyName : @YES }, &result)); ok(result && CFArrayGetCount(result) == 2); CFReleaseNull(policy); @@ -101,6 +102,7 @@ static void test(id returnKeyName) { ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecMatchLimit : (id)kSecMatchLimitAll, (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, returnKeyName : @YES }, &result)); ok(result && CFArrayGetCount(result) == 1); CFReleaseNull(result); @@ -135,6 +137,7 @@ static void test(id returnKeyName) { ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecMatchLimit : (id)kSecMatchLimitAll, (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, returnKeyName : @YES }, &result)); ok(result && CFArrayGetCount(result) == 2); CFReleaseNull(policy); @@ -149,6 +152,7 @@ static void test(id returnKeyName) { ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecMatchLimit : (id)kSecMatchLimitAll, (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, returnKeyName : @YES }, &result)); ok(result && CFArrayGetCount(result) == 1); CFReleaseNull(result); @@ -185,6 +189,7 @@ static void test(id returnKeyName) { ok_status(SecItemCopyMatching( (__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassCertificate, (id)kSecMatchLimit : (id)kSecMatchLimitAll, (id)kSecMatchPolicy : (__bridge id)policy, + (id)kSecMatchValidOnDate : validDate, returnKeyName : @YES }, &result)); ok(result && CFArrayGetCount(result) == 2); CFReleaseNull(result); diff --git a/OSX/sec/securityd/Regressions/secd-90-hsa2.c b/OSX/sec/securityd/Regressions/secd-90-hsa2.c deleted file mode 100644 index 8c31c8f6..00000000 --- a/OSX/sec/securityd/Regressions/secd-90-hsa2.c +++ /dev/null @@ -1,159 +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 -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "secd_regressions.h" -#include "SOSTestDataSource.h" - -#include "SOSRegressionUtilities.h" -#include -#include - -#include - -#include "SOSAccountTesting.h" - -#include "SecdTestKeychainUtilities.h" - -static int kTestTestCount = 75; - - -static bool SOSTestAcceptApplicant(SOSAccountRef acceptor, CFIndex appsExpected, CFErrorRef *error) { - bool retval = true; - CFArrayRef applicants = SOSAccountCopyApplicants(acceptor, error); - CFStringRef acceptorName = SOSAccountCopyName(acceptor); - - ok(applicants && CFArrayGetCount(applicants) == appsExpected, "See %ld applicant %@ (%@)", appsExpected, applicants, *error); - if(CFArrayGetCount(applicants) != appsExpected) retval = false; - ok(retval && (retval = SOSAccountAcceptApplicants(acceptor, applicants, error)), "%@ accepts (%@)", acceptorName, *error); - CFReleaseNull(*error); - CFReleaseNull(applicants); - CFReleaseNull(acceptorName); - - return retval; -} - -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); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carol"), CFSTR("TestSource")); - - ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - - // Bob wins writing at this point, feed the changes back to alice. - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(error); - - ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - ok(SOSTestAcceptApplicant(alice_account, 1, &error), "Alice Accepts"); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); - - accounts_agree("bob&alice pair", bob_account, alice_account); - - ok(SOSAccountLeaveCircle(alice_account, &error)); - CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); - - ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); - CFReleaseNull(cfpassword); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); - - SOSAccountTransactionRef txn = SOSAccountTransactionCreate(carole_account); - - SOSPeerInfoRef carole_pi = SOSAccountCopyApplication(carole_account, &error); - ok(carole_pi != NULL, "Got Carole's Application PeerInfo"); - CFReleaseNull(error); - - SOSAccountTransactionFinish(txn); - CFReleaseNull(txn); - - SOSAccountPurgePrivateCredential(bob_account); - - CFDataRef bobBlob = SOSAccountCopyCircleJoiningBlob(bob_account, carole_pi, &error); - ok(bobBlob != NULL, "Got Piggy Back Blob from Bob"); - CFReleaseNull(error); - - ok(SOSAccountJoinWithCircleJoiningBlob(carole_account, bobBlob, &error), "Carole joins circle through piggy backing: %@", error); - CFReleaseNull(error); - CFReleaseNull(bobBlob); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "Settle Circle"); - - ok(!SOSAccountIsInCircle(alice_account, NULL), "Alice still retired"); - ok(SOSAccountIsInCircle(bob_account, NULL), "Bob still here"); - ok(SOSAccountIsInCircle(carole_account, NULL), "carol still here"); - - ok(!SOSAccountCheckHasBeenInSync_wTxn(carole_account), "Carol not in sync"); - - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); - - SOSTestCleanup(); -} - - -int secd_90_hsa2(int argc, char *const *argv) -{ - plan_tests(kTestTestCount); - - secd_test_setup_temp_keychain(__FUNCTION__, NULL); - - tests(); - - return 0; -} diff --git a/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.c b/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m similarity index 87% rename from OSX/sec/securityd/Regressions/secd-95-escrow-persistence.c rename to OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m index 96409733..17167bd7 100644 --- a/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.c +++ b/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m @@ -49,8 +49,6 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 63; - static void tests(void) { CFErrorRef error = NULL; @@ -60,8 +58,8 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -112,7 +110,7 @@ static void tests(void) CFMutableDictionaryRef record = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); CFDictionaryAddValue(record, CFSTR("12345"), escrowRecord); - SOSFullPeerInfoRef alice_fpi = SOSAccountGetMyFullPeerInfo(alice_account); + SOSFullPeerInfoRef alice_fpi = alice_account.fullPeerInfo; ok(SOSFullPeerInfoAddEscrowRecord(alice_fpi, CFSTR("12345"), escrowRecord, &error), "Adding Escrow records to Alice FPI(%@)", error); CFDictionaryRef fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(alice_fpi)); ok(CFEqualSafe(CFDictionaryGetValue(fpi_escrow, CFSTR("12345")), escrowRecord), "Alice's FPI has escrow (%@)", error); @@ -122,11 +120,13 @@ static void tests(void) fpi_escrow = (CFDictionaryRef)SOSAccountGetValue(bob_account, kSOSEscrowRecord, NULL); ok(CFEqualSafe(CFDictionaryGetValue(fpi_escrow, CFSTR("12345")), escrowRecord), "Bob has escrow records in account (%@)", error); - - ok(SOSAccountResetToEmpty(alice_account, &error), "Reset to offering (%@)", error); + ok(SOSAccountHasPublicKey(alice_account, &error), "Has Public Key" ); + + ok([alice_account.trust resetAccountToEmpty:alice_account transport:alice_account.circle_transport err:&error], "Reset to offering (%@)", error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); + ok(SOSAccountHasPublicKey(bob_account, &error), "Has Public Key" ); - ok(SOSAccountResetToEmpty(bob_account, &error), "Reset to offering (%@)", error); + ok([bob_account.trust resetAccountToEmpty:bob_account transport:bob_account.circle_transport err:&error], "Reset to offering (%@)", error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); ok(SOSAccountAddEscrowRecords(bob_account, CFSTR("12345"), escrowRecord, &error), "Adding escrow to Bob's account (%@)", error); @@ -134,13 +134,14 @@ static void tests(void) ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - CFDictionaryRef bob_fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(bob_account->my_identity)); + SOSAccountTrustClassic *bobTrust = bob_account.trust; + CFDictionaryRef bob_fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(bobTrust.fullPeerInfo)); ok(bob_fpi_escrow == NULL, "Bob's FPI escrow should be null"); CFReleaseNull(bob_fpi_escrow); ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); - bob_fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(bob_account->my_identity)); - ok(CFEqualSafe(CFDictionaryGetValue(bob_fpi_escrow, CFSTR("12345")), escrowRecord), "Bob has escrow records in account (%@)", error); + bob_fpi_escrow = SOSPeerInfoCopyEscrowRecord(SOSFullPeerInfoGetPeerInfo(bobTrust.fullPeerInfo)); + ok(bob_fpi_escrow && CFEqualSafe(CFDictionaryGetValue(bob_fpi_escrow, CFSTR("12345")), escrowRecord), "Bob has escrow records in account (%@)", error); CFReleaseNull(bob_fpi_escrow); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); @@ -161,11 +162,13 @@ static void tests(void) CFReleaseNull(escrowRecord); CFReleaseNull(timeDescription); CFReleaseNull(attempts); + SOSTestCleanup(); + } int secd_95_escrow_persistence(int argc, char *const *argv) { - plan_tests(kTestTestCount); + plan_tests(63); secd_test_setup_temp_keychain(__FUNCTION__, NULL); diff --git a/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.c b/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m similarity index 78% rename from OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.c rename to OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m index 4b197a14..23a59fb4 100644 --- a/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.c +++ b/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -56,41 +58,40 @@ #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 58; +static int kTestTestCount = 56; -static bool SOSAccountResetCircleToNastyOffering(SOSAccountRef account, SecKeyRef userPriv, SOSPeerInfoRef pi, CFErrorRef *error) { +static bool SOSAccountResetCircleToNastyOffering(SOSAccount* account, SecKeyRef userPriv, SOSPeerInfoRef pi, CFErrorRef *error) { bool result = false; SecKeyRef userPub = SecKeyCreatePublicFromPrivate(userPriv); + SOSAccountTrustClassic *trust = account.trust; + if(!SOSAccountHasCircle(account, error)){ + return result; + } + if(![account.trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(account.gestalt) deviceID:(__bridge CFStringRef)(account.deviceID) backupKey:(__bridge CFDataRef)(account.backup_key) err:error]){ + return result; + } + (void) [account.trust resetAllRings:account err:error]; - require(SOSAccountHasCircle(account, error), fail); - require(SOSAccountEnsureFullPeerAvailable(account, error), fail); - - // Save for reclaming - //mygestalt = CFDictionaryCreateCopy(kCFAllocatorDefault, SOSPeerGetGestalt(SOSFullPeerInfoGetPeerInfo(account->my_identity))); - - (void) SOSAccountResetAllRings(account, error); - - SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle) { + [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { bool result = false; CFErrorRef localError = NULL; SOSFullPeerInfoRef iCloudfpi = NULL; //sleep(10); require_quiet(SOSCircleResetToEmpty(circle, error), err_out); - require_quiet(SOSAccountAddiCloudIdentity(account, circle, userPriv, error), err_out); + require_quiet([account.trust addiCloudIdentity:circle key:userPriv err:error], err_out); require_quiet(iCloudfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, error), err_out); /* Add the defenders peerInfo to circle */ require_quiet(SOSCircleRequestReadmission(circle, userPub, pi, error), err_out); require_quiet(SOSCircleAcceptRequest(circle, userPriv, iCloudfpi, pi, error), err_out); - account->departure_code = kSOSNeverLeftCircle; - + [trust setDepartureCode:kSOSNeverLeftCircle]; result = true; - account->trusted_circle = SOSCircleCopyCircle(kCFAllocatorDefault, circle, error); + [trust setTrustedCircle:SOSCircleCopyCircle(kCFAllocatorDefault, circle, error)]; SOSAccountPublishCloudParameters(account, NULL); - account->my_identity = NULL; - + trust.fullPeerInfo = nil; + err_out: if (result == false) secerror("error resetting circle (%@) to offering: %@", circle, localError); @@ -100,32 +101,33 @@ static bool SOSAccountResetCircleToNastyOffering(SOSAccountRef account, SecKeyRe } CFReleaseNull(localError); return result; - }); + }]; result = true; -fail: return result; } -static bool SOSAccountResetToNastyOffering(SOSAccountRef account, SOSPeerInfoRef pi, CFErrorRef* error) { +static bool SOSAccountResetToNastyOffering(SOSAccount* account, SOSPeerInfoRef pi, CFErrorRef* error) { SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); if (!user_key) return false; - - CFReleaseNull(account->my_identity); - + + SOSAccountTrustClassic* trust = account.trust; + trust.fullPeerInfo = nil; + return user_key && SOSAccountResetCircleToNastyOffering(account, user_key, pi, error); } -static bool performiCloudIdentityAttack(SOSAccountRef attacker, SOSAccountRef defender, SOSAccountRef accomplice, CFMutableDictionaryRef changes) { +static bool performiCloudIdentityAttack(SOSAccount* attacker, SOSAccount* defender, SOSAccount* accomplice, CFMutableDictionaryRef changes) { CFErrorRef error = NULL; bool retval = false; // false means the attack succeeds CFArrayRef applicants = NULL; - + SOSAccountTrustClassic* defenderTrust = defender.trust; + /*----- Carole makes bogus circle with fake iCloud identity and Alice's peerInfo but only signed with fake iCloud identity -----*/ - require_action_quiet(SOSAccountResetToNastyOffering(attacker, SOSFullPeerInfoGetPeerInfo(defender->my_identity), &error), testDone, retval = true); + require_action_quiet(SOSAccountResetToNastyOffering(attacker, defenderTrust.peerInfo, &error), testDone, retval = true); CFReleaseNull(error); ProcessChangesUntilNoChange(changes, defender, accomplice, attacker, NULL); @@ -168,9 +170,9 @@ static void tests(void) CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - SOSAccountRef alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); - SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); + SOSAccount* alice_account = CreateAccountForLocalChanges( CFSTR("Alice"), CFSTR("TestSource")); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource")); + SOSAccount* carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), CFSTR("TestSource")); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -207,11 +209,9 @@ static void tests(void) ok(performiCloudIdentityAttack(carole_account, alice_account, bob_account, changes), "Attack is defeated"); - CFReleaseNull(bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(carole_account); CFReleaseNull(cfpassword); - + alice_account = nil; + bob_account = nil; SOSTestCleanup(); } diff --git a/OSX/sec/securityd/Regressions/secd_77_ids_messaging.c b/OSX/sec/securityd/Regressions/secd_77_ids_messaging.m similarity index 66% rename from OSX/sec/securityd/Regressions/secd_77_ids_messaging.c rename to OSX/sec/securityd/Regressions/secd_77_ids_messaging.m index 8f0eb989..862be40d 100644 --- a/OSX/sec/securityd/Regressions/secd_77_ids_messaging.c +++ b/OSX/sec/securityd/Regressions/secd_77_ids_messaging.m @@ -48,37 +48,40 @@ #include #include "SecdTestKeychainUtilities.h" #include "SOSAccountTesting.h" -#include "SOSTransportTestTransports.h" +#import "SOSTransportTestTransports.h" #include "SOSTestDevice.h" #include "SOSTestDataSource.h" #include +#include -static int kTestTestCount = 114; - -static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account, CFStringRef peerID) { - SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(account->my_identity); +static bool SOSAccountIsThisPeerIDMe(SOSAccount* account, CFStringRef peerID) { + SOSAccountTrustClassic* trust = account.trust; + SOSPeerInfoRef mypi = trust.peerInfo; CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi); return myPeerID && CFEqualSafe(myPeerID, peerID); } -static void ids_test_sync(SOSAccountRef alice_account, SOSAccountRef bob_account){ +static void ids_test_sync(SOSAccount* alice_account, SOSAccount* bob_account){ CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); __block bool SyncingCompletedOverIDS = false; __block CFErrorRef localError = NULL; __block bool done = false; + SOSAccountTrustClassic* aliceTrust = alice_account.trust; + SOSAccountTrustClassic* bobTrust = bob_account.trust; + do{ - SOSCircleForEachValidPeer(alice_account->trusted_circle, alice_account->user_public, ^(SOSPeerInfoRef peer) { + SOSCircleForEachValidPeer(aliceTrust.trustedCircle, alice_account.accountKey, ^(SOSPeerInfoRef peer) { if (!SOSAccountIsThisPeerIDMe(alice_account, SOSPeerInfoGetPeerID(peer))) { - if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(alice_account->my_identity), peer) && - SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(alice_account->my_identity), peer)){ + if(SOSPeerInfoShouldUseIDSTransport(aliceTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(aliceTrust.peerInfo, peer)){ secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); - SyncingCompletedOverIDS = SOSTransportMessageSyncWithPeers(alice_account->ids_message_transport, ids, &localError); + SyncingCompletedOverIDS = [alice_account.ids_message_transport SOSTransportMessageSyncWithPeers:alice_account.ids_message_transport p:ids err:&localError]; CFReleaseNull(ids); } } @@ -86,23 +89,23 @@ static void ids_test_sync(SOSAccountRef alice_account, SOSAccountRef bob_account ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); - SOSCircleForEachValidPeer(bob_account->trusted_circle, bob_account->user_public, ^(SOSPeerInfoRef peer) { + SOSCircleForEachValidPeer(bobTrust.trustedCircle, bob_account.accountKey, ^(SOSPeerInfoRef peer) { if (!SOSAccountIsThisPeerIDMe(bob_account, SOSPeerInfoGetPeerID(peer))) { - if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), peer) && - SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), peer)){ + if(SOSPeerInfoShouldUseIDSTransport(bobTrust.peerInfo, peer) && + SOSPeerInfoShouldUseIDSMessageFragmentation(bobTrust.peerInfo, peer)){ secnotice("IDS Transport","Syncing with IDS capable peers using IDS!"); CFMutableSetRef ids = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); CFSetAddValue(ids, SOSPeerInfoGetPeerID(peer)); - SyncingCompletedOverIDS = SOSTransportMessageSyncWithPeers(bob_account->ids_message_transport, ids, &localError); + SyncingCompletedOverIDS = [(SOSMessageIDSTest*)bob_account.ids_message_transport SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*)bob_account.ids_message_transport p:ids err:&localError]; CFReleaseNull(ids); } } }); ok(SyncingCompletedOverIDS, "synced items over IDS"); - if(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(alice_account->ids_message_transport)) == 0 && CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(bob_account->ids_message_transport)) == 0){ + if(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)alice_account.ids_message_transport)) == 0 && CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges((SOSMessageIDSTest*)bob_account.ids_message_transport)) == 0){ done = true; break; } @@ -122,8 +125,8 @@ static void tests() CFStringRef cfaccount = CFSTR("test@test.org"); CFStringRef dsName = CFSTR("Test"); - SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), dsName); - SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), dsName); + SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), dsName); + SOSAccount* bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), dsName); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); @@ -136,7 +139,7 @@ static void tests() ok(NULL != alice_account, "Alice Created"); ok(NULL != bob_account, "Bob Created"); - + ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); CFReleaseNull(error); @@ -168,7 +171,7 @@ static void tests() CFIndex version = 0; // Optionally prefix each peer with name to make them more unique. - CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,SOSAccountGetMyPeerID(alice_account), SOSAccountGetMyPeerID(bob_account), NULL); + CFArrayRef deviceIDs = CFArrayCreateForCFTypes(kCFAllocatorDefault,alice_account.peerID, bob_account.peerID, NULL); CFSetRef views = SOSViewsCopyTestV2Default(); CFMutableArrayRef peerMetas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); CFStringRef deviceID; @@ -183,12 +186,12 @@ static void tests() SOSTestDeviceRef device = SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault, deviceID, deviceID); SOSTestDeviceSetPeerIDs(device, peerMetas, version, NULL); - if(CFEqualSafe(deviceID, SOSAccountGetMyPeerID(alice_account))){ - alice_account->factory = device->dsf; + if([alice_account.peerID isEqual: (__bridge id)(deviceID)]){ + alice_account.factory = device->dsf; SOSTestDeviceAddGenericItem(device, CFSTR("Alice"), CFSTR("Alice-add")); } else{ - bob_account->factory = device->dsf; + bob_account.factory = device->dsf; SOSTestDeviceAddGenericItem(device, CFSTR("Bob"), CFSTR("Bob-add")); } @@ -199,56 +202,60 @@ static void tests() SOSUnregisterAllTransportMessages(); CFArrayRemoveAllValues(message_transports); + + SOSAccountTrustClassic* aliceTrust = alice_account.trust; + SOSAccountTrustClassic* bobTrust = bob_account.trust; + + alice_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:alice_account andAccountName:CFSTR("Alice") andCircleName:SOSCircleGetName(aliceTrust.trustedCircle) err:&error ]; + + bob_account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:bob_account andAccountName:CFSTR("Bob") andCircleName:SOSCircleGetName(bobTrust.trustedCircle) err:&error]; - alice_account->ids_message_transport = (SOSTransportMessageRef)SOSTransportMessageIDSTestCreate(alice_account, CFSTR("Alice"), SOSCircleGetName(alice_account->trusted_circle), &error); - bob_account->ids_message_transport = (SOSTransportMessageRef)SOSTransportMessageIDSTestCreate(bob_account, CFSTR("Bob"), SOSCircleGetName(bob_account->trusted_circle), &error); - - ok(alice_account->ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); - ok(bob_account->ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); + ok(alice_account.ids_message_transport != NULL, "Alice Account, Created IDS Test Transport"); + ok(bob_account.ids_message_transport != NULL, "Bob Account, Created IDS Test Transport"); - bool result = SOSAccountModifyCircle(alice_account, &error, ^bool(SOSCircleRef circle) { + bool result = [alice_account.trust modifyCircle:alice_account.circle_transport err:&error action:^bool(SOSCircleRef circle) { CFErrorRef localError = NULL; - SOSFullPeerInfoUpdateTransportType(alice_account->my_identity, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(alice_account->my_identity, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(alice_account->my_identity, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(alice_account->my_identity, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportType(aliceTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(aliceTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(aliceTrust.fullPeerInfo, kCFBooleanTrue, &localError); - return SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(alice_account->my_identity), NULL); - }); + return SOSCircleHasPeer(circle, aliceTrust.peerInfo, NULL); + }]; ok(result, "Alice account update circle with transport type"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - result = SOSAccountModifyCircle(bob_account, &error, ^bool(SOSCircleRef circle) { + result = [bob_account.trust modifyCircle:bob_account.circle_transport err:&error action:^bool(SOSCircleRef circle) { CFErrorRef localError = NULL; - SOSFullPeerInfoUpdateTransportType(bob_account->my_identity, SOSTransportMessageTypeIDSV2, &localError); - SOSFullPeerInfoUpdateTransportPreference(bob_account->my_identity, kCFBooleanFalse, &localError); - SOSFullPeerInfoUpdateTransportFragmentationPreference(bob_account->my_identity, kCFBooleanTrue, &localError); - SOSFullPeerInfoUpdateTransportAckModelPreference(bob_account->my_identity, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportType(bobTrust.fullPeerInfo, SOSTransportMessageTypeIDSV2, &localError); + SOSFullPeerInfoUpdateTransportPreference(bobTrust.fullPeerInfo, kCFBooleanFalse, &localError); + SOSFullPeerInfoUpdateTransportFragmentationPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); + SOSFullPeerInfoUpdateTransportAckModelPreference(bobTrust.fullPeerInfo, kCFBooleanTrue, &localError); - return SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(bob_account->my_identity), NULL); - }); + return SOSCircleHasPeer(circle, bobTrust.peerInfo, NULL); + }]; ok(result, "Bob account update circle with transport type"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); - CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(alice_account)); - CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(bob_account)); + CFStringRef alice_transportType =SOSPeerInfoCopyTransportType(alice_account.peerInfo); + CFStringRef bob_accountTransportType = SOSPeerInfoCopyTransportType(bob_account.peerInfo); ok(CFEqualSafe(alice_transportType, CFSTR("IDS2.0")), "Alice transport type not IDS"); ok(CFEqualSafe(bob_accountTransportType, CFSTR("IDS2.0")), "Bob transport type not IDS"); CFReleaseNull(alice_transportType); CFReleaseNull(bob_accountTransportType); - SOSTransportMessageIDSTestSetName(alice_account->ids_message_transport, CFSTR("Alice Account")); - ok(SOSTransportMessageIDSTestGetName(alice_account->ids_message_transport) != NULL, "retrieved getting account name"); + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)alice_account.ids_message_transport, CFSTR("Alice Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)alice_account.ids_message_transport) != NULL, "retrieved getting account name"); ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); - SOSTransportMessageIDSTestSetName(bob_account->ids_message_transport, CFSTR("Bob Account")); - ok(SOSTransportMessageIDSTestGetName(bob_account->ids_message_transport) != NULL, "retrieved getting account name"); + SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)bob_account.ids_message_transport, CFSTR("Bob Account")); + ok(SOSTransportMessageIDSTestGetName((SOSMessageIDSTest*)bob_account.ids_message_transport) != NULL, "retrieved getting account name"); ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account, &error) != false, "device ID from KeychainSyncingOverIDSProxy"); @@ -270,8 +277,6 @@ static void tests() ids_test_sync(alice_account, bob_account); - CFReleaseNull(alice_account); - CFReleaseNull(bob_account); CFReleaseNull(bob_dsid); CFReleaseNull(alice_dsid); CFReleaseNull(changes); @@ -281,7 +286,7 @@ static void tests() int secd_77_ids_messaging(int argc, char *const *argv) { - plan_tests(kTestTestCount); + plan_tests(100); secd_test_setup_temp_keychain(__FUNCTION__, NULL); diff --git a/OSX/sec/securityd/Regressions/secd_regressions.h b/OSX/sec/securityd/Regressions/secd_regressions.h index b04481ef..845ccbf1 100644 --- a/OSX/sec/securityd/Regressions/secd_regressions.h +++ b/OSX/sec/securityd/Regressions/secd_regressions.h @@ -22,7 +22,7 @@ */ -#include +#include ONE_TEST(secd_01_items) ONE_TEST(secd_02_upgrade_while_locked) @@ -33,11 +33,12 @@ ONE_TEST(secd_20_keychain_upgrade) ONE_TEST(secd_21_transmogrify) DISABLED_ONE_TEST(secd_30_keychain_upgrade) //obsolete, needs updating ONE_TEST(secd_31_keychain_bad) -ONE_TEST(secd_31_keychain_unreadable) +DISABLED_ONE_TEST(secd_31_keychain_unreadable) OFF_ONE_TEST(secd_32_restore_bad_backup) ONE_TEST(secd_33_keychain_ctk) ONE_TEST(secd_35_keychain_migrate_inet) ONE_TEST(secd_36_ks_encrypt) +ONE_TEST(secd_37_pairing_initial_sync) ONE_TEST(secd_40_cc_gestalt) ONE_TEST(secd_50_account) ONE_TEST(secd_49_manifests) @@ -55,7 +56,6 @@ ONE_TEST(secd_59_account_cleanup) ONE_TEST(secd_60_account_cloud_identity) ONE_TEST(secd_60_account_cloud_exposure) ONE_TEST(secd_61_account_leave_not_in_kansas_anymore) -ONE_TEST(secd_62_account_hsa_join) ONE_TEST(secd_62_account_backup) ONE_TEST(secd_63_account_resurrection) ONE_TEST(secd_64_circlereset) @@ -68,6 +68,8 @@ ONE_TEST(secd_70_engine_smash) ONE_TEST(secd_71_engine_save) ONE_TEST(secd_76_idstransport) ONE_TEST(secd_77_ids_messaging) +ONE_TEST(secd_68_ghosts) +ONE_TEST(secd_155_otr_negotiation_monitor) DISABLED_ONE_TEST(secd_70_otr_remote) ONE_TEST(secd_74_engine_beer_servers) @@ -86,14 +88,14 @@ ONE_TEST(secd_82_persistent_ref) ONE_TEST(secd_83_item_match_policy) ONE_TEST(secd_83_item_match_valid_on_date) ONE_TEST(secd_83_item_match_trusted) -ONE_TEST(secd_90_hsa2) ONE_TEST(secd_95_escrow_persistence) ONE_TEST(secd_154_engine_backoff) ONE_TEST(secd_100_initialsync) ONE_TEST(secd_130_other_peer_views) +ONE_TEST(secd_156_timers) ONE_TEST(secd_200_logstate) ONE_TEST(secd_201_coders) ONE_TEST(secd_202_recoverykey) ONE_TEST(secd_210_keyinterest) -ONE_TEST(secd_668_ghosts) +DISABLED_ONE_TEST(secd_230_keybagtable) diff --git a/OSX/sec/securityd/Regressions/securityd_regressions.h b/OSX/sec/securityd/Regressions/securityd_regressions.h index f7e965fc..0135bbb8 100644 --- a/OSX/sec/securityd/Regressions/securityd_regressions.h +++ b/OSX/sec/securityd/Regressions/securityd_regressions.h @@ -2,6 +2,6 @@ 1) add it here 2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes */ -#include +#include ONE_TEST(sd_10_policytree) diff --git a/OSX/sec/securityd/SOSCloudCircleServer.h b/OSX/sec/securityd/SOSCloudCircleServer.h index d22d48d3..25890f74 100644 --- a/OSX/sec/securityd/SOSCloudCircleServer.h +++ b/OSX/sec/securityd/SOSCloudCircleServer.h @@ -25,9 +25,10 @@ #ifndef _SECURITY_SOSCLOUDCIRCLESERVER_H_ #define _SECURITY_SOSCLOUDCIRCLESERVER_H_ -#include -#include - +#import +#import +#import +#import __BEGIN_DECLS @@ -101,7 +102,6 @@ SOSSecurityPropertyResultCode SOSCCSecurityProperty_Server(CFStringRef property, CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error); enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error); bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error); -bool SOSCCSetHSA2AutoAcceptInfo_Server(CFDataRef pubKey, CFErrorRef *error); bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error); @@ -124,7 +124,6 @@ CF_RETURNS_RETAINED CFDataRef SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef // MARK: Internal kicks. // CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates); -void sync_the_last_data_to_kvs(SOSAccountRef account, bool waitForeverForSynchronization); // Expected to be called when the data source changes. @@ -136,17 +135,16 @@ void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId); bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error); void SOSCCEnsurePeerRegistration(void); -void SOSCCAddSyncablePeerBlock(CFStringRef ds_name, SOSAccountSyncablePeersBlock changeBlock); +typedef void (^SOSAccountSyncablePeersBlock)(CFArrayRef trustedPeers, CFArrayRef addedPeers, CFArrayRef removedPeers); + dispatch_queue_t SOSCCGetAccountQueue(void); +CFTypeRef GetSharedAccountRef(void); // returns SOSAccount* but this header is imported by C files, so we cast through CFTypeRef + // // MARK: Internal access to local account for tests. // -typedef SOSDataSourceFactoryRef (^SOSCCAccountDataSourceFactoryBlock)(); - -SOSAccountRef SOSKeychainAccountGetSharedAccount(void); -bool SOSKeychainAccountSetFactoryForAccount(SOSCCAccountDataSourceFactoryBlock factory); - +CFTypeRef SOSKeychainAccountGetSharedAccount(void); // // MARK: Internal SPIs for testing // @@ -166,8 +164,6 @@ bool SOSKeychainSaveAccountDataAndPurge(CFErrorRef *error); // MARK: Constants for where we store persistent information in the keychain // -extern CFStringRef kSOSInternalAccessGroup; - extern CFStringRef kSOSAccountLabel; extern CFStringRef kSOSPeerDataLabel; @@ -183,13 +179,23 @@ CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error); SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error); CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error); -bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, CFErrorRef *error); +bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); +CFDataRef SOSCCCopyInitialSyncData_Server(CFErrorRef *error); +bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error); bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error); bool SOSCCAccountIsNew_Server(CFErrorRef *error); +bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error); + +void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization); bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error); bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error); +XPC_RETURNS_RETAINED xpc_endpoint_t SOSCCCreateSOSEndpoint_server(CFErrorRef *error); + +void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivKey, CFErrorRef error)); +void SOSCCResetOTRNegotiation_Server(CFStringRef peerid); +void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup); __END_DECLS diff --git a/OSX/sec/securityd/SOSCloudCircleServer.c b/OSX/sec/securityd/SOSCloudCircleServer.m similarity index 73% rename from OSX/sec/securityd/SOSCloudCircleServer.c rename to OSX/sec/securityd/SOSCloudCircleServer.m index f9681639..272e9aac 100644 --- a/OSX/sec/securityd/SOSCloudCircleServer.c +++ b/OSX/sec/securityd/SOSCloudCircleServer.m @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -40,12 +42,12 @@ #include #include #include -#include -#include -#include #include - +#include #include +#import +#import +#import #include #include @@ -95,33 +97,23 @@ #include -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR static int64_t getTimeDifference(time_t start); CFStringRef const SOSAggdSyncCompletionKey = CFSTR("com.apple.security.sos.synccompletion"); CFStringRef const SOSAggdSyncTimeoutKey = CFSTR("com.apple.security.sos.timeout"); -#endif +typedef SOSDataSourceFactoryRef (^SOSCCAccountDataSourceFactoryBlock)(); static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL; -bool SOSKeychainAccountSetFactoryForAccount(SOSCCAccountDataSourceFactoryBlock block) -{ - accountDataSourceOverride = Block_copy(block); - - return true; -} - // // Forward declared // -static void do_with_account(void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)); -static void do_with_account_async(void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)); +static void do_with_account(void (^action)(SOSAccountTransaction* txn)); // // Constants // -CFStringRef kSOSInternalAccessGroup = CFSTR("com.apple.security.sos"); CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data"); @@ -220,60 +212,33 @@ exit: CFReleaseNull(saveError); } - -/* - Stolen from keychain_sync.c - */ - -static bool clearAllKVS(CFErrorRef *error) -{ - return true; - __block bool result = false; - const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC; - dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); - dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds); - - SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef cerror) - { - result = (cerror != NULL); - dispatch_semaphore_signal(waitSemaphore); - }); - - dispatch_semaphore_wait(waitSemaphore, finishTime); - dispatch_release(waitSemaphore); - - return result; -} - -static SOSAccountRef SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt) +static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt) { secdebug("account", "Created account"); CFDataRef savedAccount = SOSKeychainCopySavedAccountData(); - SOSAccountRef account = NULL; + SOSAccount* account = NULL; + SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride() : SecItemDataSourceFactoryGetDefault(); - if (!factory) { - CFReleaseNull(savedAccount); - return NULL; - } - + + require_quiet(factory, done); + if (savedAccount) { - CFErrorRef inflationError = NULL; + NSError* inflationError = NULL; - account = SOSAccountCreateFromData(kCFAllocatorDefault, savedAccount, factory, &inflationError); + account = [SOSAccount accountFromData:(__bridge NSData*) savedAccount + factory:factory + error:&inflationError]; if (account){ - SOSAccountUpdateGestalt(account, our_gestalt); + [account.trust updateGestalt:account newGestalt:our_gestalt]; } else { secerror("Got error inflating account: %@", inflationError); } - - CFReleaseNull(inflationError); } - CFReleaseSafe(savedAccount); + CFReleaseNull(savedAccount); if (!account) { account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory); @@ -281,7 +246,9 @@ static SOSAccountRef SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_g if (!account) secerror("Got NULL creating account"); } - + +done: + CFReleaseNull(savedAccount); return account; } @@ -392,10 +359,10 @@ static CFDictionaryRef CreateDeviceGestaltDictionary(SCDynamicStoreRef store, CF static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store, CFArrayRef keys, void *context) { - do_with_account(^(SOSAccountRef account, SOSAccountTransactionRef txn) { - if(account){ + do_with_account(^(SOSAccountTransaction* txn) { + if(txn.account){ CFDictionaryRef gestalt = CreateDeviceGestaltDictionary(store, keys, context); - if (SOSAccountUpdateGestalt(account, gestalt)) { + if ([txn.account.trust updateGestalt:txn.account newGestalt:gestalt]) { notify_post(kSOSCCCircleChangedNotification); } CFReleaseSafe(gestalt); @@ -456,8 +423,8 @@ errOut: -static SOSAccountRef GetSharedAccount(void) { - static SOSAccountRef sSharedAccount = NULL; +static SOSAccount* GetSharedAccount(void) { + static SOSAccount* sSharedAccount = NULL; static dispatch_once_t onceToken; #if !(TARGET_OS_EMBEDDED) @@ -486,7 +453,7 @@ static SOSAccountRef GetSharedAccount(void) { CFSetRef peer_additions, CFSetRef peer_removals, CFSetRef applicant_additions, CFSetRef applicant_removals) { CFErrorRef pi_error = NULL; - SOSPeerInfoRef me = SOSAccountGetMyPeerInfo(sSharedAccount); + SOSPeerInfoRef me = sSharedAccount.peerInfo; if (!me) { secerror("Error finding me for change: %@", pi_error); } else { @@ -537,7 +504,7 @@ static SOSAccountRef GetSharedAccount(void) { SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes) { CFRetainSafe(changes); __block CFMutableArrayRef handledKeys = NULL; - do_with_account(^(SOSAccountRef account, SOSAccountTransactionRef txn) { + do_with_account(^(SOSAccountTransaction* txn) { CFStringRef changeDescription = SOSItemsChangedCopyDescription(changes, false); secdebug(SOSCKCSCOPE, "Received: %@", changeDescription); CFReleaseSafe(changeDescription); @@ -554,14 +521,13 @@ static SOSAccountRef GetSharedAccount(void) { }); CFReleaseSafe(gestalt); - SOSAccountSetSaveBlock(sSharedAccount, ^(CFDataRef flattenedAccount, CFErrorRef flattenFailError) { + sSharedAccount.saveBlock = ^(CFDataRef flattenedAccount, CFErrorRef flattenFailError) { if (flattenedAccount) { SOSKeychainAccountEnsureSaved(flattenedAccount); } else { secerror("Failed to transform account into data, error: %@", flattenFailError); } - }); - + }; // 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); @@ -574,21 +540,19 @@ static SOSAccountRef GetSharedAccount(void) { return sSharedAccount; } -static void do_with_account_dynamic(bool sync, void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)) { - - SOSAccountRef account = GetSharedAccount(); - - if(account){ - SOSAccountWithTransaction(account, sync, action); - } +CFTypeRef GetSharedAccountRef(void) +{ + return (__bridge CFTypeRef)GetSharedAccount(); } -__unused static void do_with_account_async(void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)) { - do_with_account_dynamic(false, action); -} +static void do_with_account(void (^action)(SOSAccountTransaction* txn)) { + SOSAccount* account = GetSharedAccount(); -static void do_with_account(void (^action)(SOSAccountRef account, SOSAccountTransactionRef txn)) { - do_with_account_dynamic(true, action); + if(account){ + [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + action(txn); + }]; + } } static bool isValidUser(CFErrorRef* error) { @@ -617,6 +581,7 @@ static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action) CFSTR("Keybag never unlocked, ask after first unlock"))); action(); + return true; fail: @@ -624,13 +589,31 @@ fail: #endif } -static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* error)) +static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error)) { + static dispatch_once_t initialNotificationToken; __block bool action_result = false; return isValidUser(error) && do_if_after_first_unlock(error, ^{ - do_with_account(^(SOSAccountRef account, SOSAccountTransactionRef txn) { - action_result = action(account, txn, error); + do_with_account(^(SOSAccountTransaction* txn) { + action_result = action(txn, error); + + // The first time we run do_with_account_if_after_first_unlock and the bag is unlocked, + // if we are now 'in circle', notify our listeners of a 'circle change' and a 'view change'. + // This will prompt them to refetch circle status, and we can actually respond correctly now! + // If we are out of circle, don't send the notification--all clients 'know' we're out of circle anyway. + dispatch_once(&initialNotificationToken, ^{ + CFErrorRef cferror = NULL; + + SOSCCStatus status = [txn.account getCircleStatus:&cferror]; + if(cferror) { + secerror("error getting circle status on first unlock: %@", cferror); + } else if (status == kSOSCCInCircle) { + secnotice("secdNotify", "Notified clients of kSOSCCCircleChangedNotification && kSOSCCViewMembershipChangedNotification for in-circle initial unlock"); + notify_post(kSOSCCCircleChangedNotification); + notify_post(kSOSCCViewMembershipChangedNotification); + } + }); }); }) && action_result; @@ -640,7 +623,7 @@ static bool isAssertionLockAcquireError(CFErrorRef error) { return (CFErrorGetCode(error) == kIOReturnNotPermitted) && (CFEqualSafe(CFErrorGetDomain(error), kSecKernDomain)); } -static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* error)) +static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error)) { bool result = false; @@ -651,12 +634,20 @@ static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOS __block CFErrorRef localError = NULL; - require_quiet(isValidUser(error), done); + if(!isValidUser(error)){ + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return result; + } result = SecAKSDoWhileUserBagLocked(&localError, ^{ - do_with_account(^(SOSAccountRef account, SOSAccountTransactionRef txn) { + do_with_account(^(SOSAccountTransaction* txn) { attempted_action = true; - action_result = action(account, txn, error); + action_result = action(txn, error); }); }); @@ -665,25 +656,49 @@ static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOS // we assume our caller will hold the lock assertion for us to finsh our job. // to be extra paranoid we track if we tried the caller's block. If we did we don't do it again. - require_quiet(result == false && isAssertionLockAcquireError(localError), done); - require_quiet(!attempted_action, done); + if(result || !isAssertionLockAcquireError(localError)){ + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return result; + } + if(attempted_action){ + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return (result && action_result); + } bool isUnlocked = false; (void) SecAKSGetIsUnlocked(&isUnlocked, &statusError); - require_action_quiet(isUnlocked, done, secnotice("while-unlocked-hack", "Not trying action, aks bag locked (%@)", statusError)); + if(!isUnlocked){ + secnotice("while-unlocked-hack", "Not trying action, aks bag locked (%@)", statusError); + if (error && !*error && localError) { + CFTransferRetained(*error, localError); + } + CFReleaseNull(localError); + CFReleaseNull(statusError); + + return result && action_result; + } CFReleaseNull(localError); secnotice("while-unlocked-hack", "Trying action while unlocked without assertion"); result = true; - do_with_account(^(SOSAccountRef account, SOSAccountTransactionRef txn) { - action_result = action(account, txn, &localError); + do_with_account(^(SOSAccountTransaction* txn) { + action_result = action(txn, &localError); }); secnotice("while-unlocked-hack", "Action %s (%@)", action_result ? "succeeded" : "failed", localError); -done: if (error && !*error && localError) { CFTransferRetained(*error, localError); } @@ -693,15 +708,15 @@ done: return result && action_result; } -SOSAccountRef SOSKeychainAccountGetSharedAccount() +CFTypeRef SOSKeychainAccountGetSharedAccount() { - __block SOSAccountRef result = NULL; + __block SOSAccount* result = NULL; - do_with_account(^(SOSAccountRef account, SOSAccountTransactionRef txn) { - result = account; + do_with_account(^(SOSAccountTransaction* txn) { + result = txn.account; }); - return result; + return (__bridge CFTypeRef)result; } // @@ -711,29 +726,29 @@ SOSAccountRef SOSKeychainAccountGetSharedAccount() bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error) { - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - return SOSAccountTryUserCredentials(account, user_label, user_password, block_error); + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error); }); } SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) { __block SOSViewResultCode status = kSOSCCGeneralViewError; - do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { bool retval = false; switch(action) { case kSOSCCViewQuery: - status = SOSAccountViewStatus(account, viewname, error); + status = [txn.account.trust viewStatus:txn.account name:viewname err:error]; retval = true; break; case kSOSCCViewEnable: - status = SOSAccountUpdateView(account, viewname, action, error); + status = [txn.account.trust updateView:txn.account name:viewname code:action err:error]; retval = true; break; case kSOSCCViewDisable: - status = SOSAccountUpdateView(account, viewname, action, error); + status = [txn.account.trust updateView:txn.account name:viewname code:action err:error]; retval = true; break; default: @@ -750,8 +765,8 @@ SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode actio bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) { __block bool status = false; - do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - status = SOSAccountUpdateViewSets(account, enabledViews, disabledViews); + do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + status = [txn.account.trust updateViewSets:txn.account enabled:enabledViews disabled:disabledViews]; return true; }); return status; @@ -760,14 +775,14 @@ bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) { SOSSecurityPropertyResultCode SOSCCSecurityProperty_Server(CFStringRef property, SOSSecurityPropertyActionCode action, CFErrorRef *error) { __block SOSViewResultCode status = kSOSCCGeneralSecurityPropertyError; - do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { switch(action) { case kSOSCCSecurityPropertyQuery: - status = SOSAccountSecurityPropertyStatus(account, property, error); + status = [txn.account.trust SecurityPropertyStatus:property err:error]; break; case kSOSCCSecurityPropertyEnable: case kSOSCCSecurityPropertyDisable: // fallthrough - status = SOSAccountUpdateSecurityProperty(account, property, action, error); + status = [txn.account.trust UpdateSecurityProperty:txn.account property:property code:action err:error]; break; default: secnotice("secprop", "Bad SOSSecurityPropertyActionCode - %d", (int) action); @@ -779,10 +794,9 @@ SOSSecurityPropertyResultCode SOSCCSecurityProperty_Server(CFStringRef property, return status; } -void sync_the_last_data_to_kvs(SOSAccountRef account, bool waitForeverForSynchronization){ +void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization){ dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); - dispatch_retain(wait_for); // Both this scope and the block own it. secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait"); @@ -794,7 +808,6 @@ void sync_the_last_data_to_kvs(SOSAccountRef account, bool waitForeverForSynchro } dispatch_semaphore_signal(wait_for); - dispatch_release(wait_for); }); if(waitForeverForSynchronization) @@ -802,14 +815,13 @@ void sync_the_last_data_to_kvs(SOSAccountRef account, bool waitForeverForSynchro else dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC)); - dispatch_release(wait_for); + wait_for = nil; } #define kWAIT2MINID "EFRESH" static bool SyncKVSAndWait(CFErrorRef *error) { dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); - dispatch_retain(wait_for); // Both this scope and the block own it. __block bool success = false; @@ -825,13 +837,10 @@ static bool SyncKVSAndWait(CFErrorRef *error) { } dispatch_semaphore_signal(wait_for); - dispatch_release(wait_for); }); dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); - dispatch_release(wait_for); - secnotice("fresh", "EFP complete: %s %@", success ? "success" : "failure", error ? *error : NULL); }); @@ -842,8 +851,6 @@ static bool Flush(CFErrorRef *error) { __block bool success = false; dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); - dispatch_retain(wait_for); // Both this scope and the block own it. - secnotice("flush", "Starting"); SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { @@ -853,11 +860,9 @@ static bool Flush(CFErrorRef *error) { } dispatch_semaphore_signal(wait_for); - dispatch_release(wait_for); }); dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); - dispatch_release(wait_for); secnotice("flush", "Returned %s", success? "Success": "Failure"); @@ -867,9 +872,9 @@ static bool Flush(CFErrorRef *error) { static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); - bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { - SOSAccountAssertDSID(account, dsid); + SOSAccountAssertDSID(txn.account, dsid); } return true; }); @@ -879,15 +884,15 @@ static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CF 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(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *block_error) { - return SOSAccountAssertUserCredentials(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); }); require_quiet(result, done); require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature - result = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - return SOSAccountGenerationSignatureUpdate(account, error); + result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountGenerationSignatureUpdate(txn.account, error); }); done: @@ -907,8 +912,11 @@ bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_passw bool SOSCCCanAuthenticate_Server(CFErrorRef *error) { - bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - return SOSAccountGetPrivateCredential(account, block_error) != NULL; + bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + // If we reply that yes we can authenticate, then let's make sure we can authenticate for a while yet. + // + SOSAccountRestartPrivateCredentialTimer(txn.account); + return SOSAccountGetPrivateCredential(txn.account, block_error) != NULL; }); if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) { @@ -923,8 +931,8 @@ bool SOSCCCanAuthenticate_Server(CFErrorRef *error) bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error) { - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - SOSAccountPurgePrivateCredential(account); + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSAccountPurgePrivateCredential(txn.account); return true; }); } @@ -933,8 +941,9 @@ SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error) { __block SOSCCStatus status; - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - status = SOSAccountGetCircleStatus(account, block_error); + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + status = [txn.account getCircleStatus:block_error]; + return true; }) ? status : kSOSCCError; } @@ -943,7 +952,7 @@ bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error) { __block bool result = true; - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { result = SOSAccountJoinCircles(txn, block_error); return result; }); @@ -954,8 +963,8 @@ bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error) __block bool result = true; __block CFErrorRef localError = NULL; - bool hasPublicKey = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountHasPublicKey(account, &localError); + bool hasPublicKey = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountHasPublicKey(txn.account, &localError); return result; }); @@ -970,8 +979,8 @@ bool SOSCCAccountIsNew_Server(CFErrorRef *error) __block bool result = true; __block CFErrorRef localError = NULL; - (void) do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountIsNew(account, &localError); + (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountIsNew(txn.account, &localError); return result; }); @@ -984,8 +993,8 @@ bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error) { __block bool result = true; bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - SOSAccountEnsurePeerRegistration(account, block_error); + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSAccountEnsurePeerRegistration(txn.account, block_error); result = SOSAccountJoinCirclesAfterRestore(txn, block_error); return result; }); @@ -996,7 +1005,7 @@ bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error) bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error) { bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { return SyncKVSAndWait(block_error); }); if (returned) { @@ -1008,11 +1017,12 @@ bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error) bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error){ __block bool result = true; bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account); - SOSRingRef ring = SOSAccountCopyRing(account, ringName, error); + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; + SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; + if(fpi && ring) { - result = SOSRingApply(ring, account->user_public, fpi , error); + result = SOSRingApply(ring, txn.account.accountKey, fpi , error); } CFReleaseNull(ring); return result; @@ -1023,11 +1033,11 @@ bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error){ bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error){ __block bool result = true; bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account); - SOSRingRef ring = SOSAccountCopyRing(account, ringName, error); + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; + SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; if(fpi && ring) { - result = SOSRingWithdraw(ring, account->user_public, fpi , error); + result = SOSRingWithdraw(ring, txn.account.accountKey, fpi , error); } CFReleaseNull(ring); return result; @@ -1038,9 +1048,9 @@ bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error){ bool SOSCCEnableRing_Server(CFStringRef ringName, CFErrorRef *error){ __block bool result = true; bool returned = false; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account); - SOSRingRef ring = SOSAccountCopyRing(account, ringName, error); + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; + SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; if(fpi && ring) { result = SOSRingResetToOffering(ring, NULL, fpi, error); } @@ -1054,8 +1064,8 @@ CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){ __block CFMutableDictionaryRef result = NULL; __block CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0); - (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - SOSAccountForEachRing(account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) { + (void) do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + SOSAccountForEachRing(txn.account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) { CFStringAppendFormat(description, NULL, CFSTR("%@\n"), ring); return NULL; }); @@ -1070,11 +1080,11 @@ CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){ SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error){ __block bool result = true; SOSRingStatus returned; - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account); + returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo; SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi); - SOSRingRef ring = SOSAccountCopyRing(account, ringName, error); + SOSRingRef ring = [txn.account.trust copyRing:ringName err:error]; if(myPeer && ring) { result = SOSRingDeviceIsInRing(ring, SOSPeerInfoGetPeerID(myPeer)); } @@ -1089,8 +1099,8 @@ CFStringRef SOSCCCopyDeviceID_Server(CFErrorRef *error) { __block CFStringRef result = NULL; - (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - result = SOSAccountCopyDeviceID(account, error); + (void) do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + result = SOSAccountCopyDeviceID(txn.account, error); return (!isNull(result)); }); return result; @@ -1098,28 +1108,17 @@ CFStringRef SOSCCCopyDeviceID_Server(CFErrorRef *error) bool SOSCCSetDeviceID_Server(CFStringRef IDS, CFErrorRef *error){ - bool didSetID = false; - __block bool result = false; - - didSetID = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountSetMyDSID(txn, IDS, error); - - if(block_error && error != NULL ){ - *error = *block_error; - } - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountSetMyDSID(txn, IDS, block_error); }); - - return didSetID; } bool SOSCCRequestSyncWithPeerOverKVS_Server(CFStringRef peerid, CFDataRef message, CFErrorRef *error) { __block bool result = NULL; - result = do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - result = SOSAccountSyncWithKVSPeerWithMessage(txn, peerid, message, error); - return result; + result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountSyncWithKVSPeerWithMessage(txn, peerid, message, error); }); return result; } @@ -1129,8 +1128,8 @@ HandleIDSMessageReason SOSCCHandleIDSMessage_Server(CFDictionaryRef messageDict, __block HandleIDSMessageReason result = kHandleIDSMessageSuccess; CFErrorRef action_error = NULL; - if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSTransportMessageIDSHandleMessage(account, messageDict, error); + if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = [txn.account.ids_message_transport SOSTransportMessageIDSHandleMessage:txn.account m:messageDict err:block_error]; return true; })) { if (action_error) { @@ -1155,127 +1154,89 @@ bool SOSCCClearPeerMessageKeyInKVS_Server(CFStringRef peerID, CFErrorRef *error) { __block bool result = false; - result = do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - SOSAccountClearPeerMessageKey(txn, peerID, error); - return true; + result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountClearPeerMessageKey(txn, peerID, error); }); return result; } bool SOSCCIDSPingTest_Server(CFStringRef message, CFErrorRef *error){ - __block bool result = true; - __block CFErrorRef blockError = NULL; - - result = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result &= SOSAccountStartPingTest(account, message, &blockError); - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountStartPingTest(txn.account, message, block_error); }); - if(blockError && error != NULL) - *error = blockError; - - return result; } bool SOSCCIDSServiceRegistrationTest_Server(CFStringRef message, CFErrorRef *error){ - __block bool result = true; - __block CFErrorRef blockError = NULL; - - result = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - return SOSAccountSendIDSTestMessage(account, message, &blockError); + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountSendIDSTestMessage(txn.account, message, block_error); }); - if(blockError != NULL && error != NULL) - *error = blockError; - - return result; } bool SOSCCIDSDeviceIDIsAvailableTest_Server(CFErrorRef *error){ - bool didSendTestMessages = false; - __block bool result = true; - __block CFErrorRef blockError = NULL; - - didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(account, &blockError); - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(txn.account, block_error); }); - if(blockError != NULL && error != NULL) - *error = blockError; - - return didSendTestMessages; } bool SOSCCAccountSetToNew_Server(CFErrorRef *error) { - __block bool result = true; - - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - clearAllKVS(NULL); - SOSAccountSetToNew(account); - return result; + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSAccountSetToNew(txn.account); + return true; }); } bool SOSCCResetToOffering_Server(CFErrorRef* error) { - __block bool result = true; - - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - clearAllKVS(NULL); - result = SOSAccountResetToOffering(txn, block_error); - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error); + if (!user_key) + return false; + return [txn.account.trust resetToOffering:txn key:user_key err:block_error]; }); } bool SOSCCResetToEmpty_Server(CFErrorRef* error) { - __block bool result = true; - - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountResetToEmpty(account, block_error); - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + if (!SOSAccountHasPublicKey(txn.account, error)) + return false; + return [txn.account.trust resetAccountToEmpty:txn.account transport:txn.account.circle_transport err:block_error]; }); } bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error) { - __block bool result = true; - - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountLeaveCircle(account, block_error); - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return [txn.account.trust leaveCircle:txn.account err:block_error]; }); } bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error) { - __block bool result = true; - - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountRemovePeersFromCircle(account, peers, block_error); - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountRemovePeersFromCircle(txn.account, peers, block_error); }); } bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error) { - __block bool result = true; - - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { secnotice("sosops", "Signed out of account!"); bool waitForeverForSynchronization = true; - result = SOSAccountLeaveCircle(account, block_error); + bool result = [txn.account.trust leaveCircle:txn.account err:block_error]; - SOSAccountTransactionFinishAndRestart(txn); // Make sure this gets finished before we set to new. + [txn restart]; // Make sure this gets finished before we set to new. - sync_the_last_data_to_kvs(account, waitForeverForSynchronization); + sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization); - SOSAccountSetToNew(account); + SOSAccountSetToNew(txn.account); return result; }); @@ -1283,16 +1244,14 @@ bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error) bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error) { - __block bool result = true; - - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { bool waitForeverForSynchronization = false; - result = SOSAccountBail(account, limit_in_seconds, block_error); - - SOSAccountTransactionFinishAndRestart(txn); // Make sure this gets finished before we push our data. - - sync_the_last_data_to_kvs(account, waitForeverForSynchronization); + bool result = SOSAccountBail(txn.account, limit_in_seconds, block_error); + + [txn restart]; // Make sure this gets finished before we set to new. + + sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization); return result; }); @@ -1303,8 +1262,8 @@ CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyApplicants(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyApplicants(txn.account, block_error); return result != NULL; }); @@ -1315,8 +1274,8 @@ CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyGeneration(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyGeneration(txn.account, block_error); return result != NULL; }); @@ -1326,12 +1285,17 @@ CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error) CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyValidPeers(account, block_error); + + @autoreleasepool { + + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + @autoreleasepool { + result = SOSAccountCopyValidPeers(txn.account, block_error); + } return result != NULL; }); - + } + return result; } @@ -1339,8 +1303,8 @@ bool SOSCCValidateUserPublic_Server(CFErrorRef* error) { __block bool result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSValidateUserPublic(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSValidateUserPublic(txn.account, block_error); return result; }); @@ -1351,8 +1315,8 @@ CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyNotValidPeers(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyNotValidPeers(txn.account, block_error); return result != NULL; }); @@ -1363,8 +1327,8 @@ CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyRetired(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyRetired(txn.account, block_error); return result != NULL; }); @@ -1375,8 +1339,8 @@ CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyViewUnaware(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyViewUnaware(txn.account, block_error); return result != NULL; }); @@ -1396,7 +1360,7 @@ CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error) return result; } -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR + static int64_t getTimeDifference(time_t start) { time_t stop; @@ -1408,7 +1372,21 @@ static int64_t getTimeDifference(time_t start) return SecBucket1Significant(duration); } -#endif + +static uint64_t initialSyncTimeoutFromDefaultsWrite(void) +{ + uint64_t timeout = 10; + + //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true + CFTypeRef initialSyncTimeout = (CFNumberRef)CFPreferencesCopyValue(CFSTR("InitialSync.WaitPeriod"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + + if (isNumber(initialSyncTimeout)) { + CFNumberGetValue((CFNumberRef)initialSyncTimeout, kCFNumberSInt64Type, &timeout); + } + CFReleaseNull(initialSyncTimeout); + return timeout; +} + bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) { __block dispatch_semaphore_t inSyncSema = NULL; @@ -1416,29 +1394,26 @@ bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) { __block bool synced = false; bool timed_out = false; __block CFStringRef inSyncCallID = NULL; -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR __block time_t start; -#endif + __block CFBooleanRef shouldUseInitialSyncV0 = false; secnotice("initial sync", "Wait for initial sync start!"); - result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - bool alreadyInSync = SOSAccountHasCompletedInitialSync(account); + 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) { -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR + txn.account.isInitialSyncing = true; start = time(NULL); -#endif inSyncSema = dispatch_semaphore_create(0); - dispatch_retain(inSyncSema); // For the block - inSyncCallID = SOSAccountCallWhenInSync(account, ^bool(SOSAccountRef mightBeSynced) { + inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) { synced = true; if(inSyncSema){ dispatch_semaphore_signal(inSyncSema); - if(inSyncSema) - dispatch_release(inSyncSema); + } return true; }); @@ -1450,37 +1425,30 @@ bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) { }); require_quiet(result, fail); + if(inSyncSema){ - timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC)); + 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) { - do_with_account(^(SOSAccountRef account, SOSAccountTransactionRef txn) { - if (SOSAccountUnregisterCallWhenInSync(account, inSyncCallID)) { + if (timed_out && shouldUseInitialSyncV0) { + do_with_account(^(SOSAccountTransaction* txn) { + if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) { if(inSyncSema){ - dispatch_release(inSyncSema); // if we unregistered we release the sema inSyncSema = NULL; // We've canceled the timeout so we must be the last. } } }); - - if (!synced) { - secerror("waiting for initial sync timed out"); - result = false; - SOSErrorCreate(kSOSInitialSyncFailed, error, NULL, CFSTR("InitialSyncTimedOut")); - } } require_quiet(result, fail); - if (!synced) { - secerror("waiting for initial sync failed"); - result = false; - - SOSErrorCreate(kSOSInitialSyncFailed, error, NULL, CFSTR("Initial sync timed out.")); - } - -#if TARGET_OS_EMBEDDED && !TARGET_IPHONE_SIMULATOR - if(result) { SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start)); @@ -1489,7 +1457,10 @@ bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) { { SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1); } -#endif + + (void)do_with_account(^(SOSAccountTransaction *txn) { + txn.account.isInitialSyncing = false; + }); secnotice("initial sync", "Finished!: %d", result); @@ -1499,12 +1470,12 @@ fail: } -static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccountRef account, CFErrorRef *error) { +static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccount* account, CFErrorRef *error) { __block CFArrayRef result = NULL; CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error); if (valueFetched == kCFBooleanTrue) { - SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account); + SOSPeerInfoRef myPI = account.peerInfo; if (myPI) { SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) { result = CFSetCopyValues(enabled); @@ -1525,8 +1496,8 @@ CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) { __block CFArrayRef views = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - views = SOSAccountCopyYetToSyncViews(account, error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + views = SOSAccountCopyYetToSyncViews(txn.account, error); return true; }); @@ -1554,8 +1525,8 @@ bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName, CFDataRef in SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagForView(CFStringRef viewName, CFErrorRef* error){ __block SOSBackupSliceKeyBagRef bskb = NULL; - (void) do_with_account(^ (SOSAccountRef account, SOSAccountTransactionRef txn) { - bskb = SOSAccountBackupSliceKeyBagForView(account, viewName, error); + (void) do_with_account(^ (SOSAccountTransaction* txn) { + bskb = SOSAccountBackupSliceKeyBagForView(txn.account, viewName, error); }); return bskb; } @@ -1594,17 +1565,18 @@ exit: CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){ __block CFDictionaryRef result = NULL; - __block CFErrorRef block_error = NULL; - - (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - SOSCCStatus status = SOSAccountGetCircleStatus(account, &block_error); - CFStringRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error); + + (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + CFErrorRef localError = NULL; + SOSCCStatus status = [txn.account getCircleStatus:&localError]; + + CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error); CFDictionaryRef escrowRecords = NULL; CFDictionaryRef record = NULL; switch(status) { case kSOSCCInCircle: //get the escrow record in the peer info! - escrowRecords = SOSPeerInfoCopyEscrowRecord(SOSAccountGetMyPeerInfo(account)); + escrowRecords = SOSPeerInfoCopyEscrowRecord(txn.account.peerInfo); if(escrowRecords){ record = CFDictionaryGetValue(escrowRecords, dsid); if(record) @@ -1618,7 +1590,7 @@ CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){ case kSOSCCNotInCircle: case kSOSCCCircleAbsent: //set the escrow record in the account expansion! - escrowRecords = SOSAccountGetValue(account, kSOSEscrowRecord, error); + escrowRecords = SOSAccountGetValue(txn.account, kSOSEscrowRecord, error); if(escrowRecords){ record = CFDictionaryGetValue(escrowRecords, dsid); if(record) @@ -1638,7 +1610,7 @@ CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){ CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error) { __block CFDictionaryRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { + (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { result = SOSBackupInformation(txn, error); return true; }); @@ -1650,9 +1622,10 @@ bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErr __block bool result = true; __block CFErrorRef block_error = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - SOSCCStatus status = SOSAccountGetCircleStatus(account, &block_error); - CFStringRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error); + (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + SOSCCStatus status = [txn.account getCircleStatus:&block_error]; + + CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error); CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent(); @@ -1674,7 +1647,7 @@ bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErr switch(status) { case kSOSCCInCircle: //set the escrow record in the peer info! - if(!SOSFullPeerInfoAddEscrowRecord(SOSAccountGetMyFullPeerInfo(account), dsid, escrowRecord, error)){ + if(!SOSFullPeerInfoAddEscrowRecord(txn.account.fullPeerInfo, dsid, escrowRecord, error)){ secdebug("accout", "Could not set escrow record in the full peer info"); result = false; } @@ -1686,7 +1659,7 @@ bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErr case kSOSCCCircleAbsent: //set the escrow record in the account expansion! - if(!SOSAccountAddEscrowRecords(account, dsid, escrowRecord, error)) { + if(!SOSAccountAddEscrowRecords(txn.account, dsid, escrowRecord, error)) { secdebug("account", "Could not set escrow record in expansion data"); result = false; } @@ -1708,20 +1681,16 @@ bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErr bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error) { - __block bool result = true; - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountAcceptApplicants(account, applicants, block_error); - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountAcceptApplicants(txn.account, applicants, block_error); }); } bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error) { - __block bool result = true; - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountRejectApplicants(account, applicants, block_error); - return result; + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountRejectApplicants(txn.account, applicants, block_error); }); } @@ -1729,8 +1698,8 @@ CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyPeers(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyPeers(txn.account, block_error); return result != NULL; }); @@ -1741,8 +1710,8 @@ CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyConcurringPeers(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyConcurringPeers(txn.account, block_error); return result != NULL; }); @@ -1753,9 +1722,9 @@ SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error) { __block SOSPeerInfoRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { // Create a copy to be DERed/sent back to client - result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSAccountGetMyPeerInfo(account), block_error); + result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error); return result != NULL; }); @@ -1766,7 +1735,7 @@ CFDataRef SOSCCCopyAccountState_Server(CFErrorRef* error) { __block CFDataRef accountState = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { // Copy account state from the keychain accountState = SOSAccountCopyAccountStateFromKeychain(block_error); return accountState != NULL; @@ -1779,7 +1748,7 @@ bool SOSCCDeleteAccountState_Server(CFErrorRef* error) { __block bool result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { // Delete account state from the keychain result = SOSAccountDeleteAccountStateFromKeychain(block_error); return result; @@ -1792,7 +1761,7 @@ CFDataRef SOSCCCopyEngineData_Server(CFErrorRef* error) { __block CFDataRef engineState = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { // Copy engine state from the keychain engineState = SOSAccountCopyEngineStateFromKeychain(block_error); return engineState != NULL; @@ -1805,7 +1774,7 @@ bool SOSCCDeleteEngineState_Server(CFErrorRef* error) { __block bool result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { // Delete engine state from the keychain result = SOSAccountDeleteEngineStateFromKeychain(block_error); return result; @@ -1819,12 +1788,12 @@ bool SOSCCDeleteEngineState_Server(CFErrorRef* error) SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){ __block SOSPeerInfoRef result = NULL; - (void) do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { if(SOSAccountSetBackupPublicKey(txn,newPublicBackup, error)){ - SOSAccountTransactionFinishAndRestart(txn); // Finish the transaction to update any changes to the peer info. + [txn restart]; // Finish the transaction to update any changes to the peer info. // Create a copy to be DERed/sent back to client - result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSAccountGetMyPeerInfo(account), block_error); + result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error); secdebug("backup", "SOSCCSetNewPublicBackupKey_Server, new public backup is set"); } else @@ -1838,8 +1807,8 @@ SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFEr } bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){ - return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - return SOSAccountSetBSKBagForAllSlices(account, aks_bag, setupV0Only, error); + return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountSetBSKBagForAllSlices(txn.account, aks_bag, setupV0Only, error); }); } @@ -1847,8 +1816,8 @@ CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error) { __block CFStringRef result = NULL; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountCopyIncompatibilityInfo(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountCopyIncompatibilityInfo(txn.account, block_error); return result != NULL; }); @@ -1868,20 +1837,18 @@ bool SOSCCCheckPeerAvailability_Server(CFErrorRef *error) }); __block int token = -1; - bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { peerSemaphore = dispatch_semaphore_create(0); - dispatch_retain(peerSemaphore); notify_register_dispatch(kSOSCCPeerAvailable, &token, time_out, ^(int token) { if(peerSemaphore != NULL){ dispatch_semaphore_signal(peerSemaphore); - dispatch_release(peerSemaphore); peerIsAvailable = true; notify_cancel(token); } }); - pingedPeersInCircle = SOSAccountCheckPeerAvailability(account, block_error); + pingedPeersInCircle = SOSAccountCheckPeerAvailability(txn.account, block_error); return pingedPeersInCircle; }); @@ -1889,13 +1856,9 @@ bool SOSCCCheckPeerAvailability_Server(CFErrorRef *error) dispatch_semaphore_wait(peerSemaphore, dispatch_time(DISPATCH_TIME_NOW, 7ull * NSEC_PER_SEC)); } - if(peerSemaphore != NULL) - dispatch_release(peerSemaphore); - if(time_out != NULL && peerSemaphore != NULL){ dispatch_sync(time_out, ^{ if(!peerIsAvailable){ - dispatch_release(peerSemaphore); peerSemaphore = NULL; notify_cancel(token); secnotice("peer available", "checking peer availability timed out, releasing semaphore"); @@ -1918,8 +1881,8 @@ bool SOSCCCheckPeerAvailability_Server(CFErrorRef *error) bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error) { - bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - return SOSAccountIsLastBackupPeer(account, block_error); + bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + return SOSAccountIsLastBackupPeer(txn.account, block_error); }); return result; } @@ -1930,8 +1893,8 @@ enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error) { __block enum DepartureReason result = kSOSDepartureReasonError; - (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - result = SOSAccountGetLastDepartureReason(account, block_error); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + result = SOSAccountGetLastDepartureReason(txn.account, block_error); return result != kSOSDepartureReasonError; }); @@ -1939,35 +1902,23 @@ enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error) } bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){ - __block bool result = true; - - return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { - SOSAccountSetLastDepartureReason(account, reason); - return result; - }); -} - -bool SOSCCSetHSA2AutoAcceptInfo_Server(CFDataRef pubKey, CFErrorRef *error) { - __block bool result = true; - - return do_with_account_if_after_first_unlock(error, ^(SOSAccountRef account, - SOSAccountTransactionRef txn, CFErrorRef *block_error) { - result = SOSAccountSetHSAPubKeyExpected(account, pubKey, error); - return (bool)result; + return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + SOSAccountSetLastDepartureReason(txn.account, reason); + return true; }); } bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error) { secnotice("updates", "Request for registering peers"); - return do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - return SOSAccountEnsurePeerRegistration(account, error); + return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountEnsurePeerRegistration(txn.account, error); }); } CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error) { __block CFSetRef result = NULL; - if (!do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { + if (!do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { result = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error); return result != NULL; })) { @@ -1988,7 +1939,7 @@ SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error) CFErrorRef action_error = NULL; - if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef* block_error) { + if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { return SOSAccountRequestSyncWithAllPeers(txn, block_error); })) { if (action_error) { @@ -2021,13 +1972,9 @@ void SOSCCRequestSyncWithPeer(CFStringRef peerID) { bool SOSCCRequestSyncWithPeerOverKVSUsingIDOnly_Server(CFStringRef deviceID, CFErrorRef *error) { - __block bool result = NULL; - - result = do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - result = SOSAccountSyncWithKVSUsingIDSID(account, deviceID, error); - return result; + return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountSyncWithKVSUsingIDSID(txn.account, deviceID, error); }); - return result; } void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs) { @@ -2096,7 +2043,7 @@ void SOSCCEnsurePeerRegistration(void) CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates) { CFArrayRef result = NULL; - SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set + SOSAccount* account = (__bridge SOSAccount *)(SOSKeychainAccountGetSharedAccount()); //HACK to make sure itemsChangedBlock is set (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault)); return result; @@ -2104,33 +2051,60 @@ CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates) SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error) { __block SOSPeerInfoRef application = NULL; - do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - application = SOSAccountCopyApplication(account, error); + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + application = SOSAccountCopyApplication(txn.account, error); return application != NULL; }); return application; } + +bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error) { + __block bool result = false; + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountCleanupAllKVSKeys(txn.account, error); + }); + return result; + +} + +bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error) +{ + __block bool result = false; + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountPopulateKVSWithBadKeys(txn.account, error); + }); + return result; +} CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error) { __block CFDataRef pbblob = NULL; - do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - pbblob = SOSAccountCopyCircleJoiningBlob(account, applicant, error); + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + pbblob = SOSAccountCopyCircleJoiningBlob(txn.account, applicant, error); return pbblob != NULL; }); return pbblob; } -bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, CFErrorRef *error) { - return do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - return SOSAccountJoinWithCircleJoiningBlob(account, joiningBlob, error); +CFDataRef SOSCCCopyInitialSyncData_Server(CFErrorRef *error) { + __block CFDataRef pbblob = NULL; + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + pbblob = SOSAccountCopyInitialSyncData(txn.account, error); + return pbblob != NULL; + }); + return pbblob; +} + +bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) { + return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + return SOSAccountJoinWithCircleJoiningBlob(txn.account, joiningBlob, version, error); }); } CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error) { __block CFBooleanRef result = NULL; - do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { - result = SOSAccountPeersHaveViewsEnabled(account, viewNames, error); + do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + result = SOSAccountPeersHaveViewsEnabled(txn.account, viewNames, error); return result != NULL; }); @@ -2138,23 +2112,18 @@ CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef } bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error){ - - __block bool result = NULL; - do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { + return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { if(recovery_key != NULL && CFDataGetLength(recovery_key) != 0) - result = SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error); + return SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error); else - result = SOSAccountClearRecoveryPublicKey(txn, recovery_key, error); - return result; + return SOSAccountClearRecoveryPublicKey(txn, recovery_key, error); }); - - return result; } CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error){ __block CFDataRef result = NULL; - do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { + do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { result = SOSAccountCopyRecoveryPublicKey(txn, error); return result != NULL; }); @@ -2163,13 +2132,59 @@ CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error){ } bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) { - return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { + return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { return SOSAccountMessageFromPeerIsPending(txn, peer, error); }); } bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) { - return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, SOSAccountTransactionRef txn, CFErrorRef *error) { + return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { return SOSAccountSendToPeerIsPending(txn, peer, error); }); } + +void SOSCCResetOTRNegotiation_Server(CFStringRef peerid) +{ + CFErrorRef localError = NULL; + do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + SOSAccountResetOTRNegotiationCoder(txn, peerid); + return true; + }); + if(localError) + { + secerror("error resetting otr negotation: %@", localError); + } +} + +void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup) +{ + CFErrorRef localError = NULL; + do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + SOSAccountTimerFiredSendNextMessage(txn, (__bridge NSString*)peerid, (__bridge NSString*)accessGroup); + return true; + }); + if(localError) + { + secerror("error sending next message: %@", localError); + } +} + +XPC_RETURNS_RETAINED xpc_endpoint_t +SOSCCCreateSOSEndpoint_server(CFErrorRef *error) +{ + SOSAccount* account = (__bridge SOSAccount *)(SOSKeychainAccountGetSharedAccount()); + return [account xpcControlEndpoint]; +} + +void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivKey, CFErrorRef error)) +{ + CFErrorRef error = NULL; + do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) { + SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo; + SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, err); + CFErrorRef errorArg = err ? *err : NULL; + action(signingKey, errorArg); + CFReleaseNull(signingKey); + return error == NULL; + }); +} diff --git a/OSX/sec/securityd/SecCAIssuerCache.c b/OSX/sec/securityd/SecCAIssuerCache.c index 7f0ca428..d5f593f7 100644 --- a/OSX/sec/securityd/SecCAIssuerCache.c +++ b/OSX/sec/securityd/SecCAIssuerCache.c @@ -249,9 +249,16 @@ errOut: } static void SecCAIssuerCacheInit(void) { +#if TARGET_OS_IPHONE WithPathInKeychainDirectory(CFSTR(kSecCAIssuerFileName), ^(const char *utf8String) { kSecCAIssuerCache = SecCAIssuerCacheCreate(utf8String); }); +#else + /* macOS caches should be in user cache dir */ + WithPathInUserCacheDirectory(CFSTR(kSecCAIssuerFileName), ^(const char *utf8String) { + kSecCAIssuerCache = SecCAIssuerCacheCreate(utf8String); + }); +#endif if (kSecCAIssuerCache) atexit(SecCAIssuerCacheGC); diff --git a/OSX/sec/securityd/SecCAIssuerRequest.c b/OSX/sec/securityd/SecCAIssuerRequest.c index 7f04b8e3..6c3fde1e 100644 --- a/OSX/sec/securityd/SecCAIssuerRequest.c +++ b/OSX/sec/securityd/SecCAIssuerRequest.c @@ -175,6 +175,8 @@ static void SecCAIssuerRequestCompleted(asynchttp_t *http, secdebug("caissuer", "response: %@ not parent, trying next caissuer", http->response); + /* We're re-using this http object, so we need to free all the old memory. */ + asynchttp_free(&request->http); SecCAIssuerRequestIssue(request); } diff --git a/OSX/sec/securityd/SecCertificateServer.c b/OSX/sec/securityd/SecCertificateServer.c new file mode 100644 index 00000000..5caa4a93 --- /dev/null +++ b/OSX/sec/securityd/SecCertificateServer.c @@ -0,0 +1,1318 @@ +/* + * 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@ + */ + +/* + * SecCertificateServer.c - SecCertificate and SecCertificatePathVC types + * with additonal validation context. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +// MARK: - +// MARK: SecCertificateVC +/******************************************************** + ************* SecCertificateVC object *************** + ********************************************************/ + +struct SecCertificateVC { + CFRuntimeBase _base; + SecCertificateRef certificate; + CFArrayRef usageConstraints; + bool optionallyEV; + bool isWeakHash; + bool require_revocation_response; +}; +CFGiblisWithHashFor(SecCertificateVC) + +static void SecCertificateVCDestroy(CFTypeRef cf) { + SecCertificateVCRef cvc = (SecCertificateVCRef) cf; + CFReleaseNull(cvc->certificate); + CFReleaseNull(cvc->usageConstraints); +} + +static Boolean SecCertificateVCCompare(CFTypeRef cf1, CFTypeRef cf2) { + SecCertificateVCRef cv1 = (SecCertificateVCRef) cf1; + SecCertificateVCRef cv2 = (SecCertificateVCRef) cf2; + if (!CFEqual(cv1->certificate, cv2->certificate)) { + return false; + } + /* CertificateVCs are the same if either does not have usage constraints. */ + if (cv1->usageConstraints && cv2->usageConstraints && + !CFEqual(cv1->usageConstraints, cv2->usageConstraints)) { + return false; + } + + return true; +} + +static CFHashCode SecCertificateVCHash(CFTypeRef cf) { + SecCertificateVCRef cvc = (SecCertificateVCRef) cf; + CFHashCode hashCode = 0; + hashCode += CFHash(cvc->certificate); + if (cvc->usageConstraints) { + hashCode += CFHash(cvc->usageConstraints); + } + return hashCode; +} + +static CFStringRef SecCertificateVCCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + SecCertificateVCRef cvc = (SecCertificateVCRef)cf; + return CFCopyDescription(cvc->certificate); +} + +static bool SecCertificateVCCouldBeEV(SecCertificateRef certificate) { + CFMutableDictionaryRef keySizes = NULL; + CFNumberRef rsaSize = NULL, ecSize = NULL; + bool isEV = false; + + /* 3. Subscriber Certificate. */ + + /* (a) certificate Policies */ + const SecCECertificatePolicies *cp; + cp = SecCertificateGetCertificatePolicies(certificate); + require_quiet(cp && cp->numPolicies > 0, notEV); + /* Now find at least one policy in here that has a qualifierID of id-qt 2 + and a policyQualifier that is a URI to the CPS and an EV policy OID. */ + uint32_t ix = 0; + bool found_ev_anchor_for_leaf_policy = false; + for (ix = 0; ix < cp->numPolicies; ++ix) { + if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) { + found_ev_anchor_for_leaf_policy = true; + } + } + require_quiet(found_ev_anchor_for_leaf_policy, notEV); + + /* (b) cRLDistributionPoint + (c) authorityInformationAccess + BRv1.3.4: MUST be present with OCSP Responder unless stapled response. + */ + + /* (d) basicConstraints + If present, the cA field MUST be set false. */ + const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); + if (bc) { + require_action_quiet(bc->isCA == false, notEV, + secnotice("ev", "Leaf has invalid basic constraints")); + } + + /* (e) keyUsage. */ + SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); + if (ku) { + require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV, + secnotice("ev", "Leaf has invalid key usage %u", ku)); + } + +#if 0 + /* The EV Cert Spec errata specifies this, though this is a check for SSL + not specifically EV. */ + + /* (e) extKeyUsage + + Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */ + SecCertificateCopyExtendedKeyUsage(certificate); +#endif + + /* 6.1.5 Key Sizes */ + CFAbsoluteTime jan2014 = 410227200; + require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV); + require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize); + if (SecCertificateNotValidBefore(certificate) < jan2014) { + /* At least RSA 1024 or ECC NIST P-256. */ + require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); + require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, + secnotice("ev", "Leaf's public key is too small for issuance before 2014")); + } else { + /* At least RSA 2028 or ECC NIST P-256. */ + require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV); + CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); + require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, + secnotice("ev", "Leaf's public key is too small for issuance after 2013")); + } + + /* 6.3.2 Validity Periods */ + CFAbsoluteTime jul2016 = 489024000; + CFAbsoluteTime notAfter = SecCertificateNotValidAfter(certificate); + CFAbsoluteTime notBefore = SecCertificateNotValidBefore(certificate); + if (SecCertificateNotValidBefore(certificate) < jul2016) { + /* Validity Period no greater than 60 months. + 60 months is no more than 5 years and 2 leap days. */ + CFAbsoluteTime maxPeriod = 60*60*24*(365*5+2); + require_action_quiet(notAfter - notBefore <= maxPeriod, notEV, + secnotice("ev", "Leaf's validity period is more than 60 months")); + } else { + /* Validity Period no greater than 39 months. + 39 months is no more than 3 years, 2 31-day months, + 1 30-day month, and 1 leap day */ + CFAbsoluteTime maxPeriod = 60*60*24*(365*3+2*31+30+1); + require_action_quiet(notAfter - notBefore <= maxPeriod, notEV, + secnotice("ev", "Leaf has validity period longer than 39 months and issued after 30 June 2016")); + } + + /* 7.1.3 Algorithm Object Identifiers */ + CFAbsoluteTime jan2016 = 473299200; + if (SecCertificateNotValidBefore(certificate) > jan2016) { + /* SHA-2 only */ + require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1, + notEV, secnotice("ev", "Leaf was issued with SHA-1 after 2015")); + } + + isEV = true; + +notEV: + CFReleaseNull(rsaSize); + CFReleaseNull(ecSize); + CFReleaseNull(keySizes); + return isEV; +} + + +SecCertificateVCRef SecCertificateVCCreate(SecCertificateRef certificate, CFArrayRef usageConstraints) { + if (!certificate) { return NULL; } + CFIndex size = sizeof(struct SecCertificateVC); + SecCertificateVCRef result = + (SecCertificateVCRef)_CFRuntimeCreateInstance(kCFAllocatorDefault, + SecCertificateVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); + if (!result) + return NULL; + result->certificate = CFRetainSafe(certificate); + result->isWeakHash = SecCertificateIsWeakHash(certificate); + result->optionallyEV = SecCertificateVCCouldBeEV(certificate); + + CFArrayRef emptyArray = NULL; + if (!usageConstraints) { + require_action_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit, CFReleaseNull(result)); + usageConstraints = emptyArray; + } + result->usageConstraints = CFRetainSafe(usageConstraints); +exit: + CFReleaseNull(emptyArray); + return result; +} + +// MARK: - +// MARK: SecCertificatePathVC +/******************************************************** + ************* SecCertificatePathVC object *************** + ********************************************************/ +struct SecCertificatePathVC { + CFRuntimeBase _base; + CFIndex count; + + /* Index of next parent source to search for parents. */ + CFIndex nextParentSource; + + /* Index of last certificate in chain who's signature has been verified. + 0 means nothing has been checked. 1 means the leaf has been verified + against it's issuer, etc. */ + CFIndex lastVerifiedSigner; + + /* Index of first self issued certificate in the chain. -1 mean there is + none. 0 means the leaf is self signed. */ + CFIndex selfIssued; + + /* True iff cert at index selfIssued does in fact self verify. */ + bool isSelfSigned; + + /* True if the root of this path is an anchor. Trustedness of the + * anchor is determined by the PVC. */ + bool isAnchored; + + policy_tree_t policy_tree; + uint8_t policy_tree_verification_result; + + bool isEV; + bool isCT; + bool is_allowlisted; + bool hasStrongHashes; + + void * rvcs; + CFIndex rvcCount; + + /* This is the score of the path after determining acceptance. */ + CFIndex score; + + bool pathValidated; + + SecCertificateVCRef certificates[]; +}; +CFGiblisWithHashFor(SecCertificatePathVC) + +static void SecCertificatePathVCPrunePolicyTree(SecCertificatePathVCRef certificatePath) { + if (certificatePath->policy_tree) { + policy_tree_prune(&certificatePath->policy_tree); + } +} + +static void SecCertificatePathVCDeleteRVCs(SecCertificatePathVCRef path) { + if (path->rvcs) { + CFIndex certIX, certCount = path->rvcCount; + for (certIX = 0; certIX < certCount; ++certIX) { + SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX]; + SecRVCDelete(rvc); + } + free(path->rvcs); + path->rvcs = NULL; + } +} + +static void SecCertificatePathVCDestroy(CFTypeRef cf) { + SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; + CFIndex ix; + SecCertificatePathVCDeleteRVCs(certificatePath); + SecCertificatePathVCPrunePolicyTree(certificatePath); + for (ix = 0; ix < certificatePath->count; ++ix) { + CFReleaseNull(certificatePath->certificates[ix]); + } +} + +static Boolean SecCertificatePathVCCompare(CFTypeRef cf1, CFTypeRef cf2) { + SecCertificatePathVCRef cp1 = (SecCertificatePathVCRef) cf1; + SecCertificatePathVCRef cp2 = (SecCertificatePathVCRef) cf2; + if (cp1->count != cp2->count) + return false; + CFIndex ix; + for (ix = 0; ix < cp1->count; ++ix) { + if (!CFEqual(cp1->certificates[ix], cp2->certificates[ix])) + return false; + } + + return true; +} + +static CFHashCode SecCertificatePathVCHash(CFTypeRef cf) { + SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; + CFHashCode hashCode = 0; + CFIndex ix; + for (ix = 0; ix < certificatePath->count; ++ix) { + hashCode += CFHash(certificatePath->certificates[ix]); + } + return hashCode; +} + +static CFStringRef SecCertificatePathVCCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + SecCertificatePathVCRef certificatePath = (SecCertificatePathVCRef) cf; + CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0); + CFStringRef typeStr = CFCopyTypeIDDescription(CFGetTypeID(cf)); + CFStringAppendFormat(desc, NULL, + CFSTR("<%@ certs: "), typeStr); + CFRelease(typeStr); + CFIndex ix; + for (ix = 0; ix < certificatePath->count; ++ix) { + if (ix > 0) { + CFStringAppend(desc, CFSTR(", ")); + } + CFStringRef str = CFCopyDescription(certificatePath->certificates[ix]); + CFStringAppend(desc, str); + CFRelease(str); + } + CFStringAppend(desc, CFSTR(" >")); + + return desc; +} + +/* Create a new certificate path from an old one. */ +SecCertificatePathVCRef SecCertificatePathVCCreate(SecCertificatePathVCRef path, + SecCertificateRef certificate, CFArrayRef usageConstraints) { + CFAllocatorRef allocator = kCFAllocatorDefault; + check(certificate); + CFIndex count; + CFIndex selfIssued, lastVerifiedSigner; + bool isSelfSigned; + if (path) { + count = path->count + 1; + lastVerifiedSigner = path->lastVerifiedSigner; + selfIssued = path->selfIssued; + isSelfSigned = path->isSelfSigned; + } else { + count = 1; + lastVerifiedSigner = 0; + selfIssued = -1; + isSelfSigned = false; + } + + CFIndex size = sizeof(struct SecCertificatePathVC) + + count * sizeof(SecCertificateRef); + SecCertificatePathVCRef result = + (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, + SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); + if (!result) + return NULL; + + memset((char*)result + sizeof(result->_base), 0, + sizeof(*result) - sizeof(result->_base)); + + result->count = count; + result->lastVerifiedSigner = lastVerifiedSigner; + result->selfIssued = selfIssued; + result->isSelfSigned = isSelfSigned; + CFIndex ix; + for (ix = 0; ix < count - 1; ++ix) { + result->certificates[ix] = path->certificates[ix]; + CFRetain(result->certificates[ix]); + } + + SecCertificateVCRef cvc = SecCertificateVCCreate(certificate, usageConstraints); + result->certificates[count - 1] = cvc; + + return result; +} + +SecCertificatePathVCRef SecCertificatePathVCCopyFromParent( + SecCertificatePathVCRef path, CFIndex skipCount) { + CFAllocatorRef allocator = kCFAllocatorDefault; + CFIndex count; + CFIndex selfIssued, lastVerifiedSigner; + bool isSelfSigned; + + /* Ensure we are at least returning a path of length 1. */ + if (skipCount < 0 || path->count < 1 + skipCount) + return NULL; + + count = path->count - skipCount; + lastVerifiedSigner = path->lastVerifiedSigner > skipCount + ? path->lastVerifiedSigner - skipCount : 0; + selfIssued = path->selfIssued >= skipCount + ? path->selfIssued - skipCount : -1; + isSelfSigned = path->selfIssued >= 0 ? path->isSelfSigned : false; + + CFIndex size = sizeof(struct SecCertificatePathVC) + + count * sizeof(SecCertificateRef); + SecCertificatePathVCRef result = + (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, + SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); + if (!result) + return NULL; + + memset((char*)result + sizeof(result->_base), 0, + sizeof(*result) - sizeof(result->_base)); + + result->count = count; + result->lastVerifiedSigner = lastVerifiedSigner; + result->selfIssued = selfIssued; + result->isSelfSigned = isSelfSigned; + result->isAnchored = path->isAnchored; + CFIndex ix; + for (ix = 0; ix < count; ++ix) { + CFIndex pathIX = ix + skipCount; + result->certificates[ix] = path->certificates[pathIX]; + CFRetain(result->certificates[ix]); + } + + return result; +} + +SecCertificatePathVCRef SecCertificatePathVCCopyAddingLeaf(SecCertificatePathVCRef path, + SecCertificateRef leaf) { + CFAllocatorRef allocator = kCFAllocatorDefault; + CFIndex count; + CFIndex selfIssued, lastVerifiedSigner; + bool isSelfSigned; + + /* First make sure the new leaf is signed by path's current leaf. */ + SecKeyRef issuerKey = SecCertificatePathVCCopyPublicKeyAtIndex(path, 0); + if (!issuerKey) + return NULL; + OSStatus status = SecCertificateIsSignedBy(leaf, issuerKey); + CFRelease(issuerKey); + if (status) + return NULL; + + count = path->count + 1; + lastVerifiedSigner = path->lastVerifiedSigner + 1; + selfIssued = path->selfIssued; + isSelfSigned = path->isSelfSigned; + + CFIndex size = sizeof(struct SecCertificatePathVC) + + count * sizeof(SecCertificateRef); + SecCertificatePathVCRef result = + (SecCertificatePathVCRef)_CFRuntimeCreateInstance(allocator, + SecCertificatePathVCGetTypeID(), size - sizeof(CFRuntimeBase), 0); + if (!result) + return NULL; + + memset((char*)result + sizeof(result->_base), 0, + sizeof(*result) - sizeof(result->_base)); + + result->count = count; + result->lastVerifiedSigner = lastVerifiedSigner; + result->selfIssued = selfIssued; + result->isSelfSigned = isSelfSigned; + result->isAnchored = path->isAnchored; + + CFIndex ix; + for (ix = 1; ix < count; ++ix) { + result->certificates[ix] = path->certificates[ix - 1]; + CFRetain(result->certificates[ix]); + } + SecCertificateVCRef leafVC = SecCertificateVCCreate(leaf, NULL); + result->certificates[0] = leafVC; + + return result; +} + +CFArrayRef SecCertificatePathVCCopyCertificates(SecCertificatePathVCRef path) { + CFMutableArrayRef outCerts = NULL; + size_t count = path->count; + require_quiet(outCerts = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks), exit); + SecCertificatePathVCForEachCertificate(path, ^(SecCertificateRef cert, bool * __unused stop) { + CFArrayAppendValue(outCerts, cert); + }); +exit: + return outCerts; +} + +SecCertificatePathRef SecCertificatePathVCCopyCertificatePath(SecCertificatePathVCRef path) { + CFArrayRef certs = SecCertificatePathVCCopyCertificates(path); + SecCertificatePathRef newPath = SecCertificatePathCreateWithCertificates(certs, NULL); + CFReleaseNull(certs); + return newPath; +} + +/* Record the fact that we found our own root cert as our parent + certificate. */ +void SecCertificatePathVCSetSelfIssued( + SecCertificatePathVCRef certificatePath) { + if (certificatePath->selfIssued >= 0) { + secdebug("trust", "%@ is already issued at %" PRIdCFIndex, certificatePath, + certificatePath->selfIssued); + return; + } + secdebug("trust", "%@ is self issued", certificatePath); + certificatePath->selfIssued = certificatePath->count - 1; + + /* now check that the selfIssued cert was actually self-signed */ + if (certificatePath->selfIssued >= 0 && !certificatePath->isSelfSigned) { + SecCertificateVCRef certVC = certificatePath->certificates[certificatePath->selfIssued]; + Boolean isSelfSigned = false; + OSStatus status = SecCertificateIsSelfSigned(certVC->certificate, &isSelfSigned); + if ((status == errSecSuccess) && isSelfSigned) { + certificatePath->isSelfSigned = true; + } else { + certificatePath->selfIssued = -1; + } + } +} + +void SecCertificatePathVCSetIsAnchored( + SecCertificatePathVCRef certificatePath) { + secdebug("trust", "%@ is anchored", certificatePath); + certificatePath->isAnchored = true; + + /* Now check if that anchor (last cert) was actually self-signed. + * In the non-anchor case, this is handled by SecCertificatePathVCSetSelfIssued. + * Because anchored chains immediately go into the candidate bucket in the trust + * server, we need to ensure that the self-signed/self-issued members are set + * for the purposes of scoring. */ + if (!certificatePath->isSelfSigned && certificatePath->count > 0) { + SecCertificateVCRef certVC = certificatePath->certificates[certificatePath->count - 1]; + Boolean isSelfSigned = false; + OSStatus status = SecCertificateIsSelfSigned(certVC->certificate, &isSelfSigned); + if ((status == errSecSuccess) && isSelfSigned) { + certificatePath->isSelfSigned = true; + if (certificatePath->selfIssued == -1) { + certificatePath->selfIssued = certificatePath->count - 1; + } + } + } +} + +/* Return the index of the first non anchor certificate in the chain that is + self signed counting from the leaf up. Return -1 if there is none. */ +CFIndex SecCertificatePathVCSelfSignedIndex( + SecCertificatePathVCRef certificatePath) { + if (certificatePath->isSelfSigned) + return certificatePath->selfIssued; + return -1; +} + +Boolean SecCertificatePathVCIsAnchored( + SecCertificatePathVCRef certificatePath) { + return certificatePath->isAnchored; +} + + +void SecCertificatePathVCSetNextSourceIndex( + SecCertificatePathVCRef certificatePath, CFIndex sourceIndex) { + certificatePath->nextParentSource = sourceIndex; +} + +CFIndex SecCertificatePathVCGetNextSourceIndex( + SecCertificatePathVCRef certificatePath) { + return certificatePath->nextParentSource; +} + +CFIndex SecCertificatePathVCGetCount( + SecCertificatePathVCRef certificatePath) { + check(certificatePath); + return certificatePath ? certificatePath->count : 0; +} + +SecCertificateRef SecCertificatePathVCGetCertificateAtIndex( + SecCertificatePathVCRef certificatePath, CFIndex ix) { + check(certificatePath && ix >= 0 && ix < certificatePath->count); + return (certificatePath->certificates[ix])->certificate; +} + +void SecCertificatePathVCForEachCertificate(SecCertificatePathVCRef path, void(^operation)(SecCertificateRef certificate, bool *stop)) { + bool stop = false; + CFIndex ix, count = path->count; + for (ix = 0; ix < count; ++ix) { + SecCertificateVCRef cvc = path->certificates[ix]; + operation(cvc->certificate, &stop); + if (stop) { break; } + } +} + +CFIndex SecCertificatePathVCGetIndexOfCertificate(SecCertificatePathVCRef path, + SecCertificateRef certificate) { + CFIndex ix, count = path->count; + for (ix = 0; ix < count; ++ix) { + SecCertificateVCRef cvc = path->certificates[ix]; + if (CFEqual(cvc->certificate, certificate)) + return ix; + } + return kCFNotFound; +} + +/* Return the root certificate for certificatePath. Note that root is just + the top of the path as far as it is constructed. It may or may not be + trusted or self signed. */ +SecCertificateRef SecCertificatePathVCGetRoot( + SecCertificatePathVCRef certificatePath) { + return SecCertificatePathVCGetCertificateAtIndex(certificatePath, + SecCertificatePathVCGetCount(certificatePath) - 1); +} + +SecKeyRef SecCertificatePathVCCopyPublicKeyAtIndex( + SecCertificatePathVCRef certificatePath, CFIndex ix) { + SecCertificateRef certificate = + SecCertificatePathVCGetCertificateAtIndex(certificatePath, ix); +#if TARGET_OS_OSX + return SecCertificateCopyPublicKey_ios(certificate); +#else + return SecCertificateCopyPublicKey(certificate); +#endif +} + +CFArrayRef SecCertificatePathVCGetUsageConstraintsAtIndex( + SecCertificatePathVCRef certificatePath, CFIndex ix) { + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + return cvc->usageConstraints; +} + +void SecCertificatePathVCSetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, + CFArrayRef newConstraints, CFIndex ix) { + CFArrayRef emptyArray = NULL; + if (!newConstraints) { + require_quiet(emptyArray = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks), exit); + newConstraints = emptyArray; + } + + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + cvc->usageConstraints = CFRetainSafe(newConstraints); +exit: + CFReleaseNull(emptyArray); + return; +} + +SecPathVerifyStatus SecCertificatePathVCVerify(SecCertificatePathVCRef certificatePath) { + check(certificatePath); + if (!certificatePath) + return kSecPathVerifyFailed; + for (; + certificatePath->lastVerifiedSigner < certificatePath->count - 1; + ++certificatePath->lastVerifiedSigner) { + SecKeyRef issuerKey = + SecCertificatePathVCCopyPublicKeyAtIndex(certificatePath, + certificatePath->lastVerifiedSigner + 1); + if (!issuerKey) + return kSecPathVerifiesUnknown; + SecCertificateVCRef cvc = certificatePath->certificates[certificatePath->lastVerifiedSigner]; + OSStatus status = SecCertificateIsSignedBy(cvc->certificate, + issuerKey); + CFRelease(issuerKey); + if (status) { + return kSecPathVerifyFailed; + } + } + + return kSecPathVerifySuccess; +} + +bool SecCertificatePathVCIsValid(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) { + __block bool result = true; + SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) { + if (!SecCertificateIsValid(certificate, verifyTime)) { + result = false; + } + }); + return result; +} + +bool SecCertificatePathVCHasWeakHash(SecCertificatePathVCRef certificatePath) { + CFIndex ix, count = certificatePath->count; + + if (certificatePath->hasStrongHashes) { + return false; + } + + if (SecCertificatePathVCIsAnchored(certificatePath)) { + /* For anchored paths, don't check the hash algorithm of the anchored cert, + * since we already decided to trust it. */ + count--; + } + for (ix = 0; ix < count; ++ix) { + if (certificatePath->certificates[ix]->isWeakHash) { + return true; + } + } + certificatePath->hasStrongHashes = true; + return false; +} + +bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath) { + __block CFDictionaryRef keySizes = NULL; + CFNumberRef rsaSize = NULL, ecSize = NULL; + __block bool result = false; + + /* RSA key sizes are 2048-bit or larger. EC key sizes are P-224 or larger. */ + require(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), errOut); + require(ecSize = CFNumberCreateWithCFIndex(NULL, 224), errOut); + const void *keys[] = { kSecAttrKeyTypeRSA, kSecAttrKeyTypeEC }; + const void *values[] = { rsaSize, ecSize }; + require(keySizes = CFDictionaryCreate(NULL, keys, values, 2, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); + SecCertificatePathVCForEachCertificate(certificatePath, ^(SecCertificateRef certificate, bool *stop) { + if (!SecCertificateIsAtLeastMinKeySize(certificate, keySizes)) { + result = true; + *stop = true; + } + }); + +errOut: + CFReleaseSafe(keySizes); + CFReleaseSafe(rsaSize); + CFReleaseSafe(ecSize); + return result; +} + +/* 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. */ + score += 1000; + /* Shorter chains ending in a self-signed cert are preferred. */ + score -= 1 * certificatePath->count; + } else { + /* 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; +} + +CFIndex SecCertificatePathVCGetScore(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return 0; } + return certificatePath->score; +} + +void SecCertificatePathVCSetScore(SecCertificatePathVCRef certificatePath, CFIndex score) { + /* We may "score" the same path twice -- if we "accept" a path but then + * decide to keep looking for a better one, we we process the same path + * again in "reject" which creates a lower score. Don't replace a higher + * score with a lower score. Use reset below to post-reject a path. */ + if (score > certificatePath->score) { + certificatePath->score = score; + } +} + +void SecCertificatePathVCResetScore(SecCertificatePathVCRef certificatePath) { + certificatePath->score = 0; +} + +void *SecCertificatePathVCGetRVCAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix) { + if (ix >= certificatePath->rvcCount) { + return NULL; + } + return &((SecRVCRef)certificatePath->rvcs)[ix]; +} + +bool SecCertificatePathVCIsRevocationDone(SecCertificatePathVCRef certificatePath) { + return (bool)certificatePath->rvcs; +} + +void SecCertificatePathVCAllocateRVCs(SecCertificatePathVCRef certificatePath, CFIndex certCount) { + certificatePath->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount); + certificatePath->rvcCount = certCount; +} + +/* Return 0 if any certs revocation checking failed, or the earliest date on + which one of the used revocation validation tokens (ocsp response or + crl) expires. */ +/* This function returns 0 to indicate revocation checking was not completed + for this certificate chain, otherwise returns the date at which the first + piece of revocation checking info we used expires. */ +CFAbsoluteTime SecCertificatePathVCGetEarliestNextUpdate(SecCertificatePathVCRef path) { + CFIndex certIX, certCount = path->count; + CFAbsoluteTime enu = NULL_TIME; + if (certCount <= 1 || !path->rvcs) { + return enu; + } + + for (certIX = 0; certIX < path->rvcCount; ++certIX) { + SecRVCRef rvc = &((SecRVCRef)path->rvcs)[certIX]; + CFAbsoluteTime thisCertNextUpdate = SecRVCGetEarliestNextUpdate(rvc); + if (thisCertNextUpdate == 0) { + if (certIX > 0) { + /* We allow for CA certs to not be revocation checked if they + have no ocspResponders nor CRLDPs to check against, but the leaf + must be checked in order for us to claim we did revocation + checking. */ + SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX); + CFArrayRef ocspResponders = NULL; + ocspResponders = SecCertificateGetOCSPResponders(cert); +#if ENABLE_CRLS + CFArrayRef crlDPs = NULL; + crlDPs = SecCertificateGetCRLDistributionPoints(cert); +#endif + if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0) +#if ENABLE_CRLS + && (!crlDPs || CFArrayGetCount(crlDPs) == 0) +#endif + ) { + /* We can't check this cert so we don't consider it a soft + failure that we didn't. Ideally we should support crl + checking and remove this workaround, since that more + strict. */ + continue; + } + } + secdebug("rvc", "revocation checking soft failure for cert: %ld", + certIX); + enu = thisCertNextUpdate; + break; + } + if (enu == 0 || thisCertNextUpdate < enu) { + enu = thisCertNextUpdate; + } + } + + secdebug("rvc", "revocation valid until: %lg", enu); + return enu; +} + +bool SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix) { + if (ix > certificatePath->count - 1) { return false; } + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + return cvc->require_revocation_response; +} + +void SecCertificatePathVCSetRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix) { + if (ix > certificatePath->count - 1) { return; } + SecCertificateVCRef cvc = certificatePath->certificates[ix]; + cvc->require_revocation_response = true; +} + +bool SecCertificatePathVCIsPathValidated(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->pathValidated; +} + +void SecCertificatePathVCSetPathValidated(SecCertificatePathVCRef certificatePath) { + certificatePath->pathValidated = true; +} + +bool SecCertificatePathVCIsEV(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->isEV; +} + +void SecCertificatePathVCSetIsEV(SecCertificatePathVCRef certificatePath, bool isEV) { + certificatePath->isEV = isEV; +} + +bool SecCertificatePathVCIsOptionallyEV(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->certificates[0]->optionallyEV; +} + +bool SecCertificatePathVCIsCT(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->isCT; +} + +void SecCertificatePathVCSetIsCT(SecCertificatePathVCRef certificatePath, bool isCT) { + certificatePath->isCT = isCT; +} + +bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath) { + if (!certificatePath) { return false; } + return certificatePath->is_allowlisted; +} + +void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted) { + certificatePath->is_allowlisted = isAllowlisted; +} + +/* MARK: policy_tree path verification */ +struct policy_tree_add_ctx { + oid_t p_oid; + policy_qualifier_t p_q; +}; + +/* For each node of depth i-1 in the valid_policy_tree where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ +static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) { + struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; + policy_set_t policy_set; + for (policy_set = node->expected_policy_set; + policy_set; + policy_set = policy_set->oid_next) { + if (oid_equal(policy_set->oid, info->p_oid)) { + policy_tree_add_child(node, &info->p_oid, info->p_q); + return true; + } + } + return false; +} + +/* If the valid_policy_tree includes a node of depth i-1 with the valid_policy anyPolicy, generate a child node with the following values: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ +static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) { + struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; + if (oid_equal(node->valid_policy, oidAnyPolicy)) { + policy_tree_add_child(node, &info->p_oid, info->p_q); + return true; + } + return false; +} + +/* Return true iff node has a child with a valid_policy equal to oid. */ +static bool policy_tree_has_child_with_oid(policy_tree_t node, + const oid_t *oid) { + policy_tree_t child; + for (child = node->children; child; child = child->siblings) { + if (oid_equal(child->valid_policy, (*oid))) { + return true; + } + } + return false; +} + +/* For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node, set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node. */ +static bool policy_tree_add_expected(policy_tree_t node, void *ctx) { + policy_qualifier_t p_q = (policy_qualifier_t)ctx; + policy_set_t policy_set; + bool added_node = false; + for (policy_set = node->expected_policy_set; + policy_set; + policy_set = policy_set->oid_next) { + if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) { + policy_tree_add_child(node, &policy_set->oid, p_q); + added_node = true; + } + } + return added_node; +} + +/* For each node where ID-P is the valid_policy, set expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ +static bool policy_tree_map_if_match(policy_tree_t node, void *ctx) { + /* Can't map oidAnyPolicy. */ + if (oid_equal(node->valid_policy, oidAnyPolicy)) + return false; + + const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; + size_t mapping_ix, mapping_count = pm->numMappings; + policy_set_t policy_set = NULL; + /* Generate the policy_set of sdps for matching idp */ + for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { + const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; + if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { + policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set)); + p_node->oid = mapping->subjectDomainPolicy; + p_node->oid_next = policy_set ? policy_set : NULL; + policy_set = p_node; + } + } + if (policy_set) { + policy_tree_set_expected_policy(node, policy_set); + return true; + } + return false; +} + +/* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1 that has a valid_policy of anyPolicy as follows: + (i) set the valid_policy to ID-P; + (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i; and + (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ +static bool policy_tree_map_if_any(policy_tree_t node, void *ctx) { + if (!oid_equal(node->valid_policy, oidAnyPolicy)) { + return false; + } + + const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; + size_t mapping_ix, mapping_count = pm->numMappings; + CFMutableDictionaryRef mappings = NULL; + CFDataRef idp = NULL; + CFDataRef sdp = NULL; + require_quiet(mappings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks), + errOut); + /* First we need to walk the mappings to generate the dictionary idp->sdps */ + for (mapping_ix = 0; mapping_ix < mapping_count; mapping_ix++) { + oid_t issuerDomainPolicy = pm->mappings[mapping_ix].issuerDomainPolicy; + oid_t subjectDomainPolicy = pm->mappings[mapping_ix].subjectDomainPolicy; + idp = CFDataCreateWithBytesNoCopy(NULL, issuerDomainPolicy.data, issuerDomainPolicy.length, kCFAllocatorNull); + sdp = CFDataCreateWithBytesNoCopy(NULL, subjectDomainPolicy.data, subjectDomainPolicy.length, kCFAllocatorNull); + CFMutableArrayRef sdps = (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp); + if (sdps) { + CFArrayAppendValue(sdps, sdp); + } else { + require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeArrayCallBacks), errOut); + CFArrayAppendValue(sdps, sdp); + CFDictionarySetValue(mappings, idp, sdps); + CFRelease(sdps); + } + CFReleaseNull(idp); + CFReleaseNull(sdp); + } + + /* Now we use the dictionary to generate the new nodes */ + CFDictionaryForEach(mappings, ^(const void *key, const void *value) { + CFDataRef idp = key; + CFArrayRef sdps = value; + + /* (i) set the valid_policy to ID-P; */ + oid_t p_oid; + p_oid.data = (uint8_t *)CFDataGetBytePtr(idp); + p_oid.length = CFDataGetLength(idp); + + /* (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i */ + policy_qualifier_t p_q = node->qualifier_set; + + /* (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ + __block policy_set_t p_expected = NULL; + CFArrayForEach(sdps, ^(const void *value) { + policy_set_t p_node = (policy_set_t)malloc(sizeof(*p_expected)); + p_node->oid.data = (void *)CFDataGetBytePtr(value); + p_node->oid.length = CFDataGetLength(value); + p_node->oid_next = p_expected ? p_expected : NULL; + p_expected = p_node; + }); + + policy_tree_add_sibling(node, &p_oid, p_q, p_expected); + }); + CFReleaseNull(mappings); + return true; + +errOut: + CFReleaseNull(mappings); + CFReleaseNull(idp); + CFReleaseNull(sdp); + return false; +} + +static bool policy_tree_map_delete_if_match(policy_tree_t node, void *ctx) { + /* Can't map oidAnyPolicy. */ + if (oid_equal(node->valid_policy, oidAnyPolicy)) + return false; + + const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; + size_t mapping_ix, mapping_count = pm->numMappings; + /* If this node matches any of the idps, delete it. */ + for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { + const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; + if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { + policy_tree_remove_node(&node); + break; + } + } + return true; +} + +bool SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecCertificatePathVCRef path, CFIndex ix) { + /* The SecCertificatePath only tells us the last self-issued cert. + * The chain may have more than one self-issued cert, so we need to + * do the comparison. */ + bool result = false; + SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, ix); + CFDataRef issuer = SecCertificateCopyNormalizedIssuerSequence(cert); + CFDataRef subject = SecCertificateCopyNormalizedSubjectSequence(cert); + if (issuer && subject && CFEqual(issuer, subject)) { + result = true; + } + CFReleaseNull(issuer); + CFReleaseNull(subject); + return result; +} + +enum { + kSecPolicyTreeVerificationUnknown = 0, + kSecPolicyTreeVerificationFalse, + kSecPolicyTreeVerificationTrue, +}; + +/* RFC 5280 policy tree processing */ +bool SecCertificatePathVCVerifyPolicyTree(SecCertificatePathVCRef path, bool anchor_trusted) { + if (!path) { return false; } + if (path->policy_tree_verification_result != kSecPolicyTreeVerificationUnknown) { + return (path->policy_tree_verification_result == kSecPolicyTreeVerificationTrue); + } + + /* Path Validation initialization */ + bool result = false; + path->policy_tree_verification_result = kSecPolicyTreeVerificationFalse; + bool initial_policy_mapping_inhibit = false; + bool initial_explicit_policy = false; + bool initial_any_policy_inhibit = false; + + SecCertificatePathVCPrunePolicyTree(path); + path->policy_tree = policy_tree_create(&oidAnyPolicy, NULL); + + assert((unsigned long)path->count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ + uint32_t n = (uint32_t)path->count; + if (anchor_trusted) { + n--; + } + + uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1; + uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1; + uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1; + + SecCertificateRef cert = NULL; + uint32_t i; + for (i = 1; i <= n; ++i) { + /* Process Cert */ + cert = SecCertificatePathVCGetCertificateAtIndex(path, n - i); + bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(path, n - i); + + /* (d) */ + if (path->policy_tree) { + const SecCECertificatePolicies *cp = + SecCertificateGetCertificatePolicies(cert); + size_t policy_ix, policy_count = cp ? cp->numPolicies : 0; + for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { + const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; + oid_t p_oid = policy->policyIdentifier; + policy_qualifier_t p_q = &policy->policyQualifiers; + struct policy_tree_add_ctx ctx = { p_oid, p_q }; + if (!oid_equal(p_oid, oidAnyPolicy)) { + if (!policy_tree_walk_depth(path->policy_tree, i - 1, + policy_tree_add_if_match, &ctx)) { + policy_tree_walk_depth(path->policy_tree, i - 1, + policy_tree_add_if_any, &ctx); + } + } + } + /* The certificate policies extension includes the policy + anyPolicy with the qualifier set AP-Q and either + (a) inhibit_anyPolicy is greater than 0 or + (b) i < n and the certificate is self-issued. */ + if (inhibit_any_policy > 0 || (i < n && is_self_issued)) { + for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { + const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; + oid_t p_oid = policy->policyIdentifier; + policy_qualifier_t p_q = &policy->policyQualifiers; + if (oid_equal(p_oid, oidAnyPolicy)) { + policy_tree_walk_depth(path->policy_tree, i - 1, + policy_tree_add_expected, (void *)p_q); + } + } + } + + policy_tree_prune_childless(&path->policy_tree, i - 1); + /* (e) */ + if (!cp) { + SecCertificatePathVCPrunePolicyTree(path); + } + } + + /* (f) Verify that either explicit_policy is greater than 0 or the + valid_policy_tree is not equal to NULL. */ + if (!path->policy_tree && explicit_policy == 0) { + /* valid_policy_tree is empty and explicit policy is 0, illegal. */ + secnotice("policy", "policy tree failure on cert %u", n - i); + goto errOut; + } + /* If Last Cert in Path */ + if (i == n) + break; + + /* Prepare for Next Cert */ + /* (a) verify that anyPolicy does not appear as an + issuerDomainPolicy or a subjectDomainPolicy */ + const SecCEPolicyMappings *pm = SecCertificateGetPolicyMappings(cert); + if (pm && pm->present) { + size_t mapping_ix, mapping_count = pm->numMappings; + for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { + const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; + if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy) + || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) { + /* Policy mapping uses anyPolicy, illegal. */ + secnotice("policy", "policy mapping anyPolicy failure %u", n - i); + goto errOut; + } + } + + /* (b) */ + /* (1) If the policy_mapping variable is greater than 0 */ + if (policy_mapping > 0 && path->policy_tree) { + if (!policy_tree_walk_depth(path->policy_tree, i, + policy_tree_map_if_match, (void *)pm)) { + /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1. */ + policy_tree_walk_depth(path->policy_tree, i, policy_tree_map_if_any, (void *)pm); + } + } else if (path->policy_tree) { + /* (i) delete each node of depth i in the valid_policy_tree + where ID-P is the valid_policy. */ + policy_tree_walk_depth(path->policy_tree, i, + policy_tree_map_delete_if_match, (void *)pm); + /* (ii) If there is a node in the valid_policy_tree of depth + i-1 or less without any child nodes, delete that + node. Repeat this step until there are no nodes of + depth i-1 or less without children. */ + policy_tree_prune_childless(&path->policy_tree, i - 1); + } + } + + /* (h) */ + if (!is_self_issued) { + if (explicit_policy) + explicit_policy--; + if (policy_mapping) + policy_mapping--; + if (inhibit_any_policy) + inhibit_any_policy--; + } + /* (i) */ + const SecCEPolicyConstraints *pc = + SecCertificateGetPolicyConstraints(cert); + if (pc) { + if (pc->requireExplicitPolicyPresent + && pc->requireExplicitPolicy < explicit_policy) { + explicit_policy = pc->requireExplicitPolicy; + } + if (pc->inhibitPolicyMappingPresent + && pc->inhibitPolicyMapping < policy_mapping) { + policy_mapping = pc->inhibitPolicyMapping; + } + } + /* (j) */ + const SecCEInhibitAnyPolicy *iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert); + if (iap && iap->skipCerts < inhibit_any_policy) { + inhibit_any_policy = iap->skipCerts; + } + + } /* end of path for loop */ + + /* Wrap up */ + cert = SecCertificatePathVCGetCertificateAtIndex(path, 0); + /* (a) */ + if (explicit_policy) + explicit_policy--; + /* (b) */ + const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert); + if (pc) { + if (pc->requireExplicitPolicyPresent + && pc->requireExplicitPolicy == 0) { + explicit_policy = 0; + } + } + + /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */ + + if (path->policy_tree) { +#if !defined(NDEBUG) + policy_tree_dump(path->policy_tree); +#endif + /* (g3c4) */ + //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1); + } + + /* If either (1) the value of explicit_policy variable is greater than + zero or (2) the valid_policy_tree is not NULL, then path processing + has succeeded. */ + if (!path->policy_tree && explicit_policy == 0) { + /* valid_policy_tree is empty and explicit policy is 0, illegal. */ + secnotice("policy", "policy tree failure on leaf"); + goto errOut; + } + + path->policy_tree_verification_result = kSecPolicyTreeVerificationTrue; + result = true; + +errOut: + return result; +} diff --git a/OSX/sec/securityd/SecCertificateServer.h b/OSX/sec/securityd/SecCertificateServer.h new file mode 100644 index 00000000..51585c2f --- /dev/null +++ b/OSX/sec/securityd/SecCertificateServer.h @@ -0,0 +1,154 @@ +/* + * 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@ + */ + +/* + * SecCertificateServer.h - SecCertificate and SecCertificatePath types + * with additonal validation context. + */ + + +#ifndef _SECURITY_SECCERTIFICATESERVER_H_ +#define _SECURITY_SECCERTIFICATESERVER_H_ + +#include + +#include +#include + +#include + + +typedef struct SecCertificateVC *SecCertificateVCRef; + +SecCertificateVCRef SecCertificateVCCreate(SecCertificateRef certificate, CFArrayRef usageContraints); + +typedef struct SecCertificatePathVC *SecCertificatePathVCRef; + +/* Create a new certificate path from an old one. */ +SecCertificatePathVCRef SecCertificatePathVCCreate(SecCertificatePathVCRef path, + SecCertificateRef certificate, CFArrayRef usageConstraints); + +SecCertificatePathVCRef SecCertificatePathVCCopyAddingLeaf(SecCertificatePathVCRef path, + SecCertificateRef leaf); + +/* Return a new certificate path without the first skipCount certificates. */ +SecCertificatePathVCRef SecCertificatePathVCCopyFromParent(SecCertificatePathVCRef path, CFIndex skipCount); + +/* Create an array of SecCertificateRefs from a certificate path. */ +CFArrayRef SecCertificatePathVCCopyCertificates(SecCertificatePathVCRef path); + +SecCertificatePathRef SecCertificatePathVCCopyCertificatePath(SecCertificatePathVCRef path); + +/* Record the fact that we found our own root cert as our parent + certificate. */ +void SecCertificatePathVCSetSelfIssued(SecCertificatePathVCRef certificatePath); +bool SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecCertificatePathVCRef path, CFIndex ix); + +void SecCertificatePathVCSetIsAnchored(SecCertificatePathVCRef certificatePath); + +/* Return the index of the first non anchor certificate in the chain that is + self signed counting from the leaf up. Return -1 if there is none. */ +CFIndex SecCertificatePathVCSelfSignedIndex(SecCertificatePathVCRef certificatePath); + +Boolean SecCertificatePathVCIsAnchored(SecCertificatePathVCRef certificatePath); + +void SecCertificatePathVCSetNextSourceIndex(SecCertificatePathVCRef certificatePath, CFIndex sourceIndex); + +CFIndex SecCertificatePathVCGetNextSourceIndex(SecCertificatePathVCRef certificatePath); + +CFIndex SecCertificatePathVCGetCount(SecCertificatePathVCRef certificatePath); + +SecCertificateRef SecCertificatePathVCGetCertificateAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); + +void SecCertificatePathVCForEachCertificate(SecCertificatePathVCRef path, void(^operation)(SecCertificateRef certificate, bool *stop)); + +/* Return the index of certificate in path or kCFNotFound if certificate is + not in path. */ +CFIndex SecCertificatePathVCGetIndexOfCertificate(SecCertificatePathVCRef path, + SecCertificateRef certificate); + +/* Return the root certificate for certificatePath. Note that root is just + the top of the path as far as it is constructed. It may or may not be + trusted or self signed. */ +SecCertificateRef SecCertificatePathVCGetRoot(SecCertificatePathVCRef certificatePath); + +CFArrayRef SecCertificatePathVCGetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); + +void SecCertificatePathVCSetUsageConstraintsAtIndex(SecCertificatePathVCRef certificatePath, + CFArrayRef newConstraints, CFIndex ix); + +SecKeyRef SecCertificatePathVCCopyPublicKeyAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); + +typedef CFIndex SecPathVerifyStatus; +enum { + kSecPathVerifiesUnknown = -1, + kSecPathVerifySuccess = 0, + kSecPathVerifyFailed = 1 +}; + +SecPathVerifyStatus SecCertificatePathVCVerify(SecCertificatePathVCRef certificatePath); + +bool SecCertificatePathVCIsValid(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime); + +bool SecCertificatePathVCHasWeakHash(SecCertificatePathVCRef certificatePath); + +bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath); + +/* Score */ +CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, + CFAbsoluteTime verifyTime); +CFIndex SecCertificatePathVCGetScore(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetScore(SecCertificatePathVCRef certificatePath, CFIndex score); // only sets score if new score is higher +void SecCertificatePathVCResetScore(SecCertificatePathVCRef certificatePath); // reset score to 0 + +/* Revocation */ +bool SecCertificatePathVCIsRevocationDone(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCAllocateRVCs(SecCertificatePathVCRef certificatePath, CFIndex certCount); +CFAbsoluteTime SecCertificatePathVCGetEarliestNextUpdate(SecCertificatePathVCRef path); +void *SecCertificatePathVCGetRVCAtIndex(SecCertificatePathVCRef certificatePath, CFIndex ix); // Returns a SecRVCRef +bool SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix); +void SecCertificatePathVCSetRevocationRequiredForCertificateAtIndex(SecCertificatePathVCRef certificatePath, + CFIndex ix); + +/* Did we already validate this path (setting EV, CT, RVC, etc.) */ +bool SecCertificatePathVCIsPathValidated(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetPathValidated(SecCertificatePathVCRef certificatePath); + +/* EV */ +bool SecCertificatePathVCIsEV(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetIsEV(SecCertificatePathVCRef certificatePath, bool isEV); +bool SecCertificatePathVCIsOptionallyEV(SecCertificatePathVCRef certificatePath); + +/* CT */ +bool SecCertificatePathVCIsCT(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetIsCT(SecCertificatePathVCRef certificatePath, bool isCT); + +/* Allowlist */ +bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath); +void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted); + +/* Policy Tree */ +bool SecCertificatePathVCVerifyPolicyTree(SecCertificatePathVCRef path, bool anchor_trusted); + +#endif /* _SECURITY_SECCERTIFICATESERVER_H_ */ diff --git a/OSX/sec/securityd/SecCertificateSource.c b/OSX/sec/securityd/SecCertificateSource.c index 76811f4c..97e2b64a 100644 --- a/OSX/sec/securityd/SecCertificateSource.c +++ b/OSX/sec/securityd/SecCertificateSource.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -210,9 +211,10 @@ struct SecItemCertificateSource { }; typedef struct SecItemCertificateSource *SecItemCertificateSourceRef; -static CF_RETURNS_RETAINED CFTypeRef SecItemCertificateSourceResultsPost(CFTypeRef raw_results) { +static CF_RETURNS_RETAINED CFArrayRef _Nullable SecItemCertificateSourceResultsPost(CFTypeRef raw_results) { + CFMutableArrayRef result = NULL; if (isArray(raw_results)) { - CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks); + result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks); CFArrayForEach(raw_results, ^(const void *value) { SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, value); if (cert) { @@ -220,54 +222,32 @@ static CF_RETURNS_RETAINED CFTypeRef SecItemCertificateSourceResultsPost(CFTypeR CFRelease(cert); } }); - return result; } else if (isData(raw_results)) { - return SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)raw_results); + result = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(raw_results), &kCFTypeArrayCallBacks); + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)raw_results); + if (cert) { + CFArrayAppendValue(result, cert); + CFRelease(cert); + } } - return NULL; + return result; } static bool SecItemCertificateSourceCopyParents( SecCertificateSourceRef source, SecCertificateRef certificate, void *context, SecCertificateSourceParents callback) { SecItemCertificateSourceRef msource = (SecItemCertificateSourceRef)source; - /* FIXME: Search for things other than just subject of our issuer if we - have a subjectID or authorityKeyIdentifier. */ - CFDataRef normalizedIssuer = - SecCertificateGetNormalizedIssuerContent(certificate); - const void *keys[] = { - kSecClass, - kSecReturnData, - kSecMatchLimit, - kSecAttrSubject - }, - *values[] = { - kSecClassCertificate, - kCFBooleanTrue, - kSecMatchLimitAll, - normalizedIssuer - }; - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, - NULL, NULL); - CFTypeRef results = NULL; - SecurityClient client = { - .task = NULL, - .accessGroups = msource->accessGroups, - .allowSystemKeychain = true, - .allowSyncBubbleKeychain = false, - .isNetworkExtension = false, - }; - - /* We can make this async or run this on a queue now easily. */ + CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); + CFErrorRef localError = NULL; - if (!_SecItemCopyMatching(query, &client, &results, &localError)) { + CFArrayRef results = SecItemCopyParentCertificates_ios(normalizedIssuer, msource->accessGroups, &localError); + if (!results) { if (localError && (CFErrorGetCode(localError) != errSecItemNotFound)) { - secdebug("trust", "_SecItemCopyMatching: %@", localError); + secdebug("trust", "SecItemCopyParentCertificates_ios: %@", localError); } CFReleaseSafe(localError); } - CFRelease(query); - CFTypeRef certs = SecItemCertificateSourceResultsPost(results); + CFArrayRef certs = SecItemCertificateSourceResultsPost(results); CFReleaseSafe(results); callback(context, certs); CFReleaseSafe(certs); @@ -286,41 +266,17 @@ static bool SecItemCertificateSourceContains(SecCertificateSourceRef source, #else SecCertificateCopySerialNumber(certificate); #endif - const void *keys[] = { - kSecClass, - kSecMatchLimit, - kSecAttrIssuer, - kSecAttrSerialNumber - }, - *values[] = { - kSecClassCertificate, - kSecMatchLimitOne, - normalizedIssuer, - serialNumber - }; - SecurityClient client = { - .task = NULL, - .accessGroups = msource->accessGroups, - .allowSystemKeychain = true, - .allowSyncBubbleKeychain = false, - .isNetworkExtension = false, - }; - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, NULL, NULL); CFErrorRef localError = NULL; - CFTypeRef results = NULL; - bool ok = _SecItemCopyMatching(query, &client, &results, &localError); - CFReleaseSafe(query); - CFReleaseSafe(serialNumber); - CFReleaseSafe(normalizedIssuer); - CFReleaseSafe(results); - if (!ok) { + bool result = SecItemCertificateExists(normalizedIssuer, serialNumber, msource->accessGroups, &localError); + if (localError) { if (CFErrorGetCode(localError) != errSecItemNotFound) { - secdebug("trust", "_SecItemCopyMatching: %@", localError); + secdebug("trust", "SecItemCertificateExists_ios: %@", localError); } CFReleaseSafe(localError); - return false; } - return true; + CFReleaseSafe(serialNumber); + CFReleaseSafe(normalizedIssuer); + return result; } SecCertificateSourceRef SecItemCertificateSourceCreate(CFArrayRef accessGroups) { @@ -376,14 +332,14 @@ static CFArrayRef SecSystemAnchorSourceCopyUsageConstraints(SecCertificateSource SecCertificateRef __unused certificate) { CFMutableArrayRef result = NULL; - CFMutableDictionaryRef options = NULL, hashConstraint = NULL, trustRoot = NULL; + CFMutableDictionaryRef options = NULL, strengthConstraints = NULL, trustRoot = NULL; CFNumberRef trustResult = NULL; require_quiet(options = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), out); - require_quiet(hashConstraint = CFDictionaryCreateMutable(NULL, 1, + require_quiet(strengthConstraints = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), out); @@ -397,17 +353,18 @@ static CFArrayRef SecSystemAnchorSourceCopyUsageConstraints(SecCertificateSource CFDictionaryAddValue(trustRoot, kSecTrustSettingsResult, trustResult); CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue); - CFDictionaryAddValue(hashConstraint, kSecTrustSettingsPolicyOptions, options); + CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakKey, kCFBooleanTrue); + CFDictionaryAddValue(strengthConstraints, kSecTrustSettingsPolicyOptions, options); require_quiet(result = CFArrayCreateMutable(NULL, 2, &kCFTypeArrayCallBacks), out); - CFArrayAppendValue(result, hashConstraint); + CFArrayAppendValue(result, strengthConstraints); CFArrayAppendValue(result, trustRoot); out: CFReleaseNull(options); CFReleaseNull(trustResult); CFReleaseNull(trustRoot); - CFReleaseNull(hashConstraint); + CFReleaseNull(strengthConstraints); return result; } @@ -495,7 +452,12 @@ static CFArrayRef SecUserAnchorSourceCopyUsageConstraints(SecCertificateSourceRe CFArrayRef usageConstraints = NULL; bool ok = _SecTrustStoreCopyUsageConstraints(SecTrustStoreForDomain(kSecTrustStoreDomainUser), digest, &usageConstraints, NULL); - return (ok) ? usageConstraints : NULL; + if (ok) { + return usageConstraints; + } else { + CFReleaseNull(usageConstraints); + return NULL; + } } static bool SecUserAnchorSourceContains(SecCertificateSourceRef source, @@ -643,7 +605,7 @@ const SecCertificateSourceRef kSecCAIssuerSource = &_kSecCAIssuerSource; static bool SecLegacyCertificateSourceCopyParents( SecCertificateSourceRef source, SecCertificateRef certificate, void *context, SecCertificateSourceParents callback) { - CFArrayRef parents = SecItemCopyParentCertificates(certificate, NULL); + CFArrayRef parents = SecItemCopyParentCertificates_osx(certificate, NULL); callback(context, parents); CFReleaseSafe(parents); return true; @@ -677,7 +639,7 @@ const SecCertificateSourceRef kSecLegacyCertificateSource = &_kSecLegacyCertific static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate, void *context, SecCertificateSourceParents callback) { CFMutableArrayRef anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayRef parents = SecItemCopyParentCertificates(certificate, NULL); + CFArrayRef parents = SecItemCopyParentCertificates_osx(certificate, NULL); CFArrayRef trusted = NULL; if (parents == NULL) { goto finish; diff --git a/OSX/sec/securityd/SecDbItem.c b/OSX/sec/securityd/SecDbItem.c index 825416f6..2bf7414d 100644 --- a/OSX/sec/securityd/SecDbItem.c +++ b/OSX/sec/securityd/SecDbItem.c @@ -44,16 +44,21 @@ #include #include +#include + // MARK: type converters CFStringRef copyString(CFTypeRef obj) { CFTypeID tid = CFGetTypeID(obj); - if (tid == CFStringGetTypeID()) + if (tid == CFStringGetTypeID()) { return CFStringCreateCopy(0, obj); - else if (tid == CFDataGetTypeID()) + }else if (tid == CFDataGetTypeID()) { return CFStringCreateFromExternalRepresentation(0, obj, kCFStringEncodingUTF8); - else + } else if (tid == CFUUIDGetTypeID()) { + return CFUUIDCreateString(NULL, obj); + } else { return NULL; + } } CFDataRef copyData(CFTypeRef obj) { @@ -78,8 +83,12 @@ CFTypeRef copyUUID(CFTypeRef obj) { if (length != 0 && length != 16) return NULL; return CFDataCreateCopy(NULL, obj); - } if (tid == CFNullGetTypeID()) { + } else if (tid == CFNullGetTypeID()) { return CFDataCreate(NULL, NULL, 0); + } else if (tid == CFUUIDGetTypeID()) { + CFUUIDBytes uuidbytes = CFUUIDGetUUIDBytes(obj); + CFDataRef uuiddata = CFDataCreate(NULL, (void*) &uuidbytes, sizeof(uuidbytes)); + return uuiddata; } else { return NULL; } @@ -218,7 +227,8 @@ static bool SecDbIsTombstoneDbInsertAttr(const SecDbAttr *attr) { #endif static bool SecDbIsTombstoneDbUpdateAttr(const SecDbAttr *attr) { - return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbRowIdAttr; + // We add AuthenticatedData to include UUIDs, which can't be primary keys + return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbRowIdAttr || (attr->flags & kSecDbInAuthenticatedDataFlag); } CFTypeRef SecDbAttrCopyDefaultValue(const SecDbAttr *attr, CFErrorRef *error) { @@ -731,6 +741,7 @@ static SecDbItemRef SecDbItemCreate(CFAllocatorRef allocator, const SecDbClass * item->keybag = keybag; item->_edataState = kSecDbItemDirty; item->cryptoOp = kAKSKeyOpDecrypt; + return item; } @@ -981,12 +992,12 @@ SecDbItemRef SecDbItemCreateWithEncryptedData(CFAllocatorRef allocator, const Se bool SecDbItemInV2(SecDbItemRef item) { const SecDbClass *iclass = SecDbItemGetClass(item); return (SecDbItemGetCachedValueWithName(item, kSecAttrSyncViewHint) == NULL && - (iclass == &genp_class || iclass == &inet_class || iclass == &keys_class || iclass == &cert_class)); + (iclass == genp_class() || iclass == inet_class() || iclass == keys_class() || iclass == cert_class())); } // Return true iff an item for which SecDbItemIsSyncable() and SecDbItemInV2() already return true should be part of the v0 view. bool SecDbItemInV2AlsoInV0(SecDbItemRef item) { - return (SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL && SecDbItemGetClass(item) != &cert_class); + return (SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL && SecDbItemGetClass(item) != cert_class()); } SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates, CFErrorRef *error) { @@ -1067,6 +1078,18 @@ static SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFBooleanRef makeT return new_item; } +bool SecDbItemIsEngineInternalState(SecDbItemRef itemObject) { + // Only used for controlling logging + // Use agrp=com.apple.security.sos, since it is not encrypted + if (!itemObject) { + return false; + } + const SecDbAttr *agrp = SecDbAttrWithKey(SecDbItemGetClass(itemObject), kSecAttrAccessGroup, NULL); + CFTypeRef cfval = SecDbItemGetValue(itemObject, agrp, NULL); + return cfval && CFStringCompareSafe(cfval, kSOSInternalAccessGroup, NULL) == kCFCompareEqualTo; +} + + // MARK: - // MARK: SQL Construction helpers -- These should become private in the future @@ -1371,12 +1394,20 @@ static bool SecDbItemDoInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFEr secnotice("item", "inserted %@", item); SecDbItemRecordUpdate(dbconn, NULL, item); } else { - secnotice("item", "insert failed for item %@ with %@", item, error ? *error : NULL); + if (SecDbItemIsEngineInternalState(item)) { + secdebug ("item", "insert failed for item %@ with %@", item, error ? *error : NULL); + } else { + secnotice("item", "insert failed for item %@ with %@", item, error ? *error : NULL); + } } return ok; } +bool SecErrorIsSqliteDuplicateItemError(CFErrorRef error) { + return error && CFErrorGetCode(error) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(error)); +} + bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)) { __block CFErrorRef localError = NULL; __block bool ok = SecDbItemDoInsert(item, dbconn, &localError); @@ -1490,7 +1521,13 @@ bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnec CFRelease(sql); } if (ok) { - secnotice("item", "replaced %@ with %@ in %@", old_item, new_item, dbconn); + if (SecDbItemIsEngineInternalState(old_item)) { + secdebug ("item", "replaced %@ in %@", old_item, dbconn); + secdebug ("item", " with %@ in %@", new_item, dbconn); + } else { + secnotice("item", "replaced %@ in %@", old_item, dbconn); + secnotice("item", " with %@ in %@", new_item, dbconn); + } SecDbItemRecordUpdate(dbconn, old_item, new_item); } return ok; @@ -1572,7 +1609,7 @@ static bool SecDbItemDeleteTombstone(SecDbItemRef item, SecDbConnectionRef dbcon #endif // Replace old_item with new_item. If primary keys are the same this does an update otherwise it does a delete + add -bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error) { +bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool uuid_from_primary_key, CFErrorRef *error) { __block bool ok = true; __block CFErrorRef localError = NULL; @@ -1584,6 +1621,11 @@ bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnecti bool pk_equal = ok && CFEqual(old_pk, new_pk); if (pk_equal) { ok = SecDbItemMakeYounger(new_item, old_item, error); + } else if(!CFEqualSafe(makeTombstone, kCFBooleanFalse) && SecCKKSIsEnabled()) { + // The primary keys aren't equal, and we're going to make a tombstone. + // Help CKKS out: the tombstone should have the existing item's UUID, and the newly updated item should have a new UUID. + + s3dl_item_make_new_uuid(new_item, uuid_from_primary_key, error); } ok = ok && SecDbItemDoUpdate(old_item, new_item, dbconn, &localError, ^bool(const SecDbAttr *attr) { return attr->kind == kSecDbRowIdAttr; diff --git a/OSX/sec/securityd/SecDbItem.h b/OSX/sec/securityd/SecDbItem.h index ce695f5a..c4132de8 100644 --- a/OSX/sec/securityd/SecDbItem.h +++ b/OSX/sec/securityd/SecDbItem.h @@ -80,6 +80,7 @@ enum { kSecDbInAuthenticatedDataFlag = (1 << 13), // attr is in authenticated data kSecDbSyncPrimaryKeyV0 = (1 << 14), kSecDbSyncPrimaryKeyV2 = (1 << 15), + kSecDbSyncFlag = (1 << 16), }; #define SecVersionDbFlag(v) ((v & 0xFF) << 8) @@ -104,6 +105,7 @@ struct SecDbAttr { typedef struct SecDbClass { CFStringRef name; + bool itemclass; // true if keychain items are stored in this class, false otherwise const SecDbAttr *attrs[]; } SecDbClass; @@ -208,6 +210,9 @@ SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)); +// 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); bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error); @@ -218,7 +223,7 @@ bool SecDbItemDoDeleteSilently(SecDbItemRef item, SecDbConnectionRef dbconn, CFE bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)); // High level update, will replace tombstones and create them if needed. -bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error); +bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool uuid_from_primary_key, CFErrorRef *error); // MARK: - @@ -254,6 +259,9 @@ bool SecErrorPropagate(CFErrorRef possibleError CF_CONSUMED, CFErrorRef *error) bool SecDbItemInV2(SecDbItemRef item); bool SecDbItemInV2AlsoInV0(SecDbItemRef item); +// For debug output filtering +bool SecDbItemIsEngineInternalState(SecDbItemRef itemObject); + __END_DECLS #endif /* _SECURITYD_SECDBITEM_H_ */ diff --git a/OSX/sec/securityd/SecDbKeychainItem.c b/OSX/sec/securityd/SecDbKeychainItem.c index b934d3a6..25e042d1 100644 --- a/OSX/sec/securityd/SecDbKeychainItem.c +++ b/OSX/sec/securityd/SecDbKeychainItem.c @@ -568,7 +568,7 @@ bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessContro attributes = s3dl_item_v3_decode(plainText, error); } - require_action_quiet(attributes, out, { ok = false; secerror("decode v%d failed: %@ [item: %@]", version, error ? *error : NULL, plainText); }); + require_action_quiet(attributes, out, { ok = false; secerror("decode v%d failed: %@", version, error ? *error : NULL); }); #if USE_KEYSTORE if (version >= 4 && authenticated_attributes != NULL) { @@ -881,7 +881,7 @@ static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) { if (!isString(agrp) || !isString(accessible)) return ok; - if (SecDbItemGetClass(item) == &genp_class && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) { + if (SecDbItemGetClass(item) == genp_class() && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) { CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService); if (!isString(svce)) return ok; if (CFEqual(agrp, CFSTR("apple"))) { @@ -900,7 +900,7 @@ static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) { } } } - } else if (SecDbItemGetClass(item) == &inet_class && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) { + } else if (SecDbItemGetClass(item) == inet_class() && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) { if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) { ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error); } else if (CFEqual(agrp, CFSTR("apple"))) { @@ -981,7 +981,7 @@ bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error) if (!isString(agrp)) return true; - if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == &inet_class) { + if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == inet_class()) { CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer); CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol); CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType); @@ -1027,7 +1027,7 @@ bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRe CFStringRef className; sqlite3_int64 rowid; - if (!_SecItemParsePersistentRef(ref, &className, &rowid)) + if (!_SecItemParsePersistentRef(ref, &className, &rowid, NULL)) return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref); if (!CFEqual(SecDbItemGetClass(item)->name, className)) @@ -1056,10 +1056,24 @@ static CFTypeRef SecDbItemCopyDigestWithMask(SecDbItemRef item, CFOptionFlags ma return digest; } +static CFTypeRef SecDbItemCopySHA256DigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) { + CFDataRef digest = NULL; + CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error); + if (der) { + digest = CFDataCopySHA256Digest(der, error); + CFRelease(der); + } + return digest; +} + CFTypeRef SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { return SecDbItemCopyDigestWithMask(item, kSecDbPrimaryKeyFlag, error); } +CFTypeRef SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item, CFErrorRef *error) { + return SecDbItemCopySHA256DigestWithMask(item, kSecDbPrimaryKeyFlag, error); +} + CFTypeRef SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) { return SecDbItemCopyDigestWithMask(item, kSecDbInHashFlag, error); } diff --git a/OSX/sec/securityd/SecDbKeychainItem.h b/OSX/sec/securityd/SecDbKeychainItem.h index b5a7ea6c..35ebd36e 100644 --- a/OSX/sec/securityd/SecDbKeychainItem.h +++ b/OSX/sec/securityd/SecDbKeychainItem.h @@ -46,6 +46,7 @@ bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRe bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *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); diff --git a/OSX/sec/securityd/SecDbQuery.c b/OSX/sec/securityd/SecDbQuery.c index 64338d35..119f4f2e 100644 --- a/OSX/sec/securityd/SecDbQuery.c +++ b/OSX/sec/securityd/SecDbQuery.c @@ -194,27 +194,16 @@ __unused static inline Pair query_match_at(const Query *q, CFIndex ix) const SecDbClass *kc_class_with_name(CFStringRef name) { if (isString(name)) { -#if 0 - // TODO Iterate kc_db_classes and look for name == class->name. - // Or get clever and switch on first letter of class name and compare to verify - static const void *kc_db_classes[] = { - &genp_class, - &inet_class, - &cert_class, - &keys_class, - &identity_class - }; -#endif if (CFEqual(name, kSecClassGenericPassword)) - return &genp_class; + return genp_class(); else if (CFEqual(name, kSecClassInternetPassword)) - return &inet_class; + return inet_class(); else if (CFEqual(name, kSecClassCertificate)) - return &cert_class; + return cert_class(); else if (CFEqual(name, kSecClassKey)) - return &keys_class; + return keys_class(); else if (CFEqual(name, kSecClassIdentity)) - return &identity_class; + return identity_class(); } return NULL; } @@ -331,6 +320,11 @@ void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Que void query_add_attribute(const void *key, const void *value, Query *q) { + if (CFEqual(key, kSecAttrDeriveSyncIDFromItemAttributes)) { + q->q_uuid_from_primary_key = CFBooleanGetValue(value); + return; /* skip the attribute so it isn't part of the search */ + } + const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error); if (desc) { query_add_attribute_with_desc(desc, value, q); @@ -534,7 +528,7 @@ static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *erro value = CFDictionaryGetValue(query, kSecValuePersistentRef); if (isData(value)) { CFDataRef pref = value; - _SecItemParsePersistentRef(pref, &c_name, 0); + _SecItemParsePersistentRef(pref, &c_name, NULL, NULL); } } @@ -665,6 +659,13 @@ static void query_set_data(const void *value, Query *q) { } } +static void query_set_token_persistent_ref(Query *q, CFDictionaryRef token_persistent_ref) { + if (token_persistent_ref) { + query_add_attribute(kSecAttrTokenID, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenID), q); + CFRetainAssign(q->q_token_object_id, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenOID)); + } +} + /* AUDIT[securityd](done): key (ok) is a caller provided, string starting with 'u'. value (ok) is a caller provided, non NULL CFTypeRef. @@ -680,9 +681,12 @@ static void query_add_value(const void *key, const void *value, Query *q) #endif } else if (CFEqual(key, kSecValuePersistentRef)) { CFStringRef c_name; - if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id)) + CFDictionaryRef token_persistent_ref = NULL; + if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id, &token_persistent_ref)) { query_set_class(q, c_name, &q->q_error); - else + query_set_token_persistent_ref(q, token_persistent_ref); + CFReleaseNull(token_persistent_ref); + } else SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value); } else { SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key); @@ -760,11 +764,18 @@ static void query_applier(const void *key, const void *value, void *context) r: return like kSecReturnData u: use keys v: value + f: callbacks (ignored by the query applier) */ if (key_len == 4) { /* attributes */ query_add_attribute(key, value, q); } else if (key_len > 1) { + // We added a database column named 'persistref', which is returned as an attribute but doesn't comply with + // these matching rules. skip it for now, since it isn't filled in anyway. + if(CFEqualSafe(key, CFSTR("persistref"))) { + return; + } + UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0); switch (k_first_char) { @@ -783,6 +794,8 @@ static void query_applier(const void *key, const void *value, void *context) case 'v': /* value */ query_add_value(key, value, q); break; + case 'f': + break; default: SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key); break; @@ -806,7 +819,7 @@ static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) { return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate; } /* All other certs or in the apple agrp is dk. */ - if (q->q_class == &cert_class) { + if (q->q_class == cert_class()) { /* third party certs are always dk. */ return kSecAttrAccessibleAlwaysPrivate; } @@ -843,6 +856,7 @@ bool query_destroy(Query *q, CFErrorRef *error) { CFReleaseSafe(q->q_match_policy); CFReleaseSafe(q->q_match_valid_on_date); CFReleaseSafe(q->q_match_trusted_only); + CFReleaseSafe(q->q_token_object_id); free(q); return ok; @@ -876,7 +890,7 @@ Query *query_create(const SecDbClass *qclass, CFIndex key_count = SecDbClassAttrCount(qclass); if (key_count == 0) { // Identities claim to have 0 attributes, but they really support any keys or cert attribute. - key_count = SecDbClassAttrCount(&cert_class) + SecDbClassAttrCount(&keys_class); + key_count = SecDbClassAttrCount(cert_class()) + SecDbClassAttrCount(keys_class()); } if (query) { @@ -905,6 +919,7 @@ Query *query_create(const SecDbClass *qclass, q->q_pairs_count = key_count; q->q_musrView = (CFDataRef)CFRetain(musr); + q->q_uuid_from_primary_key = false; q->q_keybag = KEYBAG_DEVICE; q->q_class = qclass; q->q_match_begin = q->q_match_end = key_count; @@ -942,7 +957,7 @@ Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex li query_destroy(q, error); return NULL; } - if (!q->q_sync && !q->q_row_id) { + if (!q->q_sync && !q->q_row_id && !q->q_token_object_id) { /* query did not specify a kSecAttrSynchronizable attribute, * and did not contain a persistent reference. */ query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q); diff --git a/OSX/sec/securityd/SecDbQuery.h b/OSX/sec/securityd/SecDbQuery.h index 8c52b14d..76354ee2 100644 --- a/OSX/sec/securityd/SecDbQuery.h +++ b/OSX/sec/securityd/SecDbQuery.h @@ -116,6 +116,12 @@ typedef struct Query // instead of reporting them to the client as an error. bool q_skip_acl_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 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; + // SHA1 digest of DER encoded primary key CFDataRef q_primary_key_digest; @@ -133,6 +139,8 @@ typedef struct Query CFDateRef q_match_valid_on_date; //trusted only certs and identities CFBooleanRef q_match_trusted_only; + //token persistent reference for filtering items is represented by token ID (in attrs) and token object ID + CFDataRef q_token_object_id; CFIndex q_pairs_count; Pair q_pairs[]; diff --git a/OSX/sec/securityd/SecItemDataSource.c b/OSX/sec/securityd/SecItemDataSource.c index 22313cb7..ae2686d6 100644 --- a/OSX/sec/securityd/SecItemDataSource.c +++ b/OSX/sec/securityd/SecItemDataSource.c @@ -30,15 +30,18 @@ #include #include +#include #include #include #include +#include #include #include #include #include #include #include +#include /* * @@ -55,23 +58,45 @@ struct SecItemDataSource { CFStringRef name; // The name of the slice of the database we represent. }; -static const SecDbClass *dsSyncedClassesV0[] = { - &genp_class, - &inet_class, - &keys_class, -}; -static const SecDbClass *dsSyncedClasses[] = { - &genp_class, // genp must be first! - &inet_class, - &keys_class, - &cert_class, +static const SecDbClass *dsSyncedClassesV0Ptrs[] = { + NULL, + NULL, + NULL, }; +static size_t dsSyncedClassesV0Size = (array_size(dsSyncedClassesV0Ptrs)); + +static const SecDbClass** dsSyncedClassesV0() { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dsSyncedClassesV0Ptrs[0] = genp_class(); + dsSyncedClassesV0Ptrs[1] = inet_class(); + dsSyncedClassesV0Ptrs[2] = keys_class(); + }); + return dsSyncedClassesV0Ptrs; +} -static bool SecErrorIsSqliteDuplicateItemError(CFErrorRef error) { - return error && CFErrorGetCode(error) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(error)); + +static const SecDbClass *dsSyncedClassesPtrs[] = { + NULL, + NULL, + NULL, + NULL, +}; +static const size_t dsSyncedClassesSize = array_size(dsSyncedClassesPtrs); + +static const SecDbClass** dsSyncedClasses() { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dsSyncedClassesPtrs[0] = genp_class(); // genp must be first! + dsSyncedClassesPtrs[1] = inet_class(); + dsSyncedClassesPtrs[2] = keys_class(); + dsSyncedClassesPtrs[3] = cert_class(); + }); + return dsSyncedClassesPtrs; } + static bool SecDbItemSelectSHA1(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr), bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere), @@ -201,45 +226,51 @@ static bool SecItemDataSourceAppendQueriesForViewName(SecItemDataSourceRef ds, C viewName = CFRetain(compositeViewName); } + // short-circuit for CKKS-handled views here + if(!SOSViewInSOSSystem(viewName)) { + CFReleaseSafe(viewName); + return ok; + } + const bool noTKID = false; const bool allowTKID = true; if (CFEqual(viewName, kSOSViewKeychainV0)) { - for (size_t class_ix = 0; class_ix < array_size(dsSyncedClassesV0); ++class_ix) { - SecItemDataSourceAppendQueryWithClass(queries, dsSyncedClassesV0[class_ix], noTombstones, noTKID, error); + for (size_t class_ix = 0; class_ix < dsSyncedClassesV0Size; ++class_ix) { + SecItemDataSourceAppendQueryWithClass(queries, dsSyncedClassesV0()[class_ix], noTombstones, noTKID, error); } } else if (CFEqual(viewName, kSOSViewWiFi)) { - Query *q = SecItemDataSourceAppendQueryWithClassAndAgrp(queries, &genp_class, noTombstones, allowTKID, CFSTR("apple"), error); + Query *q = SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("apple"), error); if (q) { query_add_attribute(kSecAttrService, CFSTR("AirPort"), q); } } else if (CFEqual(viewName, kSOSViewAutofillPasswords)) { - SecItemDataSourceAppendQueryWithClassAndAgrp(queries, &inet_class, noTombstones, allowTKID, CFSTR("com.apple.cfnetwork"), error); + SecItemDataSourceAppendQueryWithClassAndAgrp(queries, inet_class(), noTombstones, allowTKID, CFSTR("com.apple.cfnetwork"), error); } else if (CFEqual(viewName, kSOSViewSafariCreditCards)) { - SecItemDataSourceAppendQueryWithClassAndAgrp(queries, &genp_class, noTombstones, allowTKID, CFSTR("com.apple.safari.credit-cards"), error); + SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("com.apple.safari.credit-cards"), error); } else if (CFEqual(viewName, kSOSViewiCloudIdentity)) { - SecItemDataSourceAppendQueryWithClassAndAgrp(queries, &keys_class, noTombstones, allowTKID, CFSTR("com.apple.security.sos"), error); + SecItemDataSourceAppendQueryWithClassAndAgrp(queries, keys_class(), noTombstones, allowTKID, CFSTR("com.apple.security.sos"), error); } else if (CFEqual(viewName, kSOSViewBackupBagV0)) { - SecItemDataSourceAppendQueryWithClassAndAgrp(queries, &genp_class, noTombstones, allowTKID, CFSTR("com.apple.sbd"), error); + SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("com.apple.sbd"), error); } else if (CFEqual(viewName, kSOSViewOtherSyncable)) { - SecItemDataSourceAppendQueryWithClass(queries, &cert_class, noTombstones, allowTKID, error); + SecItemDataSourceAppendQueryWithClass(queries, cert_class(), noTombstones, allowTKID, error); - Query *q1_genp = SecItemDataSourceAppendQueryWithClassAndAgrp(queries, &genp_class, noTombstones, allowTKID, CFSTR("apple"), error); + Query *q1_genp = SecItemDataSourceAppendQueryWithClassAndAgrp(queries, genp_class(), noTombstones, allowTKID, CFSTR("apple"), error); query_add_not_attribute(kSecAttrService, CFSTR("AirPort"), q1_genp); - Query *q2_genp = SecItemDataSourceAppendQueryWithClass(queries, &genp_class, noTombstones, allowTKID, error); + Query *q2_genp = SecItemDataSourceAppendQueryWithClass(queries, genp_class(), noTombstones, allowTKID, error); query_add_not_attribute(kSecAttrAccessGroup, CFSTR("apple"), q2_genp); query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.safari.credit-cards"), q2_genp); query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.sbd"), q2_genp); - Query *q_inet = SecItemDataSourceAppendQueryWithClass(queries, &inet_class, noTombstones, allowTKID, error); + Query *q_inet = SecItemDataSourceAppendQueryWithClass(queries, inet_class(), noTombstones, allowTKID, error); query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.cfnetwork"), q_inet); - Query *q_keys = SecItemDataSourceAppendQueryWithClass(queries, &keys_class, noTombstones, allowTKID, error); + Query *q_keys = SecItemDataSourceAppendQueryWithClass(queries, keys_class(), noTombstones, allowTKID, error); query_add_not_attribute(kSecAttrAccessGroup, CFSTR("com.apple.security.sos"), q_keys); } else { // All other viewNames should match on the ViewHint attribute. - for (size_t class_ix = 0; class_ix < array_size(dsSyncedClasses); ++class_ix) { - SecItemDataSourceAppendQueryWithClassAndViewHint(queries, dsSyncedClasses[class_ix], noTombstones, allowTKID, viewName, error); + for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) { + SecItemDataSourceAppendQueryWithClassAndViewHint(queries, dsSyncedClasses()[class_ix], noTombstones, allowTKID, viewName, error); } } @@ -345,7 +376,7 @@ static SOSManifestRef dsCopyManifestWithViewNameSet(SOSDataSourceRef data_source static bool dsForEachObject(SOSDataSourceRef data_source, SOSTransactionRef txn, SOSManifestRef manifest, CFErrorRef *error, void (^handle_object)(CFDataRef key, SOSObjectRef object, bool *stop)) { struct SecItemDataSource *ds = (struct SecItemDataSource *)data_source; __block bool result = true; - const SecDbAttr *sha1Attr = SecDbClassAttrWithKind(&genp_class, kSecDbSHA1Attr, error); + const SecDbAttr *sha1Attr = SecDbClassAttrWithKind(genp_class(), kSecDbSHA1Attr, error); if (!sha1Attr) return false; bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr; @@ -353,9 +384,9 @@ static bool dsForEachObject(SOSDataSourceRef data_source, SOSTransactionRef txn, bool (^use_attr_in_where)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) { return attr->kind == kSecDbSHA1Attr; }; - Query *select_queries[array_size(dsSyncedClasses)] = {}; - CFStringRef select_sql[array_size(dsSyncedClasses)] = {}; - sqlite3_stmt *select_stmts[array_size(dsSyncedClasses)] = {}; + Query *select_queries[dsSyncedClassesSize] = {}; + CFStringRef select_sql[dsSyncedClassesSize] = {}; + sqlite3_stmt *select_stmts[dsSyncedClassesSize] = {}; __block Query **queries = select_queries; __block CFStringRef *sqls = select_sql; @@ -364,16 +395,16 @@ static bool dsForEachObject(SOSDataSourceRef data_source, SOSTransactionRef txn, void (^readBlock)(SecDbConnectionRef dbconn) = ^(SecDbConnectionRef dbconn) { // Setup - for (size_t class_ix = 0; class_ix < array_size(dsSyncedClasses); ++class_ix) { + 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, 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))); } if (result) SOSManifestForEach(manifest, ^(CFDataRef key, bool *stop) { __block SecDbItemRef item = NULL; - for (size_t class_ix = 0; result && !item && class_ix < array_size(dsSyncedClasses); ++class_ix) { + for (size_t class_ix = 0; result && !item && class_ix < dsSyncedClassesSize; ++class_ix) { CFDictionarySetValue(queries[class_ix]->q_item, sha1Attr->name, key); result = SecDbItemSelectBind(queries[class_ix], stmts[class_ix], error, use_attr_in_where, NULL); if (result) { @@ -389,7 +420,7 @@ static bool dsForEachObject(SOSDataSourceRef data_source, SOSTransactionRef txn, }); // Cleanup - for (size_t class_ix = 0; class_ix < array_size(dsSyncedClasses); ++class_ix) { + for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) { result &= SecDbReleaseCachedStmt(dbconn, sqls[class_ix], stmts[class_ix], error); CFReleaseSafe(sqls[class_ix]); if (queries[class_ix]) @@ -466,7 +497,7 @@ static bool dsWith(SOSDataSourceRef data_source, CFErrorRef *error, SOSDataSourc __block bool ok = true; ok &= SecDbPerformWrite(ds->db, error, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, - source == kSOSDataSourceAPITransaction ? kSecDbExclusiveTransactionType : kSecDbExclusiveRemoteTransactionType, + source == kSOSDataSourceAPITransaction ? kSecDbExclusiveTransactionType : kSecDbExclusiveRemoteSOSTransactionType, error, ^(bool *commit) { if (onCommitQueue) { SecDbPerformOnCommitQueue(dbconn, false, ^{ @@ -498,6 +529,7 @@ static SOSMergeResult dsMergeObject(SOSTransactionRef txn, SOSObjectRef peersObj __block SecDbItemRef mergedItem = NULL; __block SecDbItemRef replacedItem = NULL; __block CFErrorRef localError = NULL; + __block bool attemptedMerge = false; if (!peersItem || !dbconn) return kSOSMergeFailure; @@ -507,38 +539,55 @@ static SOSMergeResult dsMergeObject(SOSTransactionRef txn, SOSObjectRef peersObj return kSOSMergeFailure; } - if (SecDbItemInsertOrReplace(peersItem, dbconn, &localError, ^(SecDbItemRef myItem, SecDbItemRef *replace) { + bool insertedOrReplaced = SecDbItemInsertOrReplace(peersItem, dbconn, &localError, ^(SecDbItemRef myItem, SecDbItemRef *replace) { // An item with the same primary key as dbItem already exists in the the database. That item is old_item. // Let the conflict resolver choose which item to keep. + attemptedMerge = true; mergedItem = SecItemDataSourceCopyMergedItem(peersItem, myItem, &localError); - if (!mergedItem) + if (!mergedItem) { + mr = kSOSMergeFailure; return; // from block + } if (mergedObject) *mergedObject = (SOSObjectRef)CFRetain(mergedItem); if (CFEqual(mergedItem, myItem)) { // Conflict resolver choose my (local) item - secnotice("ds", "Conflict resolver chose my (local) item: %@", myItem); + if (SecDbItemIsEngineInternalState(myItem)) + secdebug ("ds", "Conflict resolver chose my (local) item: %@", myItem); + else + secnotice("ds", "Conflict resolver chose my (local) item: %@", myItem); mr = kSOSMergeLocalObject; } else { CFRetainAssign(replacedItem, myItem); *replace = CFRetainSafe(mergedItem); if (CFEqual(mergedItem, peersItem)) { // Conflict resolver chose peer's item - secnotice("ds", "Conflict resolver chose peers item: %@", peersItem); + if (SecDbItemIsEngineInternalState(peersItem)) + secdebug ("ds", "Conflict resolver chose peers item: %@", peersItem); + else + secnotice("ds", "Conflict resolver chose peers item: %@", peersItem); mr = kSOSMergePeersObject; } else { // Conflict resolver created a new item; return it to our caller - secnotice("ds", "Conflict resolver created a new item; return it to our caller: %@", mergedItem); + if (SecDbItemIsEngineInternalState(mergedItem)) + secdebug ("ds", "Conflict resolver created a new item; return it to our caller: %@", mergedItem); + else + secnotice("ds", "Conflict resolver created a new item; return it to our caller: %@", mergedItem); mr = kSOSMergeCreatedObject; } } - })) { - // either SecDbItemInsertOrReplace or SecItemDataSourceCopyMergedItem failed - if (mr == kSOSMergeFailure) - { + }); + + if (insertedOrReplaced && !attemptedMerge) { + // SecDbItemInsertOrReplace succeeded and conflict block was never called -> insert succeeded. + // We have peersItem in the database so we need to report that + secnotice("ds", "Insert succeeded for: %@", peersItem); + mr = kSOSMergePeersObject; + + // Report only if we had an error, too. Shouldn't happen in practice. + if (localError) { secnotice("ds", "kSOSMergeFailure => kSOSMergePeersObject, %@", localError); CFReleaseSafe(localError); - mr = kSOSMergePeersObject; } } @@ -604,7 +653,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, error); if (query) { if (query->q_item) CFReleaseSafe(query->q_item); query->q_item = dict; @@ -649,7 +698,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, error); if (query) { if (query->q_item) CFReleaseSafe(query->q_item); query->q_item = dict; @@ -681,7 +730,7 @@ static bool dsSetStateWithKey(SOSDataSourceRef data_source, SOSTransactionRef tx kSecValueData, state, NULL); CFReleaseSafe(dataSourceID); - SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, &genp_class, dict, KEYBAG_DEVICE, error); + SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, genp_class(), dict, KEYBAG_DEVICE, error); SOSMergeResult mr = dsMergeObject(txn, (SOSObjectRef)item, NULL, error); if (mr == kSOSMergeFailure) secerror("failed to save %@@%@ state: %@", key, pdmn, error ? *error : NULL); CFReleaseSafe(item); @@ -700,7 +749,7 @@ static bool dsDeleteStateWithKey(SOSDataSourceRef data_source, CFStringRef key, kSecAttrSynchronizable, kCFBooleanFalse, NULL); CFReleaseSafe(dataSourceID); - SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, &genp_class, dict, KEYBAG_DEVICE, error); + SecDbItemRef item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, genp_class(), dict, KEYBAG_DEVICE, error); bool ok = SecDbItemDoDeleteSilently(item, (SecDbConnectionRef)txn, error); CFReleaseNull(dict); CFReleaseSafe(item); @@ -806,17 +855,25 @@ static void SecItemDataSourceFactoryCircleChanged(SOSDataSourceFactoryRef factor // Fire up the SOSEngines so they can static bool SOSDataSourceFactoryStartYourEngines(SOSDataSourceFactoryRef factory) { - bool ok = true; - CFStringRef dsName = SOSDataSourceFactoryCopyName(factory); - CFErrorRef localError = NULL; - SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(factory, dsName, &localError); - if (!ds) - secerror("create_datasource %@ failed %@", dsName, localError); - CFReleaseNull(localError); - SOSDataSourceRelease(ds, &localError); - CFReleaseNull(localError); - CFReleaseNull(dsName); - return ok; +#if OCTAGON + if(!SecCKKSTestDisableSOS() && !SecCKKSTestsEnabled()) { +#endif // OCTAGON + bool ok = true; + CFStringRef dsName = SOSDataSourceFactoryCopyName(factory); + CFErrorRef localError = NULL; + SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(factory, dsName, &localError); + if (!ds) + secerror("create_datasource %@ failed %@", dsName, localError); + CFReleaseNull(localError); + SOSDataSourceRelease(ds, &localError); + CFReleaseNull(localError); + CFReleaseNull(dsName); + return ok; +#if OCTAGON + } else { + return false; + } +#endif // OCTAGON } static SOSDataSourceFactoryRef SecItemDataSourceFactoryCreate(SecDbRef db) { diff --git a/OSX/sec/securityd/SecItemDb.c b/OSX/sec/securityd/SecItemDb.c index a22546e7..8a30763c 100644 --- a/OSX/sec/securityd/SecItemDb.c +++ b/OSX/sec/securityd/SecItemDb.c @@ -41,9 +41,12 @@ #include #include #include +#include #include #include +#include "keychain/ckks/CKKS.h" + #define kSecBackupKeybagUUIDKey CFSTR("keybag-uuid") const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c, @@ -51,10 +54,10 @@ const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c, CFErrorRef *error) { /* Special case: identites can have all attributes of either cert or keys. */ - if (c == &identity_class) { + if (c == identity_class()) { const SecDbAttr *desc; - if (!(desc = SecDbAttrWithKey(&cert_class, key, 0))) - desc = SecDbAttrWithKey(&keys_class, key, error); + if (!(desc = SecDbAttrWithKey(cert_class(), key, 0))) + desc = SecDbAttrWithKey(keys_class(), key, error); return desc; } @@ -74,8 +77,12 @@ const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c, } bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)()) { + return kc_transaction_type(dbt, kSecDbExclusiveTransactionType, error, perform); +} + +bool kc_transaction_type(SecDbConnectionRef dbt, SecDbTransactionType type, CFErrorRef *error, bool(^perform)()) { __block bool ok = true; - return ok && SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) { + return ok && SecDbTransaction(dbt, type, error, ^(bool *commit) { ok = *commit = perform(); }); } @@ -152,17 +159,27 @@ static void SecDbAppendDropTableWithClass(CFMutableStringRef sql, const SecDbCla static CFDataRef SecPersistentRefCreateWithItem(SecDbItemRef item, CFErrorRef *error) { sqlite3_int64 row_id = SecDbItemGetRowId(item, error); if (row_id) - return _SecItemMakePersistentRef(SecDbItemGetClass(item)->name, row_id); + return _SecItemCreatePersistentRef(SecDbItemGetClass(item)->name, row_id, item->attributes); return NULL; } -bool SecItemDbCreateSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, bool includeVersion, CFErrorRef *error) +bool SecItemDbCreateSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFArrayRef classIndexesForNewTables, bool includeVersion, CFErrorRef *error) { __block bool ok = true; CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0); - for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { - SecDbAppendCreateTableWithClass(sql, *pclass); + + if (classIndexesForNewTables) { + CFArrayForEach(classIndexesForNewTables, ^(const void* index) { + const SecDbClass* class = schema->classes[(int)index]; + SecDbAppendCreateTableWithClass(sql, class); + }); + } + else { + for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { + SecDbAppendCreateTableWithClass(sql, *pclass); + } } + if (includeVersion) { CFStringAppendFormat(sql, NULL, CFSTR("INSERT INTO tversion(version,minor) VALUES(%d, %d);"), schema->majorVersion, schema->minorVersion); @@ -224,6 +241,8 @@ CFTypeRef SecDbItemCopyResult(SecDbItemRef item, ReturnTypeMask return_type, CFE } } } + CFDictionaryRemoveValue(dict, kSecAttrUUID); + if (return_type & kSecReturnPersistentRefMask) { CFDataRef pref = SecPersistentRefCreateWithItem(item, error); CFDictionarySetValue(dict, kSecValuePersistentRef, pref); @@ -266,6 +285,21 @@ s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef * ok = SecDbItemSetValueWithName(item, CFSTR("musr"), q->q_musrView, error); SecDbItemSetCredHandle(item, q->q_use_cred_handle); +#if OCTAGON + if(SecCKKSIsEnabled() && !SecCKKSTestDisableAutomaticUUID()) { + s3dl_item_make_new_uuid(item, q->q_uuid_from_primary_key, error); + + if(q->q_add_sync_callback) { + CFTypeRef uuid = SecDbItemGetValue(item, &v10itemuuid, error); + if(uuid) { + CKKSRegisterSyncStatusCallback(uuid, q->q_add_sync_callback); + } else { + secerror("Couldn't fetch UUID from item; can't call callback"); + } + } + } +#endif + if (ok) ok = SecDbItemInsert(item, dbt, error); @@ -300,6 +334,51 @@ s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef * return ok; } +bool s3dl_item_make_new_uuid(SecDbItemRef item, bool uuid_from_primary_key, CFErrorRef* error) { + if(!item) { + return false; + } + + // Set the item UUID. + CFUUIDRef uuid = NULL; + // Were we asked to make the UUID static? + if (uuid_from_primary_key) { + // This UUID isn't used in any security mechanism, so we can + // just use the first bits of the SHA256 hash. + CFDataRef pkhash = SecDbKeychainItemCopySHA256PrimaryKey(item, error); + if(CFDataGetLength(pkhash) >= 16) { + UInt8 uuidBytes[16]; + CFRange range = CFRangeMake(0, 16); + CFDataGetBytes(pkhash, range, uuidBytes); + + uuid = CFUUIDCreateWithBytes(NULL, + uuidBytes[ 0], + uuidBytes[ 1], + uuidBytes[ 2], + uuidBytes[ 3], + uuidBytes[ 4], + uuidBytes[ 5], + uuidBytes[ 6], + uuidBytes[ 7], + uuidBytes[ 8], + uuidBytes[ 9], + uuidBytes[10], + uuidBytes[11], + uuidBytes[12], + uuidBytes[13], + uuidBytes[14], + uuidBytes[15]); + } + CFReleaseNull(pkhash); + } + if(uuid == NULL) { + uuid = CFUUIDCreate(NULL); + } + SecDbItemSetValueWithName(item, kSecAttrUUID, uuid, error); + CFReleaseNull(uuid); + return true; +} + typedef void (*s3dl_handle_row)(sqlite3_stmt *stmt, void *context); static CFDataRef @@ -354,7 +433,7 @@ handle_result(Query *q, a_result = CFDataCreate(kCFAllocatorDefault, NULL, 0); } } else if (q->q_return_type == kSecReturnPersistentRefMask) { - a_result = _SecItemMakePersistentRef(q->q_class->name, rowid); + a_result = _SecItemCreatePersistentRef(q->q_class->name, rowid, item); } else { /* We need to return more than one value. */ if (q->q_return_type & kSecReturnRefMask) { @@ -363,6 +442,29 @@ handle_result(Query *q, if (!(q->q_return_type & kSecReturnDataMask)) { CFDictionaryRemoveValue(item, kSecValueData); } + + // Add any attributes which are supposed to be returned, are not present in the decrypted blob, + // and have a way to generate themselves. + SecDbItemRef itemRef = NULL; + SecDbForEachAttrWithMask(q->q_class, attr, kSecDbReturnAttrFlag) { + if(!CFDictionaryGetValue(item, attr->name) && attr->copyValue) { + CFErrorRef cferror = NULL; + if(!itemRef) { + itemRef = SecDbItemCreateWithAttributes(NULL, q->q_class, item, KEYBAG_DEVICE, &cferror); + } + if(!cferror && itemRef) { + CFTypeRef attrValue = attr->copyValue(itemRef, attr, &cferror); + if(!cferror && attrValue) { + CFDictionarySetValue(item, attr->name, attrValue); + } + CFReleaseNull(attrValue); + } + CFReleaseNull(cferror); + } + } + CFReleaseNull(itemRef); + + CFDictionaryRemoveValue(item, kSecAttrUUID); } else { CFRetainSafe(data); CFDictionaryRemoveAllValues(item); @@ -372,7 +474,7 @@ handle_result(Query *q, CFReleaseSafe(data); } if (q->q_return_type & kSecReturnPersistentRefMask) { - CFDataRef pref = _SecItemMakePersistentRef(q->q_class->name, rowid); + CFDataRef pref = _SecItemCreatePersistentRef(q->q_class->name, rowid, item); CFDictionarySetValue(item, kSecValuePersistentRef, pref); CFRelease(pref); } @@ -388,6 +490,17 @@ static void s3dl_merge_into_dict(const void *key, const void *value, void *conte CFDictionarySetValue(context, key, value); } +static bool checkTokenObjectID(CFDataRef token_object_id, CFDataRef value_data) { + bool equalOID = false; + CFDictionaryRef itemValue = SecTokenItemValueCopy(value_data, NULL); + require_quiet(itemValue, out); + CFDataRef oID = CFDictionaryGetValue(itemValue, kSecTokenValueObjectIDKey); + equalOID = CFEqualSafe(token_object_id, oID); + CFRelease(itemValue); +out: + return equalOID; +} + static void s3dl_query_row(sqlite3_stmt *stmt, void *context) { struct s3dl_query_ctx *c = context; Query *q = c->q; @@ -423,7 +536,10 @@ static void s3dl_query_row(sqlite3_stmt *stmt, void *context) { if (!item) goto out; - if (q->q_class == &identity_class) { + if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, CFDictionaryGetValue(item, kSecValueData))) + goto out; + + if (q->q_class == identity_class()) { // TODO: Use col 2 for key rowid and use both rowids in persistent ref. CFMutableDictionaryRef key; @@ -561,9 +677,9 @@ static void SecDbAppendLimit(CFMutableStringRef sql, CFIndex limit) { CFStringAppendFormat(sql, NULL, CFSTR(" LIMIT %" PRIdCFIndex), limit); } -static CF_RETURNS_RETAINED CFStringRef s3dl_select_sql(Query *q, CFArrayRef accessGroups) { +static CFStringRef s3dl_create_select_sql(Query *q, CFArrayRef accessGroups) { CFMutableStringRef sql = CFStringCreateMutable(NULL, 0); - if (q->q_class == &identity_class) { + if (q->q_class == identity_class()) { CFStringAppendFormat(sql, NULL, CFSTR("SELECT crowid, %@" ", rowid,data FROM " "(SELECT cert.rowid AS crowid, cert.labl AS labl," @@ -588,7 +704,7 @@ static CF_RETURNS_RETAINED CFStringRef s3dl_select_sql(Query *q, CFArrayRef acce SecDbAppendWhereClause(sql, q, accessGroups); } //do not append limit for all queries which needs filtering - if (q->q_match_issuer == NULL && q->q_match_policy == NULL && q->q_match_valid_on_date == NULL && q->q_match_trusted_only == NULL) { + if (q->q_match_issuer == NULL && q->q_match_policy == NULL && q->q_match_valid_on_date == NULL && q->q_match_trusted_only == NULL && q->q_token_object_id == NULL) { SecDbAppendLimit(sql, q->q_limit); } @@ -679,13 +795,13 @@ bool SecDbItemQuery(SecDbQueryRef query, CFArrayRef accessGroups, SecDbConnectio return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr; }; - CFStringRef sql = s3dl_select_sql(query, accessGroups); + CFStringRef sql = s3dl_create_select_sql(query, accessGroups); ok = sql; if (sql) { ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) { /* Bind the values being searched for to the SELECT statement. */ int param = 1; - if (query->q_class == &identity_class) { + if (query->q_class == identity_class()) { /* Bind the access groups to cert.agrp. */ ok &= sqlBindAccessGroups(stmt, accessGroups, ¶m, error); } @@ -735,12 +851,12 @@ s3dl_query(s3dl_handle_row handle_row, } else { c->result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } - CFStringRef sql = s3dl_select_sql(q, accessGroups); + CFStringRef sql = s3dl_create_select_sql(q, accessGroups); bool ok = SecDbWithSQL(dbt, sql, error, ^(sqlite3_stmt *stmt) { bool sql_ok = true; /* Bind the values being searched for to the SELECT statement. */ int param = 1; - if (q->q_class == &identity_class) { + if (q->q_class == identity_class()) { /* Bind the access groups to cert.agrp. */ sql_ok = sqlBindAccessGroups(stmt, accessGroups, ¶m, error); } @@ -789,6 +905,9 @@ s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, if (q->q_row_id && query_attr_count(q)) return SecError(errSecItemIllegalQuery, error, 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")); // Only copy things that aren't tombstones unless the client explicitly asks otherwise. if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone)) @@ -802,6 +921,64 @@ s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, return ok; } +typedef void (^s3dl_item_digest_callback)(CFDataRef persistantReference, CFDataRef encryptedData); + +struct s3dl_digest_ctx { + Query *q; + SecDbConnectionRef dbt; + s3dl_item_digest_callback item_callback; +}; + +static void s3dl_query_row_digest(sqlite3_stmt *stmt, void *context) { + struct s3dl_query_ctx *c = context; + Query *q = c->q; + + sqlite_int64 rowid = sqlite3_column_int64(stmt, 0); + CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL); + CFDataRef persistant_reference = _SecItemCreatePersistentRef(q->q_class->name, rowid, NULL); + CFDataRef digest = NULL; + + if (edata) { + digest = CFDataCopySHA256Digest(edata, NULL); + } + + if (digest && persistant_reference) { + CFDictionaryRef item = CFDictionaryCreateForCFTypes(NULL, + kSecValuePersistentRef, persistant_reference, + kSecValueData, digest, + NULL); + if (item) + CFArrayAppendValue((CFMutableArrayRef)c->result, item); + CFReleaseNull(item); + c->found++; + } else { + secinfo("item", "rowid %lu in %@ failed to create pref/digest", (unsigned long)rowid, q->q_class->name); + } + CFReleaseNull(digest); + CFReleaseNull(edata); + CFReleaseNull(persistant_reference); +} + + +bool +s3dl_copy_digest(SecDbConnectionRef dbt, Query *q, CFArrayRef *result, CFArrayRef accessGroups, CFErrorRef *error) +{ + struct s3dl_query_ctx ctx = { + .q = q, .dbt = dbt, .accessGroups = accessGroups, + }; + // Force to always return an array + q->q_limit = kSecMatchUnlimited; + // This interface only queries live data + query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); + bool ok = s3dl_query(s3dl_query_row_digest, &ctx, error); + if (ok && result) + *result = (CFArrayRef)ctx.result; + else + CFReleaseSafe(ctx.result); + + return ok; +} + /* First remove key from q->q_pairs if it's present, then add the attribute again. */ static void query_set_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q) { if (CFDictionaryContainsKey(q->q_item, desc->name)) { @@ -898,6 +1075,8 @@ s3dl_query_update(SecDbConnectionRef dbt, Query *q, return SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported in attributes to update")); if (q->q_row_id && query_attr_count(q)) return SecError(errSecItemIllegalQuery, error, CFSTR("attributes to update illegal; both row_id and other attributes can't be updated at the same time")); + if (q->q_token_object_id && query_attr_count(q) != 1) + 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); @@ -911,6 +1090,12 @@ s3dl_query_update(SecDbConnectionRef dbt, Query *q, result &= SecDbItemQuery(q, accessGroups, dbt, error, ^(SecDbItemRef item, bool *stop) { // We always need to know the error here. CFErrorRef localError = NULL; + if (q->q_token_object_id) { + const SecDbAttr *valueDataAttr = SecDbClassAttrWithKind(item->class, kSecDbDataAttr, NULL); + CFDataRef valueData = SecDbItemGetValue(item, valueDataAttr, NULL); + if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, valueData)) + return; + } // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications. const SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL); CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, NULL)); @@ -932,7 +1117,7 @@ s3dl_query_update(SecDbConnectionRef dbt, Query *q, result = SecErrorPropagate(localError, error) && new_item; if (new_item) { bool item_is_sync = SecDbItemIsSyncable(item); - result = SecDbItemUpdate(item, new_item, dbt, s3dl_should_make_tombstone(q, item_is_sync, item), error); + result = SecDbItemUpdate(item, new_item, dbt, s3dl_should_make_tombstone(q, item_is_sync, item), q->q_uuid_from_primary_key, error); if (result) { q->q_changed = true; if (item_is_sync || SecDbItemIsSyncable(new_item)) @@ -981,6 +1166,13 @@ s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFE },^bool(sqlite3_stmt * stmt, int col) { return sqlBindWhereClause(stmt, q, accessGroups, &col, error); }, ^(SecDbItemRef item, bool *stop) { + // Check if item for token persitence ref + if (q->q_token_object_id) { + const SecDbAttr *valueDataAttr = SecDbClassAttrWithKind(item->class, kSecDbDataAttr, NULL); + CFDataRef valueData = SecDbItemGetValue(item, valueDataAttr, NULL); + if (q->q_token_object_id != NULL && !checkTokenObjectID(q->q_token_object_id, valueData)) + return; + } // Check if item need to be authenticated by LocalAuthentication item->cryptoOp = kAKSKeyOpDelete; if (SecDbItemNeedAuth(item, error)) { @@ -1021,6 +1213,19 @@ matchAnyString(CFStringRef needle, CFStringRef *haystack) but when restoring a backup the original version of the item should be added back to the keychain again after the restore completes. */ static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser) { + CFNumberRef sysb = CFDictionaryGetValue(item, kSecAttrSysBound); + if (isNumber(sysb)) { + int32_t num = 0; + if (!CFNumberGetValue(sysb, kCFNumberSInt32Type, &num)) + return false; + if (num == kSecSecAttrSysBoundNot) { + return false; + } else if (num == kSecSecAttrSysBoundPreserveDuringRestore) { + return true; + } + return true; + } + CFStringRef agrp = CFDictionaryGetValue(item, kSecAttrAccessGroup); if (!isString(agrp)) return false; @@ -1035,7 +1240,7 @@ static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bo return true; } - if (CFEqual(agrp, CFSTR("apple")) && cls == &genp_class) { + if (CFEqual(agrp, CFSTR("apple")) && cls == genp_class()) { CFStringRef service = CFDictionaryGetValue(item, kSecAttrService); CFStringRef account = CFDictionaryGetValue(item, kSecAttrAccount); @@ -1055,7 +1260,7 @@ static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bo } } - if (multiUser && CFEqual(agrp, CFSTR("com.apple.apsd")) && cls == &genp_class) { + if (multiUser && CFEqual(agrp, CFSTR("com.apple.apsd")) && cls == genp_class()) { static CFStringRef pushServices[] = { CFSTR("push.apple.com"), CFSTR("push.apple.com,PerAppToken.v0"), @@ -1069,7 +1274,7 @@ static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bo } } - if (multiUser && CFEqual(agrp, CFSTR("appleaccount")) && cls == &genp_class) { + if (multiUser && CFEqual(agrp, CFSTR("appleaccount")) && cls == genp_class()) { static CFStringRef accountServices[] = { CFSTR("com.apple.appleaccount.fmf.token"), /* temporary tokens while accout is being setup */ CFSTR("com.apple.appleaccount.fmf.apptoken"), @@ -1085,7 +1290,7 @@ static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bo } } - if (multiUser && CFEqual(agrp, CFSTR("apple")) && cls == &genp_class) { + if (multiUser && CFEqual(agrp, CFSTR("apple")) && cls == genp_class()) { static CFStringRef accountServices[] = { CFSTR("com.apple.account.AppleAccount.token"), CFSTR("com.apple.account.AppleAccount.password"), @@ -1118,7 +1323,7 @@ static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bo } } - if (multiUser && CFEqual(agrp, CFSTR("ichat")) && cls == &genp_class) { + if (multiUser && CFEqual(agrp, CFSTR("ichat")) && cls == genp_class()) { static CFStringRef accountServices[] = { CFSTR("ids"), NULL @@ -1131,7 +1336,7 @@ static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bo } } - if (multiUser && CFEqual(agrp, CFSTR("ichat")) && cls == &keys_class) { + if (multiUser && CFEqual(agrp, CFSTR("ichat")) && cls == keys_class()) { static CFStringRef exactMatchingLabel[] = { CFSTR("iMessage Encryption Key"), CFSTR("iMessage Signing Key"), @@ -1256,7 +1461,7 @@ static void s3dl_export_row(sqlite3_stmt *stmt, void *context) { /* Re-encode the item. */ secdebug("item", "export rowid %llu item: %@", rowid, item); /* The code below could be moved into handle_row. */ - CFDataRef pref = _SecItemMakePersistentRef(q->q_class->name, rowid); + CFDataRef pref = _SecItemCreatePersistentRef(q->q_class->name, rowid, item); if (pref) { if (c->dest_keybag != KEYBAG_NONE) { CFMutableDictionaryRef auth_attribs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -1376,10 +1581,10 @@ SecServerCopyKeychainPlist(SecDbConnectionRef dbt, /* Get rid of this duplicate. */ const SecDbClass *SecDbClasses[] = { - &genp_class, - &inet_class, - &cert_class, - &keys_class + genp_class(), + inet_class(), + cert_class(), + keys_class() }; for (class_ix = 0; class_ix < array_size(SecDbClasses); @@ -1604,7 +1809,7 @@ static void SecServerImportClass(const void *key, const void *value, secwarning("Ignoring unknown key class '%@'", key); return; } - if (class == &identity_class) { + if (class == identity_class()) { SecError(errSecParam, &state->error, CFSTR("attempt to import an identity")); return; } @@ -1702,11 +1907,13 @@ errOut: } CFStringRef -SecServerBackupGetKeybagUUID(CFDictionaryRef keychain) +SecServerBackupGetKeybagUUID(CFDictionaryRef keychain, CFErrorRef *error) { CFStringRef uuid = CFDictionaryGetValue(keychain, kSecBackupKeybagUUIDKey); - if (!isString(uuid)) + if (!isString(uuid)) { + SecError(errSecDecode, error, CFSTR("Missing or invalid %@ in backup dictionary"), kSecBackupKeybagUUIDKey); return NULL; + } return uuid; } @@ -1762,10 +1969,10 @@ bool s3dl_dbt_keys_current(SecDbConnectionRef dbt, uint32_t current_generation, struct check_generation_ctx ctx = { .query_ctx = { .dbt = dbt }, .current_generation = current_generation }; const SecDbClass *classes[] = { - &genp_class, - &inet_class, - &keys_class, - &cert_class, + genp_class(), + inet_class(), + keys_class(), + cert_class(), }; for (size_t class_ix = 0; class_ix < array_size(classes); ++class_ix) { diff --git a/OSX/sec/securityd/SecItemDb.h b/OSX/sec/securityd/SecItemDb.h index fd76e4c2..6d91d921 100644 --- a/OSX/sec/securityd/SecItemDb.h +++ b/OSX/sec/securityd/SecItemDb.h @@ -29,53 +29,12 @@ #define _SECURITYD_SECITEMDB_H_ #include -#include "securityd_client.h" -__BEGIN_DECLS - -#if 0 -// -// MARK: SecItemDb (a SecDb of SecDbItems) -// -typedef struct SecItemDb *SecItemDbRef; -typedef struct SecItemDbConnection *SecItemDbConnectionRef; - -struct SecItemDb { - CFRuntimeBase _base; - SecDbRef db; - CFDictionaryRef classes; // className -> SecItemClass mapping -}; - -struct SecItemDbConnection { - SecDbConnectionRef db; -}; - -SecItemDbRef SecItemDbCreate(SecDbRef db); -SecItemDbRef SecItemDbRegisterClass(SecItemDbRef db, const SecDbClass *class, void(^upgrade)(SecDbItemRef item, uint32_t current_version)); - -SecItemDbConnectionRef SecItemDbAcquireConnection(SecItemDbRef db); -void SecItemDbReleaseConnection(SecItemDbRef db, SecItemDbConnectionRef dbconn); - -bool SecItemDbInsert(SecItemDbConnectionRef dbconn, SecDbItemRef item, CFErrorRef *error); - -bool SecItemDbDelete(SecItemDbConnectionRef dbconn, SecDbItemRef item, CFErrorRef *error); - -// Low level update, just do the update -bool SecItemDbDoUpdate(SecItemDbConnectionRef dbconn, SecDbItemRef old_item, SecDbItemRef new_item, CFErrorRef *error, - bool (^use_attr_in_where)(const SecDbAttr *attr)); - -// High level update, will replace tombstones and create them if needed. -bool SecItemDbUpdate(SecItemDbConnectionRef dbconn, SecDbItemRef old_item, SecDbItemRef new_item, CFErrorRef *error); - -bool SecItemDbSelect(SecItemDbConnectionRef dbconn, SecDbQueryRef query, CFErrorRef *error, - bool (^use_attr_in_where)(const SecDbAttr *attr), - bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere), - bool (^bind_added_where)(sqlite3_stmt *stmt, int col), - void (^handle_row)(SecDbItemRef item, bool *stop)); -#endif +struct SecurityClient; +__BEGIN_DECLS -bool SecItemDbCreateSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, bool includeVersion, CFErrorRef *error); +bool SecItemDbCreateSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFArrayRef classIndexesForNewTables, bool includeVersion, CFErrorRef *error); bool SecItemDbDeleteSchema(SecDbConnectionRef dbt, const SecDbSchema *schema, CFErrorRef *error); @@ -113,13 +72,13 @@ enum SecItemFilter { }; CFDictionaryRef SecServerCopyKeychainPlist(SecDbConnectionRef dbt, - SecurityClient *client, + struct SecurityClient *client, keybag_handle_t src_keybag, keybag_handle_t dest_keybag, enum SecItemFilter filter, CFErrorRef *error); bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt, - SecurityClient *client, + struct SecurityClient *client, keybag_handle_t src_keybag, keybag_handle_t dest_keybag, CFDictionaryRef keychain, @@ -127,7 +86,7 @@ bool SecServerImportKeychainInPlist(SecDbConnectionRef dbt, CFErrorRef *error); CFStringRef -SecServerBackupGetKeybagUUID(CFDictionaryRef keychain); +SecServerBackupGetKeybagUUID(CFDictionaryRef keychain, CFErrorRef *error); #if TARGET_OS_IPHONE @@ -135,16 +94,22 @@ bool SecServerDeleteAllForUser(SecDbConnectionRef dbt, CFDataRef musrView, bool #endif bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)()); +bool kc_transaction_type(SecDbConnectionRef dbt, SecDbTransactionType type, CFErrorRef *error, bool(^perform)()); bool s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFArrayRef accessGroups, CFErrorRef *error); bool s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef *error); bool s3dl_query_update(SecDbConnectionRef dbt, Query *q, CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups, CFErrorRef *error); bool s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFErrorRef *error); +bool s3dl_copy_digest(SecDbConnectionRef dbt, Query *q, CFArrayRef *result, CFArrayRef accessGroups, CFErrorRef *error); + const SecDbAttr *SecDbAttrWithKey(const SecDbClass *c, CFTypeRef key, CFErrorRef *error); bool s3dl_dbt_keys_current(SecDbConnectionRef dbt, uint32_t current_generation, CFErrorRef *error); -bool s3dl_dbt_update_keys(SecDbConnectionRef dbt, SecurityClient *client, CFErrorRef *error); +bool s3dl_dbt_update_keys(SecDbConnectionRef dbt, struct SecurityClient *client, CFErrorRef *error); + +// We'd love to take a query here, but switching layers at the callsite means we don't have it +bool s3dl_item_make_new_uuid(SecDbItemRef item, bool uuid_from_primary_key, CFErrorRef* error); __END_DECLS diff --git a/OSX/sec/securityd/SecItemSchema.c b/OSX/sec/securityd/SecItemSchema.c index 7668a5d7..bb340052 100644 --- a/OSX/sec/securityd/SecItemSchema.c +++ b/OSX/sec/securityd/SecItemSchema.c @@ -29,6 +29,7 @@ #include "SecItemSchema.h" #include +#include // MARK - // MARK Keychain version 6 schema @@ -36,7 +37,7 @@ #define __FLAGS(ARG, ...) SECDBFLAGS(__VA_ARGS__) #define SECDBFLAGS(ARG, ...) __FLAGS_##ARG | __FLAGS(__VA_ARGS__) -#define SecDbFlags(P,L,I,S,A,D,R,C,H,B,Z,E,N,U,V) (__FLAGS_##P|__FLAGS_##L|__FLAGS_##I|__FLAGS_##S|__FLAGS_##A|__FLAGS_##D|__FLAGS_##R|__FLAGS_##C|__FLAGS_##H|__FLAGS_##B|__FLAGS_##Z|__FLAGS_##E|__FLAGS_##N|__FLAGS_##U|__FLAGS_##V) +#define SecDbFlags(P,L,I,S,A,D,R,C,H,B,Z,E,N,U,V,Y) (__FLAGS_##P|__FLAGS_##L|__FLAGS_##I|__FLAGS_##S|__FLAGS_##A|__FLAGS_##D|__FLAGS_##R|__FLAGS_##C|__FLAGS_##H|__FLAGS_##B|__FLAGS_##Z|__FLAGS_##E|__FLAGS_##N|__FLAGS_##U|__FLAGS_##V|__FLAGS_##Y) #define __FLAGS_ 0 #define __FLAGS_P kSecDbPrimaryKeyFlag @@ -55,108 +56,288 @@ #define __FLAGS_U kSecDbInAuthenticatedDataFlag #define __FLAGS_V0 kSecDbSyncPrimaryKeyV0 #define __FLAGS_V2 (kSecDbSyncPrimaryKeyV0 | kSecDbSyncPrimaryKeyV2) +#define __FLAGS_Y kSecDbSyncFlag -// ,-------------- 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 -// / / / / / / ,-------- 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) -// / / / / / / / / / ,----- 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 -// / / / / / / / / / / / / / / - S : Sync primpary key version -// / / / / / / / / / / / / / / / -// | | | | | | | | | | | | | | | -// common to all | | | | | | | | | | | | | | | -SECDB_ATTR(v6rowid, "rowid", RowId, SecDbFlags( ,L, , , , ,R, , ,B, , , , , ), NULL, NULL); -SECDB_ATTR(v6cdat, "cdat", CreationDate, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), SecDbKeychainItemCopyCurrentDate, NULL); -SECDB_ATTR(v6mdat, "mdat",ModificationDate,SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), SecDbKeychainItemCopyCurrentDate, NULL); -SECDB_ATTR(v6labl, "labl", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6data, "data", EncryptedData, SecDbFlags( ,L, , , , , , , ,B, , , , , ), SecDbKeychainItemCopyEncryptedData, NULL); -SECDB_ATTR(v6agrp, "agrp", String, SecDbFlags(P,L, , ,A, , , ,H, , , ,N,U,V0), NULL, NULL); -SECDB_ATTR(v6pdmn, "pdmn", Access, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6sync, "sync", Sync, SecDbFlags(P,L,I, ,A, , , ,H, ,Z, ,N,U,V0), NULL, NULL); -SECDB_ATTR(v6tomb, "tomb", Tomb, SecDbFlags( ,L, , , , , , ,H, ,Z, ,N,U, ), NULL, NULL); -SECDB_ATTR(v6sha1, "sha1", SHA1, SecDbFlags( ,L,I, ,A, ,R, , , , , , , , ), SecDbKeychainItemCopySHA1, NULL); -SECDB_ATTR(v6accc, "accc", AccessControl, SecDbFlags( , , , ,A, , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v6v_Data, "v_Data", Data, SecDbFlags( , , , , ,D, ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6v_pk, "v_pk", PrimaryKey, SecDbFlags( , , , , , , , , , , , , , , ), SecDbKeychainItemCopyPrimaryKey, NULL); -SECDB_ATTR(v7vwht, "vwht", String, SecDbFlags(P,L, , ,A, , , ,H, , , , ,U,V2), NULL, NULL); -SECDB_ATTR(v7tkid, "tkid", String, SecDbFlags(P,L, , ,A, , , ,H, , , , ,U,V2), NULL, NULL); -SECDB_ATTR(v7utomb, "u_Tomb", UTomb, SecDbFlags( , , , , , , , , , , , , , , ), NULL, NULL); -SECDB_ATTR(v8musr, "musr", UUID, SecDbFlags(P,L,I, , , , , , , , , ,N,U, ), NULL, NULL); -// genp and inet and keys | | | | | | | | | | | | | | | -SECDB_ATTR(v6crtr, "crtr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6alis, "alis", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ), NULL, NULL); -// genp and inet | | | | | | | | | | | | | | | -SECDB_ATTR(v6desc, "desc", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6icmt, "icmt", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6type, "type", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6invi, "invi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6nega, "nega", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6cusi, "cusi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6prot, "prot", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6scrp, "scrp", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6acct, "acct", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -// genp only | | | | | | | | | | | | | | | -SECDB_ATTR(v6svce, "svce", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -SECDB_ATTR(v6gena, "gena", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ), NULL, NULL); -// inet only | | | | | | | | | | | | | | | -SECDB_ATTR(v6sdmn, "sdmn", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -SECDB_ATTR(v6srvr, "srvr", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -SECDB_ATTR(v6ptcl, "ptcl", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6atyp, "atyp", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -SECDB_ATTR(v6port, "port", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6path, "path", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -// cert only | | | | | | | | | | | | | | | -SECDB_ATTR(v6ctyp, "ctyp", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6cenc, "cenc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6subj, "subj", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6issr, "issr", Data, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -SECDB_ATTR(v6slnr, "slnr", Data, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -SECDB_ATTR(v6skid, "skid", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6pkhh, "pkhh", Data, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ), NULL, NULL); +// ,----------------- 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 +// / / / / / / ,----------- 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) +// / / / / / / / / / ,-------- 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 +// | | | | | | | | | | | | | | | | +// common to all | | | | | | | | | | | | | | | | +SECDB_ATTR(v6rowid, "rowid", RowId, SecDbFlags( ,L, , , , ,R, , ,B, , , , , , ), NULL, NULL); +SECDB_ATTR(v6cdat, "cdat", CreationDate, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), SecDbKeychainItemCopyCurrentDate, NULL); +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, , ,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(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); +SECDB_ATTR(v6v_Data, "v_Data", Data, SecDbFlags( , , , , ,D, ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6v_pk, "v_pk", PrimaryKey, SecDbFlags( , , , , , , , , , , , , , , , ), SecDbKeychainItemCopyPrimaryKey, NULL); +SECDB_ATTR(v7vwht, "vwht", String, SecDbFlags(P,L, , ,A, , , ,H, , , , ,U,V2,Y), NULL, NULL); +SECDB_ATTR(v7tkid, "tkid", String, SecDbFlags(P,L, , ,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); +// 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); +// genp and inet | | | | | | | | | | | | | | | | +SECDB_ATTR(v6desc, "desc", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6icmt, "icmt", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6type, "type", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6invi, "invi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6nega, "nega", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6cusi, "cusi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6prot, "prot", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6scrp, "scrp", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6acct, "acct", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +// genp only | | | | | | | | | | | | | | | | +SECDB_ATTR(v6svce, "svce", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6gena, "gena", Blob, SecDbFlags( ,L, ,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +// inet only | | | | | | | | | | | | | | | | +SECDB_ATTR(v6sdmn, "sdmn", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6srvr, "srvr", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6ptcl, "ptcl", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6atyp, "atyp", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6port, "port", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6path, "path", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +// cert only | | | | | | | | | | | | | | | | +SECDB_ATTR(v6ctyp, "ctyp", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6cenc, "cenc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6subj, "subj", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6issr, "issr", Data, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6slnr, "slnr", Data, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6skid, "skid", Data, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6pkhh, "pkhh", Data, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); // cert attributes that share names with common ones but have different flags -SECDB_ATTR(v6certalis, "alis", Blob, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ), NULL, NULL); -// keys only | | | | | | | | | | | | | | | -SECDB_ATTR(v6kcls, "kcls", Number, SecDbFlags(P,L,I,S,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6perm, "perm", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6priv, "priv", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6modi, "modi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6klbl, "klbl", Data, SecDbFlags(P,L,I, ,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -SECDB_ATTR(v6atag, "atag", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0), NULL, NULL); -SECDB_ATTR(v6bsiz, "bsiz", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6esiz, "esiz", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6sdat, "sdat", Date, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6edat, "edat", Date, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6sens, "sens", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6asen, "asen", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6extr, "extr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6next, "next", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6encr, "encr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6decr, "decr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6drve, "drve", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6sign, "sign", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6vrfy, "vrfy", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6snrc, "snrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6vyrc, "vyrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6wrap, "wrap", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ), NULL, NULL); -SECDB_ATTR(v6unwp, "unwp", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ), NULL, NULL); +SECDB_ATTR(v6certalis, "alis", Blob, SecDbFlags( ,L,I,S,A, , ,C,H, , , , , , ,Y), NULL, NULL); +// keys only | | | | | | | | | | | | | | | | +SECDB_ATTR(v6kcls, "kcls", Number, SecDbFlags(P,L,I,S,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6perm, "perm", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6priv, "priv", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6modi, "modi", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6klbl, "klbl", Data, SecDbFlags(P,L,I, ,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6atag, "atag", Blob, SecDbFlags(P,L, ,S,A, , ,C,H, , ,E,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6bsiz, "bsiz", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6esiz, "esiz", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6sdat, "sdat", Date, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6edat, "edat", Date, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6sens, "sens", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6asen, "asen", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6extr, "extr", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6next, "next", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6encr, "encr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6decr, "decr", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6drve, "drve", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6sign, "sign", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6vrfy, "vrfy", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6snrc, "snrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6vyrc, "vyrc", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6wrap, "wrap", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v6unwp, "unwp", Number, SecDbFlags( ,L,I, ,A, , ,C,H, , , , , , ,Y), NULL, NULL); // keys attributes that share names with common ones but have different flags -SECDB_ATTR(v6keytype, "type", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); -SECDB_ATTR(v6keycrtr, "crtr", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0), NULL, NULL); +SECDB_ATTR(v6keytype, "type", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); +SECDB_ATTR(v6keycrtr, "crtr", Number, SecDbFlags(P,L, , ,A, , ,C,H, ,Z, ,N, ,V0,Y), NULL, NULL); // | | | | | | | | | | | | | | | -SECDB_ATTR(v6version, "version", Number, SecDbFlags(P,L, , , , , , , , , , ,N, , ), NULL, NULL); -SECDB_ATTR(v91minor, "minor", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , ), NULL, NULL); +SECDB_ATTR(v6version, "version", Number, SecDbFlags(P,L, , , , , , , , , , ,N, , ,Y), NULL, NULL); +SECDB_ATTR(v91minor, "minor", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , ,Y), NULL, NULL); + +SECDB_ATTR(v10_1pcsservice, "pcss", Number, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v10_1pcspublickey, "pcsk", Blob, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); +SECDB_ATTR(v10_1pcspublicidentity,"pcsi", Blob, SecDbFlags( ,L, , ,A, , ,C,H, , , , , , ,Y), NULL, NULL); + +SECDB_ATTR(v10itemuuid, "UUID", String, SecDbFlags( ,L, , , , , , , , , , , ,U, , ), NULL, NULL); +SECDB_ATTR(v10syncuuid, "UUID", String, SecDbFlags(P,L, , , , , , , , , , , ,U, , ), NULL, NULL); +SECDB_ATTR(v10parentKeyUUID, "parentKeyUUID", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10currentKeyUUID,"currentKeyUUID",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10wrappedkey, "wrappedkey", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10encrypteditem, "encitem", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10gencount, "gencount", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); +SECDB_ATTR(v10action, "action", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10state, "state", String, SecDbFlags(P,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10waituntiltime, "waituntil", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10encodedCKRecord, "ckrecord", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1wasCurrent, "wascurrent", Number, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10accessgroup, "accessgroup", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10keyclass, "keyclass", String, SecDbFlags(P,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10currentkey, "currentkey", Number, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10ckzone, "ckzone", String, SecDbFlags(P,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10ckzonecreated, "ckzonecreated", Number, SecDbFlags( ,L, , , , , , , , ,Z, , ,N, , ), NULL, NULL); +SECDB_ATTR(v10ckzonesubscribed,"ckzonesubscribed", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N, , , ), NULL, NULL); +SECDB_ATTR(v10ratelimiter, "ratelimiter", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10changetoken, "changetoken", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10lastfetchtime, "lastfetch", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10itempersistentref,"persistref", UUID, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10sysbound, "sysb", Number, SecDbFlags( ,L, , ,A, , ,C,H, ,Z, , , , , ), NULL, NULL); +SECDB_ATTR(v10encryptionver, "encver", Number, SecDbFlags( ,L, , , , , , , , ,Z, ,N,U, , ), NULL, NULL); + +SECDB_ATTR(v10primaryKey, "primaryKey", String, SecDbFlags(P,L, , ,A, , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10publickeyHash, "publickeyHash", Blob, SecDbFlags(P,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10publickey, "publickey", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10backupData, "backupData", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); + +SECDB_ATTR(v10_1digest, "digest", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1signatures, "signatures", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1signerID, "signerID", String, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1leafIDs, "leafIDs", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1peerManIDs, "peerManifests", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1entryDigests,"entryDigests", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_2currentItems,"currentItems", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_2futureData, "futureData", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_2schema, "schema", Blob, SecDbFlags( ,L, , , , , , , , , , ,N,U, , ), NULL, NULL); +SECDB_ATTR(v10_1encRecord, "ckrecord", Blob, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v10_1keyArchiveHash, "key_archive_hash", String, SecDbFlags(P,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1keyArchive, "key_archive", String, SecDbFlags(P,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1archivedKey, "archived_key", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1keyArchiveName, "keyarchive_name", String, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); +SECDB_ATTR(v10_1optionalEncodedCKRecord, "ckrecord", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_1archiveEscrowID,"archive_escrowid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v10_1itempersistentref,"persistref", UUID, SecDbFlags( ,L,I, , , , , , , , , ,N,U, , ), NULL, NULL); + +SECDB_ATTR(v10_1currentItemUUID,"currentItemUUID",String, SecDbFlags(P,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_1currentPtrIdentifier,"identifier",String, SecDbFlags(P,L, , , , , , , , , , , , , , ), NULL, NULL); + +SECDB_ATTR(v10_2device, "device", String, SecDbFlags(P,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2peerid, "peerid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2circleStatus,"circlestatus", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2keyState, "keystate", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2currentTLK, "currentTLK", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2currentClassA,"currentClassA",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v10_2currentClassC,"currentClassC",String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + +const SecDbClass v10_3_ckdevicestate_class = { + .name = CFSTR("ckdevicestate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10_2device, + &v10_2peerid, + &v10_2circleStatus, + &v10_2keyState, + &v10_2currentTLK, + &v10_2currentClassA, + &v10_2currentClassC, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_2_ckmanifest_class = { + .name = CFSTR("ckmanifest"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10gencount, + &v10_1digest, + &v10_1signatures, + &v10_1signerID, + &v10_1leafIDs, + &v10_1peerManIDs, + &v10_2currentItems, + &v10_2futureData, + &v10_2schema, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_2_pending_manifest_class = { + .name = CFSTR("pending_manifest"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10gencount, + &v10_1digest, + &v10_1signatures, + &v10_1signerID, + &v10_1leafIDs, + &v10_1peerManIDs, + &v10_2currentItems, + &v10_2futureData, + &v10_2schema, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_ckmanifest_class = { + .name = CFSTR("ckmanifest"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10gencount, + &v10_1digest, + &v10_1signatures, + &v10_1signerID, + &v10_1leafIDs, + &v10_1peerManIDs, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_pending_manifest_class = { + .name = CFSTR("pending_manifest"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10gencount, + &v10_1digest, + &v10_1signatures, + &v10_1signerID, + &v10_1leafIDs, + &v10_1peerManIDs, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_ckmanifest_leaf_class = { + .name = CFSTR("ckmanifest_leaf"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10_1digest, + &v10_1entryDigests, + &v10_1encRecord, + 0 + } +}; -const SecDbClass genp_class = { +const SecDbClass v10_1_pending_manifest_leaf_class = { + .name = CFSTR("pending_manifest_leaf"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10_1digest, + &v10_1entryDigests, + &v10_1encRecord, + 0 + } +}; + +const SecDbClass v10_1_genp_class = { .name = CFSTR("genp"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -188,12 +369,19 @@ const SecDbClass genp_class = { &v6accc, &v7utomb, &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, 0 }, }; -const SecDbClass inet_class = { +const SecDbClass v10_1_inet_class = { .name = CFSTR("inet"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -229,12 +417,19 @@ const SecDbClass inet_class = { &v6accc, &v7utomb, &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, 0 }, }; -const SecDbClass cert_class = { +const SecDbClass v10_1_cert_class = { .name = CFSTR("cert"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -261,12 +456,19 @@ const SecDbClass cert_class = { &v6accc, &v7utomb, &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, 0 }, }; -const SecDbClass keys_class = { +const SecDbClass v10_1_keys_class = { .name = CFSTR("keys"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -311,12 +513,19 @@ const SecDbClass keys_class = { &v6accc, &v7utomb, &v8musr, + &v10itemuuid, + &v10sysbound, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + &v10_1itempersistentref, 0 } }; -const SecDbClass tversion_class = { +const SecDbClass v10_0_tversion_class = { .name = CFSTR("tversion"), + .itemclass = false, .attrs = { &v6rowid, &v6version, @@ -325,15 +534,778 @@ const SecDbClass tversion_class = { } }; +const SecDbClass v10_2_outgoing_queue_class = { + .name = CFSTR("outgoingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10waituntiltime, + &v10accessgroup, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + &v10_1optionalEncodedCKRecord, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + +const SecDbClass v10_2_incoming_queue_class = { + .name = CFSTR("incomingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + &v10_1optionalEncodedCKRecord, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + + +const SecDbClass v10_1_outgoing_queue_class = { + .name = CFSTR("outgoingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10waituntiltime, + &v10accessgroup, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + +const SecDbClass v10_1_incoming_queue_class = { + .name = CFSTR("incomingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + + +const SecDbClass v10_0_outgoing_queue_class = { + .name = CFSTR("outgoingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10waituntiltime, + &v10accessgroup, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + 0 + } +}; + +const SecDbClass v10_0_incoming_queue_class = { + .name = CFSTR("incomingqueue"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10action, + &v10state, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encryptionver, + 0 + } +}; + +const SecDbClass v10_0_sync_key_class = { + .name = CFSTR("synckeys"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10keyclass, + &v10currentkey, + &v10parentKeyUUID, + &v10state, + &v10wrappedkey, + &v10encodedCKRecord, + 0 + } +}; + +// Stores the "Current Key" records, and parentKeyUUID refers to items in the synckeys table +// Wouldn't foreign keys be nice? +const SecDbClass v10_0_current_key_class = { + .name = CFSTR("currentkeys"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10keyclass, + &v10currentKeyUUID, + &v10encodedCKRecord, + 0 + } +}; + +const SecDbClass v10_1_current_item_class = { + .name = CFSTR("currentitems"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10_1currentPtrIdentifier, + &v10_1currentItemUUID, + &v10state, + &v10encodedCKRecord, + 0 + } +}; + +const SecDbClass v10_1_ckmirror_class = { + .name = CFSTR("ckmirror"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encodedCKRecord, + &v10encryptionver, + &v10_1wasCurrent, + &v10_1pcsservice, + &v10_1pcspublickey, + &v10_1pcspublicidentity, + 0 + } +}; + +const SecDbClass v10_0_ckmirror_class = { + .name = CFSTR("ckmirror"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10syncuuid, + &v10parentKeyUUID, + &v10gencount, + &v10wrappedkey, + &v10encrypteditem, + &v10encodedCKRecord, + &v10encryptionver, + 0 + } +}; + +const SecDbClass v10_0_ckstate_class = { + .name = CFSTR("ckstate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10ckzonecreated, + &v10ckzonesubscribed, + &v10lastfetchtime, + &v10changetoken, + &v10ratelimiter, + 0 + } +}; + +/* Backup table */ +/* Primary keys: v10primaryKey, v8musr */ +const SecDbClass v10_0_item_backup_class = { + .name = CFSTR("item_backup"), + .itemclass = false, + .attrs = { + &v6rowid, + &v10primaryKey, // Primary key of the original item, from v6v_pk + &v8musr, // + &v6sha1, // Hash of the original item + &v10backupData, // Data wrapped to backup keybag + &v6pkhh, // Hash of the public key of the backup bag [v10publickeyHash] + 0 + } +}; + +/* Backup Keybag table */ +/* Primary keys: v10publickeyHash, v8musr */ +const SecDbClass v10_0_backup_keybag_class = { + .name = CFSTR("backup_keybag"), + .itemclass = false, + .attrs = { + &v6rowid, + &v10publickeyHash, // Hash of the public key of the backup bag + &v8musr, // + &v10publickey, // Public key for the asymmetric backup bag + &v6agrp, // Used for backup agent + 0 + } +}; + +const SecDbClass v10_1_backup_keyarchive_class = { + .name = CFSTR("backup_keyarchive"), + .itemclass = false, + .attrs = { + &v10_1keyArchiveHash, // Hash of the key archive + &v8musr, // + &v10_1keyArchive, // Serialised key archive + &v10ckzone, + &v10_1optionalEncodedCKRecord, + &v10_1archiveEscrowID, + 0 + } +}; + +const SecDbClass v10_1_current_archived_keys_class = { + .name = CFSTR("archived_key_backup"), + .itemclass = false, + .attrs = { + &v6pdmn, + &v10syncuuid, + &v8musr, + &v6agrp, + &v10_1keyArchiveHash, + &v10_1archivedKey, + &v10ckzone, + &v10_1optionalEncodedCKRecord, + &v10_1archiveEscrowID, + 0 + } +}; + +const SecDbClass v10_1_current_keyarchive_class = { + .name = CFSTR("currentkeyarchives"), + .itemclass = false, + .attrs = { + &v10_1keyArchiveHash, + &v10_1keyArchiveName, + 0 + } +}; + /* An identity which is really a cert + a key, so all cert and keys attrs are allowed. */ -const SecDbClass identity_class = { +const SecDbClass v_identity_class = { .name = CFSTR("idnt"), + .itemclass = true, + .attrs = { + 0 + }, +}; + +/* + * Version 10.3 + */ +const SecDbSchema v10_3_schema = { + .majorVersion = 10, + .minorVersion = 3, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_0_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_1_current_item_class, + &v10_3_ckdevicestate_class, + 0 + } +}; + +/* + * Version 10.2 + */ +const SecDbSchema v10_2_schema = { + .majorVersion = 10, + .minorVersion = 2, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_0_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_1_current_item_class, + 0 + } +}; + +/* + * Version 10.1 + */ +const SecDbSchema v10_1_schema = { + .majorVersion = 10, + .minorVersion = 1, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_1_outgoing_queue_class, + &v10_1_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v10_0_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_1_ckmanifest_class, + &v10_1_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_1_current_item_class, + 0 + } +}; + +/* + * Version 10.0 + */ + +const SecDbClass v10_0_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, + &v10itempersistentref, + &v10sysbound, + 0 + }, +}; + +const SecDbClass v10_0_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, + &v10itempersistentref, + &v10sysbound, + 0 + }, +}; + +const SecDbClass v10_0_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, + &v10itempersistentref, + &v10sysbound, + 0 + }, +}; + +const SecDbClass v10_0_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, + &v10itempersistentref, + &v10sysbound, + 0 + } +}; + +const SecDbSchema v10_0_schema = { + .majorVersion = 10, + .minorVersion = 0, + .classes = { + &v10_0_genp_class, + &v10_0_inet_class, + &v10_0_cert_class, + &v10_0_keys_class, + &v10_0_tversion_class, + &v10_0_outgoing_queue_class, + &v10_0_incoming_queue_class, + &v10_0_sync_key_class, + &v10_0_ckmirror_class, + &v10_0_current_key_class, + &v10_0_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + 0 + } +}; + +const SecDbClass v9_1_tversion_class = { + .name = CFSTR("tversion91"), + .itemclass = false, + .attrs = { + &v6rowid, + &v6version, + &v91minor, + 0 + } +}; + +const SecDbClass v9_1_genp_class = { + .name = CFSTR("genp91"), + .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, + 0 + }, +}; + +const SecDbClass v9_1_inet_class = { + .name = CFSTR("inet91"), + .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, 0 }, }; +const SecDbClass v9_1_cert_class = { + .name = CFSTR("cert91"), + .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, + 0 + }, +}; + +const SecDbClass v9_1_keys_class = { + .name = CFSTR("keys91"), + .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, + 0 + } +}; + /* * Version 9.1 (iOS 10.0 and OSX 10.11.8/10.12 addded minor version. */ @@ -341,17 +1313,18 @@ const SecDbSchema v9_1_schema = { .majorVersion = 9, .minorVersion = 1, .classes = { - &genp_class, - &inet_class, - &cert_class, - &keys_class, - &tversion_class, + &v9_1_genp_class, + &v9_1_inet_class, + &v9_1_cert_class, + &v9_1_keys_class, + &v9_1_tversion_class, 0 } }; const SecDbClass v9genp_class = { .name = CFSTR("genp9"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -389,6 +1362,7 @@ const SecDbClass v9genp_class = { const SecDbClass v9inet_class = { .name = CFSTR("inet9"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -430,6 +1404,7 @@ const SecDbClass v9inet_class = { const SecDbClass v9cert_class = { .name = CFSTR("cert9"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -462,6 +1437,7 @@ const SecDbClass v9cert_class = { const SecDbClass v9keys_class = { .name = CFSTR("keys9"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -512,6 +1488,7 @@ const SecDbClass v9keys_class = { const SecDbClass v5tversion_class = { .name = CFSTR("tversion5"), + .itemclass = false, .attrs = { &v6version, 0 @@ -537,6 +1514,7 @@ const SecDbSchema v9_schema = { // Version 8 (Internal release iOS 9.3 and OSX 10.11.5) database schema const SecDbClass v8genp_class = { .name = CFSTR("genp8"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -574,6 +1552,7 @@ const SecDbClass v8genp_class = { const SecDbClass v8inet_class = { .name = CFSTR("inet8"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -615,6 +1594,7 @@ const SecDbClass v8inet_class = { const SecDbClass v8cert_class = { .name = CFSTR("cert8"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -647,6 +1627,7 @@ const SecDbClass v8cert_class = { const SecDbClass v8keys_class = { .name = CFSTR("keys8"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -710,6 +1691,7 @@ const SecDbSchema v8_schema = { // Version 7 (iOS 9 and OSX 10.11) database schema const SecDbClass v7genp_class = { .name = CFSTR("genp7"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -746,6 +1728,7 @@ const SecDbClass v7genp_class = { const SecDbClass v7inet_class = { .name = CFSTR("inet7"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -786,6 +1769,7 @@ const SecDbClass v7inet_class = { const SecDbClass v7cert_class = { .name = CFSTR("cert7"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -817,6 +1801,7 @@ const SecDbClass v7cert_class = { const SecDbClass v7keys_class = { .name = CFSTR("keys7"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -881,6 +1866,7 @@ const SecDbSchema v7_schema = { // Version 6 (iOS 7 and OSX 10.9) database schema static const SecDbClass v6genp_class = { .name = CFSTR("genp6"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -914,6 +1900,7 @@ static const SecDbClass v6genp_class = { static const SecDbClass v6inet_class = { .name = CFSTR("inet6"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -951,6 +1938,7 @@ static const SecDbClass v6inet_class = { static const SecDbClass v6cert_class = { .name = CFSTR("cert6"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -979,6 +1967,7 @@ static const SecDbClass v6cert_class = { static const SecDbClass v6keys_class = { .name = CFSTR("keys6"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -1039,6 +2028,7 @@ static const SecDbSchema v6_schema = { // Version 5 (iOS 5 & iOS 6) database schema. static const SecDbClass v5genp_class = { .name = CFSTR("genp5"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -1067,6 +2057,7 @@ static const SecDbClass v5genp_class = { static const SecDbClass v5inet_class = { .name = CFSTR("inet5"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -1099,6 +2090,7 @@ static const SecDbClass v5inet_class = { static const SecDbClass v5cert_class = { .name = CFSTR("cert5"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -1122,6 +2114,7 @@ static const SecDbClass v5cert_class = { static const SecDbClass v5keys_class = { .name = CFSTR("keys5"), + .itemclass = true, .attrs = { &v6rowid, &v6cdat, @@ -1173,7 +2166,13 @@ static const SecDbSchema v5_schema = { } }; -const SecDbSchema *kc_schemas[] = { +SecDbSchema const * const * kc_schemas = NULL; + +const SecDbSchema *v10_kc_schemas[] = { + &v10_3_schema, + &v10_2_schema, + &v10_1_schema, + &v10_0_schema, &v9_1_schema, &v9_schema, &v8_schema, @@ -1182,3 +2181,72 @@ const SecDbSchema *kc_schemas[] = { &v5_schema, 0 }; + +const SecDbSchema * const * all_schemas() { + return v10_kc_schemas; +} + +const SecDbSchema* current_schema() { + // For now, the current schema is the first in the list. + return all_schemas()[0]; +} + +// class accessors for current schema. +static const SecDbClass* find_class(const SecDbSchema* schema, CFStringRef class_name) { + for (const SecDbClass * const *pclass = schema->classes; *pclass; ++pclass) { + if( CFEqualSafe((*pclass)->name, class_name) ) { + return *pclass; + } + } + return NULL; +} + +const SecDbClass* genp_class() { + static const SecDbClass* genp = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + genp = find_class(current_schema(), CFSTR("genp")); + }); + return genp; +} +const SecDbClass* inet_class() { + static const SecDbClass* inet = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + inet = find_class(current_schema(), CFSTR("inet")); + }); + return inet; +} +const SecDbClass* cert_class() { + static const SecDbClass* cert = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + cert = find_class(current_schema(), CFSTR("cert")); + }); + return cert; +} +const SecDbClass* keys_class() { + static const SecDbClass* keys = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + keys = find_class(current_schema(), CFSTR("keys")); + }); + return keys; +} + +// Not really a class per-se +const SecDbClass* identity_class() { + return &v_identity_class; +} + +// Class with 1 element in it which is the database version-> +const SecDbClass* tversion_class() { + static const SecDbClass* tversion = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + tversion = find_class(current_schema(), CFSTR("tversion")); + }); + return tversion; +} + + diff --git a/OSX/sec/securityd/SecItemSchema.h b/OSX/sec/securityd/SecItemSchema.h index d79fff37..637553f7 100644 --- a/OSX/sec/securityd/SecItemSchema.h +++ b/OSX/sec/securityd/SecItemSchema.h @@ -32,30 +32,34 @@ __BEGIN_DECLS -// Current schema is always kc_schemas[0] -extern const SecDbSchema *kc_schemas[]; +const SecDbSchema* current_schema(void); +const SecDbSchema * const * all_schemas(void); -// Direct class accesors for current schema -extern const SecDbClass genp_class; -extern const SecDbClass inet_class; -extern const SecDbClass cert_class; -extern const SecDbClass keys_class; +// class accessors for current schema +const SecDbClass* genp_class(void); +const SecDbClass* inet_class(void); +const SecDbClass* cert_class(void); +const SecDbClass* keys_class(void); // Not really a class per-se -extern const SecDbClass identity_class; +const SecDbClass* identity_class(void); // Class with 1 element in it which is the database version. -extern const SecDbClass tversion_class; +const SecDbClass* tversion_class(void); -// Direct attribute accesors for current schema +// Direct attribute accessors +// If you change one of these, update it here extern const SecDbAttr v6v_Data; extern const SecDbAttr v6agrp; +extern const SecDbAttr v6desc; extern const SecDbAttr v6svce; extern const SecDbAttr v7vwht; extern const SecDbAttr v7tkid; extern const SecDbAttr v7utomb; extern const SecDbAttr v8musr; +extern const SecDbAttr v10itemuuid; +extern const SecDbAttr v10itempersistentref; // TODO: Directly expose other important attributes like // kSecItemSyncAttr, kSecItemTombAttr, kSecItemCdatAttr, kSecItemMdatAttr, kSecItemDataAttr diff --git a/OSX/sec/securityd/SecItemServer.c b/OSX/sec/securityd/SecItemServer.c index e0e7fc3b..030b4892 100644 --- a/OSX/sec/securityd/SecItemServer.c +++ b/OSX/sec/securityd/SecItemServer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -39,13 +39,18 @@ #include #include #include +#include #include #include #include #include +#include + +#include #if USE_KEYSTORE #include +#include #endif // TODO: Make this include work on both platforms. rdar://problem/16526848 #if TARGET_OS_EMBEDDED @@ -57,7 +62,7 @@ #endif #if TARGET_OS_EMBEDDED -#include +#include #include #include #endif @@ -66,24 +71,13 @@ #include #include #include +#include #include #include "swcagent_client.h" +#include "SecPLWrappers.h" -#if TARGET_OS_IPHONE && !TARGET_OS_WATCH -#include +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE #include - -typedef OSStatus (*SWCCheckService_f)(CFStringRef service, CFStringRef appID, CFStringRef domain, SWCCheckServiceCompletion_b completion); -typedef OSStatus (*SWCSetServiceFlags_f)(CFStringRef service, CFStringRef appID, CFStringRef domain, SWCFlags mask, SWCFlags flags, SWCSetServiceFlagsCompletion_b completion); -#else -typedef uint32_t SWCFlags; -#define kSWCFlags_None 0 -#define kSWCFlag_Pending ( 1U << 0 ) -#define kSWCFlag_SiteApproved ( 1U << 1 ) -#define kSWCFlag_SiteDenied ( 1U << 2 ) -#define kSWCFlag_UserApproved ( 1U << 3 ) -#define kSWCFlag_UserDenied ( 1U << 4 ) -#define kSWCFlag_ExternalMask ( kSWCFlag_UserApproved | kSWCFlag_UserDenied ) #endif /* Changed the name of the keychain changed notification, for testing */ @@ -95,11 +89,21 @@ void SecItemServerSetKeychainChangedNotification(const char *notification_name) } void SecKeychainChanged() { - uint32_t result = notify_post(g_keychain_changed_notification); - if (result == NOTIFY_STATUS_OK) - secnotice("item", "Sent %s", g_keychain_changed_notification); - else - secerror("notify_post %s returned: %" PRIu32, g_keychain_changed_notification, result); + static dispatch_once_t once; + static sec_action_t action; + + dispatch_once(&once, ^{ + action = sec_action_create("SecKeychainChanged", 1); + sec_action_set_handler(action, ^{ + uint32_t result = notify_post(g_keychain_changed_notification); + if (result == NOTIFY_STATUS_OK) + secnotice("item", "Sent %s", g_keychain_changed_notification); + else + secerror("notify_post %s returned: %" PRIu32, g_keychain_changed_notification, result); + }); + }); + + sec_action_perform(action); } /* Return the current database version in *version. */ @@ -188,11 +192,11 @@ measureUpgradePhase1(struct timeval *start, bool success, int64_t itemsMigrated) int64_t duration = measureDuration(start); if (success) { - ADClientSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-success"), itemsMigrated); - ADClientSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-success"), duration); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-success"), itemsMigrated); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-success"), duration); } else { - ADClientSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-fail"), itemsMigrated); - ADClientSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-fail"), duration); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-fail"), itemsMigrated); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-fail"), duration); } } @@ -201,20 +205,53 @@ measureUpgradePhase2(struct timeval *start, int64_t itemsMigrated) { int64_t duration = measureDuration(start); - ADClientSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-items"), itemsMigrated); - ADClientSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-time"), duration); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-items"), itemsMigrated); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-time"), duration); } #endif /* TARGET_OS_EMBEDDED */ +static bool DBClassesAreEqual(const SecDbClass* class1, const SecDbClass* class2) +{ + if (CFEqual(class1->name, class2->name) && class1->itemclass == class2->itemclass) { + int attrIndex = 0; + const SecDbAttr* class1Attr = class1->attrs[attrIndex]; + const SecDbAttr* class2Attr = class2->attrs[attrIndex]; + + while (class1Attr && class2Attr) { + if (CFEqual(class1Attr->name, class2Attr->name) && class1Attr->kind == class2Attr->kind && class1Attr->flags == class2Attr->flags && class1Attr->copyValue == class2Attr->copyValue && class1Attr->setValue == class2Attr->setValue) { + attrIndex++; + class1Attr = class1->attrs[attrIndex]; + class2Attr = class2->attrs[attrIndex]; + } + else { + return false; + } + } + + // if everything has checked out to this point, and we've hit the end of both class's attr list, then they're equal + if (class1Attr == NULL && class2Attr == NULL) { + return true; + } + } + + return false; +} + +static bool ShouldRenameTable(const SecDbClass* class1, const SecDbClass* class2, int oldTableVersion) +{ + return oldTableVersion < 10 || !DBClassesAreEqual(class1, class2); +} + // Goes through all tables represented by old_schema and tries to migrate all items from them into new (current version) tables. static bool UpgradeSchemaPhase1(SecDbConnectionRef dbt, const SecDbSchema *oldSchema, CFErrorRef *error) { __block bool ok = true; - const SecDbSchema *newSchema = kc_schemas[0]; + const SecDbSchema *newSchema = current_schema(); SecDbClass const *const *oldClass; SecDbClass const *const *newClass; SecDbQueryRef query = NULL; CFMutableStringRef sql = NULL; + SecDbClass* renamedOldClass = NULL; #if TARGET_OS_EMBEDDED __block int64_t itemsMigrated = 0; struct timeval start; @@ -222,18 +259,37 @@ static bool UpgradeSchemaPhase1(SecDbConnectionRef dbt, const SecDbSchema *oldSc gettimeofday(&start, NULL); #endif - // Rename existing tables to old names, as present in old schemas. + // Rename existing tables to names derived from old schema names sql = CFStringCreateMutable(NULL, 0); + bool oldClassDone = false; + CFMutableArrayRef classIndexesForNewTables = CFArrayCreateMutable(NULL, 0, NULL); + int classIndex = 0; for (oldClass = oldSchema->classes, newClass = newSchema->classes; - *oldClass != NULL && *newClass != NULL; oldClass++, newClass++) { - if (!CFEqual((*oldClass)->name, (*newClass)->name)) { - CFStringAppendFormat(sql, NULL, CFSTR("ALTER TABLE %@ RENAME TO %@;"), - (*newClass)->name, (*oldClass)->name); - } else { - CFStringAppendFormat(sql, NULL, CFSTR("DROP TABLE %@;"), (*oldClass)->name); + *newClass != NULL; classIndex++, oldClass++, newClass++) { + oldClassDone |= (*oldClass) == NULL; // Check if the new schema has more tables than the old + + if (!oldClassDone && !CFEqual((*oldClass)->name, (*newClass)->name) && ShouldRenameTable(*oldClass, *newClass, oldSchema->majorVersion)) { + CFStringAppendFormat(sql, NULL, CFSTR("ALTER TABLE %@ RENAME TO %@_old;"), (*newClass)->name, (*oldClass)->name); + CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); + + } else if (!oldClassDone && !DBClassesAreEqual(*oldClass, *newClass)) { + CFStringAppendFormat(sql, NULL, CFSTR("ALTER TABLE %@ RENAME TO %@_old;"), (*newClass)->name, (*oldClass)->name); + CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); + } + + if(oldClassDone && *newClass) { + // These should be no-ops, unless you're upgrading a previously-upgraded database with an invalid version number + CFStringAppendFormat(sql, NULL, CFSTR("DROP TABLE IF EXISTS %@;"), (*newClass)->name); + + if (classIndexesForNewTables) { + CFArrayAppendValue(classIndexesForNewTables, (void*)(long)classIndex); + } } } - require_quiet(ok &= SecDbExec(dbt, sql, error), out); + + if(CFStringGetLength(sql) > 0) { + require_quiet(ok &= SecDbExec(dbt, sql, error), out); + } CFReleaseNull(sql); // Drop indices that that new schemas will use @@ -247,91 +303,155 @@ static bool UpgradeSchemaPhase1(SecDbConnectionRef dbt, const SecDbSchema *oldSc CFReleaseNull(sql); // Create tables for new schema. - require_quiet(ok &= SecItemDbCreateSchema(dbt, newSchema, false, error), out); + require_quiet(ok &= SecItemDbCreateSchema(dbt, newSchema, classIndexesForNewTables, false, error), out); // Go through all classes of current schema to transfer all items to new tables. for (oldClass = oldSchema->classes, newClass = newSchema->classes; *oldClass != NULL && *newClass != NULL; oldClass++, newClass++) { - if (CFEqual((*oldClass)->name, (*newClass)->name)) + + if (CFEqual((*oldClass)->name, (*newClass)->name) && DBClassesAreEqual(*oldClass, *newClass)) { continue; + } secnotice("upgr", "Upgrading table %@", (*oldClass)->name); - // Prepare query to iterate through all items in cur_class. - if (query != NULL) - query_destroy(query, NULL); - require_quiet(query = query_create(*oldClass, SecMUSRGetAllViews(), NULL, error), out); + // Create a new 'old' class with a new 'old' name. + int count = 0; + SecDbForEachAttr(*oldClass, attr) { + count++; + } + if(renamedOldClass) { + CFReleaseNull(renamedOldClass->name); + free(renamedOldClass); + } + renamedOldClass = (SecDbClass*) malloc(sizeof(SecDbClass) + sizeof(SecDbAttr*)*(count+1)); + renamedOldClass->name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@_old"), (*oldClass)->name); + renamedOldClass->itemclass = (*oldClass)->itemclass; + for(; count >= 0; count--) { + renamedOldClass->attrs[count] = (*oldClass)->attrs[count]; + } - ok &= SecDbItemSelect(query, dbt, error, ^bool(const SecDbAttr *attr) { - // We are interested in all attributes which are physically present in the DB. - return (attr->flags & kSecDbInFlag) != 0; - }, ^bool(const SecDbAttr *attr) { - // No filtering please. - return false; - }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { - CFErrorRef localError = NULL; + // SecDbItemSelect only works for item classes. + if((*oldClass)->itemclass) { + // 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); + + ok &= SecDbItemSelect(query, dbt, error, ^bool(const SecDbAttr *attr) { + // We are interested in all attributes which are physically present in the DB. + return (attr->flags & kSecDbInFlag) != 0; + }, ^bool(const SecDbAttr *attr) { + // No filtering please. + return false; + }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { + CFErrorRef localError = NULL; -#if TARGET_OS_EMBEDDED - itemsMigrated++; + #if TARGET_OS_EMBEDDED + itemsMigrated++; + #endif + // Switch item to the new class. + item->class = *newClass; + + if (isClassD(item)) { + // Decrypt the item. + ok &= SecDbItemEnsureDecrypted(item, &localError); + require_quiet(ok, out); + + // Delete SHA1 field from the item, so that it is newly recalculated before storing + // the item into the new table. + require_quiet(ok &= SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), + kCFNull, error), out); + } else { + // Leave item encrypted, do not ever try to decrypt it since it will fail. + item->_edataState = kSecDbItemAlwaysEncrypted; + } + // Drop items with kSecAttrAccessGroupToken, as these items should not be there at all. Since agrp attribute + // is always stored as cleartext in the DB column, we can always rely on this attribute being present in item->attributes. + // + if (CFEqualSafe(SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup), kSecAttrAccessGroupToken) && + SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL) { + 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)) { + secerror("item: %@ insert during upgrade: %@", item, localError); + ok = false; + } + } + + out: + if (localError) { + OSStatus status = SecErrorGetOSStatus(localError); + + switch (status) { + // continue to upgrade and don't propagate errors for insert failures + // that are typical of a single item failure + case errSecDecode: + case errSecDuplicateItem: + ok = true; + break; + case errSecInteractionNotAllowed: + case errSecAuthNeeded: + ok = true; + break; + // This does not mean the keychain is hosed, we just can't use it right now +#if USE_KEYSTORE + case kAKSReturnNotReady: + case kAKSReturnTimeout: #endif - // Switch item to the new class. - item->class = *newClass; + case errSecNotAvailable: + secnotice("upgr", "Bailing in phase 1 because AKS is unavailable: %@", localError); + // FALLTHROUGH + default: + ok &= CFErrorPropagate(CFRetainSafe(localError), error); + break; + } + CFReleaseSafe(localError); + } - if (isClassD(item)) { - // Decrypt the item. - ok &= SecDbItemEnsureDecrypted(item, &localError); - require_quiet(ok, out); + *stop = !ok; + }); - // Delete SHA1 field from the item, so that it is newly recalculated before storing - // the item into the new table. - require_quiet(ok &= SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), - kCFNull, error), out); - } else { - // Leave item encrypted, do not ever try to decrypt it since it will fail. - item->_edataState = kSecDbItemAlwaysEncrypted; - } - // Insert new item into the new table. - if (!SecDbItemInsert(item, dbt, &localError)) { - secerror("item: %@ insert during upgrade: %@", item, localError); - ok = false; - } + require_quiet(ok, out); + } else { + // This table does not contain secdb items, and must be transferred without using SecDbItemSelect. + // For now, this code does not support removing or renaming any columns, or adding any new non-null columns. + CFReleaseNull(sql); + sql = CFStringCreateMutable(NULL, 0); + bool comma = false; - out: - if (localError) { - OSStatus status = SecErrorGetOSStatus(localError); + CFMutableStringRef columns = CFStringCreateMutable(NULL, 0); - switch (status) { - // continue to upgrade and don't propagate errors for insert failures - // that are typical of a single item failure - case errSecDecode: - case errSecDuplicateItem: - ok = true; - break; - case errSecInteractionNotAllowed: - case errSecAuthNeeded: - ok = true; - break; - default: - ok &= CFErrorPropagate(CFRetainSafe(localError), error); - break; + SecDbForEachAttr(renamedOldClass, attr) { + if(comma) { + CFStringAppendFormat(columns, NULL, CFSTR(",")); } - CFReleaseSafe(localError); + CFStringAppendFormat(columns, NULL, CFSTR("%@"), attr->name); + comma = true; } - *stop = !ok; - }); - require_quiet(ok, out); + CFStringAppendFormat(sql, NULL, CFSTR("INSERT INTO %@ (%@) SELECT %@ FROM %@;"), (*newClass)->name, columns, columns, renamedOldClass->name); + + CFReleaseNull(columns); + require_quiet(ok &= SecDbExec(dbt, sql, error), out); + } } // Remove old tables from the DB. + CFReleaseNull(sql); sql = CFStringCreateMutable(NULL, 0); for (oldClass = oldSchema->classes, newClass = newSchema->classes; *oldClass != NULL && *newClass != NULL; oldClass++, newClass++) { - if (!CFEqual((*oldClass)->name, (*newClass)->name)) { - CFStringAppendFormat(sql, NULL, CFSTR("DROP TABLE %@;"), (*oldClass)->name); + if (CFEqual((*oldClass)->name, (*newClass)->name) && DBClassesAreEqual(*oldClass, *newClass)) { + continue; } + + CFStringAppendFormat(sql, NULL, CFSTR("DROP TABLE %@_old;"), (*oldClass)->name); } - require_quiet(ok &= SecDbExec(dbt, sql, error), out); + if(CFStringGetLength(sql) > 0) { + require_quiet(ok &= SecDbExec(dbt, sql, error), out); + } out: #if TARGET_OS_EMBEDDED measureUpgradePhase1(&start, ok, SecBucket2Significant(itemsMigrated)); @@ -341,6 +461,11 @@ out: query_destroy(query, NULL); } CFReleaseSafe(sql); + CFReleaseNull(classIndexesForNewTables); + if(renamedOldClass) { + CFReleaseNull(renamedOldClass->name); + free(renamedOldClass); + } return ok; } @@ -356,10 +481,10 @@ static bool UpgradeItemPhase2(SecDbConnectionRef dbt, bool *inProgress, CFErrorR #endif // Go through all classes in new schema - const SecDbSchema *newSchema = kc_schemas[0]; + const SecDbSchema *newSchema = current_schema(); for (const SecDbClass *const *class = newSchema->classes; *class != NULL && !*inProgress; class++) { - if(CFEqual((*class)->name, tversion_class.name)) { - //Don't try to decrypt items in tversion table + if(!((*class)->itemclass)) { + //Don't try to decrypt non-item 'classes' continue; } @@ -398,10 +523,18 @@ static bool UpgradeItemPhase2(SecDbConnectionRef dbt, bool *inProgress, CFErrorR // the item into the new table. require_quiet(ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), kCFNull, &localError), out); - - // 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. - ok = SecDbItemUpdate(item, item, dbt, false, &localError); + // Drop items with kSecAttrAccessGroupToken, as these items should not be there at all. Since agrp attribute + // is always stored as cleartext in the DB column, we can always rely on this attribute being present in item->attributes. + // + 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, dbt, kCFBooleanFalse, &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. + ok = SecDbItemUpdate(item, item, dbt, false, query->q_uuid_from_primary_key, &localError); + } } if (localError) { @@ -427,6 +560,13 @@ static bool UpgradeItemPhase2(SecDbConnectionRef dbt, bool *inProgress, CFErrorR // ACM context, which we do not have). ok = true; break; +#if USE_KEYSTORE + case kAKSReturnNotReady: + case kAKSReturnTimeout: +#endif + case errSecNotAvailable: + secnotice("upgr", "Bailing in phase 2 because AKS is unavailable: %@", localError); + // FALLTHROUGH default: // Other errors should abort the migration completely. ok = CFErrorPropagate(CFRetainSafe(localError), error); @@ -466,8 +606,7 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, if (error) *error = NULL; - // The schema we want to have is the first in the list of schemas. - const SecDbSchema *newSchema = kc_schemas[0]; + const SecDbSchema *newSchema = current_schema(); // If DB schema is the one we want, we are done. require_quiet(SCHEMA_VERSION(newSchema) != version, out); @@ -485,7 +624,7 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, // NOTE: This has to be run outside of a transaction. require_action_quiet(ok = (SecDbExec(dbt, CFSTR("PRAGMA auto_vacuum = FULL"), &localError) && SecDbExec(dbt, CFSTR("PRAGMA journal_mode = WAL"), &localError)), - out, secerror("unable to enable WAL or auto vacuum, marking DB as corrupt: %@", + out, secerror("upgrade: unable to enable WAL or auto vacuum, marking DB as corrupt: %@", localError)); } @@ -502,7 +641,7 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, require_quiet(SCHEMA_VERSION(newSchema) != version2, out); // 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, true, &localError)); + require_action_quiet(version2 != 0, out, ok = SecItemDbCreateSchema(dbt, newSchema, NULL, true, &localError)); int oldVersion = VERSION_OLD(version2); version2 = VERSION_NEW(version2); @@ -520,7 +659,7 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, // Find schema for old database. const SecDbSchema *oldSchema = NULL; - for (const SecDbSchema * const *pschema = kc_schemas; *pschema; ++pschema) { + for (const SecDbSchema * const *pschema = all_schemas(); *pschema; ++pschema) { if (SCHEMA_VERSION((*pschema)) == oldVersion) { oldSchema = *pschema; break; @@ -533,7 +672,7 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, secerror("no schema for version 0x%x", oldVersion)); secnotice("upgr", "Upgrading from version 0x%x to 0x%x", oldVersion, SCHEMA_VERSION(newSchema)); - require(ok = UpgradeSchemaPhase1(dbt, oldSchema, &localError), out); + require_action(ok = UpgradeSchemaPhase1(dbt, oldSchema, &localError), out, secerror("upgrade: Upgrade phase1 failed: %@", localError)); didPhase1 = true; } @@ -554,7 +693,7 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, } } CFReleaseNull(phase2Error); - require(ok, out); + require_action(ok, out, secerror("upgrade: Upgrade phase2 (%d) failed: %@", didPhase1, localError)); if (!*inProgress) { // If either migration path we did reported that the migration was complete, signalize that @@ -572,21 +711,25 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, secnotice("upgr", "Upgrading saving version major 0x%x minor 0x%x", major, minor); sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("UPDATE tversion SET version='%d', minor='%d'"), major, minor); - require_quiet(ok = SecDbExec(dbt, sql, &localError), out); + require_action_quiet(ok = SecDbExec(dbt, sql, &localError), out, secerror("upgrade: Setting version failed: %@", localError)); out: + if (!ok) { + secerror("upgrade: SecDB upgrade failed: %@", localError); + } CFReleaseSafe(sql); *commit = ok; }); if (ok && didPhase2) { #if TARGET_OS_EMBEDDED - ADClientAddValueForScalarKey(CFSTR("com.apple.keychain.migration-success"), 1); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.migration-success"), 1); #endif } out: if (!ok || localError) { + // TODO: This logic should be inverted to a do-not-corrupt-unless default, /* * We assume that database is corrupt at this point, but we need to * check if the error we got isn't severe enough to mark the database as corrupt. @@ -598,27 +741,32 @@ out: secwarning("upgrade: error has been set but status is true"); ok = false; } + secerror("upgrade: error occurred, considering marking database as corrupt: %@", localError); if (localError) { CFStringRef domain = CFErrorGetDomain(localError); CFIndex code = CFErrorGetCode(localError); - - if (CFEqualSafe(domain, kSecDbErrorDomain) && - ((code & 0xff) == SQLITE_LOCKED || (code & 0xff) == SQLITE_BUSY || (code & 0xff) == SQLITE_FULL)) + + if ((CFEqualSafe(domain, kSecDbErrorDomain) && + ((code & 0xff) == SQLITE_LOCKED || (code & 0xff) == SQLITE_BUSY || (code & 0xff) == SQLITE_FULL)) || +#if USE_KEYSTORE + code == kAKSReturnNotReady || code == kAKSReturnTimeout || +#endif + code == errSecNotAvailable) { - // TODO This should not be true but SecDb code is too eager to corrupt, rdar://problem/29771874 - ok = true; + secerror("upgrade: not marking keychain database corrupt for error: %@", localError); markedCorrupt = false; CFReleaseNull(localError); } else { - secerror("unable to complete upgrade, marking DB as corrupt: %@", localError); + secerror("upgrade: unable to complete upgrade, marking DB as corrupt: %@", localError); } } else { - secerror("unable to complete upgrade and no error object returned, marking DB as corrupt"); + secerror("upgrade: unable to complete upgrade and no error object returned, marking DB as corrupt"); } if (markedCorrupt) { + secerror("upgrade: marking database as corrupt"); SecDbCorrupt(dbt, localError); #if TARGET_OS_EMBEDDED - ADClientAddValueForScalarKey(CFSTR("com.apple.keychain.migration-failure"), 1); + SecADSetValueForScalarKey(CFSTR("com.apple.keychain.migration-failure"), 1); #endif } } @@ -632,13 +780,17 @@ out: return ok; } +static bool accessGroupIsNetworkExtensionAndClientIsEntitled(CFStringRef accessGroup, SecurityClient* client) +{ + return client && client->canAccessNetworkExtensionAccessGroups && accessGroup && CFStringHasSuffix(accessGroup, kSecNetworkExtensionAccessGroupSuffix); +} + /* AUDIT[securityd](done): accessGroup (ok) is a caller provided, non NULL CFTypeRef. Return true iff accessGroup is allowable according to accessGroups. */ -static bool accessGroupsAllows(CFArrayRef accessGroups, - CFStringRef accessGroup) { +bool accessGroupsAllows(CFArrayRef accessGroups, CFStringRef accessGroup, SecurityClient* client) { /* NULL accessGroups is wildcard. */ if (!accessGroups) return true; @@ -650,7 +802,8 @@ static bool accessGroupsAllows(CFArrayRef accessGroups, CFRange range = { 0, CFArrayGetCount(accessGroups) }; if (range.length && (CFArrayContainsValue(accessGroups, range, accessGroup) || - CFArrayContainsValue(accessGroups, range, CFSTR("*")))) + CFArrayContainsValue(accessGroups, range, CFSTR("*")) || + accessGroupIsNetworkExtensionAndClientIsEntitled(accessGroup, client))) return true; return false; @@ -658,7 +811,7 @@ static bool accessGroupsAllows(CFArrayRef accessGroups, bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups) { return accessGroupsAllows(accessGroups, - CFDictionaryGetValue(item, kSecAttrAccessGroup)); + CFDictionaryGetValue(item, kSecAttrAccessGroup), NULL); } @@ -790,6 +943,13 @@ out: if (mkbhandle) CFRelease(mkbhandle); #endif + + if (ok) { + secwarning("Restore completed sucessfully"); + } else { + secwarning("Restore failed with: %@", error ? *error : NULL); + } + return ok; } @@ -816,8 +976,10 @@ CFStringRef __SecKeychainCopyPath(void) { // MARK; - // MARK: kc_dbhandle init and reset -SecDbRef SecKeychainDbCreate(CFStringRef path) { - return SecDbCreate(path, ^bool (SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { +SecDbRef SecKeychainDbCreate(CFStringRef path, CFErrorRef* error) { + __block CFErrorRef localerror = NULL; + + SecDbRef kc = SecDbCreate(path, ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { // Upgrade from version 0 means create the schema in empty db. int version = 0; bool ok = true; @@ -828,18 +990,58 @@ SecDbRef SecKeychainDbCreate(CFStringRef path) { if (!ok) secerror("Upgrade %sfailed: %@", didCreate ? "from v0 " : "", error ? *error : NULL); + localerror = error ? *error : NULL; + + if(ok) { + // This block might get called many, many times due to callMeAgainForNextConnection. + // When we no longer want to be called, we believe we're done. Begin the rest of initialization. + if( !callMeAgainForNextConnection || !(*callMeAgainForNextConnection)) { + SecKeychainDbInitialize(db); + } + } + return ok; }); + + if(error) { + *error = localerror; + } + + return kc; +} + +SecDbRef SecKeychainDbInitialize(SecDbRef db) { + +#if OCTAGON + if(SecCKKSIsEnabled()) { + // This needs to be async, otherwise we get hangs between securityd, cloudd, and apsd + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + SecCKKSInitialize(db); + + }); + } +#endif + + return db; } static SecDbRef _kc_dbhandle = NULL; +static dispatch_queue_t _kc_dbhandle_dispatch = NULL; +static dispatch_once_t _kc_dbhandle_dispatch_onceToken = 0; +static dispatch_queue_t get_kc_dbhandle_dispatch() { + dispatch_once(&_kc_dbhandle_dispatch_onceToken, ^{ + _kc_dbhandle_dispatch = dispatch_queue_create("sec_kc_dbhandle", DISPATCH_QUEUE_SERIAL); + }); -static void kc_dbhandle_init(void) { + return _kc_dbhandle_dispatch; +} + +static bool kc_dbhandle_init(CFErrorRef* error) { SecDbRef oldHandle = _kc_dbhandle; _kc_dbhandle = NULL; CFStringRef dbPath = __SecKeychainCopyPath(); if (dbPath) { - _kc_dbhandle = SecKeychainDbCreate(dbPath); + _kc_dbhandle = SecKeychainDbCreate(dbPath, error); CFRelease(dbPath); } else { secerror("no keychain path available"); @@ -848,55 +1050,51 @@ static void kc_dbhandle_init(void) { secerror("replaced %@ with %@", oldHandle, _kc_dbhandle); CFRelease(oldHandle); } + // Having a dbhandle means we succeeded. + return !!_kc_dbhandle; } -// A callback for the sqlite3_log() interface. -static void sqlite3Log(void *pArg, int iErrCode, const char *zMsg){ - secdebug("sqlite3", "(%d) %s", iErrCode, zMsg); -} - -void -_SecServerDatabaseSetup(void) +static SecDbRef kc_dbhandle(CFErrorRef* error) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - int rx = sqlite3_config(SQLITE_CONFIG_LOG, sqlite3Log, NULL); - if (SQLITE_OK != rx) { - secwarning("Could not set up sqlite global error logging to syslog: %d", rx); + dispatch_sync(get_kc_dbhandle_dispatch(), ^{ + if(_kc_dbhandle == NULL) { + _SecDbServerSetup(); + kc_dbhandle_init(error); } }); -} - -static SecDbRef kc_dbhandle(void) -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - _SecServerDatabaseSetup(); - kc_dbhandle_init(); - }); return _kc_dbhandle; } /* For whitebox testing only */ void SecKeychainDbReset(dispatch_block_t inbetween) { - CFStringRef dbPath = __SecKeychainCopyPath(); - if (dbPath == NULL) - abort(); + dispatch_sync(get_kc_dbhandle_dispatch(), ^{ + CFStringRef dbPath = __SecKeychainCopyPath(); + if (dbPath == NULL) + abort(); - CFReleaseNull(_kc_dbhandle); + CFReleaseNull(_kc_dbhandle); - if (inbetween) - inbetween(); + if (inbetween) + inbetween(); - _kc_dbhandle = SecKeychainDbCreate(dbPath); - CFRelease(dbPath); + CFErrorRef error = NULL; + _kc_dbhandle = SecKeychainDbCreate(dbPath, &error); + + if(error) { + secerror("error resetting database: %@", error); + } + + CFRelease(dbPath); + }); } static SecDbConnectionRef kc_acquire_dbt(bool writeAndRead, CFErrorRef *error) { - SecDbRef db = kc_dbhandle(); + SecDbRef db = kc_dbhandle(error); if (db == NULL) { - SecError(errSecDataNotAvailable, error, CFSTR("failed to get a db handle")); + if(error && !(*error)) { + SecError(errSecDataNotAvailable, error, CFSTR("failed to get a db handle")); + } return NULL; } return SecDbConnectionAcquire(db, !writeAndRead, error); @@ -905,17 +1103,23 @@ static SecDbConnectionRef kc_acquire_dbt(bool writeAndRead, CFErrorRef *error) { /* Return a per thread dbt handle for the keychain. If create is true create the database if it does not yet exist. If it is false, just return an error if it fails to auto-create. */ -static bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)) +__thread SecDbConnectionRef dbt = NULL; +bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)) { + if(dbt) { + // The kc_with_dbt upthread will clean this up when it's done. + return perform(dbt); + } // Make sure we initialize our engines before writing to the keychain if (writeAndRead) SecItemDataSourceFactoryGetDefault(); bool ok = false; - SecDbConnectionRef dbt = kc_acquire_dbt(writeAndRead, error); + dbt = kc_acquire_dbt(writeAndRead, error); if (dbt) { ok = perform(dbt); SecDbConnectionRelease(dbt); + dbt = NULL; } return ok; } @@ -1095,13 +1299,14 @@ out: static SecCertificateRef CopyCertificateFromItem(Query *q, CFDictionaryRef item) { SecCertificateRef certRef = NULL; + CFDictionaryRef itemValue = NULL; CFTypeRef tokenID = NULL; CFDataRef certData = NULL; - if (q->q_class == &identity_class) { + if (q->q_class == identity_class()) { certData = CFDictionaryGetValue(item, kSecAttrIdentityCertificateData); tokenID = CFDictionaryGetValue(item, kSecAttrIdentityCertificateTokenID); - } else if (q->q_class == &cert_class) { + } else if (q->q_class == cert_class()) { certData = CFDictionaryGetValue(item, kSecValueData); tokenID = CFDictionaryGetValue(item, kSecAttrTokenID); } @@ -1109,15 +1314,17 @@ CopyCertificateFromItem(Query *q, CFDictionaryRef item) { require_quiet(certData, out); if (tokenID != NULL) { CFErrorRef error = NULL; - CFDataRef tokenCertData = _SecTokenItemCopyValueData(certData, &error); - require_action_quiet(tokenCertData, out, { secerror("function _SecTokenItemCopyValueData failed with: %@", error); CFReleaseSafe(error); }); + itemValue = SecTokenItemValueCopy(certData, &error); + require_action_quiet(itemValue, out, { secerror("function SecTokenItemValueCopy failed with: %@", error); CFReleaseSafe(error); }); + CFDataRef tokenCertData = CFDictionaryGetValue(itemValue, kSecTokenValueDataKey); + require_action_quiet(tokenCertData, out, { secerror("token item doesn't contain token value data");}); certRef = SecCertificateCreateWithData(kCFAllocatorDefault, tokenCertData); - CFRelease(tokenCertData); } else certRef = SecCertificateCreateWithData(kCFAllocatorDefault, certData); out: + CFReleaseNull(itemValue); return certRef; } @@ -1131,21 +1338,21 @@ bool match_item(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFDic return ok; } - if (q->q_match_policy && (q->q_class == &identity_class || q->q_class == &cert_class)) { + if (q->q_match_policy && (q->q_class == identity_class() || q->q_class == cert_class())) { if (!certRef) certRef = CopyCertificateFromItem(q, item); require_quiet(certRef, out); require_quiet(_FilterWithPolicy(q->q_match_policy, q->q_match_valid_on_date, certRef), out); } - if (q->q_match_valid_on_date && (q->q_class == &identity_class || q->q_class == &cert_class)) { + if (q->q_match_valid_on_date && (q->q_class == identity_class() || q->q_class == cert_class())) { if (!certRef) certRef = CopyCertificateFromItem(q, item); require_quiet(certRef, out); require_quiet(_FilterWithDate(q->q_match_valid_on_date, certRef), out); } - if (q->q_match_trusted_only && (q->q_class == &identity_class || q->q_class == &cert_class)) { + if (q->q_match_trusted_only && (q->q_class == identity_class() || q->q_class == cert_class())) { if (!certRef) certRef = CopyCertificateFromItem(q, item); require_quiet(certRef, out); @@ -1176,6 +1383,36 @@ static bool SecEntitlementError(OSStatus status, CFErrorRef *error) return SecError(errSecMissingEntitlement, error, CFSTR("Client has neither %@ entitlements"), SEC_ENTITLEMENT_WARNING); } +static CFStringRef CopyAccessGroupForRowID(sqlite_int64 rowID, CFStringRef itemClass) +{ + __block CFStringRef accessGroup = NULL; + + __block CFErrorRef error = NULL; + bool ok = kc_with_dbt(false, &error, ^bool(SecDbConnectionRef dbt) { + CFStringRef table = CFEqual(itemClass, kSecClassIdentity) ? kSecClassCertificate : itemClass; + CFStringRef sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("SELECT agrp FROM %@ WHERE rowid == %u"), table, (unsigned int)rowID); + bool dbOk = SecDbWithSQL(dbt, sql, &error, ^bool(sqlite3_stmt *stmt) { + bool rowOk = SecDbForEach(dbt, stmt, &error, ^bool(int row_index) { + accessGroup = CFStringCreateWithBytes(NULL, sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0), kCFStringEncodingUTF8, false); + return accessGroup != NULL; + }); + + return (bool)(rowOk && accessGroup != NULL); + }); + + CFReleaseNull(sql); + return (bool)(dbOk && accessGroup); + }); + + if (ok) { + return accessGroup; + } + else { + CFReleaseNull(accessGroup); + return NULL; + } +} + /* AUDIT[securityd](done): query (ok) is a caller provided dictionary, only its cf type has been checked. */ @@ -1184,6 +1421,7 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result, SecurityClient *client, CFErrorRef *error) { CFArrayRef accessGroups = client->accessGroups; + CFMutableArrayRef mutableAccessGroups = NULL; CFIndex ag_count; if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { @@ -1191,6 +1429,21 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result, SecTaskDiagnoseEntitlements(accessGroups); return SecEntitlementError(errSecMissingEntitlement, error); } + + if (client->canAccessNetworkExtensionAccessGroups) { + CFDataRef persistentRef = CFDictionaryGetValue(query, kSecValuePersistentRef); + CFStringRef itemClass = NULL; + sqlite_int64 itemRowID = 0; + if (persistentRef && _SecItemParsePersistentRef(persistentRef, &itemClass, &itemRowID, NULL)) { + CFStringRef accessGroup = CopyAccessGroupForRowID(itemRowID, itemClass); + if (accessGroup && CFStringHasSuffix(accessGroup, kSecNetworkExtensionAccessGroupSuffix) && !CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), accessGroup)) { + mutableAccessGroups = CFArrayCreateMutableCopy(NULL, 0, accessGroups); + CFArrayAppendValue(mutableAccessGroups, accessGroup); + accessGroups = mutableAccessGroups; + } + CFReleaseNull(accessGroup); + } + } if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { /* Having the special accessGroup "*" allows access to all accessGroups. */ @@ -1201,7 +1454,7 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result, Query *q = query_create_with_limit(query, client->musr, 1, error); if (q) { CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup); - if (agrp && accessGroupsAllows(accessGroups, agrp)) { + if (agrp && accessGroupsAllows(accessGroups, agrp, client)) { // TODO: Return an error if agrp is not NULL and accessGroupsAllows() fails above. const void *val = agrp; accessGroups = CFArrayCreate(0, &val, 1, &kCFTypeArrayCallBacks); @@ -1235,11 +1488,11 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result, ok = SecError(errSecMissingEntitlement, error, CFSTR("can't do both system and syncbubble keychain")); } else if (q->q_use_item_list) { ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list unsupported")); - } else if (q->q_match_issuer && ((q->q_class != &cert_class) && - (q->q_class != &identity_class))) { + } else if (q->q_match_issuer && ((q->q_class != cert_class()) && + (q->q_class != identity_class()))) { ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported match attribute")); - } else if (q->q_match_policy && ((q->q_class != &cert_class) && - (q->q_class != &identity_class))) { + } else if (q->q_match_policy && ((q->q_class != cert_class()) && + (q->q_class != identity_class()))) { ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported kSecMatchPolicy attribute")); } else if (q->q_return_type != 0 && result == NULL) { ok = SecError(errSecReturnMissingPointer, error, CFSTR("missing pointer")); @@ -1253,6 +1506,7 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result, if (!query_destroy(q, error)) ok = false; } + CFReleaseNull(mutableAccessGroups); return ok; } @@ -1292,8 +1546,7 @@ _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *resul bool ok = true; CFIndex ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)) || - (ag_count == 1 && CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), kSecAttrAccessGroupToken))) { + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { if (SecTaskDiagnoseEntitlements) SecTaskDiagnoseEntitlements(accessGroups); return SecEntitlementError(errSecMissingEntitlement, error); @@ -1311,7 +1564,7 @@ _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *resul if (agrp) { /* The user specified an explicit access group, validate it. */ - if (!accessGroupsAllows(accessGroups, agrp)) + if (!accessGroupsAllows(accessGroups, agrp, client)) ok = SecError(errSecMissingEntitlement, error, CFSTR("explicit accessGroup %@ not in client access %@"), agrp, accessGroups); } else { @@ -1321,6 +1574,18 @@ _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *resul specified it as an attribute. */ query_add_attribute(kSecAttrAccessGroup, agrp, q); } + + if (CFEqual(agrp, kSecAttrAccessGroupToken)) { + ok = SecError(errSecParam, error, CFSTR("storing items into kSecAttrAccessGroupToken is not allowed")); + } + + if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { + CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("add"), CFSTR("AccessGroup"), agrp, NULL); + if (dict) { + SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); + CFRelease(dict); + } + } #if TARGET_OS_IPHONE if (q->q_system_keychain && client->inMultiUser) { CFReleaseNull(q->q_musrView); @@ -1334,6 +1599,15 @@ _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *resul if (ok) { query_ensure_access_control(q, agrp); +#if OCTAGON + void (^add_sync_callback)(bool, CFErrorRef) = CFDictionaryGetValue(attributes, CFSTR("f_ckkscallback")); + if(add_sync_callback) { + // The existence of this callback indicates that we need a predictable UUID for this item. + q->q_uuid_from_primary_key = true; + q->q_add_sync_callback = add_sync_callback; + } +#endif + 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) { @@ -1342,7 +1616,7 @@ _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *resul } else if (q->q_system_keychain && SecItemSynchronizable(attributes) && !client->inMultiUser) { ok = SecError(errSecInvalidKey, error, CFSTR("Can't store system keychain and synchronizable")); #endif - } else if (q->q_row_id) { + } 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) { ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt){ @@ -1371,13 +1645,21 @@ _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups = client->accessGroups; CFIndex ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)) || - (ag_count == 1 && CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), kSecAttrAccessGroupToken))) { + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { if (SecTaskDiagnoseEntitlements) SecTaskDiagnoseEntitlements(accessGroups); return SecEntitlementError(errSecMissingEntitlement, error); } + if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { + CFTypeRef agrp = CFArrayGetValueAtIndex(accessGroups, 0); + CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("update"), CFSTR("AccessGroup"), agrp, NULL); + if (dict) { + SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); + CFRelease(dict); + } + } + if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { /* Having the special accessGroup "*" allows access to all accessGroups. */ accessGroups = NULL; @@ -1426,7 +1708,10 @@ _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate, if (agrp) { /* The user is attempting to modify the access group column, validate it to make sure the new value is allowable. */ - if (!accessGroupsAllows(accessGroups, agrp)) { + if (CFEqual(agrp, kSecAttrAccessGroupToken)) { + ok = SecError(errSecParam, error, CFSTR("storing items into kSecAttrAccessGroupToken is not allowed")); + } + if (!accessGroupsAllows(accessGroups, agrp, client)) { ok = SecError(errSecNoAccessForItem, error, CFSTR("accessGroup %@ not in %@"), agrp, accessGroups); } } @@ -1455,13 +1740,21 @@ _SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error) CFArrayRef accessGroups = client->accessGroups; CFIndex ag_count; - if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)) || - (ag_count == 1 && CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), kSecAttrAccessGroupToken))) { + if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) { if (SecTaskDiagnoseEntitlements) SecTaskDiagnoseEntitlements(accessGroups); return SecEntitlementError(errSecMissingEntitlement, error); } + if (SecPLShouldLogRegisteredEvent(CFSTR("SecItem"))) { + CFTypeRef agrp = CFArrayGetValueAtIndex(accessGroups, 0); + CFDictionaryRef dict = CFDictionaryCreateForCFTypes(NULL, CFSTR("operation"), CFSTR("delete"), CFSTR("AccessGroup"), agrp, NULL); + if (dict) { + SecPLLogRegisteredEvent(CFSTR("SecItem"), dict); + CFRelease(dict); + } + } + if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) { /* Having the special accessGroup "*" allows access to all accessGroups. */ accessGroups = NULL; @@ -1493,6 +1786,8 @@ _SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error) ok = SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by delete")); } else if (q->q_row_id && query_attr_count(q)) { ok = SecError(errSecItemIllegalQuery, error, CFSTR("rowid and other attributes are mutually exclusive")); + } else if (q->q_token_object_id && query_attr_count(q) != 1) { + ok = SecError(errSecItemIllegalQuery, error, CFSTR("token persistent ref and other attributes are mutually exclusive")); } else { ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) { return kc_transaction(dbt, error, ^{ @@ -1539,7 +1834,7 @@ static bool SecItemAddTokenItem(SecDbConnectionRef dbt, CFDictionaryRef attribut 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) { + } 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); @@ -1634,12 +1929,20 @@ _SecItemServerDeleteAllWithAccessGroups(CFArrayRef accessGroups, SecurityClient illegalAccessGroups = CFSetCreate(NULL, (const void **)values, sizeof(values)/sizeof(values[0]), &kCFTypeSetCallBacks); }); - static const CFTypeRef qclasses[] = { - &inet_class, - &genp_class, - &keys_class, - &cert_class + static CFTypeRef qclasses[] = { + NULL, + NULL, + NULL, + NULL }; + // strange construction needed for schema indirection + static dispatch_once_t qclassesOnceToken; + dispatch_once(&qclassesOnceToken, ^{ + qclasses[0] = inet_class(); + qclasses[1] = genp_class(); + qclasses[2] = keys_class(); + qclasses[3] = cert_class(); + }); require_action_quiet(isArray(accessGroups), fail, ok = false; @@ -1697,7 +2000,7 @@ fail: // MARK: - // MARK: Shared web credentials -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE /* constants */ #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); @@ -1708,96 +2011,48 @@ SEC_CONST_DECL (kSecSafariPasswordsNotSaved, "Passwords not saved"); SEC_CONST_DECL (kSecSharedCredentialUrlScheme, "https://"); SEC_CONST_DECL (kSecSharedWebCredentialsService, "webcredentials"); -#if TARGET_OS_IPHONE && !TARGET_OS_WATCH -static dispatch_once_t sSecSWCInitializeOnce = 0; -static void * sSecSWCLibrary = NULL; -static SWCCheckService_f sSWCCheckService_f = NULL; -static SWCSetServiceFlags_f sSWCSetServiceFlags_f = NULL; - -static OSStatus _SecSWCEnsuredInitialized(void); - -static OSStatus _SecSWCEnsuredInitialized(void) -{ - __block OSStatus status = errSecNotAvailable; - - dispatch_once(&sSecSWCInitializeOnce, ^{ - sSecSWCLibrary = dlopen("/System/Library/PrivateFrameworks/SharedWebCredentials.framework/SharedWebCredentials", RTLD_LAZY | RTLD_LOCAL); - assert(sSecSWCLibrary); - if (sSecSWCLibrary) { - sSWCCheckService_f = (SWCCheckService_f)(uintptr_t) dlsym(sSecSWCLibrary, "SWCCheckService"); - sSWCSetServiceFlags_f = (SWCSetServiceFlags_f)(uintptr_t) dlsym(sSecSWCLibrary, "SWCSetServiceFlags"); - } - }); - - if (sSWCCheckService_f && sSWCSetServiceFlags_f) { - status = noErr; - } - return status; -} -#endif - #if !TARGET_IPHONE_SIMULATOR static SWCFlags _SecAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFErrorRef *error) { __block SWCFlags flags = kSWCFlags_None; + OSStatus status; -#if TARGET_OS_IPHONE && !TARGET_OS_WATCH - OSStatus status = _SecSWCEnsuredInitialized(); - if (status) { - SecError(status, error, CFSTR("SWC initialize failed")); - return flags; - } - CFRetainSafe(appID); - CFRetainSafe(fqdn); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - dispatch_retain(semaphore); - if (0 == sSWCCheckService_f(kSecSharedWebCredentialsService, appID, fqdn, - ^void (OSStatus inStatus, SWCFlags inFlags, CFDictionaryRef inDetails) { - if (!inStatus) { flags = inFlags; } - CFReleaseSafe(appID); - CFReleaseSafe(fqdn); - dispatch_semaphore_signal(semaphore); - dispatch_release(semaphore); - //secerror("SWCCheckService: inStatus=%d, flags=%0X", inStatus, flags); - })) + if (semaphore == NULL) + return 0; + + status = SWCCheckService(kSecSharedWebCredentialsService, appID, fqdn, ^void (OSStatus inStatus, SWCFlags inFlags, CFDictionaryRef inDetails) { - // wait for the block to complete, as we need its answer + 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 // didn't queue the block - { - CFReleaseSafe(appID); - CFReleaseSafe(fqdn); - dispatch_release(semaphore); + } else { + secerror("SWCCheckService: failed to queue"); } dispatch_release(semaphore); -#else - flags |= (kSWCFlag_SiteApproved); -#endif - - if (!error) { return flags; } - *error = NULL; - // check website approval status - if (!(flags & kSWCFlag_SiteApproved)) { - if (flags & kSWCFlag_Pending) { - SecError(errSecAuthFailed, error, CFSTR("Approval is pending for \"%@\", try later"), fqdn); - } else { - SecError(errSecAuthFailed, error, CFSTR("\"%@\" failed to approve \"%@\""), fqdn, appID); + if (error) { + if (!(flags & kSWCFlag_SiteApproved)) { + if (flags & kSWCFlag_Pending) { + SecError(errSecAuthFailed, error, CFSTR("Approval is pending for \"%@\", try later"), fqdn); + } else { + 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; - } - - // check user approval status - if (flags & kSWCFlag_UserDenied) { - SecError(errSecAuthFailed, error, CFSTR("User denied access to \"%@\" by \"%@\""), fqdn, appID); } return flags; } -#endif -#if !TARGET_IPHONE_SIMULATOR static bool _SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, CFStringRef service) { @@ -1824,23 +2079,19 @@ _SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, } return result; } -#endif +#endif /* !TARGET_OS_SIMULATOR */ static bool _SecAddNegativeWebCredential(SecurityClient *client, CFStringRef fqdn, CFStringRef appID, bool forSafari) { +#if !TARGET_IPHONE_SIMULATOR bool result = false; if (!fqdn) { return result; } -#if TARGET_OS_IPHONE && !TARGET_OS_WATCH - OSStatus status = _SecSWCEnsuredInitialized(); - if (status) { return false; } - // update our database CFRetainSafe(appID); CFRetainSafe(fqdn); - if (0 == sSWCSetServiceFlags_f(kSecSharedWebCredentialsService, - appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserDenied, + if (0 == SWCSetServiceFlags(kSecSharedWebCredentialsService, appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserDenied, ^void(OSStatus inStatus, SWCFlags inNewFlags){ CFReleaseSafe(appID); CFReleaseSafe(fqdn); @@ -1853,7 +2104,7 @@ _SecAddNegativeWebCredential(SecurityClient *client, CFStringRef fqdn, CFStringR CFReleaseSafe(appID); CFReleaseSafe(fqdn); } -#endif + if (!forSafari) { return result; } // below this point: create a negative Safari web credential item @@ -1908,6 +2159,9 @@ _SecAddNegativeWebCredential(SecurityClient *client, CFStringRef fqdn, CFStringR CFReleaseSafe(swcclient.accessGroups); return result; +#else + return true; +#endif } /* Specialized version of SecItemAdd for shared web credentials */ @@ -1925,7 +2179,7 @@ _SecAddSharedWebCredential(CFDictionaryRef attributes, CFStringRef fqdn = CFRetainSafe(CFDictionaryGetValue(attributes, kSecAttrServer)); CFStringRef account = CFDictionaryGetValue(attributes, kSecAttrAccount); -#if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE CFStringRef password = CFDictionaryGetValue(attributes, kSecSharedPassword); #else CFStringRef password = CFDictionaryGetValue(attributes, CFSTR("spwd")); @@ -2044,21 +2298,21 @@ _SecAddSharedWebCredential(CFDictionaryRef attributes, } // look up existing password - if (_SecItemCopyMatching(query, &swcclient, result, error)) { + CFDictionaryAddValue(query, kSecReturnData, kCFBooleanTrue); + bool matched = _SecItemCopyMatching(query, &swcclient, result, error); + CFDictionaryRemoveValue(query, kSecReturnData); + if (matched) { // found it, so this becomes either an "update password" or "delete password" operation - if(result) CFReleaseNull(*result); - if(error) CFReleaseNull(*error); bool update = (password != NULL); if (update) { attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDataRef credential = CFStringCreateExternalRepresentation(kCFAllocatorDefault, password, kCFStringEncodingUTF8, 0); CFDictionaryAddValue(attrs, kSecValueData, credential); + bool samePassword = result && *result && CFEqual(*result, credential); CFReleaseSafe(credential); CFDictionaryAddValue(attrs, kSecAttrComment, kSecSafariDefaultComment); - - // confirm the update - // (per rdar://16676310 we always prompt, even if there was prior user approval) - ok = /*approved ||*/ swca_confirm_operation(swca_update_request_id, clientAuditToken, query, error, + + ok = samePassword || swca_confirm_operation(swca_update_request_id, clientAuditToken, query, error, ^void (CFStringRef fqdn) { _SecAddNegativeWebCredential(client, fqdn, appID, false); }); if (ok) { ok = _SecItemUpdate(query, attrs, &swcclient, error); @@ -2073,9 +2327,10 @@ _SecAddSharedWebCredential(CFDictionaryRef attributes, ok = _SecItemDelete(query, &swcclient, error); } } - if (ok) { - if (error) CFReleaseNull(*error); - } + + if(result) CFReleaseNull(*result); + if(error) CFReleaseNull(*error); + goto cleanup; } if (result) CFReleaseNull(*result); @@ -2286,10 +2541,10 @@ _SecCopySharedWebCredential(CFDictionaryRef query, CFReleaseNull(*error); } if (ok && items && CFGetTypeID(items) == CFArrayGetTypeID()) { - #if TARGET_IPHONE_SIMULATOR +#if TARGET_IPHONE_SIMULATOR secerror("Ignoring app/site approval state in the Simulator."); bool approved = true; - #else +#else // get approval status for this app/domain pair SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error); if (count > 1) { @@ -2297,7 +2552,7 @@ _SecCopySharedWebCredential(CFDictionaryRef query, CFReleaseNull(*error); } bool approved = (flags & kSWCFlag_SiteApproved); - #endif +#endif if (approved) { CFArrayAppendArray(foundItems, items, CFRangeMake(0, CFArrayGetCount(items))); } @@ -2414,18 +2669,11 @@ _SecCopySharedWebCredential(CFDictionaryRef query, } if (ok) { - #if TARGET_OS_IPHONE && !TARGET_OS_WATCH +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_IPHONE_SIMULATOR // register confirmation with database - OSStatus status = _SecSWCEnsuredInitialized(); - if (status) { - SecError(status, error, CFSTR("SWC initialize failed")); - ok = false; - CFReleaseSafe(selected); - goto cleanup; - } CFRetainSafe(appID); CFRetainSafe(fqdn); - if (0 != sSWCSetServiceFlags_f(kSecSharedWebCredentialsService, + if (0 != SWCSetServiceFlags(kSecSharedWebCredentialsService, appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserApproved, ^void(OSStatus inStatus, SWCFlags inNewFlags){ CFReleaseSafe(appID); @@ -2436,7 +2684,7 @@ _SecCopySharedWebCredential(CFDictionaryRef query, CFReleaseSafe(appID); CFReleaseSafe(fqdn); } - #endif +#endif } CFReleaseSafe(selected); } @@ -2466,25 +2714,24 @@ cleanup: CF_RETURNS_RETAINED CFDataRef _SecServerKeychainCreateBackup(SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) { - CFDataRef backup; - SecDbConnectionRef dbt = SecDbConnectionAcquire(kc_dbhandle(), false, error); + __block CFDataRef backup; + kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) { + if (!dbt) + return NULL; - if (!dbt) - return NULL; - - if (keybag == NULL && passcode == NULL) { + if (keybag == NULL && passcode == NULL) { #if USE_KEYSTORE - backup = SecServerExportBackupableKeychain(dbt, client, KEYBAG_DEVICE, backup_keybag_handle, error); + backup = SecServerExportBackupableKeychain(dbt, client, KEYBAG_DEVICE, backup_keybag_handle, error); #else /* !USE_KEYSTORE */ - (void)client; - SecError(errSecParam, error, CFSTR("Why are you doing this?")); - backup = NULL; + (void)client; + SecError(errSecParam, error, CFSTR("Why are you doing this?")); + backup = NULL; #endif /* USE_KEYSTORE */ - } else { - backup = SecServerKeychainCreateBackup(dbt, client, keybag, passcode, error); - } - - SecDbConnectionRelease(dbt); + } else { + backup = SecServerKeychainCreateBackup(dbt, client, keybag, passcode, error); + } + return (backup != NULL); + }); return backup; } @@ -2495,8 +2742,8 @@ _SecServerKeychainRestore(CFDataRef backup, SecurityClient *client, CFDataRef ke return SecError(errSecParam, error, CFSTR("backup or keybag missing")); __block bool ok = true; - ok &= SecDbPerformWrite(kc_dbhandle(), error, ^(SecDbConnectionRef dbconn) { - ok = SecServerKeychainRestore(dbconn, client, backup, keybag, passcode, error); + ok &= kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbconn) { + return SecServerKeychainRestore(dbconn, client, backup, keybag, passcode, error); }); if (ok) { @@ -2516,7 +2763,7 @@ _SecServerBackupCopyUUID(CFDataRef data, CFErrorRef *error) kCFPropertyListImmutable, NULL, error); if (isDictionary(backup)) { - uuid = SecServerBackupGetKeybagUUID(backup); + uuid = SecServerBackupGetKeybagUUID(backup, error); if (uuid) CFRetain(uuid); } @@ -2533,7 +2780,7 @@ _SecServerBackupCopyUUID(CFDataRef data, CFErrorRef *error) // Make sure to call this before any writes to the keychain, so that we fire // up the engines to monitor manifest changes. SOSDataSourceFactoryRef SecItemDataSourceFactoryGetDefault(void) { - return SecItemDataSourceFactoryGetShared(kc_dbhandle()); + return SecItemDataSourceFactoryGetShared(kc_dbhandle(NULL)); } /* AUDIT[securityd]: @@ -2762,6 +3009,158 @@ bool _SecServerRollKeys(bool force, SecurityClient *client, CFErrorRef *error) { #endif } +static bool +InitialSyncItems(CFMutableArrayRef items, bool limitToCurrent, CFStringRef agrp, const SecDbClass *qclass, CFErrorRef *error) +{ + bool result = false; + Query *q = NULL; + + q = query_create(qclass, NULL, NULL, error); + require(q, fail); + + q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask; + q->q_limit = kSecMatchUnlimited; + q->q_keybag = KEYBAG_DEVICE; + + query_add_attribute(kSecAttrAccessGroup, agrp, q); + query_add_attribute(kSecAttrSynchronizable, kCFBooleanTrue, q); + query_add_attribute(kSecAttrTombstone, kCFBooleanFalse, q); + + result = kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^{ + CFErrorRef error2 = NULL; + + SecDbItemSelect(q, dbt, &error2, NULL, ^bool(const SecDbAttr *attr) { + return CFDictionaryGetValue(q->q_item, attr->name); + }, NULL, NULL, ^(SecDbItemRef item, bool *stop) { + CFErrorRef error3 = NULL; + secinfo("InitialSyncItems", "Copy item"); + + CFMutableDictionaryRef attrs = SecDbItemCopyPListWithMask(item, kSecDbSyncFlag, &error3); + if (attrs) { + int match = true; + CFStringRef vwht = CFDictionaryGetValue(attrs, kSecAttrSyncViewHint); + /* + * Saying its a SOS viewhint is really not the right answer post Triangle + */ + if (isString(vwht) && !SOSViewInSOSSystem(vwht)) { + match = false; + } + /* + * Here we encode how PCS stores identities so that we only copy the + * current identites for performance reasons. + */ + if (limitToCurrent) { + enum { PCS_CURRENT_IDENTITY_OFFSET = 0x10000 }; + int32_t s32; + + CFNumberRef type = CFDictionaryGetValue(attrs, kSecAttrType); + if (!isNumber(type)) { + // still allow this case since its not a service identity ?? + } else if (!CFNumberGetValue(type, kCFNumberSInt32Type, &s32)) { + match = false; + } else if ((s32 & PCS_CURRENT_IDENTITY_OFFSET) == 0) { + match = false; + } + } + if (match) { + CFDictionaryAddValue(attrs, kSecClass, SecDbItemGetClass(item)->name); + CFArrayAppendValue(items, attrs); + } + + CFReleaseNull(attrs); + } + CFReleaseNull(error3); + }); + CFReleaseNull(error2); + + return (bool)true; + }); + }); + +fail: + if (q) + query_destroy(q, NULL); + return result; +} + +CFArrayRef +_SecServerCopyInitialSyncCredentials(uint32_t flags, CFErrorRef *error) +{ + CFMutableArrayRef items = CFArrayCreateMutableForCFTypes(NULL); + + if (flags & SecServerInitialSyncCredentialFlagTLK) { + require_action(InitialSyncItems(items, false, CFSTR("com.apple.security.ckks"), inet_class(), error), fail, + secerror("failed to collect PCS-inet keys: %@", error ? *error : NULL)); + } + if (flags & SecServerInitialSyncCredentialFlagPCS) { + bool onlyCurrent = !(flags & SecServerInitialSyncCredentialFlagPCSNonCurrent); + + require_action(InitialSyncItems(items, false, CFSTR("com.apple.ProtectedCloudStorage"), genp_class(), error), fail, + secerror("failed to collect PCS-inet keys: %@", error ? *error : NULL)); + require_action(InitialSyncItems(items, onlyCurrent, CFSTR("com.apple.ProtectedCloudStorage"), inet_class(), error), fail, + secerror("failed to collect PCS-inet keys: %@", error ? *error : NULL)); + } + +fail: + return items; +} + +bool +_SecServerImportInitialSyncCredentials(CFArrayRef array, CFErrorRef *error) +{ + return kc_with_dbt(true, error, ^bool(SecDbConnectionRef dbt) { + return kc_transaction(dbt, error, ^bool(void){ + CFIndex n, count = CFArrayGetCount(array); + + secinfo("ImportInitialSyncItems", "Importing %d items", (int)count); + + for (n = 0; n < count; n++) { + CFErrorRef cferror = NULL; + + CFDictionaryRef item = CFArrayGetValueAtIndex(array, n); + if (!isDictionary(item)) + continue; + + CFStringRef className = CFDictionaryGetValue(item, kSecClass); + if (className == NULL) { + secinfo("ImportInitialSyncItems", "Item w/o class"); + continue; + } + + const SecDbClass *cls = kc_class_with_name(className); + if (cls == NULL) { + secinfo("ImportInitialSyncItems", "Item with unknown class: %@", className); + continue; + } + + SecDbItemRef dbi = SecDbItemCreateWithAttributes(NULL, cls, item, KEYBAG_DEVICE, &cferror); + if (dbi == NULL) { + secinfo("ImportInitialSyncItems", "Item creation failed with: %@", cferror); + CFReleaseNull(cferror); + continue; + } + + if (!SecDbItemSetSyncable(dbi, true, &cferror)) { + secinfo("ImportInitialSyncItems", "Failed to set sync=1: %@ for item %@", cferror, dbi); + CFReleaseNull(cferror); + CFReleaseNull(dbi); + continue; + } + + if (!SecDbItemInsert(dbi, dbt, &cferror)) { + secinfo("ImportInitialSyncItems", "Item store failed with: %@: %@", cferror, dbi); + CFReleaseNull(cferror); + } + CFReleaseNull(dbi); + } + return true; + }); + }); +} + + + #if TARGET_OS_IOS /* @@ -3067,21 +3466,21 @@ _SecServerTransmogrifyToSyncBubble(CFArrayRef services, uid_t uid, SecurityClien * The actually copy/delete the items selected */ - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyPCS, &inet_class, PCSItems, sizeof(PCSItems)/sizeof(PCSItems[0]), error); + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyPCS, inet_class(), PCSItems, sizeof(PCSItems)/sizeof(PCSItems[0]), error); require(res, fail); - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyPCS, &genp_class, PCSItems, sizeof(PCSItems)/sizeof(PCSItems[0]), error); + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyPCS, genp_class(), PCSItems, sizeof(PCSItems)/sizeof(PCSItems[0]), error); require(res, fail); /* mail */ - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyMobileMail, &genp_class, MobileMailItems, sizeof(MobileMailItems)/sizeof(MobileMailItems[0]), error); + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyMobileMail, genp_class(), MobileMailItems, sizeof(MobileMailItems)/sizeof(MobileMailItems[0]), error); require(res, fail); /* accountsd */ - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyCloudAuthToken, &genp_class, AccountsdItems, sizeof(AccountsdItems)/sizeof(AccountsdItems[0]), error); + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyCloudAuthToken, genp_class(), AccountsdItems, sizeof(AccountsdItems)/sizeof(AccountsdItems[0]), error); require(res, fail); /* nsurlsessiond */ - res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyNSURLSesssion, &inet_class, NSURLSesssiond, sizeof(NSURLSesssiond)/sizeof(NSURLSesssiond[0]), error); + res = TransmogrifyItemsToSyncBubble(client, uid, onlyDelete, copyNSURLSesssion, inet_class(), NSURLSesssiond, sizeof(NSURLSesssiond)/sizeof(NSURLSesssiond[0]), error); require(res, fail); fail: @@ -3106,15 +3505,16 @@ _SecServerTransmogrifyToSystemKeychain(SecurityClient *client, CFErrorRef *error return kc_transaction(dbt, error, ^{ CFDataRef systemUUID = SecMUSRGetSystemKeychainUUID(); - const SecDbSchema *newSchema = kc_schemas[0]; + const SecDbSchema *newSchema = current_schema(); SecDbClass const *const *kcClass; for (kcClass = newSchema->classes; *kcClass != NULL; kcClass++) { CFErrorRef localError = NULL; Query *q = NULL; - if (*kcClass == &tversion_class || *kcClass == &identity_class) + if (!((*kcClass)->itemclass)) { continue; + } q = query_create(*kcClass, SecMUSRGetSingleUserKeychainUUID(), NULL, error); if (q == NULL) @@ -3250,3 +3650,63 @@ fail: query_destroy(q, NULL); return res; } + +CFArrayRef _SecItemCopyParentCertificates(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error) { + const void *keys[] = { + kSecClass, + kSecReturnData, + kSecMatchLimit, + kSecAttrSubject + }, + *values[] = { + kSecClassCertificate, + kCFBooleanTrue, + kSecMatchLimitAll, + normalizedIssuer + }; + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, + NULL, NULL); + CFTypeRef results = NULL; + SecurityClient client = { + .task = NULL, + .accessGroups = accessGroups, + .allowSystemKeychain = true, + .allowSyncBubbleKeychain = false, + .isNetworkExtension = false, + }; + + (void)_SecItemCopyMatching(query, &client, &results, error); + CFRelease(query); + return results; +} + +bool _SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error) { + const void *keys[] = { + kSecClass, + kSecMatchLimit, + kSecAttrIssuer, + kSecAttrSerialNumber + }, + *values[] = { + kSecClassCertificate, + kSecMatchLimitOne, + normalizedIssuer, + serialNumber + }; + SecurityClient client = { + .task = NULL, + .accessGroups = accessGroups, + .allowSystemKeychain = true, + .allowSyncBubbleKeychain = false, + .isNetworkExtension = false, + }; + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, NULL, NULL); + CFTypeRef results = NULL; + bool ok = _SecItemCopyMatching(query, &client, &results, error); + CFReleaseSafe(query); + CFReleaseSafe(results); + if (!ok) { + return false; + } + return true; +} diff --git a/OSX/sec/securityd/SecItemServer.h b/OSX/sec/securityd/SecItemServer.h index 4c1a5ce2..3249d8da 100644 --- a/OSX/sec/securityd/SecItemServer.h +++ b/OSX/sec/securityd/SecItemServer.h @@ -35,7 +35,7 @@ #include #include #include -#include "securityd_client.h" +#include "sec/ipc/securityd_client.h" __BEGIN_DECLS @@ -53,6 +53,9 @@ CFDataRef _SecServerKeychainCreateBackup(SecurityClient *client, CFDataRef keyba bool _SecServerKeychainRestore(CFDataRef backup, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error); 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); CF_RETURNS_RETAINED CFArrayRef _SecServerKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error); @@ -67,7 +70,9 @@ bool _SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataR bool _SecServerTransmogrifyToSystemKeychain(SecurityClient *client, CFErrorRef *error); bool _SecServerTransmogrifyToSyncBubble(CFArrayRef services, uid_t uid, SecurityClient *client, CFErrorRef *error); bool _SecServerDeleteMUSERViews(SecurityClient *client, uid_t uid, CFErrorRef *error); +#endif +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE 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 */ @@ -75,10 +80,10 @@ bool _SecCopySharedWebCredential(CFDictionaryRef query, SecurityClient *client, // Hack to log objects from inside SOS code void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object); -SecDbRef SecKeychainDbCreate(CFStringRef path); +SecDbRef SecKeychainDbCreate(CFStringRef path, CFErrorRef* error); +SecDbRef SecKeychainDbInitialize(SecDbRef db); -void -_SecServerDatabaseSetup(void); +bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt)); /* For whitebox testing only */ @@ -99,6 +104,15 @@ CFStringRef __SecKeychainCopyPath(void); bool _SecServerRollKeys(bool force, SecurityClient *client, CFErrorRef *error); bool _SecServerRollKeysGlue(bool force, CFErrorRef *error); + +/* initial sync */ +#define SecServerInitialSyncCredentialFlagTLK 1 +#define SecServerInitialSyncCredentialFlagPCS 2 +#define SecServerInitialSyncCredentialFlagPCSNonCurrent 4 + +CFArrayRef _SecServerCopyInitialSyncCredentials(uint32_t flags, CFErrorRef *error); +bool _SecServerImportInitialSyncCredentials(CFArrayRef array, CFErrorRef *error); + struct _SecServerKeyStats { unsigned long items; CFIndex maxDataSize; @@ -107,11 +121,13 @@ struct _SecServerKeyStats { bool _SecServerGetKeyStats(const SecDbClass *qclass, struct _SecServerKeyStats *stats); - +CF_RETURNS_RETAINED CFArrayRef _SecItemCopyParentCertificates(CFDataRef normalizedIssuer, CFArrayRef accessGroups, CFErrorRef *error); +bool _SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error); // Should all be blocks called from SecItemDb bool match_item(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFDictionaryRef item); +bool accessGroupsAllows(CFArrayRef accessGroups, CFStringRef accessGroup, SecurityClient* client); bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups); void SecKeychainChanged(void); diff --git a/OSX/sec/securityd/SecKeybagSupport.c b/OSX/sec/securityd/SecKeybagSupport.c index 45797da4..d20ea19f 100644 --- a/OSX/sec/securityd/SecKeybagSupport.c +++ b/OSX/sec/securityd/SecKeybagSupport.c @@ -41,6 +41,8 @@ #if TARGET_OS_EMBEDDED #include #endif +#else /* !USE_KEYSTORE */ +#include #endif /* USE_KEYSTORE */ #include @@ -100,7 +102,7 @@ static bool hwaes_key_available(void) /* TODO: Remove this once the kext runs the daemon on demand if there is no system keybag. */ int kb_state = MKBGetDeviceLockState(NULL); - asl_log(NULL, NULL, ASL_LEVEL_INFO, "AppleKeyStore lock state: %d", kb_state); + secinfo("aks", "AppleKeyStore lock state: %d", kb_state); #endif } return true; @@ -137,11 +139,13 @@ bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag, if ((kernResult == kIOReturnNotPermitted) || (kernResult == kIOReturnNotPrivileged)) { const char *substatus = ""; if (keyclass == key_class_ck || keyclass == key_class_cku) - substatus = " (hiberation ?)"; + substatus = " (hibernation?)"; /* Access to item attempted while keychain is locked. */ return SecError(errSecInteractionNotAllowed, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Access to item attempted while keychain is locked%s."), kernResult, operation, keyclass, keybag, substatus); - } else if (kernResult == kIOReturnError) { + } else if (kernResult == kIOReturnNotFound) { + return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), kernResult, operation, keyclass, keybag); + } else if (kernResult == kIOReturnError || kernResult == kAKSReturnDecodeError) { /* Item can't be decrypted on this device, ever, so drop the item. */ return SecError(errSecDecode, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), kernResult, operation, keyclass, keybag); @@ -154,6 +158,7 @@ bool ks_crypt(CFTypeRef operation, keybag_handle_t keybag, CFDataSetLength(dest, dest_len); return true; #else /* !USE_KEYSTORE */ + uint32_t dest_len = (uint32_t)CFDataGetLength(dest); if (CFEqual(operation, kAKSKeyOpEncrypt)) { /* The no encryption case. */ @@ -280,7 +285,8 @@ static bool create_cferror_from_aks(int aks_return, CFTypeRef operation, keybag_ aks_return, operation_string, keyclass, keybag); } else if (aks_return == kAKSReturnPolicyError || aks_return == kAKSReturnBadPassword) { if (aks_return == kAKSReturnBadPassword) { - ACMContextRef acm_context_ref = ACMContextCreateWithExternalForm(CFDataGetBytePtr(acm_context_data), CFDataGetLength(acm_context_data)); + ACMContextRef acm_context_ref = NULL; + acm_context_ref = ACMContextCreateWithExternalForm(CFDataGetBytePtr(acm_context_data), CFDataGetLength(acm_context_data)); if (acm_context_ref) { ACMContextRemovePassphraseCredentialsByPurposeAndScope(acm_context_ref, kACMPassphrasePurposeGeneral, kACMScopeContext); ACMContextDelete(acm_context_ref, false); @@ -289,10 +295,13 @@ static bool create_cferror_from_aks(int aks_return, CFTypeRef operation, keybag_ /* Item needed authentication. */ ks_access_control_needed_error(error, access_control_data, operation); - } else if (aks_return == kAKSReturnError || aks_return == kAKSReturnPolicyInvalid) { + } else if (aks_return == kAKSReturnError || aks_return == kAKSReturnPolicyInvalid || aks_return == kAKSReturnDecodeError) { /* Item can't be decrypted on this device, ever, so drop the item. */ SecError(errSecDecode, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32") Item can't be decrypted on this device, ever, so drop the item."), aks_return, operation_string, keyclass, keybag); + + } else if (aks_return == kIOReturnNotFound) { + return SecError(errSecNotAvailable, error, CFSTR("ks_crypt: %x failed to '%@' item (class %"PRId32", bag: %"PRId32") No key available for class."), aks_return, operation, keyclass, keybag); } else { SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (class %"PRId32", bag: %"PRId32")"), aks_return, operation_string, keyclass, keybag); @@ -439,9 +448,9 @@ bool use_hwaes(void) { dispatch_once(&check_once, ^{ use_hwaes = hwaes_key_available(); if (use_hwaes) { - asl_log(NULL, NULL, ASL_LEVEL_INFO, "using hwaes key"); + secinfo("aks", "using hwaes key"); } else { - asl_log(NULL, NULL, ASL_LEVEL_ERR, "unable to access hwaes key"); + secerror("unable to access hwaes key"); } }); return use_hwaes; diff --git a/OSX/sec/securityd/SecLogSettingsServer.c b/OSX/sec/securityd/SecLogSettingsServer.m similarity index 88% rename from OSX/sec/securityd/SecLogSettingsServer.c rename to OSX/sec/securityd/SecLogSettingsServer.m index 14883efc..c4c02dc4 100644 --- a/OSX/sec/securityd/SecLogSettingsServer.c +++ b/OSX/sec/securityd/SecLogSettingsServer.m @@ -5,7 +5,7 @@ // #include -#include +#import #include #include #include @@ -40,9 +40,10 @@ bool SecSetCircleLogSettings_Server(CFTypeRef type, CFErrorRef* error) { bool success = false; - SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); + SOSAccount* account = (__bridge SOSAccount*)SOSKeychainAccountGetSharedAccount(); if (account) { success = SOSAccountPostDebugScope(account, type, error); } return success; } + diff --git a/OSX/sec/securityd/SecOCSPCache.c b/OSX/sec/securityd/SecOCSPCache.c index 6f856097..7e109eaf 100644 --- a/OSX/sec/securityd/SecOCSPCache.c +++ b/OSX/sec/securityd/SecOCSPCache.c @@ -64,7 +64,7 @@ // MARK: SecOCSPCacheDb static SecDbRef SecOCSPCacheDbCreate(CFStringRef path) { - return SecDbCreate(path, ^bool (SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { + return SecDbCreate(path, ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { __block bool ok; ok = (SecDbExec(dbconn, CFSTR("PRAGMA auto_vacuum = FULL"), error) && SecDbExec(dbconn, CFSTR("PRAGMA journal_mode = WAL"), error)); @@ -135,10 +135,15 @@ errOut: static CFStringRef SecOCSPCacheCopyPath(void) { CFStringRef ocspRelPath = kSecOCSPCacheFileName; +#if TARGET_OS_IPHONE CFURLRef ocspURL = SecCopyURLForFileInKeychainDirectory(ocspRelPath); if (!ocspURL) { ocspURL = SecCopyURLForFileInUserCacheDirectory(ocspRelPath); } +#else + /* macOS caches should be in user cache dir */ + CFURLRef ocspURL = SecCopyURLForFileInUserCacheDirectory(ocspRelPath); +#endif CFStringRef ocspPath = NULL; if (ocspURL) { ocspPath = CFURLCopyFileSystemPath(ocspURL, kCFURLPOSIXPathStyle); @@ -285,6 +290,15 @@ static void _SecOCSPCacheReplaceResponse(SecOCSPCacheRef this, }); if (!ok) { secerror("_SecOCSPCacheAddResponse failed: %@", localError); + CFReleaseNull(localError); + } else { + // force a vacuum when we modify the database + ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok = SecDbExec(dbconn, CFSTR("VACUUM"), &localError); + if (!ok) { + secerror("_SecOCSPCacheAddResponse VACUUM failed: %@", localError); + } + }); } CFReleaseSafe(localError); } diff --git a/OSX/sec/securityd/SecOCSPRequest.c b/OSX/sec/securityd/SecOCSPRequest.c index a9260be9..c9add9ad 100644 --- a/OSX/sec/securityd/SecOCSPRequest.c +++ b/OSX/sec/securityd/SecOCSPRequest.c @@ -148,6 +148,7 @@ errOut: } CFDataRef SecOCSPRequestGetDER(SecOCSPRequestRef this) { + if (!this) { return NULL; } CFDataRef der = this->der; if (!der) { this->der = der = _SecOCSPRequestCopyDEREncoding(this); diff --git a/OSX/sec/securityd/SecOCSPResponse.c b/OSX/sec/securityd/SecOCSPResponse.c index 3fcc3698..784c65df 100644 --- a/OSX/sec/securityd/SecOCSPResponse.c +++ b/OSX/sec/securityd/SecOCSPResponse.c @@ -220,7 +220,7 @@ bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this, CFStringRef hexResp = CFDataCopyHexString(this->data); if (this->producedAt > verifyTime + LEEWAY) { - ocspdErrorLog("OCSPResponse: producedAt more than 1:15 from now %@", hexResp); + secnotice("ocsp", "OCSPResponse: producedAt more than 1:15 from now"); goto exit; } @@ -233,7 +233,7 @@ bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this, /* thisUpdate later than 'now' invalidates the whole response. */ CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); if (thisUpdate > verifyTime + LEEWAY) { - ocspdErrorLog("OCSPResponse: thisUpdate more than 1:15 from now %@", hexResp); + secnotice("ocsp","OCSPResponse: thisUpdate more than 1:15 from now"); goto exit; } @@ -250,7 +250,7 @@ bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this, response caching. See Section 6 for additional information on caching. */ - ocspdErrorLog("OCSPResponse: nextUpdate not present %@", hexResp); + secnotice("ocsp", "OCSPResponse: nextUpdate not present"); #ifdef STRICT_RFC5019 goto exit; #endif @@ -294,7 +294,7 @@ bool SecOCSPResponseCalculateValidity(SecOCSPResponseRef this, /* Absolute expire time = current time plus defaultTTL */ this->expireTime = verifyTime + defaultTTL; } else if (this->latestNextUpdate < verifyTime - LEEWAY) { - ocspdErrorLog("OCSPResponse: latestNextUpdate more than 1:15 ago %@", hexResp); + secnotice("ocsp", "OCSPResponse: latestNextUpdate more than 1:15 ago"); goto exit; } else if (maxAge > 0) { /* Beware of double overflows such as: @@ -343,12 +343,12 @@ SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t r resp.Data = (uint8_t *)CFDataGetBytePtr(ocspResponse); if (SecAsn1DecodeData(this->coder, &resp, kSecAsn1OCSPResponseTemplate, &topResp)) { - ocspdErrorLog("OCSPResponse: decode failure at top level %@", hexResp); + ocspdErrorLog("OCSPResponse: decode failure at top level"); } /* remainder is valid only on RS_Success */ if ((topResp.responseStatus.Data == NULL) || (topResp.responseStatus.Length == 0)) { - ocspdErrorLog("OCSPResponse: no responseStatus %@", hexResp); + ocspdErrorLog("OCSPResponse: no responseStatus"); goto errOut; } this->responseStatus = topResp.responseStatus.Data[0]; @@ -360,12 +360,12 @@ SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t r } if (topResp.responseBytes == NULL) { /* I don't see how this can be legal on RS_Success */ - ocspdErrorLog("OCSPResponse: empty responseBytes %@", hexResp); + ocspdErrorLog("OCSPResponse: empty responseBytes"); goto errOut; } if (!SecAsn1OidCompare(&topResp.responseBytes->responseType, &OID_PKIX_OCSP_BASIC)) { - ocspdErrorLog("OCSPResponse: unknown responseType %@", hexResp); + ocspdErrorLog("OCSPResponse: unknown responseType"); goto errOut; } @@ -373,7 +373,7 @@ SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t r /* decode the SecAsn1OCSPBasicResponse */ if (SecAsn1DecodeData(this->coder, &topResp.responseBytes->response, kSecAsn1OCSPBasicResponseTemplate, &this->basicResponse)) { - ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse %@", hexResp); + ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse"); goto errOut; } @@ -382,17 +382,17 @@ SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t r /* decode the SecAsn1OCSPResponseData */ if (SecAsn1DecodeData(this->coder, &this->basicResponse.tbsResponseData, kSecAsn1OCSPResponseDataTemplate, &this->responseData)) { - ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData %@", hexResp); + ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData"); goto errOut; } this->producedAt = genTimeToCFAbsTime(&this->responseData.producedAt); if (this->producedAt == NULL_TIME) { - ocspdErrorLog("OCSPResponse: bad producedAt %@", hexResp); + ocspdErrorLog("OCSPResponse: bad producedAt"); goto errOut; } if (this->responseData.responderID.Data == NULL) { - ocspdErrorLog("OCSPResponse: bad responderID %@", hexResp); + ocspdErrorLog("OCSPResponse: bad responderID"); goto errOut; } @@ -410,12 +410,12 @@ SecOCSPResponseRef SecOCSPResponseCreateWithID(CFDataRef ocspResponse, int64_t r templ = kSecAsn1OCSPResponderIDAsKeyTemplate; break; default: - ocspdErrorLog("OCSPResponse: bad responderID tag %@", hexResp); + ocspdErrorLog("OCSPResponse: bad responderID tag"); goto errOut; } if (SecAsn1DecodeData(this->coder, &this->responseData.responderID, templ, &this->responderID)) { - ocspdErrorLog("OCSPResponse: decode failure at responderID %@", hexResp); + ocspdErrorLog("OCSPResponse: decode failure at responderID"); goto errOut; } @@ -423,6 +423,7 @@ fini: CFReleaseSafe(hexResp); return this; errOut: + secdebug("ocsp", "bad ocsp response: %@", hexResp); CFReleaseSafe(hexResp); if (this) { SecOCSPResponseFinalize(this); @@ -518,6 +519,7 @@ SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse( SecOCSPResponseRef this, SecOCSPRequestRef request) { SecOCSPSingleResponseRef sr = NULL; + if (!request) { return sr; } CFDataRef issuer = SecCertificateCopyIssuerSequence(request->certificate); const DERItem *publicKey = SecCertificateGetPublicKeyData(request->issuer); #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) @@ -532,10 +534,10 @@ SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse( SecAsn1OCSPSingleResponse **responses; for (responses = this->responseData.responses; *responses; ++responses) { - SecAsn1OCSPSingleResponse *resp = *responses; + SecAsn1OCSPSingleResponse *resp = *responses; SecAsn1OCSPCertID *certId = &resp->certID; /* First check the easy part, serial number should match. */ - if (certId->serialNumber.Length != (size_t)CFDataGetLength(serial) || + if (!serial || certId->serialNumber.Length != (size_t)CFDataGetLength(serial) || memcmp(CFDataGetBytePtr(serial), certId->serialNumber.Data, certId->serialNumber.Length)) { /* Serial # mismatch, skip this singleResponse. */ @@ -581,7 +583,7 @@ SecOCSPSingleResponseRef SecOCSPResponseCopySingleResponse( } } - } + } CFReleaseSafe(issuerPubKeyHash); CFReleaseSafe(issuerNameHash); diff --git a/OSX/sec/securityd/SecOTRRemote.c b/OSX/sec/securityd/SecOTRRemote.m similarity index 72% rename from OSX/sec/securityd/SecOTRRemote.c rename to OSX/sec/securityd/SecOTRRemote.m index ba67c259..683ec8a6 100644 --- a/OSX/sec/securityd/SecOTRRemote.c +++ b/OSX/sec/securityd/SecOTRRemote.m @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ - +#include "AssertMacros.h" #include #include "SecOTRRemote.h" #include @@ -29,14 +29,15 @@ #include #include - #include "SOSAccountPriv.h" +#import "Security/SecureObjectSync/SOSAccountTrustClassic.h" + CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFDataRef publicPeerId, CFDataRef privateAccountData, CFErrorRef *error) { SOSDataSourceFactoryRef ds = SecItemDataSourceFactoryGetDefault(); - SOSAccountRef privateAccount = NULL; - SOSAccountRef publicAccount = NULL; + SOSAccount* privateAccount = NULL; + SOSAccount* publicAccount = NULL; CFStringRef publicKeyString = NULL; SecKeyRef privateKeyRef = NULL; SecKeyRef publicKeyRef = NULL; @@ -47,31 +48,59 @@ CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFData require_quiet(ds, fail); require_quiet(publicPeerId, fail); - privateAccount = (privateAccountData == NULL) ? CFRetainSafe(SOSKeychainAccountGetSharedAccount()) : SOSAccountCreateFromData(kCFAllocatorDefault, privateAccountData, ds, error); + + if (privateAccountData) { + NSError* ns_error = nil; + privateAccount = [SOSAccount accountFromData:(__bridge NSData*) privateAccountData factory:ds error:&ns_error]; + if (error && *error == NULL && !privateAccount) { + *error = (CFErrorRef) CFBridgingRetain(ns_error); + } + } else { + privateAccount = (__bridge SOSAccount*)(SOSKeychainAccountGetSharedAccount()); + } + require_quiet(privateAccount, fail); privateKeyRef = SOSAccountCopyDeviceKey(privateAccount, error); require_quiet(privateKeyRef, fail); - CFReleaseNull(privateAccount); privateIdentity = SecOTRFullIdentityCreateFromSecKeyRef(kCFAllocatorDefault, privateKeyRef, error); require_quiet(privateIdentity, fail); CFReleaseNull(privateKeyRef); - publicKeyString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, publicPeerId, kCFStringEncodingUTF8); require_quiet(publicKeyString, fail); + if (publicAccountData) { + NSError* ns_error = nil; + publicAccount = [SOSAccount accountFromData:(__bridge NSData*) publicAccountData factory:ds error:&ns_error]; + if (error && *error == NULL && !publicAccount) { + *error = (CFErrorRef) CFBridgingRetain(ns_error); + } + } else { + publicAccount = (__bridge SOSAccount*)(SOSKeychainAccountGetSharedAccount()); + } - publicAccount = (publicAccountData == NULL) ? CFRetainSafe(SOSKeychainAccountGetSharedAccount()) : SOSAccountCreateFromData(kCFAllocatorDefault, publicAccountData, ds, error); require_quiet(publicAccount, fail); - publicKeyRef = SOSAccountCopyPublicKeyForPeer(publicAccount, publicKeyString, error); - require_quiet(publicKeyRef, fail); - CFReleaseNull(publicAccount); - + publicKeyRef = [publicAccount.trust copyPublicKeyForPeer:publicKeyString err:error]; + + if(!publicKeyRef){ + if(!ds){ + CFReleaseNull(ourSession); + CFReleaseNull(publicKeyString); + privateAccount= nil; + publicAccount = nil; + CFReleaseNull(privateKeyRef); + CFReleaseNull(publicKeyRef); + CFReleaseNull(publicIdentity); + CFReleaseNull(privateIdentity); + return result; + } + } publicIdentity = SecOTRPublicIdentityCreateFromSecKeyRef(kCFAllocatorDefault, publicKeyRef, error); require_quiet(publicIdentity, fail); + CFReleaseNull(publicKeyRef); ourSession = SecOTRSessionCreateFromID(kCFAllocatorDefault, privateIdentity, publicIdentity); @@ -85,13 +114,12 @@ CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFData fail: CFReleaseNull(ourSession); CFReleaseNull(publicKeyString); - CFReleaseNull(privateAccount); - CFReleaseNull(publicAccount); + privateAccount= nil; + publicAccount = nil; CFReleaseNull(privateKeyRef); CFReleaseNull(publicKeyRef); CFReleaseNull(publicIdentity); CFReleaseNull(privateIdentity); - return result; } diff --git a/OSX/utilities/src/SecCertificateTrace.h b/OSX/sec/securityd/SecPinningDb.h similarity index 55% rename from OSX/utilities/src/SecCertificateTrace.h rename to OSX/sec/securityd/SecPinningDb.h index f90ef641..42b1ddcd 100644 --- a/OSX/utilities/src/SecCertificateTrace.h +++ b/OSX/sec/securityd/SecPinningDb.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. + * 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, @@ -17,37 +17,38 @@ * 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@ + * */ -/* - * SecCertificateTrace.h - log statistics for Apple certificate usage +/*! + @header SecPinningDb + The functions in SecPinningDb.h provide an interface to look up + pinning rules based on hostname. */ -#ifndef _UTILITIES_SECCERTIFICATETRACE_H_ -#define _UTILITIES_SECCERTIFICATETRACE_H_ +#ifndef _SECURITY_SECPINNINGDB_H_ +#define _SECURITY_SECPINNINGDB_H_ #include __BEGIN_DECLS -/* top-level prefix string */ -extern const CFStringRef kCertStatsPrefix; +CF_ASSUME_NONNULL_BEGIN +CF_IMPLICIT_BRIDGING_ENABLED -/* certificate key */ -extern const CFStringRef kCertStatsCert; +extern const CFStringRef kSecPinningDbKeyHostname; +extern const CFStringRef kSecPinningDbKeyPolicyName; +extern const CFStringRef kSecPinningDbKeyRules; -/* keys for certificate field strings */ -extern const CFStringRef kCertStatsPolicy; -extern const CFStringRef kCertStatsNotBefore; -extern const CFStringRef kCertStatsNotAfter; -extern const CFStringRef kCertStatsSerialNumber; -extern const CFStringRef kCertStatsSubjectSummary; -extern const CFStringRef kCertStatsIssuerSummary; +CFDictionaryRef _Nullable SecPinningDbCopyMatching(CFDictionaryRef _Nonnull query); +void SecPinningDbInitialize(void); -bool SecCertificateTraceAddRecord(CFDictionaryRef certRecord); +CF_IMPLICIT_BRIDGING_DISABLED +CF_ASSUME_NONNULL_END __END_DECLS -#endif /* _UTILITIES_SECCERTIFICATETRACE_H_ */ + +#endif /* _SECURITY_SECPINNINGDB_H_ */ diff --git a/OSX/sec/securityd/SecPinningDb.m b/OSX/sec/securityd/SecPinningDb.m new file mode 100644 index 00000000..fd0531f5 --- /dev/null +++ b/OSX/sec/securityd/SecPinningDb.m @@ -0,0 +1,943 @@ +/* + * 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@ + * + */ + +/* + * SecPinningDb.m + */ + +#include +#import +#import +#import + +#if !TARGET_OS_BRIDGE +#import +#import +#endif + +#if TARGET_OS_OSX +#import +#endif + +#import + +#import +#import + +#include "utilities/debugging.h" +#include "utilities/sqlutils.h" +#include "utilities/iOSforOSX.h" +#include +#include +#include +#include +#include +#include "utilities/sec_action.h" + +#define kSecPinningBasePath "/Library/Keychains/" +#define kSecPinningDbFileName "pinningrules.sqlite3" + +const uint64_t PinningDbSchemaVersion = 2; +const NSString *PinningDbPolicyNameKey = @"policyName"; /* key for a string value */ +const NSString *PinningDbDomainsKey = @"domains"; /* key for an array of dictionaries */ +const NSString *PinningDbPoliciesKey = @"rules"; /* key for an array of dictionaries */ +const NSString *PinningDbDomainSuffixKey = @"suffix"; /* key for a string */ +const NSString *PinningDbLabelRegexKey = @"labelRegex"; /* key for a regex string */ + +const CFStringRef kSecPinningDbKeyHostname = CFSTR("PinningHostname"); +const CFStringRef kSecPinningDbKeyPolicyName = CFSTR("PinningPolicyName"); +const CFStringRef kSecPinningDbKeyRules = CFSTR("PinningRules"); + +#if !TARGET_OS_BRIDGE +const NSString *PinningDbMobileAssetType = @"com.apple.MobileAsset.CertificatePinning"; +#define kSecPinningDbMobileAssetNotification "com.apple.MobileAsset.CertificatePinning.cached-metadata-updated" +#endif + +#if TARGET_OS_OSX +const NSUInteger PinningDbMobileAssetCompatibilityVersion = 1; +#endif + +@interface SecPinningDb : NSObject +@property (assign) SecDbRef db; +@property dispatch_queue_t queue; +@property NSURL *dbPath; +- (instancetype) init; +- ( NSDictionary * _Nullable ) queryForDomain:(NSString *)domain; +- ( NSDictionary * _Nullable ) queryForPolicyName:(NSString *)policyName; +@end + +static bool isDbOwner() { +#ifdef NO_SERVER + // Test app running as securityd +#elif TARGET_OS_IPHONE + if (getuid() == 64) // _securityd +#else + if (getuid() == 0) +#endif + { + return true; + } + return false; +} + +static inline bool isNSNumber(id nsType) { + return nsType && [nsType isKindOfClass:[NSNumber class]]; +} + +static inline bool isNSArray(id nsType) { + return nsType && [nsType isKindOfClass:[NSArray class]]; +} + +static inline bool isNSDictionary(id nsType) { + return nsType && [nsType isKindOfClass:[NSDictionary class]]; +} + +@implementation SecPinningDb +#define getSchemaVersionSQL CFSTR("PRAGMA user_version") +#define selectVersionSQL CFSTR("SELECT ival FROM admin WHERE key='version'") +#define insertAdminSQL CFSTR("INSERT OR REPLACE INTO admin (key,ival,value) VALUES (?,?,?)") +#define selectDomainSQL CFSTR("SELECT DISTINCT labelRegex,policyName,policies FROM rules WHERE domainSuffix=?") +#define selectPolicyNameSQL CFSTR("SELECT DISTINCT policies FROM rules WHERE policyName=?") +#define insertRuleSQL CFSTR("INSERT OR REPLACE INTO rules (policyName,domainSuffix,labelRegex,policies) VALUES (?,?,?,?) ") +#define removeAllRulesSQL CFSTR("DELETE FROM rules;") + +- (NSNumber *)getSchemaVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block bool ok = true; + __block NSNumber *version = nil; + ok &= SecDbWithSQL(dbconn, getSchemaVersionSQL, error, ^bool(sqlite3_stmt *selectVersion) { + ok &= SecDbStep(dbconn, selectVersion, error, ^(bool *stop) { + int ival = sqlite3_column_int(selectVersion, 0); + version = [NSNumber numberWithInt:ival]; + }); + return ok; + }); + return version; +} + +- (BOOL)setSchemaVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + bool ok = true; + NSString *setVersion = [NSString stringWithFormat:@"PRAGMA user_version = %llu", PinningDbSchemaVersion]; + ok &= SecDbExec(dbconn, + (__bridge CFStringRef)setVersion, + error); + if (!ok) { + secerror("SecPinningDb: failed to create admin table: %@", error ? *error : nil); + } + return ok; +} + +- (NSNumber *)getContentVersion:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block bool ok = true; + __block NSNumber *version = nil; + ok &= SecDbWithSQL(dbconn, selectVersionSQL, error, ^bool(sqlite3_stmt *selectVersion) { + ok &= SecDbStep(dbconn, selectVersion, error, ^(bool *stop) { + uint64_t ival = sqlite3_column_int64(selectVersion, 0); + version = [NSNumber numberWithUnsignedLongLong:ival]; + }); + return ok; + }); + return version; +} + +- (BOOL)setContentVersion:(NSNumber *)version dbConnection:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block BOOL ok = true; + ok &= SecDbWithSQL(dbconn, insertAdminSQL, error, ^bool(sqlite3_stmt *insertAdmin) { + const char *versionKey = "version"; + ok &= SecDbBindText(insertAdmin, 1, versionKey, strlen(versionKey), SQLITE_TRANSIENT, error); + ok &= SecDbBindInt64(insertAdmin, 2, [version unsignedLongLongValue], error); + ok &= SecDbStep(dbconn, insertAdmin, error, NULL); + return ok; + }); + if (!ok) { + secerror("SecPinningDb: failed to set version %@ from pinning list: %@", version, error ? *error : nil); + } + return ok; +} + +- (BOOL) shouldUpdateContent:(NSNumber *)new_version { + __block CFErrorRef error = NULL; + __block BOOL ok = YES; + __block BOOL newer = NO; + ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { + NSNumber *db_version = [self getContentVersion:dbconn error:&error]; + if (!db_version || [new_version compare:db_version] == NSOrderedDescending) { + newer = YES; + secnotice("pinningDb", "Pinning database should update from version %@ to version %@", db_version, new_version); + } + }); + + if (!ok || error) { + secerror("SecPinningDb: error reading content version from database %@", error); + } + CFReleaseNull(error); + return newer; +} + +- (BOOL) insertRuleWithName:(NSString *)policyName + domainSuffix:(NSString *)domainSuffix + labelRegex:(NSString *)labelRegex + policies:(NSArray *)policies + dbConnection:(SecDbConnectionRef)dbconn + error:(CFErrorRef *)error{ + /* @@@ This insertion mechanism assumes that the input is trusted -- namely, that the new rules + * are allowed to replace existing rules. For third-party inputs, this assumption isn't true. */ + + secdebug("pinningDb", "inserting new rule: %@ for %@.%@", policyName, labelRegex, domainSuffix); + + __block bool ok = true; + ok &= SecDbWithSQL(dbconn, insertRuleSQL, error, ^bool(sqlite3_stmt *insertRule) { + ok &= SecDbBindText(insertRule, 1, [policyName UTF8String], [policyName length], SQLITE_TRANSIENT, error); + ok &= SecDbBindText(insertRule, 2, [domainSuffix UTF8String], [domainSuffix length], SQLITE_TRANSIENT, error); + ok &= SecDbBindText(insertRule, 3, [labelRegex UTF8String], [labelRegex length], SQLITE_TRANSIENT, error); + NSData *xmlPolicies = [NSPropertyListSerialization dataWithPropertyList:policies + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:nil]; + if (!xmlPolicies) { + secerror("SecPinningDb: failed to serialize policies"); + ok = false; + } + ok &= SecDbBindBlob(insertRule, 4, [xmlPolicies bytes], [xmlPolicies length], SQLITE_TRANSIENT, error); + ok &= SecDbStep(dbconn, insertRule, error, NULL); + return ok; + }); + if (!ok) { + secerror("SecPinningDb: failed to insert rule %@ for %@.%@ with error %@", policyName, labelRegex, domainSuffix, error ? *error : nil); + } + return ok; +} + +- (BOOL) populateDbFromBundle:(NSArray *)pinningList dbConnection:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block BOOL ok = true; + [pinningList enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if (idx ==0) { return; } // Skip the first value which is the version + if (!isNSDictionary(obj)) { + secerror("SecPinningDb: rule entry in pinning plist is wrong class"); + ok = false; + return; + } + NSDictionary *rule = obj; + __block NSString *policyName = [rule objectForKey:PinningDbPolicyNameKey]; + NSArray *domains = [rule objectForKey:PinningDbDomainsKey]; + __block NSArray *policies = [rule objectForKey:PinningDbPoliciesKey]; + + if (!policyName || !domains || !policies) { + secerror("SecPinningDb: failed to get required fields from rule entry %lu", (unsigned long)idx); + ok = false; + return; + } + + [domains enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if (!isNSDictionary(obj)) { + secerror("SecPinningDb: domain entry %lu for %@ in pinning rule is wrong class", (unsigned long)idx, policyName); + ok = false; + return; + } + NSDictionary *domain = obj; + NSString *suffix = [domain objectForKey:PinningDbDomainSuffixKey]; + NSString *labelRegex = [domain objectForKey:PinningDbLabelRegexKey]; + + if (!suffix || !labelRegex) { + secerror("SecPinningDb: failed to get required fields for entry %lu for %@", (unsigned long)idx, policyName); + ok = false; + return; + } + ok &= [self insertRuleWithName:policyName domainSuffix:suffix labelRegex:labelRegex policies:policies + dbConnection:dbconn error:error]; + }]; + }]; + if (!ok) { + secerror("SecPinningDb: failed to populate DB from pinning list: %@", error ? *error : nil); + } + return ok; +} + +- (BOOL) removeAllRulesFromDb:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + __block BOOL ok = true; + ok &= SecDbWithSQL(dbconn, removeAllRulesSQL, error, ^bool(sqlite3_stmt *deleteRules) { + ok &= SecDbStep(dbconn, deleteRules, error, NULL); + return ok; + }); + if (!ok) { + secerror("SecPinningDb: failed to delete old values: %@", error ? *error :nil); + } + return ok; +} + + +- (BOOL) createOrAlterAdminTable:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + bool ok = true; + ok &= SecDbExec(dbconn, + CFSTR("CREATE TABLE IF NOT EXISTS admin(" + "key TEXT PRIMARY KEY NOT NULL," + "ival INTEGER NOT NULL," + "value BLOB" + ");"), + error); + if (!ok) { + secerror("SecPinningDb: failed to create admin table: %@", error ? *error : nil); + } + return ok; +} + +- (BOOL) createOrAlterRulesTable:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error { + bool ok = true; + ok &= SecDbExec(dbconn, + CFSTR("CREATE TABLE IF NOT EXISTS rules(" + "policyName TEXT NOT NULL," + "domainSuffix TEXT NOT NULL," + "labelRegex TEXT NOT NULL," + "policies BLOB NOT NULL," + "UNIQUE(policyName, domainSuffix, labelRegex)" + ");"), + error); + ok &= SecDbExec(dbconn, CFSTR("CREATE INDEX IF NOT EXISTS idomain ON rules(domainSuffix);"), error); + ok &= SecDbExec(dbconn, CFSTR("CREATE INDEX IF NOT EXISTS ipolicy ON rules(policyName);"), error); + if (!ok) { + secerror("SecPinningDb: failed to create rules table: %@", error ? *error : nil); + } + return ok; +} + +#if !TARGET_OS_BRIDGE +- (BOOL) installDbFromURL:(NSURL *)localURL { + if (!localURL) { + secerror("SecPinningDb: missing url for downloaded asset"); + return NO; + } + NSURL* basePath = nil, *fileLoc = nil; + if (![localURL scheme]) { + /* MobileAsset provides the URL without the scheme. Fix it up. */ + NSString *pathWithScheme = [[NSString alloc] initWithFormat:@"%@",localURL]; + basePath = [NSURL fileURLWithPath:pathWithScheme isDirectory:YES]; + } else { + basePath = localURL; + } + fileLoc = [NSURL URLWithString:@"CertificatePinning.plist" + relativeToURL:basePath]; + __block NSArray *pinningList = [NSArray arrayWithContentsOfURL:fileLoc]; + if (!pinningList) { + secerror("SecPinningDb: unable to create pinning list from asset file: %@", fileLoc); + return NO; + } + + NSNumber *plist_version = [pinningList objectAtIndex:0]; + if (![self shouldUpdateContent:plist_version]) { + /* We got a new plist but we already have that version installed. */ + return YES; + } + + /* Update Content */ + __block CFErrorRef error = NULL; + __block BOOL ok = YES; + ok &= SecDbPerformWrite(_db, &error, ^(SecDbConnectionRef dbconn) { + ok &= [self updateDb:dbconn error:&error pinningList:pinningList updateSchema:NO updateContent:YES]; + }); + + if (error) { + secerror("SecPinningDb: error installing updated pinning list version %@: %@", [pinningList objectAtIndex:0], error); + CFReleaseNull(error); + } + + return ok; +} + +#if TARGET_OS_OSX +const CFStringRef kSecSUPrefDomain = CFSTR("com.apple.SoftwareUpdate"); +const CFStringRef kSecSUScanPrefConfigDataInstallKey = CFSTR("ConfigDataInstall"); +#endif + +static BOOL PinningDbCanCheckMobileAsset(void) { + BOOL result = YES; +#if TARGET_OS_OSX + /* Check the user's SU preferences to determine if "Install system data files" is off */ + if (!CFPreferencesSynchronize(kSecSUPrefDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost)) { + secerror("SecPinningDb: unable to synchronize SoftwareUpdate prefs"); + return NO; + } + + id value = nil; + if (CFPreferencesAppValueIsForced(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain)) { + value = CFBridgingRelease(CFPreferencesCopyAppValue(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain)); + } else { + value = CFBridgingRelease(CFPreferencesCopyValue(kSecSUScanPrefConfigDataInstallKey, kSecSUPrefDomain, + kCFPreferencesAnyUser, kCFPreferencesCurrentHost)); + } + if (isNSNumber(value)) { + result = [value boolValue]; + } + + if (!result) { secnotice("pinningDb", "User has disabled system data installation."); } + + /* MobileAsset.framework isn't mastered into the BaseSystem. Check that the MA classes are linked. */ + if (![ASAssetQuery class] || ![ASAsset class] || ![MAAssetQuery class] || ![MAAsset class]) { + secnotice("PinningDb", "Weak linked MobileAsset framework missing."); + result = NO; + } +#endif + return result; +} + +#if TARGET_OS_IPHONE +- (void) downloadPinningAsset:(BOOL __unused)isLocalOnly { + if (!PinningDbCanCheckMobileAsset()) { + secnotice("pinningDb", "MobileAsset disabled, skipping check."); + return; + } + + secnotice("pinningDb", "begin MobileAsset query for catalog"); + [MAAsset startCatalogDownload:(NSString *)PinningDbMobileAssetType then:^(MADownLoadResult result) { + if (result != MADownloadSucceesful) { + secerror("SecPinningDb: failed to download catalog: %ld", (long)result); + return; + } + MAAssetQuery *query = [[MAAssetQuery alloc] initWithType:(NSString *)PinningDbMobileAssetType]; + [query augmentResultsWithState:true]; + + secnotice("pinningDb", "begin MobileAsset metadata sync request"); + MAQueryResult queryResult = [query queryMetaDataSync]; + if (queryResult != MAQuerySucceesful) { + secerror("SecPinningDb: failed to query MobileAsset metadata: %ld", (long)queryResult); + return; + } + + if (!query.results) { + secerror("SecPinningDb: no results in MobileAsset query"); + return; + } + + for (MAAsset *asset in query.results) { + NSNumber *asset_version = [asset assetProperty:@"_ContentVersion"]; + if (![self shouldUpdateContent:asset_version]) { + secdebug("pinningDb", "skipping asset because we already have _ContentVersion %@", asset_version); + continue; + } + switch(asset.state) { + default: + secerror("SecPinningDb: unknown asset state %ld", (long)asset.state); + continue; + case MAInstalled: + /* The asset is already in the cache, get it from disk. */ + secdebug("pinningDb", "CertificatePinning asset already installed"); + if([self installDbFromURL:[asset getLocalUrl]]) { + secnotice("pinningDb", "finished db update from installed asset. purging asset."); + [asset purge:^(MAPurgeResult purge_result) { + if (purge_result != MAPurgeSucceeded) { + secerror("SecPinningDb: purge failed: %ld", (long)purge_result); + } + }]; + } + break; + case MAUnknown: + secerror("SecPinningDb: pinning asset is unknown"); + continue; + case MADownloading: + secnotice("pinningDb", "pinning asset is downloading"); + /* fall through */ + case MANotPresent: + secnotice("pinningDb", "begin download of CertificatePinning asset"); + [asset startDownload:^(MADownLoadResult downloadResult) { + if (downloadResult != MADownloadSucceesful) { + secerror("SecPinningDb: failed to download pinning asset: %ld", (long)downloadResult); + return; + } + if([self installDbFromURL:[asset getLocalUrl]]) { + secnotice("pinningDb", "finished db update from installed asset. purging asset."); + [asset purge:^(MAPurgeResult purge_result) { + if (purge_result != MAPurgeSucceeded) { + secerror("SecPinningDb: purge failed: %ld", (long)purge_result); + } + }]; + } + }]; + break; + } + } + }]; +} +#else /* !TARGET_OS_IPHONE */ +/* MobileAssetV2 fails on macOS, so use V1 */ +- (void) downloadPinningAsset:(BOOL)isLocalOnly { + if (!PinningDbCanCheckMobileAsset()) { + secnotice("pinningDb", "MobileAsset disabled, skipping check."); + return; + } + + ASAssetQuery *query = [[ASAssetQuery alloc] initWithAssetType:(NSString *)PinningDbMobileAssetType]; + [query setQueriesLocalAssetInformationOnly:isLocalOnly]; // Omitting this leads to a notifcation loop. + NSError *error = nil; + NSArray*query_results = [query runQueryAndReturnError:&error]; + if (!query_results) { + secerror("SecPinningDb: asset query failed: %@", error); + return; + } + + for (ASAsset *asset in query_results) { + NSDictionary *attributes = [asset attributes]; + + NSNumber *compatibilityVersion = [attributes objectForKey:ASAttributeCompatibilityVersion]; + if (!isNSNumber(compatibilityVersion) || + [compatibilityVersion unsignedIntegerValue] != PinningDbMobileAssetCompatibilityVersion) { + secnotice("pinningDb", "Skipping asset with compatibility version %@", compatibilityVersion); + continue; + } + + NSNumber *contentVersion = [attributes objectForKey:ASAttributeContentVersion]; + if (!isNSNumber(contentVersion) || ![self shouldUpdateContent:contentVersion]) { + secnotice("pinningDb", "Skipping asset with content version %@", contentVersion); + continue; + } + + ASProgressHandler pinningHandler = ^(NSDictionary *state, NSError *progressError){ + if (progressError) { + secerror("SecPinningDb: asset download error: %@", progressError); + return; + } + + if (!state) { + secerror("SecPinningDb: no asset state in progress handler"); + return; + } + + NSString *operationState = [state objectForKey:ASStateOperation]; + secdebug("pinningDb", "Asset state is %@", operationState); + + if (operationState && [operationState isEqualToString:ASOperationCompleted]) { + if ([self installDbFromURL:[asset localURL]]) { + secnotice("pinningDb", "finished db update from installed asset. purging asset."); + [asset purge:^(NSError *error) { + if (error) { + secerror("SecPinningDb: purge failed %@", error); + } + }]; + } + } + }; + + switch ([asset state]) { + case ASAssetStateNotPresent: + secdebug("pinningDb", "CertificatePinning asset needs to be downloaded"); + asset.progressHandler= pinningHandler; + asset.userInitiatedDownload = YES; + [asset beginDownloadWithOptions:@{ASDownloadOptionPriority : ASDownloadPriorityNormal}]; + break; + case ASAssetStateInstalled: + /* The asset is already in the cache, get it from disk. */ + secdebug("pinningDb", "CertificatePinning asset already installed"); + if([self installDbFromURL:[asset localURL]]) { + secnotice("pinningDb", "finished db update from installed asset. purging asset."); + [asset purge:^(NSError *error) { + if (error) { + secerror("SecPinningDb: purge failed %@", error); + } + }]; + } + break; + case ASAssetStatePaused: + secdebug("pinningDb", "CertificatePinning asset download paused"); + asset.progressHandler = pinningHandler; + asset.userInitiatedDownload = YES; + if (![asset resumeDownloadAndReturnError:&error]) { + secerror("SecPinningDb: failed to resume download of asset: %@", error); + } + break; + case ASAssetStateDownloading: + secdebug("pinningDb", "CertificatePinning asset downloading"); + asset.progressHandler = pinningHandler; + asset.userInitiatedDownload = YES; + break; + default: + secerror("SecPinningDb: unhandled asset state %ld", (long)asset.state); + continue; + } + } +} +#endif /* !TARGET_OS_IPHONE */ + +- (void) downloadPinningAsset { + [self downloadPinningAsset:NO]; +} +#endif /* !TARGET_OS_BRIDGE */ + +- (NSArray *) copyCurrentPinningList { + NSArray *pinningList = nil; + /* Get the pinning list shipped with the OS */ + SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); + if (otapkiref) { + pinningList = CFBridgingRelease(SecOTAPKICopyPinningList(otapkiref)); + CFReleaseNull(otapkiref); + if (!pinningList) { + secerror("SecPinningDb: failed to read pinning plist from bundle"); + } + } + +#if !TARGET_OS_BRIDGE + /* Asynchronously ask MobileAsset for most recent pinning list. */ + dispatch_async(_queue, ^{ + secnotice("pinningDb", "Initial check with MobileAsset for newer pinning asset"); + [self downloadPinningAsset]; + }); + + /* Register for changes in our asset */ + if (PinningDbCanCheckMobileAsset()) { + int out_token = 0; + notify_register_dispatch(kSecPinningDbMobileAssetNotification, &out_token, self->_queue, ^(int __unused token) { + secnotice("pinningDb", "Got a notification about a new pinning asset."); + [self downloadPinningAsset:YES]; + }); + } +#endif + + return pinningList; +} + +- (BOOL) updateDb:(SecDbConnectionRef)dbconn error:(CFErrorRef *)error pinningList:(NSArray *)pinningList + updateSchema:(BOOL)updateSchema updateContent:(BOOL)updateContent +{ + if (!isDbOwner()) { return false; } + secdebug("pinningDb", "updating or creating database"); + + __block bool ok = true; + ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) { + if (updateSchema) { + /* update the tables */ + ok &= [self createOrAlterAdminTable:dbconn error:error]; + ok &= [self createOrAlterRulesTable:dbconn error:error]; + ok &= [self setSchemaVersion:dbconn error:error]; + } + + if (updateContent) { + /* remove the old data */ + /* @@@ This behavior assumes that we have all the rules we want to populate + * elsewhere on disk and that the DB doesn't contain the sole copy of that data. */ + ok &= [self removeAllRulesFromDb:dbconn error:error]; + + /* read the new data */ + NSNumber *version = [pinningList objectAtIndex:0]; + + /* populate the tables */ + ok &= [self populateDbFromBundle:pinningList dbConnection:dbconn error:error]; + ok &= [self setContentVersion:version dbConnection:dbconn error:error]; + } + + *commit = ok; + }); + + return ok; +} + +- (SecDbRef) createAtPath { + bool readWrite = isDbOwner(); + mode_t mode = 0644; + + CFStringRef path = CFStringCreateWithCString(NULL, [_dbPath fileSystemRepresentation], kCFStringEncodingUTF8); + SecDbRef result = SecDbCreateWithOptions(path, mode, readWrite, false, false, + ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { + if (!isDbOwner()) { + /* Non-owner process can't update the db, but it should get a db connection. + * @@@ Revisit if new schema version is needed by reader processes. */ + return true; + } + + __block BOOL ok = true; + dispatch_sync(self->_queue, ^{ + bool updateSchema = false; + bool updateContent = false; + + /* Get the pinning plist */ + NSArray *pinningList = [self copyCurrentPinningList]; + if (!pinningList) { + secerror("SecPinningDb: failed to find pinning plist in bundle"); + ok = false; + return; + } + + /* Check latest data and schema versions against existing table. */ + if (!isNSNumber([pinningList objectAtIndex:0])) { + secerror("SecPinningDb: pinning plist in wrong format"); + return; // Don't change status. We can continue to use old DB. + } + NSNumber *plist_version = [pinningList objectAtIndex:0]; + NSNumber *db_version = [self getContentVersion:dbconn error:error]; + if (!db_version || [plist_version compare:db_version] == NSOrderedDescending) { + secnotice("pinningDb", "Updating pinning database content from version %@ to version %@", + db_version ? db_version : 0, plist_version); + updateContent = true; + } + NSNumber *schema_version = [self getSchemaVersion:dbconn error:error]; + NSNumber *current_version = [NSNumber numberWithUnsignedLongLong:PinningDbSchemaVersion]; + if (!schema_version || ![schema_version isEqualToNumber:current_version]) { + secnotice("pinningDb", "Updating pinning database schema from version %@ to version %@", + schema_version, current_version); + updateSchema = true; + } + + if (updateContent || updateSchema) { + ok &= [self updateDb:dbconn error:error pinningList:pinningList updateSchema:updateSchema updateContent:updateContent]; + } + if (!ok) { + secerror("SecPinningDb: %s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL); + } + }); + return ok; + }); + + CFReleaseNull(path); + return result; +} + +static void verify_create_path(const char *path) +{ + int ret = mkpath_np(path, 0755); + if (!(ret == 0 || ret == EEXIST)) { + secerror("could not create path: %s (%s)", path, strerror(ret)); + } +} + +- (NSURL *)pinningDbPath { + /* Make sure the /Library/Keychains directory is there */ +#if TARGET_OS_IPHONE + NSURL *directory = CFBridgingRelease(SecCopyURLForFileInKeychainDirectory(nil)); +#else + NSURL *directory = [NSURL fileURLWithFileSystemRepresentation:"/Library/Keychains/" isDirectory:YES relativeToURL:nil]; +#endif + verify_create_path([directory fileSystemRepresentation]); + + /* Get the full path of the pinning DB */ + return [directory URLByAppendingPathComponent:@"pinningrules.sqlite3"]; +} + +- (void) initializedDb { + dispatch_sync(_queue, ^{ + if (!self->_db) { + self->_dbPath = [self pinningDbPath]; + self->_db = [self createAtPath]; + } + }); +} + +- (instancetype) init { + if (self = [super init]) { + _queue = dispatch_queue_create("Pinning DB Queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + [self initializedDb]; + } + return self; +} + +- (void) dealloc { + CFReleaseNull(_db); +} + +- (BOOL) isPinningDisabled:(NSString * _Nullable)policy { + static dispatch_once_t once; + static sec_action_t action; + + BOOL pinningDisabled = NO; + if (SecIsInternalRelease()) { + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + pinningDisabled = [defaults boolForKey:@"AppleServerAuthenticationNoPinning"]; + if (!pinningDisabled && policy) { + NSMutableString *policySpecificKey = [NSMutableString stringWithString:@"AppleServerAuthenticationNoPinning"]; + [policySpecificKey appendString:policy]; + pinningDisabled = [defaults boolForKey:policySpecificKey]; + secinfo("pinningQA", "%@ disable pinning = %d", policy, pinningDisabled); + } + } + + dispatch_once(&once, ^{ + /* Only log system-wide pinning status once a minute */ + action = sec_action_create("pinning logging charles", 60.0); + sec_action_set_handler(action, ^{ + if (!SecIsInternalRelease()) { + secnotice("pinningQA", "could not disable pinning: not an internal release"); + } else { + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + secnotice("pinningQA", "generic pinning disable = %d", [defaults boolForKey:@"AppleServerAuthenticationNoPinning"]); + } + }); + }); + sec_action_perform(action); + + return pinningDisabled; +} + +- ( NSDictionary * _Nullable ) queryForDomain:(NSString *)domain { + if (!_queue) { (void)[self init]; } + if (!_db) { [self initializedDb]; } + + /* Check for general no-pinning setting */ + if ([self isPinningDisabled:nil]) { + return nil; + } + + /* parse the domain into suffix and 1st label */ + NSRange firstDot = [domain rangeOfString:@"."]; + if (firstDot.location == NSNotFound) { return nil; } // Probably not a legitimate domain name + __block NSString *firstLabel = [domain substringToIndex:firstDot.location]; + __block NSString *suffix = [domain substringFromIndex:(firstDot.location + 1)]; + + /* Perform SELECT */ + __block bool ok = true; + __block CFErrorRef error = NULL; + __block NSMutableArray *resultRules = [NSMutableArray array]; + __block NSString *resultName = nil; + ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { + ok &= SecDbWithSQL(dbconn, selectDomainSQL, &error, ^bool(sqlite3_stmt *selectDomain) { + ok &= SecDbBindText(selectDomain, 1, [suffix UTF8String], [suffix length], SQLITE_TRANSIENT, &error); + ok &= SecDbStep(dbconn, selectDomain, &error, ^(bool *stop) { + /* Match the labelRegex */ + const uint8_t *regex = sqlite3_column_text(selectDomain, 0); + if (!regex) { return; } + NSString *regexStr = [NSString stringWithUTF8String:(const char *)regex]; + if (!regexStr) { return; } + NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:regexStr + options:NSRegularExpressionCaseInsensitive + error:nil]; + if (!regularExpression) { return; } + NSUInteger numMatches = [regularExpression numberOfMatchesInString:firstLabel + options:0 + range:NSMakeRange(0, [firstLabel length])]; + if (numMatches == 0) { + return; + } + secdebug("SecPinningDb", "found matching rule for %@.%@", firstLabel, suffix); + + /* Check the policyName for no-pinning settings */ + const uint8_t *policyName = sqlite3_column_text(selectDomain, 1); + NSString *policyNameStr = [NSString stringWithUTF8String:(const char *)policyName]; + if ([self isPinningDisabled:policyNameStr]) { + return; + } + + /* Deserialize the policies and return. + * @@@ Assumes there is only one rule with matching suffix/label pairs. */ + NSData *xmlPolicies = [NSData dataWithBytes:sqlite3_column_blob(selectDomain, 2) length:sqlite3_column_bytes(selectDomain, 2)]; + if (!xmlPolicies) { return; } + id policies = [NSPropertyListSerialization propertyListWithData:xmlPolicies options:0 format:nil error:nil]; + if (!isNSArray(policies)) { + return; + } + [resultRules addObjectsFromArray:(NSArray *)policies]; + resultName = policyNameStr; + }); + return ok; + }); + }); + + if (error) { + secerror("SecPinningDb: error querying DB for hostname: %@", error); + CFReleaseNull(error); + } + + if ([resultRules count] > 0) { + NSDictionary *results = @{(__bridge NSString*)kSecPinningDbKeyRules:resultRules, + (__bridge NSString*)kSecPinningDbKeyPolicyName:resultName}; + return results; + } + return nil; +} + +- (NSDictionary * _Nullable) queryForPolicyName:(NSString *)policyName { + if (!_queue) { (void)[self init]; } + if (!_db) { [self initializedDb]; } + + /* Skip the "sslServer" policyName, which is not a pinning policy */ + if ([policyName isEqualToString:@"sslServer"]) { + return nil; + } + + /* Check for general no-pinning setting */ + if ([self isPinningDisabled:nil] || [self isPinningDisabled:policyName]) { + return nil; + } + + /* Perform SELECT */ + __block bool ok = true; + __block CFErrorRef error = NULL; + __block NSMutableArray *resultRules = [NSMutableArray array]; + ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) { + ok &= SecDbWithSQL(dbconn, selectPolicyNameSQL, &error, ^bool(sqlite3_stmt *selectPolicyName) { + ok &= SecDbBindText(selectPolicyName, 1, [policyName UTF8String], [policyName length], SQLITE_TRANSIENT, &error); + ok &= SecDbStep(dbconn, selectPolicyName, &error, ^(bool *stop) { + secdebug("SecPinningDb", "found matching rule for %@ policy", policyName); + + /* Deserialize the policies and return */ + NSData *xmlPolicies = [NSData dataWithBytes:sqlite3_column_blob(selectPolicyName, 0) length:sqlite3_column_bytes(selectPolicyName, 0)]; + if (!xmlPolicies) { return; } + id policies = [NSPropertyListSerialization propertyListWithData:xmlPolicies options:0 format:nil error:nil]; + if (!isNSArray(policies)) { + return; + } + [resultRules addObjectsFromArray:(NSArray *)policies]; + }); + return ok; + }); + }); + + if (error) { + secerror("SecPinningDb: error querying DB for policyName: %@", error); + CFReleaseNull(error); + } + + if ([resultRules count] > 0) { + NSDictionary *results = @{(__bridge NSString*)kSecPinningDbKeyRules:resultRules, + (__bridge NSString*)kSecPinningDbKeyPolicyName:policyName}; + return results; + } + return nil; +} + +@end + +static SecPinningDb *pinningDb = nil; +void SecPinningDbInitialize(void) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + pinningDb = [[SecPinningDb alloc] init]; + __block CFErrorRef error = NULL; + BOOL ok = SecDbPerformRead([pinningDb db], &error, ^(SecDbConnectionRef dbconn) { + NSNumber *contentVersion = [pinningDb getContentVersion:dbconn error:&error]; + NSNumber *schemaVersion = [pinningDb getSchemaVersion:dbconn error:&error]; + secinfo("pinningDb", "Database Schema: %@ Content: %@", schemaVersion, contentVersion); + }); + if (!ok || error) { + secerror("SecPinningDb: unable to initialize db: %@", error); + } + CFReleaseNull(error); + }); +} + +CFDictionaryRef _Nullable SecPinningDbCopyMatching(CFDictionaryRef query) { + SecPinningDbInitialize(); + + NSDictionary *nsQuery = (__bridge NSDictionary*)query; + NSString *hostname = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyHostname]; + + NSDictionary *results = [pinningDb queryForDomain:hostname]; + if (results) { return CFBridgingRetain(results); } + NSString *policyName = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyPolicyName]; + results = [pinningDb queryForPolicyName:policyName]; + if (!results) { return nil; } + return CFBridgingRetain(results); +} diff --git a/OSX/sec/securityd/SecPolicyServer.c b/OSX/sec/securityd/SecPolicyServer.c index 0ccb00ac..56d212ce 100644 --- a/OSX/sec/securityd/SecPolicyServer.c +++ b/OSX/sec/securityd/SecPolicyServer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2008-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,14 +22,13 @@ */ /* - * SecPolicyServer.c - Trust policies dealing with certificate revocation. + * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies. */ #include #include #include #include -#include #include #include #include @@ -49,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -57,13 +57,12 @@ #include #include #include -#include -#include -#include #include -#include -#include #include +#include +#include +#include +#include #include #include #include @@ -98,6 +97,10 @@ static void secdumpdata(CFDataRef data, const char *name) { ****************** SecPolicy object ******************** ********************************************************/ +static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix); +static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc); +static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc); + static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL; static CFMutableDictionaryRef gSecPolicyPathCallbacks = NULL; @@ -135,7 +138,7 @@ static CFArrayRef SecPolicyAnchorDigestsForEVPolicy(const DERItem *policyOID) } -static bool SecPolicyIsEVPolicy(const DERItem *policyOID) { +bool SecPolicyIsEVPolicy(const DERItem *policyOID) { return SecPolicyAnchorDigestsForEVPolicy(policyOID); } @@ -255,114 +258,6 @@ notEV: return isEV; } -bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate) { - CFMutableDictionaryRef keySizes = NULL; - CFNumberRef rsaSize = NULL, ecSize = NULL; - bool isEV = false; - - /* 3. Subscriber Certificate. */ - - /* (a) certificate Policies */ - const SecCECertificatePolicies *cp; - cp = SecCertificateGetCertificatePolicies(certificate); - require_quiet(cp && cp->numPolicies > 0, notEV); - /* Now find at least one policy in here that has a qualifierID of id-qt 2 - and a policyQualifier that is a URI to the CPS and an EV policy OID. */ - uint32_t ix = 0; - bool found_ev_anchor_for_leaf_policy = false; - for (ix = 0; ix < cp->numPolicies; ++ix) { - if (SecPolicyIsEVPolicy(&cp->policies[ix].policyIdentifier)) { - found_ev_anchor_for_leaf_policy = true; - } - } - require_quiet(found_ev_anchor_for_leaf_policy, notEV); - - /* (b) cRLDistributionPoint - (c) authorityInformationAccess - BRv1.3.4: MUST be present with OCSP Responder unless stapled response. - */ - - /* (d) basicConstraints - If present, the cA field MUST be set false. */ - const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(certificate); - if (bc) { - require_action_quiet(bc->isCA == false, notEV, - secnotice("ev", "Leaf has invalid basic constraints")); - } - - /* (e) keyUsage. */ - SecKeyUsage ku = SecCertificateGetKeyUsage(certificate); - if (ku) { - require_action_quiet((ku & (kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign)) == 0, notEV, - secnotice("ev", "Leaf has invalid key usage %u", ku)); - } - -#if 0 - /* The EV Cert Spec errata specifies this, though this is a check for SSL - not specifically EV. */ - - /* (e) extKeyUsage - -Either the value id-kp-serverAuth [RFC5280] or id-kp-clientAuth [RFC5280] or both values MUST be present. Other values SHOULD NOT be present. */ - SecCertificateCopyExtendedKeyUsage(certificate); -#endif - - /* 6.1.5 Key Sizes */ - CFAbsoluteTime jan2014 = 410227200; - require_quiet(ecSize = CFNumberCreateWithCFIndex(NULL, 256), notEV); - require_quiet(keySizes = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeEC, ecSize); - if (SecCertificateNotValidBefore(certificate) < jan2014) { - /* At least RSA 1024 or ECC NIST P-256. */ - require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 1024), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); - require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, - secnotice("ev", "Leaf's public key is too small for issuance before 2014")); - } else { - /* At least RSA 2028 or ECC NIST P-256. */ - require_quiet(rsaSize = CFNumberCreateWithCFIndex(NULL, 2048), notEV); - CFDictionaryAddValue(keySizes, kSecAttrKeyTypeRSA, rsaSize); - require_action_quiet(SecCertificateIsAtLeastMinKeySize(certificate, keySizes), notEV, - secnotice("ev", "Leaf's public key is too small for issuance after 2013")); - } - - /* 6.3.2 Validity Periods */ - CFAbsoluteTime jul2016 = 489024000; - CFAbsoluteTime notAfter = SecCertificateNotValidAfter(certificate); - CFAbsoluteTime notBefore = SecCertificateNotValidBefore(certificate); - if (SecCertificateNotValidBefore(certificate) < jul2016) { - /* Validity Period no greater than 60 months. - 60 months is no more than 5 years and 2 leap days. */ - CFAbsoluteTime maxPeriod = 60*60*24*(365*5+2); - require_action_quiet(notAfter - notBefore <= maxPeriod, notEV, - secnotice("ev", "Leaf's validity period is more than 60 months")); - } else { - /* Validity Period no greater than 39 months. - 39 months is no more than 3 years, 2 31-day months, - 1 30-day month, and 1 leap day */ - CFAbsoluteTime maxPeriod = 60*60*24*(365*3+2*31+30+1); - require_action_quiet(notAfter - notBefore <= maxPeriod, notEV, - secnotice("ev", "Leaf has validity period longer than 39 months and issued after 30 June 2016")); - } - - /* 7.1.3 Algorithm Object Identifiers */ - CFAbsoluteTime jan2016 = 473299200; - if (SecCertificateNotValidBefore(certificate) > jan2016) { - /* SHA-2 only */ - require_action_quiet(SecCertificateGetSignatureHashAlgorithm(certificate) > kSecSignatureHashAlgorithmSHA1, - notEV, secnotice("ev", "Leaf was issued with SHA-1 after 2015")); - } - - isEV = true; - -notEV: - CFReleaseNull(rsaSize); - CFReleaseNull(ecSize); - CFReleaseNull(keySizes); - return isEV; -} - /******************************************************** **************** SecPolicy Callbacks ******************* ********************************************************/ @@ -490,25 +385,14 @@ static void SecPolicyCheckBasicConstraints(SecPVCRef pvc, static void SecPolicyCheckNonEmptySubject(SecPVCRef pvc, CFStringRef key) { CFIndex ix, count = SecPVCGetCertificateCount(pvc); + SecPolicyRef policy = SecPVCGetPolicy(pvc); + CFTypeRef pvcValue = CFDictionaryGetValue(policy->_options, key); for (ix = 0; ix < count; ++ix) { SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - /* If the certificate has a subject, or - if it doesn't, and it's the leaf and not self signed, - and also has a critical subjectAltName extension it's valid. */ - if (!SecCertificateHasSubject(cert)) { - if (ix == 0 && count > 1) { - if (!SecCertificateHasCriticalSubjectAltName(cert)) { - /* Leaf certificate with empty subject does not have - a critical subject alt name extension. */ - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - } else { - /* CA certificate has empty subject. */ - if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) - return; - } - } + if (!SecPolicyCheckCertNonEmptySubject(cert, pvcValue)) { + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) + return; + } } } @@ -516,116 +400,6 @@ static void SecPolicyCheckQualifiedCertStatements(SecPVCRef pvc, CFStringRef key) { } -/* Compare hostname suffix to domain name. - This function does not process wildcards, and allows hostname to match - any subdomain level of the provided domain. - - To match, the last domain length chars of hostname must equal domain, - and the character immediately preceding domain in hostname (if any) - must be a dot. This means that domain 'bar.com' will match hostname - values 'host.bar.com' or 'host.sub.bar.com', but not 'host.foobar.com'. - - Characters in each string are converted to lowercase for the comparison. - Trailing '.' characters in both names will be ignored. - - Returns true on match, else false. - */ -static bool SecDomainSuffixMatch(CFStringRef hostname, CFStringRef domain) { - CFStringInlineBuffer hbuf = {}, dbuf = {}; - UniChar hch, dch; - CFIndex hix, dix, - hlength = CFStringGetLength(hostname), - dlength = CFStringGetLength(domain); - CFRange hrange = { 0, hlength }, drange = { 0, dlength }; - CFStringInitInlineBuffer(hostname, &hbuf, hrange); - CFStringInitInlineBuffer(domain, &dbuf, drange); - - if((hlength == 0) || (dlength == 0)) { - /* trivial case with at least one empty name */ - return (hlength == dlength) ? true : false; - } - - /* trim off trailing dots */ - hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hlength-1); - dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dlength-1); - if(hch == '.') { - hrange.length = --hlength; - } - if(dch == '.') { - drange.length = --dlength; - } - - /* trim off leading dot in suffix, if present */ - dch = CFStringGetCharacterFromInlineBuffer(&dbuf, 0); - if((dlength > 0) && (dch == '.')) { - drange.location++; - drange.length = --dlength; - } - - if(hlength < dlength) { - return false; - } - - /* perform case-insensitive comparison of domain suffix */ - for (hix = (hlength-dlength), - dix = drange.location; dix < drange.length; dix++) { - hch = CFStringGetCharacterFromInlineBuffer(&hbuf, hix); - dch = CFStringGetCharacterFromInlineBuffer(&dbuf, dix); - if (towlower(hch) != towlower(dch)) { - return false; - } - } - - /* require a dot prior to domain suffix, unless hostname == domain */ - if(hlength > dlength) { - hch = CFStringGetCharacterFromInlineBuffer(&hbuf, (hlength-(dlength+1))); - if(hch != '.') { - return false; - } - } - - return true; -} - -#define kSecPolicySHA1Size 20 -static const UInt8 kAppleCorpCASHA1[kSecPolicySHA1Size] = { - 0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1, - 0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE -}; - -/* Check whether hostname is in a particular set of allowed domains. - Returns true if OK, false if not allowed. - */ -static bool SecPolicyCheckDomain(SecPVCRef pvc, CFStringRef hostname) -{ - CFIndex count = SecPVCGetCertificateCount(pvc); - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); - CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert); - - /* is this chain anchored by kAppleCorpCASHA1? */ - CFDataRef corpSHA1 = CFDataCreateWithBytesNoCopy(NULL, - kAppleCorpCASHA1, kSecPolicySHA1Size, kCFAllocatorNull); - bool isCorpSHA1 = (corpSHA1 && CFEqual(anchorSHA1, corpSHA1)); - CFReleaseSafe(corpSHA1); - if (isCorpSHA1) { - /* limit hostname to specified domains */ - const CFStringRef dnlist[] = { - CFSTR("apple.com"), - CFSTR("icloud.com"), - }; - unsigned int idx, dncount=2; - for (idx = 0; idx < dncount; idx++) { - if (SecDomainSuffixMatch(hostname, dnlist[idx])) { - return true; - } - } - return false; - } - /* %%% other CA pinning checks TBA */ - - return true; -} - /* AUDIT[securityd](done): policy->_options is a caller provided dictionary, only its cf type has been checked. @@ -650,16 +424,6 @@ static void SecPolicyCheckSSLHostname(SecPVCRef pvc, /* Hostname mismatch or no hostnames found in certificate. */ SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); } - else if (!SecPolicyCheckDomain(pvc, hostName)) { - /* Hostname match, but domain not allowed for this CA */ - SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); - } - - if ((dnsMatch || pvc->details) - && SecPolicySubscriberCertificateCouldBeEV(leaf)) { - secdebug("policy", "enabling optionally_ev"); - pvc->optionally_ev = true; - } } @@ -935,15 +699,8 @@ static void SecPolicyCheckAnchorApple(SecPVCRef pvc, CFStringRef key) { CFIndex count = SecPVCGetCertificateCount(pvc); SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1); - SecPolicyRef policy = SecPVCGetPolicy(pvc); - CFTypeRef value = CFDictionaryGetValue(policy->_options, key); SecAppleTrustAnchorFlags flags = 0; - if (isDictionary(value)) { - if (CFDictionaryGetValue(value, kSecPolicyAppleAnchorIncludeTestRoots)) { - flags |= kSecAppleTrustAnchorFlagsIncludeTestAnchors; - } - } bool foundMatch = SecIsAppleTrustAnchor(cert, flags); @@ -1079,6 +836,7 @@ static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc, serial_ptr, sizeof(*UTN_USERFirst_Hardware_Serial))) { SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + pvc->result = kSecTrustResultFatalTrustFailure; CFReleaseSafe(serial); return; } @@ -1103,6 +861,7 @@ static void SecPolicyCheckBlackListedLeaf(SecPVCRef pvc, if (CFSetContainsValue(blackListedKeys, dgst)) { SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + pvc->result = kSecTrustResultFatalTrustFailure; } CFRelease(dgst); } @@ -1235,127 +994,6 @@ static void SecPolicyCheckIntermediateCountry(SecPVCRef pvc, CFStringRef key) } } -/* Returns true if path is on the allow list for the authority key of the - certificate at certix, false otherwise. - */ -static bool SecPVCCheckCertificateAllowList(SecPVCRef pvc, CFIndex certix) -{ - bool result = false; - CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc); - CFStringRef authKey = NULL; - CFArrayRef allowedCerts = NULL; - SecOTAPKIRef otapkiRef = NULL; - - if (certix < 0 || certix >= count) { - return result; - } - - //get authKeyID from the specified cert in the chain - SecCertificateRef issuedCert = SecPVCGetCertificateAtIndex(pvc, certix); - CFDataRef authKeyID = SecCertificateGetAuthorityKeyID(issuedCert); - if (NULL == authKeyID) { - return result; - } - authKey = CFDataCopyHexString(authKeyID); - if (NULL == authKey) { - goto errout; - } - - otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); - if (NULL == otapkiRef) { - goto errout; - } - - allowedCerts = SecOTAPKICopyAllowListForAuthKeyID(otapkiRef, authKey); - if (NULL == allowedCerts || !CFArrayGetCount(allowedCerts)) { - goto errout; - } - - //search sorted array for the SHA256 hash of a cert in the chain - CFRange range = CFRangeMake(0, CFArrayGetCount(allowedCerts)); - for (ix = 0; ix <= certix; ix++) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - if (!cert) { - goto errout; - } - - CFDataRef certHash = SecCertificateCopySHA256Digest(cert); - if (!certHash) { - goto errout; - } - - CFIndex position = CFArrayBSearchValues(allowedCerts, range, certHash, - (CFComparatorFunction)CFDataCompare, NULL); - if (position < CFArrayGetCount(allowedCerts)) { - CFDataRef possibleMatch = CFArrayGetValueAtIndex(allowedCerts, position); - if (!CFDataCompare(certHash, possibleMatch)) { - //this cert is in the allowlist - result = true; - } - } - - CFRelease(certHash); - } - -errout: - CFReleaseNull(authKey); - CFReleaseNull(otapkiRef); - CFReleaseNull(allowedCerts); - return result; -} - -#define DCMP(_idx_) memcmp(data+(8*_idx_), digest, 8) - -/* Returns true if leaf is on the CT whitelist */ -static bool SecPVCCheckCTWhiteListedLeaf(SecPVCRef pvc) -{ - SecOTAPKIRef otapkiRef = NULL; - CFDataRef whiteList = NULL; - SecCertificateRef cert = NULL; - CFDataRef dgst = NULL; - bool result = false; - const uint8_t *digest = NULL; - const uint8_t *data = NULL; - require(otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(), out); - require(whiteList = SecOTAPKICopyCTWhiteList(otapkiRef), out); - require(cert = SecPVCGetCertificateAtIndex(pvc, 0), out); - require(dgst = SecCertificateCopySHA256Digest(cert), out); - - digest = CFDataGetBytePtr(dgst); - data = CFDataGetBytePtr(whiteList); - CFIndex l = 0; - CFIndex h = CFDataGetLength(whiteList)/8-1; - - if(DCMP(l)==0 || DCMP(h)==0) { - result = true; - goto out; - } - - if(DCMP(l)>0 || DCMP(h)<0) { - goto out; - } - - while((h-l)>1) { - CFIndex i = (h+l)/ - 2; - int s = DCMP(i); - if(s == 0) { - result = true; - goto out; - } else if(s < 0) { - l = i; - } else { - h = i; - } - } - -out: - CFReleaseSafe(dgst); - CFReleaseSafe(whiteList); - CFReleaseSafe(otapkiRef); - return result; -} - /**************************************************************************** *********************** New rfc5280 Chain Validation *********************** ****************************************************************************/ @@ -1363,216 +1001,56 @@ out: #define POLICY_MAPPING 1 #define POLICY_SUBTREES 1 -struct policy_tree_add_ctx { - oid_t p_oid; - policy_qualifier_t p_q; -}; - -/* For each node of depth i-1 in the valid_policy_tree where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ -static bool policy_tree_add_if_match(policy_tree_t node, void *ctx) { - struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; - policy_set_t policy_set; - for (policy_set = node->expected_policy_set; - policy_set; - policy_set = policy_set->oid_next) { - if (oid_equal(policy_set->oid, info->p_oid)) { - policy_tree_add_child(node, &info->p_oid, info->p_q); - return true; - } - } - return false; -} - -/* If the valid_policy_tree includes a node of depth i-1 with the valid_policy anyPolicy, generate a child node with the following values: set the valid_policy to P-OID, set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}. */ -static bool policy_tree_add_if_any(policy_tree_t node, void *ctx) { - struct policy_tree_add_ctx *info = (struct policy_tree_add_ctx *)ctx; - if (oid_equal(node->valid_policy, oidAnyPolicy)) { - policy_tree_add_child(node, &info->p_oid, info->p_q); - return true; - } - return false; -} - -/* Return true iff node has a child with a valid_policy equal to oid. */ -static bool policy_tree_has_child_with_oid(policy_tree_t node, - const oid_t *oid) { - policy_tree_t child; - for (child = node->children; child; child = child->siblings) { - if (oid_equal(child->valid_policy, (*oid))) { - return true; - } - } - return false; -} - -/* For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node, set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node. */ -static bool policy_tree_add_expected(policy_tree_t node, void *ctx) { - policy_qualifier_t p_q = (policy_qualifier_t)ctx; - policy_set_t policy_set; - bool added_node = false; - for (policy_set = node->expected_policy_set; - policy_set; - policy_set = policy_set->oid_next) { - if (!policy_tree_has_child_with_oid(node, &policy_set->oid)) { - policy_tree_add_child(node, &policy_set->oid, p_q); - added_node = true; - } - } - return added_node; -} - -#if POLICY_MAPPING -/* For each node where ID-P is the valid_policy, set expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ -static bool policy_tree_map_if_match(policy_tree_t node, void *ctx) { - /* Can't map oidAnyPolicy. */ - if (oid_equal(node->valid_policy, oidAnyPolicy)) - return false; - - const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; - size_t mapping_ix, mapping_count = pm->numMappings; - policy_set_t policy_set = NULL; - /* Generate the policy_set of sdps for matching idp */ - for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { - const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; - if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { - policy_set_t p_node = (policy_set_t)malloc(sizeof(*policy_set)); - p_node->oid = mapping->subjectDomainPolicy; - p_node->oid_next = policy_set ? policy_set : NULL; - policy_set = p_node; - } - } - if (policy_set) { - policy_tree_set_expected_policy(node, policy_set); - return true; - } - return false; -} - -/* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1 that has a valid_policy of anyPolicy as follows: - (i) set the valid_policy to ID-P; - (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i; and - (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ -static bool policy_tree_map_if_any(policy_tree_t node, void *ctx) { - if (!oid_equal(node->valid_policy, oidAnyPolicy)) { - return false; - } - - const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; - size_t mapping_ix, mapping_count = pm->numMappings; - CFMutableDictionaryRef mappings = NULL; - CFDataRef idp = NULL; - CFDataRef sdp = NULL; - require_quiet(mappings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks), - errOut); - /* First we need to walk the mappings to generate the dictionary idp->sdps */ - for (mapping_ix = 0; mapping_ix < mapping_count; mapping_ix++) { - oid_t issuerDomainPolicy = pm->mappings[mapping_ix].issuerDomainPolicy; - oid_t subjectDomainPolicy = pm->mappings[mapping_ix].subjectDomainPolicy; - idp = CFDataCreateWithBytesNoCopy(NULL, issuerDomainPolicy.data, issuerDomainPolicy.length, kCFAllocatorNull); - sdp = CFDataCreateWithBytesNoCopy(NULL, subjectDomainPolicy.data, subjectDomainPolicy.length, kCFAllocatorNull); - CFMutableArrayRef sdps = (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp); - if (sdps) { - CFArrayAppendValue(sdps, sdp); - } else { - require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeArrayCallBacks), errOut); - CFArrayAppendValue(sdps, sdp); - CFDictionarySetValue(mappings, idp, sdps); - CFRelease(sdps); - } - CFReleaseNull(idp); - CFReleaseNull(sdp); - } - - /* Now we use the dictionary to generate the new nodes */ - CFDictionaryForEach(mappings, ^(const void *key, const void *value) { - CFDataRef idp = key; - CFArrayRef sdps = value; - - /* (i) set the valid_policy to ID-P; */ - oid_t p_oid; - p_oid.data = (uint8_t *)CFDataGetBytePtr(idp); - p_oid.length = CFDataGetLength(idp); - - /* (ii) set the qualifier_set to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i */ - policy_qualifier_t p_q = node->qualifier_set; - - /* (iii) set the expected_policy_set to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension. */ - __block policy_set_t p_expected = NULL; - CFArrayForEach(sdps, ^(const void *value) { - policy_set_t p_node = (policy_set_t)malloc(sizeof(*p_expected)); - p_node->oid.data = (void *)CFDataGetBytePtr(value); - p_node->oid.length = CFDataGetLength(value); - p_node->oid_next = p_expected ? p_expected : NULL; - p_expected = p_node; - }); - - policy_tree_add_sibling(node, &p_oid, p_q, p_expected); - }); - CFReleaseNull(mappings); - return true; - -errOut: - CFReleaseNull(mappings); - CFReleaseNull(idp); - CFReleaseNull(sdp); - return false; -} - -static bool policy_tree_map_delete_if_match(policy_tree_t node, void *ctx) { - /* Can't map oidAnyPolicy. */ - if (oid_equal(node->valid_policy, oidAnyPolicy)) - return false; - - const SecCEPolicyMappings *pm = (const SecCEPolicyMappings *)ctx; - size_t mapping_ix, mapping_count = pm->numMappings; - /* If this node matches any of the idps, delete it. */ - for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { - const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; - if (oid_equal(node->valid_policy, mapping->issuerDomainPolicy)) { - policy_tree_remove_node(&node); - break; - } - } - return true; -} -#endif /* POLICY_MAPPINGS */ - /* rfc5280 basic cert processing. */ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, CFStringRef key) { /* Inputs */ //cert_path_t path; CFIndex count = SecPVCGetCertificateCount(pvc); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); /* 64 bits cast: worst case here is we truncate the number of cert, and the validation may fail */ assert((unsigned long)count<=UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ uint32_t n = (uint32_t)count; - bool is_anchored = SecPVCIsAnchored(pvc); + + bool is_anchored = SecPathBuilderIsAnchored(pvc->builder); + bool is_anchor_trusted = false; if (is_anchored) { + CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, n - 1); + if (CFArrayGetCount(constraints) == 0) { + /* Given that the path builder has already indicated the last cert in this chain has + * trust set on it, empty constraints means trusted. */ + is_anchor_trusted = true; + } else { + /* Determine whether constraints say to trust this cert for this PVC. */ + SecTrustSettingsResult tsResult = SecPVCGetTrustSettingsResult(pvc, SecCertificatePathVCGetCertificateAtIndex(path, n - 1), + constraints); + if (tsResult == kSecTrustSettingsResultTrustRoot || tsResult == kSecTrustSettingsResultTrustAsRoot) { + is_anchor_trusted = true; + } + } + } + + if (is_anchor_trusted) { /* If the anchor is trusted we don't process the last cert in the chain (root). */ n--; } else { - /* trust may be restored for a path with an untrusted root that matches the allow list */ - pvc->is_allowlisted = SecPVCCheckCertificateAllowList(pvc, n - 1); - if (!pvc->is_allowlisted) { + /* trust may be restored for a path with an untrusted root that matches the allow list. + (isAllowlisted is set by revocation check, which is performed prior to path checks) */ + if (!SecCertificatePathVCIsAllowlisted(path)) { /* Add a detail for the root not being trusted. */ if (!SecPVCSetResultForced(pvc, kSecPolicyCheckAnchorTrusted, - n - 1, kCFBooleanFalse, true)) + n - 1, kCFBooleanFalse, true)) { return; + } } } CFAbsoluteTime verify_time = SecPVCGetVerifyTime(pvc); //policy_set_t user_initial_policy_set = NULL; //trust_anchor_t anchor; - bool initial_policy_mapping_inhibit = false; - bool initial_explicit_policy = false; - bool initial_any_policy_inhibit = false; /* Initialization */ - pvc->valid_policy_tree = policy_tree_create(&oidAnyPolicy, NULL); #if POLICY_SUBTREES CFMutableArrayRef permitted_subtrees = NULL; CFMutableArrayRef excluded_subtrees = NULL; @@ -1583,9 +1061,12 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, require_action_quiet(excluded_subtrees != NULL, errOut, SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true)); #endif - uint32_t explicit_policy = initial_explicit_policy ? 0 : n + 1; - uint32_t inhibit_any_policy = initial_any_policy_inhibit ? 0 : n + 1; - uint32_t policy_mapping = initial_policy_mapping_inhibit ? 0 : n + 1; + + if (!SecCertificatePathVCVerifyPolicyTree(path, is_anchor_trusted)) { + if (!SecPVCSetResultForced(pvc, key, 0, kCFBooleanFalse, true)) { + goto errOut; + } + } #if 0 /* Path builder ensures we only get cert chains with proper issuer @@ -1599,7 +1080,7 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, for (i = 1; i <= n; ++i) { /* Process Cert */ cert = SecPVCGetCertificateAtIndex(pvc, n - i); - bool is_self_issued = SecPVCIsCertificateAtIndexSelfIssued(pvc, n - i); + bool is_self_issued = SecCertificatePathVCIsCertificateAtIndexSelfIssued(SecPathBuilderGetPath(pvc->builder), n - i); /* (a) Verify the basic certificate information. */ /* @@@ Ensure that cert was signed with working_public_key_algorithm @@ -1617,6 +1098,7 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, if (!SecPVCSetResult(pvc, fail_key, n - i, kCFBooleanFalse)) { goto errOut; } + pvc->result = kSecTrustResultFatalTrustFailure; } #endif /* @@@ cert.issuer == working_issuer_name. */ @@ -1641,99 +1123,15 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, } } #endif - /* (d) */ - if (pvc->valid_policy_tree) { - const SecCECertificatePolicies *cp = - SecCertificateGetCertificatePolicies(cert); - size_t policy_ix, policy_count = cp ? cp->numPolicies : 0; - for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { - const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; - oid_t p_oid = policy->policyIdentifier; - policy_qualifier_t p_q = &policy->policyQualifiers; - struct policy_tree_add_ctx ctx = { p_oid, p_q }; - if (!oid_equal(p_oid, oidAnyPolicy)) { - if (!policy_tree_walk_depth(pvc->valid_policy_tree, i - 1, - policy_tree_add_if_match, &ctx)) { - policy_tree_walk_depth(pvc->valid_policy_tree, i - 1, - policy_tree_add_if_any, &ctx); - } - } - } - /* The certificate policies extension includes the policy - anyPolicy with the qualifier set AP-Q and either - (a) inhibit_anyPolicy is greater than 0 or - (b) i < n and the certificate is self-issued. */ - if (inhibit_any_policy > 0 || (i < n && is_self_issued)) { - for (policy_ix = 0; policy_ix < policy_count; ++policy_ix) { - const SecCEPolicyInformation *policy = &cp->policies[policy_ix]; - oid_t p_oid = policy->policyIdentifier; - policy_qualifier_t p_q = &policy->policyQualifiers; - if (oid_equal(p_oid, oidAnyPolicy)) { - policy_tree_walk_depth(pvc->valid_policy_tree, i - 1, - policy_tree_add_expected, (void *)p_q); - } - } - } - policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1); - /* (e) */ - if (!cp) { - if (pvc->valid_policy_tree) - policy_tree_prune(&pvc->valid_policy_tree); - } - } - /* (f) Verify that either explicit_policy is greater than 0 or the - valid_policy_tree is not equal to NULL. */ - if (!pvc->valid_policy_tree && explicit_policy == 0) { - /* valid_policy_tree is empty and explicit policy is 0, illegal. */ - secnotice("policy", "policy tree failure"); - if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true)) { - goto errOut; - } - } + /* (d) (e) (f) handled by SecCertificatePathVCVerifyPolicyTree */ + /* If Last Cert in Path */ if (i == n) break; /* Prepare for Next Cert */ -#if POLICY_MAPPING - /* (a) verify that anyPolicy does not appear as an - issuerDomainPolicy or a subjectDomainPolicy */ - const SecCEPolicyMappings *pm = SecCertificateGetPolicyMappings(cert); - if (pm && pm->present) { - size_t mapping_ix, mapping_count = pm->numMappings; - for (mapping_ix = 0; mapping_ix < mapping_count; ++mapping_ix) { - const SecCEPolicyMapping *mapping = &pm->mappings[mapping_ix]; - if (oid_equal(mapping->issuerDomainPolicy, oidAnyPolicy) - || oid_equal(mapping->subjectDomainPolicy, oidAnyPolicy)) { - /* Policy mapping uses anyPolicy, illegal. */ - if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, n - i, kCFBooleanFalse, true)) { - goto errOut; - } - } - } - - /* (b) */ - /* (1) If the policy_mapping variable is greater than 0 */ - if (policy_mapping > 0 && pvc->valid_policy_tree) { - if (!policy_tree_walk_depth(pvc->valid_policy_tree, i, - policy_tree_map_if_match, (void *)pm)) { - /* If no node of depth i in the valid_policy_tree has a valid_policy of ID-P but there is a node of depth i with a valid_policy of anyPolicy, then generate a child node of the node of depth i-1. */ - policy_tree_walk_depth(pvc->valid_policy_tree, i, policy_tree_map_if_any, (void *)pm); - } - } else if (pvc->valid_policy_tree) { - /* (i) delete each node of depth i in the valid_policy_tree - where ID-P is the valid_policy. */ - policy_tree_walk_depth(pvc->valid_policy_tree, i, - policy_tree_map_delete_if_match, (void *)pm); - /* (ii) If there is a node in the valid_policy_tree of depth - i-1 or less without any child nodes, delete that - node. Repeat this step until there are no nodes of - depth i-1 or less without children. */ - policy_tree_prune_childless(&pvc->valid_policy_tree, i - 1); - } - } -#endif /* POLICY_MAPPING */ - /* (c)(d)(e)(f) */ + /* (a) (b) Done by SecCertificatePathVCVerifyPolicyTree */ + /* (c)(d)(e)(f) Done by SecPathBuilderGetNext and SecCertificatePathVCVerify */ //working_issuer_name = SecCertificateGetNormalizedSubjectContent(cert); //working_public_key = SecCertificateCopyPublicKey(cert); //working_public_key_parameters = SecCertificateCopyPublicKeyParameters(cert); @@ -1754,37 +1152,12 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, CFArrayAppendArray(excluded_subtrees, excluded_subtrees_in_cert, range); } #endif - /* (h) */ - if (!is_self_issued) { - if (explicit_policy) - explicit_policy--; - if (policy_mapping) - policy_mapping--; - if (inhibit_any_policy) - inhibit_any_policy--; - } - /* (i) */ - const SecCEPolicyConstraints *pc = - SecCertificateGetPolicyConstraints(cert); - if (pc) { - if (pc->requireExplicitPolicyPresent - && pc->requireExplicitPolicy < explicit_policy) { - explicit_policy = pc->requireExplicitPolicy; - } - if (pc->inhibitPolicyMappingPresent - && pc->inhibitPolicyMapping < policy_mapping) { - policy_mapping = pc->inhibitPolicyMapping; - } - } - /* (j) */ - const SecCEInhibitAnyPolicy *iap = SecCertificateGetInhibitAnyPolicySkipCerts(cert); - if (iap && iap->skipCerts < inhibit_any_policy) { - inhibit_any_policy = iap->skipCerts; - } + /* (h), (i), (j) done by SecCertificatePathVCVerifyPolicyTree */ + /* (k) */ const SecCEBasicConstraints *bc = SecCertificateGetBasicConstraints(cert); -#if 0 /* Checked in chain builder pre signature verify already. */ +#if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */ if (!bc || !bc->isCA) { /* Basic constraints not present or not marked as isCA, illegal. */ if (!SecPVCSetResult(pvc, kSecPolicyCheckBasicConstraints, @@ -1810,7 +1183,7 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, && bc->pathLenConstraint < max_path_length) { max_path_length = bc->pathLenConstraint; } -#if 0 /* Checked in chain builder pre signature verify already. */ +#if 0 /* Checked in chain builder pre signature verify already. SecPVCParentCertificateChecks */ /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */ SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert); if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) { @@ -1830,18 +1203,7 @@ static void SecPolicyCheckBasicCertificateProcessing(SecPVCRef pvc, } } /* end loop over certs in path */ /* Wrap up */ - cert = SecPVCGetCertificateAtIndex(pvc, 0); - /* (a) */ - if (explicit_policy) - explicit_policy--; - /* (b) */ - const SecCEPolicyConstraints *pc = SecCertificateGetPolicyConstraints(cert); - if (pc) { - if (pc->requireExplicitPolicyPresent - && pc->requireExplicitPolicy == 0) { - explicit_policy = 0; - } - } + /* (a) (b) done by SecCertificatePathVCVerifyPolicyTree */ /* (c) */ //working_public_key = SecCertificateCopyPublicKey(cert); /* (d) */ @@ -1858,26 +1220,7 @@ working_public_key_algorithm are different, set the working_public_key_parameter goto errOut; } } - /* (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows */ - - if (pvc->valid_policy_tree) { -#if !defined(NDEBUG) - policy_tree_dump(pvc->valid_policy_tree); -#endif - /* (g3c4) */ - //policy_tree_prune_childless(&pvc->valid_policy_tree, n - 1); - } - - /* If either (1) the value of explicit_policy variable is greater than - zero or (2) the valid_policy_tree is not NULL, then path processing - has succeeded. */ - if (!pvc->valid_policy_tree && explicit_policy == 0) { - /* valid_policy_tree is empty and explicit policy is 0, illegal. */ - secnotice("policy", "policy tree failure"); - if (!SecPVCSetResultForced(pvc, key /* @@@ Need custom key */, 0, kCFBooleanFalse, true)) { - goto errOut; - } - } + /* (g) done by SecCertificatePathVCVerifyPolicyTree */ errOut: CFReleaseNull(permitted_subtrees); @@ -2357,7 +1700,7 @@ static void SecPolicyCheckCT(SecPVCRef pvc, CFStringRef key) CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - uint64_t vt = TimestampFromCFAbsoluteTime(pvc->verifyTime); + uint64_t vt = TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc)); __block bool at_least_one_currently_valid_external = 0; __block bool at_least_one_currently_valid_embedded = 0; @@ -2417,12 +1760,12 @@ static void SecPolicyCheckCT(SecPVCRef pvc, CFStringRef key) */ - pvc->is_ct = false; + SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc->builder), false); if(at_least_one_currently_valid_external && CFDictionaryGetCount(currentLogsValidatingScts)>=2) { - pvc->is_ct = true; + SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc->builder), true); } else if(at_least_one_currently_valid_embedded) { - __block CFAbsoluteTime issuanceTime = pvc->verifyTime; + __block CFAbsoluteTime issuanceTime = SecPVCGetVerifyTime(pvc); __block int lifetime; // in Months __block unsigned once_or_current_qualified_embedded = 0; @@ -2471,7 +1814,7 @@ static void SecPolicyCheckCT(SecPVCRef pvc, CFStringRef key) } if(once_or_current_qualified_embedded >= requiredEmbeddedSctsCount){ - pvc->is_ct = true; + SecCertificatePathVCSetIsCT(SecPathBuilderGetPath(pvc->builder), true); } } @@ -2497,8 +1840,10 @@ static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) { policy_set_t policies = policies_for_cert(cert); if (policy_set_contains(policies, &key_value)) { + policy_set_free(policies); return true; } + policy_set_free(policies); } return false; } @@ -2530,17 +1875,18 @@ static void SecPolicyCheckRevocation(SecPVCRef pvc, SecPolicyRef policy = SecPVCGetPolicy(pvc); CFTypeRef value = CFDictionaryGetValue(policy->_options, key); if (isString(value)) { - SecPVCSetCheckRevocation(pvc, value); + SecPathBuilderSetRevocationMethod(pvc->builder, value); } } static void SecPolicyCheckRevocationResponseRequired(SecPVCRef pvc, CFStringRef key) { - SecPVCSetCheckRevocationResponseRequired(pvc); + pvc->require_revocation_response = true; + secdebug("policy", "revocation response required"); } static void SecPolicyCheckRevocationOnline(SecPVCRef pvc, CFStringRef key) { - SecPVCSetCheckRevocationOnline(pvc); + SecPathBuilderSetCheckRevocationOnline(pvc->builder); } static void SecPolicyCheckNoNetworkAccess(SecPVCRef pvc, @@ -2563,6 +1909,7 @@ static void SecPolicyCheckWeakIntermediates(SecPVCRef pvc, /* Intermediate certificate has a weak key. */ if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) return; + pvc->result = kSecTrustResultFatalTrustFailure; } } } @@ -2574,6 +1921,7 @@ static void SecPolicyCheckWeakLeaf(SecPVCRef pvc, /* Leaf certificate has a weak key. */ if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) return; + pvc->result = kSecTrustResultFatalTrustFailure; } } @@ -2586,6 +1934,7 @@ static void SecPolicyCheckWeakRoot(SecPVCRef pvc, /* Root certificate has a weak key. */ if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) return; + pvc->result = kSecTrustResultFatalTrustFailure; } } @@ -2620,30 +1969,29 @@ static bool leaf_is_on_weak_hash_whitelist(SecPVCRef pvc) { SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); require_quiet(leaf, out); - /* Leaf certificates that expire before Jan 3 2017 can get a pass. - * They must be updated before this goes live. */ - if (SecCertificateNotValidAfter(leaf) < 505200000.0) { - return true; - } + /* And now a special snowflake from our tests */ - /* And now a few special snowflakes */ - - /* subject:/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Domain 2009) */ - /* issuer :/C=IE/O=Baltimore/OU=CyberTrust/CN=Baltimore CyberTrust Root */ - /* Not After : Dec 19 17:25:36 2019 GMT */ + /* subject:/C=AU/ST=NSW/L=St Leonards/O=VODAFONE HUTCHISON AUSTRALIA PTY LIMITED/OU=Technology Shared Services/CN=mybill.vodafone.com.au */ + /* issuer :/C=UK/O=Vodafone Group/CN=Vodafone (Corporate Services 2009) */ + /* Not After : May 26 09:37:50 2017 GMT */ static const uint8_t vodafone[] = { - 0xC5, 0x0E, 0x88, 0xE5, 0x20, 0xA8, 0x10, 0x41, 0x1D, 0x63, - 0x4C, 0xB8, 0xF9, 0xCC, 0x93, 0x9B, 0xFD, 0x76, 0x93, 0x99 + 0xde, 0x77, 0x63, 0x97, 0x79, 0x47, 0xee, 0x6e, 0xc1, 0x3a, + 0x7b, 0x3b, 0xad, 0x43, 0x88, 0xa9, 0x66, 0x59, 0xa8, 0x18 }; - CFIndex intermediate_ix = SecPVCGetCertificateCount(pvc) - 2; - require_quiet(intermediate_ix > 0, out); - SecCertificateRef intermediate = SecPVCGetCertificateAtIndex(pvc, intermediate_ix); - CFDataRef fingerprint = SecCertificateGetSHA1Digest(intermediate); - require_quiet(fingerprint, out); + /* subject:/C=US/ST=Kansas/L=Overland Park/O=Sprint/CN=oma.ssprov.sprint.com */ + /* issuer :/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C */ + /* Not After : Aug 16 05:04:29 2017 GMT */ + static const uint8_t sprint[] = { + 0xa3, 0x18, 0x70, 0x4f, 0xf7, 0xbf, 0xfb, 0x2b, 0xe2, 0x64, + 0x3a, 0x2d, 0x2b, 0xb8, 0x10, 0x5f, 0x77, 0xd5, 0x01, 0xab + }; + + CFDataRef leafFingerprint = SecCertificateGetSHA1Digest(leaf); + require_quiet(leafFingerprint, out); const unsigned int len = 20; - const uint8_t *dp = CFDataGetBytePtr(fingerprint); - if (dp && (!memcmp(vodafone, dp, len))) { + const uint8_t *dp = CFDataGetBytePtr(leafFingerprint); + if (dp && (!memcmp(vodafone, dp, len) || !memcmp(sprint,dp,len))) { return true; } @@ -2656,29 +2004,6 @@ static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key); static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc, CFStringRef key) { CFIndex ix, count = SecPVCGetCertificateCount(pvc); -#if !NO_SERVER - CFDataRef clientAuditToken = NULL; - SecTaskRef task = NULL; -#endif - CFStringRef signingIdentifier = NULL; - - /* Only for Safari and WebKit. */ -#if NO_SERVER - require_quiet(signingIdentifier = CFRetainSafe(CFBundleGetIdentifier(CFBundleGetMainBundle())), out); -#else - require_quiet(clientAuditToken = SecPathBuilderCopyClientAuditToken(pvc->builder), out); - audit_token_t auditToken = {}; - require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out); - CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken); - require_quiet(task = SecTaskCreateWithAuditToken(NULL, auditToken), out); - require_quiet(signingIdentifier = SecTaskCopySigningIdentifier(task, NULL), out); -#endif - require_quiet(CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.Safari")) || - CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.mobilesafari")) || - CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.WebKit.Networking")) || - /* Or one of our test apps */ - CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.security.SecurityTests")) || - CFStringHasPrefix(signingIdentifier, CFSTR("com.apple.security.SecurityDevTests")), out); Boolean keyInPolicy = false; CFArrayRef policies = pvc->policies; @@ -2698,7 +2023,7 @@ static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc, keyInPolicy, out); /* Ignore the anchor if it's trusted */ - if (SecCertificatePathIsAnchored(pvc->path)) { + if (SecPathBuilderIsAnchored(pvc->builder)) { count--; } for (ix = 0; ix < count; ++ix) { @@ -2706,1047 +2031,77 @@ static void SecPolicyCheckSystemTrustedWeakHash(SecPVCRef pvc, if (SecCertificateIsWeakHash(cert)) { if (!leaf_is_on_weak_hash_whitelist(pvc)) { if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) { - goto out; + return; } } } } out: -#if !NO_SERVER - CFReleaseNull(clientAuditToken); - CFReleaseNull(task); -#endif - CFReleaseNull(signingIdentifier); return; } -#define ENABLE_CRLS (TARGET_OS_MAC && !TARGET_OS_IPHONE) - -// MARK: - -// MARK: SecRVCRef -/******************************************************** - ****************** SecRVCRef Functions ***************** - ********************************************************/ -typedef struct OpaqueSecORVC *SecORVCRef; -#if ENABLE_CRLS -typedef struct OpaqueSecCRVC *SecCRVCRef; -#endif - -/* Revocation verification context. */ -struct OpaqueSecRVC { - /* Pointer to the pvc for this revocation check */ - SecPVCRef pvc; - - /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */ - CFIndex certIX; - - /* The OCSP Revocation verification context */ - SecORVCRef orvc; - -#if ENABLE_CRLS - SecCRVCRef crvc; -#endif - - /* Valid database info for this revocation check */ - SecValidInfoRef valid_info; - - bool done; -}; -typedef struct OpaqueSecRVC *SecRVCRef; - -// MARK: SecORVCRef -/******************************************************** - ****************** OCSP RVC Functions ****************** - ********************************************************/ -const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0; -const CFAbsoluteTime kSecOCSPResponseOnlineTTL = 5.0 * 60.0; -#define OCSP_RESPONSE_TIMEOUT (3 * NSEC_PER_SEC) - -/* OCSP Revocation verification context. */ -struct OpaqueSecORVC { - /* Will contain the response data. */ - asynchttp_t http; - - /* Pointer to the pvc for this revocation check. */ - SecPVCRef pvc; - - /* Pointer to the generic rvc for this revocation check */ - SecRVCRef rvc; - - /* The ocsp request we send to each responder. */ - SecOCSPRequestRef ocspRequest; - - /* The freshest response we received so far, from stapling or cache or responder. */ - SecOCSPResponseRef ocspResponse; - - /* The best validated candidate single response we received so far, from stapling or cache or responder. */ - SecOCSPSingleResponseRef ocspSingleResponse; - - /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */ - CFIndex certIX; - - /* Index in array returned by SecCertificateGetOCSPResponders() for current - responder. */ - CFIndex responderIX; - - /* URL of current responder. */ - CFURLRef responder; - - /* Date until which this revocation status is valid. */ - CFAbsoluteTime nextUpdate; - - bool done; -}; - -static void SecORVCFinish(SecORVCRef orvc) { - secdebug("alloc", "%p", orvc); - asynchttp_free(&orvc->http); - if (orvc->ocspRequest) { - SecOCSPRequestFinalize(orvc->ocspRequest); - orvc->ocspRequest = NULL; - } - if (orvc->ocspResponse) { - SecOCSPResponseFinalize(orvc->ocspResponse); - orvc->ocspResponse = NULL; - if (orvc->ocspSingleResponse) { - SecOCSPSingleResponseDestroy(orvc->ocspSingleResponse); - orvc->ocspSingleResponse = NULL; - } - } -} - -#define MAX_OCSP_RESPONDERS 3 -#define OCSP_REQUEST_THRESHOLD 10 - -/* Return the next responder we should contact for this rvc or NULL if we - exhausted them all. */ -static CFURLRef SecORVCGetNextResponder(SecORVCRef rvc) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); - CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert); - if (ocspResponders) { - CFIndex responderCount = CFArrayGetCount(ocspResponders); - if (responderCount >= OCSP_REQUEST_THRESHOLD) { - secnotice("rvc", "too many ocsp responders (%ld)", (long)responderCount); - return NULL; - } - while (rvc->responderIX < responderCount && rvc->responderIX < MAX_OCSP_RESPONDERS) { - CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX); - rvc->responderIX++; - CFStringRef scheme = CFURLCopyScheme(responder); - if (scheme) { - /* We only support http and https responders currently. */ - bool valid_responder = (CFEqual(CFSTR("http"), scheme) || - CFEqual(CFSTR("https"), scheme)); - CFRelease(scheme); - if (valid_responder) - return responder; - } - } - } - return NULL; -} - -/* Fire off an async http request for this certs revocation status, return - false if request was queued, true if we're done. */ -static bool SecORVCFetchNext(SecORVCRef rvc) { - while ((rvc->responder = SecORVCGetNextResponder(rvc))) { - CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest); - if (!request) - goto errOut; - - secinfo("rvc", "Sending http ocsp request for cert %ld", rvc->certIX); - if (!asyncHttpPost(rvc->responder, request, OCSP_RESPONSE_TIMEOUT, &rvc->http)) { - /* Async request was posted, wait for reply. */ - return false; - } - } - -errOut: - rvc->done = true; - return true; -} - -/* Process a verified ocsp response for a given cert. Return true if the - certificate status was obtained. */ -static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this, - SecORVCRef rvc) { - bool processed; - switch (this->certStatus) { - case CS_Good: - secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX); - /* @@@ Mark cert as valid until a given date (nextUpdate if we have one) - in the info dictionary. */ - //cert.revokeCheckGood(true); - rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate; - processed = true; - break; - case CS_Revoked: - secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX); - /* @@@ Mark cert as revoked (with reason) at revocation date in - the info dictionary, or perhaps we should use a different key per - reason? That way a client using exceptions can ignore some but - not all reasons. */ - SInt32 reason = this->crlReason; - CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); - SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX, - cfreason, true); - if (rvc->pvc && rvc->pvc->info) { - /* make the revocation reason available in the trust result */ - CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason); - } - CFRelease(cfreason); - processed = true; - break; - case CS_Unknown: - /* not an error, no per-cert status, nothing here */ - secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX); - processed = false; - break; - default: - secnotice("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex, - (int)this->certStatus, rvc->certIX); - processed = false; - break; - } - - return processed; -} - -static void SecORVCUpdatePVC(SecORVCRef rvc) { - if (rvc->ocspSingleResponse) { - SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc); - } - if (rvc->ocspResponse) { - rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse); - } -} - -typedef void (^SecOCSPEvaluationCompleted)(SecTrustResultType tr); - -static void -SecOCSPEvaluateCompleted(const void *userData, - SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info, - SecTrustResultType result) { - SecOCSPEvaluationCompleted evaluated = (SecOCSPEvaluationCompleted)userData; - evaluated(result); - Block_release(evaluated); - -} - -static bool SecOCSPResponseEvaluateSigner(SecORVCRef rvc, CFArrayRef signers, CFArrayRef issuers, CFAbsoluteTime verifyTime) { - __block bool evaluated = false; - bool trusted = false; - if (!signers || !issuers) { - return trusted; - } - - /* Verify the signer chain against the OCSPSigner policy, using the issuer chain as anchors. */ - const void *ocspSigner = SecPolicyCreateOCSPSigner(); - CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault, - &ocspSigner, 1, &kCFTypeArrayCallBacks); - CFRelease(ocspSigner); - - SecOCSPEvaluationCompleted completed = Block_copy(^(SecTrustResultType result) { - if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) { - evaluated = true; - } - }); - - CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->pvc->builder); - SecPathBuilderRef oBuilder = SecPathBuilderCreate(clientAuditToken, - signers, issuers, true, false, - policies, NULL, NULL, NULL, - verifyTime, NULL, - SecOCSPEvaluateCompleted, completed); - /* Build the chain(s), evaluate them, call the completed block, free the block and builder */ - SecPathBuilderStep(oBuilder); - CFReleaseNull(clientAuditToken); - CFReleaseNull(policies); - - /* verify the public key of the issuer signed the OCSP signer */ - if (evaluated) { - SecCertificateRef issuer = NULL, signer = NULL; - SecKeyRef issuerPubKey = NULL; - - issuer = (SecCertificateRef)CFArrayGetValueAtIndex(issuers, 0); - signer = (SecCertificateRef)CFArrayGetValueAtIndex(signers, 0); - - if (issuer) { -#if TARGET_OS_IPHONE - issuerPubKey = SecCertificateCopyPublicKey(issuer); -#else - issuerPubKey = SecCertificateCopyPublicKey_ios(issuer); -#endif - } - if (signer && issuerPubKey && (errSecSuccess == SecCertificateIsSignedBy(signer, issuerPubKey))) { - trusted = true; - } else { - secnotice("ocsp", "ocsp signer cert not signed by issuer"); - } - CFReleaseNull(issuerPubKey); - } - - return trusted; -} - -static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecORVCRef rvc, CFAbsoluteTime verifyTime) { - bool trusted; - SecCertificatePathRef issuers = SecCertificatePathCopyFromParent(rvc->pvc->path, rvc->certIX + 1); - SecCertificateRef issuer = issuers ? CFRetainSafe(SecCertificatePathGetCertificateAtIndex(issuers, 0)) : NULL; - CFArrayRef signers = SecOCSPResponseCopySigners(ocspResponse); - SecCertificateRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer); - - if (signer && signers) { - if (issuer && CFEqual(signer, issuer)) { - /* We already know we trust issuer since it's the issuer of the - * cert we are verifying. */ - secinfo("ocsp", "ocsp responder: %@ response signed by issuer", - rvc->responder); - trusted = true; - } else { - secinfo("ocsp", "ocsp responder: %@ response signed by cert issued by issuer", - rvc->responder); - CFMutableArrayRef signerCerts = NULL; - CFArrayRef issuerCerts = NULL; - - /* Ensure the signer cert is the 0th cert for trust evaluation */ - signerCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(signerCerts, signer); - CFArrayAppendArray(signerCerts, signers, CFRangeMake(0, CFArrayGetCount(signers))); - - if (issuers) { - issuerCerts = SecCertificatePathCopyCertificates(issuers, NULL); - } - - if (SecOCSPResponseEvaluateSigner(rvc, signerCerts, issuerCerts, verifyTime)) { - secdebug("ocsp", "response satisfies ocspSigner policy (%@)", - rvc->responder); - trusted = true; - } else { - /* @@@ We don't trust the cert so don't use this response. */ - secnotice("ocsp", "ocsp response signed by certificate which " - "does not satisfy ocspSigner policy"); - trusted = false; - } - CFReleaseNull(signerCerts); - CFReleaseNull(issuerCerts); - } - } else { - /* @@@ No signer found for this ocsp response, discard it. */ - secnotice("ocsp", "ocsp responder: %@ no signer found for response", - rvc->responder); - trusted = false; - } - -#if DUMP_OCSPRESPONSES - char buf[40]; - snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der", - rvc->certIX, (trusted ? "t" : "u")); - secdumpdata(ocspResponse->data, buf); -#endif - CFReleaseNull(issuers); - CFReleaseNull(issuer); - CFReleaseNull(signers); - CFReleaseNull(signer); - return trusted; -} - -static void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, CFTimeInterval maxAge, bool updateCache) { - SecOCSPSingleResponseRef sr = NULL; - require_quiet(ocspResponse, errOut); - SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse); - require_action_quiet(orStatus == kSecOCSPSuccess, errOut, - secnotice("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus)); - require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut, - secnotice("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder)); - // Check if this response is fresher than any (cached) response we might still have in the rvc. - require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut); - - CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent(); - /* TODO: If the responder doesn't have the ocsp-nocheck extension we should - check whether the leaf was revoked (we are already checking the rest of - the chain). */ - /* Check the OCSP response signature and verify the response. */ - require_quiet(SecOCSPResponseVerify(ocspResponse, rvc, - sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut); - - // If we get here, we have a properly signed ocsp response - // but we haven't checked dates yet. - - bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime); - if (sr->certStatus == CS_Good) { - // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime - require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut); - } else if (sr->certStatus == CS_Revoked) { - // Expire revoked responses when the subject certificate itself expires. - ocspResponse->expireTime = SecCertificateNotValidAfter(SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX)); - } - - // Ok we like the new response, let's toss the old one. - if (updateCache) - SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime); - - if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse); - rvc->ocspResponse = ocspResponse; - ocspResponse = NULL; - - if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse); - rvc->ocspSingleResponse = sr; - sr = NULL; - - rvc->done = sr_valid; - -errOut: - if (sr) SecOCSPSingleResponseDestroy(sr); - if (ocspResponse) SecOCSPResponseFinalize(ocspResponse); -} - -/* Callback from async http code after an ocsp response has been received. */ -static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) { - SecORVCRef rvc = (SecORVCRef)http->info; - SecPVCRef pvc = rvc->pvc; - SecOCSPResponseRef ocspResponse = NULL; - if (http->response) { - CFDataRef data = CFHTTPMessageCopyBody(http->response); - if (data) { - /* Parse the returned data as if it's an ocspResponse. */ - ocspResponse = SecOCSPResponseCreate(data); - CFRelease(data); - } - } - - SecORVCConsumeOCSPResponse(rvc, ocspResponse, maxAge, true); - // TODO: maybe we should set the cache-control: false in the http header and try again if the response is stale - - if (!rvc->done) { - /* Clear the data for the next response. */ - asynchttp_free(http); - SecORVCFetchNext(rvc); - } - - if (rvc->done) { - secdebug("rvc", "got OCSP response for cert: %ld", rvc->certIX); - SecORVCUpdatePVC(rvc); - SecORVCFinish(rvc); - if (!--pvc->asyncJobCount) { - secdebug("rvc", "done with all async jobs"); - SecPathBuilderStep(pvc->builder); - } - } -} - -static SecORVCRef SecORVCCreate(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) { - SecORVCRef orvc = NULL; - orvc = malloc(sizeof(struct OpaqueSecORVC)); - if (orvc) { - memset(orvc, 0, sizeof(struct OpaqueSecORVC)); - orvc->pvc = pvc; - orvc->rvc = rvc; - orvc->certIX = certIX; - orvc->http.queue = SecPathBuilderGetQueue(pvc->builder); - orvc->http.token = SecPathBuilderCopyClientAuditToken(pvc->builder); - orvc->http.completed = SecOCSPFetchCompleted; - orvc->http.info = orvc; - orvc->ocspRequest = NULL; - orvc->responderIX = 0; - orvc->responder = NULL; - orvc->nextUpdate = NULL_TIME; - orvc->ocspResponse = NULL; - orvc->ocspSingleResponse = NULL; - orvc->done = false; - - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX); - CFIndex count = SecPVCGetCertificateCount(pvc); - if (certIX + 1 < count) { - SecCertificateRef issuer = SecPVCGetCertificateAtIndex(pvc, certIX + 1); - orvc->ocspRequest = SecOCSPRequestCreate(cert, issuer); - } - } - return orvc; -} - -static void SecORVCProcessStapledResponses(SecORVCRef rvc) { - /* Get stapled OCSP responses */ - CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(rvc->pvc->builder); - - if(ocspResponsesData) { - secdebug("rvc", "Checking stapled responses for cert %ld", rvc->certIX); - CFArrayForEach(ocspResponsesData, ^(const void *value) { - SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value); - SecORVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false); - }); - CFRelease(ocspResponsesData); - } -} - -// MARK: SecCRVCRef -/******************************************************** - ******************* CRL RVC Functions ****************** - ********************************************************/ -#if ENABLE_CRLS -#include <../trustd/SecTrustOSXEntryPoints.h> -#define kSecDefaultCRLTTL kSecDefaultOCSPResponseTTL - -/* CRL Revocation verification context. */ -struct OpaqueSecCRVC { - /* Response data from ocspd. Yes, ocspd does CRLs, but not OCSP... */ - async_ocspd_t async_ocspd; - - /* Pointer to the pvc for this revocation check. */ - SecPVCRef pvc; - - /* Pointer to the generic rvc for this revocation check */ - SecRVCRef rvc; - - /* The current CRL status from ocspd. */ - OSStatus status; - - /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */ - CFIndex certIX; - - /* Index in array returned by SecCertificateGetCRLDistributionPoints() for - current distribution point. */ - CFIndex distributionPointIX; - - /* URL of current distribution point. */ - CFURLRef distributionPoint; - - /* Date until which this revocation status is valid. */ - CFAbsoluteTime nextUpdate; - - bool done; -}; - -static void SecCRVCFinish(SecCRVCRef crvc) { - // nothing yet -} - -#define MAX_CRL_DPS 3 -#define CRL_REQUEST_THRESHOLD 10 - -static CFURLRef SecCRVCGetNextDistributionPoint(SecCRVCRef rvc) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); - CFArrayRef crlDPs = SecCertificateGetCRLDistributionPoints(cert); - if (crlDPs) { - CFIndex crlDPCount = CFArrayGetCount(crlDPs); - if (crlDPCount >= CRL_REQUEST_THRESHOLD) { - secnotice("rvc", "too many CRL DP entries (%ld)", (long)crlDPCount); - return NULL; - } - while (rvc->distributionPointIX < crlDPCount && rvc->distributionPointIX < MAX_CRL_DPS) { - CFURLRef distributionPoint = CFArrayGetValueAtIndex(crlDPs, rvc->distributionPointIX); - rvc->distributionPointIX++; - CFStringRef scheme = CFURLCopyScheme(distributionPoint); - if (scheme) { - /* We only support http and https responders currently. */ - bool valid_DP = (CFEqual(CFSTR("http"), scheme) || - CFEqual(CFSTR("https"), scheme) || - CFEqual(CFSTR("ldap"), scheme)); - CFRelease(scheme); - if (valid_DP) - return distributionPoint; - } - } - } - return NULL; -} - -static void SecCRVCGetCRLStatus(SecCRVCRef rvc) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); - SecCertificatePathRef path = rvc->pvc->path; - CFArrayRef serializedCertPath = SecCertificatePathCreateSerialized(path, NULL); - secdebug("rvc", "searching CRL cache for cert: %ld", rvc->certIX); - rvc->status = SecTrustLegacyCRLStatus(cert, serializedCertPath, rvc->distributionPoint); - CFReleaseNull(serializedCertPath); - /* we got a response indicating that the CRL was checked */ - if (rvc->status == errSecSuccess || rvc->status == errSecCertificateRevoked) { - rvc->done = true; - /* ocspd doesn't give us the nextUpdate time, so set to default */ - rvc->nextUpdate = SecPVCGetVerifyTime(rvc->pvc) + kSecDefaultCRLTTL; - } -} +static void SecPolicyCheckSystemTrustedWeakKey(SecPVCRef pvc, + CFStringRef key) { + CFIndex ix, count = SecPVCGetCertificateCount(pvc); -static void SecCRVCCheckRevocationCache(SecCRVCRef rvc) { - while ((rvc->distributionPoint = SecCRVCGetNextDistributionPoint(rvc))) { - SecCRVCGetCRLStatus(rvc); - if (rvc->status == errSecCertificateRevoked) { - return; + Boolean keyInPolicy = false; + CFArrayRef policies = pvc->policies; + CFIndex policyIX, policyCount = CFArrayGetCount(policies); + for (policyIX = 0; policyIX < policyCount; ++policyIX) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); + if (policy && CFDictionaryContainsKey(policy->_options, key)) { + keyInPolicy = true; } } -} -/* Fire off an async http request for this certs revocation status, return - false if request was queued, true if we're done. */ -static bool SecCRVCFetchNext(SecCRVCRef rvc) { - while ((rvc->distributionPoint = SecCRVCGetNextDistributionPoint(rvc))) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); - SecCertificatePathRef path = rvc->pvc->path; - CFArrayRef serializedCertPath = SecCertificatePathCreateSerialized(path, NULL); - secinfo("rvc", "fetching CRL for cert: %ld", rvc->certIX); - if (!SecTrustLegacyCRLFetch(&rvc->async_ocspd, rvc->distributionPoint, - CFAbsoluteTimeGetCurrent(), cert, serializedCertPath)) { - CFDataRef clientAuditToken = NULL; - SecTaskRef task = NULL; - audit_token_t auditToken = {}; - clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->pvc->builder); - require(clientAuditToken, out); - require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out); - CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken); - require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out); - secnotice("rvc", "asynchronously fetching CRL (%@) for client (%@)", - rvc->distributionPoint, task); - - out: - CFReleaseNull(clientAuditToken); - CFReleaseNull(task); - /* Async request was posted, wait for reply. */ - return false; - } - } - rvc->done = true; - return true; -} + /* We only enforce this check when *both* of the following are true: + * 1. One of the certs in the path has this usage constraint, and + * 2. One of the policies in the PVC has this key + * (As compared to normal policy options which require only one to be true..) */ + require_quiet(SecPVCKeyIsConstraintPolicyOption(pvc, key) && + keyInPolicy, out); -static void SecCRVCUpdatePVC(SecCRVCRef rvc) { - if (rvc->status == errSecCertificateRevoked) { - secdebug("rvc", "CRL revoked cert %" PRIdCFIndex, rvc->certIX); - SInt32 reason = 0; // unspecified, since ocspd didn't tell us - CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); - SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX, - cfreason, true); - if (rvc->pvc && rvc->pvc->info) { - /* make the revocation reason available in the trust result */ - CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason); - } - CFReleaseNull(cfreason); + /* Ignore the anchor if it's trusted */ + if (SecPathBuilderIsAnchored(pvc->builder)) { + count--; } -} - -static void SecCRVCFetchCompleted(async_ocspd_t *ocspd) { - SecCRVCRef rvc = ocspd->info; - SecPVCRef pvc = rvc->pvc; - /* we got a response indicating that the CRL was checked */ - if (ocspd->response == errSecSuccess || ocspd->response == errSecCertificateRevoked) { - rvc->status = ocspd->response; - rvc->done = true; - /* ocspd doesn't give us the nextUpdate time, so set to default */ - rvc->nextUpdate = SecPVCGetVerifyTime(rvc->pvc) + kSecDefaultCRLTTL; - secdebug("rvc", "got CRL response for cert: %ld", rvc->certIX); - SecCRVCUpdatePVC(rvc); - SecCRVCFinish(rvc); - if (!--pvc->asyncJobCount) { - secdebug("rvc", "done with all async jobs"); - SecPathBuilderStep(pvc->builder); - } - } else { - if(SecCRVCFetchNext(rvc)) { - if (!--pvc->asyncJobCount) { - secdebug("rvc", "done with all async jobs"); - SecPathBuilderStep(pvc->builder); + for (ix = 0; ix < count; ++ix) { + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + if (!SecCertificateIsStrongKey(cert)) { + if (!SecPVCSetResult(pvc, key, ix, kCFBooleanFalse)) { + return; } } - } -} - -static SecCRVCRef SecCRVCCreate(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) { - SecCRVCRef crvc = NULL; - crvc = malloc(sizeof(struct OpaqueSecCRVC)); - if (crvc) { - memset(crvc, 0, sizeof(struct OpaqueSecCRVC)); - crvc->pvc = pvc; - crvc->rvc = rvc; - crvc->certIX = certIX; - crvc->status = errSecInternal; - crvc->distributionPointIX = 0; - crvc->distributionPoint = NULL; - crvc->nextUpdate = NULL_TIME; - crvc->async_ocspd.queue = SecPathBuilderGetQueue(pvc->builder); - crvc->async_ocspd.completed = SecCRVCFetchCompleted; - crvc->async_ocspd.response = errSecInternal; - crvc->async_ocspd.info = crvc; - crvc->done = false; - } - return crvc; -} - -static bool SecRVCShouldCheckCRL(SecRVCRef rvc) { - if (rvc->pvc->check_revocation && - CFEqual(kSecPolicyCheckRevocationCRL, rvc->pvc->check_revocation)) { - /* Our client insists on CRLs */ - secinfo("rvc", "client told us to check CRL"); - return true; - } - SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); - CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert); - if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0) && - (rvc->pvc->check_revocation && !CFEqual(kSecPolicyCheckRevocationOCSP, rvc->pvc->check_revocation))) { - /* The cert doesn't have OCSP responders and the client didn't specifically ask for OCSP. - * This logic will skip the CRL cache check if the client didn't ask for revocation checking */ - secinfo("rvc", "client told us to check revocation and CRL is only option for cert: %ld", rvc->certIX); - return true; - } - return false; -} -#endif /* ENABLE_CRLS */ - -static void SecRVCFinish(SecRVCRef rvc) { - if (rvc->orvc) { - SecORVCFinish(rvc->orvc); - } -#if ENABLE_CRLS - if (rvc->crvc) { - SecCRVCFinish(rvc->crvc); - } -#endif -} - -static void SecRVCDelete(SecRVCRef rvc) { - if (rvc->orvc) { - SecORVCFinish(rvc->orvc); - free(rvc->orvc); - } -#if ENABLE_CRLS - if (rvc->crvc) { - SecCRVCFinish(rvc->crvc); - free(rvc->crvc); - } -#endif - if (rvc->valid_info) { - SecValidInfoRelease(rvc->valid_info); - } -} - -static void SecRVCInit(SecRVCRef rvc, SecPVCRef pvc, CFIndex certIX) { - secdebug("alloc", "%p", rvc); - rvc->pvc = pvc; - rvc->certIX = certIX; - rvc->orvc = SecORVCCreate(rvc, pvc, certIX); -#if ENABLE_CRLS - rvc->crvc = SecCRVCCreate(rvc, pvc, certIX); -#endif - rvc->done = false; -} - -static void SecRVCUpdatePVC(SecRVCRef rvc) { - SecORVCUpdatePVC(rvc->orvc); -#if ENABLE_CRLS - SecCRVCUpdatePVC(rvc->crvc); -#endif -} -#if ENABLE_CRLS -static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) { - if (!rvc->pvc->check_revocation - || !CFEqual(rvc->pvc->check_revocation, kSecPolicyCheckRevocationCRL)) { - return true; - } - return false; -} -#else -static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) { - return true; + } /* Cert loop */ +out: + return; } -#endif - -static void SecRVCProcessValidInfoResults(SecRVCRef rvc) { - if (!rvc || !rvc->valid_info || !rvc->pvc) { - return; - } - /* Handle definitive revocations. - */ - bool valid = rvc->valid_info->valid; - SecValidInfoFormat format = rvc->valid_info->format; - if (!valid && (format == kSecValidInfoFormatSerial || format == kSecValidInfoFormatSHA256)) { - secdebug("validupdate", "rvc: revoked cert %" PRIdCFIndex, rvc->certIX); - SInt32 reason = 0; // unspecified, since the Valid db doesn't tell us - CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); - SecPVCSetResultForced(rvc->pvc, kSecPolicyCheckRevocation, rvc->certIX, - cfreason, true); - if (rvc->pvc->info) { - /* make the revocation reason available in the trust result */ - CFDictionarySetValue(rvc->pvc->info, kSecTrustRevocationReason, cfreason); - } - CFReleaseNull(cfreason); - - rvc->done = true; - return; - } - /* Handle non-definitive information. - We set rvc->done = true above ONLY if the result was definitive; - otherwise we require a revocation check for SSL usage. - */ - if (format == kSecValidInfoFormatNto1) { - /* matched the filter */ - CFIndex count = SecPVCGetCertificateCount(rvc->pvc); - CFIndex issuerIX = rvc->certIX + 1; - if (issuerIX >= count) { - /* cannot perform a revocation check on the last cert in the - chain, since we don't have its issuer. */ +static void SecPolicyCheckPinningRequired(SecPVCRef pvc, CFStringRef key) { + /* Pinning is disabled on the system, skip. */ + if (SecIsInternalRelease()) { + if (CFPreferencesGetAppBooleanValue(CFSTR("AppleServerAuthenticationNoPinning"), + CFSTR("com.apple.security"), NULL)) { return; } - SecPolicyRef policy = SecPVCGetPolicy(rvc->pvc); - CFStringRef policyName = (policy) ? SecPolicyGetName(policy) : NULL; - if (policyName && CFEqual(CFSTR("sslServer"), policyName)) { - /* perform revocation check for SSL policy; - require for leaf if an OCSP responder is present. */ - if (0 == rvc->certIX) { - SecCertificateRef cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); - CFArrayRef resps = (cert) ? SecCertificateGetOCSPResponders(cert) : NULL; - CFIndex rcount = (resps) ? CFArrayGetCount(resps) : 0; - if (rcount > 0) { - rvc->pvc->response_required = true; - } - } - rvc->pvc->check_revocation = kSecPolicyCheckRevocationAny; - } } -} - -static bool SecRVCCheckValidInfoDatabase(SecRVCRef rvc) { - /* If the valid database is enabled... */ -#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) - /* Make sure revocation db info is up-to-date, - if we are allowed to access the network */ -#if !TARGET_OS_BRIDGE - SecPathBuilderRef builder = rvc->pvc->builder; - if (SecPathBuilderCanAccessNetwork(builder)) { - SecRevocationDbCheckNextUpdate(); - } -#endif - /* Check whether we have valid db info for this cert, - given the cert and its issuer */ - SecValidInfoRef info = NULL; - CFIndex count = SecPVCGetCertificateCount(rvc->pvc); - if (count) { - SecCertificateRef cert = NULL; - SecCertificateRef issuer = NULL; - CFIndex issuerIX = rvc->certIX + 1; - if (count > issuerIX) { - issuer = SecPVCGetCertificateAtIndex(rvc->pvc, issuerIX); - } else if (count == issuerIX) { - CFIndex rootIX = SecCertificatePathSelfSignedIndex(rvc->pvc->path); - if (rootIX == rvc->certIX) { - issuer = SecPVCGetCertificateAtIndex(rvc->pvc, rootIX); + CFArrayRef policies = pvc->policies; + CFIndex policyIX, policyCount = CFArrayGetCount(policies); + for (policyIX = 0; policyIX < policyCount; ++policyIX) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); + CFStringRef policyName = SecPolicyGetName(policy); + if (CFEqualSafe(policyName, CFSTR("sslServer"))) { + /* policy required pinning, but we didn't use a pinning policy */ + if (!SecPVCSetResult(pvc, key, 0, kCFBooleanFalse)) { + return; } } - cert = SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); - info = SecRevocationDbCopyMatching(cert, issuer); - } - if (info) { - SecValidInfoRef old_info = rvc->valid_info; - rvc->valid_info = info; - if (old_info) { - SecValidInfoRelease(old_info); - } - return true; - } -#endif - return false; -} - -static void SecRVCCheckRevocationCaches(SecRVCRef rvc) { - /* Don't check OCSP cache if CRLs enabled and policy requested CRL only */ - if (SecRVCShouldCheckOCSP(rvc)) { - secdebug("ocsp", "Checking cached responses for cert %ld", rvc->certIX); - SecOCSPResponseRef response = NULL; - if (rvc->pvc->online_revocation) { - CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); - response = SecOCSPCacheCopyMatchingWithMinInsertTime(rvc->orvc->ocspRequest, NULL, now - kSecOCSPResponseOnlineTTL); - } else { - response = SecOCSPCacheCopyMatching(rvc->orvc->ocspRequest, NULL); - } - SecORVCConsumeOCSPResponse(rvc->orvc, - response, - NULL_TIME, false); - } -#if ENABLE_CRLS - /* Don't check CRL cache if policy requested OCSP only */ - if (SecRVCShouldCheckCRL(rvc)) { - SecCRVCCheckRevocationCache(rvc->crvc); - } -#endif -} - -static bool SecRVCFetchNext(SecRVCRef rvc) { - bool OCSP_fetch_finished = true; - /* Don't send OCSP request only if CRLs enabled and policy requested CRL only */ - if (SecRVCShouldCheckOCSP(rvc)) { - OCSP_fetch_finished &= SecORVCFetchNext(rvc->orvc); - } - if (OCSP_fetch_finished) { - /* we didn't start an OCSP background job for this cert */ - rvc->pvc->asyncJobCount--; - } - -#if ENABLE_CRLS - bool CRL_fetch_finished = true; - /* Don't check CRL cache if policy requested OCSP only */ - if (SecRVCShouldCheckCRL(rvc)) { - /* reset the distributionPointIX because we already iterated through the CRLDPs - * in SecCRVCCheckRevocationCache */ - rvc->crvc->distributionPointIX = 0; - CRL_fetch_finished &= SecCRVCFetchNext(rvc->crvc); } - if (CRL_fetch_finished) { - /* we didn't start a CRL background job for this cert */ - rvc->pvc->asyncJobCount--; - } - OCSP_fetch_finished &= CRL_fetch_finished; -#endif - - return OCSP_fetch_finished; } -static bool SecPVCCheckRevocation(SecPVCRef pvc) { - secdebug("rvc", "checking revocation"); - CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); - bool completed = true; - if (certCount <= 1) { - /* Can't verify without an issuer; we're done */ - return completed; - } - - /* - * Don't need to call SecPVCIsAnchored; having an issuer is sufficient here. - * - * Note: we can't check revocation for the last certificate in the chain - * via OCSP or CRL methods, since there isn't a separate issuer cert to - * sign those responses. However, since a self-signed root has an implied - * issuer of itself, we can check for it in the valid database. - */ - - if (pvc->rvcs) { - /* We have done revocation checking already, we're done. */ - secdebug("rvc", "Not rechecking revocation"); - return completed; - } - - /* Setup things so we check revocation status of all certs. */ - pvc->rvcs = calloc(sizeof(struct OpaqueSecRVC), certCount); - - /* Note that if we are multi threaded and a job completes after it - is started but before we return from this function, we don't want - a callback to decrement asyncJobCount to zero before we finish issuing - all the jobs. To avoid this we pretend we issued certCount-1 async jobs, - and decrement pvc->asyncJobCount for each cert that we don't start a - background fetch for. (We will never start an async job for the final - cert in the chain.) */ -#if !ENABLE_CRLS - pvc->asyncJobCount = (unsigned int)(certCount-1); -#else - /* If we enable CRLS, we may end up with two async jobs per cert: one - * for OCSP and one for fetching the CRL */ - pvc->asyncJobCount = 2 * (unsigned int)(certCount-1); -#endif - secdebug("rvc", "set asyncJobCount to %d", pvc->asyncJobCount); - - /* Loop though certificates again and issue an ocsp fetch if the - * revocation status checking isn't done yet (and we have an issuer!) */ - for (certIX = 0; certIX < certCount; ++certIX) { - secdebug("rvc", "checking revocation for cert: %ld", certIX); - SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX]; - SecRVCInit(rvc, pvc, certIX); - if (rvc->done){ - continue; - } - -#if !TARGET_OS_BRIDGE - /* Check valid database first (separate from OCSP response cache) */ - if (SecRVCCheckValidInfoDatabase(rvc)) { - SecRVCProcessValidInfoResults(rvc); - } -#endif - /* Any other revocation method requires an issuer certificate; - * skip the last cert in the chain since it doesn't have one. */ - if (certIX+1 >= certCount) { - continue; - } - - /* Ignore stapled OCSP responses only if CRLs are enabled and the - * policy specifically requested CRLs only. */ - if (SecRVCShouldCheckOCSP(rvc)) { - /* If we have any OCSP stapled responses, check those first */ - SecORVCProcessStapledResponses(rvc->orvc); - } - -#if TARGET_OS_BRIDGE - /* The bridge has no writeable storage and no network. Nothing else we can - * do here. */ - rvc->done = true; - return completed; -#endif - - /* Then check the caches for revocation results. */ - SecRVCCheckRevocationCaches(rvc); - - /* The check is done if we found cached responses from either method. */ - if (rvc->orvc->done -#if ENABLE_CRLS - || rvc->orvc->done -#endif - ) { - secdebug("rvc", "found cached response for cert: %ld", certIX); - rvc->done = true; - } - - /* If we got a cached response that is no longer valid (which can only be true for - * revoked responses), let's try to get a fresher response even if no one asked. - * This check resolves unrevocation events after the nextUpdate time. */ - bool old_cached_response = (!rvc->done && rvc->orvc->ocspResponse); - - /* 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 = SecPathBuilderCanAccessNetwork(pvc->builder) && - (pvc->is_ev || pvc->check_revocation || old_cached_response); - bool fetch_done = true; - if (rvc->done || !allow_fetch) { - /* We got a cache hit or we aren't allowed to access the network */ - SecRVCUpdatePVC(rvc); - SecRVCFinish(rvc); - /* We didn't really start any background jobs for this cert. */ - pvc->asyncJobCount--; -#if ENABLE_CRLS - pvc->asyncJobCount--; -#endif - secdebug("rvc", "not fetching and job count is %d for cert %ld", pvc->asyncJobCount, certIX); - } else { - fetch_done = SecRVCFetchNext(rvc); - } - if (!fetch_done) { - /* We started at least one background fetch. */ - secdebug("rvc", "waiting on background fetch for cert %ld", certIX); - completed = false; - } - } - - /* Return false if we started any background jobs. */ - /* We can't just return !pvc->asyncJobCount here, since if we started any - jobs the completion callback will be called eventually and it will call - SecPathBuilderStep(). If for some reason everything completed before we - get here we still want the outer SecPathBuilderStep() to terminate so we - keep track of whether we started any jobs and return false if so. */ - return completed; -} - -static CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc) { - CFAbsoluteTime enu = NULL_TIME; - enu = rvc->orvc->nextUpdate; -#if ENABLE_CRLS - CFAbsoluteTime crlNextUpdate = rvc->crvc->nextUpdate; - if (enu == NULL_TIME || - ((crlNextUpdate > NULL_TIME) && (enu > crlNextUpdate))) { - /* We didn't check OCSP or CRL next update time was sooner */ - enu = crlNextUpdate; - } -#endif - return enu; -} - - -void SecPolicyServerInitalize(void) { +void SecPolicyServerInitialize(void) { gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); gSecPolicyPathCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, @@ -3770,7 +2125,7 @@ void SecPolicyServerInitalize(void) { CFDictionaryAddValue(gSecPolicyLeafCallbacks, kSecPolicyCheckBasicConstraints, SecPolicyCheckBasicConstraints); - CFDictionaryAddValue(gSecPolicyLeafCallbacks, + CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheckNonEmptySubject, SecPolicyCheckNonEmptySubject); CFDictionaryAddValue(gSecPolicyLeafCallbacks, @@ -3863,7 +2218,7 @@ void SecPolicyServerInitalize(void) { CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheckIntermediateMarkerOid, SecPolicyCheckIntermediateMarkerOid); - CFDictionaryAddValue(gSecPolicyLeafCallbacks, + CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheckCertificatePolicy, SecPolicyCheckCertificatePolicyOid); CFDictionaryAddValue(gSecPolicyPathCallbacks, @@ -3884,12 +2239,18 @@ void SecPolicyServerInitalize(void) { CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheckSystemTrustedWeakHash, SecPolicyCheckSystemTrustedWeakHash); + CFDictionaryAddValue(gSecPolicyPathCallbacks, + kSecPolicyCheckSystemTrustedWeakKey, + SecPolicyCheckSystemTrustedWeakKey); CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheckIntermediateOrganization, SecPolicyCheckIntermediateOrganization); CFDictionaryAddValue(gSecPolicyPathCallbacks, kSecPolicyCheckIntermediateCountry, SecPolicyCheckIntermediateCountry); + CFDictionaryAddValue(gSecPolicyLeafCallbacks, + kSecPolicyCheckPinningRequired, + SecPolicyCheckPinningRequired); } // MARK: - @@ -3898,8 +2259,7 @@ void SecPolicyServerInitalize(void) { ****************** SecPVCRef Functions ***************** ********************************************************/ -void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies, - CFAbsoluteTime verifyTime) { +void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies) { secdebug("alloc", "%p", pvc); // Weird logging policies crashes. //secdebug("policy", "%@", policies); @@ -3910,107 +2270,120 @@ void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies, pvc->policies = policies; if (policies) CFRetain(policies); - pvc->verifyTime = verifyTime; - pvc->result = true; -} + pvc->result = kSecTrustResultUnspecified; -static void SecPVCDeleteRVCs(SecPVCRef pvc) { - secdebug("alloc", "%p", pvc); - if (pvc->rvcs) { - CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); - for (certIX = 0; certIX < certCount; ++certIX) { - SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX]; - SecRVCDelete(rvc); - } - free(pvc->rvcs); - pvc->rvcs = NULL; - } + CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + pvc->leafDetails = CFArrayCreate(kCFAllocatorDefault, (const void **)&certDetail, + 1, &kCFTypeArrayCallBacks); + CFRelease(certDetail); } void SecPVCDelete(SecPVCRef pvc) { secdebug("alloc", "%p", pvc); CFReleaseNull(pvc->policies); CFReleaseNull(pvc->details); - CFReleaseNull(pvc->info); - if (pvc->valid_policy_tree) { - policy_tree_prune(&pvc->valid_policy_tree); - } - SecPVCDeleteRVCs(pvc); - CFReleaseNull(pvc->path); + CFReleaseNull(pvc->leafDetails); } -void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path, - CF_CONSUMED CFArrayRef details) { +void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path) { secdebug("policy", "%@", path); - bool samePath = ((!path && !pvc->path) || (path && pvc->path && CFEqual(path, pvc->path))); - if (!samePath) { - /* Changing path makes us clear the Revocation Verification Contexts */ - SecPVCDeleteRVCs(pvc); - CFReleaseSafe(pvc->path); - pvc->path = CFRetainSafe(path); - } - pvc->details = details; - CFReleaseNull(pvc->info); - if (pvc->valid_policy_tree) { - policy_tree_prune(&pvc->valid_policy_tree); - } + pvc->policyIX = 0; + pvc->result = kSecTrustResultUnspecified; + CFReleaseNull(pvc->details); +} + +void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path) { pvc->policyIX = 0; /* Since we don't run the LeafChecks again, we need to preserve the * result the leaf had. */ - pvc->result = (details) ? (CFDictionaryGetCount(CFArrayGetValueAtIndex(details, 0)) == 0) - : true; + CFIndex ix, pathLength = SecCertificatePathVCGetCount(path); + CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault, + pathLength, pvc->leafDetails); + for (ix = 1; ix < pathLength; ++ix) { + CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFArrayAppendValue(details, certDetail); + CFRelease(certDetail); + } + CFRetainAssign(pvc->details, details); + pvc->result = pvc->leafResult; + CFReleaseSafe(details); } SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) { return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX); } -CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) { - return SecCertificatePathGetCount(pvc->path); +static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) { + return SecPathBuilderGetCertificateCount(pvc->builder); } -SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) { - return SecCertificatePathGetCertificateAtIndex(pvc->path, ix); +static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) { + return SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); } -bool SecPVCIsCertificateAtIndexSelfIssued(SecPVCRef pvc, CFIndex ix) { - /* The SecCertificatePath only tells us the last self-issued cert. - * The chain may have more than one self-issued cert, so we need to - * do the comparison. */ - bool result = false; - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - CFDataRef issuer = SecCertificateCopyNormalizedIssuerSequence(cert); - CFDataRef subject = SecCertificateCopyNormalizedSubjectSequence(cert); - if (issuer && subject && CFEqual(issuer, subject)) { - result = true; - } - CFReleaseNull(issuer); - CFReleaseNull(subject); - return result; +static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) { + return SecPathBuilderGetVerifyTime(pvc->builder); } -void SecPVCSetCheckRevocation(SecPVCRef pvc, CFStringRef method) { - pvc->check_revocation = method; - secdebug("rvc", "deferred revocation checking enabled using %@ method", method); -} +static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CFTypeRef value) { + CFArrayRef exceptions = SecPathBuilderGetExceptions(pvc->builder); + if (!exceptions) { return false; } + CFIndex exceptionsCount = CFArrayGetCount(exceptions); -void SecPVCSetCheckRevocationResponseRequired(SecPVCRef pvc) { - pvc->response_required = true; - secdebug("rvc", "revocation response required"); -} + /* There are two types of exceptions: + * 1. Those that are built from SecTrustCopyExceptions, which are particular to the + * certs in the chain -- as indicated by the SHA1 digest in the exception dictionary. + * 2. On macOS, those built from SecTrustSetOptions, which are generic excepted errors. + */ +#if TARGET_OS_OSX + CFDictionaryRef options = CFArrayGetValueAtIndex(exceptions, 0); + /* Type 2 */ + if (exceptionsCount == 1 && (ix > 0 || !CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest))) { + /* SHA1Digest not allowed */ + if (CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest)) { return false; } + /* Key excepted */ + if (CFDictionaryContainsKey(options, key)) { + /* Special case -- AnchorTrusted only for self-signed certs */ + if (CFEqual(kSecPolicyCheckAnchorTrusted, key)) { + Boolean isSelfSigned = false; + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); + if (!cert || (errSecSuccess != SecCertificateIsSelfSigned(cert, &isSelfSigned)) || !isSelfSigned) { + return false; + } + } + return true; + } + } +#endif -void SecPVCSetCheckRevocationOnline(SecPVCRef pvc) { - pvc->online_revocation = true; - secdebug("rvc", "revocation force online check"); -} + /* Type 1 */ + if (ix >= exceptionsCount) { return false; } + CFDictionaryRef exception = CFArrayGetValueAtIndex(exceptions, ix); -bool SecPVCIsAnchored(SecPVCRef pvc) { - return SecCertificatePathIsAnchored(pvc->path); -} + /* Compare the cert hash */ + if (!CFDictionaryContainsKey(exception, kSecCertificateDetailSHA1Digest)) { return false; } + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); + if (!CFEqual(SecCertificateGetSHA1Digest(cert), CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest))) { + return false; + } -CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) { - return pvc->verifyTime; + /* Key Excepted */ + CFTypeRef exceptionValue = CFDictionaryGetValue(exception, key); + if (exceptionValue && CFEqual(value, exceptionValue)) { + /* Only change result if PVC is already ok */ + if (SecPVCIsOkResult(pvc)) { + // Chains that pass due to exceptions get Proceed result. + pvc->result = kSecTrustResultProceed; + } + return true; + } + + return false; } static int32_t detailKeyToCssmErr(CFStringRef key) { @@ -4035,8 +2408,9 @@ static bool SecPVCMeetsConstraint(SecPVCRef pvc, SecCertificateRef certificate, static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) { bool result = false; - CFArrayRef constraints = SecCertificatePathGetUsageConstraintsAtIndex(pvc->path, ix); - SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, ix); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, ix); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints); for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) { @@ -4062,9 +2436,10 @@ static bool SecPVCIsAllowedError(SecPVCRef pvc, CFIndex ix, CFStringRef key) { } static bool SecPVCKeyIsConstraintPolicyOption(SecPVCRef pvc, CFStringRef key) { - CFIndex certIX, certCount = SecCertificatePathGetCount(pvc->path); + CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); for (certIX = 0; certIX < certCount; certIX++) { - CFArrayRef constraints = SecCertificatePathGetUsageConstraintsAtIndex(pvc->path, certIX); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX); CFIndex constraintIX, constraintCount = CFArrayGetCount(constraints); for (constraintIX = 0; constraintIX < constraintCount; constraintIX++) { CFDictionaryRef constraint = (CFDictionaryRef)CFArrayGetValueAtIndex(constraints, constraintIX); @@ -4114,7 +2489,16 @@ bool SecPVCSetResultForced(SecPVCRef pvc, return true; } - pvc->result = false; + /* Check to see if exceptions tells us to ignore this error. */ + if (SecPVCIsExceptedError(pvc, ix, key, result)) { + secinfo("policy", "cert[%d]: skipped exception error %@", (int) ix, key); + return true; + } + + /* Check SecPVCIsOkResult to avoid resetting deny or fatal to recoverable */ + if (SecPVCIsOkResult(pvc)) { + pvc->result = kSecTrustResultRecoverableTrustFailure; + } if (!pvc->details) return false; @@ -4143,32 +2527,26 @@ static void SecPVCValidateKey(const void *key, const void *value, /* If our caller doesn't want full details and we failed earlier there is no point in doing additional checks. */ - if (!pvc->result && !pvc->details) + if (!SecPVCIsOkResult(pvc) && !pvc->details) return; SecPolicyCheckFunction fcn = (SecPolicyCheckFunction) CFDictionaryGetValue(pvc->callbacks, key); if (!fcn) { -#if 0 - /* Why not to have optional policy checks rant: - Not all keys are in all dictionaries anymore, so why not make checks - optional? This way a client can ask for something and the server will - do a best effort based on the supported flags. It works since they are - synchronized now, but we need some debug checking here for now. */ - pvc->result = false; -#endif if (pvc->callbacks == gSecPolicyLeafCallbacks) { if (!CFDictionaryContainsKey(gSecPolicyPathCallbacks, key)) { - pvc->result = false; + pvc->result = kSecTrustResultOtherError; } } else if (pvc->callbacks == gSecPolicyPathCallbacks) { if (!CFDictionaryContainsKey(gSecPolicyLeafCallbacks, key)) { - pvc->result = false; + pvc->result = kSecTrustResultOtherError; } } else { - /* Non standard validation phase, nothing is optional. */ - pvc->result = false; + /* Non standard validation phase. This may be a new key from the + * pinning DB which is not implemented in this OS version. Log + * a warning. */ + secwarning("policy: unknown policy key %@, skipping", key); } return; } @@ -4180,8 +2558,10 @@ static void SecPVCValidateKey(const void *key, const void *value, policy->_options is a caller provided dictionary, only its cf type has been checked. */ -bool SecPVCLeafChecks(SecPVCRef pvc) { - pvc->result = true; +SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc) { + /* We need to compute details for the leaf. */ + CFRetainAssign(pvc->details, pvc->leafDetails); + CFArrayRef policies = pvc->policies; CFIndex ix, count = CFArrayGetCount(policies); for (ix = 0; ix < count; ++ix) { @@ -4190,31 +2570,45 @@ bool SecPVCLeafChecks(SecPVCRef pvc) { /* Validate all keys for all policies. */ pvc->callbacks = gSecPolicyLeafCallbacks; CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc); - if (!pvc->result && !pvc->details) - return pvc->result; } + pvc->leafResult = pvc->result; + CFRetainAssign(pvc->leafDetails, pvc->details); + return pvc->result; } +bool SecPVCIsOkResult(SecPVCRef pvc) { + if (pvc->result == kSecTrustResultRecoverableTrustFailure || + pvc->result == kSecTrustResultDeny || + pvc->result == kSecTrustResultFatalTrustFailure || + pvc->result == kSecTrustResultOtherError) { + return false; + } + return true; +} + bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) { /* Check stuff common to intermediate and anchors. */ - CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); - SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); - bool is_anchor = (ix == SecPVCGetCertificateCount(pvc) - 1 - && SecPVCIsAnchored(pvc)); - if (!SecCertificateIsValid(cert, verifyTime)) { - /* Certificate has expired. */ - if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot - : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse)) + CFAbsoluteTime verifyTime = SecPVCGetVerifyTime(pvc); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); + CFIndex anchor_ix = SecPVCGetCertificateCount(pvc) - 1; + bool is_anchor = (ix == anchor_ix && SecPathBuilderIsAnchored(pvc->builder)); + + if (!SecCertificateIsValid(cert, verifyTime)) { + /* Certificate has expired. */ + if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckValidRoot + : kSecPolicyCheckValidIntermediates, ix, kCFBooleanFalse)) { goto errOut; - } + } + } if (SecCertificateIsWeakKey(cert)) { /* Certificate uses weak key. */ if (!SecPVCSetResult(pvc, is_anchor ? kSecPolicyCheckWeakRoot - : kSecPolicyCheckWeakIntermediates, ix, kCFBooleanFalse)) + : kSecPolicyCheckWeakIntermediates, ix, kCFBooleanFalse)) { goto errOut; + } } if (is_anchor) { @@ -4223,33 +2617,47 @@ bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix) { } else { /* Perform intermediate specific checks. */ - /* (k) Basic constraints only relevant for v3 and later. */ - if (SecCertificateVersion(cert) >= 3) { - const SecCEBasicConstraints *bc = - SecCertificateGetBasicConstraints(cert); - if (!bc || !bc->isCA) { - /* Basic constraints not present or not marked as isCA, illegal. */ - if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints, - ix, kCFBooleanFalse, true)) - goto errOut; - } - } - /* (l) max_path_length is checked elsewhere. */ + /* (k) Basic constraints only relevant for v3 and later. */ + if (SecCertificateVersion(cert) >= 3) { + const SecCEBasicConstraints *bc = + SecCertificateGetBasicConstraints(cert); + if (!bc || !bc->isCA) { + /* Basic constraints not present or not marked as isCA, illegal. */ + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints, + ix, kCFBooleanFalse, true)) { + goto errOut; + } + } + } + /* For a v1 or v2 certificate in an intermediate slot (not a leaf and + not an anchor), we additionally require that the certificate chain + does not end in a v3 or later anchor. [rdar://32204517] */ + else if (ix > 0 && ix < anchor_ix) { + SecCertificateRef anchor = SecPVCGetCertificateAtIndex(pvc, anchor_ix); + if (SecCertificateVersion(anchor) >= 3) { + if (!SecPVCSetResultForced(pvc, kSecPolicyCheckBasicConstraints, + ix, kCFBooleanFalse, true)) { + goto errOut; + } + } + } + /* (l) max_path_length is checked elsewhere. */ /* (n) If a key usage extension is present, verify that the keyCertSign bit is set. */ SecKeyUsage keyUsage = SecCertificateGetKeyUsage(cert); if (keyUsage && !(keyUsage & kSecKeyUsageKeyCertSign)) { if (!SecPVCSetResultForced(pvc, kSecPolicyCheckKeyUsage, - ix, kCFBooleanFalse, true)) + ix, kCFBooleanFalse, true)) { goto errOut; + } } } errOut: - return pvc->result; + return SecPVCIsOkResult(pvc); } -bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) { +static bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) { /* Check stuff common to intermediate and anchors. */ SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); @@ -4262,7 +2670,7 @@ bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) { SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); CFIndex count = SecPVCGetCertificateCount(pvc); bool is_last = (ix == count - 1); - bool is_anchor = (is_last && SecPVCIsAnchored(pvc)); + bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder)); if (!is_anchor) { /* Check for blacklisted intermediate issuer keys. */ CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); @@ -4271,29 +2679,27 @@ bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix) { if (CFSetContainsValue(blackListedKeys, dgst)) { /* Check allow list for this blacklisted issuer key, which is the authority key of the issued cert at ix-1. - If ix is the last cert, the root is missing, so we - also check our own authority key in that case. */ - bool allowed = ((ix && SecPVCCheckCertificateAllowList(pvc, ix - 1)) || - (is_last && SecPVCCheckCertificateAllowList(pvc, ix))); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + bool allowed = path && SecCertificatePathVCIsAllowlisted(path); if (!allowed) { SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, ix, kCFBooleanFalse, true); + pvc->result = kSecTrustResultFatalTrustFailure; } - pvc->is_allowlisted = allowed; } CFRelease(dgst); } } CFRelease(blackListedKeys); - return pvc->result; + return SecPVCIsOkResult(pvc); } } // Assume OK return true; } -bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix) +static bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix) { /* Check stuff common to intermediate and anchors. */ SecOTAPKIRef otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); @@ -4306,7 +2712,7 @@ bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix) SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix); CFIndex count = SecPVCGetCertificateCount(pvc); bool is_last = (ix == count - 1); - bool is_anchor = (is_last && SecPVCIsAnchored(pvc)); + bool is_anchor = (is_last && SecPathBuilderIsAnchored(pvc->builder)); if (!is_anchor) { /* Check for gray listed intermediate issuer keys. */ CFDataRef dgst = SecCertificateCopyPublicKeySHA1Digest(cert); @@ -4315,22 +2721,19 @@ bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix) if (CFSetContainsValue(grayListKeys, dgst)) { /* Check allow list for this graylisted issuer key, which is the authority key of the issued cert at ix-1. - If ix is the last cert, the root is missing, so we - also check our own authority key in that case. */ - bool allowed = ((ix && SecPVCCheckCertificateAllowList(pvc, ix - 1)) || - (is_last && SecPVCCheckCertificateAllowList(pvc, ix))); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + bool allowed = path && SecCertificatePathVCIsAllowlisted(path); if (!allowed) { SecPVCSetResultForced(pvc, kSecPolicyCheckGrayListedKey, ix, kCFBooleanFalse, true); } - pvc->is_allowlisted = allowed; } CFRelease(dgst); } } CFRelease(grayListKeys); - return pvc->result; + return SecPVCIsOkResult(pvc); } } // Assume ok @@ -4481,8 +2884,9 @@ static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc, * so it's a root/intermediate. If there is no path, this is the leaf. */ CFIndex pathIndex = -1; - if (pvc->path) { - pathIndex = SecCertificatePathGetIndexOfCertificate(pvc->path, certificate); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + if (path) { + pathIndex = SecCertificatePathVCGetIndexOfCertificate(path, certificate); } else { pathIndex = 0; } @@ -4510,29 +2914,41 @@ static bool SecPVCContainsTrustSettingsKeyUsage(SecPVCRef pvc, return false; } -#if TARGET_OS_MAC && !TARGET_OS_IPHONE - +#if TARGET_OS_OSX #include +#include +#include #include #include +extern OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); + static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appRef) { bool result = false; audit_token_t auditToken = {}; - char path[MAXPATHLEN]; + SecTaskRef task = NULL; + SecRequirementRef requirement = NULL; + CFStringRef stringRequirement = NULL; require(appRef && clientAuditToken, out); require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out); + require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef)appRef, &requirement), out); + require(requirement, out); + require_noerr(SecRequirementsCopyString(requirement, kSecCSDefaultFlags, &stringRequirement), out); + require(stringRequirement, out); require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out); CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken); - require(proc_pidpath(audit_token_to_pid(auditToken), path, sizeof(path)) > 0, out); + require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out); - if(errSecSuccess == SecTrustedApplicationValidateWithPath((SecTrustedApplicationRef)appRef, path)) { + if(errSecSuccess == SecTaskValidateForRequirement(task, stringRequirement)) { result = true; } out: + CFReleaseNull(task); + CFReleaseNull(requirement); + CFReleaseNull(stringRequirement); return result; } #endif @@ -4638,20 +3054,34 @@ SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificat return result; } -bool SecPVCCheckUsageConstraints(SecPVCRef pvc) { - bool shouldDeny = false; - CFIndex certIX, certCount = SecCertificatePathGetCount(pvc->path); +static void SecPVCCheckUsageConstraints(SecPVCRef pvc) { + CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); for (certIX = 0; certIX < certCount; certIX++) { - CFArrayRef constraints = SecCertificatePathGetUsageConstraintsAtIndex(pvc->path, certIX); - SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, certIX); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFArrayRef constraints = SecCertificatePathVCGetUsageConstraintsAtIndex(path, certIX); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX); SecTrustSettingsResult result = SecPVCGetTrustSettingsResult(pvc, cert, constraints); + /* Set the pvc trust result based on the usage constraints and anchor source. */ if (result == kSecTrustSettingsResultDeny) { SecPVCSetResultForced(pvc, kSecPolicyCheckUsageConstraints, certIX, kCFBooleanFalse, true); - shouldDeny = true; + pvc->result = kSecTrustResultDeny; + } else if ((result == kSecTrustSettingsResultTrustRoot || result == kSecTrustSettingsResultTrustAsRoot || + result == kSecTrustSettingsResultInvalid) && SecPVCIsOkResult(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 + if (SecPathBuilderIsAnchorSource(pvc->builder, kSecLegacyAnchorSource) && + SecCertificateSourceContains(kSecLegacyAnchorSource, cert)) { +#endif + pvc->result = kSecTrustResultProceed; + } } } - return shouldDeny; } #define kSecPolicySHA256Size 32 @@ -4688,7 +3118,7 @@ static const UInt8 kSC_G2[kSecPolicySHA256Size] = { 0x8F,0xAE,0x1F,0x93,0xC4,0x39,0x7F,0xEA,0x44,0x1B,0xB7,0xCB,0xE6,0xFD,0x59,0x95 }; -bool SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) { +static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) { static CFSetRef sConstrainedRoots = NULL; static dispatch_once_t _t; dispatch_once(&_t, ^{ @@ -4710,18 +3140,19 @@ bool SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) { }); bool shouldDeny = false; - CFIndex certIX, certCount = SecCertificatePathGetCount(pvc->path); + CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); for (certIX = certCount - 1; certIX >= 0 && !shouldDeny; certIX--) { - SecCertificateRef cert = SecCertificatePathGetCertificateAtIndex(pvc->path, certIX); + SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, certIX); CFDataRef sha256 = SecCertificateCopySHA256Digest(cert); if (sha256 && CFSetContainsValue(sConstrainedRoots, sha256)) { /* matched a constrained root; check notBefore dates on all its children. */ CFIndex childIX = certIX; while (--childIX >= 0) { - SecCertificateRef child = SecCertificatePathGetCertificateAtIndex(pvc->path, childIX); + SecCertificateRef child = SecPVCGetCertificateAtIndex(pvc, childIX); /* 1 Dec 2016 00:00:00 GMT */ if (child && (CFAbsoluteTime)502243200.0 <= SecCertificateNotValidBefore(child)) { SecPVCSetResultForced(pvc, kSecPolicyCheckBlackListedKey, certIX, kCFBooleanFalse, true); + pvc->result = kSecTrustResultFatalTrustFailure; shouldDeny = true; break; } @@ -4729,21 +3160,22 @@ bool SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) { } CFReleaseNull(sha256); } - return shouldDeny; } /* AUDIT[securityd](done): policy->_options is a caller provided dictionary, only its cf type has been checked. */ -bool SecPVCPathChecks(SecPVCRef pvc) { - secdebug("policy", "begin path: %@", pvc->path); - bool completed = true; +void SecPVCPathChecks(SecPVCRef pvc) { + secdebug("policy", "begin path: %@", SecPathBuilderGetPath(pvc->builder)); + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); /* This needs to be initialized before we call any function that might call SecPVCSetResultForced(). */ pvc->policyIX = 0; SecPolicyCheckIdLinkage(pvc, kSecPolicyCheckIdLinkage); - if (pvc->result || pvc->details) { + if (SecPVCIsOkResult(pvc) || pvc->details) { + /* @@@ This theoretically only needs to be done once per path, but since + this function affects the pvc result, we'll run it every time. */ SecPolicyCheckBasicCertificateProcessing(pvc, kSecPolicyCheckBasicCertificateProcessing); } @@ -4755,105 +3187,69 @@ bool SecPVCPathChecks(SecPVCRef pvc) { pvc->callbacks = gSecPolicyPathCallbacks; SecPolicyRef policy = SecPVCGetPolicy(pvc); CFDictionaryApplyFunction(policy->_options, SecPVCValidateKey, pvc); - if (!pvc->result && !pvc->details) - return completed; + if (!SecPVCIsOkResult(pvc) && !pvc->details) + return; } // Reset pvc->policyIX = 0; /* Check whether the TrustSettings say to deny a cert in the path. */ - (void)SecPVCCheckUsageConstraints(pvc); - - /* Check for issuer date constraints. */ - (void)SecPVCCheckIssuerDateConstraints(pvc); - - /* Check the things we can't check statically for the certificate path. */ - /* Critical Extensions, chainLength. */ - - /* Policy tests. */ - pvc->is_ev = false; - if ((pvc->result || pvc->details) && pvc->optionally_ev) { - bool pre_ev_check_result = pvc->result; - SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation); - pvc->is_ev = pvc->result; - /* If ev checking failed, we still want to accept this chain - as a non EV one, if it was valid as such. */ - pvc->result = pre_ev_check_result; - } - - /* Check revocation always, since we don't want a lesser recoverable result - * to prevent the check from occurring. */ - completed = SecPVCCheckRevocation(pvc); - - /* Check for CT */ - if (pvc->result || pvc->details) { + SecPVCCheckUsageConstraints(pvc); + + /* Check for Blocklisted certs */ + SecPVCCheckIssuerDateConstraints(pvc); + CFIndex ix; + count = SecCertificatePathVCGetCount(path); + for (ix = 1; ix < count; ix++) { + SecPVCGrayListedKeyChecks(pvc, ix); + SecPVCBlackListedKeyChecks(pvc, ix); + } + + /* Path-based check tests. */ + if (!SecCertificatePathVCIsPathValidated(path)) { + bool ev_check_ok = false; + if (SecCertificatePathVCIsOptionallyEV(path)) { + SecTrustResultType pre_ev_check_result = pvc->result; + SecPolicyCheckEV(pvc, kSecPolicyCheckExtendedValidation); + ev_check_ok = SecPVCIsOkResult(pvc); + /* If ev checking failed, we still want to accept this chain + as a non EV one, if it was valid as such. */ + pvc->result = pre_ev_check_result; + } + + /* Check for CT */ /* This call will set the value of pvc->is_ct, but won't change the result (pvc->result) */ SecPolicyCheckCT(pvc, kSecPolicyCheckCertificateTransparency); - } - if (pvc->is_ev && !pvc->is_ct) { - pvc->is_ct_whitelisted = SecPVCCheckCTWhiteListedLeaf(pvc); - } else { - pvc->is_ct_whitelisted = false; + /* Certs are only EV if they are also CT verified */ + if (ev_check_ok && SecCertificatePathVCIsCT(path)) { + SecCertificatePathVCSetIsEV(path, true); + } } //errOut: - secdebug("policy", "end %strusted completed: %d path: %@", - (pvc->result ? "" : "not "), completed, pvc->path); - return completed; + secdebug("policy", "end %strusted path: %@", + (SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder)); + + SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder)); + return; } -/* This function returns 0 to indicate revocation checking was not completed - for this certificate chain, otherwise return to date at which the first - piece of revocation checking info we used expires. */ -CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc) { - CFIndex certIX, certCount = SecPVCGetCertificateCount(pvc); - CFAbsoluteTime enu = NULL_TIME; - if (certCount <= 1 || !pvc->rvcs) { - return enu; - } - certCount--; - - for (certIX = 0; certIX < certCount; ++certIX) { - SecRVCRef rvc = &((SecRVCRef)pvc->rvcs)[certIX]; - CFAbsoluteTime thisCertNextUpdate = SecRVCGetEarliestNextUpdate(rvc); - if (thisCertNextUpdate == 0) { - if (certIX > 0) { - /* We allow for CA certs to not be revocation checked if they - have no ocspResponders nor CRLDPs to check against, but the leaf - must be checked in order for us to claim we did revocation - checking. */ - SecCertificateRef cert = - SecPVCGetCertificateAtIndex(rvc->pvc, rvc->certIX); - CFArrayRef ocspResponders = NULL; - ocspResponders = SecCertificateGetOCSPResponders(cert); -#if ENABLE_CRLS - CFArrayRef crlDPs = NULL; - crlDPs = SecCertificateGetCRLDistributionPoints(cert); -#endif - if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0) -#if ENABLE_CRLS - && (!crlDPs || CFArrayGetCount(crlDPs) == 0) -#endif - ) { - /* We can't check this cert so we don't consider it a soft - failure that we didn't. Ideally we should support crl - checking and remove this workaround, since that more - strict. */ - continue; - } +void SecPVCPathCheckRevocationRequired(SecPVCRef pvc) { + SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); + CFIndex ix, certCount = SecCertificatePathVCGetCount(path); + for (ix = 0; ix < certCount; ix++) { + /* If we require revocation (for that cert per the SecCertificateVCRef or + * per the pvc) */ + if (SecCertificatePathVCIsRevocationRequiredForCertificateAtIndex(path, ix) || + ((ix == 0) && pvc->require_revocation_response)) { + /* Do we have a valid revocation response? */ + SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, ix); + if (SecRVCGetEarliestNextUpdate(rvc) == NULL_TIME) { + SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired, + ix, kCFBooleanFalse, true); } - secdebug("rvc", "revocation checking soft failure for cert: %ld", - certIX); - enu = thisCertNextUpdate; - break; - } - if (enu == 0 || thisCertNextUpdate < enu) { - enu = thisCertNextUpdate; } } - - secdebug("rvc", "revocation valid until: %lg", enu); - return enu; } diff --git a/OSX/sec/securityd/SecPolicyServer.h b/OSX/sec/securityd/SecPolicyServer.h index c46df7eb..18840997 100644 --- a/OSX/sec/securityd/SecPolicyServer.h +++ b/OSX/sec/securityd/SecPolicyServer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2010,2012-2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2008-2010,2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -30,55 +30,19 @@ #ifndef _SECURITY_SECPOLICYSERVER_H_ #define _SECURITY_SECPOLICYSERVER_H_ +#include #include #include -#include #include +#include __BEGIN_DECLS -typedef struct OpaqueSecPVC *SecPVCRef; - -struct OpaqueSecPVC { - SecPathBuilderRef builder; - - /* @@@ Duplicated from builder, remove. */ - CFArrayRef policies; - CFAbsoluteTime verifyTime; - - SecCertificatePathRef path; - CFArrayRef details; - CFMutableDictionaryRef info; - policy_tree_t valid_policy_tree; - CFDictionaryRef callbacks; - CFIndex policyIX; - - void *rvcs; - unsigned int asyncJobCount; - - CFStringRef check_revocation; - bool response_required; - bool online_revocation; - bool optionally_ev; - bool is_ev; - bool is_ct; - bool is_ct_whitelisted; - bool is_allowlisted; - bool result; -}; - -void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies, - CFAbsoluteTime verifyTime); +void SecPVCInit(SecPVCRef pvc, SecPathBuilderRef builder, CFArrayRef policies); void SecPVCDelete(SecPVCRef pvc); -void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathRef path, - CF_CONSUMED CFArrayRef details); +void SecPVCSetPath(SecPVCRef pvc, SecCertificatePathVCRef path); SecPolicyRef SecPVCGetPolicy(SecPVCRef pv); -CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pv); -CFIndex SecPVCGetCertificateCount(SecPVCRef pv); -SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pv, CFIndex ix); -bool SecPVCIsCertificateAtIndexSelfIssued(SecPVCRef pvc, CFIndex ix); -bool SecPVCIsAnchored(SecPVCRef pvc); /* Set the string result as the reason for the sub policy check key failing. The policy check function should continue processing if @@ -87,38 +51,29 @@ bool SecPVCSetResult(SecPVCRef pv, CFStringRef key, CFIndex ix, CFTypeRef result); bool SecPVCSetResultForced(SecPVCRef pvc, CFStringRef key, CFIndex ix, CFTypeRef result, bool force); +bool SecPVCIsOkResult(SecPVCRef pvc); -/* Enable revocation checking if the rest of the policy checks succeed. */ -void SecPVCSetCheckRevocation(SecPVCRef pvc, CFStringRef method); +/* Is the current result considered successful. */ +bool SecPVCIsOkResult(SecPVCRef pvc); -/* Require a revocation response for the leaf certificate. */ -void SecPVCSetCheckRevocationResponseRequired(SecPVCRef pvc); - -/* Require a online revocation response for the chain. */ -void SecPVCSetCheckRevocationOnline(SecPVCRef pvc); +/* Compute details */ +void SecPVCComputeDetails(SecPVCRef pvc, SecCertificatePathVCRef path); /* Run static leaf checks on the path in pvc. */ -bool SecPVCLeafChecks(SecPVCRef pvc); +SecTrustResultType SecPVCLeafChecks(SecPVCRef pvc); /* Run static parent checks on the path in pvc. */ bool SecPVCParentCertificateChecks(SecPVCRef pvc, CFIndex ix); -/* Check whether an intermediate certificates key has been blacklisted. */ -bool SecPVCBlackListedKeyChecks(SecPVCRef pvc, CFIndex ix); - -/* Check whether an intermediate certificates key has been gray listed. */ -bool SecPVCGrayListedKeyChecks(SecPVCRef pvc, CFIndex ix); - /* Run dynamic checks on the complete path in pvc. Return true if the operation is complete, returns false if an async backgroup request was scheduled. Upon completion of the async background job SecPathBuilderStep() should be called. */ -bool SecPVCPathChecks(SecPVCRef pvc); +void SecPVCPathChecks(SecPVCRef pvc); -/* Return 0 if any certs revocation checking failed, the earliest date on - which one of the used revocation validation tokens (ocsp response or - crl) expires. */ -CFAbsoluteTime SecPVCGetEarliestNextUpdate(SecPVCRef pvc); +/* Check whether revocation was required for any cert but revocation + * check failed. */ +void SecPVCPathCheckRevocationRequired(SecPVCRef pvc); typedef void (*SecPolicyCheckFunction)(SecPVCRef pv, CFStringRef key); @@ -128,19 +83,12 @@ typedef void (*SecPolicyCheckFunction)(SecPVCRef pv, CFStringRef key); */ bool SecPolicyValidate(SecPolicyRef policy, SecPVCRef pvc, CFStringRef key); -void SecPolicyServerInitalize(void); +void SecPolicyServerInitialize(void); -/* True iff certificate could be an extended validation (EV) certificate. */ -bool SecPolicySubscriberCertificateCouldBeEV(SecCertificateRef certificate); - -void SecEVPolicyToAnchorDigestsInit(void); +bool SecPolicyIsEVPolicy(const DERItem *policyOID); SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints); -bool SecPVCCheckUsageConstraints(SecPVCRef pvc); - -bool SecPVCCheckIssuerDateConstraints(SecPVCRef pvc); - __END_DECLS #endif /* !_SECURITY_SECPOLICYSERVER_H_ */ diff --git a/OSX/sec/securityd/SecRevocationDb.c b/OSX/sec/securityd/SecRevocationDb.c index b9e7b3c2..76347c81 100644 --- a/OSX/sec/securityd/SecRevocationDb.c +++ b/OSX/sec/securityd/SecRevocationDb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,10 +28,14 @@ #include #include +#include +#include #include #include +#include #include #include +#include #include #include #include @@ -41,7 +45,9 @@ #include #include #include +#include #include "utilities/debugging.h" +#include "utilities/sec_action.h" #include "utilities/sqlutils.h" #include "utilities/SecAppleAnchorPriv.h" #include "utilities/iOSforOSX.h" @@ -55,56 +61,81 @@ #include #include #include +#include #include #include #include - -static CFStringRef kAcceptEncoding = CFSTR("Accept-Encoding"); -static CFStringRef kAppEncoding = CFSTR("deflate"); -static CFStringRef kUserAgent = CFSTR("User-Agent"); -static CFStringRef kAppUserAgent = CFSTR("com.apple.trustd/1.0"); static CFStringRef kValidUpdateServer = CFSTR("valid.apple.com"); static CFStringRef kSecPrefsDomain = CFSTR("com.apple.security"); static CFStringRef kUpdateServerKey = CFSTR("ValidUpdateServer"); static CFStringRef kUpdateEnabledKey = CFSTR("ValidUpdateEnabled"); static CFStringRef kUpdateIntervalKey = CFSTR("ValidUpdateInterval"); -static CFStringRef kUpdateWiFiOnlyKey = CFSTR("ValidUpdateWiFiOnly"); typedef CF_OPTIONS(CFOptionFlags, SecValidInfoFlags) { kSecValidInfoComplete = 1u << 0, kSecValidInfoCheckOCSP = 1u << 1, kSecValidInfoKnownOnly = 1u << 2, kSecValidInfoRequireCT = 1u << 3, - kSecValidInfoAllowlist = 1u << 4 + kSecValidInfoAllowlist = 1u << 4, + kSecValidInfoNoCACheck = 1u << 5 }; -/* minimum initial interval after process startup */ +/* minimum update interval */ #define kSecMinUpdateInterval (60.0 * 5) -/* second and subsequent intervals */ +/* standard update interval */ #define kSecStdUpdateInterval (60.0 * 60) /* maximum allowed interval */ #define kSecMaxUpdateInterval (60.0 * 60 * 24 * 7) -/* background download timeout */ -#define kSecMaxDownloadSeconds (60.0 * 10) - #define kSecRevocationBasePath "/Library/Keychains/crls" +#define kSecRevocationCurUpdateFile "update-current" #define kSecRevocationDbFileName "valid.sqlite3" +#define kSecRevocationDbReplaceFile ".valid_replace" + +/* database schema version + v1 = initial version + v2 = fix for group entry transitions + v3 = handle optional entries in update dictionaries + v4 = add db_format and db_source entries + + Note: kSecRevocationDbMinSchemaVersion is the lowest version whose + results can be used. This allows revocation results to be obtained + from an existing db before the next update interval occurs, at which + time we'll update to the current version (kSecRevocationDbSchemaVersion). +*/ +#define kSecRevocationDbSchemaVersion 4 /* current version we support */ +#define kSecRevocationDbMinSchemaVersion 3 /* minimum version we can use */ + +/* update file format +*/ +CF_ENUM(CFIndex) { + kSecValidUpdateFormatG1 = 1, /* initial version */ + kSecValidUpdateFormatG2 = 2, /* signed content, single plist */ + kSecValidUpdateFormatG3 = 3 /* signed content, multiple plists */ +}; -bool SecRevocationDbVerifyUpdate(CFDictionaryRef update); -CFIndex SecRevocationDbIngestUpdate(CFDictionaryRef update); +#define kSecRevocationDbUpdateFormat 3 /* current version we support */ +#define kSecRevocationDbMinUpdateFormat 2 /* minimum version we can use */ + +bool SecRevocationDbVerifyUpdate(void *update, CFIndex length); +CFIndex SecRevocationDbIngestUpdate(CFDictionaryRef update, CFIndex chunkVersion); void SecRevocationDbApplyUpdate(CFDictionaryRef update, CFIndex version); -CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFDictionaryRef update); +CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFIndex updateInterval); void SecRevocationDbSetSchemaVersion(CFIndex dbversion); +CFIndex SecRevocationDbGetUpdateFormat(void); +void SecRevocationDbSetUpdateFormat(CFIndex dbformat); +void SecRevocationDbSetUpdateSource(CFStringRef source); +CFStringRef SecRevocationDbCopyUpdateSource(void); void SecRevocationDbSetNextUpdateTime(CFAbsoluteTime nextUpdate); CFAbsoluteTime SecRevocationDbGetNextUpdateTime(void); dispatch_queue_t SecRevocationDbGetUpdateQueue(void); void SecRevocationDbRemoveAllEntries(void); +void SecRevocationDbReleaseAllConnections(void); static CFDataRef copyInflatedData(CFDataRef data) { @@ -150,6 +181,64 @@ static CFDataRef copyInflatedData(CFDataRef data) { return (CFDataRef)outData; } +static CFDataRef copyInflatedDataToFile(CFDataRef data, char *fileName) { + if (!data) { + return NULL; + } + z_stream zs; + memset(&zs, 0, sizeof(zs)); + /* 32 is a magic value which enables automatic header detection + of gzip or zlib compressed data. */ + if (inflateInit2(&zs, 32+MAX_WBITS) != Z_OK) { + return NULL; + } + zs.next_in = (UInt8 *)(CFDataGetBytePtr(data)); + zs.avail_in = (uInt)CFDataGetLength(data); + + (void)remove(fileName); /* We need an empty file to start */ + int fd; + off_t off; + fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (fd < 0 || (off = lseek(fd, 0, SEEK_SET)) < 0) { + secerror("unable to open %s (errno %d)", fileName, errno); + if (fd >= 0) { + close(fd); + } + return NULL; + } + + CFIndex buf_sz = malloc_good_size(zs.avail_in ? zs.avail_in : 1024 * 4); + unsigned char *buf = malloc(buf_sz); + int rc; + do { + zs.next_out = (Bytef*)buf; + zs.avail_out = (uInt)buf_sz; + rc = inflate(&zs, 0); + if (off < (int64_t)zs.total_out) { + off = write(fd, buf, (int64_t)zs.total_out - off); + } + } while (rc == Z_OK); + close(fd); + + inflateEnd(&zs); + + if (buf) { + free(buf); + } + if (rc != Z_STREAM_END) { + (void)remove(fileName); + return NULL; + } + + /* Now return an mmapped version of that data */ + CFDataRef outData = NULL; + if ((rc = readValidFile(fileName, &outData)) != 0) { + secerror("unable to read and map %s (errno %d)", fileName, rc); + CFReleaseNull(outData); + } + return outData; +} + static CFDataRef copyDeflatedData(CFDataRef data) { if (!data) { return NULL; @@ -200,101 +289,79 @@ static CFDataRef copyDeflatedData(CFDataRef data) { return (CFDataRef)outData; } -static uint32_t calculateCrc32(CFDataRef data) { - if (!data) { return 0; } - uint32_t crc = (uint32_t)crc32(0L, Z_NULL, 0); - uint32_t len = (uint32_t)CFDataGetLength(data); - const unsigned char *bytes = CFDataGetBytePtr(data); - return (uint32_t)crc32(crc, bytes, len); -} - -static int checkBasePath(const char *basePath) { - return mkpath_np((char*)basePath, 0755); -} - -static int writeFile(const char *fileName, - const unsigned char *bytes, // compressed data, if crc != 0 - size_t numBytes, // length of content to write - uint32_t crc, // crc32 over uncompressed content - uint32_t length) { // uncompressed content length +/* Read file opens the file, mmaps it and then closes the file. */ +int readValidFile(const char *fileName, + CFDataRef *bytes) { // mmapped and returned -- must be munmapped! int rtn, fd; - off_t off; - size_t numToWrite=numBytes; - const unsigned char *p=bytes; - - fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0644); - if(fd < 0) { return errno; } - off = lseek(fd, 0, SEEK_SET); - if(off < 0) { return errno; } - if(crc) { - /* add gzip header per RFC1952 2.2 */ - uint8_t hdr[10] = { 31, 139, 8, 0, 0, 0, 0, 0, 2, 3 }; - write(fd, hdr, sizeof(hdr)); - /* skip 2-byte stream header and 4-byte trailing CRC */ - if (numToWrite > 6) { - numToWrite -= 6; - p += 2; - } - } - off = write(fd, p, numToWrite); - if((size_t)off != numToWrite) { - rtn = EIO; - } else { - rtn = 0; - } - if(crc) { - /* add gzip trailer per RFC1952 2.2 */ - /* note: gzip seems to want these values in host byte order. */ - write(fd, &crc, sizeof(crc)); - write(fd, &length, sizeof(length)); - } - close(fd); - return rtn; -} - -static int readFile(const char *fileName, - CFDataRef *bytes) { // allocated and returned - int rtn, fd; - char *buf; + const uint8_t *buf = NULL; struct stat sb; - size_t size; - ssize_t rrc; + size_t size = 0; *bytes = NULL; fd = open(fileName, O_RDONLY); - if(fd < 0) { return errno; } + if (fd < 0) { return errno; } rtn = fstat(fd, &sb); - if(rtn) { goto errOut; } + if (rtn) { goto errOut; } if (sb.st_size > (off_t) ((UINT32_MAX >> 1)-1)) { rtn = EFBIG; goto errOut; } size = (size_t)sb.st_size; - *bytes = (CFDataRef)CFDataCreateMutable(NULL, (CFIndex)size); - if(!*bytes) { - rtn = ENOMEM; + buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (!buf || buf == MAP_FAILED) { + rtn = errno; + secerror("unable to map %s (errno %d)", fileName, rtn); goto errOut; } - CFDataSetLength((CFMutableDataRef)*bytes, (CFIndex)size); - buf = (char*)CFDataGetBytePtr(*bytes); - rrc = read(fd, buf, size); - if(rrc != (ssize_t) size) { - rtn = EIO; - } - else { - rtn = 0; - } + *bytes = CFDataCreateWithBytesNoCopy(NULL, buf, size, kCFAllocatorNull); errOut: close(fd); if(rtn) { CFReleaseNull(*bytes); + if (buf) { + int unmap_err = munmap((void *)buf, size); + if (unmap_err != 0) { + secerror("unable to unmap %ld bytes at %p (error %d)", (long)size, buf, rtn); + } + } } return rtn; } +static void unmapData(CFDataRef CF_CONSUMED data) { + if (data) { + int rtn = munmap((void *)CFDataGetBytePtr(data), CFDataGetLength(data)); + if (rtn != 0) { + secerror("unable to unmap %ld bytes at %p (error %d)", CFDataGetLength(data), CFDataGetBytePtr(data), rtn); + } + + } + CFReleaseNull(data); +} + +static bool removeFileWithSuffix(const char *basepath, const char *suffix) { + bool result = false; + char *path = NULL; + asprintf(&path, "%s%s", basepath, suffix); + if (path) { + if (remove(path) == -1) { + int error = errno; + if (error == ENOENT) { + result = true; // not an error if the file did not exist + } else { + secnotice("validupdate", "remove (%s): %s", path, strerror(error)); + } + } else { + result = true; + } + free(path); + } + return result; +} + static bool isDbOwner() { #if TARGET_OS_EMBEDDED if (getuid() == 64) // _securityd @@ -309,309 +376,400 @@ static bool isDbOwner() { // MARK: - -// MARK: SecValidUpdateRequest +// MARK: SecValidUpdate /* ====================================================================== - SecValidUpdateRequest + SecValidUpdate ======================================================================*/ -static CFAbsoluteTime gUpdateRequestScheduled = 0.0; -static CFAbsoluteTime gNextUpdate = 0.0; +CFAbsoluteTime gUpdateStarted = 0.0; +CFAbsoluteTime gNextUpdate = 0.0; static CFIndex gUpdateInterval = 0; static CFIndex gLastVersion = 0; -typedef struct SecValidUpdateRequest *SecValidUpdateRequestRef; -struct SecValidUpdateRequest { - asynchttp_t http; /* Must be first field. */ - CFStringRef server; /* Server name. (e.g. "valid.apple.com") */ - CFIndex version; /* Our current version. */ - xpc_object_t criteria; /* Constraints dictionary for request. */ -}; +/* Update Format: + 1. The length of the signed data, as a 4-byte integer in network byte order. + 2. The signed data, which consists of: + a. A 4-byte integer in network byte order, the count of plists to follow; and then for each plist: + i. A 4-byte integer, the length of each plist + ii. A plist, in binary form + b. There may be other data after the plists in the signed data, described by a future version of this specification. + 3. The length of the following CMS blob, as a 4-byte integer in network byte order. + 4. A detached CMS signature of the signed data described above. + 5. There may be additional data after the CMS blob, described by a future version of this specification. + + Note: the difference between g2 and g3 format is the addition of the 4-byte count in (2a). +*/ +static bool SecValidUpdateProcessData(CFIndex format, CFDataRef updateData) { + if (!updateData || format < 2) { + return false; + } + bool result = false; + CFIndex version = 0; + CFIndex interval = 0; + const UInt8* p = CFDataGetBytePtr(updateData); + CFIndex bytesRemaining = (p) ? CFDataGetLength(updateData) : 0; + /* make sure there is enough data to contain length and count */ + if (bytesRemaining < ((CFIndex)sizeof(uint32_t) * 2)) { + secinfo("validupdate", "Skipping property list creation (length %ld is too short)", (long)bytesRemaining); + return result; + } + /* get length of signed data */ + uint32_t dataLength = OSSwapInt32(*((uint32_t *)p)); + bytesRemaining -= sizeof(uint32_t); + p += sizeof(uint32_t); + + /* get plist count (G3 format and later) */ + uint32_t plistCount = 1; + uint32_t plistTotal = 1; + if (format > kSecValidUpdateFormatG2) { + plistCount = OSSwapInt32(*((uint32_t *)p)); + plistTotal = plistCount; + bytesRemaining -= sizeof(uint32_t); + p += sizeof(uint32_t); + } + if (dataLength > bytesRemaining) { + secinfo("validupdate", "Skipping property list creation (dataLength=%ld, bytesRemaining=%ld)", + (long)dataLength, (long)bytesRemaining); + return result; + } + + /* process each chunked plist */ + uint32_t plistProcessed = 0; + while (plistCount > 0 && bytesRemaining > 0) { + CFPropertyListRef propertyList = NULL; + uint32_t plistLength = dataLength; + if (format > kSecValidUpdateFormatG2) { + plistLength = OSSwapInt32(*((uint32_t *)p)); + bytesRemaining -= sizeof(uint32_t); + p += sizeof(uint32_t); + } + --plistCount; + ++plistProcessed; -static void SecValidUpdateRequestRelease(SecValidUpdateRequestRef request) { - if (!request) { - return; + /* We're about to use a lot of memory for the plist -- go active so we don't get jetsammed */ + os_transaction_t transaction; + transaction = os_transaction_create("com.apple.trustd.valid"); + + if (plistLength <= bytesRemaining) { + CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, p, plistLength, kCFAllocatorNull); + propertyList = CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable, NULL, NULL); + CFReleaseNull(data); + } + if (isDictionary(propertyList)) { + secdebug("validupdate", "Ingesting plist chunk %u of %u, length: %u", + plistProcessed, plistTotal, plistLength); + CFIndex curVersion = SecRevocationDbIngestUpdate((CFDictionaryRef)propertyList, version); + if (plistProcessed == 1) { + version = curVersion; + // get server-provided interval + CFTypeRef value = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)propertyList, + CFSTR("check-again")); + if (isNumber(value)) { + CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &interval); + } + } + if (curVersion < 0) { + plistCount = 0; // we already had this version; skip remaining plists + result = true; + } + } else { + secinfo("validupdate", "Failed to deserialize update chunk %u of %u", + plistProcessed, plistTotal); + if (plistProcessed == 1) { + gNextUpdate = SecRevocationDbComputeNextUpdateTime(0); + } + } + /* All finished with this property list */ + CFReleaseSafe(propertyList); + os_release(transaction); + + bytesRemaining -= plistLength; + p += plistLength; } - CFReleaseSafe(request->server); - asynchttp_free(&request->http); - if (request->criteria) { - xpc_release(request->criteria); + + if (version > 0) { + secdebug("validupdate", "Update received: v%lu", (unsigned long)version); + gLastVersion = version; + gNextUpdate = SecRevocationDbComputeNextUpdateTime(interval); + secdebug("validupdate", "Next update time: %f", gNextUpdate); + result = true; } - free(request); -} -static void SecValidUpdateRequestIssue(SecValidUpdateRequestRef request) { - // issue the async http request now - CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("https://%@/get/v%ld"), - request->server, (long)request->version); + // remember next update time in case of restart + SecRevocationDbSetNextUpdateTime(gNextUpdate); + + return result; +} - CFURLRef url = (urlStr) ? CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL) : NULL; - CFReleaseSafe(urlStr); - if (!url) { - secnotice("validupdate", "invalid update url"); - SecValidUpdateRequestRelease(request); +void SecValidUpdateVerifyAndIngest(CFDataRef updateData) { + if (!updateData) { + secnotice("validupdate", "invalid update data"); return; } - CFHTTPMessageRef msg = CFHTTPMessageCreateRequest(kCFAllocatorDefault, - CFSTR("GET"), url, kCFHTTPVersion1_1); - CFReleaseSafe(url); - if (msg) { - secdebug("validupdate", "%@", msg); - CFHTTPMessageSetHeaderFieldValue(msg, CFSTR("Accept"), CFSTR("*/*")); - CFHTTPMessageSetHeaderFieldValue(msg, kAcceptEncoding, kAppEncoding); - CFHTTPMessageSetHeaderFieldValue(msg, kUserAgent, kAppUserAgent); - bool done = asynchttp_request(msg, kSecMaxDownloadSeconds*NSEC_PER_SEC, &request->http); - CFReleaseSafe(msg); - if (done == false) { - return; + /* Verify CMS signature on signed data */ + if (SecRevocationDbVerifyUpdate((void *)CFDataGetBytePtr(updateData), CFDataGetLength(updateData))) { + bool result = SecValidUpdateProcessData(kSecValidUpdateFormatG3, updateData); + if (!result) { + // Try g2 update format as a fallback if we failed to read g3 + result = SecValidUpdateProcessData(kSecValidUpdateFormatG2, updateData); + } + if (!result) { + secerror("failed to process valid update"); } + } else { + secerror("failed to verify valid update"); } - secdebug("validupdate", "no request issued"); - SecValidUpdateRequestRelease(request); } -static bool SecValidUpdateRequestSchedule(SecValidUpdateRequestRef request) { - if (!request || !request->server) { - secnotice("validupdate", "invalid update request"); - SecValidUpdateRequestRelease(request); - return false; - } else if (gUpdateRequestScheduled != 0.0) { - // TBD: may need a separate scheduled activity which can perform a request with - // fewer constraints if our request has not been satisfied for a week or so - secdebug("validupdate", "update request already scheduled at %f, will not reissue", - (double)gUpdateRequestScheduled); - SecValidUpdateRequestRelease(request); - return true; // request is still in the queue - } else { - gUpdateRequestScheduled = CFAbsoluteTimeGetCurrent(); - secdebug("validupdate", "scheduling update at %f", (double)gUpdateRequestScheduled); - } +static bool SecValidUpdateFromCompressed(CFDataRef CF_CONSUMED data) { + if (!data) { return false; } - // determine whether to issue request without waiting for activity criteria to be satisfied - bool updateOnWiFiOnly = true; - CFTypeRef value = (CFBooleanRef)CFPreferencesCopyValue(kUpdateWiFiOnlyKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (isBoolean(value)) { - updateOnWiFiOnly = CFBooleanGetValue((CFBooleanRef)value); - } - CFReleaseNull(value); - if (!updateOnWiFiOnly) { - SecValidUpdateRequestIssue(request); - gUpdateRequestScheduled = 0.0; - return true; + /* We're about to use a lot of memory for the uncompressed update -- go active */ + os_transaction_t transaction; + transaction = os_transaction_create("com.apple.trustd.valid"); + + /* Expand the update */ + __block CFDataRef inflatedData = NULL; + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationCurUpdateFile), ^(const char *curUpdatePath) { + inflatedData = copyInflatedDataToFile(data, (char *)curUpdatePath); + secdebug("validupdate", "data expanded: %ld bytes", (long)CFDataGetLength(inflatedData)); + }); + unmapData(data); + os_release(transaction); + + if (inflatedData) { + SecValidUpdateVerifyAndIngest(inflatedData); + unmapData(inflatedData); } - xpc_object_t criteria = xpc_dictionary_create(NULL, NULL, 0); - xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_REPEATING, false); - xpc_dictionary_set_string(criteria, XPC_ACTIVITY_PRIORITY, XPC_ACTIVITY_PRIORITY_MAINTENANCE); - // we want to start as soon as possible - xpc_dictionary_set_int64(criteria, XPC_ACTIVITY_DELAY, 0); - xpc_dictionary_set_int64(criteria, XPC_ACTIVITY_GRACE_PERIOD, 5); - // we are downloading data and want to use WiFi instead of cellular - xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_REQUIRE_NETWORK_CONNECTIVITY, true); - xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_REQUIRE_INEXPENSIVE_NETWORK_CONNECTIVITY, true); - xpc_dictionary_set_string(criteria, XPC_ACTIVITY_NETWORK_TRANSFER_DIRECTION, XPC_ACTIVITY_NETWORK_TRANSFER_DIRECTION_DOWNLOAD); - - if (request->criteria) { - xpc_release(request->criteria); - } - request->criteria = criteria; - - xpc_activity_register("com.apple.trustd.validupdate", criteria, ^(xpc_activity_t activity) { - xpc_activity_state_t activityState = xpc_activity_get_state(activity); - switch (activityState) { - case XPC_ACTIVITY_STATE_CHECK_IN: { - secdebug("validupdate", "xpc activity state: XPC_ACTIVITY_STATE_CHECK_IN"); - break; - } - case XPC_ACTIVITY_STATE_RUN: { - secdebug("validupdate", "xpc activity state: XPC_ACTIVITY_STATE_RUN"); - if (!xpc_activity_set_state(activity, XPC_ACTIVITY_STATE_CONTINUE)) { - secnotice("validupdate", "unable to set activity state to XPC_ACTIVITY_STATE_CONTINUE"); - } - // criteria for this activity have been met; issue the network request - SecValidUpdateRequestIssue(request); - gUpdateRequestScheduled = 0.0; - if (!xpc_activity_set_state(activity, XPC_ACTIVITY_STATE_DONE)) { - secnotice("validupdate", "unable to set activity state to XPC_ACTIVITY_STATE_DONE"); - } - break; - } - default: { - secdebug("validupdate", "unhandled activity state (%ld)", (long)activityState); - break; - } - } + /* All done with the temporary file */ + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationCurUpdateFile), ^(const char *curUpdatePath) { + (void)removeFileWithSuffix(curUpdatePath, ""); }); return true; } -static bool SecValidUpdateRequestConsumeReply(CF_CONSUMED CFDataRef data, CFIndex version, bool save) { - if (!data) { - secnotice("validupdate", "invalid data"); - return false; - } - CFIndex length = CFDataGetLength(data); - secdebug("validupdate", "data received: %ld bytes", (long)length); +static bool SecValidDatabaseFromCompressed(CFDataRef CF_CONSUMED data) { + if (!data) { return false; } + + secdebug("validupdate", "read %ld bytes from file", (long)CFDataGetLength(data)); + + /* We're about to use a lot of memory for the uncompressed update -- go active */ + os_transaction_t transaction; + transaction = os_transaction_create("com.apple.trustd.valid"); + + /* Expand the database */ + __block CFDataRef inflatedData = NULL; + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbFileName), ^(const char *dbPath) { + inflatedData = copyInflatedDataToFile(data, (char *)dbPath); + secdebug("validupdate", "data expanded: %ld bytes", (long)CFDataGetLength(inflatedData)); + }); + unmapData(data); + os_release(transaction); - char *curPathBuf = NULL; - if (save) { - checkBasePath(kSecRevocationBasePath); - asprintf(&curPathBuf, "%s/%s.plist.gz", kSecRevocationBasePath, "update-current"); - } - // expand compressed data - CFDataRef inflatedData = copyInflatedData(data); if (inflatedData) { - CFIndex cmplength = length; - length = CFDataGetLength(inflatedData); - if (curPathBuf) { - uint32_t crc = calculateCrc32(inflatedData); - writeFile(curPathBuf, CFDataGetBytePtr(data), cmplength, crc, (uint32_t)length); - } - CFReleaseSafe(data); - data = inflatedData; + unmapData(inflatedData); } - secdebug("validupdate", "data expanded: %ld bytes", (long)length); - - // mmap the expanded data while property list object is created - CFPropertyListRef propertyList = NULL; - char *expPathBuf = NULL; - asprintf(&expPathBuf, "%s/%s.plist", kSecRevocationBasePath, "update-current"); - if (expPathBuf) { - writeFile(expPathBuf, CFDataGetBytePtr(data), length, 0, (uint32_t)length); - CFReleaseNull(data); - // no copies of data should exist in memory at this point - int fd = open(expPathBuf, O_RDONLY); - if (fd < 0) { - secerror("unable to open %s (errno %d)", expPathBuf, errno); - } - else { - void *p = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0); - if (!p || p == MAP_FAILED) { - secerror("unable to map %s (errno %d)", expPathBuf, errno); - } - else { - data = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)p, length, kCFAllocatorNull); - if (data) { - propertyList = CFPropertyListCreateWithData(kCFAllocatorDefault, data, - kCFPropertyListImmutable, NULL, NULL); - } - int rtn = munmap(p, length); - if (rtn != 0) { - secerror("unable to unmap %ld bytes at %p (error %d)", (long)length, p, rtn); - } + return true; +} + +static bool SecValidUpdateSatisfiedLocally(CFStringRef server, CFIndex version, bool safeToReplace) { + __block bool result = false; + CFDataRef data = NULL; + SecOTAPKIRef otapkiRef = NULL; + int rtn = 0; + static int sNumLocalUpdates = 0; + + // if we've replaced the database with a local asset twice in a row, + // something is wrong with it. Get this update from the server. + if (sNumLocalUpdates > 1) { + secdebug("validupdate", "%d consecutive db resets, ignoring local asset", sNumLocalUpdates); + goto updateExit; + } + + // if a non-production server is specified, we will not be able to use a + // local production asset since its update sequence will be different. + if (kCFCompareEqualTo != CFStringCompare(server, kValidUpdateServer, + kCFCompareCaseInsensitive)) { + secdebug("validupdate", "non-production server specified, ignoring local asset"); + goto updateExit; + } + + // check static database asset(s) + otapkiRef = SecOTAPKICopyCurrentOTAPKIRef(); + if (!otapkiRef) { + goto updateExit; + } + CFIndex assetVersion = SecOTAPKIGetValidSnapshotVersion(otapkiRef); + CFIndex assetFormat = SecOTAPKIGetValidSnapshotFormat(otapkiRef); + // version <= 0 means the database is invalid or empty. + // version > 0 means we have some version, but we need to see if a + // newer version is available as a local asset. + if (assetVersion <= version || assetFormat < kSecValidUpdateFormatG3) { + // asset is not newer than ours, or its version is unknown + goto updateExit; + } + + // replace database only if safe to do so (i.e. called at startup) + if (!safeToReplace) { + // write semaphore file that we will pick up when we next launch + char *semPathBuf = NULL; + asprintf(&semPathBuf, "%s/%s", kSecRevocationBasePath, kSecRevocationDbReplaceFile); + if (semPathBuf) { + struct stat sb; + int fd = open(semPathBuf, O_WRONLY | O_CREAT, DEFFILEMODE); + if (fd == -1 || fstat(fd, &sb) || close(fd)) { + secnotice("validupdate", "unable to write %s", semPathBuf); } - (void)close(fd); + free(semPathBuf); } - // all done with this file - (void)remove(expPathBuf); - free(expPathBuf); + // exit as gracefully as possible so we can replace the database + secnotice("validupdate", "process exiting to replace db file"); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + xpc_transaction_exit_clean(); + }); + goto updateExit; + } + + // try to copy uncompressed database asset, if available + const char *validDbPathBuf = SecOTAPKIGetValidDatabaseSnapshot(otapkiRef); + if (validDbPathBuf) { + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbFileName), ^(const char *path) { + secdebug("validupdate", "will copy data from \"%s\"", validDbPathBuf); + copyfile_state_t state = copyfile_state_alloc(); + int retval = copyfile(validDbPathBuf, path, state, COPYFILE_DATA); + copyfile_state_free(state); + if (retval < 0) { + secnotice("validupdate", "copyfile error %d", retval); + } else { + result = true; + } + }); + } + if (result) { + goto updateExit; } - CFReleaseSafe(data); - CFIndex curVersion = version; - Boolean fullUpdate = false; - if (isDictionary(propertyList)) { - if (SecRevocationDbVerifyUpdate((CFDictionaryRef)propertyList)) { - CFTypeRef value = (CFBooleanRef)CFDictionaryGetValue((CFDictionaryRef)propertyList, CFSTR("full")); - if (isBoolean(value)) { - fullUpdate = CFBooleanGetValue((CFBooleanRef)value); + // see if compressed database asset is available + if (validDbPathBuf) { + char *validDbCmpPathBuf = NULL; + asprintf(&validDbCmpPathBuf, "%s%s", validDbPathBuf, ".gz"); + if (validDbCmpPathBuf) { + secdebug("validupdate", "will read data from \"%s\"", validDbCmpPathBuf); + if ((rtn = readValidFile(validDbCmpPathBuf, &data)) != 0) { + unmapData(data); + data = NULL; + secnotice("validupdate", "readValidFile error %d", rtn); } - curVersion = SecRevocationDbIngestUpdate((CFDictionaryRef)propertyList); - gNextUpdate = SecRevocationDbComputeNextUpdateTime((CFDictionaryRef)propertyList); + free(validDbCmpPathBuf); } - } else { - secerror("update failed: could not create property list"); } - CFReleaseSafe(propertyList); + result = SecValidDatabaseFromCompressed(data); + if (result) { + goto updateExit; + } - if (curVersion > version) { - secdebug("validupdate", "update received: v%ld", (unsigned long)curVersion); - // save this update and make it current - char *newPathBuf = NULL; - if (fullUpdate) { - asprintf(&newPathBuf, "%s/update-full.plist.gz", kSecRevocationBasePath); - //%%% glob and remove all "update-v*.plist.gz" files here - } - else { - asprintf(&newPathBuf, "%s/update-v%ld.plist.gz", kSecRevocationBasePath, (unsigned long)curVersion); - } - if (newPathBuf) { - if (curPathBuf) { - if (fullUpdate) { - // try to save the latest full update - (void)rename(curPathBuf, newPathBuf); - } - else { - // try to remove delta updates - (void)remove(curPathBuf); - } - } - free(newPathBuf); + // unable to use database asset; try update asset + const char *validUpdatePathBuf = SecOTAPKIGetValidUpdateSnapshot(otapkiRef); + if (validUpdatePathBuf) { + secdebug("validupdate", "will read data from \"%s\"", validUpdatePathBuf); + if ((rtn = readValidFile(validUpdatePathBuf, &data)) != 0) { + unmapData(data); + data = NULL; + secnotice("validupdate", "readValidFile error %d", rtn); } - gLastVersion = curVersion; } - if (curPathBuf) { - free(curPathBuf); + result = SecValidUpdateFromCompressed(data); + +updateExit: + CFReleaseNull(otapkiRef); + if (result) { + sNumLocalUpdates++; + SecRevocationDbSetUpdateSource(server); + gLastVersion = SecRevocationDbGetVersion(); + gUpdateStarted = 0; + secdebug("validupdate", "local update to g%ld/v%ld complete at %f", + (long)SecRevocationDbGetUpdateFormat(), (long)gLastVersion, + (double)CFAbsoluteTimeGetCurrent()); + } else { + sNumLocalUpdates = 0; // reset counter } - - // remember next update time in case of restart - SecRevocationDbSetNextUpdateTime(gNextUpdate); - - return true; + return result; } -static bool SecValidUpdateRequestSatisfiedLocally(SecValidUpdateRequestRef request) { - // if we can read the requested data locally, we don't need a network request. - - // note: only need this if we don't have any version and are starting from scratch. - // otherwise we don't know what the current version actually is; only the server - // can tell us that at any given time, so we have to ask it for any version >0. - // we cannot reuse a saved delta without being on the exact version from which - // it was generated. - // TBD: - // - if requested version N is 0, and no 'update-full' in kSecRevocationBasePath, - // call a OTATrustUtilities SPI to obtain static 'update-full' asset data. - - CFDataRef data = NULL; - char *curPathBuf = NULL; - if (0 == request->version) { - asprintf(&curPathBuf, "%s/update-full.plist.gz", kSecRevocationBasePath); +static bool SecValidUpdateSchedule(bool updateEnabled, CFStringRef server, CFIndex version) { + /* Check if we have a later version available locally */ + if (SecValidUpdateSatisfiedLocally(server, version, false)) { + return true; } - else { + + /* If update not permitted return */ + if (!updateEnabled) { return false; - //asprintf(&curPathBuf, "%s/update-v%ld.plist.gz", kSecRevocationBasePath, (unsigned long)request->version); - } - if (curPathBuf) { - secdebug("validupdate", "will read data from \"%s\"", curPathBuf); - int rtn = readFile(curPathBuf, &data); - free(curPathBuf); - if (rtn) { CFReleaseNull(data); } - } - if (data) { - secdebug("validupdate", "read %ld bytes from file", (long)CFDataGetLength(data)); - //%%% TBD dispatch this work on the request's queue and return true immediately - return SecValidUpdateRequestConsumeReply(data, request->version, false); } + +#if !TARGET_OS_BRIDGE + /* Schedule as a maintenance task */ + return SecValidUpdateRequest(SecRevocationDbGetUpdateQueue(), server, version); +#else return false; +#endif } -static void SecValidUpdateRequestCompleted(asynchttp_t *http, CFTimeInterval maxAge) { - // cast depends on http being first field in struct SecValidUpdateRequest. - SecValidUpdateRequestRef request = (SecValidUpdateRequestRef)http; - if (!request) { - secnotice("validupdate", "no request to complete!"); - return; +void SecRevocationDbInitialize() { + if (!isDbOwner()) { return; } + __block bool initializeDb = false; + + /* create base path if it doesn't exist */ + (void)mkpath_np(kSecRevocationBasePath, 0755); + + /* check semaphore file */ + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbReplaceFile), ^(const char *path) { + struct stat sb; + if (stat(path, &sb) == 0) { + initializeDb = true; /* file was found, so we will replace the database */ + if (remove(path) == -1) { + int error = errno; + secnotice("validupdate", "remove (%s): %s", path, strerror(error)); + } + } + }); + + /* check database */ + WithPathInRevocationInfoDirectory(CFSTR(kSecRevocationDbFileName), ^(const char *path) { + if (initializeDb) { + /* remove old database file(s) */ + (void)removeFileWithSuffix(path, ""); + (void)removeFileWithSuffix(path, "-journal"); + (void)removeFileWithSuffix(path, "-shm"); + (void)removeFileWithSuffix(path, "-wal"); + } + else { + struct stat sb; + if (stat(path, &sb) == -1) { + initializeDb = true; /* file not found, so we will create the database */ + } + } + }); + + if (!initializeDb) { + return; /* database exists and doesn't need replacing */ } - CFDataRef data = (request->http.response) ? CFHTTPMessageCopyBody(request->http.response) : NULL; - CFIndex version = request->version; - SecValidUpdateRequestRelease(request); - if (!data) { - secdebug("validupdate", "no data received"); - return; + + /* initialize database from local asset */ + CFTypeRef value = (CFStringRef)CFPreferencesCopyValue(kUpdateServerKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + CFStringRef server = (isString(value)) ? (CFStringRef)value : (CFStringRef)kValidUpdateServer; + CFIndex version = 0; + secnotice("validupdate", "initializing database"); + if (!SecValidUpdateSatisfiedLocally(server, version, true)) { +#if !TARGET_OS_BRIDGE + /* Schedule full update as a maintenance task */ + (void)SecValidUpdateRequest(SecRevocationDbGetUpdateQueue(), server, version); +#endif } - SecValidUpdateRequestConsumeReply(data, version, true); + CFReleaseSafe(value); } @@ -625,8 +783,10 @@ static void SecValidUpdateRequestCompleted(asynchttp_t *http, CFTimeInterval max static SecValidInfoRef SecValidInfoCreate(SecValidInfoFormat format, CFOptionFlags flags, + bool isOnList, CFDataRef certHash, - CFDataRef issuerHash) { + CFDataRef issuerHash, + CFDataRef anchorHash) { SecValidInfoRef validInfo; validInfo = (SecValidInfoRef)calloc(1, sizeof(struct __SecValidInfo)); if (!validInfo) { return NULL; } @@ -636,11 +796,14 @@ static SecValidInfoRef SecValidInfoCreate(SecValidInfoFormat format, validInfo->format = format; validInfo->certHash = certHash; validInfo->issuerHash = issuerHash; + validInfo->anchorHash = anchorHash; + validInfo->isOnList = isOnList; validInfo->valid = (flags & kSecValidInfoAllowlist); validInfo->complete = (flags & kSecValidInfoComplete); validInfo->checkOCSP = (flags & kSecValidInfoCheckOCSP); validInfo->knownOnly = (flags & kSecValidInfoKnownOnly); validInfo->requireCT = (flags & kSecValidInfoRequireCT); + validInfo->noCACheck = (flags & kSecValidInfoNoCACheck); return validInfo; } @@ -649,10 +812,28 @@ void SecValidInfoRelease(SecValidInfoRef validInfo) { if (validInfo) { CFReleaseSafe(validInfo->certHash); CFReleaseSafe(validInfo->issuerHash); + CFReleaseSafe(validInfo->anchorHash); free(validInfo); } } +void SecValidInfoSetAnchor(SecValidInfoRef validInfo, SecCertificateRef anchor) { + if (!validInfo) { + return; + } + CFDataRef anchorHash = NULL; + if (anchor) { + anchorHash = SecCertificateCopySHA256Digest(anchor); + + /* clear no-ca flag for anchors where we want OCSP checked [32523118] */ + if (SecIsAppleTrustAnchor(anchor, 0)) { + validInfo->noCACheck = false; + } + } + CFReleaseNull(validInfo->anchorHash); + validInfo->anchorHash = anchorHash; +} + // MARK: - // MARK: SecRevocationDb @@ -665,7 +846,7 @@ void SecValidInfoRelease(SecValidInfoRef validInfo) { /* SecRevocationDbCheckNextUpdate returns true if we dispatched an update request, otherwise false. */ -bool SecRevocationDbCheckNextUpdate(void) { +static bool _SecRevocationDbCheckNextUpdate(void) { // are we the db owner instance? if (!isDbOwner()) { return false; @@ -675,11 +856,12 @@ bool SecRevocationDbCheckNextUpdate(void) { // is it time to check? CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); CFAbsoluteTime minNextUpdate = now + gUpdateInterval; + gUpdateStarted = now; + if (0 == gNextUpdate) { // first time we're called, check if we have a saved nextUpdate value gNextUpdate = SecRevocationDbGetNextUpdateTime(); - // pin to minimum first-time interval, so we don't perturb startup - minNextUpdate = now + kSecMinUpdateInterval; + minNextUpdate = now; if (gNextUpdate < minNextUpdate) { gNextUpdate = minNextUpdate; } @@ -700,10 +882,19 @@ bool SecRevocationDbCheckNextUpdate(void) { if (interval > 0) { gUpdateInterval = interval; } + // pin next update time to the preferred update interval + if (gNextUpdate > (gUpdateStarted + gUpdateInterval)) { + gNextUpdate = gUpdateStarted + gUpdateInterval; + } + secdebug("validupdate", "next update at %f (in %f seconds)", + (double)gUpdateStarted, (double)gNextUpdate-gUpdateStarted); } if (gNextUpdate > now) { + gUpdateStarted = 0; return false; } + secnotice("validupdate", "starting update"); + // set minimum next update time here in case we can't get an update gNextUpdate = minNextUpdate; @@ -717,7 +908,7 @@ bool SecRevocationDbCheckNextUpdate(void) { } CFReleaseNull(value); - // determine what version we currently have + // determine version of our current database CFIndex version = SecRevocationDbGetVersion(); secdebug("validupdate", "got version %ld from db", (long)version); if (version <= 0) { @@ -727,18 +918,27 @@ bool SecRevocationDbCheckNextUpdate(void) { 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(kValidUpdateServer); + } + // determine whether we need to recreate the database CFIndex db_version = SecRevocationDbGetSchemaVersion(); - if (db_version == 1) { - /* code which created this db failed to update changed flags, - so we need to fully rebuild its contents. */ + 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. */ SecRevocationDbRemoveAllEntries(); version = gLastVersion = 0; } // determine whether update fetching is enabled #if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) - bool updateEnabled = true; // macOS 10.13 or iOS 11.0, not tvOS, not watchOS + bool updateEnabled = true; // macOS 10.13 or iOS 11.0 #else bool updateEnabled = false; #endif @@ -748,40 +948,122 @@ bool SecRevocationDbCheckNextUpdate(void) { } CFReleaseNull(value); - // set up a network request - SecValidUpdateRequestRef request = (SecValidUpdateRequestRef)calloc(1, sizeof(*request)); - request->http.queue = SecRevocationDbGetUpdateQueue(); - request->http.completed = SecValidUpdateRequestCompleted; - request->server = server; - request->version = version; - request->criteria = NULL; + // Schedule maintenance work + bool result = SecValidUpdateSchedule(updateEnabled, server, version); + CFReleaseNull(server); + CFReleaseNull(db_source); + return result; +} - if (SecValidUpdateRequestSatisfiedLocally(request)) { - SecValidUpdateRequestRelease(request); - return true; +void SecRevocationDbCheckNextUpdate(void) { + static dispatch_once_t once; + static sec_action_t action; + + dispatch_once(&once, ^{ + dispatch_queue_t update_queue = SecRevocationDbGetUpdateQueue(); + action = sec_action_create_with_queue(update_queue, "update_check", kSecMinUpdateInterval); + sec_action_set_handler(action, ^{ + (void)_SecRevocationDbCheckNextUpdate(); + }); + }); + sec_action_perform(action); +} + +/* This function verifies an update, in this format: + 1) unsigned 32-bit network-byte-order length of binary plist + 2) binary plist data + 3) unsigned 32-bit network-byte-order length of CMS message + 4) CMS message (containing certificates and signature over binary plist) + + The length argument is the total size of the packed update data. +*/ +bool SecRevocationDbVerifyUpdate(void *update, CFIndex length) { + if (!update || length <= (CFIndex)sizeof(uint32_t)) { + return false; } - if (!updateEnabled) { - SecValidUpdateRequestRelease(request); + uint32_t plistLength = OSSwapInt32(*((uint32_t *)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); + return false; + } + uint8_t *plistData = (uint8_t *)update + sizeof(uint32_t); + uint8_t *sigData = (uint8_t *)plistData + plistLength; + uint32_t sigLength = OSSwapInt32(*((uint32_t *)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"); return false; } - return SecValidUpdateRequestSchedule(request); -} -bool SecRevocationDbVerifyUpdate(CFDictionaryRef update) { + OSStatus status = 0; + CMSSignerStatus signerStatus; + CMSDecoderRef cms = NULL; + SecPolicyRef policy = NULL; + SecTrustRef trust = NULL; + CFDataRef content = NULL; - //%%% TBD: check signature with new SecPolicyRef; rdar://28619456 - return true; -} + if ((content = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, + (const UInt8 *)plistData, (CFIndex)plistLength, kCFAllocatorNull)) == NULL) { + secdebug("validupdate", "CFDataCreateWithBytesNoCopy failed (%ld bytes)\n", (long)plistLength); + return false; + } -CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFDictionaryRef update) { - CFIndex interval = 0; - // get server-provided interval - if (update) { - CFTypeRef value = (CFNumberRef)CFDictionaryGetValue(update, CFSTR("check-again")); - if (isNumber(value)) { - CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &interval); - } + if ((status = CMSDecoderCreate(&cms)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderCreate failed with error %d\n", (int)status); + goto verifyExit; + } + if ((status = CMSDecoderUpdateMessage(cms, sigData, sigLength)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderUpdateMessage failed with error %d\n", (int)status); + goto verifyExit; + } + if ((status = CMSDecoderSetDetachedContent(cms, content)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderSetDetachedContent failed with error %d\n", (int)status); + goto verifyExit; + } + if ((status = CMSDecoderFinalizeMessage(cms)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderFinalizeMessage failed with error %d\n", (int)status); + goto verifyExit; + } + + policy = SecPolicyCreateApplePinned(CFSTR("ValidUpdate"), // kSecPolicyNameAppleValidUpdate + CFSTR("1.2.840.113635.100.6.2.10"), // System Integration 2 Intermediate Certificate + CFSTR("1.2.840.113635.100.6.51")); // Valid update signing OID + + // Check that the first signer actually signed this message. + if ((status = CMSDecoderCopySignerStatus(cms, 0, policy, + false, &signerStatus, &trust, NULL)) != errSecSuccess) { + secdebug("validupdate", "CMSDecoderCopySignerStatus failed with error %d\n", (int)status); + goto verifyExit; + } + // Make sure the signature verifies against the detached content + if (signerStatus != kCMSSignerValid) { + secdebug("validupdate", "ERROR: signature did not verify (signer status %d)\n", (int)signerStatus); + status = errSecInvalidSignature; + goto verifyExit; } + // Make sure the signing certificate is valid for the specified policy + SecTrustResultType trustResult = kSecTrustResultInvalid; + status = SecTrustEvaluate(trust, &trustResult); + if (status != errSecSuccess) { + secdebug("validupdate", "SecTrustEvaluate failed with error %d (trust=%p)\n", (int)status, (void *)trust); + } else if (!(trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)) { + secdebug("validupdate", "SecTrustEvaluate failed with trust result %d\n", (int)trustResult); + status = errSecVerificationFailure; + goto verifyExit; + } + +verifyExit: + CFReleaseSafe(content); + CFReleaseSafe(trust); + CFReleaseSafe(policy); + CFReleaseSafe(cms); + + return (status == errSecSuccess); +} + +CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFIndex updateInterval) { + CFIndex interval = updateInterval; // try to use interval preference if it exists CFTypeRef value = (CFNumberRef)CFPreferencesCopyValue(kUpdateIntervalKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); if (isNumber(value)) { @@ -789,6 +1071,10 @@ CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFDictionaryRef update) { } CFReleaseNull(value); + if (interval <= 0) { + interval = kSecStdUpdateInterval; + } + // sanity check if (interval < kSecMinUpdateInterval) { interval = kSecMinUpdateInterval; @@ -803,7 +1089,13 @@ CFAbsoluteTime SecRevocationDbComputeNextUpdateTime(CFDictionaryRef update) { return nextUpdate; } -CFIndex SecRevocationDbIngestUpdate(CFDictionaryRef update) { +void SecRevocationDbComputeAndSetNextUpdateTime(void) { + gNextUpdate = SecRevocationDbComputeNextUpdateTime(0); + SecRevocationDbSetNextUpdateTime(gNextUpdate); + gUpdateStarted = 0; /* no update is currently in progress */ +} + +CFIndex SecRevocationDbIngestUpdate(CFDictionaryRef update, CFIndex chunkVersion) { CFIndex version = 0; if (!update) { return version; @@ -814,109 +1106,157 @@ CFIndex SecRevocationDbIngestUpdate(CFDictionaryRef update) { version = 0; } } - SecRevocationDbApplyUpdate(update, version); - + if (version == 0) { + // only the first chunk will have a version, so the second and + // subsequent chunks will need to pass it in chunkVersion. + version = chunkVersion; + } + CFIndex curVersion = SecRevocationDbGetVersion(); + if (version > curVersion || chunkVersion > 0) { + SecRevocationDbApplyUpdate(update, version); + } else { + secdebug("validupdate", "we have v%ld, skipping update to v%ld", + (long)curVersion, (long)version); + version = -1; // invalid, so we know to skip subsequent chunks + } return version; } -/* Database management */ - -/* v1 = initial version */ -/* v2 = fix for group entry transitions */ -#define kSecRevocationDbSchemaVersion 2 +/* Database schema */ + +/* admin table holds these key-value (or key-ival) pairs: + 'version' (integer) // version of database content + 'check_again' (double) // CFAbsoluteTime of next check (optional; this value is currently stored in prefs) + 'db_version' (integer) // version of database schema + 'db_hash' (blob) // SHA-256 database hash + --> entries in admin table are unique by text key + + issuers table holds map of issuing CA hashes to group identifiers: + groupid (integer) // associated group identifier in group ID table + issuer_hash (blob) // SHA-256 hash of issuer certificate (primary key) + --> entries in issuers table are unique by issuer_hash; + multiple issuer entries may have the same groupid! + + groups table holds records with these attributes: + groupid (integer) // ordinal ID associated with this group entry + flags (integer) // a bitmask of the following values: + kSecValidInfoComplete (0x00000001) set if we have all revocation info for this issuer group + kSecValidInfoCheckOCSP (0x00000002) set if must check ocsp for certs from this issuer group + kSecValidInfoKnownOnly (0x00000004) set if any CA from this issuer group must be in database + kSecValidInfoRequireCT (0x00000008) set if all certs from this issuer group must have SCTs + kSecValidInfoAllowlist (0x00000010) set if this entry describes valid certs (i.e. is allowed) + kSecValidInfoNoCACheck (0x00000020) set if this entry does not require an OCSP check to accept + format (integer) // an integer describing format of entries: + kSecValidInfoFormatUnknown (0) unknown format + kSecValidInfoFormatSerial (1) serial number, not greater than 20 bytes in length + kSecValidInfoFormatSHA256 (2) SHA-256 hash, 32 bytes in length + kSecValidInfoFormatNto1 (3) filter data blob of arbitrary length + data (blob) // Bloom filter data if format is 'nto1', otherwise NULL + --> entries in groups table are unique by groupid + + serials table holds serial number blobs with these attributes: + rowid (integer) // ordinal ID associated with this serial number entry + groupid (integer) // identifier for issuer group in the groups table + serial (blob) // serial number + --> entries in serials table are unique by serial and groupid + + hashes table holds SHA-256 hashes of certificates with these attributes: + rowid (integer) // ordinal ID associated with this sha256 hash entry + groupid (integer) // identifier for issuer group in the groups table + sha256 (blob) // SHA-256 hash of subject certificate + --> entries in hashes table are unique by sha256 and groupid + */ +#define createTablesSQL CFSTR("CREATE TABLE admin(" \ + "key TEXT PRIMARY KEY NOT NULL," \ + "ival INTEGER NOT NULL," \ + "value BLOB" \ + ");" \ + "CREATE TABLE issuers(" \ + "groupid INTEGER NOT NULL," \ + "issuer_hash BLOB PRIMARY KEY NOT NULL" \ + ");" \ + "CREATE INDEX issuer_idx ON issuers(issuer_hash);" \ + "CREATE TABLE groups(" \ + "groupid INTEGER PRIMARY KEY AUTOINCREMENT," \ + "flags INTEGER," \ + "format INTEGER," \ + "data BLOB" \ + ");" \ + "CREATE TABLE serials(" \ + "rowid INTEGER PRIMARY KEY AUTOINCREMENT," \ + "groupid INTEGER NOT NULL," \ + "serial BLOB NOT NULL," \ + "UNIQUE(groupid,serial)" \ + ");" \ + "CREATE TABLE hashes(" \ + "rowid INTEGER PRIMARY KEY AUTOINCREMENT," \ + "groupid INTEGER NOT NULL," \ + "sha256 BLOB NOT NULL," \ + "UNIQUE(groupid,sha256)" \ + ");" \ + "CREATE TRIGGER group_del BEFORE DELETE ON groups FOR EACH ROW " \ + "BEGIN " \ + "DELETE FROM serials WHERE groupid=OLD.groupid; " \ + "DELETE FROM hashes WHERE groupid=OLD.groupid; " \ + "DELETE FROM issuers WHERE groupid=OLD.groupid; " \ + "END;") #define selectGroupIdSQL CFSTR("SELECT DISTINCT groupid " \ "FROM issuers WHERE issuer_hash=?") +#define selectVersionSQL CFSTR("SELECT ival FROM admin " \ +"WHERE key='version'") +#define selectDbVersionSQL CFSTR("SELECT ival FROM admin " \ +"WHERE key='db_version'") +#define selectDbFormatSQL CFSTR("SELECT ival FROM admin " \ +"WHERE key='db_format'") +#define selectDbHashSQL CFSTR("SELECT value FROM admin " \ +"WHERE key='db_hash'") +#define selectDbSourceSQL CFSTR("SELECT value FROM admin " \ +"WHERE key='db_source'") +#define selectNextUpdateSQL CFSTR("SELECT value FROM admin " \ +"WHERE key='check_again'") +#define selectGroupRecordSQL CFSTR("SELECT flags,format,data FROM " \ +"groups WHERE groupid=?") +#define selectSerialRecordSQL CFSTR("SELECT rowid FROM serials " \ +"WHERE groupid=? AND serial=?") +#define selectHashRecordSQL CFSTR("SELECT rowid FROM hashes " \ +"WHERE groupid=? AND sha256=?") +#define insertAdminRecordSQL CFSTR("INSERT OR REPLACE INTO admin " \ +"(key,ival,value) VALUES (?,?,?)") +#define insertIssuerRecordSQL CFSTR("INSERT OR REPLACE INTO issuers " \ +"(groupid,issuer_hash) VALUES (?,?)") +#define insertGroupRecordSQL CFSTR("INSERT OR REPLACE INTO groups " \ +"(groupid,flags,format,data) VALUES (?,?,?,?)") +#define insertSerialRecordSQL CFSTR("INSERT OR REPLACE INTO serials " \ +"(groupid,serial) VALUES (?,?)") +#define insertSha256RecordSQL CFSTR("INSERT OR REPLACE INTO hashes " \ +"(groupid,sha256) VALUES (?,?)") +#define deleteGroupRecordSQL CFSTR("DELETE FROM groups WHERE groupid=?") + +#define deleteAllEntriesSQL CFSTR("DELETE from hashes; " \ +"DELETE from serials; DELETE from issuers; DELETE from groups; " \ +"DELETE from admin; DELETE from sqlite_sequence") +#define deleteTablesSQL CFSTR("DROP TABLE hashes; " \ +"DROP TABLE serials; DROP TABLE issuers; DROP TABLE groups; " \ +"DROP TABLE admin; DELETE from sqlite_sequence") + +/* Database management */ static SecDbRef SecRevocationDbCreate(CFStringRef path) { /* only the db owner should open a read-write connection. */ bool readWrite = isDbOwner(); mode_t mode = 0644; - SecDbRef result = SecDbCreateWithOptions(path, mode, readWrite, false, false, ^bool (SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { + SecDbRef result = SecDbCreateWithOptions(path, mode, readWrite, false, false, ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error) { __block bool ok = true; CFErrorRef localError = NULL; if (ok && !SecDbWithSQL(dbconn, selectGroupIdSQL, &localError, NULL) && CFErrorGetCode(localError) == SQLITE_ERROR) { /* SecDbWithSQL returns SQLITE_ERROR if the table we are preparing the above statement for doesn't exist. */ - /* admin table holds these key-value (or key-ival) pairs: - 'version' (integer) // version of database content - 'check_again' (double) // CFAbsoluteTime of next check (optional; this value is currently stored in prefs) - 'db_version' (integer) // version of database schema - 'db_hash' (blob) // SHA-256 database hash - --> entries in admin table are unique by text key - - issuers table holds map of issuing CA hashes to group identifiers: - issuer_hash (blob) // SHA-256 hash of issuer certificate (primary key) - groupid (integer) // associated group identifier in group ID table - --> entries in issuers table are unique by issuer_hash; - multiple issuer entries may have the same groupid! - - groups table holds records with these attributes: - groupid (integer) // ordinal ID associated with this group entry - flags (integer) // a bitmask of the following values: - kSecValidInfoComplete (0x00000001) set if we have all revocation info for this issuer group - kSecValidInfoCheckOCSP (0x00000002) set if must check ocsp for certs from this issuer group - kSecValidInfoKnownOnly (0x00000004) set if any CA from this issuer group must be in database - kSecValidInfoRequireCT (0x00000008) set if all certs from this issuer group must have SCTs - kSecValidInfoAllowlist (0x00000010) set if this entry describes valid certs (i.e. is allowed) - format (integer) // an integer describing format of entries: - kSecValidInfoFormatUnknown (0) unknown format - kSecValidInfoFormatSerial (1) serial number, not greater than 20 bytes in length - kSecValidInfoFormatSHA256 (2) SHA-256 hash, 32 bytes in length - kSecValidInfoFormatNto1 (3) filter data blob of arbitrary length - data (blob) // Bloom filter data if format is 'nto1', otherwise NULL - --> entries in groups table are unique by groupid - - serials table holds serial number blobs with these attributes: - rowid (integer) // ordinal ID associated with this serial number entry - serial (blob) // serial number - groupid (integer) // identifier for issuer group in the groups table - --> entries in serials table are unique by serial and groupid - - hashes table holds SHA-256 hashes of certificates with these attributes: - rowid (integer) // ordinal ID associated with this sha256 hash entry - sha256 (blob) // SHA-256 hash of subject certificate - groupid (integer) // identifier for issuer group in the groups table - --> entries in hashes table are unique by sha256 and groupid - */ + /* Create all database tables, indexes, and triggers. */ ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, error, ^(bool *commit) { - ok = SecDbExec(dbconn, - CFSTR("CREATE TABLE admin(" - "key TEXT PRIMARY KEY NOT NULL," - "ival INTEGER NOT NULL," - "value BLOB" - ");" - "CREATE TABLE issuers(" - "issuer_hash BLOB PRIMARY KEY NOT NULL," - "groupid INTEGER NOT NULL" - ");" - "CREATE INDEX issuer_idx ON issuers(issuer_hash);" - "CREATE TABLE groups(" - "groupid INTEGER PRIMARY KEY AUTOINCREMENT," - "flags INTEGER NOT NULL," - "format INTEGER NOT NULL," - "data BLOB" - ");" - "CREATE TABLE serials(" - "rowid INTEGER PRIMARY KEY AUTOINCREMENT," - "serial BLOB NOT NULL," - "groupid INTEGER NOT NULL," - "UNIQUE(serial,groupid)" - ");" - "CREATE TABLE hashes(" - "rowid INTEGER PRIMARY KEY AUTOINCREMENT," - "sha256 BLOB NOT NULL," - "groupid INTEGER NOT NULL," - "UNIQUE(sha256,groupid)" - ");" - "CREATE TRIGGER group_del BEFORE DELETE ON groups FOR EACH ROW " - "BEGIN " - "DELETE FROM serials WHERE groupid=OLD.groupid; " - "DELETE FROM hashes WHERE groupid=OLD.groupid; " - "DELETE FROM issuers WHERE groupid=OLD.groupid; " - "END;"), error); + ok = SecDbExec(dbconn, createTablesSQL, error); *commit = ok; }); } @@ -933,35 +1273,37 @@ typedef struct __SecRevocationDb *SecRevocationDbRef; struct __SecRevocationDb { SecDbRef db; dispatch_queue_t update_queue; - bool fullUpdateInProgress; + bool updateInProgress; + bool unsupportedVersion; }; static dispatch_once_t kSecRevocationDbOnce; static SecRevocationDbRef kSecRevocationDb = NULL; static SecRevocationDbRef SecRevocationDbInit(CFStringRef db_name) { - SecRevocationDbRef this; + SecRevocationDbRef rdb; dispatch_queue_attr_t attr; - require(this = (SecRevocationDbRef)malloc(sizeof(struct __SecRevocationDb)), errOut); - this->db = NULL; - this->update_queue = NULL; - this->fullUpdateInProgress = false; + require(rdb = (SecRevocationDbRef)malloc(sizeof(struct __SecRevocationDb)), errOut); + rdb->db = NULL; + rdb->update_queue = NULL; + rdb->updateInProgress = false; + rdb->unsupportedVersion = false; - require(this->db = SecRevocationDbCreate(db_name), errOut); + require(rdb->db = SecRevocationDbCreate(db_name), errOut); attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0); - require(this->update_queue = dispatch_queue_create(NULL, attr), errOut); + require(rdb->update_queue = dispatch_queue_create(NULL, attr), errOut); - return this; + return rdb; errOut: secdebug("validupdate", "Failed to create db at \"%@\"", db_name); - if (this) { - if (this->update_queue) { - dispatch_release(this->update_queue); + if (rdb) { + if (rdb->update_queue) { + dispatch_release(rdb->update_queue); } - CFReleaseSafe(this->db); - free(this); + CFReleaseSafe(rdb->db); + free(rdb); } return NULL; } @@ -991,146 +1333,239 @@ static void SecRevocationDbWith(void(^dbJob)(SecRevocationDbRef db)) { } }); // Do pre job run work here (cancel idle timers etc.) - if (kSecRevocationDb->fullUpdateInProgress) { + if (kSecRevocationDb->updateInProgress) { return; // this would block since SecDb has an exclusive transaction lock } - dbJob(kSecRevocationDb); - // Do post job run work here (gc timer, etc.) + dbJob(kSecRevocationDb); + // Do post job run work here (gc timer, etc.) +} + +static int64_t _SecRevocationDbGetVersion(SecRevocationDbRef rdb, CFErrorRef *error) { + /* look up version entry in admin table; returns -1 on error */ + __block int64_t version = -1; + __block bool ok = true; + __block CFErrorRef localError = NULL; + + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + if (ok) ok &= SecDbWithSQL(dbconn, selectVersionSQL, &localError, ^bool(sqlite3_stmt *selectVersion) { + ok = SecDbStep(dbconn, selectVersion, &localError, NULL); + version = sqlite3_column_int64(selectVersion, 0); + return ok; + }); + }); + (void) CFErrorPropagate(localError, error); + return version; +} + +static void _SecRevocationDbSetVersion(SecRevocationDbRef rdb, CFIndex version){ + secdebug("validupdate", "setting version to %ld", (long)version); + + __block CFErrorRef localError = NULL; + __block bool ok = true; + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { + if (ok) ok = SecDbWithSQL(dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertVersion) { + if (ok) { + const char *versionKey = "version"; + ok = SecDbBindText(insertVersion, 1, versionKey, strlen(versionKey), + SQLITE_TRANSIENT, &localError); + } + if (ok) { + ok = SecDbBindInt64(insertVersion, 2, + (sqlite3_int64)version, &localError); + } + if (ok) { + ok = SecDbStep(dbconn, insertVersion, &localError, NULL); + } + return ok; + }); + }); + }); + if (!ok) { + secerror("_SecRevocationDbSetVersion failed: %@", localError); + } + CFReleaseSafe(localError); +} + +static int64_t _SecRevocationDbGetSchemaVersion(SecRevocationDbRef rdb, CFErrorRef *error) { + /* look up db_version entry in admin table; returns -1 on error */ + __block int64_t db_version = -1; + __block bool ok = true; + __block CFErrorRef localError = NULL; + + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + if (ok) ok &= SecDbWithSQL(dbconn, selectDbVersionSQL, &localError, ^bool(sqlite3_stmt *selectDbVersion) { + ok = SecDbStep(dbconn, selectDbVersion, &localError, NULL); + db_version = sqlite3_column_int64(selectDbVersion, 0); + return ok; + }); + }); + (void) CFErrorPropagate(localError, error); + return db_version; +} + +static void _SecRevocationDbSetSchemaVersion(SecRevocationDbRef rdb, CFIndex dbversion) { + secdebug("validupdate", "setting db_version to %ld", (long)dbversion); + + __block CFErrorRef localError = NULL; + __block bool ok = true; + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { + if (ok) ok = SecDbWithSQL(dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertDbVersion) { + if (ok) { + const char *dbVersionKey = "db_version"; + ok = SecDbBindText(insertDbVersion, 1, dbVersionKey, strlen(dbVersionKey), + SQLITE_TRANSIENT, &localError); + } + if (ok) { + ok = SecDbBindInt64(insertDbVersion, 2, + (sqlite3_int64)dbversion, &localError); + } + if (ok) { + ok = SecDbStep(dbconn, insertDbVersion, &localError, NULL); + } + return ok; + }); + }); + }); + if (!ok) { + secerror("_SecRevocationDbSetSchemaVersion failed: %@", localError); + } else { + rdb->unsupportedVersion = false; + } + CFReleaseSafe(localError); } -/* Instance implementation. */ - -#define selectVersionSQL CFSTR("SELECT ival FROM admin " \ -"WHERE key='version'") -#define selectDbVersionSQL CFSTR("SELECT ival FROM admin " \ -"WHERE key='db_version'") -#define selectDbHashSQL CFSTR("SELECT value FROM admin " \ -"WHERE key='db_hash'") -#define selectNextUpdateSQL CFSTR("SELECT value FROM admin " \ -"WHERE key='check_again'") -#define selectGroupRecordSQL CFSTR("SELECT flags,format,data FROM " \ -"groups WHERE groupid=?") -#define selectSerialRecordSQL CFSTR("SELECT rowid FROM serials " \ -"WHERE serial=? AND groupid=?") -#define selectHashRecordSQL CFSTR("SELECT rowid FROM hashes " \ -"WHERE sha256=? AND groupid=?") -#define insertAdminRecordSQL CFSTR("INSERT OR REPLACE INTO admin " \ -"(key,ival,value) VALUES (?,?,?)") -#define insertIssuerRecordSQL CFSTR("INSERT OR REPLACE INTO issuers " \ -"(issuer_hash,groupid) VALUES (?,?)") -#define insertGroupRecordSQL CFSTR("INSERT OR REPLACE INTO groups " \ -"(groupid,flags,format,data) VALUES (?,?,?,?)") -#define insertSerialRecordSQL CFSTR("INSERT OR REPLACE INTO serials " \ -"(rowid,serial,groupid) VALUES (?,?,?)") -#define insertSha256RecordSQL CFSTR("INSERT OR REPLACE INTO hashes " \ -"(rowid,sha256,groupid) VALUES (?,?,?)") -#define deleteGroupRecordSQL CFSTR("DELETE FROM groups WHERE groupid=?") - -#define deleteAllEntriesSQL CFSTR("DELETE from hashes; " \ -"DELETE from serials; DELETE from issuers; DELETE from groups; " \ -"DELETE from admin; DELETE from sqlite_sequence; VACUUM") - -static int64_t _SecRevocationDbGetVersion(SecRevocationDbRef this, CFErrorRef *error) { - /* look up version entry in admin table; returns -1 on error */ - __block int64_t version = -1; +static int64_t _SecRevocationDbGetUpdateFormat(SecRevocationDbRef rdb, CFErrorRef *error) { + /* look up db_format entry in admin table; returns -1 on error */ + __block int64_t db_format = -1; __block bool ok = true; __block CFErrorRef localError = NULL; - ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { - if (ok) ok &= SecDbWithSQL(dbconn, selectVersionSQL, &localError, ^bool(sqlite3_stmt *selectVersion) { - ok = SecDbStep(dbconn, selectVersion, &localError, NULL); - version = sqlite3_column_int64(selectVersion, 0); + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + if (ok) ok &= SecDbWithSQL(dbconn, selectDbFormatSQL, &localError, ^bool(sqlite3_stmt *selectDbFormat) { + ok = SecDbStep(dbconn, selectDbFormat, &localError, NULL); + db_format = sqlite3_column_int64(selectDbFormat, 0); return ok; }); }); (void) CFErrorPropagate(localError, error); - return version; + return db_format; } -static void _SecRevocationDbSetVersion(SecRevocationDbRef this, CFIndex version){ - secdebug("validupdate", "setting version to %ld", (long)version); +static void _SecRevocationDbSetUpdateFormat(SecRevocationDbRef rdb, CFIndex dbformat) { + secdebug("validupdate", "setting db_format to %ld", (long)dbformat); __block CFErrorRef localError = NULL; __block bool ok = true; - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { - if (ok) ok = SecDbWithSQL(dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertVersion) { + if (ok) ok = SecDbWithSQL(dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertDbFormat) { if (ok) { - const char *versionKey = "version"; - ok = SecDbBindText(insertVersion, 1, versionKey, strlen(versionKey), + const char *dbFormatKey = "db_format"; + ok = SecDbBindText(insertDbFormat, 1, dbFormatKey, strlen(dbFormatKey), SQLITE_TRANSIENT, &localError); } if (ok) { - ok = SecDbBindInt64(insertVersion, 2, - (sqlite3_int64)version, &localError); + ok = SecDbBindInt64(insertDbFormat, 2, + (sqlite3_int64)dbformat, &localError); } if (ok) { - ok = SecDbStep(dbconn, insertVersion, &localError, NULL); + ok = SecDbStep(dbconn, insertDbFormat, &localError, NULL); } return ok; }); }); }); if (!ok) { - secerror("_SecRevocationDbSetVersion failed: %@", localError); + secerror("_SecRevocationDbSetUpdateFormat failed: %@", localError); + } else { + rdb->unsupportedVersion = false; } CFReleaseSafe(localError); } -static int64_t _SecRevocationDbGetSchemaVersion(SecRevocationDbRef this, CFErrorRef *error) { - /* look up db_version entry in admin table; returns -1 on error */ - __block int64_t db_version = -1; +static CFStringRef _SecRevocationDbCopyUpdateSource(SecRevocationDbRef rdb, CFErrorRef *error) { + /* look up db_source entry in admin table; returns NULL on error */ + __block CFStringRef updateSource = NULL; __block bool ok = true; __block CFErrorRef localError = NULL; - ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { - if (ok) ok &= SecDbWithSQL(dbconn, selectDbVersionSQL, &localError, ^bool(sqlite3_stmt *selectDbVersion) { - ok = SecDbStep(dbconn, selectDbVersion, &localError, NULL); - db_version = sqlite3_column_int64(selectDbVersion, 0); + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + if (ok) ok &= SecDbWithSQL(dbconn, selectDbSourceSQL, &localError, ^bool(sqlite3_stmt *selectDbSource) { + ok = SecDbStep(dbconn, selectDbSource, &localError, NULL); + const UInt8 *p = (const UInt8 *)sqlite3_column_blob(selectDbSource, 0); + if (p != NULL) { + CFIndex length = (CFIndex)sqlite3_column_bytes(selectDbSource, 0); + if (length > 0) { + updateSource = CFStringCreateWithBytes(kCFAllocatorDefault, p, length, kCFStringEncodingUTF8, false); + } + } return ok; }); }); + (void) CFErrorPropagate(localError, error); - return db_version; + return updateSource; } -static void _SecRevocationDbSetSchemaVersion(SecRevocationDbRef this, CFIndex dbversion){ - secdebug("validupdate", "setting db_version to %ld", (long)dbversion); +static void _SecRevocationDbSetUpdateSource(SecRevocationDbRef rdb, CFStringRef updateSource) { + if (!updateSource) { + secerror("_SecRevocationDbSetUpdateSource failed: %d", errSecParam); + return; + } + __block char buffer[256]; + __block const char *updateSourceCStr = CFStringGetCStringPtr(updateSource, kCFStringEncodingUTF8); + if (!updateSourceCStr) { + if (CFStringGetCString(updateSource, buffer, 256, kCFStringEncodingUTF8)) { + updateSourceCStr = buffer; + } + } + if (!updateSourceCStr) { + secerror("_SecRevocationDbSetUpdateSource failed: unable to get UTF-8 encoding"); + return; + } + secdebug("validupdate", "setting update source to \"%s\"", updateSourceCStr); __block CFErrorRef localError = NULL; __block bool ok = true; - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { - if (ok) ok = SecDbWithSQL(dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertDbVersion) { + if (ok) ok = SecDbWithSQL(dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertRecord) { if (ok) { - const char *dbVersionKey = "db_version"; - ok = SecDbBindText(insertDbVersion, 1, dbVersionKey, strlen(dbVersionKey), + const char *dbSourceKey = "db_source"; + ok = SecDbBindText(insertRecord, 1, dbSourceKey, strlen(dbSourceKey), SQLITE_TRANSIENT, &localError); } if (ok) { - ok = SecDbBindInt64(insertDbVersion, 2, - (sqlite3_int64)dbversion, &localError); + ok = SecDbBindInt64(insertRecord, 2, + (sqlite3_int64)0, &localError); } if (ok) { - ok = SecDbStep(dbconn, insertDbVersion, &localError, NULL); + ok = SecDbBindBlob(insertRecord, 3, + updateSourceCStr, strlen(updateSourceCStr), + SQLITE_TRANSIENT, &localError); + } + if (ok) { + ok = SecDbStep(dbconn, insertRecord, &localError, NULL); } return ok; }); }); }); if (!ok) { - secerror("_SecRevocationDbSetSchemaVersion failed: %@", localError); + secerror("_SecRevocationDbSetUpdateSource failed: %@", localError); } CFReleaseSafe(localError); } -static CFAbsoluteTime _SecRevocationDbGetNextUpdateTime(SecRevocationDbRef this, CFErrorRef *error) { +static CFAbsoluteTime _SecRevocationDbGetNextUpdateTime(SecRevocationDbRef rdb, CFErrorRef *error) { /* look up check_again entry in admin table; returns 0 on error */ __block CFAbsoluteTime nextUpdate = 0; __block bool ok = true; __block CFErrorRef localError = NULL; - ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { if (ok) ok &= SecDbWithSQL(dbconn, selectNextUpdateSQL, &localError, ^bool(sqlite3_stmt *selectNextUpdate) { ok = SecDbStep(dbconn, selectNextUpdate, &localError, NULL); CFAbsoluteTime *p = (CFAbsoluteTime *)sqlite3_column_blob(selectNextUpdate, 0); @@ -1147,12 +1582,12 @@ static CFAbsoluteTime _SecRevocationDbGetNextUpdateTime(SecRevocationDbRef this, return nextUpdate; } -static void _SecRevocationDbSetNextUpdateTime(SecRevocationDbRef this, CFAbsoluteTime nextUpdate){ +static void _SecRevocationDbSetNextUpdateTime(SecRevocationDbRef rdb, CFAbsoluteTime nextUpdate){ secdebug("validupdate", "setting next update to %f", (double)nextUpdate); __block CFErrorRef localError = NULL; __block bool ok = true; - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { if (ok) ok = SecDbWithSQL(dbconn, insertAdminRecordSQL, &localError, ^bool(sqlite3_stmt *insertRecord) { if (ok) { @@ -1182,27 +1617,35 @@ static void _SecRevocationDbSetNextUpdateTime(SecRevocationDbRef this, CFAbsolut CFReleaseSafe(localError); } -static bool _SecRevocationDbRemoveAllEntries(SecRevocationDbRef this) { - /* remove all entries from all tables in the database */ +static bool _SecRevocationDbRemoveAllEntries(SecRevocationDbRef rdb) { + /* clear out the contents of the database and start fresh */ __block bool ok = true; __block CFErrorRef localError = NULL; - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { - ok &= SecDbWithSQL(dbconn, deleteAllEntriesSQL, &localError, ^bool(sqlite3_stmt *deleteAll) { - ok = SecDbStep(dbconn, deleteAll, &localError, NULL); - return ok; - }); + //ok &= SecDbWithSQL(dbconn, deleteAllEntriesSQL, &localError, ^bool(sqlite3_stmt *deleteAll) { + // ok = SecDbStep(dbconn, deleteAll, &localError, NULL); + // return ok; + //}); + /* drop all tables and recreate them, in case of schema changes */ + ok &= SecDbExec(dbconn, deleteTablesSQL, &localError); + ok &= SecDbExec(dbconn, createTablesSQL, &localError); + secdebug("validupdate", "resetting database, result: %d", (ok) ? 1 : 0); + *commit = ok; }); + /* compact the db (must be done outside transaction scope) */ + SecDbExec(dbconn, CFSTR("VACUUM"), &localError); }); - /* one more thing: update the schema version */ - _SecRevocationDbSetSchemaVersion(this, kSecRevocationDbSchemaVersion); + /* one more thing: update the schema version and format to current */ + _SecRevocationDbSetSchemaVersion(rdb, kSecRevocationDbSchemaVersion); + _SecRevocationDbSetUpdateFormat(rdb, kSecRevocationDbUpdateFormat); CFReleaseSafe(localError); return ok; } -static bool _SecRevocationDbUpdateIssuers(SecRevocationDbRef this, int64_t groupId, CFArrayRef issuers, CFErrorRef *error) { +static bool _SecRevocationDbUpdateIssuers(SecRevocationDbRef rdb, int64_t groupId, CFArrayRef issuers, CFErrorRef *error) { /* insert or replace issuer records in issuers table */ if (!issuers || groupId < 0) { return false; /* must have something to insert, and a group to associate with it */ @@ -1210,7 +1653,7 @@ static bool _SecRevocationDbUpdateIssuers(SecRevocationDbRef this, int64_t group __block bool ok = true; __block CFErrorRef localError = NULL; - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { if (isArray(issuers)) { CFIndex issuerIX, issuerCount = CFArrayGetCount(issuers); @@ -1219,15 +1662,15 @@ static bool _SecRevocationDbUpdateIssuers(SecRevocationDbRef this, int64_t group if (!hash) { continue; } if (ok) ok = SecDbWithSQL(dbconn, insertIssuerRecordSQL, &localError, ^bool(sqlite3_stmt *insertIssuer) { if (ok) { - ok = SecDbBindBlob(insertIssuer, 1, + ok = SecDbBindInt64(insertIssuer, 1, + groupId, &localError); + } + if (ok) { + ok = SecDbBindBlob(insertIssuer, 2, CFDataGetBytePtr(hash), CFDataGetLength(hash), SQLITE_TRANSIENT, &localError); } - if (ok) { - ok = SecDbBindInt64(insertIssuer, 2, - groupId, &localError); - } /* Execute the insert statement for this issuer record. */ if (ok) { ok = SecDbStep(dbconn, insertIssuer, &localError, NULL); @@ -1243,16 +1686,22 @@ static bool _SecRevocationDbUpdateIssuers(SecRevocationDbRef this, int64_t group return ok; } -static bool _SecRevocationDbUpdatePerIssuerData(SecRevocationDbRef this, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { - /* insert records in serials or hashes table. */ +static bool _SecRevocationDbUpdatePerIssuerData(SecRevocationDbRef rdb, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { + /* update/delete records in serials or hashes table. */ if (!dict || groupId < 0) { return false; /* must have something to insert, and a group to associate with it */ } __block bool ok = true; __block CFErrorRef localError = NULL; - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { + CFArrayRef deleteArray = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("delete")); + /* process deletions */ + if (isArray(deleteArray)) { + //%%% delete old data here (rdar://31439625) + } + /* process additions */ CFArrayRef addArray = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("add")); if (isArray(addArray)) { CFIndex identifierIX, identifierCount = CFArrayGetCount(addArray); @@ -1271,18 +1720,18 @@ static bool _SecRevocationDbUpdatePerIssuerData(SecRevocationDbRef this, int64_t if (!sql) { continue; } if (ok) ok = SecDbWithSQL(dbconn, sql, &localError, ^bool(sqlite3_stmt *insertIdentifier) { - /* (rowid,serial|sha256,groupid) */ - /* rowid == column 1, autoincrement so we don't set directly */ + /* rowid,(groupid,serial|sha256) */ + /* rowid is autoincremented and we never set it directly */ + if (ok) { + ok = SecDbBindInt64(insertIdentifier, 1, + groupId, &localError); + } if (ok) { ok = SecDbBindBlob(insertIdentifier, 2, CFDataGetBytePtr(identifierData), CFDataGetLength(identifierData), SQLITE_TRANSIENT, &localError); } - if (ok) { - ok = SecDbBindInt64(insertIdentifier, 3, - groupId, &localError); - } /* Execute the insert statement for the identifier record. */ if (ok) { ok = SecDbStep(dbconn, insertIdentifier, &localError, NULL); @@ -1298,126 +1747,332 @@ static bool _SecRevocationDbUpdatePerIssuerData(SecRevocationDbRef this, int64_t return ok; } -static int64_t _SecRevocationDbUpdateGroup(SecRevocationDbRef this, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { +static SecValidInfoFormat _SecRevocationDbGetGroupFormat(SecRevocationDbRef rdb, + int64_t groupId, SecValidInfoFlags *flags, CFDataRef *data, CFErrorRef *error) { + /* return group record fields for a given groupId. + on success, returns a non-zero format type, and other field values in optional output parameters. + caller is responsible for releasing data and error parameters, if provided. + */ + __block bool ok = true; + __block SecValidInfoFormat format = 0; + __block CFErrorRef localError = NULL; + + /* Select the group record to determine flags and format. */ + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbWithSQL(dbconn, selectGroupRecordSQL, &localError, ^bool(sqlite3_stmt *selectGroup) { + ok = SecDbBindInt64(selectGroup, 1, groupId, &localError); + ok &= SecDbStep(dbconn, selectGroup, &localError, ^(bool *stop) { + if (flags) { + *flags = (SecValidInfoFlags)sqlite3_column_int(selectGroup, 0); + } + format = (SecValidInfoFormat)sqlite3_column_int(selectGroup, 1); + if (data) { + //TODO: stream this from sqlite through the inflation so we return an inflated copy, then remove inflate from others + uint8_t *p = (uint8_t *)sqlite3_column_blob(selectGroup, 2); + if (p != NULL && format == kSecValidInfoFormatNto1) { + CFIndex length = (CFIndex)sqlite3_column_bytes(selectGroup, 2); + *data = CFDataCreate(kCFAllocatorDefault, p, length); + } + } + }); + return ok; + }); + }); + if (!ok) { + secdebug("validupdate", "GetGroupFormat for groupId %lu failed", (unsigned long)groupId); + format = kSecValidInfoFormatUnknown; + } + (void) CFErrorPropagate(localError, error); + if (!(format > kSecValidInfoFormatUnknown)) { + secdebug("validupdate", "GetGroupFormat: got format %d for groupId %lld", format, (long long)groupId); + } + return format; +} + +static bool _SecRevocationDbUpdateFlags(CFDictionaryRef dict, CFStringRef key, SecValidInfoFlags mask, SecValidInfoFlags *flags) { + /* If a boolean value exists in the given dictionary for the given key, + set or clear the corresponding bit(s) defined by the mask argument. + Function returns true if the flags value was changed, false otherwise. + */ + bool result = false; + CFTypeRef value = (CFBooleanRef)CFDictionaryGetValue(dict, key); + if (isBoolean(value) && flags) { + SecValidInfoFlags oldFlags = *flags; + if (CFBooleanGetValue((CFBooleanRef)value)) { + *flags |= mask; + } else { + *flags &= ~(mask); + } + result = (*flags != oldFlags); + } + return result; +} + +static bool _SecRevocationDbUpdateFilter(CFDictionaryRef dict, CFDataRef oldData, CFDataRef * __nonnull CF_RETURNS_RETAINED xmlData) { + /* If xor and/or params values exist in the given dictionary, create a new + property list containing the updated values, and return as a flattened + data blob in the xmlData output parameter (note: caller must release.) + Function returns true if there is new xmlData to save, false otherwise. + */ + bool result = false; + bool xorProvided = false; + bool paramsProvided = false; + bool missingData = false; + + if (!dict || !xmlData) { + return result; /* no-op if no dictionary is provided, or no way to update the data */ + } + *xmlData = NULL; + CFDataRef xorCurrent = NULL; + CFDataRef xorUpdate = (CFDataRef)CFDictionaryGetValue(dict, CFSTR("xor")); + if (isData(xorUpdate)) { + xorProvided = true; + } + CFArrayRef paramsCurrent = NULL; + CFArrayRef paramsUpdate = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("params")); + if (isArray(paramsUpdate)) { + paramsProvided = true; + } + if (!(xorProvided || paramsProvided)) { + return result; /* nothing to update, so we can bail out here. */ + } + + CFPropertyListRef nto1Current = NULL; + CFMutableDictionaryRef nto1Update = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!nto1Update) { + return result; + } + + /* turn old data into property list */ + CFDataRef data = (CFDataRef)CFRetainSafe(oldData); + CFDataRef inflatedData = copyInflatedData(data); + if (inflatedData) { + CFReleaseSafe(data); + data = inflatedData; + } + if (data) { + nto1Current = CFPropertyListCreateWithData(kCFAllocatorDefault, data, 0, NULL, NULL); + CFReleaseSafe(data); + } + if (nto1Current) { + xorCurrent = (CFDataRef)CFDictionaryGetValue((CFDictionaryRef)nto1Current, CFSTR("xor")); + paramsCurrent = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)nto1Current, CFSTR("params")); + } + + /* set current or updated xor data in new property list */ + if (xorProvided) { + CFDataRef xorNew = NULL; + if (xorCurrent) { + CFIndex xorUpdateLen = CFDataGetLength(xorUpdate); + CFMutableDataRef xor = CFDataCreateMutableCopy(NULL, 0, xorCurrent); + if (xor && xorUpdateLen > 0) { + /* truncate or zero-extend data to match update size */ + CFDataSetLength(xor, xorUpdateLen); + /* exclusive-or update bytes over the existing data */ + UInt8 *xorP = (UInt8 *)CFDataGetMutableBytePtr(xor); + UInt8 *updP = (UInt8 *)CFDataGetBytePtr(xorUpdate); + if (xorP && updP) { + for (int idx = 0; idx < xorUpdateLen; idx++) { + xorP[idx] = xorP[idx] ^ updP[idx]; + } + } + } + xorNew = (CFDataRef)xor; + } else { + xorNew = (CFDataRef)CFRetainSafe(xorUpdate); + } + if (xorNew) { + CFDictionaryAddValue(nto1Update, CFSTR("xor"), xorNew); + CFReleaseSafe(xorNew); + } else { + secdebug("validupdate", "Failed to get updated filter data"); + missingData = true; + } + } else if (xorCurrent) { + /* not provided, so use existing xor value */ + CFDictionaryAddValue(nto1Update, CFSTR("xor"), xorCurrent); + } else { + secdebug("validupdate", "Failed to get current filter data"); + missingData = true; + } + + /* set current or updated params in new property list */ + if (paramsProvided) { + CFDictionaryAddValue(nto1Update, CFSTR("params"), paramsUpdate); + } else if (paramsCurrent) { + /* not provided, so use existing params value */ + CFDictionaryAddValue(nto1Update, CFSTR("params"), paramsCurrent); + } else { + /* missing params: neither provided nor existing */ + secdebug("validupdate", "Failed to get current filter params"); + missingData = true; + } + + CFReleaseSafe(nto1Current); + if (!missingData) { + *xmlData = CFPropertyListCreateData(kCFAllocatorDefault, nto1Update, + kCFPropertyListXMLFormat_v1_0, + 0, NULL); + result = (*xmlData != NULL); + } + CFReleaseSafe(nto1Update); + + /* compress the xmlData blob, if possible */ + if (result) { + CFDataRef deflatedData = copyDeflatedData(*xmlData); + if (deflatedData) { + if (CFDataGetLength(deflatedData) < CFDataGetLength(*xmlData)) { + CFRelease(*xmlData); + *xmlData = deflatedData; + } else { + CFRelease(deflatedData); + } + } + } + return result; +} + + +static int64_t _SecRevocationDbUpdateGroup(SecRevocationDbRef rdb, int64_t groupId, CFDictionaryRef dict, CFErrorRef *error) { /* insert group record for a given groupId. if the specified groupId is < 0, a new group entry is created. returns the groupId on success, or -1 on failure. */ + if (!dict) { + return groupId; /* no-op if no dictionary is provided */ + } + __block int64_t result = -1; __block bool ok = true; + __block bool isFormatChange = false; __block CFErrorRef localError = NULL; - if (!dict) { - return groupId; /* no-op if no dictionary is provided */ + __block SecValidInfoFlags flags = 0; + __block SecValidInfoFormat format = kSecValidInfoFormatUnknown; + __block SecValidInfoFormat formatUpdate = kSecValidInfoFormatUnknown; + __block CFDataRef data = NULL; + + if (groupId >= 0) { + /* fetch the flags and data for an existing group record, in case some are being changed. */ + format = _SecRevocationDbGetGroupFormat(rdb, groupId, &flags, &data, NULL); + if (format == kSecValidInfoFormatUnknown) { + secdebug("validupdate", "existing group %lld has unknown format %d, flags=%lu", + (long long)groupId, format, flags); + //%%% clean up by deleting all issuers with this groupId, then the group record, + // or just force a full update? note: we can get here if we fail to bind the + // format value in the prepared SQL statement below. + return -1; + } + } + CFTypeRef value = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("format")); + if (isString(value)) { + if (CFStringCompare((CFStringRef)value, CFSTR("serial"), 0) == kCFCompareEqualTo) { + formatUpdate = kSecValidInfoFormatSerial; + } else if (CFStringCompare((CFStringRef)value, CFSTR("sha256"), 0) == kCFCompareEqualTo) { + formatUpdate = kSecValidInfoFormatSHA256; + } else if (CFStringCompare((CFStringRef)value, CFSTR("nto1"), 0) == kCFCompareEqualTo) { + formatUpdate = kSecValidInfoFormatNto1; + } } + /* if format value is explicitly supplied, then this is effectively a new group entry. */ + isFormatChange = (formatUpdate > kSecValidInfoFormatUnknown && + formatUpdate != format && + groupId >= 0); - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { + if (isFormatChange) { + secdebug("validupdate", "group %lld format change from %d to %d", + (long long)groupId, format, formatUpdate); + /* format of an existing group is changing; delete the group first. + this should ensure that all entries referencing the old groupid are deleted. + */ + ok &= SecDbWithSQL(dbconn, deleteGroupRecordSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) { + ok = SecDbBindInt64(deleteResponse, 1, groupId, &localError); + /* Execute the delete statement. */ + if (ok) { + ok = SecDbStep(dbconn, deleteResponse, &localError, NULL); + } + return ok; + }); + } ok &= SecDbWithSQL(dbconn, insertGroupRecordSQL, &localError, ^bool(sqlite3_stmt *insertGroup) { - CFTypeRef value; - SecValidInfoFormat format = kSecValidInfoFormatUnknown; /* (groupid,flags,format,data) */ /* groups.groupid */ - if (ok && !(groupId < 0)) { + if (ok && (!isFormatChange) && (groupId >= 0)) { /* bind to existing groupId row if known, otherwise will insert and autoincrement */ ok = SecDbBindInt64(insertGroup, 1, groupId, &localError); + if (!ok) { + secdebug("validupdate", "failed to set groupId %lld", (long long)groupId); + } } /* groups.flags */ if (ok) { - int flags = 0; - value = (CFBooleanRef)CFDictionaryGetValue(dict, CFSTR("complete")); - if (isBoolean(value)) { - if (CFBooleanGetValue((CFBooleanRef)value)) { - flags |= kSecValidInfoComplete; - } - } - value = (CFBooleanRef)CFDictionaryGetValue(dict, CFSTR("check-ocsp")); - if (isBoolean(value)) { - if (CFBooleanGetValue((CFBooleanRef)value)) { - flags |= kSecValidInfoCheckOCSP; - } - } - value = (CFBooleanRef)CFDictionaryGetValue(dict, CFSTR("known-intermediates-only")); - if (isBoolean(value)) { - if (CFBooleanGetValue((CFBooleanRef)value)) { - flags |= kSecValidInfoKnownOnly; - } - } - value = (CFBooleanRef)CFDictionaryGetValue(dict, CFSTR("require-ct")); - if (isBoolean(value)) { - if (CFBooleanGetValue((CFBooleanRef)value)) { - flags |= kSecValidInfoRequireCT; - } - } - value = (CFBooleanRef)CFDictionaryGetValue(dict, CFSTR("valid")); - if (isBoolean(value)) { - if (CFBooleanGetValue((CFBooleanRef)value)) { - flags |= kSecValidInfoAllowlist; - } + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("complete"), kSecValidInfoComplete, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("check-ocsp"), kSecValidInfoCheckOCSP, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("known-intermediates-only"), kSecValidInfoKnownOnly, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("require-ct"), kSecValidInfoRequireCT, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("valid"), kSecValidInfoAllowlist, &flags); + (void)_SecRevocationDbUpdateFlags(dict, CFSTR("no-ca"), kSecValidInfoNoCACheck, &flags); + + ok = SecDbBindInt(insertGroup, 2, (int)flags, &localError); + if (!ok) { + secdebug("validupdate", "failed to set flags (%lu) for groupId %lld", flags, (long long)groupId); } - ok = SecDbBindInt(insertGroup, 2, flags, &localError); } /* groups.format */ if (ok) { - value = (CFBooleanRef)CFDictionaryGetValue(dict, CFSTR("format")); - if (isString(value)) { - if (CFStringCompare((CFStringRef)value, CFSTR("serial"), 0) == kCFCompareEqualTo) { - format = kSecValidInfoFormatSerial; - } else if (CFStringCompare((CFStringRef)value, CFSTR("sha256"), 0) == kCFCompareEqualTo) { - format = kSecValidInfoFormatSHA256; - } else if (CFStringCompare((CFStringRef)value, CFSTR("nto1"), 0) == kCFCompareEqualTo) { - format = kSecValidInfoFormatNto1; - } + SecValidInfoFormat formatValue = format; + if (formatUpdate > kSecValidInfoFormatUnknown) { + formatValue = formatUpdate; + } + ok = SecDbBindInt(insertGroup, 3, (int)formatValue, &localError); + if (!ok) { + secdebug("validupdate", "failed to set format (%d) for groupId %lld", formatValue, (long long)groupId); } - ok = SecDbBindInt(insertGroup, 3, (int)format, &localError); } /* groups.data */ CFDataRef xmlData = NULL; - if (ok && format == kSecValidInfoFormatNto1) { - CFMutableDictionaryRef nto1 = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - value = (CFDataRef)CFDictionaryGetValue(dict, CFSTR("xor")); - if (isData(value)) { - CFDictionaryAddValue(nto1, CFSTR("xor"), value); - } - value = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("params")); - if (isArray(value)) { - CFDictionaryAddValue(nto1, CFSTR("params"), value); - } - xmlData = CFPropertyListCreateData(kCFAllocatorDefault, nto1, - kCFPropertyListXMLFormat_v1_0, 0, &localError); - CFReleaseSafe(nto1); - - if (xmlData) { - // compress the xmlData blob, if possible - CFDataRef deflatedData = copyDeflatedData(xmlData); - if (deflatedData) { - if (CFDataGetLength(deflatedData) < CFDataGetLength(xmlData)) { - CFRelease(xmlData); - xmlData = deflatedData; - } - else { - CFRelease(deflatedData); - } + if (ok) { + bool hasFilter = ((formatUpdate == kSecValidInfoFormatNto1) || + (formatUpdate == kSecValidInfoFormatUnknown && + format == kSecValidInfoFormatNto1)); + if (hasFilter) { + CFDataRef dataValue = data; /* use existing data */ + if (_SecRevocationDbUpdateFilter(dict, data, &xmlData)) { + dataValue = xmlData; /* use updated data */ + } + if (dataValue) { + ok = SecDbBindBlob(insertGroup, 4, + CFDataGetBytePtr(dataValue), + CFDataGetLength(dataValue), + SQLITE_TRANSIENT, &localError); + } + if (!ok) { + secdebug("validupdate", "failed to set data for groupId %lld", + (long long)groupId); } - ok = SecDbBindBlob(insertGroup, 4, - CFDataGetBytePtr(xmlData), - CFDataGetLength(xmlData), - SQLITE_TRANSIENT, &localError); } + /* else there is no data, so NULL is implicitly bound to column 4 */ } /* Execute the insert statement for the group record. */ if (ok) { ok = SecDbStep(dbconn, insertGroup, &localError, NULL); + if (!ok) { + secdebug("validupdate", "failed to execute insertGroup statement for groupId %lld", + (long long)groupId); + } result = (int64_t)sqlite3_last_insert_rowid(SecDbHandle(dbconn)); } if (!ok) { - secdebug("validupdate", "Failed to insert group %ld", (long)result); + secdebug("validupdate", "failed to insert group %lld", (long long)result); } /* Clean up temporary allocation made in this block. */ CFReleaseSafe(xmlData); + CFReleaseSafe(data); return ok; }); }); @@ -1427,25 +2082,36 @@ static int64_t _SecRevocationDbUpdateGroup(SecRevocationDbRef this, int64_t grou return result; } -static int64_t _SecRevocationDbGroupIdForIssuerHash(SecRevocationDbRef this, CFDataRef hash, CFErrorRef *error) { +static int64_t _SecRevocationDbGroupIdForIssuerHash(SecRevocationDbRef rdb, CFDataRef hash, CFErrorRef *error) { /* look up issuer hash in issuers table to get groupid, if it exists */ __block int64_t groupId = -1; __block bool ok = true; __block CFErrorRef localError = NULL; + if (!hash) { + secdebug("validupdate", "failed to get hash (%@)", hash); + } require(hash, errOut); /* This is the starting point for any lookup; find a group id for the given issuer hash. Before we do that, need to verify the current db_version. We cannot use results from a - database created with schema version 1. At the next database update interval, - we'll be removing and recreating the database contents with the current schema version. + database created with a schema version older than the minimum supported version. + However, we may be able to use results from a newer version. At the next database + update interval, if the existing schema is old, we'll be removing and recreating + the database contents with the current schema version. */ - int64_t db_version = _SecRevocationDbGetSchemaVersion(this, NULL); - require(db_version > 1, errOut); + int64_t db_version = _SecRevocationDbGetSchemaVersion(rdb, NULL); + if (db_version < kSecRevocationDbMinSchemaVersion) { + if (!rdb->unsupportedVersion) { + secdebug("validupdate", "unsupported db_version: %lld", (long long)db_version); + rdb->unsupportedVersion = true; /* only warn once for a given unsupported version */ + } + } + require_quiet(db_version >= kSecRevocationDbMinSchemaVersion, errOut); /* Look up provided issuer_hash in the issuers table. */ - ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbWithSQL(dbconn, selectGroupIdSQL, &localError, ^bool(sqlite3_stmt *selectGroupId) { ok = SecDbBindBlob(selectGroupId, 1, CFDataGetBytePtr(hash), CFDataGetLength(hash), SQLITE_TRANSIENT, &localError); ok &= SecDbStep(dbconn, selectGroupId, &localError, ^(bool *stopGroupId) { @@ -1460,17 +2126,17 @@ errOut: return groupId; } -static bool _SecRevocationDbApplyGroupDelete(SecRevocationDbRef this, CFDataRef issuerHash, CFErrorRef *error) { +static bool _SecRevocationDbApplyGroupDelete(SecRevocationDbRef rdb, CFDataRef issuerHash, CFErrorRef *error) { /* delete group associated with the given issuer; schema trigger will delete associated issuers, serials, and hashes. */ __block int64_t groupId = -1; __block bool ok = true; __block CFErrorRef localError = NULL; - groupId = _SecRevocationDbGroupIdForIssuerHash(this, issuerHash, &localError); + groupId = _SecRevocationDbGroupIdForIssuerHash(rdb, issuerHash, &localError); require(!(groupId < 0), errOut); - ok &= SecDbPerformWrite(this->db, &localError, ^(SecDbConnectionRef dbconn) { + ok &= SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { ok = SecDbWithSQL(dbconn, deleteGroupRecordSQL, &localError, ^bool(sqlite3_stmt *deleteResponse) { ok = SecDbBindInt64(deleteResponse, 1, groupId, &localError); @@ -1488,7 +2154,7 @@ errOut: return (groupId < 0) ? false : true; } -static bool _SecRevocationDbApplyGroupUpdate(SecRevocationDbRef this, CFDictionaryRef dict, CFErrorRef *error) { +static bool _SecRevocationDbApplyGroupUpdate(SecRevocationDbRef rdb, CFDictionaryRef dict, CFErrorRef *error) { /* process one issuer group's update dictionary */ int64_t groupId = -1; CFErrorRef localError = NULL; @@ -1500,49 +2166,45 @@ static bool _SecRevocationDbApplyGroupUpdate(SecRevocationDbRef this, CFDictiona for (issuerIX=0; issuerIX 0) ? true : false; } -static void _SecRevocationDbApplyUpdate(SecRevocationDbRef this, CFDictionaryRef update, CFIndex version) { +static void _SecRevocationDbApplyUpdate(SecRevocationDbRef rdb, CFDictionaryRef update, CFIndex version) { /* process entire update dictionary */ - if (!this || !update) { + if (!rdb || !update) { secerror("_SecRevocationDbApplyUpdate failed: invalid args"); return; } - CFRetain(update); - __block CFDictionaryRef localUpdate = update; + __block CFDictionaryRef localUpdate = (CFDictionaryRef)CFRetainSafe(update); __block CFErrorRef localError = NULL; - // This may take a while; do the work on our update queue with background priority. - - dispatch_async(this->update_queue, ^{ - - CFTypeRef value; + CFTypeRef value = NULL; CFIndex deleteCount = 0; CFIndex updateCount = 0; + rdb->updateInProgress = true; + /* check whether this is a full update */ - this->fullUpdateInProgress = false; value = (CFBooleanRef)CFDictionaryGetValue(update, CFSTR("full")); - if (isBoolean(value)) { - this->fullUpdateInProgress = CFBooleanGetValue((CFBooleanRef)value); + if (isBoolean(value) && CFBooleanGetValue((CFBooleanRef)value)) { + /* clear the database before processing a full update */ + SecRevocationDbRemoveAllEntries(); } /* process 'delete' list */ @@ -1553,7 +2215,7 @@ static void _SecRevocationDbApplyUpdate(SecRevocationDbRef this, CFDictionaryRef for (CFIndex deleteIX=0; deleteIXdb, &localError, ^(SecDbConnectionRef dbconn) { - SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &localError, ^(bool *commit) { - SecDbExec(dbconn, CFSTR("VACUUM;"), &localError); - CFReleaseNull(localError); - }); - }); - this->fullUpdateInProgress = false; + /* set db_format if not already set */ + int64_t db_format = _SecRevocationDbGetUpdateFormat(rdb, NULL); + if (db_format <= 0) { + _SecRevocationDbSetUpdateFormat(rdb, kSecRevocationDbUpdateFormat); + } + /* compact the db (must be done outside transaction scope) */ + (void)SecDbPerformWrite(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { + SecDbExec(dbconn, CFSTR("VACUUM"), &localError); + CFReleaseNull(localError); }); + + rdb->updateInProgress = false; } -static bool _SecRevocationDbSerialInGroup(SecRevocationDbRef this, +static bool _SecRevocationDbSerialInGroup(SecRevocationDbRef rdb, CFDataRef serial, int64_t groupId, CFErrorRef *error) { __block bool result = false; __block bool ok = true; __block CFErrorRef localError = NULL; - require(this && serial, errOut); - ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { + require(rdb && serial, errOut); + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbWithSQL(dbconn, selectSerialRecordSQL, &localError, ^bool(sqlite3_stmt *selectSerial) { - ok &= SecDbBindBlob(selectSerial, 1, CFDataGetBytePtr(serial), + ok &= SecDbBindInt64(selectSerial, 1, groupId, &localError); + ok &= SecDbBindBlob(selectSerial, 2, CFDataGetBytePtr(serial), CFDataGetLength(serial), SQLITE_TRANSIENT, &localError); - ok &= SecDbBindInt64(selectSerial, 2, groupId, &localError); ok &= SecDbStep(dbconn, selectSerial, &localError, ^(bool *stop) { int64_t foundRowId = (int64_t)sqlite3_column_int64(selectSerial, 0); result = (foundRowId > 0); @@ -1621,19 +2286,19 @@ errOut: return result; } -static bool _SecRevocationDbCertHashInGroup(SecRevocationDbRef this, +static bool _SecRevocationDbCertHashInGroup(SecRevocationDbRef rdb, CFDataRef certHash, int64_t groupId, CFErrorRef *error) { __block bool result = false; __block bool ok = true; __block CFErrorRef localError = NULL; - require(this && certHash, errOut); - ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { + require(rdb && certHash, errOut); + ok &= SecDbPerformRead(rdb->db, &localError, ^(SecDbConnectionRef dbconn) { ok &= SecDbWithSQL(dbconn, selectHashRecordSQL, &localError, ^bool(sqlite3_stmt *selectHash) { - ok = SecDbBindBlob(selectHash, 1, CFDataGetBytePtr(certHash), + ok &= SecDbBindInt64(selectHash, 1, groupId, &localError); + ok = SecDbBindBlob(selectHash, 2, CFDataGetBytePtr(certHash), CFDataGetLength(certHash), SQLITE_TRANSIENT, &localError); - ok &= SecDbBindInt64(selectHash, 2, groupId, &localError); ok &= SecDbStep(dbconn, selectHash, &localError, ^(bool *stop) { int64_t foundRowId = (int64_t)sqlite3_column_int64(selectHash, 0); result = (foundRowId > 0); @@ -1647,7 +2312,7 @@ errOut: return result; } -static bool _SecRevocationDbSerialInFilter(SecRevocationDbRef this, +static bool _SecRevocationDbSerialInFilter(SecRevocationDbRef rdb, CFDataRef serialData, CFDataRef xmlData) { /* N-To-1 filter implementation. @@ -1713,82 +2378,74 @@ errOut: return result; } -static SecValidInfoRef _SecRevocationDbValidInfoForCertificate(SecRevocationDbRef this, +static SecValidInfoRef _SecRevocationDbValidInfoForCertificate(SecRevocationDbRef rdb, SecCertificateRef certificate, CFDataRef issuerHash, CFErrorRef *error) { __block CFErrorRef localError = NULL; - __block bool ok = true; - __block int flags = 0; + __block SecValidInfoFlags flags = 0; __block SecValidInfoFormat format = kSecValidInfoFormatUnknown; __block CFDataRef data = NULL; bool matched = false; + bool isOnList = false; int64_t groupId = 0; CFDataRef serial = NULL; CFDataRef certHash = NULL; SecValidInfoRef result = NULL; -#if TARGET_OS_OSX - require(serial = SecCertificateCopySerialNumber(certificate, NULL), errOut); -#else - require(serial = SecCertificateCopySerialNumber(certificate), errOut); -#endif - require(certHash = SecCertificateCopySHA256Digest(certificate), errOut); - - require(groupId = _SecRevocationDbGroupIdForIssuerHash(this, issuerHash, &localError), errOut); + require((serial = SecCertificateCopySerialNumberData(certificate, NULL)) != NULL, errOut); + require((certHash = SecCertificateCopySHA256Digest(certificate)) != NULL, errOut); + require((groupId = _SecRevocationDbGroupIdForIssuerHash(rdb, issuerHash, &localError)) > 0, errOut); - /* Select the group record to determine flags and format. */ - ok &= SecDbPerformRead(this->db, &localError, ^(SecDbConnectionRef dbconn) { - ok &= SecDbWithSQL(dbconn, selectGroupRecordSQL, &localError, ^bool(sqlite3_stmt *selectGroup) { - ok = SecDbBindInt64(selectGroup, 1, groupId, &localError); - ok &= SecDbStep(dbconn, selectGroup, &localError, ^(bool *stop) { - flags = (int)sqlite3_column_int(selectGroup, 0); - format = (SecValidInfoFormat)sqlite3_column_int(selectGroup, 1); - uint8_t *p = (uint8_t *)sqlite3_column_blob(selectGroup, 2); - if (p != NULL && format == kSecValidInfoFormatNto1) { - CFIndex length = (CFIndex)sqlite3_column_bytes(selectGroup, 2); - data = CFDataCreate(kCFAllocatorDefault, p, length); - } - }); - return ok; - }); - }); + /* Look up the group record to determine flags and format. */ + format = _SecRevocationDbGetGroupFormat(rdb, groupId, &flags, &data, &localError); if (format == kSecValidInfoFormatUnknown) { /* No group record found for this issuer. */ } else if (format == kSecValidInfoFormatSerial) { /* Look up certificate's serial number in the serials table. */ - matched = _SecRevocationDbSerialInGroup(this, serial, groupId, &localError); + matched = _SecRevocationDbSerialInGroup(rdb, serial, groupId, &localError); } else if (format == kSecValidInfoFormatSHA256) { /* Look up certificate's SHA-256 hash in the hashes table. */ - matched = _SecRevocationDbCertHashInGroup(this, certHash, groupId, &localError); + matched = _SecRevocationDbCertHashInGroup(rdb, certHash, groupId, &localError); } else if (format == kSecValidInfoFormatNto1) { /* Perform a Bloom filter match against the serial. If matched is false, then the cert is definitely not in the list. But if matched is true, we don't know for certain, so we would need to check OCSP. */ - matched = _SecRevocationDbSerialInFilter(this, serial, data); + matched = _SecRevocationDbSerialInFilter(rdb, serial, data); } if (matched) { - /* Always return SecValidInfo for a matched certificate. */ - secdebug("validupdate", "Valid db matched cert: %@, format=%d, flags=%d", + /* Found a specific match for this certificate. */ + secdebug("validupdate", "Valid db matched certificate: %@, format=%d, flags=%lu", certHash, format, flags); - result = SecValidInfoCreate(format, flags, certHash, issuerHash); + isOnList = true; } else if ((flags & kSecValidInfoComplete) && (flags & kSecValidInfoAllowlist)) { - /* Not matching against a complete whitelist is equivalent to revocation. */ - secdebug("validupdate", "Valid db did NOT match cert on allowlist: %@, format=%d, flags=%d", + /* Not matching against a complete allowlist is equivalent to revocation. */ + secdebug("validupdate", "Valid db did NOT match certificate on allowlist: %@, format=%d, flags=%lu", + certHash, format, flags); + matched = true; + } + else if ((!(flags & kSecValidInfoComplete)) && (format > kSecValidInfoFormatUnknown)) { + /* Not matching against an incomplete list implies we need to check OCSP. */ + secdebug("validupdate", "Valid db did not find certificate on incomplete list: %@, format=%d, flags=%lu", certHash, format, flags); - result = SecValidInfoCreate(format, flags, certHash, issuerHash); + matched = true; + } + + if (matched) { + /* Return SecValidInfo for a matched certificate. */ + result = SecValidInfoCreate(format, flags, isOnList, certHash, issuerHash, NULL); } if (result && SecIsAppleTrustAnchor(certificate, 0)) { /* Prevent a catch-22. */ - secdebug("validupdate", "Valid db match for Apple trust anchor: %@, format=%d, flags=%d", + secdebug("validupdate", "Valid db match for Apple trust anchor: %@, format=%d, flags=%lu", certHash, format, flags); SecValidInfoRelease(result); result = NULL; @@ -1820,8 +2477,8 @@ errOut: return result; } -static dispatch_queue_t _SecRevocationDbGetUpdateQueue(SecRevocationDbRef this) { - return (this) ? this->update_queue : NULL; +static dispatch_queue_t _SecRevocationDbGetUpdateQueue(SecRevocationDbRef rdb) { + return (rdb) ? rdb->update_queue : NULL; } @@ -1845,6 +2502,38 @@ void SecRevocationDbSetSchemaVersion(CFIndex db_version) { }); } +/* Set the update format for the revocation database. + (This function is expected to be called only by the database maintainer, + normally the system instance of trustd.) +*/ +void SecRevocationDbSetUpdateFormat(CFIndex db_format) { + SecRevocationDbWith(^(SecRevocationDbRef db) { + _SecRevocationDbSetUpdateFormat(db, db_format); + }); +} + +/* Set the update source for the revocation database. + (This function is expected to be called only by the database + maintainer, normally the system instance of trustd. If the + caller does not have write access, this is a no-op.) +*/ +void SecRevocationDbSetUpdateSource(CFStringRef updateSource) { + SecRevocationDbWith(^(SecRevocationDbRef db) { + _SecRevocationDbSetUpdateSource(db, updateSource); + }); +} + +/* Return the update source as a retained CFStringRef. + If the value cannot be obtained, NULL is returned. +*/ +CFStringRef SecRevocationDbCopyUpdateSource(void) { + __block CFStringRef result = NULL; + SecRevocationDbWith(^(SecRevocationDbRef db) { + result = _SecRevocationDbCopyUpdateSource(db, NULL); + }); + return result; +} + /* Set the next update value for the revocation database. (This function is expected to be called only by the database maintainer, normally the system instance of trustd. If the @@ -1888,7 +2577,15 @@ void SecRevocationDbRemoveAllEntries(void) { }); } -/* === Public API === */ +/* Release all connections to the revocation database. +*/ +void SecRevocationDbReleaseAllConnections(void) { + SecRevocationDbWith(^(SecRevocationDbRef db) { + SecDbReleaseAllConnections((db) ? db->db : NULL); + }); +} + +/* === SecRevocationDb API === */ /* Given a certificate and its issuer, returns a SecValidInfoRef if the valid database contains matching info; otherwise returns NULL. @@ -1927,3 +2624,15 @@ CFIndex SecRevocationDbGetSchemaVersion(void) { }); return result; } + +/* Return the current update format of the revocation database. + A version of 0 indicates the format was unknown. + If the update format cannot be obtained, -1 is returned. +*/ +CFIndex SecRevocationDbGetUpdateFormat(void) { + __block CFIndex result = -1; + SecRevocationDbWith(^(SecRevocationDbRef db) { + result = (CFIndex)_SecRevocationDbGetUpdateFormat(db, NULL); + }); + return result; +} diff --git a/OSX/sec/securityd/SecRevocationDb.h b/OSX/sec/securityd/SecRevocationDb.h index 24808cc6..6c7c8c90 100644 --- a/OSX/sec/securityd/SecRevocationDb.h +++ b/OSX/sec/securityd/SecRevocationDb.h @@ -58,11 +58,14 @@ struct __SecValidInfo { SecValidInfoFormat format; // format of per-issuer validity data CFDataRef certHash; // SHA-256 hash of cert to which the following info applies CFDataRef issuerHash; // SHA-256 hash of issuing CA certificate - bool valid; // true if found on allow list, false if on block list + CFDataRef anchorHash; // SHA-256 hash of anchor certificate (optional) + bool isOnList; // true if this cert was found on allow list or block list + bool valid; // true if this is an allow list, false if a block list bool complete; // true if list is complete (i.e. status is definitive) bool checkOCSP; // true if complete is false and OCSP check is required bool knownOnly; // true if all intermediates under issuer must be found in database bool requireCT; // true if this cert must have CT proof + bool noCACheck; // true if an entry does not require an OCSP check to accept }; /*! @@ -72,12 +75,20 @@ struct __SecValidInfo { */ void SecValidInfoRelease(SecValidInfoRef validInfo); +/*! + @function SecValidInfoSetAnchor + @abstract Updates a SecValidInfo reference with info about the anchor certificate in a chain. + @param validInfo The SecValidInfo reference to be updated. + @param anchor The certificate which anchors the chain for the certificate in this SecValidInfo reference. + @discussion A SecValidInfo reference contains information about a single certificate and its issuer. In some cases, it may be necessary to additionally examine the anchor of the certificate chain to determine validity. + */ +void SecValidInfoSetAnchor(SecValidInfoRef validInfo, SecCertificateRef anchor); + /*! @function SecRevocationDbCheckNextUpdate @abstract Periodic hook to poll for updates. - @result A boolean value indicating whether an update check was dispatched. */ -bool SecRevocationDbCheckNextUpdate(void); +void SecRevocationDbCheckNextUpdate(void); /*! @function SecRevocationDbCopyMatching @@ -103,6 +114,35 @@ CFIndex SecRevocationDbGetVersion(void); */ CFIndex SecRevocationDbGetSchemaVersion(void); +/*! + @function SecValidUpdateVerifyAndIngest + @abstract Callback for receiving update data. + @param updateData The decompressed update data. + */ +void SecValidUpdateVerifyAndIngest(CFDataRef updateData); + +/*! + @function readValidFile + @abstract Reads data into a CFDataRef using mmap. + @param fileName The file to read. + @param bytes The data read from the file. + @result An integer indicating failure (non-zero) or success. + @discussion This function mmaps the file and then makes a no-copy CFData for use of that mmapped file. This data MUST be munmapped when the caller has finished with the data. + */ +int readValidFile(const char *fileName, CFDataRef *bytes); + +/*! + @function SecRevocationDbComputeAndSetNextUpdateTime + @abstract Callback to push forward next update. + */ +void SecRevocationDbComputeAndSetNextUpdateTime(void); + +/*! + @function SecRevocationDbInitialize + @abstract Initializes revocation database if it doesn't exist or needs to be replaced. This should only be called once at process startup, before any database connections are established. + */ +void SecRevocationDbInitialize(void); + __END_DECLS diff --git a/OSX/sec/SOSCircle/Regressions/sc-140-hsa2.c b/OSX/sec/securityd/SecRevocationNetworking.h similarity index 81% rename from OSX/sec/SOSCircle/Regressions/sc-140-hsa2.c rename to OSX/sec/securityd/SecRevocationNetworking.h index 15e03c51..6af99881 100644 --- a/OSX/sec/SOSCircle/Regressions/sc-140-hsa2.c +++ b/OSX/sec/securityd/SecRevocationNetworking.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,19 +19,9 @@ * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ + * */ +#import -#include - -#include "SOSCircle_regressions.h" - -int -sc_140_hsa2(int argc, char *const *argv) -{ - plan_tests(1); - - ok(true); - - return 0; -} +bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version); diff --git a/OSX/sec/securityd/SecRevocationNetworking.m b/OSX/sec/securityd/SecRevocationNetworking.m new file mode 100644 index 00000000..d64069ac --- /dev/null +++ b/OSX/sec/securityd/SecRevocationNetworking.m @@ -0,0 +1,408 @@ +/* + * 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@ + * + */ + +#include +#import +#import + +#include +#include +#include +#include "utilities/debugging.h" +#include "utilities/SecCFWrappers.h" +#include "utilities/SecPLWrappers.h" +#include "utilities/SecFileLocations.h" + +#include "SecRevocationDb.h" + +#import "SecRevocationNetworking.h" + +#define kSecRevocationBasePath "/Library/Keychains/crls" + +static CFStringRef kSecPrefsDomain = CFSTR("com.apple.security"); +static CFStringRef kUpdateWiFiOnlyKey = CFSTR("ValidUpdateWiFiOnly"); +static CFStringRef kUpdateBackgroundKey = CFSTR("ValidUpdateBackground"); + +extern CFAbsoluteTime gUpdateStarted; +extern CFAbsoluteTime gNextUpdate; + +static int checkBasePath(const char *basePath) { + return mkpath_np((char*)basePath, 0755); +} + +static uint64_t systemUptimeInSeconds() { + struct timeval boottime; + size_t tv_size = sizeof(boottime); + time_t now, uptime = 0; + int mib[2]; + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + (void) time(&now); + if (sysctl(mib, 2, &boottime, &tv_size, NULL, 0) != -1 && + boottime.tv_sec != 0) { + uptime = now - boottime.tv_sec; + } + return (uint64_t)uptime; +} + +typedef void (^CompletionHandler)(void); + +@interface ValidDelegate : NSObject +@property CompletionHandler handler; +@property dispatch_queue_t revDbUpdateQueue; +@property os_transaction_t transaction; +@property NSFileHandle *currentUpdateFile; +@property NSURL *currentUpdateFileURL; +@property BOOL finishedDownloading; +@end + +@implementation ValidDelegate + +- (void)reschedule { + /* make sure we release any os transaction, if we went active */ + if (self->_transaction) { + //os_release(self->_transaction); // ARC does this for us and won't let us call release + self->_transaction = NULL; + } + /* POWER LOG EVENT: operation canceled */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : (self->_finishedDownloading) ? @"updateCanceled" : @"downloadCanceled" + }); + secnotice("validupdate", "%s canceled at %f", + (self->_finishedDownloading) ? "update" : "download", + (double)CFAbsoluteTimeGetCurrent()); + + self->_handler(); + SecRevocationDbComputeAndSetNextUpdateTime(); +} + +- (void)updateDb:(NSUInteger)version{ + __block NSURL *updateFileURL = self->_currentUpdateFileURL; + __block NSFileHandle *updateFile = self->_currentUpdateFile; + if (!updateFileURL || !updateFile) { + [self reschedule]; + return; + } + + dispatch_async(_revDbUpdateQueue, ^{ + /* POWER LOG EVENT: background update started */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"updateStarted" + }); + secnotice("validupdate", "update started at %f", (double)CFAbsoluteTimeGetCurrent()); + + CFDataRef updateData = NULL; + const char *updateFilePath = [updateFileURL fileSystemRepresentation]; + int rtn; + if ((rtn = readValidFile(updateFilePath, &updateData)) != 0) { + secerror("failed to read %@ with error %d", updateFileURL, rtn); + [self reschedule]; + return; + } + + secdebug("validupdate", "verifying and ingesting data from %@", updateFileURL); + SecValidUpdateVerifyAndIngest(updateData); + if ((rtn = munmap((void *)CFDataGetBytePtr(updateData), CFDataGetLength(updateData))) != 0) { + secerror("unable to unmap current update %ld bytes at %p (error %d)", CFDataGetLength(updateData), CFDataGetBytePtr(updateData), rtn); + } + CFReleaseNull(updateData); + + /* We're done with this file */ + [updateFile closeFile]; + if (updateFilePath) { + (void)remove(updateFilePath); + } + self->_currentUpdateFile = nil; + self->_currentUpdateFileURL = nil; + + /* POWER LOG EVENT: background update finished */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"updateFinished" + }); + + /* Update is complete */ + secnotice("validupdate", "update finished at %f", (double)CFAbsoluteTimeGetCurrent()); + gUpdateStarted = 0; + + self->_handler(); + }); +} + +- (NSInteger)versionFromTask:(NSURLSessionTask *)task { + return atol([task.taskDescription cStringUsingEncoding:NSUTF8StringEncoding]); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { + secinfo("validupdate", "Session %@ data task %@ returned response %ld, expecting %lld bytes", session, dataTask, + (long)[(NSHTTPURLResponse *)response statusCode],[response expectedContentLength]); + + (void)checkBasePath(kSecRevocationBasePath); + CFURLRef updateFileURL = SecCopyURLForFileInRevocationInfoDirectory(CFSTR("update-current")); + self->_currentUpdateFileURL = (updateFileURL) ? CFBridgingRelease(updateFileURL) : nil; + const char *updateFilePath = [self->_currentUpdateFileURL fileSystemRepresentation]; + if (!updateFilePath) { + secnotice("validupdate", "failed to find revocation info directory. canceling task %@", dataTask); + completionHandler(NSURLSessionResponseCancel); + [self reschedule]; + return; + } + + /* Clean up any old files from previous tasks. */ + (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) { + secnotice("validupdate","unable to open %@ (errno %d)", self->_currentUpdateFileURL, errno); + } + if (fd >= 0) { + close(fd); + } + + /* POWER LOG EVENT: background download actually started */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"downloadStarted" + }); + secnotice("validupdate", "download started at %f", (double)CFAbsoluteTimeGetCurrent()); + + NSError *error = nil; + self->_currentUpdateFile = [NSFileHandle fileHandleForWritingToURL:self->_currentUpdateFileURL error:&error]; + if (!self->_currentUpdateFile) { + secnotice("validupdate", "failed to open %@: %@. canceling task %@", self->_currentUpdateFileURL, error, dataTask); + completionHandler(NSURLSessionResponseCancel); + [self reschedule]; + return; + } + + /* We're about to begin downloading -- go active now so we don't get jetsammed */ + self->_transaction = os_transaction_create("com.apple.trustd.valid.download"); + completionHandler(NSURLSessionResponseAllow); +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + secdebug("validupdate", "Session %@ data task %@ returned %lu bytes (%lld bytes so far) out of expected %lld bytes", + session, dataTask, (unsigned long)[data length], [dataTask countOfBytesReceived], [dataTask countOfBytesExpectedToReceive]); + + if (!self->_currentUpdateFile) { + secnotice("validupdate", "received data, but output file is not open"); + [dataTask cancel]; + [self reschedule]; + return; + } + + @try { + /* Writing can fail and throw an exception, e.g. if we run out of disk space. */ + [self->_currentUpdateFile writeData:data]; + } + @catch(NSException *exception) { + secnotice("validupdate", "%s", exception.description.UTF8String); + [dataTask cancel]; + [self reschedule]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +didCompleteWithError:(NSError *)error { + /* all finished downloading data -- go inactive */ + if (self->_transaction) { + // os_release(self->_transaction); // ARC does this for us and won't let us call release + self->_transaction = NULL; + } + if (error) { + secnotice("validupdate", "Session %@ task %@ failed with error %@", session, task, error); + [self reschedule]; + /* close file before we leave */ + [self->_currentUpdateFile closeFile]; + self->_currentUpdateFile = nil; + self->_currentUpdateFileURL = nil; + } else { + /* POWER LOG EVENT: background download finished */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"downloadFinished" + }); + secnotice("validupdate", "download finished at %f", (double)CFAbsoluteTimeGetCurrent()); + secdebug("validupdate", "Session %@ task %@ succeeded", session, task); + self->_finishedDownloading = YES; + [self updateDb:[self versionFromTask:task]]; + } +} + +@end + +@interface ValidUpdateRequest : NSObject +@property NSTimeInterval updateScheduled; +@property NSURLSession *backgroundSession; +@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 *config = nil; + if (updateInBackground) { + config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: @"com.apple.trustd.networking.background"]; + config.networkServiceType = NSURLNetworkServiceTypeBackground; + config.discretionary = YES; + } else { + config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; // no cookies or data storage + config.networkServiceType = NSURLNetworkServiceTypeDefault; + config.discretionary = NO; + } + + config.HTTPAdditionalHeaders = @{ @"User-Agent" : @"com.apple.trustd/2.0", + @"Accept" : @"*/*", + @"Accept-Encoding" : @"gzip,deflate,br"}; + + config.TLSMinimumSupportedProtocol = kTLSProtocol12; + config.TLSMaximumSupportedProtocol = kTLSProtocol13; + + config._requiresPowerPluggedIn = YES; + + config.allowsCellularAccess = (!updateOnWiFiOnly) ? YES : NO; + + return config; +} + +- (void) createSession:(dispatch_queue_t)updateQueue { + NSURLSessionConfiguration *config = [self validUpdateConfiguration]; + ValidDelegate *delegate = [[ValidDelegate alloc] init]; + delegate.handler = ^(void) { + request.updateScheduled = 0.0; + secdebug("validupdate", "resetting scheduled time"); + }; + delegate.transaction = NULL; + delegate.revDbUpdateQueue = updateQueue; + delegate.finishedDownloading = NO; + + /* Callbacks should be on a separate NSOperationQueue. + We'll then dispatch the work on updateQueue and return from the callback. */ + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + _backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue]; +} + +- (BOOL) scheduleUpdateFromServer:(NSString *)server forVersion:(NSUInteger)version withQueue:(dispatch_queue_t)updateQueue { + if (!server) { + secnotice("validupdate", "invalid update request"); + return NO; + } + + if (!updateQueue) { + secnotice("validupdate", "missing update queue, skipping update"); + return NO; + } + + /* nsurlsessiond waits for unlock to finish launching, so we can't block trust evaluations + * on scheduling this background task. Also, we want to wait a sufficient amount of time + * after system boot before trying to initiate network activity, to avoid the possibility + * of a performance regression in the boot path. + */ + dispatch_async(updateQueue, ^{ + CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); + if (self.updateScheduled != 0.0) { + secdebug("validupdate", "update in progress (scheduled %f)", (double)self.updateScheduled); + return; + } else { + uint64_t uptime = systemUptimeInSeconds(); + const uint64_t minUptime = 180; + if (uptime < minUptime) { + gNextUpdate = now + (minUptime - uptime); + gUpdateStarted = 0; + secnotice("validupdate", "postponing update until %f", gNextUpdate); + } else { + self.updateScheduled = now; + secnotice("validupdate", "scheduling update at %f", (double)self.updateScheduled); + } + } + + NSURL *validUrl = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@/g3/v%ld", + server, (unsigned long)version]]; + if (!validUrl) { + secnotice("validupdate", "invalid update url"); + return; + } + + /* clear all old sessions and cleanup disk (for previous download tasks) */ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [NSURLSession _obliterateAllBackgroundSessionsWithCompletionHandler:^{ + secnotice("validupdate", "removing all old sessions for trustd"); + }]; + }); + + if (!self.backgroundSession) { + [self createSession:updateQueue]; + } + + /* POWER LOG EVENT: scheduling our background download session now */ + SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{ + @"timestamp" : @([[NSDate date] timeIntervalSince1970]), + @"event" : @"downloadScheduled", + @"version" : @(version) + }); + + NSURLSessionDataTask *dataTask = [self.backgroundSession dataTaskWithURL:validUrl]; + dataTask.taskDescription = [NSString stringWithFormat:@"%ld",version]; + [dataTask resume]; + secnotice("validupdate", "scheduled background data task %@ at %f", dataTask, CFAbsoluteTimeGetCurrent()); + }); + + return YES; +} +@end + +bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + request = [[ValidUpdateRequest alloc] init]; + }); + return [request scheduleUpdateFromServer:(__bridge NSString*)server forVersion:version withQueue:queue]; +} diff --git a/OSX/sec/securityd/SecRevocationServer.c b/OSX/sec/securityd/SecRevocationServer.c new file mode 100644 index 00000000..60abe20a --- /dev/null +++ b/OSX/sec/securityd/SecRevocationServer.c @@ -0,0 +1,1096 @@ +/* + * Copyright (c) 2008-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * SecRevocationServer.c - Engine for evaluating certificate revocation. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +// MARK: SecORVCRef +/******************************************************** + ****************** OCSP RVC Functions ****************** + ********************************************************/ +const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0; +const CFAbsoluteTime kSecOCSPResponseOnlineTTL = 5.0 * 60.0; +#define OCSP_RESPONSE_TIMEOUT (3 * NSEC_PER_SEC) + +/* OCSP Revocation verification context. */ +struct OpaqueSecORVC { + /* Will contain the response data. */ + asynchttp_t http; + + /* Pointer to the builder for this revocation check. */ + SecPathBuilderRef builder; + + /* Pointer to the generic rvc for this revocation check */ + SecRVCRef rvc; + + /* The ocsp request we send to each responder. */ + SecOCSPRequestRef ocspRequest; + + /* The freshest response we received so far, from stapling or cache or responder. */ + SecOCSPResponseRef ocspResponse; + + /* The best validated candidate single response we received so far, from stapling or cache or responder. */ + SecOCSPSingleResponseRef ocspSingleResponse; + + /* Index of cert in builder that this RVC is for 0 = leaf, etc. */ + CFIndex certIX; + + /* Index in array returned by SecCertificateGetOCSPResponders() for current + responder. */ + CFIndex responderIX; + + /* URL of current responder. */ + CFURLRef responder; + + /* Date until which this revocation status is valid. */ + CFAbsoluteTime nextUpdate; + + bool done; +}; + +static void SecORVCFinish(SecORVCRef orvc) { + secdebug("alloc", "%p", orvc); + asynchttp_free(&orvc->http); + if (orvc->ocspRequest) { + SecOCSPRequestFinalize(orvc->ocspRequest); + orvc->ocspRequest = NULL; + } + if (orvc->ocspResponse) { + SecOCSPResponseFinalize(orvc->ocspResponse); + orvc->ocspResponse = NULL; + if (orvc->ocspSingleResponse) { + SecOCSPSingleResponseDestroy(orvc->ocspSingleResponse); + orvc->ocspSingleResponse = NULL; + } + } +} + +#define MAX_OCSP_RESPONDERS 3 +#define OCSP_REQUEST_THRESHOLD 10 + +/* Return the next responder we should contact for this rvc or NULL if we + exhausted them all. */ +static CFURLRef SecORVCGetNextResponder(SecORVCRef rvc) { + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert); + if (ocspResponders) { + CFIndex responderCount = CFArrayGetCount(ocspResponders); + if (responderCount >= OCSP_REQUEST_THRESHOLD) { + secnotice("rvc", "too many ocsp responders (%ld)", (long)responderCount); + return NULL; + } + while (rvc->responderIX < responderCount && rvc->responderIX < MAX_OCSP_RESPONDERS) { + CFURLRef responder = CFArrayGetValueAtIndex(ocspResponders, rvc->responderIX); + rvc->responderIX++; + CFStringRef scheme = CFURLCopyScheme(responder); + if (scheme) { + /* We only support http and https responders currently. */ + bool valid_responder = (CFEqual(CFSTR("http"), scheme) || + CFEqual(CFSTR("https"), scheme)); + CFRelease(scheme); + if (valid_responder) + return responder; + } + } + } + return NULL; +} + +/* Fire off an async http request for this certs revocation status, return + false if request was queued, true if we're done. */ +static bool SecORVCFetchNext(SecORVCRef rvc) { + while ((rvc->responder = SecORVCGetNextResponder(rvc))) { + CFDataRef request = SecOCSPRequestGetDER(rvc->ocspRequest); + if (!request) + goto errOut; + + secinfo("rvc", "Sending http ocsp request for cert %ld", rvc->certIX); + if (!asyncHttpPost(rvc->responder, request, OCSP_RESPONSE_TIMEOUT, &rvc->http)) { + /* Async request was posted, wait for reply. */ + return false; + } + } + +errOut: + rvc->done = true; + return true; +} + +/* Process a verified ocsp response for a given cert. Return true if the + certificate status was obtained. */ +static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this, + SecORVCRef rvc) { + bool processed; + switch (this->certStatus) { + case CS_Good: + secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX); + /* @@@ Mark cert as valid until a given date (nextUpdate if we have one) + in the info dictionary. */ + //cert.revokeCheckGood(true); + rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate; + processed = true; + break; + case CS_Revoked: + secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX); + /* @@@ Mark cert as revoked (with reason) at revocation date in + the info dictionary, or perhaps we should use a different key per + reason? That way a client using exceptions can ignore some but + not all reasons. */ + SInt32 reason = this->crlReason; + CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, + cfreason, true, kSecTrustResultFatalTrustFailure); + if (rvc->builder) { + CFMutableDictionaryRef info = SecPathBuilderGetInfo(rvc->builder); + if (info) { + /* make the revocation reason available in the trust result */ + CFDictionarySetValue(info, kSecTrustRevocationReason, cfreason); + } + } + CFRelease(cfreason); + processed = true; + break; + case CS_Unknown: + /* not an error, no per-cert status, nothing here */ + secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX); + processed = false; + break; + default: + secnotice("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex, + (int)this->certStatus, rvc->certIX); + processed = false; + break; + } + + return processed; +} + +static void SecORVCUpdatePVC(SecORVCRef rvc) { + if (rvc->ocspSingleResponse) { + SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc); + } + if (rvc->ocspResponse) { + rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse); + } +} + +typedef void (^SecOCSPEvaluationCompleted)(SecTrustResultType tr); + +static void +SecOCSPEvaluateCompleted(const void *userData, + SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info, + SecTrustResultType result) { + SecOCSPEvaluationCompleted evaluated = (SecOCSPEvaluationCompleted)userData; + evaluated(result); + Block_release(evaluated); + +} + +static bool SecOCSPResponseEvaluateSigner(SecORVCRef rvc, CFArrayRef signers, CFArrayRef issuers, CFAbsoluteTime verifyTime) { + __block bool evaluated = false; + bool trusted = false; + if (!signers || !issuers) { + return trusted; + } + + /* Verify the signer chain against the OCSPSigner policy, using the issuer chain as anchors. */ + const void *ocspSigner = SecPolicyCreateOCSPSigner(); + CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault, + &ocspSigner, 1, &kCFTypeArrayCallBacks); + CFRelease(ocspSigner); + + SecOCSPEvaluationCompleted completed = Block_copy(^(SecTrustResultType result) { + if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) { + evaluated = true; + } + }); + + CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->builder); + SecPathBuilderRef oBuilder = SecPathBuilderCreate(clientAuditToken, + signers, issuers, true, false, + policies, NULL, NULL, NULL, + verifyTime, NULL, NULL, + SecOCSPEvaluateCompleted, completed); + /* Build the chain(s), evaluate them, call the completed block, free the block and builder */ + SecPathBuilderStep(oBuilder); + CFReleaseNull(clientAuditToken); + CFReleaseNull(policies); + + /* verify the public key of the issuer signed the OCSP signer */ + if (evaluated) { + SecCertificateRef issuer = NULL, signer = NULL; + SecKeyRef issuerPubKey = NULL; + + issuer = (SecCertificateRef)CFArrayGetValueAtIndex(issuers, 0); + signer = (SecCertificateRef)CFArrayGetValueAtIndex(signers, 0); + + if (issuer) { +#if TARGET_OS_IPHONE + issuerPubKey = SecCertificateCopyPublicKey(issuer); +#else + issuerPubKey = SecCertificateCopyPublicKey_ios(issuer); +#endif + } + if (signer && issuerPubKey && (errSecSuccess == SecCertificateIsSignedBy(signer, issuerPubKey))) { + trusted = true; + } else { + secnotice("ocsp", "ocsp signer cert not signed by issuer"); + } + CFReleaseNull(issuerPubKey); + } + + return trusted; +} + +static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecORVCRef rvc, CFAbsoluteTime verifyTime) { + bool trusted; + SecCertificatePathVCRef issuers = SecCertificatePathVCCopyFromParent(SecPathBuilderGetPath(rvc->builder), rvc->certIX + 1); + SecCertificateRef issuer = issuers ? CFRetainSafe(SecCertificatePathVCGetCertificateAtIndex(issuers, 0)) : NULL; + CFArrayRef signers = SecOCSPResponseCopySigners(ocspResponse); + SecCertificateRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer); + + if (signer && signers) { + if (issuer && CFEqual(signer, issuer)) { + /* We already know we trust issuer since it's the issuer of the + * cert we are verifying. */ + secinfo("ocsp", "ocsp responder: %@ response signed by issuer", + rvc->responder); + trusted = true; + } else { + secinfo("ocsp", "ocsp responder: %@ response signed by cert issued by issuer", + rvc->responder); + CFMutableArrayRef signerCerts = NULL; + CFArrayRef issuerCerts = NULL; + + /* Ensure the signer cert is the 0th cert for trust evaluation */ + signerCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(signerCerts, signer); + CFArrayAppendArray(signerCerts, signers, CFRangeMake(0, CFArrayGetCount(signers))); + + if (issuers) { + issuerCerts = SecCertificatePathVCCopyCertificates(issuers); + } + + if (SecOCSPResponseEvaluateSigner(rvc, signerCerts, issuerCerts, verifyTime)) { + secdebug("ocsp", "response satisfies ocspSigner policy (%@)", + rvc->responder); + trusted = true; + } else { + /* @@@ We don't trust the cert so don't use this response. */ + secnotice("ocsp", "ocsp response signed by certificate which " + "does not satisfy ocspSigner policy"); + trusted = false; + } + CFReleaseNull(signerCerts); + CFReleaseNull(issuerCerts); + } + } else { + /* @@@ No signer found for this ocsp response, discard it. */ + secnotice("ocsp", "ocsp responder: %@ no signer found for response", + rvc->responder); + trusted = false; + } + +#if DUMP_OCSPRESPONSES + char buf[40]; + snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der", + rvc->certIX, (trusted ? "t" : "u")); + secdumpdata(ocspResponse->data, buf); +#endif + CFReleaseNull(issuers); + CFReleaseNull(issuer); + CFReleaseNull(signers); + CFReleaseNull(signer); + return trusted; +} + +static void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/, CFTimeInterval maxAge, bool updateCache) { + SecOCSPSingleResponseRef sr = NULL; + require_quiet(ocspResponse, errOut); + SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse); + require_action_quiet(orStatus == kSecOCSPSuccess, errOut, + secnotice("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus)); + require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut, + secnotice("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder)); + // Check if this response is fresher than any (cached) response we might still have in the rvc. + require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut); + + CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent(); + /* TODO: If the responder doesn't have the ocsp-nocheck extension we should + check whether the leaf was revoked (we are already checking the rest of + the chain). */ + /* Check the OCSP response signature and verify the response. */ + require_quiet(SecOCSPResponseVerify(ocspResponse, rvc, + sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut); + + // If we get here, we have a properly signed ocsp response + // but we haven't checked dates yet. + + bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime); + if (sr->certStatus == CS_Good) { + // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime + require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut); + } else if (sr->certStatus == CS_Revoked) { + // Expire revoked responses when the subject certificate itself expires. + ocspResponse->expireTime = SecCertificateNotValidAfter(SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX)); + } + + // Ok we like the new response, let's toss the old one. + if (updateCache) + SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime); + + if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse); + rvc->ocspResponse = ocspResponse; + ocspResponse = NULL; + + if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse); + rvc->ocspSingleResponse = sr; + sr = NULL; + + rvc->done = sr_valid; + +errOut: + if (sr) SecOCSPSingleResponseDestroy(sr); + if (ocspResponse) SecOCSPResponseFinalize(ocspResponse); +} + +/* Callback from async http code after an ocsp response has been received. */ +static void SecOCSPFetchCompleted(asynchttp_t *http, CFTimeInterval maxAge) { + SecORVCRef rvc = (SecORVCRef)http->info; + SecPathBuilderRef builder = rvc->builder; + SecOCSPResponseRef ocspResponse = NULL; + if (http->response) { + CFDataRef data = CFHTTPMessageCopyBody(http->response); + if (data) { + /* Parse the returned data as if it's an ocspResponse. */ + ocspResponse = SecOCSPResponseCreate(data); + CFRelease(data); + } + } + + SecORVCConsumeOCSPResponse(rvc, ocspResponse, maxAge, true); + // TODO: maybe we should set the cache-control: false in the http header and try again if the response is stale + + if (!rvc->done) { + /* Clear the data for the next response. */ + asynchttp_free(http); + SecORVCFetchNext(rvc); + } + + if (rvc->done) { + secdebug("rvc", "got OCSP response for cert: %ld", rvc->certIX); + SecORVCUpdatePVC(rvc); + if (!SecPathBuilderDecrementAsyncJobCount(builder)) { + secdebug("rvc", "done with all async jobs"); + SecPathBuilderStep(builder); + } + } +} + +static SecORVCRef SecORVCCreate(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) { + SecORVCRef orvc = NULL; + orvc = malloc(sizeof(struct OpaqueSecORVC)); + if (orvc) { + memset(orvc, 0, sizeof(struct OpaqueSecORVC)); + orvc->builder = builder; + orvc->rvc = rvc; + orvc->certIX = certIX; + orvc->http.queue = SecPathBuilderGetQueue(builder); + orvc->http.token = SecPathBuilderCopyClientAuditToken(builder); + orvc->http.completed = SecOCSPFetchCompleted; + orvc->http.info = orvc; + orvc->ocspRequest = NULL; + orvc->responderIX = 0; + orvc->responder = NULL; + orvc->nextUpdate = NULL_TIME; + orvc->ocspResponse = NULL; + orvc->ocspSingleResponse = NULL; + orvc->done = false; + + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(builder, certIX); + if (SecPathBuilderGetCertificateCount(builder) > (certIX + 1)) { + SecCertificateRef issuer = SecPathBuilderGetCertificateAtIndex(builder, certIX + 1); + orvc->ocspRequest = SecOCSPRequestCreate(cert, issuer); + } + } + return orvc; +} + +static void SecORVCProcessStapledResponses(SecORVCRef rvc) { + /* Get stapled OCSP responses */ + CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(rvc->builder); + + if(ocspResponsesData) { + secdebug("rvc", "Checking stapled responses for cert %ld", rvc->certIX); + CFArrayForEach(ocspResponsesData, ^(const void *value) { + SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value); + SecORVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false); + }); + CFRelease(ocspResponsesData); + } +} + +// MARK: SecCRVCRef +/******************************************************** + ******************* CRL RVC Functions ****************** + ********************************************************/ +#if ENABLE_CRLS +#include <../trustd/macOS/SecTrustOSXEntryPoints.h> +#define kSecDefaultCRLTTL kSecDefaultOCSPResponseTTL + +/* CRL Revocation verification context. */ +struct OpaqueSecCRVC { + /* Response data from ocspd. Yes, ocspd does CRLs, but not OCSP... */ + async_ocspd_t async_ocspd; + + /* Pointer to the builder for this revocation check. */ + SecPathBuilderRef builder; + + /* Pointer to the generic rvc for this revocation check */ + SecRVCRef rvc; + + /* The current CRL status from ocspd. */ + OSStatus status; + + /* Index of cert in builder that this RVC is for 0 = leaf, etc. */ + CFIndex certIX; + + /* Index in array returned by SecCertificateGetCRLDistributionPoints() for + current distribution point. */ + CFIndex distributionPointIX; + + /* URL of current distribution point. */ + CFURLRef distributionPoint; + + /* Date until which this revocation status is valid. */ + CFAbsoluteTime nextUpdate; + + bool done; +}; + +static void SecCRVCFinish(SecCRVCRef crvc) { + // nothing yet +} + +#define MAX_CRL_DPS 3 +#define CRL_REQUEST_THRESHOLD 10 + +static CFURLRef SecCRVCGetNextDistributionPoint(SecCRVCRef rvc) { + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + CFArrayRef crlDPs = SecCertificateGetCRLDistributionPoints(cert); + if (crlDPs) { + CFIndex crlDPCount = CFArrayGetCount(crlDPs); + if (crlDPCount >= CRL_REQUEST_THRESHOLD) { + secnotice("rvc", "too many CRL DP entries (%ld)", (long)crlDPCount); + return NULL; + } + while (rvc->distributionPointIX < crlDPCount && rvc->distributionPointIX < MAX_CRL_DPS) { + CFURLRef distributionPoint = CFArrayGetValueAtIndex(crlDPs, rvc->distributionPointIX); + rvc->distributionPointIX++; + CFStringRef scheme = CFURLCopyScheme(distributionPoint); + if (scheme) { + /* We only support http and https responders currently. */ + bool valid_DP = (CFEqual(CFSTR("http"), scheme) || + CFEqual(CFSTR("https"), scheme) || + CFEqual(CFSTR("ldap"), scheme)); + CFRelease(scheme); + if (valid_DP) + return distributionPoint; + } + } + } + return NULL; +} + +static void SecCRVCGetCRLStatus(SecCRVCRef rvc) { + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); + SecCertificatePathRef nonVCpath = SecCertificatePathVCCopyCertificatePath(path); + CFArrayRef serializedCertPath = SecCertificatePathCreateSerialized(nonVCpath, NULL); + CFReleaseNull(nonVCpath); + secdebug("rvc", "searching CRL cache for cert: %ld", rvc->certIX); + rvc->status = SecTrustLegacyCRLStatus(cert, serializedCertPath, rvc->distributionPoint); + CFReleaseNull(serializedCertPath); + /* we got a response indicating that the CRL was checked */ + if (rvc->status == errSecSuccess || rvc->status == errSecCertificateRevoked) { + rvc->done = true; + /* ocspd doesn't give us the nextUpdate time, so set to default */ + rvc->nextUpdate = SecPathBuilderGetVerifyTime(rvc->builder) + kSecDefaultCRLTTL; + } +} + +static void SecCRVCCheckRevocationCache(SecCRVCRef rvc) { + while ((rvc->distributionPoint = SecCRVCGetNextDistributionPoint(rvc))) { + SecCRVCGetCRLStatus(rvc); + if (rvc->status == errSecCertificateRevoked) { + return; + } + } +} + +/* Fire off an async http request for this certs revocation status, return + false if request was queued, true if we're done. */ +static bool SecCRVCFetchNext(SecCRVCRef rvc) { + while ((rvc->distributionPoint = SecCRVCGetNextDistributionPoint(rvc))) { + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); + SecCertificatePathRef nonVCpath = SecCertificatePathVCCopyCertificatePath(path); + CFArrayRef serializedCertPath = SecCertificatePathCreateSerialized(nonVCpath, NULL); + CFReleaseNull(nonVCpath); + secinfo("rvc", "fetching CRL for cert: %ld", rvc->certIX); + if (!SecTrustLegacyCRLFetch(&rvc->async_ocspd, rvc->distributionPoint, + CFAbsoluteTimeGetCurrent(), cert, serializedCertPath)) { + CFDataRef clientAuditToken = NULL; + SecTaskRef task = NULL; + audit_token_t auditToken = {}; + clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->builder); + require(clientAuditToken, out); + require(sizeof(auditToken) == CFDataGetLength(clientAuditToken), out); + CFDataGetBytes(clientAuditToken, CFRangeMake(0, sizeof(auditToken)), (uint8_t *)&auditToken); + require(task = SecTaskCreateWithAuditToken(NULL, auditToken), out); + secnotice("rvc", "asynchronously fetching CRL (%@) for client (%@)", + rvc->distributionPoint, task); + + out: + CFReleaseNull(clientAuditToken); + CFReleaseNull(task); + /* Async request was posted, wait for reply. */ + return false; + } + } + rvc->done = true; + return true; +} + +static void SecCRVCUpdatePVC(SecCRVCRef rvc) { + if (rvc->status == errSecCertificateRevoked) { + secdebug("rvc", "CRL revoked cert %" PRIdCFIndex, rvc->certIX); + SInt32 reason = 0; // unspecified, since ocspd didn't tell us + CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, + cfreason, true, kSecTrustResultFatalTrustFailure); + if (rvc->builder) { + CFMutableDictionaryRef info = SecPathBuilderGetInfo(rvc->builder); + if (info) { + /* make the revocation reason available in the trust result */ + CFDictionarySetValue(info, kSecTrustRevocationReason, cfreason); + } + } + CFReleaseNull(cfreason); + } +} + +static void SecCRVCFetchCompleted(async_ocspd_t *ocspd) { + SecCRVCRef rvc = ocspd->info; + SecPathBuilderRef builder = rvc->builder; + /* we got a response indicating that the CRL was checked */ + if (ocspd->response == errSecSuccess || ocspd->response == errSecCertificateRevoked) { + rvc->status = ocspd->response; + rvc->done = true; + /* ocspd doesn't give us the nextUpdate time, so set to default */ + rvc->nextUpdate = SecPathBuilderGetVerifyTime(rvc->builder) + kSecDefaultCRLTTL; + secdebug("rvc", "got CRL response for cert: %ld", rvc->certIX); + SecCRVCUpdatePVC(rvc); + if (!SecPathBuilderDecrementAsyncJobCount(builder)) { + secdebug("rvc", "done with all async jobs"); + SecPathBuilderStep(builder); + } + } else { + if(SecCRVCFetchNext(rvc)) { + if (!SecPathBuilderDecrementAsyncJobCount(builder)) { + secdebug("rvc", "done with all async jobs"); + SecPathBuilderStep(builder); + } + } + } +} + +static SecCRVCRef SecCRVCCreate(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) { + SecCRVCRef crvc = NULL; + crvc = malloc(sizeof(struct OpaqueSecCRVC)); + if (crvc) { + memset(crvc, 0, sizeof(struct OpaqueSecCRVC)); + crvc->builder = builder; + crvc->rvc = rvc; + crvc->certIX = certIX; + crvc->status = errSecInternal; + crvc->distributionPointIX = 0; + crvc->distributionPoint = NULL; + crvc->nextUpdate = NULL_TIME; + crvc->async_ocspd.queue = SecPathBuilderGetQueue(builder); + crvc->async_ocspd.completed = SecCRVCFetchCompleted; + crvc->async_ocspd.response = errSecInternal; + crvc->async_ocspd.info = crvc; + crvc->done = false; + } + return crvc; +} + +static bool SecRVCShouldCheckCRL(SecRVCRef rvc) { + CFStringRef revocation_method = SecPathBuilderGetRevocationMethod(rvc->builder); + if (revocation_method && + CFEqual(kSecPolicyCheckRevocationCRL, revocation_method)) { + /* Our client insists on CRLs */ + secinfo("rvc", "client told us to check CRL"); + return true; + } + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert); + if ((!ocspResponders || CFArrayGetCount(ocspResponders) == 0) && + (revocation_method && !CFEqual(kSecPolicyCheckRevocationOCSP, revocation_method))) { + /* The cert doesn't have OCSP responders and the client didn't specifically ask for OCSP. + * This logic will skip the CRL cache check if the client didn't ask for revocation checking */ + secinfo("rvc", "client told us to check revocation and CRL is only option for cert: %ld", rvc->certIX); + return true; + } + return false; +} +#endif /* ENABLE_CRLS */ + +void SecRVCDelete(SecRVCRef rvc) { + if (rvc->orvc) { + SecORVCFinish(rvc->orvc); + free(rvc->orvc); + } +#if ENABLE_CRLS + if (rvc->crvc) { + SecCRVCFinish(rvc->crvc); + free(rvc->crvc); + } +#endif + if (rvc->valid_info) { + SecValidInfoRelease(rvc->valid_info); + } +} + +static void SecRVCInit(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) { + secdebug("alloc", "%p", rvc); + rvc->builder = builder; + rvc->certIX = certIX; + rvc->orvc = SecORVCCreate(rvc, builder, certIX); +#if ENABLE_CRLS + rvc->crvc = SecCRVCCreate(rvc, builder, certIX); +#endif + rvc->done = false; +} + +#if ENABLE_CRLS +static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) { + CFStringRef revocation_method = SecPathBuilderGetRevocationMethod(rvc->builder); + if (!revocation_method + || !CFEqual(revocation_method, kSecPolicyCheckRevocationCRL)) { + return true; + } + return false; +} +#else +static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) { + return true; +} +#endif + +static void SecRVCProcessValidInfoResults(SecRVCRef rvc) { + if (!rvc || !rvc->valid_info || !rvc->builder) { + return; + } + SecValidInfoFormat format = rvc->valid_info->format; + bool valid = rvc->valid_info->valid; + bool noCACheck = rvc->valid_info->noCACheck; + bool checkOCSP = rvc->valid_info->checkOCSP; + bool complete = rvc->valid_info->complete; + bool isOnList = rvc->valid_info->isOnList; + bool definitive = false; + + if (format == kSecValidInfoFormatSerial || format == kSecValidInfoFormatSHA256) { + /* serial or hash list: could be blocked or allowed; could be incomplete */ + if (((!valid && complete && isOnList) || (valid && complete && !isOnList)) && noCACheck) { + /* definitely revoked */ + SInt32 reason = 0; /* unspecified, since the Valid db doesn't tell us */ + CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason); + SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX, + cfreason, true, kSecTrustResultFatalTrustFailure); + CFMutableDictionaryRef info = SecPathBuilderGetInfo(rvc->builder); + if (info) { + /* make the revocation reason available in the trust result */ + CFDictionarySetValue(info, kSecTrustRevocationReason, cfreason); + } + CFReleaseNull(cfreason); + definitive = true; + } + else if (valid && complete && isOnList && noCACheck) { + /* definitely not revoked (allowlisted) */ + SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder); + if (path) { + SecCertificatePathVCSetIsAllowlisted(path, true); + } else { + secdebug("validupdate", "rvc: no certificate path for builder"); + } + definitive = true; + } + if (definitive) { + /* either definitely revoked or allowed; no need to check further. */ + secdebug("validupdate", "rvc: definitely %s cert %" PRIdCFIndex, + (valid && complete && isOnList) ? "allowed" : "revoked", rvc->certIX); + rvc->done = true; + return; + } + /* verify our info with the OCSP server */ + checkOCSP = true; + } + + /* Handle non-definitive information. + We set rvc->done = true above ONLY if the result was definitive; + otherwise we require a revocation check for SSL usage. + */ + if (format == kSecValidInfoFormatNto1) { + /* matched the filter */ + checkOCSP = true; + } + + if (checkOCSP) { + CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder); + CFIndex issuerIX = rvc->certIX + 1; + if (issuerIX >= count) { + /* cannot perform a revocation check on the last cert in the + chain, since we don't have its issuer. */ + return; + } + CFIndex pvcIX; + for (pvcIX = 0; pvcIX < SecPathBuilderGetPVCCount(rvc->builder); pvcIX++) { + SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, pvcIX); + if (!pvc) { continue; } + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0); + CFStringRef policyName = (policy) ? SecPolicyGetName(policy) : NULL; + if (policyName && CFEqual(CFSTR("sslServer"), policyName)) { + /* perform revocation check for SSL policy; + require for leaf if an OCSP responder is present. */ + if (0 == rvc->certIX) { + SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + CFArrayRef resps = (cert) ? SecCertificateGetOCSPResponders(cert) : NULL; + CFIndex rcount = (resps) ? CFArrayGetCount(resps) : 0; + if (rcount > 0) { + // %%% rdar://31279923 + // This currently requires a valid revocation response for each cert, + // but we only want to require a leaf check. For now, do not require. + //SecPathBuilderSetRevocationResponseRequired(rvc->builder); + } + } + secdebug("validupdate", "rvc: %s%s cert %" PRIdCFIndex " (will check OCSP)", + (complete) ? "" : "possibly ", (valid) ? "allowed" : "revoked", + rvc->certIX); + SecPathBuilderSetRevocationMethod(rvc->builder, kSecPolicyCheckRevocationAny); + } + } + } +} + +static bool SecRVCCheckValidInfoDatabase(SecRVCRef rvc) { + /* Skip checking for OCSP Signer verification */ + if (SecPathBuilderGetPVCCount(rvc->builder) == 1) { + SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, 0); + if (!pvc) { return false; } + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0); + CFStringRef policyName = (policy) ? SecPolicyGetName(policy) : NULL; + if (policyName && CFEqual(policyName, CFSTR("OCSPSigner"))) { + return false; + } + } + + /* Make sure revocation db info is up-to-date. + * We don't care if the builder is allowed to access the network because + * the network fetching does not block the trust evaluation. */ + SecRevocationDbCheckNextUpdate(); + + /* Check whether we have valid db info for this cert, + given the cert and its issuer */ + SecValidInfoRef info = NULL; + CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder); + if (count) { + bool isSelfSigned = false; + SecCertificateRef cert = NULL; + SecCertificateRef issuer = NULL; + CFIndex issuerIX = rvc->certIX + 1; + if (count > issuerIX) { + issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, issuerIX); + } else if (count == issuerIX) { + CFIndex rootIX = SecCertificatePathVCSelfSignedIndex(SecPathBuilderGetPath(rvc->builder)); + if (rootIX == rvc->certIX) { + issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, rootIX); + isSelfSigned = true; + } + } + cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX); + if (!isSelfSigned) { + /* skip revocation db check for self-signed certificates [33137065] */ + info = SecRevocationDbCopyMatching(cert, issuer); + } + SecValidInfoSetAnchor(info, SecPathBuilderGetCertificateAtIndex(rvc->builder, count-1)); + } + if (info) { + SecValidInfoRef old_info = rvc->valid_info; + rvc->valid_info = info; + if (old_info) { + SecValidInfoRelease(old_info); + } + return true; + } + return false; +} + +static void SecRVCCheckRevocationCaches(SecRVCRef rvc) { + /* Don't check OCSP cache if CRLs enabled and policy requested CRL only */ + if (SecRVCShouldCheckOCSP(rvc) && (rvc->orvc->ocspRequest)) { + secdebug("ocsp", "Checking cached responses for cert %ld", rvc->certIX); + SecOCSPResponseRef response = NULL; + if (SecPathBuilderGetCheckRevocationOnline(rvc->builder)) { + CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); + response = SecOCSPCacheCopyMatchingWithMinInsertTime(rvc->orvc->ocspRequest, NULL, now - kSecOCSPResponseOnlineTTL); + } else { + response = SecOCSPCacheCopyMatching(rvc->orvc->ocspRequest, NULL); + } + SecORVCConsumeOCSPResponse(rvc->orvc, + response, + NULL_TIME, false); + } +#if ENABLE_CRLS + /* Don't check CRL cache if policy requested OCSP only */ + if (SecRVCShouldCheckCRL(rvc)) { + SecCRVCCheckRevocationCache(rvc->crvc); + } +#endif +} + +static void SecRVCUpdatePVC(SecRVCRef rvc) { + SecRVCProcessValidInfoResults(rvc); /* restore the results we got from Valid */ + SecORVCUpdatePVC(rvc->orvc); +#if ENABLE_CRLS + SecCRVCUpdatePVC(rvc->crvc); +#endif +} + +static bool SecRVCFetchNext(SecRVCRef rvc) { + bool OCSP_fetch_finished = true; + /* Don't send OCSP request only if CRLs enabled and policy requested CRL only */ + if (SecRVCShouldCheckOCSP(rvc)) { + OCSP_fetch_finished &= SecORVCFetchNext(rvc->orvc); + } + if (OCSP_fetch_finished) { + /* we didn't start an OCSP background job for this cert */ + (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder); + } + +#if ENABLE_CRLS + bool CRL_fetch_finished = true; + /* Don't check CRL cache if policy requested OCSP only */ + if (SecRVCShouldCheckCRL(rvc)) { + /* reset the distributionPointIX because we already iterated through the CRLDPs + * in SecCRVCCheckRevocationCache */ + rvc->crvc->distributionPointIX = 0; + CRL_fetch_finished &= SecCRVCFetchNext(rvc->crvc); + } + if (CRL_fetch_finished) { + /* we didn't start a CRL background job for this cert */ + (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder); + } + OCSP_fetch_finished &= CRL_fetch_finished; +#endif + + return OCSP_fetch_finished; +} + +bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder) { + secdebug("rvc", "checking revocation"); + CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder); + SecCertificatePathVCRef path = SecPathBuilderGetPath(builder); + bool completed = true; + if (certCount <= 1) { + /* Can't verify without an issuer; we're done */ + return completed; + } + + /* + * Don't need to call SecPVCIsAnchored; having an issuer is sufficient here. + * + * Note: we can't check revocation for the last certificate in the chain + * via OCSP or CRL methods, since there isn't a separate issuer cert to + * sign those responses. However, since a self-signed root has an implied + * issuer of itself, we can check for it in the valid database. + */ + + if (SecCertificatePathVCIsRevocationDone(path)) { + /* We have done revocation checking already, set PVCs with results. */ + for (certIX = 0; certIX < certCount; ++certIX) { + SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX); + if (rvc) { SecRVCUpdatePVC(rvc); } + } + secdebug("rvc", "Not rechecking revocation"); + return completed; + } + + /* Setup things so we check revocation status of all certs. */ + SecCertificatePathVCAllocateRVCs(path, certCount); + + /* Note that if we are multi threaded and a job completes after it + is started but before we return from this function, we don't want + a callback to decrement asyncJobCount to zero before we finish issuing + all the jobs. To avoid this we pretend we issued certCount-1 async jobs, + and decrement pvc->asyncJobCount for each cert that we don't start a + background fetch for. (We will never start an async job for the final + cert in the chain.) */ +#if !ENABLE_CRLS + SecPathBuilderSetAsyncJobCount(builder, (unsigned int)(certCount-1)); +#else + /* If we enable CRLS, we may end up with two async jobs per cert: one + * for OCSP and one for fetching the CRL */ + SecPathBuilderSetAsyncJobCount(builder, 2 * (unsigned int)(certCount-1)); +#endif + + /* Loop though certificates again and issue an ocsp fetch if the + revocation status checking isn't done yet (and we have an issuer!) */ + for (certIX = 0; certIX < certCount; ++certIX) { + secdebug("rvc", "checking revocation for cert: %ld", certIX); + SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX); + if (!rvc) { + continue; + } + + SecRVCInit(rvc, builder, certIX); + if (rvc->done){ + continue; + } + +#if !TARGET_OS_BRIDGE + /* Check valid database first (separate from OCSP response cache) */ + if (SecRVCCheckValidInfoDatabase(rvc)) { + SecRVCProcessValidInfoResults(rvc); + } +#endif + /* Any other revocation method requires an issuer certificate; + * skip the last cert in the chain since it doesn't have one. */ + if (certIX+1 >= certCount) { + continue; + } + + /* Ignore stapled OCSP responses only if CRLs are enabled and the + * policy specifically requested CRLs only. */ + if (SecRVCShouldCheckOCSP(rvc)) { + /* If we have any OCSP stapled responses, check those first */ + SecORVCProcessStapledResponses(rvc->orvc); + } + +#if TARGET_OS_BRIDGE + /* The bridge has no writeable storage and no network. Nothing else we can + * do here. */ + rvc->done = true; + return completed; +#endif + + /* Then check the caches for revocation results. */ + SecRVCCheckRevocationCaches(rvc); + + /* The check is done if we found cached responses from either method. */ + if (rvc->orvc->done +#if ENABLE_CRLS + || rvc->orvc->done +#endif + ) { + secdebug("rvc", "found cached response for cert: %ld", certIX); + rvc->done = true; + } + + /* If we got a cached response that is no longer valid (which can only be true for + * revoked responses), let's try to get a fresher response even if no one asked. + * This check resolves unrevocation events after the nextUpdate time. */ + bool old_cached_response = (!rvc->done && rvc->orvc->ocspResponse); + + /* 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 = SecPathBuilderCanAccessNetwork(builder) && + (SecCertificatePathVCIsEV(path) || SecCertificatePathVCIsOptionallyEV(path) || + SecPathBuilderGetRevocationMethod(builder) || old_cached_response); + bool fetch_done = true; + if (rvc->done || !allow_fetch) { + /* We got a cache hit or we aren't allowed to access the network */ + SecRVCUpdatePVC(rvc); + /* We didn't really start any background jobs for this cert. */ + (void)SecPathBuilderDecrementAsyncJobCount(builder); +#if ENABLE_CRLS + (void)SecPathBuilderDecrementAsyncJobCount(builder); +#endif + } else { + fetch_done = SecRVCFetchNext(rvc); + } + if (!fetch_done) { + /* We started at least one background fetch. */ + secdebug("rvc", "waiting on background fetch for cert %ld", certIX); + completed = false; + } + } + + /* Return false if we started any background jobs. */ + /* We can't just return !builder->asyncJobCount here, since if we started any + jobs the completion callback will be called eventually and it will call + SecPathBuilderStep(). If for some reason everything completed before we + get here we still want the outer SecPathBuilderStep() to terminate so we + keep track of whether we started any jobs and return false if so. */ + return completed; +} + +CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc) { + CFAbsoluteTime enu = NULL_TIME; + if (!rvc || !rvc->orvc) { return enu; } + enu = rvc->orvc->nextUpdate; +#if ENABLE_CRLS + CFAbsoluteTime crlNextUpdate = rvc->crvc->nextUpdate; + if (enu == NULL_TIME || + ((crlNextUpdate > NULL_TIME) && (enu > crlNextUpdate))) { + /* We didn't check OCSP or CRL next update time was sooner */ + enu = crlNextUpdate; + } +#endif + return enu; +} diff --git a/OSX/sec/securityd/SecRevocationServer.h b/OSX/sec/securityd/SecRevocationServer.h new file mode 100644 index 00000000..aa73ab88 --- /dev/null +++ b/OSX/sec/securityd/SecRevocationServer.h @@ -0,0 +1,70 @@ +/* + * 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@ + */ + +/*! + @header SecRevocationServer + The functions provided in SecRevocationServer.h provide an interface to + the trust evaluation engine for dealing with certificate revocation. + */ + +#ifndef _SECURITY_SECREVOCATIONSERVER_H_ +#define _SECURITY_SECREVOCATIONSERVER_H_ + +#include +#include + +#define ENABLE_CRLS (TARGET_OS_MAC && !TARGET_OS_IPHONE) + +typedef struct OpaqueSecORVC *SecORVCRef; +#if ENABLE_CRLS +typedef struct OpaqueSecCRVC *SecCRVCRef; +#endif + +/* Revocation verification context. */ +struct OpaqueSecRVC { + /* Pointer to the builder for this revocation check */ + SecPathBuilderRef builder; + + /* Index of cert in pvc that this RVC is for 0 = leaf, etc. */ + CFIndex certIX; + + /* The OCSP Revocation verification context */ + SecORVCRef orvc; + +#if ENABLE_CRLS + SecCRVCRef crvc; +#endif + + /* Valid database info for this revocation check */ + SecValidInfoRef valid_info; + + bool done; +}; +typedef struct OpaqueSecRVC *SecRVCRef; + +bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder); +CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc); +void SecRVCDelete(SecRVCRef rvc); + + +#endif /* _SECURITY_SECREVOCATIONSERVER_H_ */ diff --git a/OSX/sec/securityd/SecTrustServer.c b/OSX/sec/securityd/SecTrustServer.c index bfaba35b..ca01d37c 100644 --- a/OSX/sec/securityd/SecTrustServer.c +++ b/OSX/sec/securityd/SecTrustServer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2010,2012-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2006-2010,2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include #include @@ -95,6 +98,8 @@ struct SecPathBuilder { CFArrayRef ocspResponses; // Stapled OCSP responses CFArrayRef signedCertificateTimestamps; // Stapled SCTs CFArrayRef trustedLogs; // Trusted CT logs + CFAbsoluteTime verifyTime; + CFArrayRef exceptions; /* Hashed set of all paths we've constructed so far, used to prevent re-considering a path that was already constructed once before. @@ -116,19 +121,20 @@ struct SecPathBuilder { CFIndex partialIX; - CFArrayRef leafDetails; - - CFIndex bestPathScore; - bool considerRejected; bool considerPartials; bool canAccessNetwork; - struct OpaqueSecPVC path; - SecCertificatePathRef bestPath; - bool bestPathIsEV; - bool bestPathIsSHA2; - bool denyBestPath; + SecPVCRef * pvcs; + CFIndex pvcCount; + + SecCertificatePathVCRef path; + unsigned int asyncJobCount; + bool online_revocation; + CFStringRef revocation_check_method; + + SecCertificatePathVCRef bestPath; + CFMutableDictionaryRef info; CFIndex activations; bool (*state)(SecPathBuilderRef); @@ -138,6 +144,7 @@ struct SecPathBuilder { /* State functions. Return false if a async job was scheduled, return true to execute the next state. */ +static bool SecPathBuilderProcessLeaf(SecPathBuilderRef builder); static bool SecPathBuilderGetNext(SecPathBuilderRef builder); static bool SecPathBuilderValidatePath(SecPathBuilderRef builder); static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder); @@ -147,30 +154,14 @@ static bool SecPathBuilderReportResult(SecPathBuilderRef builder); /* Forward declarations. */ static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder, SecCertificateRef certificate, SecCertificateSourceRef *foundInSource); - -/* IDEA: policies could be made capable of replacing incoming anchors and - anchorsOnly argument values. For example, some policies require the - Apple Inc. CA and not any other anchor. This can be done in - SecPathBuilderLeafCertificateChecks since this only runs once. */ -static void SecPathBuilderLeafCertificateChecks(SecPathBuilderRef builder, - SecCertificatePathRef path) { - CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable( - kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - builder->leafDetails = CFArrayCreate(kCFAllocatorDefault, - (const void **)&certDetail, 1, &kCFTypeArrayCallBacks); - CFRelease(certDetail); - SecPVCRef pvc = &builder->path; - SecPVCSetPath(pvc, path, builder->leafDetails); - builder->considerRejected = !SecPVCLeafChecks(pvc); -} +static void SecPathBuilderSetPath(SecPathBuilderRef builder, SecCertificatePathVCRef path); static void SecPathBuilderInit(SecPathBuilderRef builder, CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef ocspResponses, CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, - CFAbsoluteTime verifyTime, CFArrayRef accessGroups, + CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, SecPathBuilderCompleted completed, const void *context) { secdebug("alloc", "%p", builder); CFAllocatorRef allocator = kCFAllocatorDefault; @@ -194,7 +185,12 @@ static void SecPathBuilderInit(SecPathBuilderRef builder, builder->candidatePaths = CFArrayCreateMutable(allocator, 0, NULL); /* Init the policy verification context. */ - SecPVCInit(&builder->path, builder, policies, verifyTime); + builder->pvcs = malloc(sizeof(SecPVCRef)); + builder->pvcs[0] = malloc(sizeof(struct OpaqueSecPVC)); + SecPVCInit(builder->pvcs[0], builder, policies); + builder->pvcCount = 1; + builder->verifyTime = verifyTime; + builder->exceptions = CFRetainSafe(exceptions); /* Let's create all the certificate sources we might want to use. */ builder->certificateSource = @@ -277,29 +273,6 @@ static void SecPathBuilderInit(SecPathBuilderRef builder, } #endif /* !TARGET_OS_BRIDGE */ - /* Now let's get the leaf cert and turn it into a path. */ - SecCertificateRef leaf = - (SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0); - SecCertificateSourceRef source = NULL; - bool isAnchor = false; - CFArrayRef constraints = NULL; - if (SecPathBuilderIsAnchor(builder, leaf, &source)) { - isAnchor = true; - } - if (source) { - constraints = SecCertificateSourceCopyUsageConstraints(source, leaf); - } - SecCertificatePathRef path = SecCertificatePathCreate(NULL, leaf, constraints); - CFReleaseSafe(constraints); - CFSetAddValue(builder->allPaths, path); - CFArrayAppendValue(builder->partialPaths, path); - if (isAnchor) { - SecCertificatePathSetIsAnchored(path); - CFArrayAppendValue(builder->candidatePaths, path); - } - SecPathBuilderLeafCertificateChecks(builder, path); - CFRelease(path); - builder->ocspResponses = CFRetainSafe(ocspResponses); builder->signedCertificateTimestamps = CFRetainSafe(signedCertificateTimestamps); @@ -311,7 +284,22 @@ static void SecPathBuilderInit(SecPathBuilderRef builder, CFReleaseSafe(otapkiref); } - builder->state = SecPathBuilderGetNext; + /* Now let's get the leaf cert and turn it into a path. */ + SecCertificateRef leaf = + (SecCertificateRef)CFArrayGetValueAtIndex(certificates, 0); + SecCertificatePathVCRef path = SecCertificatePathVCCreate(NULL, leaf, NULL); + CFSetAddValue(builder->allPaths, path); + CFArrayAppendValue(builder->partialPaths, path); + + builder->path = CFRetainSafe(path); + SecPathBuilderSetPath(builder, path); + CFRelease(path); + + /* Set the revocation context */ + + /* Next step is to process the leaf. We do that work on the builder queue + * to avoid blocking the main thread with database lookups. */ + builder->state = SecPathBuilderProcessLeaf; builder->completed = completed; builder->context = context; } @@ -320,17 +308,29 @@ SecPathBuilderRef SecPathBuilderCreate(CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef ocspResponses, CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, - CFAbsoluteTime verifyTime, CFArrayRef accessGroups, + CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, SecPathBuilderCompleted completed, const void *context) { SecPathBuilderRef builder = malloc(sizeof(*builder)); memset(builder, 0, sizeof(*builder)); SecPathBuilderInit(builder, clientAuditToken, certificates, anchors, anchorsOnly, keychainsAllowed, policies, ocspResponses, signedCertificateTimestamps, trustedLogs, verifyTime, - accessGroups, completed, context); + accessGroups, exceptions, completed, context); return builder; } +/* Don't use this if you're going to modify the PVC array in the operation. */ +static void SecPathBuilderForEachPVC(SecPathBuilderRef builder,void (^operation)(SecPVCRef pvc, bool *stop)) { + if (!builder->pvcs) { return; } + bool stop = false; + CFIndex ix; + for (ix = 0; ix < builder->pvcCount; ix++) { + if (!builder->pvcs[ix]) { continue; } + operation(builder->pvcs[ix], &stop); + if (stop) { break; } + } +} + static void SecPathBuilderDestroy(SecPathBuilderRef builder) { secdebug("alloc", "%p", builder); dispatch_release_null(builder->queue); @@ -357,14 +357,40 @@ static void SecPathBuilderDestroy(SecPathBuilderRef builder) { CFReleaseNull(builder->partialPaths); CFReleaseNull(builder->rejectedPaths); CFReleaseNull(builder->candidatePaths); - CFReleaseNull(builder->leafDetails); CFReleaseNull(builder->ocspResponses); CFReleaseNull(builder->signedCertificateTimestamps); CFReleaseNull(builder->trustedLogs); + CFReleaseNull(builder->path); + CFReleaseNull(builder->revocation_check_method); + CFReleaseNull(builder->info); + CFReleaseNull(builder->exceptions); + + if (builder->pvcs) { + CFIndex ix; + for (ix = 0; ix < builder->pvcCount; ix++) { + if (builder->pvcs[ix]) { + SecPVCDelete(builder->pvcs[ix]); + free(builder->pvcs[ix]); + } + } + free(builder->pvcs); + builder->pvcs = NULL; + } +} + +static void SecPathBuilderSetPath(SecPathBuilderRef builder, SecCertificatePathVCRef path) { + bool samePath = ((!path && !builder->path) || (path && builder->path && CFEqual(path, builder->path))); + if (!samePath) { + CFRetainAssign(builder->path, path); + } + CFReleaseNull(builder->info); - SecPVCDelete(&builder->path); + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCSetPath(pvc, path); + }); } + bool SecPathBuilderCanAccessNetwork(SecPathBuilderRef builder) { return builder->canAccessNetwork; } @@ -410,15 +436,114 @@ CFArrayRef SecPathBuilderCopyTrustedLogs(SecPathBuilderRef builder) return CFRetainSafe(builder->trustedLogs); } -SecCertificatePathRef SecPathBuilderGetBestPath(SecPathBuilderRef builder) +SecCertificatePathVCRef SecPathBuilderGetBestPath(SecPathBuilderRef builder) { return builder->bestPath; } +SecCertificatePathVCRef SecPathBuilderGetPath(SecPathBuilderRef builder) { + return builder->path; +} + +CFAbsoluteTime SecPathBuilderGetVerifyTime(SecPathBuilderRef builder) { + return builder->verifyTime; +} + +CFIndex SecPathBuilderGetCertificateCount(SecPathBuilderRef builder) { + return SecCertificatePathVCGetCount(builder->path); +} + +SecCertificateRef SecPathBuilderGetCertificateAtIndex(SecPathBuilderRef builder, CFIndex ix) { + return SecCertificatePathVCGetCertificateAtIndex(builder->path, ix); +} + +bool SecPathBuilderIsAnchored(SecPathBuilderRef builder) { + return SecCertificatePathVCIsAnchored(builder->path); +} + +unsigned int SecPathBuilderDecrementAsyncJobCount(SecPathBuilderRef builder) { + return --builder->asyncJobCount; +} + +void SecPathBuilderSetAsyncJobCount(SecPathBuilderRef builder, unsigned int jobCount) { + builder->asyncJobCount = jobCount; + secdebug("rvc", "set asyncJobCount to %d", builder->asyncJobCount); +} + +CFMutableDictionaryRef SecPathBuilderGetInfo(SecPathBuilderRef builder) { + return builder->info; +} + +CFStringRef SecPathBuilderGetRevocationMethod(SecPathBuilderRef builder) { + return builder->revocation_check_method; +} + +void SecPathBuilderSetRevocationMethod(SecPathBuilderRef builder, CFStringRef method) { + CFRetainAssign(builder->revocation_check_method, method); + secdebug("rvc", "deferred revocation checking enabled using %@ method", method); +} + +bool SecPathBuilderGetCheckRevocationOnline(SecPathBuilderRef builder) { + return builder->online_revocation; +} + +void SecPathBuilderSetCheckRevocationOnline(SecPathBuilderRef builder) { + builder->online_revocation = true; + secdebug("rvc", "revocation force online check"); +} + +CFArrayRef SecPathBuilderGetExceptions(SecPathBuilderRef builder) { + return builder->exceptions; +} + +CFIndex SecPathBuilderGetPVCCount(SecPathBuilderRef builder) { + return builder->pvcCount; +} + +SecPVCRef SecPathBuilderGetPVCAtIndex(SecPathBuilderRef builder, CFIndex ix) { + if (ix > (builder->pvcCount - 1)) { + return NULL; + } + return builder->pvcs[ix]; +} + +void SecPathBuilderSetResultInPVCs(SecPathBuilderRef builder, CFStringRef key, + CFIndex ix, CFTypeRef result, bool force, + SecTrustResultType resultType) { + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCSetResultForced(pvc, key, ix, result, force); + pvc->result = resultType; + }); +} + +static bool SecPathBuilderIsOkResult(SecPathBuilderRef builder) { + /* If any of the PVCs passed, we accept the path. */ + __block bool acceptPath = false; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + acceptPath |= SecPVCIsOkResult(pvc); + }); + return acceptPath; +} + +static SecPVCRef SecPathBuilderGetResultPVC(SecPathBuilderRef builder) { + /* Return the first PVC that passed */ + __block SecPVCRef resultPVC = NULL; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool *stop) { + if (SecPVCIsOkResult(pvc)) { + resultPVC = pvc; + *stop = true; + } + }); + if (resultPVC) { return resultPVC; } + + /* If we didn't return a passing PVC, return the first PVC. */ + return builder->pvcs[0]; +} + /* This function assumes that the input source is an anchor source */ static bool SecPathBuilderIsAnchorPerConstraints(SecPathBuilderRef builder, SecCertificateSourceRef source, SecCertificateRef certificate) { - bool result = false; + __block bool result = false; CFArrayRef constraints = NULL; constraints = SecCertificateSourceCopyUsageConstraints(source, certificate); @@ -436,26 +561,32 @@ static bool SecPathBuilderIsAnchorPerConstraints(SecPathBuilderRef builder, SecC goto out; } - /* Get the trust settings result for the PVC */ + /* Get the trust settings result for the PVCs. Only one PVC need match to + * trigger the anchor behavior -- policy validation will handle whether the + * path is truly anchored for that PVC. */ require(constraints, out); - SecTrustSettingsResult settingsResult = kSecTrustSettingsResultInvalid; - settingsResult = SecPVCGetTrustSettingsResult(&builder->path, - certificate, - constraints); - if ((selfSigned && settingsResult == kSecTrustSettingsResultTrustRoot) || - (!selfSigned && settingsResult == kSecTrustSettingsResultTrustAsRoot)) { - // For our purposes, this is an anchor. - secinfo("trust", "complex trust settings anchor"); - result = true; - } + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecTrustSettingsResult settingsResult = kSecTrustSettingsResultInvalid; + settingsResult = SecPVCGetTrustSettingsResult(pvc, + certificate, + constraints); + if ((selfSigned && settingsResult == kSecTrustSettingsResultTrustRoot) || + (!selfSigned && settingsResult == kSecTrustSettingsResultTrustAsRoot)) { + // For our purposes, this is an anchor. + secinfo("trust", "complex trust settings anchor"); + result = true; + *stop = true; + } - if (settingsResult == kSecTrustSettingsResultDeny) { - /* We consider denied certs "anchors" because the trust decision - is set regardless of building the chain further. The policy - validation will handle rejecting this chain. */ - secinfo("trust", "complex trust settings denied anchor"); - result = true; - } + if (settingsResult == kSecTrustSettingsResultDeny) { + /* We consider denied certs "anchors" because the trust decision + is set regardless of building the chain further. The policy + validation will handle rejecting this chain. */ + secinfo("trust", "complex trust settings denied anchor"); + result = true; + *stop = true; + } + }); out: CFReleaseNull(constraints); @@ -484,24 +615,36 @@ static bool SecPathBuilderIsAnchor(SecPathBuilderRef builder, return false; } +bool SecPathBuilderIsAnchorSource(SecPathBuilderRef builder, SecCertificateSourceRef source) { + CFIndex anchorCount = CFArrayGetCount(builder->anchorSources); + return CFArrayContainsValue(builder->anchorSources, CFRangeMake(0,anchorCount), source); +} + /* Return false if path is not a partial, if path was a valid candidate it will have been added to builder->candidatePaths, if path was rejected by the parent certificate checks (because it's expired or some other static chaining check failed) it will have been added to rejectedPaths. Return true path if path is a partial. */ static bool SecPathBuilderIsPartial(SecPathBuilderRef builder, - SecCertificatePathRef path) { - SecPVCRef pvc = &builder->path; - SecPVCSetPath(pvc, path, NULL); + SecCertificatePathVCRef path) { + SecPathBuilderSetPath(builder, path); + __block bool parentChecksFail = true; + + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + /* The parent checks aren't actually PVC-dependent, so theoretically, + * we only need to run this once per path, but we want to set the + * results in all PVCs. */ + parentChecksFail &= !SecPVCParentCertificateChecks(pvc, + SecCertificatePathVCGetCount(path) - 1); + }); - if (!builder->considerRejected && !SecPVCParentCertificateChecks(pvc, - SecPVCGetCertificateCount(pvc) - 1)) { + if (!builder->considerRejected && parentChecksFail) { secdebug("trust", "Found rejected path %@", path); CFArrayAppendValue(builder->rejectedPaths, path); return false; } - SecPathVerifyStatus vstatus = SecCertificatePathVerify(path); + SecPathVerifyStatus vstatus = SecCertificatePathVCVerify(path); /* Candidate paths with failed signatures are discarded. */ if (vstatus == kSecPathVerifyFailed) { secdebug("trust", "Verify failed for path %@", path); @@ -511,13 +654,13 @@ static bool SecPathBuilderIsPartial(SecPathBuilderRef builder, if (vstatus == kSecPathVerifySuccess) { /* The signature chain verified sucessfully, now let's find out if we have an anchor for path. */ - if (SecCertificatePathIsAnchored(path)) { + if (SecCertificatePathVCIsAnchored(path)) { secdebug("trust", "Adding candidate %@", path); CFArrayAppendValue(builder->candidatePaths, path); } /* The path is not partial if the last cert is self-signed. */ - if ((SecCertificatePathSelfSignedIndex(path) >= 0) && - (SecCertificatePathSelfSignedIndex(path) == SecCertificatePathGetCount(path)-1)) { + if ((SecCertificatePathVCSelfSignedIndex(path) >= 0) && + (SecCertificatePathVCSelfSignedIndex(path) == SecCertificatePathVCGetCount(path)-1)) { return false; } } @@ -525,19 +668,121 @@ static bool SecPathBuilderIsPartial(SecPathBuilderRef builder, return true; } +static void addOptionsToPolicy(SecPolicyRef policy, CFDictionaryRef newOptions) { + __block CFMutableDictionaryRef oldOptions = CFDictionaryCreateMutableCopy(NULL, 0, policy->_options); + CFDictionaryForEach(newOptions, ^(const void *key, const void *value) { + CFDictionaryAddValue(oldOptions, key, value); + }); + CFAssignRetained(policy->_options, oldOptions); +} + +static void SecPathBuilderAddPinningPolicies(SecPathBuilderRef builder) { + CFIndex ix, initialPVCCount = builder->pvcCount; + for (ix = 0; ix < initialPVCCount; ix++) { + CFArrayRef policies = CFRetainSafe(builder->pvcs[ix]->policies); + CFIndex policyIX; + for (policyIX = 0; policyIX < CFArrayGetCount(policies); policyIX++) { + SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX); + CFStringRef policyName = SecPolicyGetName(policy); + CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname); + if (!hostname) { continue; } //No hostname to look up; probably not an SSL policy, skip + + /* Query the pinning database for this policy */ + CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(query, kSecPinningDbKeyPolicyName, policyName); + CFDictionaryAddValue(query, kSecPinningDbKeyHostname, hostname); + CFDictionaryRef results = SecPinningDbCopyMatching(query); + CFReleaseNull(query); + if (!results) { continue; } //No rules for this hostname or policyName + + /* Found pinning policies. Apply them to the path builder. */ + CFArrayRef newRules = CFDictionaryGetValue(results, kSecPinningDbKeyRules); + CFStringRef dbPolicyName = CFDictionaryGetValue(results, kSecPinningDbKeyPolicyName); + secinfo("trust", "found pinning %lu %@ policies for hostname %@, policyName %@", + (unsigned long)CFArrayGetCount(newRules), dbPolicyName, hostname, policyName); + CFIndex newRulesIX; + for (newRulesIX = 0; newRulesIX < CFArrayGetCount(newRules); newRulesIX++) { + if (!isDictionary(CFArrayGetValueAtIndex(newRules, newRulesIX))) { + continue; + } + + /* Create the new policies with pinning rules (preserving other ANDed policies). */ + CFDictionaryRef newOptions = (CFDictionaryRef)CFArrayGetValueAtIndex(newRules, newRulesIX); + SecPolicyRef newPolicy = SecPolicyCreateSSL(true, hostname); + if (!newPolicy) { continue; } + addOptionsToPolicy(newPolicy, newOptions); + SecPolicySetName(newPolicy, dbPolicyName); + CFMutableArrayRef newPolicies = CFArrayCreateMutableCopy(NULL, 0, policies); + if (!newPolicies) { CFReleaseNull(newPolicy); continue; } + CFArrayReplaceValues(newPolicies, CFRangeMake(policyIX, 1), (const void **)&newPolicy, 1); + + if (newRulesIX == 0) { + /* For the first set of pinning rules, replace this PVC's policies */ + CFRetainAssign(builder->pvcs[ix]->policies, newPolicies); + } else { + /* If there were two or more dictionaries of rules, we need to treat them as an "OR". + * Create another PVC for this dicitionary. */ + builder->pvcs = realloc(builder->pvcs, (builder->pvcCount + 1) * sizeof(SecPVCRef)); + builder->pvcs[builder->pvcCount] = malloc(sizeof(struct OpaqueSecPVC)); + SecPVCInit(builder->pvcs[builder->pvcCount], builder, newPolicies); + builder->pvcCount++; + } + CFReleaseNull(newPolicy); + CFReleaseNull(newPolicies); + } + CFReleaseNull(results); + } + CFReleaseNull(policies); + } +} + +static bool SecPathBuilderProcessLeaf(SecPathBuilderRef builder) { + SecPathBuilderAddPinningPolicies(builder); + + /* We need to find and set constraints on the leaf-only path */ + SecCertificatePathVCRef path = builder->path; + SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0); + + SecCertificateSourceRef source = NULL; + bool isAnchor = false; + CFArrayRef constraints = NULL; + if (SecPathBuilderIsAnchor(builder, leaf, &source)) { + isAnchor = true; + } + if (source) { + constraints = SecCertificateSourceCopyUsageConstraints(source, leaf); + } + SecCertificatePathVCSetUsageConstraintsAtIndex(path, constraints, 0); + CFReleaseSafe(constraints); + if (isAnchor) { + SecCertificatePathVCSetIsAnchored(path); + CFArrayAppendValue(builder->candidatePaths, path); + } + + __block bool leafChecksFail = true; + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCLeafChecks(pvc); + leafChecksFail &= !SecPVCIsOkResult(pvc); + }); + builder->considerRejected = leafChecksFail; + + builder->state = SecPathBuilderGetNext; + return true; +} + /* Given the builder, a partial chain partial and the parents array, construct a SecCertificatePath for each parent. After discarding previously considered paths and paths with cycles, sort out which array each path should go in, if any. */ static void SecPathBuilderProcessParents(SecPathBuilderRef builder, - SecCertificatePathRef partial, CFArrayRef parents) { - CFIndex rootIX = SecCertificatePathGetCount(partial) - 1; + SecCertificatePathVCRef partial, CFArrayRef parents) { + CFIndex rootIX = SecCertificatePathVCGetCount(partial) - 1; CFIndex num_parents = parents ? CFArrayGetCount(parents) : 0; CFIndex parentIX; for (parentIX = 0; parentIX < num_parents; ++parentIX) { SecCertificateRef parent = (SecCertificateRef) CFArrayGetValueAtIndex(parents, parentIX); - CFIndex ixOfParent = SecCertificatePathGetIndexOfCertificate(partial, + CFIndex ixOfParent = SecCertificatePathVCGetIndexOfCertificate(partial, parent); if (ixOfParent != kCFNotFound) { /* partial already contains parent. Let's not add the same @@ -545,7 +790,7 @@ static void SecPathBuilderProcessParents(SecPathBuilderRef builder, if (ixOfParent == rootIX) { /* parent is equal to the root of the partial, so partial looks to be self issued. */ - SecCertificatePathSetSelfIssued(partial); + SecCertificatePathVCSetSelfIssued(partial); } continue; } @@ -556,14 +801,14 @@ static void SecPathBuilderProcessParents(SecPathBuilderRef builder, SecCertificateSourceRef source = NULL; bool is_anchor = SecPathBuilderIsAnchor(builder, parent, &source); CFArrayRef constraints = (source) ? SecCertificateSourceCopyUsageConstraints(source, parent) : NULL; - SecCertificatePathRef path = SecCertificatePathCreate(partial, parent, constraints); + SecCertificatePathVCRef path = SecCertificatePathVCCreate(partial, parent, constraints); CFReleaseSafe(constraints); if (!path) continue; if (!CFSetContainsValue(builder->allPaths, path)) { CFSetAddValue(builder->allPaths, path); if (is_anchor) - SecCertificatePathSetIsAnchored(path); + SecCertificatePathVCSetIsAnchored(path); if (SecPathBuilderIsPartial(builder, path)) { /* Insert path right at the current position since it's a new candiate partial. */ @@ -582,7 +827,7 @@ static void SecPathBuilderProcessParents(SecPathBuilderRef builder, SecCertificateSourceCopyParents(). */ static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents) { SecPathBuilderRef builder = (SecPathBuilderRef)context; - SecCertificatePathRef partial = (SecCertificatePathRef) + SecCertificatePathVCRef partial = (SecCertificatePathVCRef) CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX); secdebug("async", "%@ parents %@", partial, parents); SecPathBuilderProcessParents(builder, partial, parents); @@ -594,12 +839,12 @@ static void SecPathBuilderExtendPaths(void *context, CFArrayRef parents) { static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { /* If we have any candidates left to go return those first. */ if (CFArrayGetCount(builder->candidatePaths)) { - SecCertificatePathRef path = (SecCertificatePathRef) + SecCertificatePathVCRef path = (SecCertificatePathVCRef) CFArrayGetValueAtIndex(builder->candidatePaths, 0); CFArrayRemoveValueAtIndex(builder->candidatePaths, 0); secdebug("trust", "SecPathBuilderGetNext returning candidate %@", path); - SecPVCSetPath(&builder->path, path, NULL); + SecPathBuilderSetPath(builder, path); builder->state = SecPathBuilderValidatePath; return true; } @@ -613,7 +858,7 @@ static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { CFIndex rejectedIX = CFArrayGetCount(builder->rejectedPaths); if (rejectedIX) { rejectedIX--; - SecCertificatePathRef path = (SecCertificatePathRef) + SecCertificatePathVCRef path = (SecCertificatePathVCRef) CFArrayGetValueAtIndex(builder->rejectedPaths, rejectedIX); if (SecPathBuilderIsPartial(builder, path)) { CFArrayInsertValueAtIndex(builder->partialPaths, @@ -663,14 +908,14 @@ static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { } /* We know builder->partialIX >= 0 if we get here. */ - SecCertificatePathRef partial = (SecCertificatePathRef) + SecCertificatePathVCRef partial = (SecCertificatePathVCRef) CFArrayGetValueAtIndex(builder->partialPaths, builder->partialIX); /* Don't try to extend partials anymore once we are in the considerPartials state, since at this point every partial has been extended with every possible parentSource already. */ if (builder->considerPartials) { --builder->partialIX; - SecPVCSetPath(&builder->path, partial, NULL); + SecPathBuilderSetPath(builder, partial); builder->state = SecPathBuilderValidatePath; return true; } @@ -683,7 +928,7 @@ static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { /* Attempt to extend partial, leaving all possible extended versions of partial in builder->extendedPaths. */ - CFIndex sourceIX = SecCertificatePathGetNextSourceIndex(partial); + CFIndex sourceIX = SecCertificatePathVCGetNextSourceIndex(partial); CFIndex num_anchor_sources = CFArrayGetCount(builder->anchorSources); if (sourceIX < num_anchor_sources + builder->nextParentSource) { SecCertificateSourceRef source; @@ -699,8 +944,8 @@ static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { secdebug("trust", "searching parent source %" PRIdCFIndex "/%" PRIdCFIndex, parentIX + 1, builder->nextParentSource); } - SecCertificatePathSetNextSourceIndex(partial, sourceIX + 1); - SecCertificateRef root = SecCertificatePathGetRoot(partial); + SecCertificatePathVCSetNextSourceIndex(partial, sourceIX + 1); + SecCertificateRef root = SecCertificatePathVCGetRoot(partial); return SecCertificateSourceCopyParents(source, root, builder, SecPathBuilderExtendPaths); } else { @@ -713,93 +958,75 @@ static bool SecPathBuilderGetNext(SecPathBuilderRef builder) { /* One or more of the policies did not accept the candidate path. */ static void SecPathBuilderReject(SecPathBuilderRef builder) { check(builder); - SecPVCRef pvc = &builder->path; builder->state = SecPathBuilderGetNext; - if (builder->bestPathIsEV && !pvc->is_ev) { + bool bestPathIsEV = SecCertificatePathVCIsEV(builder->bestPath); + bool isEV = SecCertificatePathVCIsEV(builder->path); + + if (bestPathIsEV && !isEV) { /* We never replace an ev reject with a non ev reject. */ return; } - CFIndex bestPathScore = builder->bestPathScore; - CFIndex score = SecCertificatePathScore(builder->path.path, - SecPVCGetVerifyTime(&builder->path)); + CFIndex bestPathScore = SecCertificatePathVCGetScore(builder->bestPath); + CFIndex score = SecCertificatePathVCScore(builder->path, builder->verifyTime); + SecCertificatePathVCSetScore(builder->path, score); /* The current chain is valid for EV, but revocation checking failed. We replace any previously accepted or rejected non EV chains with the current one. */ - if (pvc->is_ev && !builder->bestPathIsEV) { + if (isEV && !bestPathIsEV) { bestPathScore = 0; } - -#if 0 - if (pvc->is_ev) { - /* Since this means we found a valid ev chain that was revoked, - we might want to switch directly to the - SecPathBuilderComputeDetails state here if we think further - searching for new chains is pointless. For now we'll keep - going, since we could accept an alternate EV certification - path that isn't revoked. */ - builder->state = SecPathBuilderComputeDetails; - } -#endif - - /* Do this last so that changes to bestPathScore above will take effect. */ if (!builder->bestPath || score > bestPathScore) { if (builder->bestPath) { secinfo("reject", "replacing %sev %s score: %ld with %sev score: %" PRIdCFIndex " %@", - (builder->bestPathIsEV ? "" : "non "), - (builder->bestPathScore > ACCEPT_PATH_SCORE ? "accept" : "reject"), - builder->bestPathScore, - (pvc->is_ev ? "" : "non "), (long)score, builder->path.path); + (bestPathIsEV ? "" : "non "), + (bestPathScore > ACCEPT_PATH_SCORE ? "accept" : "reject"), + bestPathScore, + (isEV ? "" : "non "), (long)score, builder->path); } else { secinfo("reject", "%sev score: %" PRIdCFIndex " %@", - (pvc->is_ev ? "" : "non "), score, builder->path.path); + (isEV ? "" : "non "), score, builder->path); } - builder->bestPathScore = score; - builder->bestPath = pvc->path; - builder->bestPathIsEV = pvc->is_ev; - builder->denyBestPath = SecPVCCheckUsageConstraints(pvc); - } else { + builder->bestPath = builder->path; + } else { secinfo("reject", "%sev score: %" PRIdCFIndex " lower than %" PRIdCFIndex " %@", - (pvc->is_ev ? "" : "non "), score, bestPathScore, builder->path.path); + (isEV ? "" : "non "), score, bestPathScore, builder->path); } } /* All policies accepted the candidate path. */ static void SecPathBuilderAccept(SecPathBuilderRef builder) { if (!builder) { return; } - SecPVCRef pvc = &builder->path; - if (!pvc) { return; } - bool isSHA2 = !SecCertificatePathHasWeakHash(pvc->path); - bool isOptionallySHA2 = !SecCertificateIsWeakHash(SecPVCGetCertificateAtIndex(pvc, 0)); - CFIndex bestScore = builder->bestPathScore; + bool isSHA2 = !SecCertificatePathVCHasWeakHash(builder->path); + bool isOptionallySHA2 = !SecCertificateIsWeakHash(SecPathBuilderGetCertificateAtIndex(builder, 0)); + bool isEV = SecCertificatePathVCIsEV(builder->path); + bool isOptionallyEV = SecCertificatePathVCIsOptionallyEV(builder->path); + CFIndex bestScore = SecCertificatePathVCGetScore(builder->bestPath); /* Score this path. Note that all points awarded or deducted in * SecCertificatePathScore are < 100,000 */ - CFIndex currScore = (SecCertificatePathScore(pvc->path, pvc->verifyTime) + + CFIndex currScore = (SecCertificatePathVCScore(builder->path, builder->verifyTime) + ACCEPT_PATH_SCORE + // 10,000,000 points for accepting - ((pvc->is_ev) ? 1000000 : 0)); //1,000,000 points for EV + (isEV ? 1000000 : 0)); //1,000,000 points for EV + SecCertificatePathVCSetScore(builder->path, currScore); if (currScore > bestScore) { // current path is better than existing best path secinfo("accept", "replacing %sev %s score: %ld with %sev score: %" PRIdCFIndex " %@", - (builder->bestPathIsEV ? "" : "non "), - (builder->bestPathScore > ACCEPT_PATH_SCORE ? "accept" : "reject"), - builder->bestPathScore, - (pvc->is_ev ? "" : "non "), (long)currScore, builder->path.path); - - builder->bestPathScore = currScore; - builder->bestPathIsEV = pvc->is_ev; - builder->bestPathIsSHA2 = isSHA2; - builder->bestPath = pvc->path; - builder->denyBestPath = SecPVCCheckUsageConstraints(pvc); /* should always be false */ + (SecCertificatePathVCIsEV(builder->bestPath) ? "" : "non "), + (bestScore > ACCEPT_PATH_SCORE ? "accept" : "reject"), + bestScore, + (isEV ? "" : "non "), (long)currScore, builder->path); + + builder->bestPath = builder->path; } /* If we found the best accept we can, we want to switch directly to the SecPathBuilderComputeDetails state here, since we're done. */ - if ((pvc->is_ev || !pvc->optionally_ev) && (isSHA2 || !isOptionallySHA2)) + if ((isEV || !isOptionallyEV) && (isSHA2 || !isOptionallySHA2)) builder->state = SecPathBuilderComputeDetails; else builder->state = SecPathBuilderGetNext; @@ -808,7 +1035,6 @@ static void SecPathBuilderAccept(SecPathBuilderRef builder) { /* Return true iff a given path satisfies all the specified policies at verifyTime. */ static bool SecPathBuilderValidatePath(SecPathBuilderRef builder) { - SecPVCRef pvc = &builder->path; if (builder->considerRejected) { SecPathBuilderReject(builder); @@ -816,12 +1042,27 @@ static bool SecPathBuilderValidatePath(SecPathBuilderRef builder) { } builder->state = SecPathBuilderDidValidatePath; - return SecPVCPathChecks(pvc); + + /* Revocation checking is now done before path checks, to ensure that + isAllowlisted will be set correctly for the subsequent path checks. */ + bool completed = SecPathBuilderCheckRevocation(builder); + + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCPathChecks(pvc); + }); + + return completed; } static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder) { - SecPVCRef pvc = &builder->path; - if (pvc->result) { + /* We perform the revocation required policy checks here because + * this is the state we call back into once all the asynchronous + * revocation check calls are done. */ + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCPathCheckRevocationRequired(pvc); + }); + + if (SecPathBuilderIsOkResult(builder)) { SecPathBuilderAccept(builder); } else { SecPathBuilderReject(builder); @@ -831,116 +1072,98 @@ static bool SecPathBuilderDidValidatePath(SecPathBuilderRef builder) { } static bool SecPathBuilderComputeDetails(SecPathBuilderRef builder) { - // foobar - SecPVCRef pvc = &builder->path; -#if 0 - if (!builder->caller_wants_details) { - SecPVCSetPath(pvc, builder->bestPath, NULL); - pvc->result = builder->bestPathScore > ACCEPT_PATH_SCORE; - builder->state = SecPathBuilderReportResult; - return true; - } -#endif - CFIndex ix, pathLength = SecCertificatePathGetCount(builder->bestPath); - CFMutableArrayRef details = CFArrayCreateMutableCopy(kCFAllocatorDefault, - pathLength, builder->leafDetails); - CFRetainSafe(details); - SecPVCSetPath(pvc, builder->bestPath, details); - /* Only report on EV stuff if the bestPath actually was valid for EV. */ - pvc->optionally_ev = builder->bestPathIsEV; - pvc->info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - for (ix = 1; ix < pathLength; ++ix) { - CFMutableDictionaryRef certDetail = CFDictionaryCreateMutable( - kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFArrayAppendValue(details, certDetail); - CFRelease(certDetail); - SecPVCParentCertificateChecks(pvc, ix); - SecPVCGrayListedKeyChecks(pvc, ix); - SecPVCBlackListedKeyChecks(pvc, ix); - } + /* We have to re-do all the checks so that the results get set in the + * PVC for the best path, as the last path checked may not have been the best. */ + SecPathBuilderSetPath(builder, builder->bestPath); + __block CFIndex ix, pathLength = SecCertificatePathVCGetCount(builder->bestPath); + + __block bool completed = true; + + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCComputeDetails(pvc, builder->bestPath); + completed &= SecPathBuilderCheckRevocation(builder); + for (ix = 1; ix < pathLength; ++ix) { + SecPVCParentCertificateChecks(pvc, ix); + } + SecPVCPathChecks(pvc); + }); + builder->state = SecPathBuilderReportResult; - bool completed = SecPVCPathChecks(pvc); - /* Reject the certificate if it was accepted before but we failed it now. */ - if (builder->bestPathScore > ACCEPT_PATH_SCORE && !pvc->result) { - builder->bestPathScore = 0; - } + SecPathBuilderForEachPVC(builder, ^(SecPVCRef pvc, bool * __unused stop) { + SecPVCPathCheckRevocationRequired(pvc); + }); - /* Accept a partial path if certificate is on the allow list - and is temporally valid and passed all PVC checks. */ - if (completed && pvc->is_allowlisted && pvc->result && - builder->bestPathScore < ACCEPT_PATH_SCORE && - SecCertificatePathIsValid(pvc->path, pvc->verifyTime)) { - builder->bestPathScore += ACCEPT_PATH_SCORE; + /* Reject the certificate if it was accepted before but we failed it now. (Should not happen anymore.) */ + if (SecCertificatePathVCGetScore(builder->bestPath) > ACCEPT_PATH_SCORE && !SecPathBuilderIsOkResult(builder)) { + SecCertificatePathVCResetScore(builder->bestPath); + secwarning("In ComputeDetails, we got a reject after an accept in DidValidatePath."); } - CFReleaseSafe(details); - return completed; } static bool SecPathBuilderReportResult(SecPathBuilderRef builder) { - SecPVCRef pvc = &builder->path; - bool haveRevocationResponse = false; - if (pvc->info && pvc->is_ev && pvc->result) { - CFDictionarySetValue(pvc->info, kSecTrustInfoExtendedValidationKey, - kCFBooleanTrue); /* iOS key */ - CFDictionarySetValue(pvc->info, kSecTrustExtendedValidation, - kCFBooleanTrue); /* unified API key */ - SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0); - CFStringRef leafCompanyName = SecCertificateCopyCompanyName(leaf); - if (leafCompanyName) { - CFDictionarySetValue(pvc->info, kSecTrustInfoCompanyNameKey, - leafCompanyName); /* iOS key */ - CFDictionarySetValue(pvc->info, kSecTrustOrganizationName, - leafCompanyName); /* unified API key */ - CFRelease(leafCompanyName); - } - if (pvc->rvcs) { - CFAbsoluteTime nextUpdate = SecPVCGetEarliestNextUpdate(pvc); - if (nextUpdate == 0) { - /* populate revocation info for failed revocation check */ - CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey, - kCFBooleanFalse); /* iOS key */ - CFDictionarySetValue(pvc->info, kSecTrustRevocationChecked, - kCFBooleanFalse); /* unified API key */ + builder->info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + + /* isEV is not set unless also CT verified. Here, we need to check that we + * got a revocation response as well. */ + if (builder->info && SecCertificatePathVCIsEV(builder->bestPath) && SecPathBuilderIsOkResult(builder)) { +#if !TARGET_OS_WATCH + if (SecCertificatePathVCIsRevocationDone(builder->bestPath)) { + CFAbsoluteTime nextUpdate = SecCertificatePathVCGetEarliestNextUpdate(builder->bestPath); + if (nextUpdate != 0) { +#else + /* We don't do networking on watchOS, so we can't require OCSP for EV */ + { + { +#endif + /* Successful revocation check, so this cert is EV */ + CFDictionarySetValue(builder->info, kSecTrustInfoExtendedValidationKey, + kCFBooleanTrue); /* iOS key */ + CFDictionarySetValue(builder->info, kSecTrustExtendedValidation, + kCFBooleanTrue); /* unified API key */ + SecCertificateRef leaf = SecPathBuilderGetCertificateAtIndex(builder, 0); + CFStringRef leafCompanyName = SecCertificateCopyCompanyName(leaf); + if (leafCompanyName) { + CFDictionarySetValue(builder->info, kSecTrustInfoCompanyNameKey, + leafCompanyName); /* iOS key */ + CFDictionarySetValue(builder->info, kSecTrustOrganizationName, + leafCompanyName); /* unified API key */ + CFRelease(leafCompanyName); + } } } } - if (pvc->info && pvc->result && pvc->rvcs) { - CFAbsoluteTime nextUpdate = SecPVCGetEarliestNextUpdate(pvc); + if (builder->info && SecPathBuilderIsOkResult(builder) && SecCertificatePathVCIsRevocationDone(builder->bestPath)) { + CFAbsoluteTime nextUpdate = SecCertificatePathVCGetEarliestNextUpdate(builder->bestPath); if (nextUpdate != 0) { /* always populate revocation info for successful revocation check */ - haveRevocationResponse = true; CFDateRef validUntil = CFDateCreate(kCFAllocatorDefault, nextUpdate); - CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationValidUntilKey, + CFDictionarySetValue(builder->info, kSecTrustInfoRevocationValidUntilKey, validUntil); /* iOS key */ - CFDictionarySetValue(pvc->info, kSecTrustRevocationValidUntilDate, + CFDictionarySetValue(builder->info, kSecTrustRevocationValidUntilDate, validUntil); /* unified API key */ CFRelease(validUntil); - CFDictionarySetValue(pvc->info, kSecTrustInfoRevocationKey, + CFDictionarySetValue(builder->info, kSecTrustInfoRevocationKey, kCFBooleanTrue); /* iOS key */ - CFDictionarySetValue(pvc->info, kSecTrustRevocationChecked, + CFDictionarySetValue(builder->info, kSecTrustRevocationChecked, kCFBooleanTrue); /* unified API key */ + } else if (SecCertificatePathVCIsEV(builder->bestPath)) { + /* populate revocation info for failed revocation check with EV */ + CFDictionarySetValue(builder->info, kSecTrustInfoRevocationKey, + kCFBooleanFalse); /* iOS key */ + CFDictionarySetValue(builder->info, kSecTrustRevocationChecked, + kCFBooleanFalse); /* unified API key */ } } - if (pvc->info && pvc->result && pvc->response_required && !haveRevocationResponse) { - builder->bestPathScore = 0; - SecPVCSetResultForced(pvc, kSecPolicyCheckRevocationResponseRequired, - 0, kCFBooleanFalse, true); - } - - if (pvc->info && pvc->is_ct && pvc->result) { - CFDictionarySetValue(pvc->info, kSecTrustInfoCertificateTransparencyKey, - kCFBooleanTrue); - } - - if (pvc->info && pvc->is_ct_whitelisted && pvc->result) { - CFDictionarySetValue(pvc->info, kSecTrustInfoCertificateTransparencyWhiteListKey, + if (builder->info && SecCertificatePathVCIsCT(builder->bestPath) && SecPathBuilderIsOkResult(builder)) { + CFDictionarySetValue(builder->info, kSecTrustInfoCertificateTransparencyKey, kCFBooleanTrue); } @@ -992,21 +1215,21 @@ bool SecPathBuilderStep(SecPathBuilderRef builder) { return false; } - SecTrustResultType result = kSecTrustResultInvalid; - if (builder->denyBestPath) { - result = kSecTrustResultDeny; - } else if (builder->bestPathScore > ACCEPT_PATH_SCORE) { - result = kSecTrustResultUnspecified; - } else { - result = kSecTrustResultRecoverableTrustFailure; + SecPVCRef pvc = SecPathBuilderGetResultPVC(builder); + SecTrustResultType result = pvc->result; + + if (builder->exceptions && pvc->result == kSecTrustResultUnspecified) { + result = kSecTrustResultProceed; } secinfo("trust", "completed: %@ details: %@ result: %d", - builder->bestPath, builder->path.details, result); + builder->bestPath, pvc->details, result); if (builder->completed) { - builder->completed(builder->context, builder->bestPath, - builder->path.details, builder->path.info, result); + SecCertificatePathRef resultPath = SecCertificatePathVCCopyCertificatePath(builder->bestPath); + builder->completed(builder->context, resultPath, + pvc->details, builder->info, result); + CFReleaseNull(resultPath); } /* Finally, destroy the builder and free it. */ @@ -1042,7 +1265,7 @@ SecTrustServerEvaluateCompleted(const void *userData, } void -SecTrustServerEvaluateBlock(CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error)) { +SecTrustServerEvaluateBlock(CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error)) { /* We need an array containing at least one certificate to proceed. */ if (!isArray(certificates) || !(CFArrayGetCount(certificates) > 0)) { CFErrorRef certError = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL); @@ -1056,17 +1279,17 @@ SecTrustServerEvaluateBlock(CFDataRef clientAuditToken, CFArrayRef certificates, certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, SCTs, trustedLogs, - verifyTime, accessGroups, + verifyTime, accessGroups, exceptions, SecTrustServerEvaluateCompleted, userData); dispatch_async(builder->queue, ^{ SecPathBuilderStep(builder); }); } // 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 *pdetails, CFDictionaryRef *pinfo, SecCertificatePathRef *pchain, CFErrorRef *perror) { +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, SecCertificatePathRef *pchain, CFErrorRef *perror) { dispatch_semaphore_t done = dispatch_semaphore_create(0); __block SecTrustResultType result = kSecTrustResultInvalid; - SecTrustServerEvaluateBlock(NULL, certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, SCTs, trustedLogs, verifyTime, accessGroups, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error) { + SecTrustServerEvaluateBlock(NULL, certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, SCTs, trustedLogs, verifyTime, accessGroups, exceptions, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error) { result = tr; if (tr == kSecTrustResultInvalid) { if (perror) { @@ -1090,6 +1313,7 @@ SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef an dispatch_semaphore_signal(done); }); dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER); + dispatch_release(done); return result; } diff --git a/OSX/sec/securityd/SecTrustServer.h b/OSX/sec/securityd/SecTrustServer.h index 3dff2b4d..5c7dcd20 100644 --- a/OSX/sec/securityd/SecTrustServer.h +++ b/OSX/sec/securityd/SecTrustServer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2009,2012-2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2008-2009,2012-2014,2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -30,9 +30,11 @@ #include -#include #include #include /* For errSecWaitForCallback. */ +#include +#include +#include #include @@ -40,6 +42,22 @@ __BEGIN_DECLS typedef struct SecPathBuilder *SecPathBuilderRef; +typedef struct OpaqueSecPVC *SecPVCRef; + +struct OpaqueSecPVC { + SecPathBuilderRef builder; + CFArrayRef policies; + CFDictionaryRef callbacks; + CFIndex policyIX; + bool require_revocation_response; + + CFArrayRef leafDetails; + SecTrustResultType leafResult; + + CFArrayRef details; + SecTrustResultType result; +}; + /* Completion callback. You should call SecTrustSessionDestroy from this. */ typedef void(*SecPathBuilderCompleted)(const void *userData, SecCertificatePathRef chain, CFArrayRef details, CFDictionaryRef info, @@ -50,7 +68,7 @@ SecPathBuilderRef SecPathBuilderCreate(CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef ocspResponse, CFArrayRef signedCertificateTimestamps, CFArrayRef trustedLogs, - CFAbsoluteTime verifyTime, CFArrayRef accessGroups, + CFAbsoluteTime verifyTime, CFArrayRef accessGroups, CFArrayRef exceptions, SecPathBuilderCompleted completed, const void *userData); /* Returns true if it's ok to perform network operations for this builder. */ @@ -65,6 +83,42 @@ CFArrayRef SecPathBuilderCopySignedCertificateTimestamps(SecPathBuilderRef build CFArrayRef SecPathBuilderCopyOCSPResponses(SecPathBuilderRef builder); CFArrayRef SecPathBuilderCopyTrustedLogs(SecPathBuilderRef builder); +SecCertificatePathVCRef SecPathBuilderGetPath(SecPathBuilderRef builder); +SecCertificatePathVCRef SecPathBuilderGetBestPath(SecPathBuilderRef builder); +CFAbsoluteTime SecPathBuilderGetVerifyTime(SecPathBuilderRef builder); +CFIndex SecPathBuilderGetCertificateCount(SecPathBuilderRef builder); +SecCertificateRef SecPathBuilderGetCertificateAtIndex(SecPathBuilderRef builder, CFIndex ix); +CFArrayRef SecPathBuilderGetExceptions(SecPathBuilderRef builder); + +/* Returns the isAnchored status of the path. The path builder sets isAnchored + * based solely on whether the terminating cert has some sort of trust setting + * on it. This check does NOT reflect whether that anchor is actually trusted, + * as trust in an anchor is contextual to the policy being validated. */ +bool SecPathBuilderIsAnchored(SecPathBuilderRef builder); +bool SecPathBuilderIsAnchorSource(SecPathBuilderRef builder, SecCertificateSourceRef source); + + +CFIndex SecPathBuilderGetPVCCount(SecPathBuilderRef builder); +SecPVCRef SecPathBuilderGetPVCAtIndex(SecPathBuilderRef builder, CFIndex ix); + +void SecPathBuilderSetResultInPVCs(SecPathBuilderRef builder, CFStringRef key, + CFIndex ix, CFTypeRef result, bool force, + SecTrustResultType resultType); + +/* This is a pre-decrement operation */ +unsigned int SecPathBuilderDecrementAsyncJobCount(SecPathBuilderRef builder); +void SecPathBuilderSetAsyncJobCount(SecPathBuilderRef builder, unsigned int jobCount); + +CFMutableDictionaryRef SecPathBuilderGetInfo(SecPathBuilderRef builder); + +/* Enable revocation checking if the rest of the policy checks succeed. */ +CFStringRef SecPathBuilderGetRevocationMethod(SecPathBuilderRef builder); +void SecPathBuilderSetRevocationMethod(SecPathBuilderRef builder, CFStringRef method); + +/* Require a online revocation response for the chain. */ +bool SecPathBuilderGetCheckRevocationOnline(SecPathBuilderRef builder); +void SecPathBuilderSetCheckRevocationOnline(SecPathBuilderRef builder); + /* Core of the trust evaluation engine, this will invoke the completed callback and return false if the evaluation completed, or return true if the evaluation is still waiting for some external event (usually the @@ -79,16 +133,13 @@ dispatch_queue_t SecPathBuilderGetQueue(SecPathBuilderRef builder); CFDataRef SecPathBuilderCopyClientAuditToken(SecPathBuilderRef builder); /* Evaluate trust and call evaluated when done. */ -void SecTrustServerEvaluateBlock(CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error)); +void SecTrustServerEvaluateBlock(CFDataRef clientAuditToken, CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, void (^evaluated)(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef error)); /* Synchronously invoke SecTrustServerEvaluateBlock. */ -SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error); +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 *details, CFDictionaryRef *info, SecCertificatePathRef *chain, CFErrorRef *error); void InitializeAnchorTable(void); -/* Return the current best chain */ -SecCertificatePathRef SecPathBuilderGetBestPath(SecPathBuilderRef builder); - __END_DECLS #endif /* !_SECURITY_SECTRUSTSERVER_H_ */ diff --git a/OSX/sec/securityd/asynchttp.c b/OSX/sec/securityd/asynchttp.c index 904ce862..0a29fc43 100644 --- a/OSX/sec/securityd/asynchttp.c +++ b/OSX/sec/securityd/asynchttp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2010,2012-2015 Apple Inc. All Rights Reserved. + * Copyright (c) 2009-2010,2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -47,17 +47,20 @@ #define PRIstatus "ld" #endif +static CFStringRef kUserAgent = CFSTR("User-Agent"); +static CFStringRef kAppUserAgent = CFSTR("com.apple.trustd/1.0"); + /* POST method has Content-Type header line equal to "application/ocsp-request" */ -static CFStringRef kContentType = CFSTR("Content-Type"); -static CFStringRef kAppOcspRequest = CFSTR("application/ocsp-request"); +static CFStringRef kContentType = CFSTR("Content-Type"); +static CFStringRef kAppOcspRequest = CFSTR("application/ocsp-request"); /* SPI to specify timeout on CFReadStream */ #define _kCFStreamPropertyReadTimeout CFSTR("_kCFStreamPropertyReadTimeout") -#define _kCFStreamPropertyWriteTimeout CFSTR("_kCFStreamPropertyWriteTimeout") +#define _kCFStreamPropertyWriteTimeout CFSTR("_kCFStreamPropertyWriteTimeout") /* The timeout we set - 7 seconds */ -#define STREAM_TIMEOUT (7 * NSEC_PER_SEC) +#define STREAM_TIMEOUT (7 * NSEC_PER_SEC) #define POST_BUFSIZE 2048 @@ -408,8 +411,9 @@ void asynchttp_free(asynchttp_t *http) { bool asynchttp_request(CFHTTPMessageRef request, uint64_t timeout, asynchttp_t *http) { secdebug("http", "request %@", request); if (request) { - http->request = request; - CFRetain(request); + CFRetainAssign(http->request, request); + /* Set user agent. */ + CFHTTPMessageSetHeaderFieldValue(request, kUserAgent, kAppUserAgent); } /* Create the stream for the request. */ diff --git a/OSX/sec/securityd/com.apple.secd.sb b/OSX/sec/securityd/com.apple.secd.sb new file mode 100644 index 00000000..f73a83d3 --- /dev/null +++ b/OSX/sec/securityd/com.apple.secd.sb @@ -0,0 +1,47 @@ +(version 1) + +(deny default) + +(import "system.sb") + +(allow file-read* file-write* + (subpath "/private/var/db/mds") + (regex #"^/private/var/folders/[^/]+/[^/]+/T(/|$)") + (regex (string-append "^" (regex-quote (param "_HOME")) #"/Library/Keychains(/|$)"))) + + +;;;;;; will be fully fixed in 29465717 +(allow file-read* (subpath "/")) + +(allow user-preference-read + (preference-domain ".GlobalPreferences")) +(allow user-preference-read + (preference-domain "com.apple.security")) + +(allow file-read* + (literal "/usr/libexec/secd") + (literal "/Library/Preferences/com.apple.security.plist") + (literal "/Library/Preferences/.GlobalPreferences.plist") + (literal "/AppleInternal") + (literal "/usr/libexec")) + + +(allow mach-lookup + (global-name "com.apple.system.opendirectoryd.api") + (global-name "com.apple.SystemConfiguration.configd") + (global-name "com.apple.security.cloudkeychainproxy3") + (global-name "com.apple.security.keychainsyncingoveridsproxy") + (global-name "com.apple.cloudd") + (global-name "com.apple.apsd") + (global-name "com.apple.windowserver.active")) + +(allow iokit-open + (iokit-user-client-class "AppleKeyStoreUserClient")) + +(allow iokit-get-properties (iokit-registry-entry-class "IOPlatformExpertDevice")) + +(allow ipc-posix-shm + (ipc-posix-name "com.apple.AppleDatabaseChanged")) + +(allow network-outbound) +(allow system-socket) diff --git a/OSX/sec/securityd/entitlements.plist b/OSX/sec/securityd/entitlements.plist index 7b98ab4f..68535bba 100644 --- a/OSX/sec/securityd/entitlements.plist +++ b/OSX/sec/securityd/entitlements.plist @@ -2,6 +2,38 @@ + com.apple.private.aps-connection-initiate + + aps-connection-initiate + + aps-environment + serverPreferred + com.apple.aps-environment + serverPreferred + com.apple.private.cloudkit.setEnvironment + + com.apple.developer.icloud-container-identifiers + + iCloud.com.apple.security.keychain + + com.apple.developer.icloud-services + + CloudKit + + com.apple.developer.icloud-container-environment + Production + com.apple.private.cloudkit.systemService + + com.apple.private.cloudkit.buddyAccess + + com.apple.private.appleaccount.app-hidden-from-icloud-settings + + com.apple.private.tcc.allow + + kTCCServiceLiverpool + + com.apple.application-identifier + com.apple.securityd application-identifier com.apple.securityd com.apple.keystore.access-keychain-keys diff --git a/OSX/sec/securityd/personalization.c b/OSX/sec/securityd/personalization.c index d2b98545..05e42b9e 100644 --- a/OSX/sec/securityd/personalization.c +++ b/OSX/sec/securityd/personalization.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,5 +24,6 @@ #include "personalization.h" #include #include +#include #include diff --git a/OSX/sec/securityd/policytree.c b/OSX/sec/securityd/policytree.c index 356e7a6a..b85f4fd4 100644 --- a/OSX/sec/securityd/policytree.c +++ b/OSX/sec/securityd/policytree.c @@ -138,12 +138,14 @@ bool policy_tree_walk_depth(policy_tree_t root, int depth, required depth yet, we go depth first and proccess it. */ stack[++stack_ix] = child; } else { + /* Get the sibling now in case we delete the node in the callback */ + policy_tree_t sibling = node->siblings; if (stack_ix == depth) { /* Proccess node. */ match |= callback(node, ctx); } + /* Move on to sibling of node. */ - policy_tree_t sibling = node->siblings; if (sibling) { /* Replace current node with it's sibling. */ stack[stack_ix] = sibling; diff --git a/OSX/sec/securityd/policytree.h b/OSX/sec/securityd/policytree.h index 147285d5..bbc07ebf 100644 --- a/OSX/sec/securityd/policytree.h +++ b/OSX/sec/securityd/policytree.h @@ -33,7 +33,6 @@ #include #include #include -#include __BEGIN_DECLS diff --git a/OSX/sec/securityd/spi.c b/OSX/sec/securityd/spi.c index a07a834a..c845fa5e 100644 --- a/OSX/sec/securityd/spi.c +++ b/OSX/sec/securityd/spi.c @@ -23,6 +23,8 @@ #include +#include +#include #include #include #include @@ -41,31 +43,16 @@ #include "utilities/SecFileLocations.h" #include "OTATrustUtilities.h" -static struct securityd spi = { -#if !TRUSTD_SERVER - /* Trustd must xpc to secd to use these. */ +static struct securityd securityd_spi = { .sec_item_add = _SecItemAdd, .sec_item_copy_matching = _SecItemCopyMatching, .sec_item_update = _SecItemUpdate, .sec_item_delete = _SecItemDelete, -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_BRIDGE .sec_add_shared_web_credential = _SecAddSharedWebCredential, .sec_copy_shared_web_credential = _SecCopySharedWebCredential, #endif - .sec_trust_store_for_domain = SecTrustStoreForDomainName, - .sec_trust_store_contains = SecTrustStoreContainsCertificateWithDigest, - .sec_trust_store_set_trust_settings = _SecTrustStoreSetTrustSettings, - .sec_trust_store_remove_certificate = SecTrustStoreRemoveCertificateWithDigest, - .sec_truststore_remove_all = _SecTrustStoreRemoveAll, .sec_item_delete_all = _SecItemDeleteAll, -#endif -#if TRUSTD_SERVER || TARGET_OS_IPHONE - /* Local trust evaluation only occurs in trustd and iOS securityd */ - .sec_trust_evaluate = SecTrustServerEvaluate, - .sec_device_is_internal = SecIsDeviceInternal, -#endif -#if !TRUSTD_SERVER - /* Trustd must xpc to secd to use these. */ .sec_keychain_backup = _SecServerKeychainCreateBackup, .sec_keychain_restore = _SecServerKeychainRestore, .sec_keychain_backup_syncable = _SecServerBackupSyncable, @@ -76,7 +63,6 @@ static struct securityd spi = { .sec_item_backup_restore = SecServerItemBackupRestore, .sec_otr_session_create_remote = _SecOTRSessionCreateRemote, .sec_otr_session_process_packet_remote = _SecOTRSessionProcessPacketRemote, - .sec_ota_pki_asset_version = SecOTAPKIGetCurrentAssetVersion, .soscc_TryUserCredentials = SOSCCTryUserCredentials_Server, .soscc_SetUserCredentials = SOSCCSetUserCredentials_Server, .soscc_SetUserCredentialsAndDSID = SOSCCSetUserCredentialsAndDSID_Server, @@ -113,8 +99,6 @@ static struct securityd spi = { .soscc_CopyEngineState = SOSCCCopyEngineState_Server, .soscc_CopyPeerInfo = SOSCCCopyPeerPeerInfo_Server, .soscc_CopyConcurringPeerInfo = SOSCCCopyConcurringPeerPeerInfo_Server, - .ota_CopyEscrowCertificates = SecOTAPKICopyCurrentEscrowCertificates, - .sec_ota_pki_get_new_asset = SecOTAPKISignalNewAsset, .soscc_ProcessSyncWithPeers = SOSCCProcessSyncWithPeers_Server, .soscc_ProcessSyncWithAllPeers = SOSCCProcessSyncWithAllPeers_Server, .soscc_EnsurePeerRegistration = SOSCCProcessEnsurePeerRegistration_Server, @@ -131,7 +115,6 @@ static struct securityd spi = { .sec_set_circle_log_settings = SecSetCircleLogSettings_Server, .soscc_CopyMyPeerInfo = SOSCCCopyMyPeerInfo_Server, .soscc_SetLastDepartureReason = SOSCCSetLastDepartureReason_Server, - .soscc_SetHSA2AutoAcceptInfo = SOSCCSetHSA2AutoAcceptInfo_Server, .soscc_SetNewPublicBackupKey = SOSCCSetNewPublicBackupKey_Server, .soscc_RegisterSingleRecoverySecret = SOSCCRegisterSingleRecoverySecret_Server, .soscc_WaitForInitialSync = SOSCCWaitForInitialSync_Server, @@ -147,8 +130,6 @@ static struct securityd spi = { .soscc_AccountHasPublicKey = SOSCCAccountHasPublicKey_Server, .soscc_AccountIsNew = SOSCCAccountIsNew_Server, .sec_item_update_token_items = _SecItemUpdateTokenItems, - .sec_trust_store_copy_all = _SecTrustStoreCopyAll, - .sec_trust_store_copy_usage_constraints = _SecTrustStoreCopyUsageConstraints, .sec_delete_items_with_access_groups = _SecItemServerDeleteAllWithAccessGroups, .soscc_IsThisDeviceLastBackup = SOSCCkSecXPCOpIsThisDeviceLastBackup_Server, .soscc_requestSyncWithPeerOverKVS = SOSCCRequestSyncWithPeerOverKVS_Server, @@ -160,13 +141,72 @@ static struct securityd spi = { .soscc_CopyBackupInformation = SOSCCCopyBackupInformation_Server, .soscc_SOSCCMessageFromPeerIsPending = SOSCCMessageFromPeerIsPending_Server, .soscc_SOSCCSendToPeerIsPending = SOSCCSendToPeerIsPending_Server, + .sec_item_copy_parent_certificates = _SecItemCopyParentCertificates, + .sec_item_certificate_exists = _SecItemCertificateExists, +}; -#endif /* !TRUSTD_SERVER */ +#ifdef LIBTRUSTD +static struct trustd trustd_spi = { + .sec_trust_store_for_domain = SecTrustStoreForDomainName, + .sec_trust_store_contains = SecTrustStoreContainsCertificateWithDigest, + .sec_trust_store_set_trust_settings = _SecTrustStoreSetTrustSettings, + .sec_trust_store_remove_certificate = SecTrustStoreRemoveCertificateWithDigest, + .sec_truststore_remove_all = _SecTrustStoreRemoveAll, + .sec_trust_evaluate = SecTrustServerEvaluate, + .sec_ota_pki_asset_version = SecOTAPKIGetCurrentAssetVersion, + .ota_CopyEscrowCertificates = SecOTAPKICopyCurrentEscrowCertificates, + .sec_ota_pki_get_new_asset = SecOTAPKISignalNewAsset, + .sec_trust_store_copy_all = _SecTrustStoreCopyAll, + .sec_trust_store_copy_usage_constraints = _SecTrustStoreCopyUsageConstraints, }; +#endif + +#if SECD_SERVER +static CFTypeRef +delayedSOSSharedObject(void) +{ + static CFTypeRef soscc_status; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + soscc_status = SOSKeychainAccountGetSharedAccount(); + }); + return soscc_status; +} +#endif + +void securityd_init_local_spi(void) { + gSecurityd = &securityd_spi; +#if SECD_SERVER + // We're the server: we need to handle this locally. Bring them up and set them in the global object. + securityd_spi.soscc_status = delayedSOSSharedObject; +#endif + // You're trying to bring up a (non-trustd) 'securityd'. Create the local handler for securityd XPCs. + securityd_spi.secd_xpc_server = SecCreateLocalCFSecuritydXPCServer(); +} void securityd_init_server(void) { - gSecurityd = &spi; - SecPolicyServerInitalize(); + securityd_init_local_spi(); + + // Lazy initialization is no good; bring up the keychain on start + // If you want to not do this, you'll need to check the APSConnection Mach mailbox for messages here instead (good luck) + CFErrorRef cferror = nil; + bool keychainAlive = kc_with_dbt(false, &cferror, ^bool(SecDbConnectionRef dbt) { + secnotice("keychain", "Keychain initialized!"); + return true; + }); + if(!keychainAlive || cferror) { + secerror("Couldn't bring up keychain: %@", cferror); + } + CFReleaseNull(cferror); + + SecdLoadWatchDog(); +} + +static void trustd_init_server(void) { +#ifdef LIBTRUSTD + gTrustd = &trustd_spi; + SecPolicyServerInitialize(); +#endif } void securityd_init(CFURLRef home_path) { @@ -174,4 +214,5 @@ void securityd_init(CFURLRef home_path) { SetCustomHomeURL(home_path); securityd_init_server(); + trustd_init_server(); } diff --git a/OSX/sec/securityd/spi.h b/OSX/sec/securityd/spi.h index 4c5f503a..7e769031 100644 --- a/OSX/sec/securityd/spi.h +++ b/OSX/sec/securityd/spi.h @@ -30,11 +30,14 @@ __BEGIN_DECLS /* Calling this function initializes the spi interface in the library to call - directly into the backend. It uses home_dir for root of files if specified. */ + directly into the backend. It uses home_dir for root of files if specified. + This function only initializes the trust spi interface if libtrustd is linked + by the caller and LIBTRUSTD=1 is specified. */ void securityd_init(CFURLRef home_dir); -// Don't call this function unless you are really securityd +// Don't call either of these functions unless you are really securityd void securityd_init_server(void); +void securityd_init_local_spi(void); __END_DECLS diff --git a/OSX/sectests/main.c b/OSX/sectests/main.c index dcb0c395..64332770 100644 --- a/OSX/sectests/main.c +++ b/OSX/sectests/main.c @@ -25,12 +25,12 @@ #include #include -#include "test/testenv.h" +#include "regressions/test/testenv.h" #include "testlist.h" -#include +#include #include "testlist.h" -#include +#include int main(int argc, char *argv[]) { diff --git a/OSX/shared_regressions/shared_regressions.h b/OSX/shared_regressions/shared_regressions.h index 537de386..534d53f6 100644 --- a/OSX/shared_regressions/shared_regressions.h +++ b/OSX/shared_regressions/shared_regressions.h @@ -6,10 +6,11 @@ This file contains iOS/OSX shared tests that are built in libSharedRegression.a For iOS-only tests see Security_regressions.h */ -#include +#include ONE_TEST(si_15_certificate) ONE_TEST(si_16_ec_certificate) +ONE_TEST(si_18_certificate_parse) ONE_TEST(si_20_sectrust) ONE_TEST(si_20_sectrust_policies) ONE_TEST(si_21_sectrust_asr) @@ -29,19 +30,29 @@ ONE_TEST(si_26_sectrust_copyproperties) ONE_TEST(si_27_sectrust_exceptions) ONE_TEST(si_28_sectrustsettings) ONE_TEST(si_29_sectrust_sha1_deprecation) +ONE_TEST(si_32_sectrust_pinning_required) ONE_TEST(si_44_seckey_gen) ONE_TEST(si_44_seckey_rsa) ONE_TEST(si_44_seckey_ec) ONE_TEST(si_44_seckey_ies) +ONE_TEST(si_44_seckey_aks) +#if TARGET_OS_IOS && !TARGET_OS_SIMULATOR +ONE_TEST(si_44_seckey_fv) +#endif +ONE_TEST(si_60_cms) +ONE_TEST(si_61_pkcs12) 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_blacklist) +ONE_TEST(si_67_sectrust_blocklist) ONE_TEST(si_84_sectrust_allowlist) #else -DISABLED_ONE_TEST(si_67_sectrust_blacklist) +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) @@ -52,3 +63,5 @@ ONE_TEST(si_85_sectrust_ssl_policy) ONE_TEST(si_87_sectrust_name_constraints) ONE_TEST(si_97_sectrust_path_scoring) ONE_TEST(rk_01_recoverykey) + +ONE_TEST(padding_00_mmcs) diff --git a/OSX/shared_regressions/si-18-certificate-parse/KeyFailureCerts/parse_fail_spki_unused_bits.cer b/OSX/shared_regressions/si-18-certificate-parse/KeyFailureCerts/parse_fail_spki_unused_bits.cer new file mode 100644 index 0000000000000000000000000000000000000000..3cc0172051dab22a6302c0a21219d883a3fd37d6 GIT binary patch literal 584 zcmXqLVsbHPVtl=TnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYGLkkBO0uRlAXefs5IZC1}@cQQo|B zt3Ka&{PNfF-mS;HJ03g=NdC$3BD5zZW%If_jGG_22%WYouRf$@prw)`ki*s{_GA;U zO=rM|1^<-4E_O9=HV^`aj;t^v<9`+o12!N9j5Y&4kQhHmj0G5tYzDF*J|Bx1i^!V; zmR0xDszo;n&+EOmseIY4cUlXPqL$f%!N8SC!KtKd%BEc(v*t(IUsQSd;_J4}lO5;R zUaJkyE}iC@w3&xVk>S{!GdvQzd&^YSR2>DYnlBYEdCg_8Vv(|Z)4xTo=VDg?03Q3T A^Z)<= literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_basic_constraints_too_many_bytes.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_basic_constraints_too_many_bytes.cer new file mode 100644 index 0000000000000000000000000000000000000000..dc2864f29a5840bd6e31c258e0f49d9c10f57359 GIT binary patch literal 586 zcmXqLVsbNRVtl)RnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzb$666O7vH&BJ%|I5!=VK9L z5qWdKvg&?Xwdh9SdA-**l`q@%PHQ1jPYqjCorPExKHuEqkG8~(8hDTy|Z<(r^s-s|4^QGb?uel6XEK-(l`nSmSTPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzb0yu@3l?k%XYofT8I?4%pME|u1pF}C1q1K?fRHCKhpl9%F7pDw{4#6 zIKTE6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfhjNg$)Ej91b2X=fs@MwEUvH%tS*W0|AgAI}fLGX+dgHNoHO? zOd%H!mt#RePO5@uUb3E{tbsI0AvcdmaB6aCQD#Y{f@@xSW?pJ)QD$Dcp_G9HNSc{P z&^f;-HKeGtxI`f&6-YQc8pw(B8k!pz8krdx8yOoLMM1gdP_98^7abicXCMP{s3@94 zeNq$C6buc*fB^ytLMBEwR_#U>1}?7hci4A zcyFAZ$vM%lTWCqWdB-eyPGtNke+(cH5w*!JyudQuz!aT>&q literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_11.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_11.cer new file mode 100644 index 0000000000000000000000000000000000000000..216eacd658f2417763bc741e6bff46858455385f GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pwjNg$)Ej91b2X=fs@MwEUvH%tS*W0|AgAI}fLGX+dgHNoHO? zOd%H!mt#RePO5@uUb3E{tbsI0AvcdmaB6aCQD#Y{f@@xSW?pJ)QD$Dcp_G9HNSc{P z&^f;-HKeGtxI`f&6-YQc8pw(B8k!pz8krdx8yOoLMM1gdP_98^7abicXCMP{s3@94 zeNq$C6buc*fB^ytLMBEwR_#U>1}?7hci4A zcyFAZ$vM%lTWCqWdB-eyPGtNke+(cH5w*!JyudQuz!UHZg^ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_12.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_12.cer new file mode 100644 index 0000000000000000000000000000000000000000..5b56e232edb68b3c3978c7d35a5ee626cb83e1ff GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fUtvukcp9vRlAXefs5IRf#sJoL)`oK#=Dr~tDPR5uhmM-eDu2N;SA3N z-W#W9a!&N?7Ftp-x$a9+ubGs|oRohrH!<1$ZJt}_P^-vy<<@keM~h1hiVb*xHp>b# zGX7^_GGH*^1M&DlJQijq)&&N_AigRKj{z4Ohc+7{D=RxQlYuNqkdH--MP#?#xi7nB z?U^t4v-q~)>(I%IBcpQ+6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fUtvukcp9vRlAXefs5IRf#sJoL)`oK#=Dr~tDPR5uhmM-eDu2N;SA3N z-W#W9a!&N?7Ftp-x$a9+ubGs|oRohrH!<1$ZJt}_P^-vy<<@keM~h1hiVb*xHp>b# zGX7^_GGH*^1M&DlJQijq)&&N_AigRKj{z4Ohc+7{D=RxQlYuNqkdH--MP#?#xi7nB z?U^t4v-q~)>(I%IBcpQ+6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hW^5VRP<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh* literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_18.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_18.cer new file mode 100644 index 0000000000000000000000000000000000000000..6aca37fb6e0c46057cde78fc6ec74471a2b347d0 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWQsTUZ<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYn1M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYzFM~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz1M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxTulfIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxW&ofIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi^~m)4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi;E134S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%Sj44S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP40wPx%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4fugJ%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4Y+_d%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6h3P#K3d8zU<#J2R7kEJ%=#MT|vcx81ofyJqc~ zFZZ+fw&3f~$%`YSa}4A`(#k9n24W2&Zw^>i-A}6)-6%Y-_u8iNWxL*KEksHW%pME| zu1pHrb534vORG8?@yCPh+p#l`_*Xnh6Vq97CUBc{*qYt*uP`YxEDBsx_RQLvxAN?^ a!nAqsZFYpc+MnVP%{|+KZQrh^C&d9_G{lAg literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_3.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_3.cer new file mode 100644 index 0000000000000000000000000000000000000000..5542a660e236f9ecda6cd8068bf836fceb441744 GIT binary patch literal 649 zcmXqLVrn&LV$xs0%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S3jCLS=;+ z8UM2|888^|0o@_X58|;fGqEl(5C-v8S$GV%*f_M=7+G1_nVAe^L4tfNVk{!N?aqDK zHEYj&xu3`*uA&DGmT*hs22h literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_31.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_31.cer new file mode 100644 index 0000000000000000000000000000000000000000..6cb245a4549c704714d6211cbd2604e3f6d20e49 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S3j?RAq%3 z8UM2|888^|0o@_X58|;fGqEl(5C-v8S$GV%*f_M=7+G1_nVAe^L4tfNVk{!N?aqDK zHEYj&xu3`*uA&DGmTVJ;YZ4 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_32.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_32.cer new file mode 100644 index 0000000000000000000000000000000000000000..cbb0238e1e98e29507f168e30de7acd62b41b2e4 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{byk^U@+hV@%R}T|Ff_#GqEl(5C-v8S$GV%*f_M=7+G1_nVAe^L4tfNVk{!N?aqDK zHEYj&xu3`*uA&DGmT*g2agc literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_33.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_33.cer new file mode 100644 index 0000000000000000000000000000000000000000..7a2594b054ab23fcd420ae97ee717d9d199f779c GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t^U@+hV@%X_!W+v7J2Erh|DhrPR7aNB*8zU<#J2R7kEJ%=#MT|vcx81ofyJqc~ zFZZ+fw&3f~$%`YSa}4A`(#k9n24W2&Zw^>i-A}6)-6%Y-_u8iNWxL*KEksHW%pME| zu1pHrb534vORG8?@yCPh+p#l`_*Xnh6Vq97CUBc{*qYt*uP`YxEDBsx_RQLvxAN?^ a!nAqsZFYpc+MnVP%{|+KZQrh^C&d9|Jj99s literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_34.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_34.cer new file mode 100644 index 0000000000000000000000000000000000000000..456ffc73fe8c9f9961d091f27cf835bbedf34ad4 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{s+bmg8?6i#}DGMFf*|(Fc1duRatlpxY#(f*%(<_*_oLPWI=*_EMhDoyY0?>*)?m= ze7T>+w*_B^PF@@tons&ml2&GsFc51Hd2_(B>V8_a=tkjrz1KFCFWdD_Yavp4VD?}z zaAi`^o^$eYTUyoGh(8`|-;SMm#J}Q6nwZXtGlAQr!`AGce}zerVNu|kvS-%Typ?CS b6{gL5Z?hxp)&3NZXztk-Z2NXSJt+6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hZ@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hY@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+igV+obz2k}^#nOGMX2!mu*S$GV%*f_M=7+G1_nVAe^L4tfNVk{!N?aqDK zHEYj&xu3`*uA&DGmT*dBlkT literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_38.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_38.cer new file mode 100644 index 0000000000000000000000000000000000000000..7b29b19374c6e86a27355daec3d7bcfb3a926ae0 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+igV+xh!2k}^#nOGMX2!mu*S$GV%*f_M=7+G1_nVAe^L4tfNVk{!N?aqDK zHEYj&xu3`*uA&DGmT)3&e*2 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_39.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_39.cer new file mode 100644 index 0000000000000000000000000000000000000000..fd9e2af4b6eabe571fd7baaae6d8485cce5d195a GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%R~;{`*uA&DGmT*bi|1O literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_4.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_4.cer new file mode 100644 index 0000000000000000000000000000000000000000..822523200d38b1a605e2a36ee416b8939e46a2a2 GIT binary patch literal 649 zcmXqLVrn&LVp3ed%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJR%RyF1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%X_!W+v7J2Erh|DhrPR7aNB*8zU<#J2R7kEJ%=#MT|vcx81ofyJqc~ zFZZ+fw&3f~$%`YSa}4A`(#k9n24W2&Zw^>i-A}6)-6%Y-_u8iNWxL*KEksHW%pME| zu1pHrb534vORG8?@yCPh+p#l`_*Xnh6Vq97CUBc{*qYt*uP`YxEDBsx_RQLvxAN?^ a!nAqsZFYpc+MnVP%{|+KZQrh^C&d9_WW6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G`GF1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G_4)1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPxZzA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1>lH~Rb}BZ;9}#@W@BV!WoKqGkOe8?V-aH!*==|3%dS~_ z=F9yozAgAVbn@cJ=o|xikhC(3gn?Lt$eRO}Rrk}XMK=o1>%F$AeA%vdS__fV1G5K% zfh&`O_MDTK+tRAeM*Q($`*!TiBmNan(!_LDoC(|}9kyoo{3}d~42uHSls&Vy=B+%t btuSrgdz&3$ulA>SM03x!VB5Fr=}B<_V8_IT literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_46.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_46.cer new file mode 100644 index 0000000000000000000000000000000000000000..bd9b22ee7499a42a51a047291a848619fddda226 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPCA%AvBVEIbBWY#iEbjI6Be%uEKdAVqvEVk{!N?aqDK zHEYj&xu3`*uA&DGmU8n8dCC literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_47.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_47.cer new file mode 100644 index 0000000000000000000000000000000000000000..5b52cc5726211f1eba57c355b221e6088e5a1844 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzAB590T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0V^AaHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0Y4juHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_50.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_50.cer new file mode 100644 index 0000000000000000000000000000000000000000..00d8fed692bc14d1839b9198f99901d723f7d4ef GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yaHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&y;HX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfjmf%k420{WVhY9FS};# znJ@RV__pBd(8-G&*PpcN)C_JzC+NSblyWVLnL`o0L9t;Mq zObXg_PF`+Ht2!I;$Aj(Lu``eOS3F4*(^+vQaGP}4n%(oSFex%D3S3k6%-Wi_^6a+4 Zw0ZAsc7(m!pW+eCJ==n9->#=8#Q|sF#E<|0 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_53.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_53.cer new file mode 100644 index 0000000000000000000000000000000000000000..7193378d3f44996ef8c3a04c775dfaa7efc26eab GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2lj0V_z5k420{WVhY9FS};# znJ@RV__pBd(8-G6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfh?PJs4O3g7>memyK`T5 z&Dt|x?q~6B!PlXa7e_|t7|4V4D6>cyh&713Ibd0JKdoAHqwu`mYn#fK?RuxR5Gg${ zdoUQdGAU@!IeED)t?F#V9}l)~$Id+BU-2YOOlQTJz-`iDYj)4S!lcNsC~!^LGiz(! e%Cp-F)8@Um*%9_?e~L#m_iPKceY>8X6bArwXvC%f literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_55.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_55.cer new file mode 100644 index 0000000000000000000000000000000000000000..47902a4da4978e2554e61a83fa6a7cf29ff88395 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfhdB-eyPGtNke+(cH5w*!JyudQuz!U){ui literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_59.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_59.cer new file mode 100644 index 0000000000000000000000000000000000000000..99a84730349d52e15c04862cbc39c832339b79bc GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfh#=8#Q|pw#E$>~ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_6.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_6.cer new file mode 100644 index 0000000000000000000000000000000000000000..25708f1138a07c47c43cf6ebee4bbd5782dbb40c GIT binary patch literal 649 zcmXqLVrn&LV$xZ_#Kg$NB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfh8v;txJ^22&F=YEm=qZn1+FQ3W^K(| dd3IZ2+PwERJHlS=Pw|N6o^8RlZ`ae4;s9n4#Ebv{ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_61.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_length_61.cer new file mode 100644 index 0000000000000000000000000000000000000000..fdb1bbf140beba97bab60a3b4a4eb0716a445a41 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qPBJzA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfhc=8c2f_a`T7;rzV#cWtLPbxaOs2=B1_6C)$T0baEQJudz);%+^^b@_3M&*?Ma9@1IYoo zTzW*|yvJNYW#ev%m+f|I-u|j8Utgm;d10H`HG_*s_zchNNUGd1C53&)qLm*?{vW-w zJlk_BTVUz$sRy`a=koru`;*nZ>09fFUI#D`$x9*y+nK&qTvUj~_XpfvFZ4(2NXf^Y7*Ve_Y|- z^&l=`gL~D&(@~Y`CnHVn?2G%}GFL)+=ecURg)1+*M5izIy}7aW$6v{gGvB2it+=GW zn&|GyZh)B7+Y7vD4sTv1GNo!5Y}`IKD(jX}R&i9%!`$)`&2RHxGnTt2 z%*)=?RHOK@PbC@ko0rWGqb2 zcKR1`^_xxSWW5#^LA>zyC~y*QtkHnr}-M15Ad#?5LaEc_JX9&?|NH4 E0MKo6A^-pY literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_rsa_sig_nonnull.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_rsa_sig_nonnull.cer new file mode 100644 index 0000000000000000000000000000000000000000..96259072e5662f7bd4f3b769bc071d7a14783ce6 GIT binary patch literal 847 zcmXqLV)iy@VlrO9%*4pVBw`eHVLH=EQ-KK25Uq`xf0)l}O>{TlW#iOp^Jx3d%gD&h z%4pEoWyo#7$;KSY!Y0fV8f++RAPC}c@NhXN=47Vj7v*Ip8VVT*fCSljIGsxiQj1D5 z^YUQ|xp=r73kq^l6+H8j^$cYVq(KU~c|?L!lS_*-ODYvy^U^c(Qd5gE^U@9F3}isk z%sisb`9-NAMWw|h3L&XLA}H8V!P(J3PMp`!+`!P-(8$ol(8w|h%r!EAaR-TGeNq$C z6pRhRfPume49au1OpI)-+Kns>T+B`kEZ=@#KD>X?G<`;{Mkdk8VJn|CeU+?_cQLy0 zOuL`slF5?=6&XafKsB<>mJ9hdq%rnuj(c?!;7tBqJ zj0_R}Q~tlc(iXck-cxFQ9`~ssesag>y)nDz9m}{UBeYfY?khe;o|1)@ zCL)Cf*N&e3yT(zSMCygUyxQXv25a+Gd@Zic3fTb;?RUE zNBOt(^1#L#k#isv4;88+}7flj)1P- z{Vf-mQ-V+1c=8c2f_a`T7;rzV#cWtLPbxaOs2=B1_66C=X`UbO{1F8(j#Zau$s`EiQR=`-OT(plG?Zi~OTx@RMY+!pgWEXmz}7D#Pe zdPL#8$6P^W<8FzU?RIP4{;DcpU!yyDVVl`CgNsM_4A1OHs@yRpg?+}Nl^;s}AHB0Y z+jA;gVCnCv2e@VD^8T~?lhwWHTkFD-dxDZT9Xw=K|G#qDPP4+XY0fsO1HlvLXvayU zKbRX7`;|NGc-%xwRkvSd$BU}V4`j5uTn=%`-W1hxcFWe1JM4C|LtN&a5RK0;Q|zjZ zGS%mA`fy?8%)JWv_ZElERQc|z6aM)AkLH+14f^F@8v2yPf3}Lc*j)%WYOcpihXNc|C>B}(BM8igpA32y}Ygaa7O4-0~95Z}VR>mb)j+ z%ih#fqxiAo-no8-8k?Mqjm`akgJ!W#QEA&*P;1NjYI9I6gNP8+|EKJXK z`WJHbn@#6ry%rI6v9o_~p3HFbc51!5DC2!n?e_Vn`5KxJ@UEQ@S6#ODf~3yxdRsmK DUNLeS literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_1.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_1.cer new file mode 100644 index 0000000000000000000000000000000000000000..ae97c2b29b9e67be155e691847cdecfc9a8f1b09 GIT binary patch literal 649 zcmXqPVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYuMODM~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeL&Gp&fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqOG*uj4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiQ4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S9ez%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4R~0XLuG{- z8UM2|888^|0o@_X58|;fGqEl(5C-v8S$GV%*f_M=7+G1_nVAe^L4tfNVk{!N?aqDK zHEYj&xu3`*uA&DGmT(HpGSi literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_16.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_16.cer new file mode 100644 index 0000000000000000000000000000000000000000..5bf0a727acb70e47b625719197da802a32a31406 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3w z{%2t_U@+hV@%R~mJQijq)&&N_AigRKj{z4Ohc+7{D=RxQlYuNqkdH--MP#?#xi7nB z?U^t4v-q~)>(I%IBcpQ+6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2+~U@+hV@%Vu}78YhE)&&N_AigRKj{z4Ohc+7{D=RxtnJh?6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_WH8_Z@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+tZ@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfhJk literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_2.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_2.cer new file mode 100644 index 0000000000000000000000000000000000000000..f65a92a2bdd1eb01c121087ce237484f999fbdef GIT binary patch literal 649 zcmXqLVrn&PV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+ig0rL1kJQijq)&&N_AX!xw9s@2m4sA9@R#tXqCIeZJARmhui^y)fb6ZxTfrxwKZ?$ d*=>bs^WNL+2z#|Z#Uq+~wgub1T~AMn0{~%C#D)L> literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_21.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_21.cer new file mode 100644 index 0000000000000000000000000000000000000000..22ef45356460926674863dd970f093ebd2d2e177 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%Wj5JQijq)&&N_AigRKj{z4Ohc+7{D=RxQlYuNqkdH--MP#?#xi7nB z?U^t4v-q~)>(I%IBcpQ+6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%Vu}W)@~9)&&N_AigRKj{z4Ohc+7{D=RxQlYuNqkdH--MP#?#xi7nB z?U^t4v-q~)>(I%IBcpQ+6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ78WMf1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1%|>PzA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+_K)xyqj{z4Ohc+7{D=RxQlYuNq5g&^fi^y)fb6ZxTfrxwKZ?$ d*=>bs^WNL+2z#|Z#Uq+~wgub1T~AMn0{~%i#D)L> literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_26.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_26.cer new file mode 100644 index 0000000000000000000000000000000000000000..85383c03944b1b3ec5d77f5c0499eae9d3cd6635 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA7`10T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljp)5#{k420{WVhY9FS};# znJ@RV__pBd(8-G6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh-G9kdH--MP#?#xi7nB z?U^t4v-q~)>(I%IBcpQ+ZxTfrxwKZ?$ d*=>bs^WNL+2z#|Z#Uq+~wgub1T~AMn0{~&1#D)L> literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_31.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_31.cer new file mode 100644 index 0000000000000000000000000000000000000000..0b83e84d822af434d5fcb0ba86c8a2ba5ec7cbae GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh2u literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_33.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_33.cer new file mode 100644 index 0000000000000000000000000000000000000000..e1aa22ff609989ce583556b02eca2832016ba50b GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfhrZ# literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_34.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_34.cer new file mode 100644 index 0000000000000000000000000000000000000000..04d5196b63196b4f388c1654dbfa5856842e29eb GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfhjNg$)Ej91b2X=fs@MwEUvH%tS*W0|AgAI}fLGX+dgHNoHO? zOd%H!mt#RePO5@uUb3E{tbsI0AvcdmaB6aCQD#Y{f@@xSW?pJ)QD$Dcp_G9HNSc{P z&^f;-HKeGtxI`f&6-YQc8pw(B8k!pz8krdx8yOoLMM1gdP_98^7abicXCMP{s3@94 zeNq$C6buc*fB^ytLMBEwR_#U>1}?7hci4A zcyFAZ$vM%lTWCqWdB-eyPGtNke+(cH5w*!JyudQuz!Whcam literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_7.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_7.cer new file mode 100644 index 0000000000000000000000000000000000000000..d947fb970f7b8e06a7b64173a4934760e4fdfd17 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pwjNg$)Ej91b2X=fs@MwEUvH%tS*W0|AgAI}fLGX+dgHNoHO? zOd%H!mt#RePO5@uUb3E{tbsI0AvcdmaB6aCQD#Y{f@@xSW?pJ)QD$Dcp_G9HNSc{P z&^f;-HKeGtxI`f&6-YQc8pw(B8k!pz8krdx8yOoLMM1gdP_98^7abicXCMP{s3@94 zeNq$C6buc*fB^ytLMBEwR_#U>1}?7hci4A zcyFAZ$vM%lTWCqWdB-eyPGtNke+(cH5w*!JyudQuz!UHrs` literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_8.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/parse_fail_tag_8.cer new file mode 100644 index 0000000000000000000000000000000000000000..1bc896bead9affff320b12f4668d99ff125b18cc GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&i>a^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfhPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4s4Y=TO%k05m;L4=nR8lr&)2@$M^CRsqs=R#hb=&62 zj`M4;)rM!6PIFD#%)_L}aBR*Q9*Nz(WvXhbj)GOqmx`CX<}z5ZNLjw=-y+v@u`2+4 C5v}PUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4s4cOpu%k05m;L4=nR8lr&)2@$M^CRsqs=R#hb=&62 zj`M4;)rM!6PIFD#%)_L}aBR*Q9*Nz(WvXhbj)GOqmx`CX<}z5ZNLjw=-y+v@u`2+2 C!L9WG literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_3.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_3.cer new file mode 100644 index 0000000000000000000000000000000000000000..71a9481420a056c82b2e9d0a68888a743717e34f GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwmBGN3Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004U8 Bt@Qu^ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_4.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_4.cer new file mode 100644 index 0000000000000000000000000000000000000000..d626fda8fbdf3d5fc780da14e029e1b6c93e7bd5 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwpTWSDNx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004cw Bt^WW3 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_5.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_length_5.cer new file mode 100644 index 0000000000000000000000000000000000000000..e75872056b6a97fd5b05325ebee5ed719c038921 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sfpN(Sjaz091_M_n1*ej-DVuhE%$gr*e^KS-i?7=@ zPj;MNd#yG+yL6gs(qPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sfpN(Xjaz091_M_n1*ej-DVuhE%$gr*e^KS-i?7=@ zPj;MNd#yG+yL6gs(qPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4s4H0q6?7?8*%B0{_QZ{ANu8&#sBkeD$ynOL>+vdrR z^J}lwhG&;fb4}XJ!=%V?Y|a@TiQTq6zikH0RGFY)lS-$DtBG+@VD*${F Bt@!`| literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_tag_2.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_tag_2.cer new file mode 100644 index 0000000000000000000000000000000000000000..63fffbad0e3cf5751f84bbe245fb2c674eb6634b GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4s4LDg~am(z%VBpH6;8apJWz(*YS@R?9FRHwJ@paqg z$&T}DuhoWUmrip{+RVeG$Z%}V86JtE9yPbFnJ` Ddl#+t literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_tag_3.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/signature_fail_tag_3.cer new file mode 100644 index 0000000000000000000000000000000000000000..8071b5615eb1445b21395309898da2586ce08f6a GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxcgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004Xk Bt@!`| literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_1.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_1.cer new file mode 100644 index 0000000000000000000000000000000000000000..42533fcdee459bf5fe9c01972f88e69a48dc0a11 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYGLkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004i9 Bt^5E0 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_10.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_10.cer new file mode 100644 index 0000000000000000000000000000000000000000..f8715b941dad160ee602e5a06e76ec8e3448ad09 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IJfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004Ra Bt@Z!_ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_2.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_2.cer new file mode 100644 index 0000000000000000000000000000000000000000..cf2da6fba33d2df2e0cd62932b59ac61afcac4e4 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYGXU|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004Fi Bt?~c> literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_3.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_3.cer new file mode 100644 index 0000000000000000000000000000000000000000..4d39d0ef6c4c4861f22f61128e37e340011b94c4 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{15s%3F)^~SYB#bla4|bEumtUTEy|mB zZq?@-k6->e-n;dfcgKTA0m(l(UWE3fq-|&IUrj;E@$(Wc<&_sUwqxRd9vgD z+H1Ap*`?E5lQ#1(DKZ?JbB0G^cW;@hnyRB A{Qv*} literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_4.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_4.cer new file mode 100644 index 0000000000000000000000000000000000000000..bb34c500d7244eebc20f1cdb876614a54f40dc13 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{11@OrF)^~SYB#bla4|bEumtUTEy|mB zZq?@-k6->e-n;dfcgKTA0m(l(UWE3fq-|&IUrj;E@$(Wc<&_sUwqxRd9vgD z+H1Ap*`?E5lQ#1(DKZ?JbB0G^cW;@hnyRBPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|{frgO7=kja9pmg@KFNiGd|(*K1MU zymPBQ-+27;*YV!1$GkfpJPJtu$?+nzCnaU`x;u=UAG!#gwkxkbq-CI`k|L19)+Y93 z6R%BYz=s9@l)o-^HE=c%0tSz)FeBrC77hb8AO(y!13r)#KS+!P7>{fQvLHSmix`W@ zn*)|r_tUCHHww?|y|$@**{*k53z6cM*@MBrl}W*=q-@HjT_3aNN7`RhdHLe&w#}0r z=ht4V4bLu}=9;vbhe?s)*qk#w61#iLRMk`+1*@7b6)$PUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|_I{fQvLHSmix`W@ zn*)|r_tUCHHww?|y|$@**{*k53z6cM*@MBrl}W*=q-@HjT_3aNN7`RhdHLe&w#}0r z=ht4V4bLu}=9;vbhe?s)*qk#w61#iLRMk`+1*@7b6)$vol literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_7.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_7.cer new file mode 100644 index 0000000000000000000000000000000000000000..a49b9790288261d0f2f824986cf657bfe078b2a7 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uS-X*ifs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004RM Bt@Z!_ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_8.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_8.cer new file mode 100644 index 0000000000000000000000000000000000000000..347511d24f2c607e96e9a7f716bbc57b9b4bcae8 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uOS_SUfs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004kH Bt^EK1 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_9.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_length_9.cer new file mode 100644 index 0000000000000000000000000000000000000000..4d96d3891afb6b10002a8119ea5cfc40f96a51cb GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IdfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004ek Bt@{7~ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_tag_1.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_tag_1.cer new file mode 100644 index 0000000000000000000000000000000000000000..ead473182034dec2bc8ebcf281c6dda9d9bcfe72 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{fQvLHSmix`W@ zn*)|r_tUCHHww?|y|$@**{*k53z6cM*@MBrl}W*=q-@HjT_3aNN7`RhdHLe&w#}0r z=ht4V4bLu}=9;vbhe?s)*qk#w61#iLRMk`+1*@7b6)$PUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{Ljh>;F)^~SYB#bla4|bEumtUTEy|mB zZq?@-k6->e-n;dfcgKTA0m(l(UWE3fq-|&IUrj;E@$(Wc<&_sUwqxRd9vgD z+H1Ap*`?E5lQ#1(DKZ?JbB0G^cW;@hnyRBPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{0|6FD@G&v6v1&K6FmN$DF|Y*fdM(PE zcW%|^8;@W9I^MhWn0Lp6M*+z{IbMYJq@-+KcZYHFLl>dbcIDNFv<$RVQUr3?+Qgo0 z;tojZNc)Q_FJFA!wt2GS z{Mu`^;n}6rT$48QFex$|n{$RoVs~$us+y{!U{&*_;w7)S3|1^smT&sE$n{+83IKWC Bt@Z!_ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_tag_5.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/spki_fail_tag_5.cer new file mode 100644 index 0000000000000000000000000000000000000000..1700a48cc3fd1786904859e6f039dc4d1f9934bb GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs4h7fhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004ZQ Bt@!`| literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_basic_constraints_no_pathlen.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_basic_constraints_no_pathlen.cer new file mode 100644 index 0000000000000000000000000000000000000000..d81c95a2653f12a9c331b747023cb1a844e9ee22 GIT binary patch literal 582 zcmXqLVsbKQVtl!PnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbV8_a=tkjrz1KFCFWdD_Yavp^GJ7x>xH2g?m6T1{wCiKm{7CzYDlcDr-L`qMP`|aj0Clwp;vTZOXzXBP z4rO7MYiwZfWyoYmW+-CFXD9~ZG=>re1qL@DtB4^L$ODPzfyF|AD&2u{9t{YLH8e6XHZU?W zGBh?djS}ZIu{1CQLNJILd=746R6-6^Mpg#qCPsb+gC<5UrY1&4hFMH2-97!<&wSzC zbyu~ZVAZD2E=R6sz82Rt;!OUk6)dRZLTEUc7+8@WKIkyZHVZy-nR8 zXXh=~khmr|x7UQvruAM*n2*&d8NCH6H)fxef5GueTL1Cn|E(*ZmM`<%DVw@mb~%s`-{KTGS4%5nOwMRqWyP*|BO??LN9KtX$eket##&DZmxXp zzVfC8LYGb?{5`lxve>HP%L`%ui6_0|ZEkKAG`nq^z5H+E9qv6(zpT>`UnV|FRlGx< ziJ6gsv5}LZc+yMr_WQ^7G$ELan;1iY;S^vX3rv2pd@N!tB0Fx(~WG)MjI3VQexNWo6?4GFe&KnHk|MW&?hZ zN?{fb12#s+|4fX)#J(RS!pPFN-Jo$x16I2hHclLLNvsKxdsRUmP+*ZWkTH;g`IL#t zfX{#jiN}DP9)X!0m>wA!W-752ow#hj_RrtvS2skM-q2k8 z^wQd!`?@94O!76D5*xgV-nAJDU7eJpGC7^=Y4CdIJL;|R+FzUMa(&7s^*?4wF%j?K zJJH5u&1849!f)=)hdNAMzcb&n);<3tZhH5&+j=(d-l&)U%Bpm(Q1#ef`nh6>a0~|iY~|4eqR-?|Fyo$<4SS@`_0=Qnk^1qvd*e5kgzIR zvp@UaKaNvRY34(ke%!BiTl;k e|BcOlccuQjp6mLe$g{zeVRNd-Ja=Eiv+)2hU#>v_ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_keyusage_mask.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_keyusage_mask.cer new file mode 100644 index 0000000000000000000000000000000000000000..ffd8e2b33c5b6e5aa55e81a09645866cce9a55e7 GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a^#;NqzA6ik0T&yGHX9==D?2ljfhGE5!d3SP4iJx@aAtptJ$Guh#lU^N~(xJPlyZva{gxD(|9o9$w+Q_sow3aF3qb>kC Cr^;&p literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_unknown_apple_extension.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/parse_success_unknown_apple_extension.cer new file mode 100644 index 0000000000000000000000000000000000000000..e605422992309fde5d3d431da2206301c587a4eb GIT binary patch literal 466 zcmXqLVmxQi#8|R`nTe5!iILHOi;Y98&EuRc3p0~}qoJ^YARBWi3x_b5b7D?rT7FSp zW+F_GOPI^Cpdcqz!80#e&rsAr7^IR}m?t=~EHOP**V$3m)xbbboY&CIz{1Gb(A3D% z&@4)v*Vqt=YtT5+klTP0q?1jUDKr>nHW3!87$||XaSKaBEL3nwEz3+!Rd7x%D#=XC zOinDx%+E74GBAKROVa=X40R1Gjg!nREs_n*(h}2>42(>ZO$}1g%u-X6%}gu|4blw! z3){MsF*~ZB z{@hlYzhNHJ?~99AT;{B7zxLI3)$E1J46g+jiyMFfhZAUG+xO%YHV;O||18Wv0y(Ui zJs1pJnG|xDYcu}aaQWwb51-{OG4;|>y$n79jbEo-NmkNb_I%!KCPjuT4c5$DA9Md* d-k6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfhw=ExeYjhY!)_QrqEzRVFN)Bhl7X9IWZ?QEx#x)Gtp4UKma7j&co?kT98^) zl9`teQ^>``Q?c1rpAV26E!OhUNx_MrKCFM#jcQQBbZqlxxt~MMsCq8OT5! zDvIV%pVY)O1w(@{V1Pivk%^IwRlAXefs5IRf#sJoL)`oK#=Dr~tDPR5uhmM-eDu2N z;SA3N-W#W9a!&N?7Ftp-x$a9+ubGs|oRohrH!<1$ZJt}_P^-vy<<@keM~h1hiVb*x zHp>b#GX7^_GGGA47m&vf;;}F@u`VzW2Jux{cnrAMIJDUqSy|bcnG9q>f_yAuEF!z@ z&VAW6YtMYSpT)NYUx!X!92uQsAPeLHsM5&w!OX<|An&IE3g4qLN({uL%ghDCvE j%AQ$U^H!eSR+u*Lz0HoWSNl^uqPb^VuPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>Zxwox#9`Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRN%7d6GdvQzd&^YSR2>DYnlBYEdCg_8Vv(|Z)4xTo=VDg?0NIDF A^#A|> literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/path_fail_mismatch_algorithm.cer b/OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/path_fail_mismatch_algorithm.cer new file mode 100644 index 0000000000000000000000000000000000000000..34bb7f6a56a805bb4d12a17d66c7f6950fc2482a GIT binary patch literal 655 zcmXqLV(K<%VlrO9%*4pVBw`eHVLH=EQ-KK25Uq`xf0)l}O>{TlW#iOp^Jx3d%gD&h z%3#pgWyo#7$;KSY!Y0fV8f++RAPC}c@NhXN=47Vj7v*Ip8VVT*fCSljIGsxiQj1D5 z^YUQ|xp=r73kq^l6+H8j^$cYVq(KU~c|?L!lS_*-ODYvy^U^c(Qd5gE^U@9F3}isk z%sisb`9-NAMWw|h3L&XLA}H8V!P(J3PMp`!+`!P-(8$ol(8w|h%r!EAaR-TGeNq$C z6pRhRfPume49au1OpI)-+Kns>T+B`kEZ=@#KD>X?G<`;{Mkdk8VJn|CeU+?_cQLy0 zOuL`slF5?=6&XafKsB<>mJ9hdq%rnuj(c=fE0f=W< z7@6G}3|yELBpyFAy?0RH%<5So-_5P|7U?{=ZK@Y}=;56Bi*Hvi3Fc!`sO);KxXRGC eao!noFaKrbliNdzrgW9RXx%+^8pn;D2`&IE#=Wxu literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_length_7.cer b/OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_length_7.cer new file mode 100644 index 0000000000000000000000000000000000000000..19a221c72640865f3ed8bc4cebfa941eb04d0009 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcUwNx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004UH Bt@Qu^ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_length_8.cer b/OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_length_8.cer new file mode 100644 index 0000000000000000000000000000000000000000..b681592f4b48b35b2259cb93b23a52b1add02f4a GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU`Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004e@ Bt^xo6 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_tag_4.cer b/OSX/shared_regressions/si-18-certificate-parse/PathFailureCerts/signature_fail_tag_4.cer new file mode 100644 index 0000000000000000000000000000000000000000..a660b8109da41b12f40c4d3ffe4f1b7fd2dea2d0 GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTc_1Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004Xh Bt@!`| literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/TODODescriptions.txt b/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/TODODescriptions.txt new file mode 100644 index 00000000..6a30ddba --- /dev/null +++ b/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/TODODescriptions.txt @@ -0,0 +1,29 @@ +The following certs do not fail because parse failures in non-critical extensions are ignored. +The certificate merely marks those extensions as not present. +parse_fail_keyusage_extra_bit.cer + -the length field says 2 but there are 2 bytes in the bitstring (plus unused bits field which makes 3) + -we happily skip the extra byte +parse_fail_length_63.cer + -length field in AKID +parse_fail_tag_27.cer + -tag field in EKU (seq) +parse_fail_tag_28.cer + -tag field in EKU (oid) +parse_fail_tag_32.cer + -tag field in SKID +parse_fail_tag_36.cer + -tag field in AKID + +parse_fail_too_big.cer succeeds because we ignore extra data after the cert. + +parse_fail_basic_constraints_notCA_pathlen.cer +We don’t enforce (from RFC 5280): + CAs MUST NOT include the pathLenConstraint field unless the cA + boolean is asserted and the key usage extension asserts the + keyCertSign bit. + +parse_fail_ec_not_on_curve.cer +We don’t check that the point is on the curve until we use the key (e.g. for verifying a signature). + +spki_fail_tag_4.cer +SecECPublicKeyInit doesn’t read the parameters of the algorithm ID. \ No newline at end of file diff --git a/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_basic_constraints_notCA_pathlen.cer b/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_basic_constraints_notCA_pathlen.cer new file mode 100644 index 0000000000000000000000000000000000000000..ac8ff965b433c089448b4cbb996eaa99fbc8e97d GIT binary patch literal 582 zcmXqLVsbKQVtl!PnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhBO)Yf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004U7 Bt@i)` literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_keyusage_extra_bit.cer b/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_keyusage_extra_bit.cer new file mode 100644 index 0000000000000000000000000000000000000000..3bb62abe8876b4e5889311eb7b848b7744832904 GIT binary patch literal 650 zcmXqLVrnyJV$xl}%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi^~j340wPx%L+3x z{%2t_U@+hZ@%TYJR%Ryl1q}wmAOTet9s@2m4sA9@R#tXqCIeZJARmhui^y)fb6ZxTfrxwKZ?$ d*=>bs^WNL+2z#|Z#Uq+~wgub1T~AMn0{})R#Sj1h literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_length_63.cer b/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/parse_fail_length_63.cer new file mode 100644 index 0000000000000000000000000000000000000000..e61aece15eae2f68791caa07e2d18429431eb7fd GIT binary patch literal 649 zcmXqLVrn&LV$xZ_%*4pVB+790&24pw6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ikAr~8mHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&C0HX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh6uSWu9Ys^FQItY;`|APrK;%_9<=np|3xSyHLsnwOrLmzr9XnU`)TWgr2PX66xe z&M!(0DJm^4Q3y!|63&hWa^k#(<_3mFW=6(F#>PfbP_8+YYtYz5M~BK8$Uqz_isn$C z)WkFeLxV72fIxzfiII&}yOD)~i`j{R<(D%<-23;&yO`svogSU9)k@5K^t$Td49^7K z8>eS-PW0;*T2e2$?n_dynUu+#lz%TbG1>iXo?GWotH^id)^wpqi%SiP4S0Yy%L+3x z{%2t_U@+hV@%TYJ7G@^a1qQ+(zA6ik0T&yGHX9==D?2ljfh$~79Liq+ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/spki_fail_tag_4.cer b/OSX/shared_regressions/si-18-certificate-parse/TODOFailureCerts/spki_fail_tag_4.cer new file mode 100644 index 0000000000000000000000000000000000000000..c4d068a0548fa8186b27a233e41547b4d822889f GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0mRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004RK Bt@Z!_ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-18-certificate-parse/root.cer b/OSX/shared_regressions/si-18-certificate-parse/root.cer new file mode 100644 index 0000000000000000000000000000000000000000..015792dcc08f2f38ff6a152776f798d122646d6a GIT binary patch literal 585 zcmXqLVsbTTVtliJnTe5!iId^L)SpY2DDu8E;ACUhYV$Z}%fe{T*k;HLPUq5s)S{BiynL8KE*>t&f`Xh>1<$-> zJwsUoX^=v09+BYG{U|>LkkBO0uRlAXefs5IRfhB0yYf;|3 zbE`hzc>MC$@!qY+ygME|3P}FR@glS*C1vxvJB*tjx(J=NE3ZDJWuT>!B9Oz@CiY|# zuT5vbhXwzXzbmf8 z1C~|y)2c-`3eW4kwyAvCu6J4sk>ZxwgTcU+Nx`Y4Y|5rxAG791+Fw+8`Qq!g&66GH z*Iug)&n}(jnzWgRNs-~$oHINUyL-!2)l?k?tC}wrFL}*nuws$2eAB;0uIFM`004Wv Bt@r={ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/AppleiPh0neCA.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/AppleiPh0neCA.cer new file mode 100644 index 0000000000000000000000000000000000000000..c6849621d8e5b36ead6142b5114848dafa03b52e GIT binary patch literal 1015 zcmXqLV*YH<#B_TBGZP~d6Qj5RFB_*;n@8JsUPeY%RtAG4Lv903Hs(+kHesgFU_)U8 zK@f*an9H%CASYG9GcQ@sP|ZLEB*-l+3lVfqEh@=O%S=uz$;{7Fa4ap!$S=w)sWcQb z5CN%U7UqSh3(C(gQE+xNkQ3)MFgGwUG%_?dF*dS@66ZBCLgE@!Qqc{%2HFres6gD1 z8IX~mm#Ton$p%e~O2{F?$jZRn#K_M86z5`UVq|1kEVu82`++U<1ft!R>`>g{-=TN^-~VKbh}-g#39Ky`9aEMgMTN@p>1ZSKbYrTiU-xZ~2>YcXQDL;mv== zZ|-@%;_acH#6wy?-<(?-cP;aE3U@C@|BeL#Zk%@{pFG_#C3pAtnKO>OnC<9y7c4RFPLxU$=(tOZCj!l;mPyL{ko`$@wWpDT)YbQ>1@?9Fz?Y5eSPss&UA~=u#KkL z5wBbptF^v6k>>T}eCG$-S4~q?K7D48$5lv@c}3PbuU4_a(bm&tchjci(!BI0G|~0(lmF17IXB&|IM2 zrkYVwQedU8UtV6Wmk3Iaddc~@`e0UaqJ9xDdFdq=jbqms=gzg*sn91{GbD=8J&d6~n@F()GI-fXLftl>|S&R^mO E07{s9>Hq)$ literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/AppleiPh0neDeviceCA.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/AppleiPh0neDeviceCA.cer new file mode 100644 index 0000000000000000000000000000000000000000..fac79ff89daf7520aec9adafa728f34524663bac GIT binary patch literal 877 zcmXqLV$L*ZVhUWq%*4pV#K>sC%f_kI=F#?@mywZ`mBFCWklTQhjX9KsO_(V(*ihI& z5X9jU=5j13$VpZ3%uCiYR5MTk333a|LIj;ti%K%nGLsWaGV}8k97{_w@{2M{Dh+iF zv_a~ag;gNxG6OR5^HLRXC^wK3=QS`lFflYUGBPzWF^dxCH8eru8blG{G*JU#h|_qG ztu&N3kcGHJ3|UygCABOw8R#HKgU0#D0l~=1z}(o&V9?mf)Y!=Iaf;W;SG%Gl64stx zAfBAF>3$)0w4`irz#?(uHx(yO+56^Cp*&GK!p*$$pii>{Vt!=Tik#t)~L&(Zc# z+n{Ry(r8sRN6C~o2fZz1)BQMtrbKl|E{?fA`OAWTp{=`p+@{CnZ7O%wPmkHdEwMjx zXHMI9tk4Pgy<|F&2?c{}h#7+NNezUTswCD;Bu1+^4U^Kpv!CnMJ}ttU=_tiI$$yJFE~qgzumCBLXE8L;H_%<6y+E@~J)@+gz)D}gyu4g55tIh>lJj%*!K~y& z{mcSTlmc5(!)mX<-QC3UnUf-?~@TN|HN}3 zGyJ6A;Z`@XGP7;*e_r)(-S&WM=i7^1v&&zt7TOu37%JK4uIw(j@gna@nBbV-xyHaE?ZmLLTdhsPJs?pd^> z-Qu&M{<)SVnjvfKEEFY=&2|cXT(->Y?)KZ8yW@T?jI!Uopp0o#Lv-A`mxb(#7tUC| gyOUr0vNFiZ$F?%MnPa&Mf8KnJb)oluU9eFB0FE3n_5c6? literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/EntrustCAL1C.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/EntrustCAL1C.cer new file mode 100644 index 0000000000000000000000000000000000000000..5d16f8d329d31f0969cadc909b4f868a42c5135e GIT binary patch literal 1270 zcmXqLV)XDOu`!3Ta0zp} z=9Ltc7MJMdrIr{v7}$YCxkb#&%ggmr5iG&V2Yn15S{+Y{E>T!G>Z6A|MWzFfY^+9R<(4WIaPm19ONQ4bXjARFJ5USq$}Keo-RO zsZfum7NzDTry9x|$U?M=fxKsAU;y_X)NDNi9gqTMVO6M|3b;I_tKehkY|zB0gd97J ztPIRejQk8haW1ANMn;C|i*;@0-DABad`Pf&Zr|hjjV= z*>H*f8s`o?<71l`pxJ!!(_yXKH*Wi}oMCv~y=~f^J*$2Nm9reYE%{{KoWC~R%*M9Tgh4N)OvIH8IWEc`&uSOvPu$_gq7Z-?#tWHfJhZC^3E6 znR^PHo@OeUPT!uGCw+{}U1{^yWX|Hg+jp$4f9J}7uXp3>(*7?^%Lrv+W@KPo+{DNY3=wt%K493&@-s62XJG-R zZZ-pc5MLO?XEk63QU=Cs9NKKaG|tY*$f9llN{mpx0b`qZMoCG5mA-y{a&ZB2+BPr( znIg}kZJ=qOzCd+>a+@MlWpYstvO;}OGE7d?0}2~hgY+n{m;lqF0UHaD$zY&ipa!#z ziBU`nY6g}h22Mk=d@N!tB61&Bce4HPsIqJV+vX3Ni~d*WmB+X$ r-gIFw{JhV||0|af@1H-r#LB`pUGtdqse75-_BAn?uej~gTz3Kh(9g@> literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/EntrustRootCA.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/EntrustRootCA.cer new file mode 100644 index 0000000000000000000000000000000000000000..ce27297ade38c499c2db43ee85c55863b024de67 GIT binary patch literal 1070 zcmXqLV$m{aVisD!%*4pV#A1d#AN85K^Mn+av27|^eh9U++Y|No7T*BP0 zc_l@q#U*-qsU?OE26iA(ZV~hH@^ZaYgp9s(KybW~fr*7eW?piBQGuR9Ql&ysYMP#c zMowmKW=XL^PG(|~o~EIyfilNcj^BP$im;<>c zhNgx_QA5>RO^iy&5yZ&Kz}&>h&tTBR$i>ve$jGqP*L$T<+oo5G71%|^Qna+aFYf2| z^6h)uP_{IEdxgV+Vy6=s2W|&z-;LW*Hp6ssx76GkVJklQ=clYYV>rYfPC8%yV7_b z|Jl34^I%!0r{v!QEB1CSPS-y+e@~%g!VcY+IwvQTrBzRPw7%k6YH+O0wK<#4Ycl`T zUlOqCipM!tqtLFun^JuEp3Gn`yZ1{7b3a8l4 z0_0EzW&>a-Gcs7u?hl)7@H}{CO;zP`-|5#Sr%w3ICV$Gf#x1#jTAIo)2Wdt1Q_qTu zKl%SNocZ?zk55MMv4$q$8Narzy%lTw@m$_FQNbxqJn!tMt`}U*e_j8cJad1zj@-%J zv!q<6zLxM`CV#dzTtI&|3ujcz*1Q|CRu8YuyO>iMS1BWM^zj9s$=0bhZ|~dgTlRFS z)Zwj?hxf)s@BXj+K11@f&}8)(X5D;)3v%0}*4&HwesR?b^=1Dm8;?}ZG!EY-v|;4~ zr<}>B!tVXcZQ313?^lna{o$tXR Z8g_pFN9~%pS!FLHCmgM5HWf?_1ORo~ir)YL literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/EscrowServiceRootCA0.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/EscrowServiceRootCA0.cer new file mode 100644 index 0000000000000000000000000000000000000000..a6684f618021f3df9ab91934b20dec0781b6e8bb GIT binary patch literal 976 zcmXqLVm@Qg#I$7rGZP~d6C;BGFB_*;n@8JsUPeZ4RtAG|LoNdjHs(+kR$)d1Lv903 z5SvYyDKywn*gz1(;S%O@EGWoHRq)J9)-zNyPyq>Y3(GX?PaT#J*7^2-&1Q;W(nlT#If^7Bg+oE;71#CZ*k4a|(pjf{+q zjLf6Nd5w^{1Lv?NMkVAxVq|4tZerwTFlb`rVrpV!WVpI#*3pA!KFQhcPb!=Fd$)bt zgF?YO*X!mtAG30pe%e%d?ZVUNQXT zc+^61n&XP_zV!Rk{gYLGabMb`Ki6A!!>z5QNpqH{DNGMFQlAv&xY@L56Vn+E<^l~a z)pvKrXFSo~+Qigb)F`i$_)0Od*!)Fh!j@O}SH;NqX(W_ zXuuDQVOe2D#{Vp=2FyUpfDa_V4-#MjCO0;45|HI%5n~alD&Bi8R``?uIggts|2IYN z$bXnCVIU7uuFN7~Al86g0cu(WMgt>*{rY*+F4r3Ntml+_<6cF7IuvkwQWTx+Tf=P`GG`X^E#U4UuRlqoyh6xZu5_+@=O zp>u(d?a{ZEGXp-kzfQ|(-z~%?C%0I#tZc{I%d`Hu{`~yw7vF)k0*Nn#&%WC1t8(DO zM#VdfQI2hMOd0G?e*UAdZilh8P*+#*%G!(PxDW1dem3LdKmOg5UB87a-EbiGdw9T- ldtxnfvn(U~7f6ZBkWXptbug@Wvc~593WKv| z%k6C1y7a%@y{-IST^b4JOSdd2sQLP6%4a2}6OHFgj;CcwtlIK7cLVobue;|Ta7fE6 zyS;1E!6gFmrvBaCRf})id<&WCv{uXdA6w7ENgorYM@Zl7-}l?iM>9s|gTglLr9zyu zH5^T*&;Q)vomuqCN_|6sY=2{lxp{(N2ZS+nEb2uRdt2VL5Yh zVe6LJdpi8CuZ{Vy!`sjoXsOV>Ue0amFJ9?O`x_q2&-MChm@Xl>G+CYF-A#7Q3s=l0 zM*sHWX1~Z=DV8V3q}*^!ls$I=+cwt;8`dpZ%U8;xtzGdkyhXWPj*p+VMPJJn}t7YD|gr4-TyBf2Q z)r)aY{?CZG?<|S$z8+g3?V=ZD6}fQphA-PrKgiLJ?E0PcU{N?{<-xnZTiRZyX%?^B zAF~?r2Fvin^NXw@-;`SydwXVAD%g_-Q_Rw1 z;(a|_{P7#*yu%Ck>K|5`%h#9QTd_0XG)L3wH4`Sfwn@}*ech#$?)^6Yz@*LWY$?lc z2@3zXyI{qilOL9TTsq;W@U5ThV%IFrD4Cl(ZO%$wRW@&P`w}zj#~}&~#*;a9+~#Gr zHQ#u7z$uzVjQ3I7{BZv5VLS33MBJ#jx8`FIyXVrA)AQ9lO$$XV1ntUdZZa`5GB7Sq zHb^w!2gb3iFeBrC7FGjhAZ5S@65t03umF=B8#ocj^0A1qi1eJ`Ul_WfrMmav%%0Ew z5?lG38}be0LCTd`Bn-qFuq!}KufS+vWSF|qkzXL**UU@)e_i>>#49ht7Q{$?u`8JU zPidjeX`5@0)wa2@p3^zxbuznPiOly7kNK;knoN%emfx?^^w`1Wp=bBHDz*O3>F)No zZ`PZx4|=TOzEE;G`@E~y-c)W=HJWvvW5(wdDIwe*1urkTMhHJ>wLD!P6Lg~SV?R^x z1@8ELz{|iqRrvqC&P`vzIm7?FLUTl&*S#*TvSicpuZNv20tD7hJ>vraaY$-h literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist index bfe6b2cb..0f63cc19 100644 --- a/OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist +++ b/OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist @@ -6,7 +6,7 @@ MajorTestName AST2 MinorTestName - PositiveTest + NegativeTest Policies PolicyIdentifier @@ -14,29 +14,25 @@ Properties SecPolicyName - idiagnostics-uat.apple.com + p04-fmip.icloud.com Leaf - ast2 + fmip Intermediates - TestAppleServerAuthentication + AppleServerAuthentication Anchors - TestAppleRootCA + AppleRootCA VerifyDate - 2015-12-16T00:19:45Z + 2016-04-18T19:00:00Z ExpectedResult - 4 - ChainLength - 3 - EnableTestCertificates - AppleServerAuthenticationAllowUATAST2 + 5 MajorTestName AST2 MinorTestName - NegativeTest + PositiveTest Policies PolicyIdentifier @@ -56,7 +52,11 @@ VerifyDate 2015-12-16T00:19:45Z ExpectedResult - 5 + 4 + ChainLength + 3 + EnableTestCertificates + AppleServerAuthenticationAllowUATAST2 MajorTestName @@ -100,17 +100,17 @@ Properties SecPolicyName - p04-escrowproxy.icloud.com + p04-fmip.icloud.com Leaf - escrow + fmip Intermediates AppleServerAuthentication Anchors AppleRootCA VerifyDate - 2016-01-14T00:16:53Z + 2017-02-14T00:16:53Z ExpectedResult 5 @@ -156,11 +156,11 @@ Properties SecPolicyName - p04-fmip.icloud.com + p04-escrowproxy.icloud.com Leaf - fmip + escrowproxy Intermediates AppleServerAuthentication Anchors @@ -472,36 +472,6 @@ ExpectedResult 5 - - MajorTestName - AppleSSLPinned - MinorTestName - NegativeTest-TestHierarchy - Policies - - PolicyIdentifier - 1.2.840.113635.100.1.63 - Properties - - SecPolicyPolicyName - TestAST2ServerAuth - SecPolicyLeafMarkerOid - 1.2.840.113635.100.6.27.8.2 - SecPolicyName - idiagnostics-uat.apple.com - - - Leaf - ast2 - Intermediates - TestAppleServerAuthentication - Anchors - TestAppleRootCA - VerifyDate - 2016-02-12T17:56:50Z - ExpectedResult - 5 - MajorTestName AppleSSLPinned @@ -1026,7 +996,7 @@ MajorTestName iPhoneApplicationSigning MinorTestName - PositiveTest-vpn + NegativeTest-vpn Policies PolicyIdentifier @@ -1041,9 +1011,7 @@ VerifyDate 2008-03-26T17:07:46Z ExpectedResult - 4 - ChainLength - 3 + 5 MajorTestName @@ -1294,7 +1262,7 @@ Leaf - ids + ids_qa Intermediates AppleServerAuthentication Anchors @@ -1308,6 +1276,35 @@ EnableTestCertificates AppleServerAuthenticationAllowUATIDS + + MajorTestName + LegacyAPN + MinorTestName + NegativeTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.70 + Properties + + SecPolicyName + courier.push.apple.com + + + Leaf + apn_legacy + Intermediates + + EntrustCAL1C + EntrustRootCA + + VerifyDate + 2015-05-11T19:00:00Z + ExpectedResult + 5 + ChainLength + 3 + MajorTestName IPSec @@ -1700,27 +1697,6 @@ ExpectedResult 5 - - MajorTestName - AppleIDAuthority - MinorTestName - PositiveTest - Policies - - PolicyIdentifier - 1.2.840.113635.100.1.18 - - Leaf - appleid_authority - Intermediates - AppleApplicationIntegrationCA - Anchors - AppleRootCA - VerifyDate - 2011-09-01T19:00:00Z - ExpectedResult - 4 - MajorTestName AppleIDAuthority @@ -2047,9 +2023,9 @@ MajorTestName - EscrowProxyCompatibility + EscrowProxy MinorTestName - NegativeTest + PositiveTest Policies PolicyIdentifier @@ -2067,7 +2043,7 @@ Anchors GeoTrustGlobalCA ExpectedResult - 5 + 4 VerifyDate 2016-10-04T19:00:00Z @@ -2130,7 +2106,7 @@ MajorTestName MMCSCompatibility MinorTestName - NegativeTest + PositiveTest Policies PolicyIdentifier @@ -2148,9 +2124,11 @@ Anchors GeoTrustGlobalCA ExpectedResult - 5 + 4 VerifyDate 2016-10-04T19:00:00Z + ChainLength + 3 MajorTestName @@ -2214,26 +2192,7 @@ Anchors TestAppleRootCA ExpectedResult - 5 - - - MajorTestName - LASecureStaticIOAssets - MinorTestName - NegativeTest - Policies - - PolicyIdentifier - 1.2.840.113635.100.1.75 - - Leaf - LASecureIOStaticAssetSigningTest - Intermediates - TestAppleSystemIntegration2CA - Anchors - TestAppleRootCA - ExpectedResult - 5 + 4 EnableTestCertificates AllowAppleTestCertificatesSecureIOStaticAsset @@ -2385,5 +2344,517 @@ VerifyDate 2016-01-01T21:00:00Z + + MajorTestName + Systemwide-Baseline + MinorTestName + IDS-Prod + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + openmarket.ess.apple.com + + + Leaf + ids_prod + Intermediates + AppleServerAuthentication + Anchors + AppleRootCA + ExpectedResult + 4 + ChainLength + 3 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide-Baseline + MinorTestName + IDS-Symantec + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + openmarket.ess.apple.com + + + Leaf + ids_symantec + Intermediates + SymantecClass3SSCAG4 + Anchors + VeriSignClass3PublicPrimaryCertificationAuthorityG5 + ExpectedResult + 4 + ChainLength + 3 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide-Hostname + MinorTestName + IDS-PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + profile.ess.apple.com + + + Leaf + ids_prod + Intermediates + AppleServerAuthentication + Anchors + AppleRootCA + ExpectedResult + 4 + ChainLength + 3 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide-Hostname + MinorTestName + IDS-NegativeTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + profile.ess.apple.com + + + Leaf + ids_symantec + Intermediates + SymantecClass3SSCAG4 + Anchors + VeriSignClass3PublicPrimaryCertificationAuthorityG5 + ExpectedResult + 5 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide-PolicyName + MinorTestName + IDS-PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + openmarket.ess.apple.com + SecPolicyPolicyName + IDS + + + Leaf + ids_prod + Intermediates + AppleServerAuthentication + Anchors + AppleRootCA + ExpectedResult + 4 + ChainLength + 3 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide-PolicyName + MinorTestName + IDS-NegativeTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + openmarket.ess.apple.com + SecPolicyPolicyName + IDS + + + Leaf + ids_symantec + Intermediates + SymantecClass3SSCAG4 + Anchors + VeriSignClass3PublicPrimaryCertificationAuthorityG5 + ExpectedResult + 5 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide-Both + MinorTestName + IDS-PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + profile.ess.apple.com + SecPolicyPolicyName + IDS + + + Leaf + ids_prod + Intermediates + AppleServerAuthentication + Anchors + AppleRootCA + ExpectedResult + 4 + ChainLength + 3 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide-Both + MinorTestName + IDS-NegativeTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + profile.ess.apple.com + SecPolicyPolicyName + IDS + + + Leaf + ids_symantec + Intermediates + SymantecClass3SSCAG4 + Anchors + VeriSignClass3PublicPrimaryCertificationAuthorityG5 + ExpectedResult + 5 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide + MinorTestName + IDSBag-NegativeTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.67 + Properties + + SecPolicyName + profile.ess.apple.com + + + Leaf + ids_symantec + Intermediates + SymantecClass3SSCAG4 + Anchors + VeriSignClass3PublicPrimaryCertificationAuthorityG5 + ExpectedResult + 5 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + Systemwide + MinorTestName + IDSBag-PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.67 + Properties + + SecPolicyName + init.ess.apple.com + + + Leaf + ids_symantec + Intermediates + SymantecClass3SSCAG4 + Anchors + VeriSignClass3PublicPrimaryCertificationAuthorityG5 + ExpectedResult + 4 + VerifyDate + 2017-02-08T21:00:00Z + + + MajorTestName + PPQSigning + MinorTestName + PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.35 + + Leaf + ppq_signing + Intermediates + AppleSystemIntegration2CA + Anchors + AppleRootCA + VerifyDate + 2017-02-18T00:19:45Z + ExpectedResult + 4 + ChainLength + 3 + + + MajorTestName + Systemwide + MinorTestName + ckdatabasews-PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.3 + Properties + + SecPolicyName + p62-ckdatabasews.icloud.com + + + Leaf + wildcard_icloud + Intermediates + AppleISTCA2G1 + Anchors + GeoTrustGlobalCA + ExpectedResult + 4 + VerifyDate + 2017-02-20T21:00:00Z + + + MajorTestName + PCSEscrowService + MinorTestName + NegativeTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.34 + + Leaf + escrow_service_key_9B6EEF8D + Intermediates + EscrowServiceRootCA100 + Anchors + EscrowServiceRootCA100 + ExpectedResult + 5 + + + MajorTestName + EscrowService + MinorTestName + NegativeTest-v1 + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.24 + + Leaf + escrow_service_key_B157A8D4 + Intermediates + EscrowServiceRootCA0 + Anchors + EscrowServiceRootCA0 + ExpectedResult + 5 + + + MajorTestName + EscrowService + MinorTestName + NegativeTest-v2 + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.24 + + Leaf + escrow_service_key_049F9D11 + Intermediates + EscrowServiceRootCA101 + Anchors + EscrowServiceRootCA101 + ExpectedResult + 5 + + + MajorTestName + PCSEscrowService + MinorTestName + PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.24 + + Leaf + escrow_service_key_9B6EEF8D + Intermediates + EscrowServiceRootCA100 + Anchors + EscrowServiceRootCA100 + ExpectedResult + 4 + ChainLength + 2 + + + MajorTestName + macOSProfileSigning + MinorTestName + NegativeTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.81 + + Leaf + iphone_developer + Intermediates + AppleWWDR-expired + Anchors + AppleRootCA + VerifyDate + 2015-06-16T19:00:00Z + ExpectedResult + 5 + + + MajorTestName + macOSProfileSigning + MinorTestName + PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.81 + + Leaf + developer_id + Intermediates + DeveloperIDCA + Anchors + AppleRootCA + ExpectedResult + 4 + ChainLength + 3 + + + MajorTestName + macOSProfileSigning + MinorTestName + PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.81 + + Leaf + mac_developer + Intermediates + AppleWWDR-expired + Anchors + AppleRootCA + ExpectedResult + 4 + ChainLength + 3 + + + MajorTestName + iPhoneVPNApplicationSigning + MinorTestName + PositiveTest + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.86 + + Leaf + ios_vpn_app_signing + Intermediates + AppleiPhoneCA + Anchors + AppleRootCA + VerifyDate + 2008-03-26T17:07:46Z + ExpectedResult + 4 + ChainLength + 3 + + + MajorTestName + iPhoneVPNApplicationSigning + MinorTestName + Negative + Policies + + PolicyIdentifier + 1.2.840.113635.100.1.86 + + Leaf + ios_app_signing + Intermediates + AppleiPhoneCA + Anchors + AppleRootCA + VerifyDate + 2008-03-26T17:07:46Z + ExpectedResult + 5 + diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/SymantecClass3SSCAG4.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/SymantecClass3SSCAG4.cer new file mode 100644 index 0000000000000000000000000000000000000000..797febd7e4d6f9ea1436146f31dfaee3870715ab GIT binary patch literal 1340 zcmXqLVzn@6Vo_MY%*4pVBoJu7v&5ocyNQEiufb%tng0!V**LY@JlekVGBR?rG8iR&pN4RQlsyFFwZ@wF)UcZUCYEH1~OAmQB{}XdHf9$Ia z`}Y0sO{cjzWh|*qpgGt*S*)N{NM8UA$W+BXKf6Utoi=?3S(PUe{enTJvsm zHDk&9Ow-q=uG+4AH+{yb-c>Gqsx!Srr!6^`%M>E7m8JHG%_`Yr%@&`FrIQ2x3+rFI z_3)U)*ZC(^V?Q%k-Ba`3qRDxd-&Q$a%&SrC_orro!#l3s2sN_(xR-x#Pta5^vFTMo zipiz=Vn2_h?fbfw^TvO5hO;g;`QG*$zB4g1GB7S~VoU~xNW6g%FmPps85#exa2T)w zDJDh+0|StlJd37*x`FBfh0S4MU-gCGMnm|iAEF)66t^73+!W>6{zyCu1x*gylWj>$kq3YW^FfFGB2uooB-k!RKx~9e^;Or>N$0Eie5}$BBaYE?*7H5&J z1g%Y9tG+l(ya)OVXp%CEgn?LtNd4v1<%jOR+5N$Q^Ru(%FQ)azhQ`PV5m*oa6Cxu+ z+>|iSyM4N;Uk{oEZexCYYhJPBC;7%lm@9p=mG4f?q$^KQnH6w&G~rzY83XR3kVFGoGDY z^i1TQUyzFK-=~$r!O!FLb$z9C9Ylk)zqfZ*2sP&2^j)P}apjPXEk}I&#Ch_38}1nd zrL=XfnwvIsC%f_kI=F#?@mywZ`mBFB~!I0a4lZ`o)g-w_#G}uts zKoG>?66SI&D9A}w@XSlrGgLEB0SR&o%R&U5Q;SM6(=wA2OEUBG6dX%SGV+TuODYXb z42(ePm_@XsLtKMHVih3DGXpa6^HLRX=rWKK=QS`lFg7wYFf%eRHHZ@DH8L_VHZ+2A z4HAiPp{Ri{#DzS_R>B<4EFz1|K`yCfnaMzRIT|$1M-CT8RtDzAUSQaCGBq|bTu%tn z`ZYP|&h2%RvahX)6qlc+@YZDAA<-9)KUgQX+{o=^N-cSoB%yxsPsL$NB7pA*wr#Iy9F}c!*+=7H}U%5nb&3Nz9|8>m`Cx zgkExfu0EKRoT#5!0E$_?YH1 zot(`oMSst!m?TU!xNeka`1H!vp@ zAiLphhmdz$pUFMGGyA7a)~*|e6+YheJZ-g1^K8)1&z~jY?lv{=c;Poiph`|~L9%aO zf|smok?(>v@*8G!Z!wN)O*miQX_}OJQQBk4n^Or=bC+G*Y5O^4N&3a5(%Wu6Pc1#Y zUcc)0jfG!6bMButQ_5u7TluCI?rkeFV&8aP*=*9X{`8WY3?KHe=ZHU_y8E#0&D~kT svL<`=56=4Nn;su#JYm!O|LV6S6GAss9O^NNPPBUXCUH`?KFh3Q0OEBD}zDf zDMM}pPB!LH7B*p~&|pJx15pr%OPDV#wJ0+ZAHEh*10$~Lqzuz)Bq)JWD;FfuSOQ-G<27@?r6;Fe#ckXTxhkzbTqm71bZTAZqo zpO;f<=xX2$(#tGt1Jk15oRe5wtYEAVP@0sJnXC{{l$o1YRH@*cT2zvmmYJMbl9`{U z;0Q6Rq!MVhyQzVkIIn@3p`n3=0T@Jy^BS8Om>ZfI8Jk*~T1E{o&o(hCAx9=7D+6;A zBR_*d6C)Q>6C)$TdKC^1%_`G*2|TNwdt3Y6so7)WDzjVr!9Pu=pWz&fQ(8sUzkXbM z!mu+|>4ny+Wlo#>f9wq1zHz(v=70Tl?BQ?TJKs)A5=}gxz`Nwey&n$_Cvn(@2*36` z6&cd1_EfuHdj9LL3nv~j_PpVooE7AKssBYmpzp=b%-!|V7D!E-9>m7D^+J4dU zg&V#sQvI}EW>UJu(=Ti+?OuN3=ynE37+PwSCm+Najefwa${%+|+ zV@X*Vhtnl0l8TdWiu_xn6?DA+DvRfn-emUZfO>87Laa8?dvn zYV$EONwJ9ZKfNr~wx+i)`|$aOtScT8I@OYT2C8Dp86_nJR{Hum`RVz3WxzaC49r7% z$@#hZWyN4IkV&AdB+JJl#v)RGId%D=yKi=XFyQ>`Z2606y|JM&aE$6CEUW{y6yd{%yxq52h)cJewkF(RgyoyG1RU z+`{>Nw|VZWGTmO%E$MQ}v5Ga*E5bkFR9#aRH`6Lram%f@>z}uzYEA9h+jcLmQLI^4 z;LN?hE1I-&HRO4@k34-Yr6&3Ci(tOM)~SD+*A#(ax4;xJwkvQ5H1Bj%HnSF1%xbNs~@I-k}E KUR&`tIST-5H^c1! literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/apn_legacy.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/apn_legacy.cer new file mode 100644 index 0000000000000000000000000000000000000000..b223c4b11c1af078015aefaa8ccd34467074eeab GIT binary patch literal 1319 zcmXqLVpTS1V&PuE%*4pV#NwlP-^75IjZ>@5qwPB{BO@y-gF)j)Lv903Hs(+kHesgF zU_&tj5fFzJSuFtAiWHCxX>2c&>mSQRR+ z;G9}il9`s7oLG{XpQqqhT9T1plvz@#psV0x=xiV-&TD95U}$7$U}$P$Y#s&Vnt{1M z($F%>AP3b;!UlpM<2i)6oD*|0)AEb*G7}Aj3 zmbM3qTr$6T{6W(3;sm{Ti~1u{5ihv6UZ~vq{Fai)$Avo{XlSgAa5l{4igz{Q-!@md za^j*5ORDm}e37VD`sX(7xz+y7tGzWh@-4VhVs^+}!n^apoFgHx%@eo9HdsS0~IYEDYzs0;r3*PB)(cCh#@W_Pt^>W{x!UiWb+aW~_ySW` z%FG{y0&EXYI711$rM1!@aa+LSU%N(!v>^^=QoP?BIyYFTQIVX_`j+#m&J03#zygh7~r zGK_D)*d`9upPyV@fNX$)K3ow~n=({UVrC+;8hs-J6AN9iEvZEYULdC_us9ny8kj;d z)VEr8Zzcl`12vdYOpIbuP@}M983PVBw)93GV74?+1eqnsB4r@age#57gOn(V}RqFg7qgO|gW?BlmO+N_E z;IhIjOa=_dNfns?fk~B-fhlNT+0ORdfKOcZuX8Rvi23&a#e+G;9II7#+!0XJ`!d(# z$=~A~P4)_F8bm5m9$!*BV&Cr{dq@11d5FWK=-DMMf7sNYefG7!E@)y_dh+MZikOTO zvmdQ8j-Hs`Y`!?R2mdqfljIEpMW?2=Ypp1G<(NV?<1kLCJn zzyDsQ!~Fa}ZkiYSi71CnC8uAsu&ysFWR0EI;>k84_4W6f*BY{txg4zfI2F74(@&Sw z&GM4633!=OZ`?X#ZXWYTrGW2C4xL*qyu<01dsgS)YuXP}w)@T0UA5ZsaNU&oamjP$ eoDAHp%9D0w2A|H-v-i1Hg-U-}9aJlES`Yx~`n>o6 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_049F9D11.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_049F9D11.cer new file mode 100644 index 0000000000000000000000000000000000000000..b6ee02583aa0a098fb7681edeec8415129f3864d GIT binary patch literal 1034 zcmXqLVqr6AVtTiLnTe5!iG^kUTtNd~HcqWJkGAi;jEvl@3XFjHu-p|F77X7iE@I8p<2Ug48h!i@6pj7v+~L1g932WhSR81m)+KC^$PB$cghBni`lI zni-fHSr{2b0lDT#T!Y5hsIGxJjYF8p*%7mx2l?nzX zmTs0VhK8<|t_GHd29{1vW(HO9F~l%49rc8{0u;GE~X|%Muuy4%C{~|Ztvc2F?ZVe2hDHqn3@>= zEsZ<>ZT6;#28%Mx@{Wez`tmow-!pBJ*ROw?oaI+D5+i$O#j2VKoO`}pcJ*e4Yz`^z z4au*b$;}V*3VS*sE#O+Y;?JEr0=o*kj)?I8EYm%G<^YqD*}mq0Qtd}6Q;joPc6r6zhl?XmU7yCPxbs;lOVf|#eFkj%o>?;JE@ru6!_de3>AKg(N}eOJ z$~AWU3$p|heuXq%TwjvdER&>c^z6%V-aEa&S0;1$|u-ZpzGtFoL@6XOM zkOwJOW|1%uYY^!vIWFpNCO?4wF896EKOBX`ZgDUnlYGQG?nZ=eX4p_pbQAz2X$QPU`&E zW10)yOw2o+Rho?$9={b-u~~e3+N-&@1@_$dV6M`C$2?2@83H`m{G4D@G5<*H7d5Z$oBC2b4e+!;sA^NSC?Yx@#Z>#eP-$tN}4N&R|yY9fEX; R8n3Uctej(Q literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_9B6EEF8D.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_9B6EEF8D.cer new file mode 100644 index 0000000000000000000000000000000000000000..bce94cb54c04c2a4392e29cc99d8df0efa5f0b3a GIT binary patch literal 1035 zcmXqLVqrIEVtT)TnTe5!iIrh?-uqqyUN%mxHjlRNyo`+8tPBQ~hCBvbY|No7tisHO z1_p-Q2Am)sn=n&ou%WPlAc(^y%;i{6kdvz5nU}0*sAix7666+^g$O#Q7L{bCWhN(< zWaj57IF^=V1=FjZf<1iXy$C{X5wn<>}+OW z?r7vW(|LQiv)5bmL_QipIa8Z);{2tl$_4vbt)Z8eHL3iJht-u z)?kDE)vwAGRsK%&$xoPH@$+rV(|4=ckD9D}#P#*-ue8z=c608&O8C&sEXlE?b;IY4 zAFFJ)oVcqRCH-|l#n0Uw>iH{wioZC`xH#%U`tR-Ux5p?<5s!7-d+Fb{jE?!sxTo{$ z2`C56%k2Kr(99Rj^2cwXkxN&yoi%rX=oRsU`*t&$zxW-|ZTsekd(%@UW=00a#l;4N z20Xx6kQHWR{LjK{+nr^HBiSt8R@(IkNCyB@C>J*;*6lz4~gmNp!$1JM$H4 zUvHNk@$%q2&%!01(`%C_=lJKn>)xWsIDtgJwR}&?Y`(X@54oH8aw30S(6xC?*SDQn zGOu=5{1%6k&!#4>+u6BGReIY!j{1)GHIcr>$G@^q5w89-zm!)h^FyGSoLkumb-&bz zG{?BP|2_&_wTXUpcAB|wSx3Te`%P60TOMrNS(eAN?R#&xRm?rVol97ci7d0v+57h$ z_tzNpu%jNK6-9SWP2JA4>5kvtM-}a7wr;3V3OcwUigWI^eb2oY@hLcKly}HqTe36k U!i8o0i{I;Qmvu<|u~Xa!0QKQ|IsgCw literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_B157A8D4.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/escrow_service_key_B157A8D4.cer new file mode 100644 index 0000000000000000000000000000000000000000..eadbb028ceadec899fe420dfa5916f5289d620ed GIT binary patch literal 1033 zcmXqLVqrCCVtTuPnTe5!iIw5XitvpFylk9WZ60mkc^MhGSs4t<4Y>?B*qB3EScMr4 z47m+BL2Nc*rqEzRVFN)BhfA2tv7jI)RlzeaSkPAtjH z&r@(LEy>6)$}FiglsAwCsbdxvb1hCT$}d+4PAw|SOion@%Fi!RaCS716X!KFHZU_X zH!?CdGBS?>a!rxA292{(T?2I*hcJ_~BX+0p7;r(H#_SprY#3t@1#v(ynghI3D;1m! zP0bxGTue+1j7>}|4J}P9EX>UfoXy>wO`I&9jV&xpTuscK&0HN_99>K;jm(VAE!>Qp zObrdq4P2dE4V(>{7?qGil982xxrvdV0VvMJ)Wpcha7k^}lYKnbR(@-^;<7jNw_LD8 z{gRBkAMWYdKTxT?E68`=I40wkR{gC%SC*dswDwlY)wn;Ie^;E(P5ZdYbkgIi+G}`9 zst+)WALUy-X>Yf~uyTbNhTGT!ZyX8~f?fP#b$n7M5urZ5v14V)>AbtKFgBUrn94&~Rng)hfY`ivE%+pWRhIRxI5w8KIfF zP4>K@3 zg$6vpSdbNFWc<&nBFo1j#v*cC{@u;9OP-yccWP(L_QyFB zDyRQqHIN4>S7wng5Ni;rD&Bi8R``?uIggts|2IYN$bXnC0ZgG>;MAO)!Y0lLG?I}4 zIa+`T92hN(47_c*zeA&DEPG?IQfjG)?Zz3Lt$!y-tb1_g@t!lcUPgO=n_+tFZuXp| z-9B$aa=0D^JU02jul&lN!Kf|8ENN5kH>w5cNcO7i;Wo>jlI9J(stAveBu=X+Jm z-lK7Uo4B}-Nv!)3(Wr$#Seo;gZ4nmXV`ySv1aX9R zWp z7q{0vOP%=b{I&Q;U!RmJEm?k+&uj8tHOU2`VG;YAHXqOYIGg*$viD0`Pm7B#%$>iY z?oGXGyBb%kQDL-a(xhq2)St*1bG;Td+-%q}vsnGBoVM}bmck8JT0U~ScxE|XJiO3X zV)<^H_YKE1L@M=iW?mP#De(2l$4TwNilNJ8CM?`tzW3b`5z~LO@BLPPIQ6PX^tpb) zgG~~0Chie?3vHif-g~X{EXJ++Vt~SM6CDIp_iacrmkf=ze20&Y}j?R>sr;`L_1Eo%xz6Kv1?(Am-;E4h@nf8lzS zne&;L85tNCH!*$$hR9n3Szy@8^0A1qh)j?VUoXD(&G~oyw`I)cEPgDyt7@wO4@g>= zk?}tZlK}%bB4m|WBn-qFL^{;PIah9zNa%j^de=Ai$fH3ai?;(!_6iPBOixraLNitO- zsZt>^uTr5Pv8V*dDlRU~O)XYPOioTMD1qon1L{cy;XH*zV2%MMBo?J8 z0FziQP(xmdLUMjyN+vjmDCDOploqGzpjcFp57Y~?45$)rKQKQj6ci;Umt+E+2Q;%J zH8(Y{q*%{D6YdE{G1-igk^(Dz{qpj1J&+Sp^^)^*^}(#O@#(1R9-El$@xST$E$L2QrQy6d^3kOzaH?Vj#XMh|god1#=ZM zvw<)h7r2~BPGMtY0>>Y)v_UO=fZ2kPVV=&eeu-x+E0|5chpFuRqp8&9^s(_=(=16J z-VJ`wYA&*^et$Vy{QlaOMU%y<03rm#p?OiqU@f98cG%{d1@7EQhG zp^^7=u|meKdoMaB|59L;eaH9JzUkA6X9uPQ?6R9TSH$;1an0SZZ=Q2bZJZ$&|L*bW z-QVYW7(B_%|MOz6#x_+>$NFmXeQeF_=OX9InaZZMud7P^T{ipt^^e|3OD$4xEG@}M%`3@FPAtjH&r@)AG*mE<11aR@5qC~4D#=WPNr6=6 z7iE@I8VVZ-f>dzva6ydn%uCiYL6D)0ffU3!!iA-&MU{G~#l?DwAcyHC=jR#<81O;d!0zc1tPmXJN`#$Fj7rG9 zW@KexZerwTFlb`rVrpV!WH`m=*|N6r*2&o$-c%=_eAlweFlOuGzW<@u&w3^bZsG}2 zyX}#=8jKqW=Z)i=U??=fu!C83B5xR zS1k=T{+-@aI#FSl!)YbOsmm6ds~wV^9{fCWV&$>dW+j)Oi>7@#o3*_;^-TD=nT0d- zc7@N5H`}e#u_hty-BhP-88G))h?g9<$~YL zgo+8T4{Z9YC9rGxbgL|x6YiJH>ztKOaqX=5TH9vNeq(8I%(~)2g9~Q@&R=Vc|6NoT zDeTX@V7^$N%j;blYFX0)_`k)wJTv|2-w<<=iJ6gsad8vlBw&d28OQ>|SC)@Oj76ku zY3O8=xb^Dw&#ng^XxAz`d*WBP0S`!8n33^63zGqZfjo$(%pzeR)*zyDG&kt3;rpI9 z9F1@9-#O*X;L3Qxzy_p1p2ZXx$A$~^7wEQWXOxr_Sn2C07v&(LRUaI|#o&aO2uw}M ziH3SW1>m@r7A5FD*b56w6EjCHWGxRM#YtUyz!Yn^=^cT7srSw4f+IEfbhHQIcts zR8eYrW^qXoIPajzNhGGH1Emv7@{3SqfSHFIoHdhE*rZvQSeSs>6E(L2(=8)|EJx9` z>HD8#-H$YMp;sduX1_&Su4#*K0ZpY@fMGt;yk%Ve2}3 zLG#4yr}vob_HwtsTOXHcEC1{9`gz`mV|O3aRp&H`I($U+n1EFFo|cu-&uh0#`F?xl z;opM2&&_0A7?2~ZPP7~b7%B7`IYNdbYtatVf!yyY_DF=|jikQ+g&lmHeNU{&tc) z-B;$EQ{p&h&InsIrI9`~Qa4NH_9V7d;D@+H&5pLJno|WIc!`dgeUJW7@_KrY*MX4Z z(}Tt)O;Mf9p3^2WRTl287arAhK$JdFVyWSB zrVh0TXDRnL*7N+PHXIo`ip?IL>Ih_JTmT6*W0%R);+Ku-}8(Y8O%WIHYKn-0vIvhI1F^t@6)& zV$c4i^hQKKw;mzE5PVXFJOnCa6c`dJvUN~Ge$~H}R2z-WL=gZ1hI+abhUZX}gpkYU zeZ{sy^#F^aVM~F@$v8oW@rvQ+$Kx zz*Y?~MJ<6jz{*X^jk65Zj07R!mVX$DAW|j)!5>Ls81)1m#O(`Z0XU2K`MIchmn~le zApdi*f^eOZLM0SJ;XBC)il8c3LJTn+4JANBPuaF9be}3LC%ryhEKRk`FNFtp9?Dy% z)6v&Fak&?Q;J^xRw5>w{r_^xQp-2XRKXUo~2n@R)tx zcnyLv8uB`&?iZ|MJe!S6qtCQu*mj-1HKQuYZWjcE-MbbDB|@iKH482ngs={_F)MpT zQtDc#V)TvCNXvLqAL9o7H|+)5r}MOKU^8L{m3G)pIzK3O`71T!;`*(f8HKSax}qI! z*#>KUljSZm4hWXY$=B7QTir=zFuwWonC`asqQ(nz8lHXASlLX|Hlrz`T=8`AYttyz zWtZH^RvWh0>|VcJqN4+@{Z!G}HXomN9Sgj-{wa6w!SBc_tEm;fJ<98a-Q706`e|iH zc1Lk+u9(07ewaUsV46_dwZLaDYVL{oW+AogX#cU7P5c(PjZMSO1&orzKkWoW|0FsA z4B2~b$~64hiIEqUH$1F&qN~d)-%vjH${att#$X~to^MgCWaVTI*MoFsjxn%aPl^f58wx*JHYtJn|2Bf49r3LBp$3u`SHibUK*w z;bpShF>e=)ff??2oJL(yiOF{Lg|--UUfiI#f0LfkFmlIrs90)gf8|J(wz2hD+6GGM z{gD~#;aDsvEnC^{jr0suzx;LgRl@`0#s(30JD&}zzUDoty%jZz&A3Z84e09PgAMw6 z6%k)9DJ^R`cTXJ9w%YZb#hFL@_D{rKqD|D=aIX0jh*@UJ*1UB;yf(^tNZMT&RAVyy EHyy!3{{R30 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/ppq_signing.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/ppq_signing.cer new file mode 100644 index 0000000000000000000000000000000000000000..f62ff92530d0b4d8a44ba9d813213518d67aa695 GIT binary patch literal 1036 zcmXqLV&O1oV*0RvnTe5!i9>ehrXEYV-yaQl**LY@JlekVGBR?rG8ijN`vb&FDq3-a@dQ}q%-uGUM=&ovY<;Db1Z-8sJ~Rlz^l zkg&B)j7rF1!pO?N+{DPwV9>7iwwdjiTu@?L0^qzgT zw7=<5p(d9>;Ae|j!aI(9c=I9h{?_6NcNbllGf^}6zxQX6FAEO3pH~Q#cj69ywCxak zZH|#s^3#10n!ch&PlF$}_UN}IQV7x zSj1RFex2)HxMzlv!aSA-b!>g6g?XMP(gr-hz?T(fWc<&FXyKcOEX+*o4Fjv@#dJH9-TYZhwT)EbN{JMIP(p7~WPN(yX#8uXJ z+{$m9GsSt%?YH@%MlO@gc4hM4vM{)5VljV{ccI^T=bo(^+P{J>eG;oFVYJft`Ym$P zk9*bm6(@V+b6zC_IVc!xE}Oedu@7Guzn!z zu%bhT$izg2&X0kLWTJ6%Bs0opgw18*f-E{lx(yiHvN<3SHDSF9r2O}L-jBS`J@5M* zaEkT-CsOJb!VnAxir)DC)ThBh~l$BXjm3y<>)e+Bskj4V3{_~V7Ahn9Y?`3zCwaZ=K2{@g9m{n zd{B(S1=~SXSTLRfba)z`oSc$`zvG2zAPG;OgTRJ|0@TMrDphM}(rC8nHKf^uuLLUJ zaA|~zV2E9(WHRXq}1dE22y_pbF>1bk}SeVmzk{$O)RG6gkt>F zfJ6eJ6Osvl6OzDA2oih|zxix&-+ee-`(a53Jt9+WK3RCEwh8Y1VRA$0^*a~smsjYX zi+wcn1RZV$z-W`DQ6 z`qkuyOLv%cm>E22gZvbkthIykk>#4NT0_5awQlz&XS?knn~88 zA^0oe*XM&EInfuOS&k%hrDfs{|9 z5HyRxKmek7q(YVhMYVizPgC~321|pY<>#=|P`1!Dpk4(WvwQ`HIHrMP5;&fUCBE|} z^`amII6S~{ex4`{14pye(UeCSX@Vgs%zMV1fo3ss;j$^L)Q%C19kUQt&ii6nn~7pE zf+Q&m_p+zVm*>C9YlTv;UpUHY@|G}qj5ITPns*0_naeO6OYu>y+3Gidw~ob1kR0uu z&vFFkyJ=PfRxhxG6p3?kR#sN}sp-d(m^Yu+Y9T-xFF-T`fCePE)$TY~>|8%-HTv~0 zT7$-$10j5)j8_^F!Xo#}#jHdWKt4}K2rax|5XP4;LzaRN=OUZ>o5=f1@tOz{tSzIv z;_Hl=o^|BVQvAH;tzPU}#Kiln9<=0!-HNHZe>F!wP*=Z2S5xuc`tG>XyT(^NRN~L0 z=$1#5pI?k(%}-SRN~(^$2<)!U`!_Mkp(r(6DiVJ8 zV7z5yg;TpbYaiH@H%`=s-|9Hl`1QJgyGMi=L=3<9(REZ#2JWwF zHn%l&pRDq{8ykB52U|hl A00000 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-20-sectrust-policies.m b/OSX/shared_regressions/si-20-sectrust-policies.m index bde1ada1..bffb97fd 100644 --- a/OSX/shared_regressions/si-20-sectrust-policies.m +++ b/OSX/shared_regressions/si-20-sectrust-policies.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,6 +24,9 @@ /* INSTRUCTIONS FOR ADDING NEW SUBTESTS: * 1. Add the certificates, as DER-encoded files with the 'cer' extension, to OSX/shared_regressions/si-20-sectrust-policies-data/ + * NOTE: If your cert needs to be named with "(i[Pp]hone|i[Pp]ad|i[Pp]od)", you need to make two copies -- one named properly + * and another named such that it doesn't match that regex. Use the regex trick below for TARGET_OS_TV to make sure your test + * works. * 2. Add a new dictionary to the test plist (OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist). * This dictionary must include: (see constants below) * MajorTestName @@ -38,7 +41,7 @@ /* INSTRUCTIONS FOR DEBUGGING SUBTESTS: * Add a debugging.plist to OSX/shared_regressions/si-20-sectrust-policies-data/ containing only those subtest dictionaries - * you want to debug. Git will ignore this file, so you don't accidentally commit it. + * you want to debug. */ #include "shared_regressions.h" @@ -63,7 +66,7 @@ const NSString *kSecTrustTestAnchors = @"Anchors"; /* Recommend const NSString *kSecTrustTestVerifyDate = @"VerifyDate"; /* Recommended; value: date */ const NSString *kSecTrustTestExpectedResult = @"ExpectedResult"; /* Required; value: number */ const NSString *kSecTrustTestChainLength = @"ChainLength"; /* Optional; value: number */ -const NSString *kSecTrustTestEnableTestCerts= @"EnableTestCertificates"; /* Optiona; value: string */ +const NSString *kSecTrustTestEnableTestCerts= @"EnableTestCertificates"; /* Optional; value: string */ /* Key Constants for Policies Dictionaries */ const NSString *kSecTrustTestPolicyOID = @"PolicyIdentifier"; /* Required; value: string */ @@ -86,6 +89,20 @@ const NSString *kSecTrustTestPinningPolicyResources = @"si-20-sectrust-policies- @end @implementation TestObject +#if TARGET_OS_TV +/* Mastering removes all files named i[Pp]hone, so dynamically replace any i[Pp]hone's with + * iPh0ne. We have two copies in the resources directory. */ +- (NSString *)replaceiPhoneNamedFiles:(NSString *)filename { + NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:@"iphone" + options:NSRegularExpressionCaseInsensitive + error:nil]; + NSString *newfilename = [regularExpression stringByReplacingMatchesInString:filename + options:0 + range:NSMakeRange(0, [filename length]) + withTemplate:@"iPh0ne"]; + return newfilename; +} +#endif - (id)init { self = [super init]; @@ -101,15 +118,20 @@ const NSString *kSecTrustTestPinningPolicyResources = @"si-20-sectrust-policies- - (bool)addLeafToCertificates:(NSString *)leafName { SecCertificateRef cert; - NSString *path = nil; + NSString *path = nil, *filename = nil; require_action_quiet(leafName, errOut, fail("%@: failed to get leaf for test", _fullTestName)); +#if TARGET_OS_TV + filename = [self replaceiPhoneNamedFiles:leafName]; +#else + filename = leafName; +#endif path = [[NSBundle mainBundle] - pathForResource:leafName + pathForResource:filename ofType:@"cer" inDirectory:(NSString *)kSecTrustTestPinningPolicyResources]; - require_action_quiet(path, errOut, fail("%@: failed to get path for leaf", _fullTestName)); + require_action_quiet(path, errOut, fail("%@: failed to get path for leaf %@", _fullTestName, filename)); cert = SecCertificateCreateWithData(NULL, (CFDataRef)[NSData dataWithContentsOfFile:path]); require_action_quiet(cert, errOut, fail("%@: failed to create leaf certificate from path %@", @@ -127,18 +149,23 @@ errOut: - (bool)addCertsToArray:(id)pathsObj outputArray:(NSMutableArray *)outArray { __block SecCertificateRef cert = NULL; - __block NSString* path = nil; + __block NSString* path = nil, *filename = nil; require_action_quiet(pathsObj, errOut, fail("%@: failed to get certificate paths for test", _fullTestName)); if ([pathsObj isKindOfClass:[NSString class]]) { /* Only one cert path */ +#if TARGET_OS_TV + filename = [self replaceiPhoneNamedFiles:pathsObj]; +#else + filename = pathsObj; +#endif path = [[NSBundle mainBundle] - pathForResource:pathsObj + pathForResource:filename ofType:@"cer" inDirectory:(NSString *)kSecTrustTestPinningPolicyResources]; - require_action_quiet(path, errOut, fail("%@: failed to get path for cert", - _fullTestName)); + require_action_quiet(path, errOut, fail("%@: failed to get path for cert %@", + _fullTestName, filename)); cert = SecCertificateCreateWithData(NULL, (CFDataRef)[NSData dataWithContentsOfFile:path]); require_action_quiet(cert, errOut, fail("%@: failed to create certificate from path %@", @@ -150,13 +177,18 @@ errOut: else if ([pathsObj isKindOfClass:[NSArray class]]) { /* Test has more than one intermediate */ [(NSArray *)pathsObj enumerateObjectsUsingBlock:^(NSString *resource, NSUInteger idx, BOOL *stop) { +#if TARGET_OS_TV + filename = [self replaceiPhoneNamedFiles:resource]; +#else + filename = resource; +#endif path = [[NSBundle mainBundle] - pathForResource:resource + pathForResource:filename ofType:@"cer" inDirectory:(NSString *)kSecTrustTestPinningPolicyResources]; require_action_quiet(path, blockOut, - fail("%@: failed to get path for cert %ld", - self->_fullTestName, (unsigned long)idx)); + fail("%@: failed to get path for cert %ld, %@", + self->_fullTestName, (unsigned long)idx, filename)); cert = SecCertificateCreateWithData(NULL, (CFDataRef)[NSData dataWithContentsOfFile:path]); require_action_quiet(cert, blockOut, fail("%@: failed to create certificate %ld from path %@", @@ -302,6 +334,8 @@ void (^runTestForObject)(id, NSUInteger, BOOL *) = NSDate *verifyDate = nil; NSNumber *expectedResult = nil, *chainLen = nil; + /* Test certificates work by default on internal builds. We still need this to + * determine whether to expect failure for production devices. */ bool enableTestCertificates = (bool)[testDict objectForKey:kSecTrustTestEnableTestCerts]; /* Test name, for documentation purposes */ @@ -316,16 +350,6 @@ void (^runTestForObject)(id, NSUInteger, BOOL *) = require_quiet([test addLeafToCertificates:[testDict objectForKey:kSecTrustTestLeaf]], testOut); require_quiet([test addIntermediatesToCertificates:[testDict objectForKey:kSecTrustTestIntermediates]], testOut); - /* Optionally: enable test certificates for the policy */ - if (enableTestCertificates) { - /* Note: Some of the policies use defaults writes with the "com.apple.Security" domain; - * others use "com.apple.security". Set both since we don't know which one this is. */ - CFPreferencesSetAppValue((__bridge CFStringRef)[testDict objectForKey:kSecTrustTestEnableTestCerts], - kCFBooleanTrue, CFSTR("com.apple.Security")); - CFPreferencesSetAppValue((__bridge CFStringRef)[testDict objectForKey:kSecTrustTestEnableTestCerts], - kCFBooleanTrue, CFSTR("com.apple.security")); - } - /* Create the policies */ require_quiet([test addPolicies:[testDict objectForKey:kSecTrustTestPolicies]], testOut); @@ -378,13 +402,6 @@ void (^runTestForObject)(id, NSUInteger, BOOL *) = test.fullTestName, SecTrustGetCertificateCount(trust), [chainLen longValue])); testOut: - // Unset preferences to prevent contamination - if (enableTestCertificates) { - CFPreferencesSetAppValue((__bridge CFStringRef)[testDict objectForKey:kSecTrustTestEnableTestCerts], - kCFBooleanFalse, CFSTR("com.apple.security")); - CFPreferencesSetAppValue((__bridge CFStringRef)[testDict objectForKey:kSecTrustTestEnableTestCerts], - kCFBooleanFalse, CFSTR("com.apple.Security")); - } CFReleaseNull(trust); }; diff --git a/OSX/shared_regressions/si-44-seckey-aks.m b/OSX/shared_regressions/si-44-seckey-aks.m new file mode 100644 index 00000000..05961b21 --- /dev/null +++ b/OSX/shared_regressions/si-44-seckey-aks.m @@ -0,0 +1,131 @@ +// +// Copyright 2016 Apple. All rights reserved. +// + +#import +#import +#import +#import +#if !TARGET_OS_OSX +#import "MobileGestalt.h" +#endif + +#import "shared_regressions.h" + +static id generateKey(id keyType) { + id accessControl = (__bridge_transfer id)SecAccessControlCreateWithFlags(NULL, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, kSecAccessControlPrivateKeyUsage, NULL); + NSDictionary *keyAttributes = @{ (id)kSecAttrTokenID : (id)kSecAttrTokenIDAppleKeyStore, + (id)kSecAttrKeyType : keyType, + (id)kSecAttrAccessControl : accessControl, + (id)kSecAttrIsPermanent : @NO }; + NSError *error; + id key = (__bridge_transfer id)SecKeyCreateRandomKey((CFDictionaryRef)keyAttributes, (void *)&error); + ok(key, "failed to create random key %@", error); + return key; +} + +static void secKeySepTest(BOOL testPKA) { + NSArray *keyTypes; + if (testPKA) { + keyTypes = @[(id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyTypeECSECPrimeRandomPKA, (id)kSecAttrKeyTypeSecureEnclaveAttestation]; + } else { + keyTypes = @[(id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyTypeSecureEnclaveAttestation]; + } + for (id keyType in keyTypes) { + id privateKey = generateKey((id)keyType); + ok(privateKey, "failed to create key '%@'", keyType); + id publicKey = (__bridge_transfer id)SecKeyCopyPublicKey((SecKeyRef)privateKey); + + NSArray *attestaionKeyTypes = @[@(kSecKeyAttestationKeyTypeSIK), @(kSecKeyAttestationKeyTypeGID)]; + for (NSNumber *attestationKeyType in attestaionKeyTypes) { + id attestationKey = (__bridge_transfer id)SecKeyCopyAttestationKey([attestationKeyType unsignedIntValue], NULL); + ok(attestationKey, "failed to create attestaion key '%@'", attestationKeyType); + NSError *error; + if (![keyType isEqual:(id)kSecAttrKeyTypeSecureEnclaveAttestation]) { + const char rawData[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + NSData *dataToSign = [NSData dataWithBytes:rawData length:sizeof(rawData)]; + NSData *signedData = (__bridge_transfer NSData*)SecKeyCreateSignature((SecKeyRef)privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, (void *)&error); + ok(signedData, "failed to sign data, error %@", error); + error = nil; + ok(SecKeyVerifySignature((SecKeyRef)publicKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, (__bridge CFDataRef)signedData, (void *)&error), + "failed to verify data '%@'", error); + + // Try signing large data. + dataToSign = [NSMutableData dataWithLength:10 * 1024 * 1024]; + error = nil; + signedData = (__bridge_transfer NSData*)SecKeyCreateSignature((SecKeyRef)privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, (void *)&error); + ok(signedData, "failed to sign data, error %@", error); + error = nil; + ok(SecKeyVerifySignature((SecKeyRef)publicKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)dataToSign, (__bridge CFDataRef)signedData, (void *)&error), + "failed to verify data '%@'", error); + } + NSData *attestationData = (__bridge_transfer NSData *)SecKeyCreateAttestation((__bridge SecKeyRef)attestationKey, (__bridge SecKeyRef)privateKey, (void *)&error); + ok(attestationData, "failed to attest key '%@'", error); + } + + NSDictionary *keyAttrs = (__bridge_transfer NSDictionary *)SecKeyCopyAttributes((SecKeyRef)privateKey); + NSData *keyBlob = keyAttrs[(id)kSecAttrTokenOID]; + + NSDictionary *params = @{ (id)kSecAttrTokenID : (id)kSecAttrTokenIDAppleKeyStore, + (id)kSecAttrTokenOID : keyBlob, + (id)kSecReturnRef : @YES }; + + privateKey = nil; + NSError *error; + privateKey = (__bridge_transfer id)SecKeyCreateWithData((__bridge CFDataRef)keyBlob, (__bridge CFDictionaryRef)params, (void *)&error); + ok(privateKey, "failed to create key with data '%@'", error); +// SecItemAdd fails to create SecKey from aks key blob +// +// ok_status(SecItemAdd((__bridge CFDictionaryRef)params, (void *)&privateKey), "failed to create key from aks blob"); +// ok_status(SecItemDelete((__bridge CFDictionaryRef) @{(id)kSecValueRef : privateKey}), "failed to delete key from aks blob"); + } +} + +static void attestationTest(void) { + NSError *error; + id privKey = generateKey((id)kSecAttrKeyTypeECSECPrimeRandom); + id uik = generateKey((id)kSecAttrKeyTypeSecureEnclaveAttestation); + id sik = CFBridgingRelease(SecKeyCopyAttestationKey(kSecKeyAttestationKeyTypeSIK, (void *)&error)); + ok(sik != nil, "get SIk key: %@", error); + + error = nil; + NSData *attSIKPlain = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)uik, (void *)&error)); + ok(attSIKPlain != nil, "SIK attesting UIK, no nonce: %@", error); + + error = nil; + NSData *attUIKPlain = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)uik, (__bridge SecKeyRef)privKey, (void *)&error)); + ok(attUIKPlain != nil, "UIK attesting privKey, no nonce: %@", error); + + error = nil; + NSData *nonce = [@"TESTnonce" dataUsingEncoding:NSUTF8StringEncoding]; + ok(SecKeySetParameter((__bridge SecKeyRef)sik, kSecKeyParameterSETokenAttestationNonce, (__bridge CFPropertyListRef)nonce, (void *)&error), "Set nonce to SIK: %@", error); + NSData *attSIKNonce = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)uik, (void *)&error)); + ok(attSIKNonce != nil, "SIK attesting UIK, with nonce: %@", error); +// NSRange found = [attSIKNonce rangeOfData:nonce options:0 range:NSMakeRange(0, attSIKNonce.length)]; +// ok(found.location != NSNotFound, "nonce found in SIK-attested data"); + + error = nil; + 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); +// found = [attUIKNonce rangeOfData:nonce options:0 range:NSMakeRange(0, attUIKNonce.length)]; +// ok(found.location != NSNotFound, "nonce found in UIK-attested data"); +} + +int si_44_seckey_aks(int argc, char *const *argv) { + @autoreleasepool { + BOOL testPKA = YES; +#if !TARGET_OS_OSX + id hasPKA = (__bridge_transfer id)MGCopyAnswer(kMGQHasPKA, NULL); + if(![hasPKA isKindOfClass:NSNumber.class] || ![(NSNumber *)hasPKA boolValue]) { + testPKA = NO; + } +#else + testPKA = NO; +#endif + plan_tests(testPKA ? 46 : 31); + secKeySepTest(testPKA); + attestationTest(); + return 0; + } +} diff --git a/OSX/shared_regressions/si-44-seckey-ec.m b/OSX/shared_regressions/si-44-seckey-ec.m index ef160784..e8d0cffe 100644 --- a/OSX/shared_regressions/si-44-seckey-ec.m +++ b/OSX/shared_regressions/si-44-seckey-ec.m @@ -24,6 +24,10 @@ #import +#import +#import +#import + #include "shared_regressions.h" static void test_export_import_run(int size) { @@ -69,12 +73,94 @@ static void test_export_import() { } static const int TestExportImport = TestExportImportRun * 3; -static const int TestCount = TestExportImport; +static void test_sign_digest_run(id privKey, ccec_const_cp_t cp, SecKeyAlgorithm algorithm, const struct ccdigest_info *di) { + ok(SecKeyIsAlgorithmSupported((SecKeyRef)privKey, kSecKeyOperationTypeSign, algorithm), "algorithm %@ should be supported", algorithm); + + NSError *error; + NSData *digest = [NSMutableData dataWithLength:di ? di->output_size : 50]; + + error = nil; + NSData *signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)privKey, algorithm, (CFDataRef)digest, (void *)&error)); + ok(signature != nil, "signing failed: %@", error); + + error = nil; + id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privKey)); + NSData *pubKeyData = CFBridgingRelease(SecKeyCopyExternalRepresentation((SecKeyRef)publicKey, (void *)&error)); + ok(pubKeyData, "export public key: %@", error); + ccec_pub_ctx_decl_cp(cp, pubkey); + ok(ccec_x963_import_pub(cp, pubKeyData.length, pubKeyData.bytes, pubkey) == 0, "error importing cc ec key"); + bool valid = false; + is(ccec_verify(pubkey, digest.length, digest.bytes, signature.length, signature.bytes, &valid), 0, "ccec_verify"); + is(valid, true, "ccec_verify detected bad signature"); + + if (di != NULL) { + error = nil; + digest = [NSMutableData dataWithLength:di->output_size + 1]; + signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)privKey, algorithm, (CFDataRef)digest, (void *)&error)); + is(signature, nil, "signing long digest fails"); + is(error.code, errSecParam, "wrong error for long digest: %@", error); + + error = nil; + digest = [NSMutableData dataWithLength:di->output_size - 1]; + signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)privKey, algorithm, (CFDataRef)digest, (void *)&error)); + is(signature, nil, "signing short digest fails"); + is(error.code, errSecParam, "wrong error for short digest: %@", error); + } else { + // Balance count of tests + ok(true); + ok(true); + ok(true); + ok(true); + } +} +static const int TestSignDigestRun = 10; + +static void test_sign_digest() { + + NSError *error = nil; + id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @192}, (void *)&error)); + ok(privateKey, "key properly generated: %@", error); + + test_sign_digest_run(privateKey, ccec_cp_192(), kSecKeyAlgorithmECDSASignatureDigestX962, NULL); + test_sign_digest_run(privateKey, ccec_cp_192(), kSecKeyAlgorithmECDSASignatureDigestX962SHA1, ccsha1_di()); + test_sign_digest_run(privateKey, ccec_cp_192(), kSecKeyAlgorithmECDSASignatureDigestX962SHA224, ccsha224_di()); + test_sign_digest_run(privateKey, ccec_cp_192(), kSecKeyAlgorithmECDSASignatureDigestX962SHA256, ccsha256_di()); + test_sign_digest_run(privateKey, ccec_cp_192(), kSecKeyAlgorithmECDSASignatureDigestX962SHA384, ccsha384_di()); + test_sign_digest_run(privateKey, ccec_cp_192(), kSecKeyAlgorithmECDSASignatureDigestX962SHA512, ccsha512_di()); + + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256}, (void *)&error)); + ok(privateKey, "key properly generated: %@", error); + + test_sign_digest_run(privateKey, ccec_cp_256(), kSecKeyAlgorithmECDSASignatureDigestX962, NULL); + test_sign_digest_run(privateKey, ccec_cp_256(), kSecKeyAlgorithmECDSASignatureDigestX962SHA1, ccsha1_di()); + test_sign_digest_run(privateKey, ccec_cp_256(), kSecKeyAlgorithmECDSASignatureDigestX962SHA224, ccsha224_di()); + test_sign_digest_run(privateKey, ccec_cp_256(), kSecKeyAlgorithmECDSASignatureDigestX962SHA256, ccsha256_di()); + test_sign_digest_run(privateKey, ccec_cp_256(), kSecKeyAlgorithmECDSASignatureDigestX962SHA384, ccsha384_di()); + test_sign_digest_run(privateKey, ccec_cp_256(), kSecKeyAlgorithmECDSASignatureDigestX962SHA512, ccsha512_di()); + + + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @521}, (void *)&error)); + ok(privateKey, "key properly generated: %@", error); + + test_sign_digest_run(privateKey, ccec_cp_521(), kSecKeyAlgorithmECDSASignatureDigestX962, NULL); + test_sign_digest_run(privateKey, ccec_cp_521(), kSecKeyAlgorithmECDSASignatureDigestX962SHA1, ccsha1_di()); + test_sign_digest_run(privateKey, ccec_cp_521(), kSecKeyAlgorithmECDSASignatureDigestX962SHA224, ccsha224_di()); + test_sign_digest_run(privateKey, ccec_cp_521(), kSecKeyAlgorithmECDSASignatureDigestX962SHA256, ccsha256_di()); + test_sign_digest_run(privateKey, ccec_cp_521(), kSecKeyAlgorithmECDSASignatureDigestX962SHA384, ccsha384_di()); + test_sign_digest_run(privateKey, ccec_cp_521(), kSecKeyAlgorithmECDSASignatureDigestX962SHA512, ccsha512_di()); +} +static const int TestSignDigest = TestSignDigestRun * 18 + 3; + +static const int TestCount = +TestExportImport + +TestSignDigest; + int si_44_seckey_ec(int argc, char *const *argv) { plan_tests(TestCount); @autoreleasepool { test_export_import(); + test_sign_digest(); } return 0; diff --git a/OSX/shared_regressions/si-44-seckey-fv.m b/OSX/shared_regressions/si-44-seckey-fv.m new file mode 100644 index 00000000..6442b20f --- /dev/null +++ b/OSX/shared_regressions/si-44-seckey-fv.m @@ -0,0 +1,68 @@ +// +// si-44-seckey-fv.m +// + +#import + +#if TARGET_OS_IOS && !TARGET_OS_SIMULATOR +#import "SecureKeyVaultPublic.h" +#import + +#import "shared_regressions.h" + +static void testFileVaultKeyRawSign() { + id key = CFBridgingRelease(SecKeyCreateWithSecureKeyVaultID(kCFAllocatorDefault, kSecureKeyVaultIAPAuthPrivateKey)); + id certificate = CFBridgingRelease(SecCertificateCreateWithSecureKeyVaultID(kCFAllocatorDefault, kSecureKeyVaultIAPAuthPrivateKey)); + id pubKey = CFBridgingRelease(SecCertificateCopyPublicKey((SecCertificateRef)certificate)); + + uint8_t hash[20] = { 0 }; + uint8_t signature[256] = { 0 }; + size_t siglen = sizeof(signature); + ok_status(SecKeyRawSign((SecKeyRef)key, kSecPaddingPKCS1SHA1, hash, sizeof(hash), signature, &siglen), "rawSign for fileVault failed"); + ok_status(SecKeyRawVerify((SecKeyRef)pubKey, kSecPaddingPKCS1SHA1, hash, sizeof(hash), signature, siglen), "rawverify for fileVault failed"); +} + +static void testFileVaultKeySign() { + NSData *data = [@"dataToSign" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *signature; + SecKeyAlgorithm algorithm = NULL; + NSError *error; + id key = CFBridgingRelease(SecKeyCreateWithSecureKeyVaultID(kCFAllocatorDefault, kSecureKeyVaultIAPAuthPrivateKey)); + id certificate = CFBridgingRelease(SecCertificateCreateWithSecureKeyVaultID(kCFAllocatorDefault, kSecureKeyVaultIAPAuthPrivateKey)); + id pubKey = CFBridgingRelease(SecCertificateCopyPublicKey((SecCertificateRef)certificate)); + + algorithm = kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1; + error = nil; + signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)key, algorithm, (CFDataRef)data, (void *)&error)); + ok(signature != NULL, "signing with alg %@ failed, err %@", algorithm, error); + ok(SecKeyVerifySignature((SecKeyRef)pubKey, algorithm, (CFDataRef)data, (CFDataRef)signature, (void *)&error)); + + algorithm = kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256; + error = nil; + signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)key, algorithm, (CFDataRef)data, (void *)&error)); + ok(signature != NULL, "signing with alg %@ failed, err %@", algorithm, error); + ok(SecKeyVerifySignature((SecKeyRef)pubKey, algorithm, (CFDataRef)data, (CFDataRef)signature, (void *)&error)); + + algorithm = kSecKeyAlgorithmRSASignatureMessagePSSSHA1; + error = nil; + signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)key, algorithm, (CFDataRef)data, (void *)&error)); + ok(signature != NULL, "signing with alg %@ failed, err %@", algorithm, error); + ok(SecKeyVerifySignature((SecKeyRef)pubKey, algorithm, (CFDataRef)data, (CFDataRef)signature, (void *)&error)); + + algorithm = kSecKeyAlgorithmRSASignatureMessagePSSSHA256; + error = nil; + signature = CFBridgingRelease(SecKeyCreateSignature((SecKeyRef)key, algorithm, (CFDataRef)data, (void *)&error)); + ok(signature != NULL, "signing with alg %@ failed, err %@", algorithm, error); + ok(SecKeyVerifySignature((SecKeyRef)pubKey, algorithm, (CFDataRef)data, (CFDataRef)signature, (void *)&error)); +} + +int si_44_seckey_fv(int argc, char *const *argv) { + @autoreleasepool { + plan_tests(10); + testFileVaultKeyRawSign(); + testFileVaultKeySign(); + return 0; + } +} + +#endif diff --git a/OSX/shared_regressions/si-44-seckey-gen.m b/OSX/shared_regressions/si-44-seckey-gen.m index 27272263..073135c7 100644 --- a/OSX/shared_regressions/si-44-seckey-gen.m +++ b/OSX/shared_regressions/si-44-seckey-gen.m @@ -48,6 +48,10 @@ static void create_random_key_worker(id keyType, int keySize, bool permPub, bool id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey)); ok(publicKey != nil, "got public key from generated private key"); + error = nil; + NSData *pubKeyData = CFBridgingRelease(SecKeyCopyExternalRepresentation((SecKeyRef)publicKey, (void *)&error)); + ok(pubKeyData != nil, "get public key data, error %@", error); + params = @{ (id)kSecClass: (id)kSecClassKey, (id)kSecAttrKeyType: keyType, @@ -61,42 +65,125 @@ static void create_random_key_worker(id keyType, int keySize, bool permPub, bool is_status(SecItemCopyMatching((CFDictionaryRef)params, (void *)&items), expected, "keychain query for generated keys"); is((int)items.count, (permPub ? 1 : 0) + (permPriv ? 1 : 0), "found keys in the keychain"); - if (items.count > 0) { - params = @{ - (id)kSecClass: (id)kSecClassKey, - (id)kSecAttrKeyType: keyType, - (id)kSecAttrKeySizeInBits: @(keySize), -#if TARGET_OS_OSX - // Despite headerdoc and other docs, SecItemDelete on macOS deletes only first found item, we need to persuade - // it to delete everything passing the query. On the other hand, iOS implementation errs out when - // kSecMatchLimit is given, so we need to add it only for macOS. - (id)kSecMatchLimit: (id)kSecMatchLimitAll, -#endif + if (!permPub) { + // Store public key into keychain explicitly. + NSDictionary *add = @{ + (id)kSecValueRef: (id)publicKey, + (id)kSecAttrLabel: @"si-44-seckey-gen:0", + (id)kSecReturnPersistentRef: @YES, + }; + NSData *pRef; + ok_status(SecItemAdd((CFDictionaryRef)add, (void *)&pRef), "Add public key"); + ok([pRef isKindOfClass:NSData.class] || [pRef isKindOfClass:NSArray.class] , "got persistent ref"); + } else { + ok(true); + ok(true); + } + + if (!permPriv) { + // Store public key into keychain explicitly. + NSDictionary *add = @{ + (id)kSecValueRef: (id)privateKey, (id)kSecAttrLabel: @"si-44-seckey-gen:0", + (id)kSecReturnPersistentRef: @YES, }; - ok_status(SecItemDelete((CFDictionaryRef)params), "clear generated pair from keychain"); + NSData *pRef; + ok_status(SecItemAdd((CFDictionaryRef)add, (void *)&pRef), "Add private key"); + ok([pRef isKindOfClass:NSData.class] || [pRef isKindOfClass:NSArray.class] , "got persistent ref"); + } else { + ok(true); + ok(true); } + + items = nil; + ok_status(SecItemCopyMatching((CFDictionaryRef)params, (void *)&items), "keychain query for generated keys"); + is((int)items.count, 2, "keypair is in the keychain"); + + params = @{ + (id)kSecClass: (id)kSecClassKey, + (id)kSecAttrKeyType: keyType, + (id)kSecAttrKeySizeInBits: @(keySize), +#if TARGET_OS_OSX + // Despite headerdoc and other docs, SecItemDelete on macOS deletes only first found item, we need to persuade + // it to delete everything passing the query. On the other hand, iOS implementation errs out when + // kSecMatchLimit is given, so we need to add it only for macOS. + (id)kSecMatchLimit: (id)kSecMatchLimitAll, +#endif + (id)kSecAttrLabel: @"si-44-seckey-gen:0", + }; + ok_status(SecItemDelete((CFDictionaryRef)params), "clear generated pair from keychain"); } static void test_create_random_key() { create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, false, false); - create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, true, false); create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, false, true); create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, true, true); create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, false, false); - create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, true, false); create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, false, true); create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, true, true); + + // Create pair with pub-permanent&priv-nonpermanent currently does not work well, created + // pub key has some strange ACL which prevents it from sensible use. However, this combination + // also does not make sense at all from usage point of view. +// create_random_key_worker((id)kSecAttrKeyTypeRSA, 1024, true, false); +// create_random_key_worker((id)kSecAttrKeyTypeECSECPrimeRandom, 256, true, false); +} +static const int TestCountCreateRandomKey = (3 * 12) * 2; + +static void test_create_key_with_attrs_run(NSDictionary *attrs) { + NSMutableDictionary *params = attrs.mutableCopy; + params[(id)kSecAttrKeyType] = (id)kSecAttrKeyTypeRSA; + params[(id)kSecAttrKeySizeInBits] = @1024; + params[(id)kSecAttrIsPermanent] = @YES; + + NSError *error; + id privKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privKey != nil, "generatekey: %@", privKey); + + id pubKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privKey)); + ok(pubKey != nil, "get pub key"); + + NSDictionary *result; + ok_status(SecItemCopyMatching((CFDictionaryRef)@{(id)kSecValueRef: privKey, (id)kSecReturnAttributes: @YES}, (void *)&result), "copymatching create privkey"); + __block BOOL failed = NO; + [attrs enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + failed = failed || ![result[key] isEqual:obj]; + }]; + ok(!failed, "retrieved attributes differ (privkey): expected: %@ - got: %@", attrs, result); + + result = nil; + ok_status(SecItemCopyMatching((CFDictionaryRef)@{(id)kSecValueRef: pubKey, (id)kSecReturnAttributes: @YES}, (void *)&result), "copymatching create privkey"); + failed = NO; + [attrs enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + failed = failed || ![result[key] isEqual:obj]; + }]; + ok(!failed, "retrieved attributes differ (pubkey): expected: %@ - got: %@", attrs, result); + + // Cleanup of the keys. + ok_status(SecItemDelete((CFDictionaryRef)@{(id)kSecValueRef: privKey})); + ok_status(SecItemDelete((CFDictionaryRef)@{(id)kSecValueRef: pubKey})); +} +static const int TestCountCreateKeyWithAttrsRun = 8; + +static void test_create_key_with_attrs() { + test_create_key_with_attrs_run(@{(id)kSecAttrLabel:@"Label"}); + test_create_key_with_attrs_run(@{(id)kSecAttrApplicationTag:[@"AppTag" dataUsingEncoding:NSUTF8StringEncoding]}); + test_create_key_with_attrs_run(@{(id)kSecAttrLabel:@"Label", + (id)kSecAttrApplicationTag:[@"AppTag" dataUsingEncoding:NSUTF8StringEncoding]}); } -static const int TestCountCreateRandomKey = (4 * 4 + 1 * 3) * 2; +static const int TestCountCreateKeyWithAttrs = 3 * TestCountCreateKeyWithAttrsRun; -static const int TestCount = TestCountCreateRandomKey; +static const int TestCount = +TestCountCreateRandomKey + +TestCountCreateKeyWithAttrs +; int si_44_seckey_gen(int argc, char *const *argv) { plan_tests(TestCount); @autoreleasepool { test_create_random_key(); + test_create_key_with_attrs(); } return 0; diff --git a/OSX/shared_regressions/si-44-seckey-ies.m b/OSX/shared_regressions/si-44-seckey-ies.m index b76be120..27980924 100644 --- a/OSX/shared_regressions/si-44-seckey-ies.m +++ b/OSX/shared_regressions/si-44-seckey-ies.m @@ -25,7 +25,7 @@ #import #import -#import +#import #import #import #import @@ -33,12 +33,8 @@ #include "shared_regressions.h" -static struct ccrng_system_state ccrng_system_state_seckey_ies_test; - -static void test_ies_run(CFStringRef keyType, id keySize, SecKeyAlgorithm algorithm) { +static void test_ies_run(id privateKey, SecKeyAlgorithm algorithm) { NSError *error = nil; - id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (__bridge id)keyType, (id)kSecAttrKeySizeInBits: keySize}, (void *)&error)); - ok(privateKey, "key properly generated"); id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey)); ok(publicKey, "public key retrieved"); @@ -94,48 +90,80 @@ static void test_ies_run(CFStringRef keyType, id keySize, SecKeyAlgorithm algori decrypted = CFBridgingRelease(SecKeyCreateDecryptedData((SecKeyRef)privateKey, algorithm, (CFDataRef)badEncrypted, (void *)&error)); ok(decrypted == nil, "broken encrypted message failed to decrypt (pubkey data breakage)"); } -static const int TestCountIESRun = 13; +static const int TestCountIESRun = 12; static void test_ecies() { - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(192), kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(192), kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(192), kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(192), kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(192), kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); - - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(256), kSecKeyAlgorithmECIESEncryptionCofactorX963SHA1AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(256), kSecKeyAlgorithmECIESEncryptionCofactorX963SHA224AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(256), kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(256), kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(256), kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM); - - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(521), kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(521), kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(521), kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(521), kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM); - test_ies_run(kSecAttrKeyTypeECSECPrimeRandom, @(521), kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM); + NSError *error; + id privateKey; + + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @192}, (void *)&error)); + ok(privateKey, "key generation error %@", error); + error = nil; + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); + + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM); + + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256}, (void *)&error)); + ok(privateKey, "key generation error %@", error); + error = nil; + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA1AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA224AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM); + + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM); + + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @521}, (void *)&error)); + ok(privateKey, "key generation error %@", error); + error = nil; + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM); + + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM); } -static const int TestCountECIES = TestCountIESRun * 5 * 3; +static const int TestCountECIES = TestCountIESRun * 9 * 3 + 3; static void test_rsawrap() { - test_ies_run(kSecAttrKeyTypeRSA, @(1024), kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM); - test_ies_run(kSecAttrKeyTypeRSA, @(1024), kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM); - test_ies_run(kSecAttrKeyTypeRSA, @(1024), kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM); - test_ies_run(kSecAttrKeyTypeRSA, @(1024), kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM); - test_ies_run(kSecAttrKeyTypeRSA, @(4096), kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM); + NSError *error; + id privateKey; + + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @1024}, (void *)&error)); + ok(privateKey, "key generation error %@", error); + error = nil; + test_ies_run(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM); + test_ies_run(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM); + + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @4096}, (void *)&error)); + ok(privateKey, "key generation error %@", error); + error = nil; + test_ies_run(privateKey, kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM); } -static const int TestCountRSAWRAP = TestCountIESRun * 5; +static const int TestCountRSAWRAP = TestCountIESRun * 5 + 2; -static void test_ies_against_corecrypto(id keySize, ccec_const_cp_t cp, const struct ccdigest_info *di, uint32_t ccKeySize, SecKeyAlgorithm algorithm) { +static void test_ies_against_corecrypto(id privKey, ccec_const_cp_t cp, const struct ccdigest_info *di, uint32_t ccKeySize, bool secureIV, SecKeyAlgorithm algorithm) { // Generate SecKey and import it as corecrypto fullkey. - NSError *error = nil; - NSDictionary *params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: keySize, - (id)kSecAttrNoLegacy: @YES}; - id privKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); - ok(privKey != nil, "create key (error %@)", error); - error = nil; + NSError *error; NSData *privKeyData = CFBridgingRelease(SecKeyCopyExternalRepresentation((SecKeyRef)privKey, (void *)&error)); - ok(privKey != nil, "export key (error %@)", error); + ok(privKeyData != nil, "export key (error %@)", error); ccec_full_ctx_decl_cp(cp, fullkey); ok(ccec_x963_import_priv(cp, privKeyData.length, privKeyData.bytes, fullkey) == 0, "error importing cc ec key"); @@ -147,7 +175,8 @@ static void test_ies_against_corecrypto(id keySize, ccec_const_cp_t cp, const st NSData *ciphertext = CFBridgingRelease(SecKeyCreateEncryptedData((SecKeyRef)publicKey, algorithm, (CFDataRef)plaintext, (void *)&error)); ok(ciphertext != nil, "encrypt data with SecKey (error %@)", error); struct ccecies_gcm ecies_dec; - ccecies_decrypt_gcm_setup(&ecies_dec, di, ccaes_gcm_decrypt_mode(), ccKeySize, 16, ECIES_EPH_PUBKEY_IN_SHAREDINFO1 | ECIES_EXPORT_PUB_STANDARD); + ccecies_decrypt_gcm_setup(&ecies_dec, di, ccaes_gcm_decrypt_mode(), ccKeySize, 16, + ECIES_EPH_PUBKEY_IN_SHAREDINFO1 | ECIES_EXPORT_PUB_STANDARD | (secureIV ? 0 : ECIES_LEGACY_IV)); size_t decryptedLength = plaintext.length; NSMutableData *decrypted = [NSMutableData dataWithLength:decryptedLength]; if (ciphertext != nil) { @@ -159,54 +188,84 @@ static void test_ies_against_corecrypto(id keySize, ccec_const_cp_t cp, const st // cc encrypt -> SecKey decrypt struct ccecies_gcm ecies_enc; - ccecies_encrypt_gcm_setup(&ecies_enc, di, (struct ccrng_state *)&ccrng_system_state_seckey_ies_test, - ccaes_gcm_encrypt_mode(), ccKeySize, 16, ECIES_EPH_PUBKEY_IN_SHAREDINFO1 | ECIES_EXPORT_PUB_STANDARD); - size_t encryptedLength = ccecies_encrypt_gcm_ciphertext_size(fullkey, &ecies_enc, sizeof(knownPlaintext)); + ccecies_encrypt_gcm_setup(&ecies_enc, di, ccrng(NULL), ccaes_gcm_encrypt_mode(), ccKeySize, 16, + ECIES_EPH_PUBKEY_IN_SHAREDINFO1 | ECIES_EXPORT_PUB_STANDARD | (secureIV ? 0 : ECIES_LEGACY_IV)); + size_t encryptedLength = ccecies_encrypt_gcm_ciphertext_size(ccec_ctx_pub(fullkey), &ecies_enc, sizeof(knownPlaintext)); NSMutableData *encrypted = [NSMutableData dataWithLength:encryptedLength]; - ok(ccecies_encrypt_gcm(fullkey, &ecies_enc, sizeof(knownPlaintext), knownPlaintext, 0, NULL, 0, NULL, &encryptedLength, encrypted.mutableBytes) == 0, "encrypt data with cc failed"); + ok(ccecies_encrypt_gcm(ccec_ctx_pub(fullkey), &ecies_enc, sizeof(knownPlaintext), knownPlaintext, 0, NULL, 0, NULL, &encryptedLength, encrypted.mutableBytes) == 0, "encrypt data with cc failed"); error = nil; NSData *decryptedPlaintext = CFBridgingRelease(SecKeyCreateDecryptedData((SecKeyRef)privKey, algorithm, (CFDataRef)encrypted, (void *)&error)); ok(decryptedPlaintext != nil, "decrypt data with SecKey (error %@)", error); ok([plaintext isEqualToData:decryptedPlaintext], "SecKey decrypted data are the same"); } -static const int TestCountIESAgainstCoreCryptoRun = 10; +static const int TestCountIESAgainstCoreCryptoRun = 9; static void test_against_corecrypto() { + id privKey; + NSDictionary *params; + NSError *error; - // Tests ifdefed-out by this define fail because of - // ccecies is broken when AES keysize > KDF hash output size -#define CC_HAS_BUG_26855537 1 - - test_ies_against_corecrypto(@(192), ccec_cp_192(), ccsha1_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); - test_ies_against_corecrypto(@(192), ccec_cp_192(), ccsha224_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); - test_ies_against_corecrypto(@(192), ccec_cp_192(), ccsha256_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); - test_ies_against_corecrypto(@(192), ccec_cp_192(), ccsha384_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); - test_ies_against_corecrypto(@(192), ccec_cp_192(), ccsha512_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); - test_ies_against_corecrypto(@(256), ccec_cp_256(), ccsha1_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); - test_ies_against_corecrypto(@(256), ccec_cp_256(), ccsha224_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); - test_ies_against_corecrypto(@(256), ccec_cp_256(), ccsha256_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); - test_ies_against_corecrypto(@(256), ccec_cp_256(), ccsha384_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); - test_ies_against_corecrypto(@(256), ccec_cp_256(), ccsha512_di(), 16, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); -#if !CC_HAS_BUG_26855537 - test_ies_against_corecrypto(@(384), ccec_cp_384(), ccsha1_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); - test_ies_against_corecrypto(@(384), ccec_cp_384(), ccsha224_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); -#endif - test_ies_against_corecrypto(@(384), ccec_cp_384(), ccsha256_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); - test_ies_against_corecrypto(@(384), ccec_cp_384(), ccsha384_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); - test_ies_against_corecrypto(@(384), ccec_cp_384(), ccsha512_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); -#if !CC_HAS_BUG_26855537 - test_ies_against_corecrypto(@(521), ccec_cp_521(), ccsha1_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); - test_ies_against_corecrypto(@(521), ccec_cp_521(), ccsha224_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); -#endif - test_ies_against_corecrypto(@(521), ccec_cp_521(), ccsha256_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); - test_ies_against_corecrypto(@(521), ccec_cp_521(), ccsha384_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); - test_ies_against_corecrypto(@(521), ccec_cp_521(), ccsha512_di(), 32, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); + params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @192, (id)kSecAttrNoLegacy: @YES}; + privKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privKey != nil, "create key (error %@)", error); + error = nil; + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha1_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha224_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha256_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha384_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha512_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); + + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha224_di(), 16, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha256_di(), 16, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha384_di(), 16, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_192(), ccsha512_di(), 16, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM); + + params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrNoLegacy: @YES}; + privKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privKey != nil, "create key (error %@)", error); + error = nil; + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha1_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha224_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha256_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha384_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha512_di(), 16, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); + + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha224_di(), 16, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha256_di(), 16, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha384_di(), 16, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_256(), ccsha512_di(), 16, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM); + + params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @384, (id)kSecAttrNoLegacy: @YES}; + privKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privKey != nil, "create key (error %@)", error); + error = nil; + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha1_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha224_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha256_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha384_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha512_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); + + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha224_di(), 32, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha256_di(), 32, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha384_di(), 32, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_384(), ccsha512_di(), 32, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM); + + params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @521, (id)kSecAttrNoLegacy: @YES}; + privKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privKey != nil, "create key (error %@)", error); + error = nil; + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha1_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha224_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha256_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha384_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha512_di(), 32, false, kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM); + + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha224_di(), 32, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha256_di(), 32, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha384_di(), 32, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM); + test_ies_against_corecrypto(privKey, ccec_cp_521(), ccsha512_di(), 32, true, kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM); } -#if !CC_HAS_BUG_26855537 -static const int TestCountAgainstCoreCrypto = TestCountIESAgainstCoreCryptoRun * 20; -#else -static const int TestCountAgainstCoreCrypto = TestCountIESAgainstCoreCryptoRun * 16; -#endif +static const int TestCountAgainstCoreCrypto = TestCountIESAgainstCoreCryptoRun * 36 + 4; static void test_ies_known_ciphertext(CFStringRef keyType, id keySize, SecKeyAlgorithm algorithm, NSString *privKeyData, NSString *ciphertext) { #define GENERATE_VECTORS 0 @@ -277,8 +336,6 @@ int si_44_seckey_ies(int argc, char *const *argv) { plan_tests(TestCount); @autoreleasepool { - ccrng_system_init(&ccrng_system_state_seckey_ies_test); - test_ecies(); test_rsawrap(); test_against_corecrypto(); diff --git a/OSX/shared_regressions/si-44-seckey-rsa.m b/OSX/shared_regressions/si-44-seckey-rsa.m index b41a37e0..23f58798 100644 --- a/OSX/shared_regressions/si-44-seckey-rsa.m +++ b/OSX/shared_regressions/si-44-seckey-rsa.m @@ -25,8 +25,15 @@ #import #import +#import #import +#import +#import +#import +#import +#import + #include "shared_regressions.h" static NSData *decryptAndUnpad(SecKeyRef privateKey, SecKeyAlgorithm algorithm, NSData *ciphertext, NSError **error) { @@ -144,6 +151,100 @@ static const int TestCountEncryption = TestCountEncryptKeypairRun + (TestCountEncryptRun * 6) + (1 * 1) + TestCountEncryptKeypairRun + (TestCountEncryptRun * 7) + (1 * 0); +static void test_pss_sign_run(SecKeyRef privateKey, SecKeyAlgorithm algorithm, SecKeyAlgorithm digestAlgorithm, + const struct ccdigest_info *di) { + NSError *error; + id publicKey = CFBridgingRelease(SecKeyCopyPublicKey(privateKey)); + NSData *message = [NSData dataWithBytes:"1234" length:4]; + NSMutableData *digest = [NSMutableData dataWithLength:di->output_size]; + ccdigest(di, message.length, message.bytes, digest.mutableBytes); + + // Verify algorithm's availability + ok(SecKeyIsAlgorithmSupported((SecKeyRef)privateKey, kSecKeyOperationTypeSign, algorithm), "algorithm %@ available on key %@", algorithm, privateKey); + ok(SecKeyIsAlgorithmSupported((SecKeyRef)privateKey, kSecKeyOperationTypeSign, digestAlgorithm), "algorithm %@ available on key %@", digestAlgorithm, privateKey); + + // Calculate signature of the message using SecKey + error = nil; + NSData *signature = CFBridgingRelease(SecKeyCreateSignature(privateKey, algorithm, (CFDataRef)message, (void *)&error)); + ok(signature != nil, "sign message with algorithm %@: error %@", algorithm, error); + + // Verify signature of the message using SecKey + error = nil; + Boolean verified = SecKeyVerifySignature((SecKeyRef)publicKey, algorithm, (CFDataRef)message, (CFDataRef)signature, (void *)&error); + ok(verified, "signature verified for algorithm %@: error %@", algorithm, error); + + // Calculate signature of the digest using SecKey + error = nil; + signature = CFBridgingRelease(SecKeyCreateSignature(privateKey, digestAlgorithm, (CFDataRef)digest, (void *)&error)); + ok(signature != nil, "sign digest with algorithm %@: error %@", digestAlgorithm, error); + + // Verify signature of the digest using CC + NSData *pubData = CFBridgingRelease(SecKeyCopyExternalRepresentation((SecKeyRef)publicKey, (void *)&error)); + ok(pubData != nil, "export public key: error %@", error); + cc_size n = ccrsa_import_pub_n(pubData.length, pubData.bytes); + ccrsa_pub_ctx_decl(ccn_sizeof_n(n), ccpub); + ccrsa_ctx_n(ccpub) = n; + int err = ccrsa_import_pub(ccpub, pubData.length, pubData.bytes); + is(err, 0, "ccrsa_import_pub(key=%@) failed", publicKey); + + bool valid = false; + err = ccrsa_verify_pss(ccpub, di, di, di->output_size, digest.bytes, signature.length, signature.bytes, di->output_size, &valid); + is(err, 0, "ccrsa_verify_pss(%@) failed", algorithm); + ok(valid, "ccrsa verify signature (alg %@)", algorithm); + + // Calculate signature of the digest using CC + error = nil; + NSData *privData = CFBridgingRelease(SecKeyCopyExternalRepresentation(privateKey, (void *)&error)); + ok(privData != nil, "export private key: error %@", error); + n = ccrsa_import_priv_n(privData.length, privData.bytes); + ccrsa_full_ctx_decl(ccn_sizeof_n(n), ccpriv); + ccrsa_ctx_n(ccpriv) = n; + err = ccrsa_import_priv(ccpriv, privData.length, privData.bytes); + is(err, 0, "ccrsa_import_priv(key=%@) failed", privateKey); + + NSMutableData *ccSig = [NSMutableData dataWithLength:SecKeyGetBlockSize(privateKey)]; + size_t sigSize = ccSig.length; + err = ccrsa_sign_pss(ccpriv, di, di, di->output_size, ccrng(NULL), digest.length, digest.bytes, &sigSize, ccSig.mutableBytes); + is(err, 0, "ccrsa_sign_pss(%@) failed", digestAlgorithm); + is(sigSize, ccSig.length, "unexpected signature size for algorithm %@", digestAlgorithm); + + // Verify signature of the digest using SecKey + error = nil; + verified = SecKeyVerifySignature((SecKeyRef)publicKey, digestAlgorithm, (CFDataRef)digest, (CFDataRef)ccSig, (void *)&error); + ok(verified, "signature verified for algorithm %@: error %@", digestAlgorithm, error); +} +static const int TestCountPSSSignRun = 14; + +static void test_pss_sign() { + NSError *error; + NSDictionary *params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @1024}; + + error = nil; + id privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privateKey != nil, "generate private key (error %@)", error); + + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA1, kSecKeyAlgorithmRSASignatureDigestPSSSHA1, ccsha1_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA224, kSecKeyAlgorithmRSASignatureDigestPSSSHA224, ccsha224_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA256, kSecKeyAlgorithmRSASignatureDigestPSSSHA256, ccsha256_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA384, kSecKeyAlgorithmRSASignatureDigestPSSSHA384, ccsha384_di()); + + // RSASSA-PSS requires hlen + slen + 2 size modulus, so it requires at least 1040bit keys, and should not be available for 1024b keys. + ok(!SecKeyIsAlgorithmSupported((SecKeyRef)privateKey, kSecKeyOperationTypeSign, kSecKeyAlgorithmRSASignatureDigestPSSSHA512)); + ok(!SecKeyIsAlgorithmSupported((SecKeyRef)privateKey, kSecKeyOperationTypeSign, kSecKeyAlgorithmRSASignatureMessagePSSSHA512)); + + error = nil; + params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @2048}; + privateKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)params, (void *)&error)); + ok(privateKey != nil, "generate private key (error %@)", error); + + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA1, kSecKeyAlgorithmRSASignatureDigestPSSSHA1, ccsha1_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA224, kSecKeyAlgorithmRSASignatureDigestPSSSHA224, ccsha224_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA256, kSecKeyAlgorithmRSASignatureDigestPSSSHA256, ccsha256_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA384, kSecKeyAlgorithmRSASignatureDigestPSSSHA384, ccsha384_di()); + test_pss_sign_run((__bridge SecKeyRef)privateKey, kSecKeyAlgorithmRSASignatureMessagePSSSHA512, kSecKeyAlgorithmRSASignatureDigestPSSSHA512, ccsha512_di()); +} +static const int TestCountPSSSign = 1 + TestCountPSSSignRun * 4 + 2 + 1 + TestCountPSSSignRun * 5; + static void test_bad_input(NSInteger keySizeInBits, NSInteger inputSize, SecKeyAlgorithm algorithm) { NSError *error; NSDictionary *params = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, (id)kSecAttrKeySizeInBits: @(keySizeInBits)}; @@ -231,6 +332,7 @@ static const int TestCountBadSignature = 12; static const int TestCount = TestCountEncryption + +TestCountPSSSign + TestCountBadInputSize + TestCountBadSignature; @@ -239,6 +341,7 @@ int si_44_seckey_rsa(int argc, char *const *argv) { @autoreleasepool { test_encryption(); + test_pss_sign(); test_bad_input_size(); test_bad_signature(); } diff --git a/OSX/shared_regressions/si-82-sectrust-ct.m b/OSX/shared_regressions/si-82-sectrust-ct.m index 64872ace..3213623f 100644 --- a/OSX/shared_regressions/si-82-sectrust-ct.m +++ b/OSX/shared_regressions/si-82-sectrust-ct.m @@ -81,6 +81,7 @@ static void test_ct_trust(CFArrayRef certs, CFArrayRef scts, CFTypeRef ocsprespo ok((isCFTrue(ct) == ct_expected), "unexpected CT result (%s)", test_name); ok((isCFTrue(ev) == ev_expected), "unexpected EV result (%s)", test_name); ok((isCFTrue(ct_whitelist) == ct_whitelist_expected), "unexpected CT WhiteList result (%s)", test_name); + /* Note that the CT whitelist has been removed due to the expiration of all contents. */ #ifdef PRINT_SECTRUST_EVALUATE_TIME printf("%s: %lu\n", test_name, t1); @@ -207,12 +208,12 @@ static void tests() CFReleaseNull(certs); CFReleaseNull(scts); - /* case 3: digicert : 2 embedded SCTs, but lifetime of cert is 24 month, so not CT qualified, but is whitelisted */ + /* case 3: digicert : 2 embedded SCTs, but lifetime of cert is 24 month, so not CT qualified */ isnt(certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create cert array"); CFArrayAppendValue(certs, www_digicert_com_2015_cert); CFArrayAppendValue(certs, digicert_sha2_ev_server_ca); test_ct_trust(certs, NULL, NULL, NULL, NULL, CFSTR("www.digicert.com"), date_20150307, - false, true, true, "digicert 2015"); + false, false, false, "digicert 2015"); CFReleaseNull(certs); /* case 4: paypal.com cert - not CT, but EV */ @@ -220,7 +221,7 @@ static void tests() CFArrayAppendValue(certs, www_paypal_com_cert); CFArrayAppendValue(certs, www_paypal_com_issuer_cert); test_ct_trust(certs, NULL, NULL, NULL, trustedLogs, CFSTR("www.paypal.com"), date_20150307, - false, true, false, "paypal"); + false, false, false, "paypal"); CFReleaseNull(certs); /* Case 5: coreos-ct-test standalone SCT - 2 SCTs - CT qualified */ @@ -270,7 +271,7 @@ static void tests() CFArrayAppendValue(certs, pilot_cert_3055998); CFArrayAppendValue(certs, pilot_cert_3055998_issuer); test_ct_trust(certs, NULL, NULL, NULL, NULL, CFSTR("www.ssbwingate.com"), date_20150307, - false, true, false, "previously whitelisted cert"); + false, false, false, "previously whitelisted cert"); CFReleaseNull(certs); /* Case 10-13: WhiteListed EV cert */ @@ -278,28 +279,28 @@ static void tests() CFArrayAppendValue(certs, whitelist_00008013); CFArrayAppendValue(certs, whitelist_00008013_issuer); test_ct_trust(certs, NULL, NULL, NULL, NULL, CFSTR("clava.com"), date_20150307, - false, true, true, "whitelisted cert 00008013"); + false, false, false, "whitelisted cert 00008013"); CFReleaseNull(certs); isnt(certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create cert array"); CFArrayAppendValue(certs, whitelist_5555bc4f); CFArrayAppendValue(certs, whitelist_5555bc4f_issuer); test_ct_trust(certs, NULL, NULL, NULL, NULL, CFSTR("lanai.dartmouth.edu"), - date_20150307, false, true, true, "whitelisted cert 5555bc4f"); + date_20150307, false, false, false, "whitelisted cert 5555bc4f"); CFReleaseNull(certs); isnt(certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create cert array"); CFArrayAppendValue(certs, whitelist_aaaae152); CFArrayAppendValue(certs, whitelist_5555bc4f_issuer); // Same issuer (Go Daddy) as above test_ct_trust(certs, NULL, NULL, NULL, NULL, CFSTR("www.falymusic.com"), - date_20150307, false, true, true, "whitelisted cert aaaae152"); + date_20150307, false, false, false, "whitelisted cert aaaae152"); CFReleaseNull(certs); isnt(certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create cert array"); CFArrayAppendValue(certs, whitelist_fff9b5f6); CFArrayAppendValue(certs, whitelist_fff9b5f6_issuer); test_ct_trust(certs, NULL, NULL, NULL, NULL, CFSTR("www.defencehealth.com.au"), - date_20150307, false, true, true, "whitelisted cert fff9b5f6"); + date_20150307, false, false, false, "whitelisted cert fff9b5f6"); CFReleaseNull(certs); diff --git a/OSX/trustd/com.apple.trustd.sb b/OSX/trustd/com.apple.trustd.sb deleted file mode 100644 index 8f6f075b..00000000 --- a/OSX/trustd/com.apple.trustd.sb +++ /dev/null @@ -1,30 +0,0 @@ -(version 1) - -(deny default) - -(import "system.sb") - -(allow file-read*) - -(allow file-read* file-write* - (regex #"^/private/var/db/crls/.*$") - (regex #"^/System/Library/Security/.*$") - (literal "/private/var/db/mds/system/mds.lock")) - -(allow mach-lookup - (global-name "com.apple.CoreServices.coreservicesd") - (global-name "com.apple.PowerManagement.control") - (global-name "com.apple.security.agent") - (global-name "com.apple.security.agent.login") - (global-name "com.apple.security.authhost") - (global-name "com.apple.SecurityServer") - (global-name "com.apple.system.opendirectoryd.api") - (global-name "com.apple.ocspd")) - -(allow ipc-posix-shm - (ipc-posix-name "apple.shm.notification_center") - (ipc-posix-name "com.apple.AppleDatabaseChanged")) - -(allow mach-per-user-lookup) - -(allow system-audit system-sched) diff --git a/OSX/trustd/iOS/com.apple.trustd.plist b/OSX/trustd/iOS/com.apple.trustd.plist new file mode 100644 index 00000000..fa838619 --- /dev/null +++ b/OSX/trustd/iOS/com.apple.trustd.plist @@ -0,0 +1,38 @@ + + + + + EnablePressuredExit + + EnableTransactions + + EnvironmentVariables + + DEBUGSCOPE + -policy-node,policy-set,policy,alloc,trust,bind,profile,trace,dbconn,OTR,serverxpc,sqlite3,error_thee_well, ringSigning + WAIT4DEBUGGER + NO + + GroupName + _securityd + Label + com.apple.trustd + MachServices + + com.apple.trustd + + + ProgramArguments + + /usr/libexec/trustd + + Umask + 54 + UserName + _securityd + POSIXSpawnType + Adaptive + MinimalBootProfile + + + diff --git a/OSX/trustd/iOS/entitlements.plist b/OSX/trustd/iOS/entitlements.plist new file mode 100644 index 00000000..8513f430 --- /dev/null +++ b/OSX/trustd/iOS/entitlements.plist @@ -0,0 +1,28 @@ + + + + + application-identifier + com.apple.trustd + com.apple.application-identifier + com.apple.trustd + com.apple.private.necp.match + + com.apple.private.network.socket-delegate + + com.apple.private.network.delegation-whitelist + + com.apple.private.keychain.certificates + + com.apple.private.read-trustd-downloads + + com.apple.private.assets.accessible-asset-types + + com.apple.MobileAsset.CertificatePinning + + seatbelt-profiles + + trustd + + + diff --git a/OSX/trustd/SecTrustOSXEntryPoints.h b/OSX/trustd/macOS/SecTrustOSXEntryPoints.h similarity index 96% rename from OSX/trustd/SecTrustOSXEntryPoints.h rename to OSX/trustd/macOS/SecTrustOSXEntryPoints.h index 13c073ee..3f44a3a4 100644 --- a/OSX/trustd/SecTrustOSXEntryPoints.h +++ b/OSX/trustd/macOS/SecTrustOSXEntryPoints.h @@ -34,7 +34,7 @@ __BEGIN_DECLS -void SecTrustLegacySourcesEventRunloopCreate(void); +void SecTrustLegacySourcesListenForKeychainEvents(void); OSStatus SecTrustLegacyCRLStatus(SecCertificateRef cert, CFArrayRef chain, CFURLRef currCRLDP); diff --git a/OSX/trustd/com.apple.trustd.agent.plist b/OSX/trustd/macOS/com.apple.trustd.agent.plist similarity index 97% rename from OSX/trustd/com.apple.trustd.agent.plist rename to OSX/trustd/macOS/com.apple.trustd.agent.plist index dd8116b8..8b315af2 100644 --- a/OSX/trustd/com.apple.trustd.agent.plist +++ b/OSX/trustd/macOS/com.apple.trustd.agent.plist @@ -27,7 +27,7 @@ POSIXSpawnType - Interactive + Adaptive ProgramArguments /usr/libexec/trustd diff --git a/OSX/trustd/com.apple.trustd.plist b/OSX/trustd/macOS/com.apple.trustd.plist similarity index 96% rename from OSX/trustd/com.apple.trustd.plist rename to OSX/trustd/macOS/com.apple.trustd.plist index aab29c3d..fac729cb 100644 --- a/OSX/trustd/com.apple.trustd.plist +++ b/OSX/trustd/macOS/com.apple.trustd.plist @@ -21,7 +21,7 @@ POSIXSpawnType - Interactive + Adaptive ProgramArguments /usr/libexec/trustd diff --git a/OSX/trustd/macOS/com.apple.trustd.sb b/OSX/trustd/macOS/com.apple.trustd.sb new file mode 100644 index 00000000..e080f69c --- /dev/null +++ b/OSX/trustd/macOS/com.apple.trustd.sb @@ -0,0 +1,70 @@ +(version 1) + +(deny default) +(deny file-map-executable iokit-get-properties process-info* nvram*) +(deny dynamic-code-generation) + +(import "system.sb") +(import "com.apple.corefoundation.sb") +(corefoundation) + +(allow process-info* (target self)) + +;; For resolving symlinks, realpath(3), and equivalents. +(allow file-read-metadata) + +;; For validating the entitlements of clients (for keychain and trust settings) +;; see 31353815 +(allow process-info-codesignature) +(allow process-info-pidinfo) +(allow file-read*) + +;; ${PRODUCT_NAME}’s preference domain. +(allow user-preference-read user-preference-write + (preference-domain "com.apple.trustd")) + +;; Global and security preferences +(allow user-preference-read + (preference-domain "com.apple.security") + (preference-domain ".GlobalPreferences") + (preference-domain "com.apple.MobileAsset")) + +;; Read/write access to a temporary directory. +(allow file-read* file-write* + (subpath (param "_TMPDIR")) + (subpath (param "_DARWIN_CACHE_DIR"))) + +;; Read/write access to keychains and caches +(allow file-read* file-write* + (subpath "/private/var/db/mds/") + (subpath "/private/var/db/crls/") + (subpath "/System/Library/Security/") + (subpath "/Library/Keychains/") + (subpath "/private/var/root/Library/Caches/com.apple.nsurlsessiond/")) + +(allow file-read* + (literal "/usr/libexec") + (literal "/usr/libexec/trustd") + (literal "/Library/Preferences/com.apple.security.plist") + (regex #"/.GlobalPreferences[^/]*\.plist") + (literal "/Library/Preferences/com.apple.SoftwareUpdate.plist") + (literal "/Library/Application Support/CrashReporter/SubmitDiagInfo.domains")) + +(allow file-map-executable + (regex #"/CoreServicesInternal") + (regex #"/csparser")) + +(allow mach-lookup + (global-name "com.apple.ocspd") + (global-name "com.apple.SecurityServer") + (global-name "com.apple.SystemConfiguration.configd") + (global-name "com.apple.mobileassetd") + (global-name "com.apple.securityd.xpc") + (global-name "com.apple.cfnetwork.cfnetworkagent") + (global-name "com.apple.nsurlsessiond")) + +(allow ipc-posix-shm + (ipc-posix-name "com.apple.AppleDatabaseChanged")) + +(allow network-outbound) +(allow system-socket) diff --git a/OSX/trustd/entitlements.plist b/OSX/trustd/macOS/entitlements.plist similarity index 58% rename from OSX/trustd/entitlements.plist rename to OSX/trustd/macOS/entitlements.plist index 72ccc7b8..d8fc3a06 100644 --- a/OSX/trustd/entitlements.plist +++ b/OSX/trustd/macOS/entitlements.plist @@ -8,5 +8,13 @@ com.apple.private.network.socket-delegate + com.apple.private.network.delegation-whitelist + + com.apple.private.keychain.certificates + + com.apple.private.assets.accessible-asset-types + + com.apple.MobileAsset.CertificatePinning + diff --git a/OSX/trustd/macOS/trustd.8 b/OSX/trustd/macOS/trustd.8 new file mode 100644 index 00000000..21914269 --- /dev/null +++ b/OSX/trustd/macOS/trustd.8 @@ -0,0 +1,14 @@ +.Dd Sat Jan 14 2017 \" DATE +.Dt trustd 8 \" Program name and manual section number +.Os +.Sh NAME \" Section Header - required - don't modify +.Nm trustd +.Nd Daemon and LaunchAgent that performs trust evaluations +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Sh DESCRIPTION \" Section Header - required - don't modify +.Nm +provides services for evaluating trust in certificates for all processes on +the system. +.Pp +This command is not intended to be invoked directly. diff --git a/OSX/trustd/trustd-Info.plist b/OSX/trustd/trustd-Info.plist index 78df5db9..df9088c6 100644 --- a/OSX/trustd/trustd-Info.plist +++ b/OSX/trustd/trustd-Info.plist @@ -21,7 +21,7 @@ CFBundleVersion ${CURRENT_PROJECT_VERSION} NSHumanReadableCopyright - Copyright © 2015 Apple. All rights reserved. + Copyright © 2015-2017 Apple. All rights reserved. XPCService ServiceType diff --git a/OSX/trustd/trustd.c b/OSX/trustd/trustd.c new file mode 100644 index 00000000..503aaa6b --- /dev/null +++ b/OSX/trustd/trustd.c @@ -0,0 +1,655 @@ +/* + * 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@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if TARGET_OS_OSX +#include +#include +#include +#endif + +#include "OTATrustUtilities.h" + +static struct trustd trustd_spi = { + .sec_trust_store_for_domain = SecTrustStoreForDomainName, + .sec_trust_store_contains = SecTrustStoreContainsCertificateWithDigest, + .sec_trust_store_set_trust_settings = _SecTrustStoreSetTrustSettings, + .sec_trust_store_remove_certificate = SecTrustStoreRemoveCertificateWithDigest, + .sec_truststore_remove_all = _SecTrustStoreRemoveAll, + .sec_trust_evaluate = SecTrustServerEvaluate, + .sec_ota_pki_asset_version = SecOTAPKIGetCurrentAssetVersion, + .ota_CopyEscrowCertificates = SecOTAPKICopyCurrentEscrowCertificates, + .sec_ota_pki_get_new_asset = SecOTAPKISignalNewAsset, + .sec_trust_store_copy_all = _SecTrustStoreCopyAll, + .sec_trust_store_copy_usage_constraints = _SecTrustStoreCopyUsageConstraints, +}; + +static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, SecCertificatePathRef path, CFErrorRef *error) { + if (!path) + return true; + xpc_object_t xpc_chain = SecCertificatePathCopyXPCArray(path, error); + if (!xpc_chain) + return false; + + xpc_dictionary_set_value(message, key, xpc_chain); + xpc_release(xpc_chain); + return true; +} + +static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) { + size_t length = 0; + const void *bytes = xpc_dictionary_get_data(message, key, &length); + if (bytes) { + SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length); + if (certificate) + return certificate; + SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key); + } else { + SecError(errSecParam, error, CFSTR("object for key %s missing"), key); + } + return NULL; +} + +static bool SecXPCDictionaryCopyCertificates(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) { + xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key); + if (!xpc_certificates) + return SecError(errSecAllocate, error, CFSTR("no certs for key %s"), key); + *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error); + return *certificates; +} + +static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) { + xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key); + if (!xpc_certificates) { + *certificates = NULL; + return true; + } + *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error); + return *certificates; +} + +static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message, const char *key, CFArrayRef *policies, CFErrorRef *error) { + xpc_object_t xpc_policies = xpc_dictionary_get_value(message, key); + if (!xpc_policies) { + if (policies) + *policies = NULL; + return true; + } + *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error); + return *policies != NULL; +} + +// Returns error if entitlement isn't present. +static bool +EntitlementPresentAndTrue(uint64_t op, SecTaskRef clientTask, CFStringRef entitlement, CFErrorRef *error) +{ + if (!SecTaskGetBooleanValueForEntitlement(clientTask, entitlement)) { + SecError(errSecMissingEntitlement, error, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation)op), clientTask, entitlement); + return false; + } + return true; +} + +static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) { + SecTrustStoreRef ts = NULL; + CFStringRef domain = SecXPCDictionaryCopyString(message, key, error); + if (domain) { + ts = SecTrustStoreForDomainName(domain, error); + CFRelease(domain); + } + return ts; +} + +static bool SecXPCTrustStoreContains(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { + bool result = false; + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); + if (digest) { + bool contains; + if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, error)) { + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, contains); + result = true; + } + CFReleaseNull(digest); + } + } + return result; +} + +static bool SecXPCTrustStoreSetTrustSettings(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { + bool noError = false; + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, error); + if (certificate) { + CFTypeRef trustSettingsDictOrArray = NULL; + if (SecXPCDictionaryCopyPListOptional(event, kSecXPCKeySettings, &trustSettingsDictOrArray, error)) { + bool result = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray, error); + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); + noError = true; + CFReleaseSafe(trustSettingsDictOrArray); + } + CFReleaseNull(certificate); + } + } + return noError; +} + +static bool SecXPCTrustStoreRemoveCertificate(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { + bool noError = false; + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); + if (digest) { + bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, error); + xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result); + noError = true; + CFReleaseNull(digest); + } + } + return noError; +} + +static bool SecXPCTrustStoreCopyAll(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { + bool result = false; + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + CFArrayRef trustStoreContents = NULL; + if(_SecTrustStoreCopyAll(ts, &trustStoreContents, error) && trustStoreContents) { + SecXPCDictionarySetPList(reply, kSecXPCKeyResult, trustStoreContents, error); + CFReleaseNull(trustStoreContents); + result = true; + } + } + return result; +} + +static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { + bool result = false; + SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error); + if (ts) { + CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error); + if (digest) { + CFArrayRef usageConstraints = NULL; + if(_SecTrustStoreCopyUsageConstraints(ts, digest, &usageConstraints, error) && usageConstraints) { + SecXPCDictionarySetPList(reply, kSecXPCKeyResult, usageConstraints, error); + CFReleaseNull(usageConstraints); + result = true; + } + CFReleaseNull(digest); + } + } + return result; +} + +static bool SecXPC_OTAPKI_GetAssetVersion(xpc_object_t __unused event, xpc_object_t reply, CFErrorRef *error) { + xpc_dictionary_set_int64(reply, kSecXPCKeyResult, SecOTAPKIGetCurrentAssetVersion(error)); + return true; +} + +static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) { + bool result = false; + uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType"); + CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, error); + if (array) { + xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array); + xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_array); + xpc_release(xpc_array); + result = true; + } + CFReleaseNull(array); + return result; +} + +static bool SecXPC_OTAPKI_GetNewAsset(xpc_object_t __unused event, xpc_object_t reply, CFErrorRef *error) { + xpc_dictionary_set_int64(reply, kSecXPCKeyResult, SecOTAPKISignalNewAsset(error)); + return true; +} + +typedef bool(*SecXPCOperationHandler)(xpc_object_t event, xpc_object_t reply, CFErrorRef *error); + +typedef struct { + CFStringRef entitlement; + SecXPCOperationHandler handler; +} SecXPCServerOperation; + +struct trustd_operations { + SecXPCServerOperation trust_store_contains; + SecXPCServerOperation trust_store_set_trust_settings; + SecXPCServerOperation trust_store_remove_certificate; + SecXPCServerOperation trust_store_copy_all; + SecXPCServerOperation trust_store_copy_usage_constraints; + SecXPCServerOperation ota_pki_asset_version; + SecXPCServerOperation ota_pki_get_escrow_certs; + SecXPCServerOperation ota_pki_get_new_asset; +}; + +static struct trustd_operations trustd_ops = { + .trust_store_contains = { NULL, SecXPCTrustStoreContains }, + .trust_store_set_trust_settings = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreSetTrustSettings }, + .trust_store_remove_certificate = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreRemoveCertificate }, + .trust_store_copy_all = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyAll }, + .trust_store_copy_usage_constraints = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyUsageConstraints }, + .ota_pki_asset_version = { NULL, SecXPC_OTAPKI_GetAssetVersion }, + .ota_pki_get_escrow_certs = { NULL, SecXPC_OTAPKI_GetEscrowCertificates }, + .ota_pki_get_new_asset = { NULL, SecXPC_OTAPKI_GetNewAsset }, +}; + +static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc_object_t event) { + xpc_type_t type = xpc_get_type(event); + __block CFErrorRef error = NULL; + xpc_object_t xpcError = NULL; + xpc_object_t replyMessage = NULL; + CFDataRef clientAuditToken = NULL; + CFArrayRef domains = NULL; + SecurityClient client = { + .task = NULL, + .accessGroups = NULL, + .musr = NULL, + .uid = xpc_connection_get_euid(connection), + .allowSystemKeychain = true, + .allowSyncBubbleKeychain = false, + .isNetworkExtension = false, + .canAccessNetworkExtensionAccessGroups = false, +#if TARGET_OS_IPHONE + .inMultiUser = false, +#endif + }; + + secdebug("serverxpc", "entering"); + if (type == XPC_TYPE_DICTIONARY) { + // TODO: Find out what we're dispatching. + replyMessage = xpc_dictionary_create_reply(event); + + + uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation); + + audit_token_t auditToken = {}; + xpc_connection_get_audit_token(connection, &auditToken); + + client.task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); + clientAuditToken = CFDataCreate(kCFAllocatorDefault, (const UInt8*)&auditToken, sizeof(auditToken)); + client.accessGroups = SecTaskCopyAccessGroups(client.task); + + secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64 ")", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation); + + if (operation == sec_trust_evaluate_id) { + CFArrayRef certificates = NULL, anchors = NULL, policies = NULL, responses = NULL, scts = NULL, trustedLogs = NULL, exceptions = NULL; + bool anchorsOnly = xpc_dictionary_get_bool(event, kSecTrustAnchorsOnlyKey); + bool keychainsAllowed = xpc_dictionary_get_bool(event, kSecTrustKeychainsAllowedKey); + double verifyTime; + if (SecXPCDictionaryCopyCertificates(event, kSecTrustCertificatesKey, &certificates, &error) && + SecXPCDictionaryCopyCertificatesOptional(event, kSecTrustAnchorsKey, &anchors, &error) && + SecXPCDictionaryCopyPoliciesOptional(event, kSecTrustPoliciesKey, &policies, &error) && + SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustResponsesKey, &responses, &error) && + SecXPCDictionaryCopyCFDataArrayOptional(event, kSecTrustSCTsKey, &scts, &error) && + SecXPCDictionaryCopyArrayOptional(event, kSecTrustTrustedLogsKey, &trustedLogs, &error) && + SecXPCDictionaryGetDouble(event, kSecTrustVerifyDateKey, &verifyTime, &error) && + SecXPCDictionaryCopyArrayOptional(event, kSecTrustExceptionsKey, &exceptions, &error)) { + // If we have no error yet, capture connection and reply in block and properly retain them. + xpc_retain(connection); + CFRetainSafe(client.task); + CFRetainSafe(clientAuditToken); + + // Clear replyMessage so we don't send a synchronous reply. + xpc_object_t asyncReply = replyMessage; + replyMessage = NULL; + + SecTrustServerEvaluateBlock(clientAuditToken, certificates, anchors, anchorsOnly, keychainsAllowed, policies, + responses, scts, trustedLogs, verifyTime, client.accessGroups, exceptions, + ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, + CFErrorRef replyError) { + // Send back reply now + if (replyError) { + CFRetain(replyError); + } else { + xpc_dictionary_set_int64(asyncReply, kSecTrustResultKey, tr); + SecXPCDictionarySetPListOptional(asyncReply, kSecTrustDetailsKey, details, &replyError) && + SecXPCDictionarySetPListOptional(asyncReply, kSecTrustInfoKey, info, &replyError) && + SecXPCDictionarySetChainOptional(asyncReply, kSecTrustChainKey, chain, &replyError); + } + if (replyError) { + secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError); + xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError); + if (xpcReplyError) { + xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError); + xpc_release(xpcReplyError); + } + CFReleaseNull(replyError); + } else { + secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply); + } + + xpc_connection_send_message(connection, asyncReply); + xpc_release(asyncReply); + xpc_release(connection); + CFReleaseSafe(client.task); + CFReleaseSafe(clientAuditToken); + }); + } + CFReleaseSafe(policies); + CFReleaseSafe(anchors); + CFReleaseSafe(certificates); + CFReleaseSafe(responses); + CFReleaseSafe(scts); + CFReleaseSafe(trustedLogs); + CFReleaseSafe(exceptions); + } else { + SecXPCServerOperation *server_op = NULL; + switch (operation) { + case sec_trust_store_contains_id: + server_op = &trustd_ops.trust_store_contains; + break; + case sec_trust_store_set_trust_settings_id: + server_op = &trustd_ops.trust_store_set_trust_settings; + break; + case sec_trust_store_remove_certificate_id: + server_op = &trustd_ops.trust_store_remove_certificate; + break; + case sec_trust_store_copy_all_id: + server_op = &trustd_ops.trust_store_copy_all; + break; + case sec_trust_store_copy_usage_constraints_id: + server_op = &trustd_ops.trust_store_copy_usage_constraints; + break; + case sec_ota_pki_asset_version_id: + server_op = &trustd_ops.ota_pki_asset_version; + break; + case kSecXPCOpOTAGetEscrowCertificates: + server_op = &trustd_ops.ota_pki_get_escrow_certs; + break; + case kSecXPCOpOTAPKIGetNewAsset: + server_op = &trustd_ops.ota_pki_get_new_asset; + break; + default: + break; + } + if (server_op && server_op->handler) { + bool entitled = true; + if (server_op->entitlement) { + entitled = EntitlementPresentAndTrue(operation, client.task, server_op->entitlement, &error); + } + if (entitled) { + (void)server_op->handler(event, replyMessage, &error); + } + } + } + + if (error) + { + if(SecErrorGetOSStatus(error) == errSecItemNotFound) + secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); + else if (SecErrorGetOSStatus(error) == errSecAuthNeeded) + secwarning("Authentication is needed %@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); + else + secerror("%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error); + + xpcError = SecCreateXPCObjectWithCFError(error); + if (replyMessage) { + xpc_dictionary_set_value(replyMessage, kSecXPCKeyError, xpcError); + } + } else if (replyMessage) { + secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyMessage); + } + } else { + SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, &error, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event); + secerror("%@: returning error: %@", client.task, error); + xpcError = SecCreateXPCObjectWithCFError(error); + replyMessage = xpc_create_reply_with_format(event, "{%string: %value}", kSecXPCKeyError, xpcError); + } + + if (replyMessage) { + xpc_connection_send_message(connection, replyMessage); + xpc_release(replyMessage); + } + if (xpcError) + xpc_release(xpcError); + CFReleaseSafe(error); + CFReleaseSafe(client.accessGroups); + CFReleaseSafe(client.musr); + CFReleaseSafe(client.task); + CFReleaseSafe(domains); + CFReleaseSafe(clientAuditToken); +} + +static void trustd_xpc_init(const char *service_name) +{ + secdebug("serverxpc", "start"); + xpc_connection_t listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); + if (!listener) { + seccritical("security failed to register xpc listener for %s, exiting", service_name); + abort(); + } + + xpc_connection_set_event_handler(listener, ^(xpc_object_t connection) { + if (xpc_get_type(connection) == XPC_TYPE_CONNECTION) { + xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { + if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { + xpc_retain(connection); + xpc_retain(event); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + trustd_xpc_dictionary_handler(connection, event); + xpc_release(event); + xpc_release(connection); + }); + } + }); + xpc_connection_resume(connection); + } + }); + xpc_connection_resume(listener); +} + +static void trustd_delete_old_files(void) { + +#if TARGET_OS_EMBEDDED + if (getuid() != 64) // _securityd +#else + if (getuid() != 0) +#endif + { return; } + /* If we get past this line, then we can attempt to delete old revocation files; + otherwise we won't have sufficient privilege. */ + + /* We try to clean up after ourselves, but don't care if we succeed. */ + WithPathInRevocationInfoDirectory(CFSTR("update-current"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String) { + (void)remove(utf8String); + }); +} + +#if TARGET_OS_OSX +static void trustd_delete_old_caches(void) { + /* We try to clean up after ourselves, but don't care if we succeed. */ + WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-wal"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-shm"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-journal"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-wal"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-shm"), ^(const char *utf8String) { + (void)remove(utf8String); + }); + WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-journal"), ^(const char *utf8String) { + (void)remove(utf8String); + }); +} + +static void trustd_sandbox(void) { + char buf[PATH_MAX] = ""; + + if (!_set_user_dir_suffix("com.apple.trustd") || + confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)) == 0 || + (mkdir(buf, 0700) && errno != EEXIST)) { + secerror("failed to initialize temporary directory (%d): %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + char *tempdir = realpath(buf, NULL); + if (tempdir == NULL) { + secerror("failed to resolve temporary directory (%d): %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (confstr(_CS_DARWIN_USER_CACHE_DIR, buf, sizeof(buf)) == 0 || + (mkdir(buf, 0700) && errno != EEXIST)) { + secerror("failed to initialize cache directory (%d): %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + char *cachedir = realpath(buf, NULL); + if (cachedir == NULL) { + secerror("failed to resolve cache directory (%d): %s", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + const char *parameters[] = { + "_TMPDIR", tempdir, + "_DARWIN_CACHE_DIR", cachedir, + NULL + }; + + char *sberror = NULL; + if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED, parameters, &sberror) != 0) { + secerror("Failed to enter trustd sandbox: %{public}s", sberror); + exit(EXIT_FAILURE); + } + + free(tempdir); + free(cachedir); +} +#else +static void trustd_sandbox(void) { + char buf[PATH_MAX] = ""; + _set_user_dir_suffix("com.apple.trustd"); + confstr(_CS_DARWIN_USER_TEMP_DIR, buf, sizeof(buf)); +} +#endif + +int main(int argc, char *argv[]) +{ + char *wait4debugger = getenv("WAIT4DEBUGGER"); + if (wait4debugger && !strcasecmp("YES", wait4debugger)) { + seccritical("SIGSTOPing self, awaiting debugger"); + kill(getpid(), SIGSTOP); + seccritical("Again, for good luck (or bad debuggers)"); + kill(getpid(), SIGSTOP); + } + + /* Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites + Our process doesn't realize DB connections get invalidated when network home directory users logout + and their home gets unmounted. Exit our process and start fresh when user logs back in. + */ +#if TARGET_OS_OSX + int sessionstatechanged_tok; + notify_register_dispatch(kSA_SessionStateChangedNotification, &sessionstatechanged_tok, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int token __unused) { + // we could be a process running as root. + // However, since root never logs out this isn't an issue. + if (SASSessionStateForUser(getuid()) == kSA_state_loggingout_pointofnoreturn) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + xpc_transaction_exit_clean(); + }); + } + }); +#endif + +#if TARGET_OS_OSX + /* Before we enter the sandbox, we need to delete the old caches kept in ~/Library/Keychains + * After we enter the sandbox, we won't be able to access them. */ + trustd_delete_old_caches(); +#endif + /* Also clean up old files in /Library/Keychains/crls */ + trustd_delete_old_files(); + + trustd_sandbox(); + + const char *serviceName = kTrustdXPCServiceName; + if (argc > 1 && (!strcmp(argv[1], "--agent"))) { + serviceName = kTrustdAgentXPCServiceName; + } + + /* set up SQLite before some other component has a chance to create a database connection */ + _SecDbServerSetup(); + + /* set up revocation database if it doesn't already exist, or needs to be replaced */ + SecRevocationDbInitialize(); + + gTrustd = &trustd_spi; + SecPolicyServerInitialize(); + SecPinningDbInitialize(); +#if TARGET_OS_OSX + SecTrustLegacySourcesListenForKeychainEvents(); +#endif + trustd_xpc_init(serviceName); + + dispatch_main(); +} diff --git a/OSX/utilities/Regressions/su-41-secdb-stress.c b/OSX/utilities/Regressions/su-41-secdb-stress.c index 32c8f15a..15d9723a 100644 --- a/OSX/utilities/Regressions/su-41-secdb-stress.c +++ b/OSX/utilities/Regressions/su-41-secdb-stress.c @@ -190,7 +190,7 @@ static void tests(void) CFStringRef dbName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s/Library/Keychains/su-41-sqldb-stress.db"), home_var ? home_var : ""); CFStringPerformWithCString(dbName, ^(const char *path) { unlink(path); }); - SecDbRef db = SecDbCreate(dbName, ^bool (SecDbConnectionRef dbconn, bool did_create, bool *callMeAgainForNextConnection, CFErrorRef *firstOpenError) { + SecDbRef db = SecDbCreate(dbName, ^bool (SecDbRef db, SecDbConnectionRef dbconn, bool did_create, bool *callMeAgainForNextConnection, CFErrorRef *firstOpenError) { // This test will run when the database is first opened. return ts_ok(SecDbExec(dbconn, CFSTR("CREATE TABLE tablea(key TEXT,value BLOB);"), firstOpenError), "create table: %@", *firstOpenError); diff --git a/OSX/utilities/Regressions/utilities_regressions.h b/OSX/utilities/Regressions/utilities_regressions.h index ce83dc64..6d69eb3e 100644 --- a/OSX/utilities/Regressions/utilities_regressions.h +++ b/OSX/utilities/Regressions/utilities_regressions.h @@ -2,7 +2,7 @@ 1) add it here 2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes */ -#include +#include ONE_TEST(su_07_debugging) ONE_TEST(su_05_cfwrappers) diff --git a/OSX/utilities/SecurityTool/readline.c b/OSX/utilities/SecurityTool/readline.c index 14ef05ef..727ca6a8 100644 --- a/OSX/utilities/SecurityTool/readline.c +++ b/OSX/utilities/SecurityTool/readline.c @@ -139,6 +139,10 @@ read_file(const char *name, uint8_t **outData, size_t *outLength) length = (size_t)off_end; buffer = malloc(length); + if (buffer == NULL) { + result = -1; + goto loser; + } do { bytes_read = pread(fd, buffer, length, 0); diff --git a/OSX/utilities/src/SecADWrapper.c b/OSX/utilities/src/SecADWrapper.c index 4b3e1d3e..3f50e112 100644 --- a/OSX/utilities/src/SecADWrapper.c +++ b/OSX/utilities/src/SecADWrapper.c @@ -63,33 +63,40 @@ setup(void) }); return bundle != NULL; } +#endif void SecADClearScalarKey(CFStringRef key) { +#if TARGET_OS_EMBEDDED if (setup()) soft_ADClientClearScalarKey(key); +#endif } void SecADSetValueForScalarKey(CFStringRef key, int64_t value) { +#if TARGET_OS_EMBEDDED if (setup()) soft_ADClientSetValueForScalarKey(key, value); - +#endif } void SecADAddValueForScalarKey(CFStringRef key, int64_t value) { +#if TARGET_OS_EMBEDDED if (setup()) soft_ADClientAddValueForScalarKey(key, value); +#endif } void SecADClientPushValueForDistributionKey(CFStringRef key, int64_t value) { +#if TARGET_OS_EMBEDDED if (setup()) soft_ADClientPushValueForDistributionKey(key, value); +#endif } -#endif diff --git a/OSX/utilities/src/SecADWrapper.h b/OSX/utilities/src/SecADWrapper.h index 3a7fbe07..3ea457f0 100644 --- a/OSX/utilities/src/SecADWrapper.h +++ b/OSX/utilities/src/SecADWrapper.h @@ -27,11 +27,9 @@ #include #include -#if TARGET_OS_EMBEDDED 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 #endif /* SecADWrapper_h */ diff --git a/OSX/utilities/src/SecAKSWrappers.h b/OSX/utilities/src/SecAKSWrappers.h index e2c8e371..86964c3d 100644 --- a/OSX/utilities/src/SecAKSWrappers.h +++ b/OSX/utilities/src/SecAKSWrappers.h @@ -32,22 +32,28 @@ #include +#ifdef USE_KEYSTORE +#define TARGET_HAS_KEYSTORE USE_KEYSTORE +#else + #if RC_HORIZON -#define TARGET_HAS_KEYSTORE 0 + #define TARGET_HAS_KEYSTORE 0 #elif TARGET_OS_SIMULATOR -#define TARGET_HAS_KEYSTORE 0 + #define TARGET_HAS_KEYSTORE 0 #elif TARGET_OS_OSX -#if TARGET_CPU_X86 -#define TARGET_HAS_KEYSTORE 0 -#else -#define TARGET_HAS_KEYSTORE 1 -#endif + #if TARGET_CPU_X86 + #define TARGET_HAS_KEYSTORE 0 + #else + #define TARGET_HAS_KEYSTORE 1 + #endif #elif TARGET_OS_EMBEDDED -#define TARGET_HAS_KEYSTORE 1 + #define TARGET_HAS_KEYSTORE 1 #else -#error "unknown keystore status for this platform" + #error "unknown keystore status for this platform" #endif +#endif // USE_KEYSTORE + #if !TARGET_HAS_KEYSTORE #include diff --git a/OSX/utilities/src/SecCFCCWrappers.c b/OSX/utilities/src/SecCFCCWrappers.c index 9f52ebd7..588b9de2 100644 --- a/OSX/utilities/src/SecCFCCWrappers.c +++ b/OSX/utilities/src/SecCFCCWrappers.c @@ -36,8 +36,19 @@ CFDataRef CFDataCreateSHA1DigestWithBytes(CFAllocatorRef allocator, size_t len, return CFDataCreateDigestWithBytes(allocator, ccsha1_di(), len, data, error); } +CFDataRef CFDataCreateSHA256DigestWithBytes(CFAllocatorRef allocator, size_t len, const void *data, CFErrorRef *error) { + return CFDataCreateDigestWithBytes(allocator, ccsha256_di(), len, data, error); +} + + CFDataRef CFDataCopySHA1Digest(CFDataRef dataToDigest, CFErrorRef *error) { CFIndex length = CFDataGetLength(dataToDigest); assert((unsigned long)length < UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ return CFDataCreateSHA1DigestWithBytes(CFGetAllocator(dataToDigest), length, CFDataGetBytePtr(dataToDigest), error); } + +CFDataRef CFDataCopySHA256Digest(CFDataRef dataToDigest, CFErrorRef *error) { + CFIndex length = CFDataGetLength(dataToDigest); + assert((unsigned long)length < UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */ + return CFDataCreateSHA256DigestWithBytes(CFGetAllocator(dataToDigest), length, CFDataGetBytePtr(dataToDigest), error); +} diff --git a/OSX/utilities/src/SecCFCCWrappers.h b/OSX/utilities/src/SecCFCCWrappers.h index 44ba96ae..47a0ba2e 100644 --- a/OSX/utilities/src/SecCFCCWrappers.h +++ b/OSX/utilities/src/SecCFCCWrappers.h @@ -28,6 +28,7 @@ #include #include +#include __BEGIN_DECLS @@ -35,8 +36,10 @@ CFDataRef CFDataCreateDigestWithBytes(CFAllocatorRef allocator, const struct ccd const void *data, CFErrorRef *error); CFDataRef CFDataCreateSHA1DigestWithBytes(CFAllocatorRef allocator, size_t len, const void *data, CFErrorRef *error); +CFDataRef CFDataCreateSHA256DigestWithBytes(CFAllocatorRef allocator, size_t len, const void *data, CFErrorRef *error); CFDataRef CFDataCopySHA1Digest(CFDataRef dataToDigest, CFErrorRef *error); +CFDataRef CFDataCopySHA256Digest(CFDataRef dataToDigest, CFErrorRef *error); __END_DECLS diff --git a/OSX/utilities/src/SecCFError.c b/OSX/utilities/src/SecCFError.c index bb5e1e9f..0aebede6 100644 --- a/OSX/utilities/src/SecCFError.c +++ b/OSX/utilities/src/SecCFError.c @@ -162,16 +162,6 @@ bool SecAllocationError(const void *allocated, CFErrorRef *error, CFStringRef fo return false; } - -bool SecCFCreateError(CFIndex errorCode, CFStringRef domain, CFStringRef descriptionString, - CFErrorRef previousError, CFErrorRef *newError) -{ -#pragma clang diagnostic push -#pragma GCC diagnostic ignored "-Wformat-security" - return SecCFCreateErrorWithFormat(errorCode, domain, previousError, newError, NULL, descriptionString); -#pragma clang diagnostic pop -} - bool SecCFCreateErrorWithFormat(CFIndex errorCode, CFStringRef domain, CFErrorRef previousError, CFErrorRef *newError, CFDictionaryRef formatoptions, CFStringRef format, ...) { diff --git a/OSX/utilities/src/SecCFError.h b/OSX/utilities/src/SecCFError.h index 419c34a2..bc6ea016 100644 --- a/OSX/utilities/src/SecCFError.h +++ b/OSX/utilities/src/SecCFError.h @@ -34,39 +34,47 @@ // kern_return_t errors #define kSecKernDomain kCFErrorDomainMach -bool SecKernError(kern_return_t result, CFErrorRef *error, CFStringRef format, ...); +bool SecKernError(kern_return_t result, CFErrorRef *error, CFStringRef format, ...) + CF_FORMAT_FUNCTION(3, 4); // Unix errno errors #define kSecErrnoDomain kCFErrorDomainPOSIX -bool SecCheckErrno(int result, CFErrorRef *error, CFStringRef format, ...); +bool SecCheckErrno(int result, CFErrorRef *error, CFStringRef format, ...) + CF_FORMAT_FUNCTION(3, 4); // OSStatus errors #define kSecErrorDomain kCFErrorDomainOSStatus -bool SecError(OSStatus status, 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, ...); +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, ...); +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, ...); +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, ...); +bool SecRequirementError(bool requirement, CFErrorRef *error, CFStringRef format, ...) + CF_FORMAT_FUNCTION(3, 4); // Allocation failure -bool SecAllocationError(const void *allocated, CFErrorRef *error, CFStringRef format, ...); - +bool SecAllocationError(const void *allocated, CFErrorRef *error, CFStringRef format, ...) + CF_FORMAT_FUNCTION(3, 4); // // Create and chain, all return false to make the analyzer happy. // -bool SecCFCreateError(CFIndex errorCode, CFStringRef domain, CFStringRef descriptionString, - CFErrorRef previousError, CFErrorRef *newError); +#define SecCFCreateError(errorCode, domain, descriptionString, previousError, newError) \ + SecCFCreateErrorWithFormat(errorCode, domain, previousError, newError, NULL, descriptionString) bool SecCFCreateErrorWithFormat(CFIndex errorCode, CFStringRef domain, CFErrorRef previousError, CFErrorRef *newError, CFDictionaryRef formatoptions, CFStringRef descriptionString, ...) diff --git a/OSX/utilities/src/SecCFWrappers.h b/OSX/utilities/src/SecCFWrappers.h index 19f93a0b..9598944e 100644 --- a/OSX/utilities/src/SecCFWrappers.h +++ b/OSX/utilities/src/SecCFWrappers.h @@ -84,6 +84,7 @@ extern CFStringRef kSecDebugFormatOption; extern CFDictionaryRef SecGetDebugDescriptionFormatOptions(void); +typedef void (^SecBoolCFErrorCallback) (bool, CFErrorRef); #define CFGiblisGetSingleton(returnType, giblisClassName, result, doThisOnce) \ returnType giblisClassName(void); \ @@ -97,7 +98,7 @@ returnType giblisClassName(void) { \ #define CFGiblisWithFunctions(gibliClassName, init_func, copy_func, finalize_func, equal_func, hash_func, copyFormattingDesc_func, copyDebugDesc_func, reclaim_func, refcount_func, run_once_block) \ CFGiblisGetSingleton(CFTypeID, gibliClassName##GetTypeID, typeID, (^{ \ - void(^_onceBlock)() = (run_once_block); \ + void (^ const _onceBlock)(void) = (run_once_block); \ static const CFRuntimeClass s##gibliClassName##Class = { \ .version = (reclaim_func == NULL ? 0 : _kCFRuntimeResourcefulObject) \ | (refcount_func == NULL ? 0 : _kCFRuntimeCustomRefCount), \ @@ -250,19 +251,15 @@ static void fprint_string(FILE *file, CFStringRef string) { } } +static inline void cffprint_v(FILE *file, CFStringRef fmt, va_list args) CF_FORMAT_FUNCTION(2, 0); +static void cffprint(FILE *file, CFStringRef fmt, ...) CF_FORMAT_FUNCTION(2,0); + static inline void cffprint_v(FILE *file, CFStringRef fmt, va_list args) { CFStringRef line = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, args); fprint_string(file, line); CFRelease(line); } -static inline void cffprint_c_v(FILE *file, const char *fmt, va_list args) { - CFStringRef cffmt = CFStringCreateWithCString(kCFAllocatorDefault, fmt, kCFStringEncodingUTF8); - cffprint_v(file, cffmt, args); - CFRelease(cffmt); -} - -static void cffprint(FILE *file, CFStringRef fmt, ...) CF_FORMAT_FUNCTION(2,0); static inline void cffprint(FILE *file, CFStringRef fmt, ...) { va_list args; va_start(args, fmt); diff --git a/OSX/utilities/src/SecCertificateTrace.c b/OSX/utilities/src/SecCertificateTrace.c deleted file mode 100644 index e9b9eda2..00000000 --- a/OSX/utilities/src/SecCertificateTrace.c +++ /dev/null @@ -1,549 +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 "SecCertificateTrace.h" -#include -#include -#include "SecCFWrappers.h" -#include -#include -#include "debugging.h" - -#define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); - -SEC_CONST_DECL (kCertStatsPrefix, "com.apple.certstats"); -SEC_CONST_DECL (kCertStatsCert, "cert"); -SEC_CONST_DECL (kCertStatsPolicy, "id"); -SEC_CONST_DECL (kCertStatsNotBefore, "nb"); -SEC_CONST_DECL (kCertStatsNotAfter, "na"); -SEC_CONST_DECL (kCertStatsSerialNumber, "sn"); -SEC_CONST_DECL (kCertStatsSubjectSummary, "s"); -SEC_CONST_DECL (kCertStatsIssuerSummary, "i"); - -static const CFStringRef kCertStatsFormat = CFSTR("%@/%@=%@/%@=%@/%@=%@/%@=%@/%@=%@/%@=%@"); -static const CFStringRef kCertStatsDelimiters = CFSTR("/"); - -bool SetCertificateTraceValueForKey(CFStringRef key, int64_t value); -void* BeginCertificateLoggingTransaction(void); -bool AddKeyValuePairToCertificateLoggingTransaction(void* token, CFStringRef key, int64_t value); -void CloseCertificateLoggingTransaction(void* token); -CFStringRef SecCFStringCopyEncodingDelimiters(CFStringRef str, CFStringRef delimiters); - -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) -#include - -static const char* gTopLevelKeyForCertificateTracing = "com.apple.certstats"; - -static const char* gMessageTracerSetPrefix = "com.apple.message."; - -static const char* gMessageTracerDomainField = "com.apple.message.domain"; - -/* -------------------------------------------------------------------------- - Function: OSX_BeginCertificateLoggingTransaction - - Description: For OSX, the message tracer back end wants its logging - done in "bunches". This function allows for beginning - a 'transaction' of logging which will allow for putting - all of the transaction's items into a single log making - the message tracer folks happy. - - The work of this function is to create the aslmsg context - and set the domain field and then return the aslmsg - context as a void* result. - -------------------------------------------------------------------------- */ -static void* OSX_BeginCertificateLoggingTransaction() -{ - void* result = NULL; - aslmsg mAsl = NULL; - mAsl = asl_new(ASL_TYPE_MSG); - if (NULL == mAsl) - { - return result; - } - - asl_set(mAsl, gMessageTracerDomainField, gTopLevelKeyForCertificateTracing); - - result = (void *)mAsl; - return result; -} - -/* -------------------------------------------------------------------------- - Function: OSX_AddKeyValuePairToCertificateLoggingTransaction - - Description: Once a call to OSX_BeginCertificateLoggingTransaction - is done, this call will allow for adding items to the - "bunch" of items being logged. - - NOTE: The key should be a simple key such as - "numberOfPeers". This is because this function will - append the required prefix of "com.apple.message." - -------------------------------------------------------------------------- */ -static bool OSX_AddKeyValuePairToCertificateLoggingTransaction(void* token, CFStringRef key, int64_t value) -{ - if (NULL == token || NULL == key) - { - return false; - } - - aslmsg mAsl = (aslmsg)token; - - // Fix up the key - CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key); - if (NULL == real_key) - { - return false; - } - - CFIndex key_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key), kCFStringEncodingUTF8); - key_length += 1; // For null - char key_buffer[key_length]; - memset(key_buffer, 0,key_length); - if (!CFStringGetCString(real_key, key_buffer, key_length, kCFStringEncodingUTF8)) - { - CFRelease(real_key); - return false; - } - CFRelease(real_key); - - CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value); - if (NULL == value_str) - { - return false; - } - - CFIndex value_str_numBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str), kCFStringEncodingUTF8); - value_str_numBytes += 1; // For null - char value_buffer[value_str_numBytes]; - memset(value_buffer, 0, value_str_numBytes); - if (!CFStringGetCString(value_str, value_buffer, value_str_numBytes, kCFStringEncodingUTF8)) - { - CFRelease(value_str); - return false; - } - CFRelease(value_str); - - asl_set(mAsl, key_buffer, value_buffer); - return true; -} - -/* -------------------------------------------------------------------------- - Function: OSX_CloseCertificateLoggingTransaction - - Description: Once a call to OSX_BeginCertificateLoggingTransaction - is done, and all of the items that are to be in the - "bunch" of items being logged, this function will do the - real logging and free the aslmsg context. - -------------------------------------------------------------------------- */ -static void OSX_CloseCertificateLoggingTransaction(void* token) -{ - if (NULL != token) - { - aslmsg mAsl = (aslmsg)token; - asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, ""); - asl_free(mAsl); - } -} - -/* -------------------------------------------------------------------------- - Function: OSX_SetCertificateTraceValueForKey - - Description: If "bunching" of items either cannot be done or is not - desired, then this 'single shot' function should be used. - It will create the aslmsg context, register the domain, - fix up the key and log the key value pair, and then - do the real logging and free the aslmsg context. - -------------------------------------------------------------------------- */ -static bool OSX_SetCertificateTraceValueForKey(CFStringRef key, int64_t value) -{ - bool result = false; - - if (NULL == key) - { - return result; - } - - aslmsg mAsl = NULL; - mAsl = asl_new(ASL_TYPE_MSG); - if (NULL == mAsl) - { - return result; - } - - // Fix up the key - CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key); - if (NULL == real_key) - { - return false; - } - - CFIndex key_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key), kCFStringEncodingUTF8); - key_length += 1; // For null - char key_buffer[key_length]; - memset(key_buffer, 0,key_length); - if (!CFStringGetCString(real_key, key_buffer, key_length, kCFStringEncodingUTF8)) - { - CFRelease(real_key); - return false; - } - CFRelease(real_key); - - - CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value); - if (NULL == value_str) - { - asl_free(mAsl); - return result; - } - - CFIndex value_str_numBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str), kCFStringEncodingUTF8); - value_str_numBytes += 1; // For null - char value_buffer[value_str_numBytes]; - memset(value_buffer, 0, value_str_numBytes); - if (!CFStringGetCString(value_str, value_buffer, value_str_numBytes, kCFStringEncodingUTF8)) - { - asl_free(mAsl); - CFRelease(value_str); - return result; - } - CFRelease(value_str); - - /* Domain */ - asl_set(mAsl, gMessageTracerDomainField, gTopLevelKeyForCertificateTracing); - - /* Our custom key (starts with com.apple.message.) and its value */ - asl_set(mAsl, key_buffer, value_buffer); - - /* Log this ASL record (note actual log message is empty) */ - asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, ""); - asl_free(mAsl); - return true; - -} -#endif - -#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) - -static const char* gTopLevelKeyForCertificateTracing = "com.apple.certstats"; - -typedef void (*type_ADClientClearScalarKey)(CFStringRef key); -typedef void (*type_ADClientAddValueForScalarKey)(CFStringRef key, int64_t value); - -static type_ADClientClearScalarKey gADClientClearScalarKey = NULL; -static type_ADClientAddValueForScalarKey gADClientAddValueForScalarKey = NULL; - -static dispatch_once_t gADFunctionPointersSet = 0; -static CFBundleRef gAggdBundleRef = NULL; -static bool gFunctionPointersAreLoaded = false; - -/* -------------------------------------------------------------------------- - Function: InitializeADFunctionPointers - - Description: Linking to the Aggregate library causes a build cycle, - so this function dynamically loads the needed function - pointers. - -------------------------------------------------------------------------- */ -static bool InitializeADFunctionPointers() -{ - if (gFunctionPointersAreLoaded) - { - return gFunctionPointersAreLoaded; - } - - dispatch_once(&gADFunctionPointersSet, - ^{ - CFStringRef path_to_aggd_framework = CFSTR("/System/Library/PrivateFrameworks/AggregateDictionary.framework"); - - CFURLRef aggd_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_to_aggd_framework, kCFURLPOSIXPathStyle, true); - - if (NULL != aggd_url) - { - gAggdBundleRef = CFBundleCreate(kCFAllocatorDefault, aggd_url); - if (NULL != gAggdBundleRef) - { - gADClientClearScalarKey = (type_ADClientClearScalarKey) - CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientClearScalarKey")); - - gADClientAddValueForScalarKey = (type_ADClientAddValueForScalarKey) - CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientAddValueForScalarKey")); - } - CFRelease(aggd_url); - } - }); - - gFunctionPointersAreLoaded = ((NULL != gADClientClearScalarKey) && (NULL != gADClientAddValueForScalarKey)); - return gFunctionPointersAreLoaded; -} - -/* -------------------------------------------------------------------------- - Function: Internal_ADClientClearScalarKey - - Description: This function is a wrapper around calling the - ADClientClearScalarKey function. - - NOTE: The key should be a simple key such as - "numberOfPeers". This is because this function will - append the required prefix of "com.apple.certstats" - -------------------------------------------------------------------------- */ -static void Internal_ADClientClearScalarKey(CFStringRef key) -{ - if (InitializeADFunctionPointers()) - { - CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%@"), gTopLevelKeyForCertificateTracing, key); - if (NULL == real_key) - { - return; - } - - gADClientClearScalarKey(real_key); - CFRelease(real_key); - } -} - -/* -------------------------------------------------------------------------- - Function: Internal_ADClientAddValueForScalarKey - - Description: This function is a wrapper around calling the - ADClientAddValueForScalarKey function. - - NOTE: The key should be a simple key such as - "numberOfPeers". This is because this function will - append the required prefix of "com.apple.certstats" - -------------------------------------------------------------------------- */ -static void Internal_ADClientAddValueForScalarKey(CFStringRef key, int64_t value) -{ - if (InitializeADFunctionPointers()) - { - CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%@"), gTopLevelKeyForCertificateTracing, key); - if (NULL == real_key) - { - return; - } - - gADClientAddValueForScalarKey(real_key, value); - CFRelease(real_key); - } -} - - -/* -------------------------------------------------------------------------- - Function: iOS_SetCertificateTraceValueForKey - - Description: This function is a wrapper around calling either - ADClientAddValueForScalarKey or ADClientClearScalarKey, - depending on whether the value is 0. - - NOTE: The key should be a simple key such as - "numberOfPeers". This is because this function will - append the required prefix of "com.apple.certstats" - -------------------------------------------------------------------------- */ -static bool iOS_SetCertificateTraceValueForKey(CFStringRef key, int64_t value) -{ - if (NULL == key) - { - return false; - } - - if (0LL == value) - { - Internal_ADClientClearScalarKey(key); - } - else - { - Internal_ADClientAddValueForScalarKey(key, value); - } - return true; -} - -/* -------------------------------------------------------------------------- - Function: iOS_AddKeyValuePairToCertificateLoggingTransaction - - Description: For iOS there is no "bunching". This function will simply - call iOS_SetCloudKeychainTraceValueForKey to log the - key-value pair. - -------------------------------------------------------------------------- */ -static bool iOS_AddKeyValuePairToCertificateLoggingTransaction(void* token, CFStringRef key, int64_t value) -{ -#pragma unused(token) - return iOS_SetCertificateTraceValueForKey(key, value); -} -#endif - -/* -------------------------------------------------------------------------- - Function: SetCertificateTraceValueForKey - - Description: SPI to log a single key-value pair with the logging system - -------------------------------------------------------------------------- */ -bool SetCertificateTraceValueForKey(CFStringRef key, int64_t value) -{ -#if (TARGET_IPHONE_SIMULATOR) - return false; -#endif - -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) - return OSX_SetCertificateTraceValueForKey(key, value); -#endif - -#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) - return iOS_SetCertificateTraceValueForKey(key, value); -#endif -} - -/* -------------------------------------------------------------------------- - Function: BeginCertificateLoggingTransaction - - Description: SPI to begin a logging transaction - -------------------------------------------------------------------------- */ -void* BeginCertificateLoggingTransaction(void) -{ -#if (TARGET_IPHONE_SIMULATOR) - return (void *)-1; -#endif - -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) - return OSX_BeginCertificateLoggingTransaction(); -#endif - -#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) - return NULL; -#endif -} - -/* -------------------------------------------------------------------------- - Function: AddKeyValuePairToCertificateLoggingTransaction - - Description: SPI to add a key-value pair to an outstanding logging - transaction - -------------------------------------------------------------------------- */ -bool AddKeyValuePairToCertificateLoggingTransaction(void* token, CFStringRef key, int64_t value) -{ -#if (TARGET_IPHONE_SIMULATOR) - return false; -#endif - -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) - return OSX_AddKeyValuePairToCertificateLoggingTransaction(token, key, value); -#endif - -#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) - return iOS_AddKeyValuePairToCertificateLoggingTransaction(token, key, value); -#endif -} - -/* -------------------------------------------------------------------------- - Function: CloseCertificateLoggingTransaction - - Description: SPI to complete a logging transaction and clean up the - context - -------------------------------------------------------------------------- */ -void CloseCertificateLoggingTransaction(void* token) -{ -#if (TARGET_IPHONE_SIMULATOR) - ; // nothing -#endif - -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) - OSX_CloseCertificateLoggingTransaction(token); -#endif - -#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) - ; // nothing -#endif -} - -/* -------------------------------------------------------------------------- - Function: SecCFStringCopyEncodingDelimiters - - Description: Utility to replace all characters in the given string - which match characters in the delimiters string. This - should be expanded later; for now we are assuming the - delimiters string is a single character, and we replace - it with an underscore instead of percent encoding. - -------------------------------------------------------------------------- */ - -CFStringRef SecCFStringCopyEncodingDelimiters(CFStringRef str, CFStringRef delimiters) -{ - CFMutableStringRef newStr = (str) ? CFStringCreateMutableCopy(kCFAllocatorDefault, 0, str) : NULL; - if (newStr && delimiters) - { - CFStringRef replacementString = CFSTR("_"); - CFIndex idx, count = CFStringGetLength(delimiters); - for (idx = 0; idx < count; idx++) { - UniChar uc = CFStringGetCharacterAtIndex(delimiters, idx); - CFStringRef stringToFind = CFStringCreateWithCharacters(kCFAllocatorDefault, &uc, 1); - if (stringToFind) { - CFStringFindAndReplace(newStr, stringToFind, replacementString, CFRangeMake(0, CFStringGetLength(newStr)), 0); - CFRelease(stringToFind); - } - } - } - return (CFStringRef) newStr; -} - -/* -------------------------------------------------------------------------- - Function: SecCertificateTraceAddRecord - - Description: High-level SPI that logs a single certificate record, - given a dictionary containing key-value pairs. - -------------------------------------------------------------------------- */ -bool SecCertificateTraceAddRecord(CFDictionaryRef certRecord) -{ - bool result = false; - if (!certRecord) - return result; - - /* encode delimiter characters in supplied strings */ - CFStringRef policy = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsPolicy), kCertStatsDelimiters); - CFStringRef notBefore = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsNotBefore), kCertStatsDelimiters); - CFStringRef notAfter = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsNotAfter), kCertStatsDelimiters); - CFStringRef serial = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsSerialNumber), kCertStatsDelimiters); - CFStringRef subject = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsSubjectSummary), kCertStatsDelimiters); - CFStringRef issuer = SecCFStringCopyEncodingDelimiters(CFDictionaryGetValue(certRecord, kCertStatsIssuerSummary), kCertStatsDelimiters); - - /* this generates a key which includes delimited fields to identify the certificate */ - CFStringRef keyStr = CFStringCreateWithFormat(NULL, NULL, - kCertStatsFormat, /* format string */ - kCertStatsCert, /* certificate key */ - kCertStatsPolicy, policy, - kCertStatsNotBefore, notBefore, - kCertStatsNotAfter, notAfter, - kCertStatsSerialNumber, serial, - kCertStatsSubjectSummary, subject, - kCertStatsIssuerSummary, issuer - ); - CFReleaseSafe(policy); - CFReleaseSafe(notBefore); - CFReleaseSafe(notAfter); - CFReleaseSafe(serial); - CFReleaseSafe(subject); - CFReleaseSafe(issuer); - - result = SetCertificateTraceValueForKey(keyStr, 1); -#if DEBUG - secerror("%@.%@ (%d)", kCertStatsPrefix, keyStr, (result) ? 1 : 0); -#endif - CFReleaseSafe(keyStr); - - return result; -} - diff --git a/OSX/utilities/src/SecDb.c b/OSX/utilities/src/SecDb.c index 414a69a9..01cb53a0 100644 --- a/OSX/utilities/src/SecDb.c +++ b/OSX/utilities/src/SecDb.c @@ -88,7 +88,7 @@ struct __OpaqueSecDb { dispatch_semaphore_t write_semaphore; dispatch_semaphore_t read_semaphore; bool didFirstOpen; - bool (^opened)(SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error); + bool (^opened)(SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error); bool callOpenedHandlerForNextConnection; CFMutableArrayRef notifyPhase; /* array of SecDBNotifyBlock */ mode_t mode; /* database file permissions, default 0600 */ @@ -124,13 +124,22 @@ bool SecDbErrorWithDb(int sql_code, sqlite3 *db, CFErrorRef *error, CFStringRef va_start(args, format); CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args); va_end(args); + CFStringRef errno_code = NULL; + + if (sql_code == SQLITE_CANTOPEN) { + int errno_number = sqlite3_system_errno(db); + errno_code = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), errno_number); + } else { + errno_code = CFRetain(CFSTR("")); + } int extended_code = sqlite3_extended_errcode(db); if (sql_code == extended_code) - SecDbError(sql_code, error, CFSTR("%@: [%d] %s"), message, sql_code, sqlite3_errmsg(db)); + SecDbError(sql_code, error, CFSTR("%@: [%d]%@ %s"), message, sql_code, errno_code, sqlite3_errmsg(db)); else - SecDbError(sql_code, error, CFSTR("%@: [%d->%d] %s"), message, sql_code, extended_code, sqlite3_errmsg(db)); + SecDbError(sql_code, error, CFSTR("%@: [%d->%d]%@ %s"), message, sql_code, extended_code, errno_code, sqlite3_errmsg(db)); CFReleaseSafe(message); + CFReleaseSafe(errno_code); } return false; } @@ -155,6 +164,22 @@ bool SecDbErrorWithStmt(int sql_code, sqlite3_stmt *stmt, CFErrorRef *error, CFS return false; } +// A callback for the sqlite3_log() interface. +static void sqlite3Log(void *pArg, int iErrCode, const char *zMsg){ + secdebug("sqlite3", "(%d) %s", iErrCode, zMsg); +} + +void _SecDbServerSetup(void) +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + int rx = sqlite3_config(SQLITE_CONFIG_LOG, sqlite3Log, NULL); + if (SQLITE_OK != rx) { + secwarning("Could not set up sqlite global error logging to syslog: %d", rx); + } + }); +} + // MARK: - // MARK: Static helper functions @@ -206,7 +231,7 @@ CFGiblisFor(SecDb) SecDbRef SecDbCreateWithOptions(CFStringRef dbName, mode_t mode, bool readWrite, bool allowRepair, bool useWAL, - bool (^opened)(SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error)) + bool (^opened)(SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error)) { SecDbRef db = NULL; @@ -244,7 +269,7 @@ done: SecDbRef SecDbCreate(CFStringRef dbName, - bool (^opened)(SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error)) + bool (^opened)(SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error)) { return SecDbCreateWithOptions(dbName, 0600, true, true, true, opened); } @@ -260,12 +285,15 @@ SecDbIdleConnectionCount(SecDbRef db) { void SecDbAddNotifyPhaseBlock(SecDbRef db, SecDBNotifyBlock notifyPhase) { - SecDBNotifyBlock block = Block_copy(notifyPhase); /* Force the block off the stack */ - if (db->notifyPhase == NULL) { - db->notifyPhase = CFArrayCreateMutableForCFTypes(NULL); - } - CFArrayAppendValue(db->notifyPhase, block); - Block_release(block); + // 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 */ + if (db->notifyPhase == NULL) { + db->notifyPhase = CFArrayCreateMutableForCFTypes(NULL); + } + CFArrayAppendValue(db->notifyPhase, block); + Block_release(block); + }); } static void SecDbNotifyPhase(SecDbConnectionRef dbconn, SecDbTransactionPhase phase) { @@ -299,20 +327,45 @@ CFStringRef SecDbGetPath(SecDbRef db) { static bool SecDbCheckCorrupted(SecDbConnectionRef dbconn) { - __block bool isCorrupted = true; + __block bool checkDidRun = false; + __block bool isCorrupted = false; __block CFErrorRef error = NULL; SecDbPrepare(dbconn, CFSTR("PRAGMA integrity_check"), &error, ^(sqlite3_stmt *stmt) { SecDbStep(dbconn, stmt, &error, ^(bool *stop) { const char * result = (const char*)sqlite3_column_text(stmt, 0); - if (result && strncasecmp(result, "ok", 3) == 0) { - isCorrupted = false; + if (!result || strncasecmp(result, "ok", 3) != 0) { + isCorrupted = true; + secerror("SecDBCheckCorrupted integrity_check returned %s", (result) ? result : "NULL"); } + checkDidRun = true; }); }); - if (error) { - secinfo("#SecDB", "#SecDB warning error %{public}@ when running integrity check", error); - CFRelease(error); + if (!checkDidRun) { + // An error occurred in SecDbPrepare before we could run the block. + if (error) { + CFIndex code = CFErrorGetCode(error); + if (SQLITE_CORRUPT == code || SQLITE_NOTADB == code) { + isCorrupted = true; + } + secinfo("#SecDB", "#SecDB warning error %{public}@ when running integrity check", error); + } else { + // We don't have an error ref if SecDbPrepare has called SecDbConnectionCheckCode, + // which then called SecDbHandleCorrupt. That code path is only entered when the + // original error was SQLITE_CORRUPT or SQLITE_NOTADB. On other errors, the + // CFErrorRef is not cleared and we can just check the code above. + isCorrupted = true; + secinfo("#SecDB", "#SecDB warning: failed to run integrity check due to corruption"); + } + } + if (isCorrupted) { + if (checkDidRun) { + secerror("SecDBCheckCorrupted ran integrity_check, and that didn't return ok"); + } else { + secerror("SecDBCheckCorrupted failed to run integrity check"); + } } + CFReleaseNull(error); + return isCorrupted; } @@ -321,20 +374,14 @@ static bool SecDbDidCreateFirstConnection(SecDbConnectionRef dbconn, bool didCre secinfo("#SecDB", "#SecDB starting maintenance"); bool ok = true; - if (!didCreate && !dbconn->isCorrupted) { - dbconn->isCorrupted = SecDbCheckCorrupted(dbconn); - if (dbconn->isCorrupted) { - secinfo("#SecDB", "#SecDB integrity check=fail"); - } else { - secinfo("#SecDB", "#SecDB starting maintenance"); - } - } + // Historical note: this used to check for integrity but that became too slow and caused panics at boot. + // Now, just react to SQLite errors when doing an operation. If file on disk is borked it'll tell us right away. if (!dbconn->isCorrupted && dbconn->db->opened) { CFErrorRef localError = NULL; dbconn->db->callOpenedHandlerForNextConnection = false; - ok = dbconn->db->opened(dbconn, didCreate, &dbconn->db->callOpenedHandlerForNextConnection, &localError); + ok = dbconn->db->opened(dbconn->db, dbconn, didCreate, &dbconn->db->callOpenedHandlerForNextConnection, &localError); if (!ok) secerror("opened block failed: %@", localError); @@ -344,13 +391,23 @@ static bool SecDbDidCreateFirstConnection(SecDbConnectionRef dbconn, bool didCre localError = NULL; } else { if (localError) - secerror("opened block failed: error is released and lost"); + secerror("opened block failed: error (%@) is being released and lost", localError); CFReleaseNull(localError); } } if (dbconn->isCorrupted) { - ok = SecDbHandleCorrupt(dbconn, 0, error); + /* SecDbHandleCorrupt must be executed on the db queue so nobody + can acquire a new connection while it is running. */ + if (dispatch_get_current_queue() == dbconn->db->queue) { + ok = SecDbHandleCorrupt(dbconn, 0, error); + } else { + /* We aren't on the db queue already when we get here. It may be + unsafe to dispatch this work from the current queue, so log + and return false without attempting recovery. */ + secerror("WARNING: unable to call SecDbHandleCorrupt (not on db queue)"); + ok = false; + } } secinfo("#SecDB", "#SecDB starting maintenance"); @@ -391,6 +448,10 @@ static uint8_t knownDbPathIndex(SecDbConnectionRef dbconn) return 0; } +static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn, int code, CFErrorRef *error, CFStringRef desc, ...) + CF_FORMAT_FUNCTION(4, 5); + + // Return true if there was no error, returns false otherwise and set *error to an appropriate CFErrorRef. static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn, int code, CFErrorRef *error, CFStringRef desc, ...) { @@ -402,7 +463,7 @@ static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn, int code, CFErro va_start(args, desc); CFStringRef msg = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, desc, args); va_end(args); - SecDbErrorWithDb(code, dbconn->handle, error, msg); + SecDbErrorWithDb(code, dbconn->handle, error, CFSTR("%@"), msg); CFRelease(msg); } @@ -428,7 +489,16 @@ static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn, int code, CFErro dbconn->isCorrupted = SecDbCheckCorrupted(dbconn); if (dbconn->isCorrupted) { secerror("operation returned code: %d integrity check=fail", code); - SecDbHandleCorrupt(dbconn, code, error); + /* SecDbHandleCorrupt must be executed on the db queue so nobody + can acquire a new connection while it is running. */ + if (dispatch_get_current_queue() == dbconn->db->queue) { + (void)SecDbHandleCorrupt(dbconn, code, error); + } else { + /* We aren't on the db queue already when we get here. It may be + unsafe to dispatch this work from the current queue, so log + and return false without attempting recovery. */ + secerror("WARNING: unable to call SecDbHandleCorrupt (not on db queue)"); + } } else { secerror("operation returned code: %d: integrity check=pass", code); } @@ -504,7 +574,7 @@ static bool SecDbWaitIfNeeded(SecDbConnectionRef dbconn, int s3e, sqlite3_stmt * } } - return SecDbConnectionCheckCode(dbconn, s3e, error, desc); + return SecDbConnectionCheckCode(dbconn, s3e, error, CFSTR("%@"), desc); } enum SecDbStepResult { @@ -571,25 +641,31 @@ static bool SecDbBeginTransaction(SecDbConnectionRef dbconn, SecDbTransactionTyp CFStringRef query; switch (type) { case kSecDbImmediateTransactionType: - secnoticeq("db", "SecDbBeginTransaction SecDbBeginTransaction %p", dbconn); - query = CFSTR("BEGIN IMMEDATE"); + secdebug("db", "SecDbBeginTransaction SecDbBeginTransaction %p", dbconn); + query = CFSTR("BEGIN IMMEDIATE"); break; - case kSecDbExclusiveRemoteTransactionType: - secnoticeq("db", "SecDbBeginTransaction kSecDbExclusiveRemoteTransactionType %p", dbconn); + case kSecDbExclusiveRemoteSOSTransactionType: + secdebug("db", "SecDbBeginTransaction kSecDbExclusiveRemoteSOSTransactionType %p", dbconn); dbconn->source = kSecDbSOSTransaction; - // FALL THROUGH + query = CFSTR("BEGIN EXCLUSIVE"); + break; + case kSecDbExclusiveRemoteCKKSTransactionType: + secdebug("db", "SecDbBeginTransaction kSecDbExclusiveRemoteCKKSTransactionType %p", dbconn); + dbconn->source = kSecDbCKKSTransaction; + query = CFSTR("BEGIN EXCLUSIVE"); + break; case kSecDbExclusiveTransactionType: if (type==kSecDbExclusiveTransactionType) - secnoticeq("db", "SecDbBeginTransaction kSecDbExclusiveTransactionType %p", dbconn); + secdebug("db", "SecDbBeginTransaction kSecDbExclusiveTransactionType %p", dbconn); query = CFSTR("BEGIN EXCLUSIVE"); break; case kSecDbNormalTransactionType: - secnoticeq("db", "SecDbBeginTransaction kSecDbNormalTransactionType %p", dbconn); + secdebug("db", "SecDbBeginTransaction kSecDbNormalTransactionType %p", dbconn); query = CFSTR("BEGIN"); break; default: - secnoticeq("db", "SecDbBeginTransaction invalid transaction type %lu", type); - ok = SecDbError(SQLITE_ERROR, error, CFSTR("invalid transaction type %" PRIu32), type); + secdebug("db", "SecDbBeginTransaction invalid transaction type %lu", type); + ok = SecDbError(SQLITE_ERROR, error, CFSTR("invalid transaction type %d"), (int)type); query = NULL; break; } @@ -610,17 +686,17 @@ static bool SecDbEndTransaction(SecDbConnectionRef dbconn, bool commit, CFErrorR dispatch_block_t notifyAndExec = ^{ if (commit) { - secnoticeq("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p", dbconn); + //secdebug("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p", dbconn); SecDbNotifyPhase(dbconn, kSecDbTransactionWillCommit); commited = ok = SecDbExec(dbconn, CFSTR("END"), error); - secnoticeq("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p (after notify)", dbconn); + //secdebug("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p (after notify)", dbconn); } else { ok = SecDbExec(dbconn, CFSTR("ROLLBACK"), error); commited = false; } dbconn->inTransaction = false; SecDbNotifyPhase(dbconn, commited ? kSecDbTransactionDidCommit : kSecDbTransactionDidRollback); - secnoticeq("db", "SecDbEndTransaction %s %p", commited ? "kSecDbTransactionDidCommit" : "kSecDbTransactionDidRollback", dbconn); + secdebug("db", "SecDbEndTransaction %s %p", commited ? "kSecDbTransactionDidCommit" : "kSecDbTransactionDidRollback", dbconn); dbconn->source = kSecDbAPITransaction; }; @@ -740,7 +816,8 @@ static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn, int rc, CFErrorRef *er { if (!dbconn->db->allowRepair) { SecCFCreateErrorWithFormat(rc, kSecErrnoDomain, NULL, error, NULL, - CFSTR("SecDbHandleCorrupt repair not allowed: [%d] %s"), rc, strerror(rc)); + CFSTR("SecDbHandleCorrupt handled error: [%d] %s"), rc, strerror(rc)); + dbconn->isCorrupted = false; return false; } @@ -762,9 +839,31 @@ static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn, int rc, CFErrorRef *er if (error) CFReleaseNull(*error); - didRename = (!dbconn->handle || SecDbError(sqlite3_close(dbconn->handle), error, CFSTR("close"))) && - SecCheckErrno(rename(db_path, buf), error, CFSTR("rename %s %s"), db_path, buf) && - SecDbOpenHandle(dbconn, NULL, error); + // Explicitly close our connection, plus all other open connections to this db. + bool closed = true; + if (dbconn->handle) { + closed &= SecDbError(sqlite3_close(dbconn->handle), error, CFSTR("close")); + dbconn->handle = NULL; + } + SecDbRef db = dbconn->db; + CFIndex idx, count = (db->connections) ? CFArrayGetCount(db->connections) : 0; + for (idx = 0; idx < count; idx++) { + SecDbConnectionRef dbconn = (SecDbConnectionRef) CFArrayGetValueAtIndex(db->connections, idx); + if (dbconn && dbconn->handle) { + closed &= SecDbError(sqlite3_close(dbconn->handle), error, CFSTR("close")); + dbconn->handle = NULL; + } + } + CFArrayRemoveAllValues(db->connections); + + // Attempt rename only if all connections closed successfully. + if (closed) { + if (SecCheckErrno(rename(db_path, buf), error, CFSTR("rename %s %s"), db_path, buf)) { + if (SecDbOpenHandle(dbconn, NULL, error)) { + didRename = true; + } + } + } } if (didRename) { secerror("Database at path %@ is corrupt. Copied it to %s for further investigation.", dbconn->db->db_path, buf); @@ -784,7 +883,7 @@ static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn, int rc, CFErrorRef *er // Invoke our callers opened callback, since we just created a new database if (ok && dbconn->db->opened) { dbconn->db->callOpenedHandlerForNextConnection = false; - ok = dbconn->db->opened(dbconn, true, &dbconn->db->callOpenedHandlerForNextConnection, error); + ok = dbconn->db->opened(dbconn->db, dbconn, true, &dbconn->db->callOpenedHandlerForNextConnection, error); } return ok; @@ -845,11 +944,12 @@ SecDbTraceV2(unsigned mask, void *ctx, void *p, void *x) { const char *trace = "unknown"; if (mask == SQLITE_TRACE_PROFILE) - trace = "profile"; - else if (mask == SQLITE_TRACE_STMT) - trace = "stmt"; - else if (mask == SQLITE_TRACE_ROW) - trace = "row"; + 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); + } secinfo("#SecDB", "#SecDB %{public}s", trace); return 0; @@ -1005,7 +1105,7 @@ SecDbConnectionRef SecDbConnectionAcquire(SecDbRef db, bool readOnly, CFErrorRef dispatch_sync(db->queue, ^{ if (dbconn->db->callOpenedHandlerForNextConnection) { dbconn->db->callOpenedHandlerForNextConnection = false; - if (!dbconn->db->opened(dbconn, false, &dbconn->db->callOpenedHandlerForNextConnection, error)) { + if (!dbconn->db->opened(db, dbconn, false, &dbconn->db->callOpenedHandlerForNextConnection, error)) { if (!dbconn->isCorrupted || !SecDbHandleCorrupt(dbconn, 0, error)) { CFReleaseNull(dbconn); } @@ -1052,6 +1152,78 @@ void SecDbConnectionRelease(SecDbConnectionRef dbconn) { }); } +void SecDbReleaseAllConnections(SecDbRef db) { + // Force all connections to be removed (e.g. file descriptor no longer valid) + if (!db) { + secerror("called with NULL db"); + return; + } + dispatch_sync(db->queue, ^{ + CFArrayRemoveAllValues(db->connections); + dispatch_semaphore_signal(db->write_semaphore); + dispatch_semaphore_signal(db->read_semaphore); + }); +} + +bool SecDbReplace(SecDbRef db, CFStringRef newDbPath, CFErrorRef *error) { + // Replace the given database with the contents of the database + // at newDbPath, as an atomic operation on db->queue. + + __block bool result = false; + if (!db || !newDbPath) { + secerror("called with NULL argument"); + return result; + } + dispatch_sync(db->queue, ^{ + // Explicitly close all database connections + CFIndex idx, count = (db->connections) ? CFArrayGetCount(db->connections) : 0; + for (idx = 0; idx < count; idx++) { + SecDbConnectionRef dbconn = (SecDbConnectionRef) CFArrayGetValueAtIndex(db->connections, idx); + if (dbconn->handle) { + sqlite3_close(dbconn->handle); + dbconn->handle = NULL; + } + } + CFArrayRemoveAllValues(db->connections); + + __block sqlite3 *old_db = NULL; + __block sqlite3 *new_db = NULL; + CFStringPerformWithCString(db->db_path, ^(const char *db_path) { + int s3e = sqlite3_open_v2(db_path, &old_db, SQLITE_OPEN_READWRITE, NULL); + if (SQLITE_OK != s3e) { + secerror("Unable to open db for writing: %s (error %d)", db_path, s3e); + } + }); + CFStringPerformWithCString(newDbPath, ^(const char *new_db_path) { + int s3e = sqlite3_open_v2(new_db_path, &new_db, SQLITE_OPEN_READONLY, NULL); + if (SQLITE_OK != s3e) { + secerror("Unable to open db for reading: %s (error %d)", new_db_path, s3e); + } + }); + if (old_db && new_db) { + // Replace old_db with contents of new_db + int s3e = sqlite3_file_control(old_db, NULL, SQLITE_FCNTL_REPLACE_DATABASE, new_db); + if (SQLITE_OK != s3e) { + secerror("Unable to replace db: %@ (error %d)", db->db_path, s3e); + } else { + result = true; + } + } + if (old_db) { + sqlite3_close(old_db); + } + if (new_db) { + sqlite3_close(new_db); + } + + // Signal that connections are available again. + dispatch_semaphore_signal(db->write_semaphore); + dispatch_semaphore_signal(db->read_semaphore); + }); + + return result; +} + bool SecDbPerformRead(SecDbRef db, CFErrorRef *error, void (^perform)(SecDbConnectionRef dbconn)) { SecDbConnectionRef dbconn = SecDbConnectionAcquire(db, true, error); bool success = false; @@ -1118,7 +1290,7 @@ void SecDbPerformOnCommitQueue(SecDbConnectionRef dbconn, bool barrier, dispatch bool SecDbBindNull(sqlite3_stmt *stmt, int param, CFErrorRef *error) { bool ok = SecDbErrorWithStmt(sqlite3_bind_null(stmt, param), stmt, error, CFSTR("bind_null[%d]"), param); - secinfo("bind", "bind_null[%d]: %@", param, error ? *error : NULL); + secinfo("bind", "bind_null[%d] error: %@", param, error ? *error : NULL); return ok; } #endif @@ -1141,28 +1313,28 @@ bool SecDbBindText(sqlite3_stmt *stmt, int param, const char *zData, size_t n, v } bool ok = SecDbErrorWithStmt(sqlite3_bind_text(stmt, param, zData, (int)n, xDel), stmt, error, CFSTR("bind_text[%d]"), param); - secinfo("bind", "bind_text[%d]: \"%s\": %@", param, zData, error ? *error : NULL); + secinfo("bind", "bind_text[%d]: \"%s\" error: %@", param, zData, error ? *error : NULL); return ok; } bool SecDbBindDouble(sqlite3_stmt *stmt, int param, double value, CFErrorRef *error) { bool ok = SecDbErrorWithStmt(sqlite3_bind_double(stmt, param, value), stmt, error, CFSTR("bind_double[%d]"), param); - secinfo("bind", "bind_double[%d]: %f: %@", param, value, error ? *error : NULL); + secinfo("bind", "bind_double[%d]: %f error: %@", param, value, error ? *error : NULL); return ok; } bool SecDbBindInt(sqlite3_stmt *stmt, int param, int value, CFErrorRef *error) { bool ok = SecDbErrorWithStmt(sqlite3_bind_int(stmt, param, value), stmt, error, CFSTR("bind_int[%d]"), param); - secinfo("bind", "bind_int[%d]: %d: %@", param, value, error ? *error : NULL); + secinfo("bind", "bind_int[%d]: %d error: %@", param, value, error ? *error : NULL); return ok; } bool SecDbBindInt64(sqlite3_stmt *stmt, int param, sqlite3_int64 value, CFErrorRef *error) { bool ok = SecDbErrorWithStmt(sqlite3_bind_int64(stmt, param, value), stmt, error, CFSTR("bind_int64[%d]"), param); - secinfo("bind", "bind_int64[%d]: %lld: %@", param, value, error ? *error : NULL); + secinfo("bind", "bind_int64[%d]: %lld error: %@", param, value, error ? *error : NULL); return ok; } @@ -1453,6 +1625,27 @@ SecDbEventRef SecDbEventCreateWithComponents(CFTypeRef deleted, CFTypeRef insert return NULL; } +void SecDbEventTranslateComponents(SecDbEventRef item, CFTypeRef* deleted, CFTypeRef* inserted) { + if(CFGetTypeID(item) == CFArrayGetTypeID()) { + // One item: deletion. Two: update. + CFIndex arraySize = CFArrayGetCount(item); + if(arraySize == 1) { + if(deleted) { *deleted = CFArrayGetValueAtIndex(item, 0); } + if(inserted) { *inserted = NULL; } + } else if(arraySize == 2) { + if(deleted) { *deleted = CFArrayGetValueAtIndex(item, 0); } + if(inserted) { *inserted = CFArrayGetValueAtIndex(item, 1); } + } else { + if(deleted) { *deleted = NULL; } + if(inserted) { *inserted = NULL; } + } + } else { + if(deleted) { *deleted = NULL; } + if(inserted) { *inserted = item; } + } + +} + bool SecDbEventGetComponents(SecDbEventRef event, CFTypeRef *deleted, CFTypeRef *inserted, CFErrorRef *error) { if (isArray(event)) { CFArrayRef array = event; diff --git a/OSX/utilities/src/SecDb.h b/OSX/utilities/src/SecDb.h index bc00eac0..d00276cf 100644 --- a/OSX/utilities/src/SecDb.h +++ b/OSX/utilities/src/SecDb.h @@ -50,7 +50,8 @@ enum { kSecDbImmediateTransactionType, kSecDbExclusiveTransactionType, kSecDbNormalTransactionType, - kSecDbExclusiveRemoteTransactionType, + kSecDbExclusiveRemoteSOSTransactionType, + kSecDbExclusiveRemoteCKKSTransactionType, }; typedef CFOptionFlags SecDbTransactionType; @@ -62,9 +63,11 @@ enum SecDbTransactionPhase { typedef CFOptionFlags SecDbTransactionPhase; enum SecDbTransactionSource { - kSecDbSOSTransaction, // A remotely initated transaction. - kSecDbAPITransaction, // A user initated transaction. - kSecDbInvalidTransaction, // An invalid transaction source (used for initialization) + kSecDbSOSTransaction = 0, // A remotely initated transaction (via SOS) + kSecDbCKKSTransaction = 3, // A transaction initiated by CKKS (either via remote notification or queue processing) + kSecDbAPITransaction = 1, // A user initated transaction. + kSecDbInvalidTransaction = 2, // An invalid transaction source (used for initialization) + }; typedef CFOptionFlags SecDbTransactionSource; @@ -76,16 +79,19 @@ extern CFStringRef kSecDbErrorDomain; typedef CFTypeRef SecDbEntryRef; -bool SecDbError(int sql_code, CFErrorRef *error, CFStringRef format, ...); -bool SecDbErrorWithDb(int sql_code, sqlite3 *db, CFErrorRef *error, CFStringRef format, ...); -bool SecDbErrorWithStmt(int sql_code, sqlite3_stmt *stmt, CFErrorRef *error, CFStringRef format, ...); +bool SecDbError(int sql_code, CFErrorRef *error, CFStringRef format, ...) CF_FORMAT_FUNCTION(3, 4); +bool SecDbErrorWithDb(int sql_code, sqlite3 *db, CFErrorRef *error, CFStringRef format, ...) CF_FORMAT_FUNCTION(4, 5); +bool SecDbErrorWithStmt(int sql_code, sqlite3_stmt *stmt, CFErrorRef *error, CFStringRef format, ...) CF_FORMAT_FUNCTION(4, 5); // MARK: mark - // MARK: mark SecDbRef +void _SecDbServerSetup(void); + typedef CFTypeRef SecDbEventRef; SecDbEventRef SecDbEventCreateWithComponents(CFTypeRef deleted, CFTypeRef inserted); +void SecDbEventTranslateComponents(SecDbEventRef item, CFTypeRef* deleted, CFTypeRef* inserted); // Return deleted and inserted for a given changes entry, both are optional bool SecDbEventGetComponents(SecDbEventRef event, CFTypeRef *deleted, CFTypeRef *inserted, CFErrorRef *error); @@ -96,9 +102,9 @@ typedef void (^SecDBNotifyBlock)(SecDbConnectionRef dbconn, SecDbTransactionPhas CFTypeID SecDbGetTypeID(void); // Database creation -SecDbRef SecDbCreateWithOptions(CFStringRef dbName, mode_t mode, bool readWrite, bool allowRepair, bool useWAL, bool (^opened)(SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error)); +SecDbRef SecDbCreateWithOptions(CFStringRef dbName, mode_t mode, bool readWrite, bool allowRepair, bool useWAL, bool (^opened)(SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error)); -SecDbRef SecDbCreate(CFStringRef dbName, bool (^opened)(SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error)); +SecDbRef SecDbCreate(CFStringRef dbName, bool (^opened)(SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error)); void SecDbAddNotifyPhaseBlock(SecDbRef db, SecDBNotifyBlock notifyPhase); @@ -114,6 +120,8 @@ bool SecDbPerformWrite(SecDbRef db, CFErrorRef *error, void (^perform)(SecDbConn // TODO: DEBUG only -> Private header CFIndex SecDbIdleConnectionCount(SecDbRef db); +void SecDbReleaseAllConnections(SecDbRef db); +bool SecDbReplace(SecDbRef db, CFStringRef newDbPath, CFErrorRef *error); CFStringRef SecDbGetPath(SecDbRef db); diff --git a/OSX/utilities/src/SecFileLocations.c b/OSX/utilities/src/SecFileLocations.c index 29ab3a3e..65ff60b4 100644 --- a/OSX/utilities/src/SecFileLocations.c +++ b/OSX/utilities/src/SecFileLocations.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -47,7 +49,7 @@ static CFURLRef sCustomHomeURL = NULL; -static CFURLRef SecCopyHomeURL(void) +CFURLRef SecCopyHomeURL(void) { // This returns a CFURLRef so that it can be passed as the second parameter // to CFURLCreateCopyAppendingPathComponent @@ -204,14 +206,14 @@ done: CFURLRef SecCopyURLForFileInUserCacheDirectory(CFStringRef fileName) { -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) +#if TARGET_OS_OSX Boolean isDirectory = (fileName == NULL); CFURLRef resultURL = NULL; CFStringRef cacheDirStr = NULL; char strBuffer[PATH_MAX + 1]; size_t result = confstr(_CS_DARWIN_USER_CACHE_DIR, strBuffer, sizeof(strBuffer)); if (result == 0) { - syslog(LOG_CRIT, "SecOCSPCacheCopyPath: confstr on _CS_DARWIN_USER_CACHE_DIR failed"); + syslog(LOG_CRIT, "SecCopyURLForFileInUserCacheDirectory: confstr on _CS_DARWIN_USER_CACHE_DIR failed: %d", errno); return resultURL; } cacheDirStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s/%@"), strBuffer, fileName); @@ -268,7 +270,7 @@ static void WithPathInDirectory(CFURLRef fileURL, void(^operation)(const char *u { /* Ownership of fileURL is taken by this function and so we release it. */ if (fileURL) { - UInt8 buffer[MAXPATHLEN]; + UInt8 buffer[PATH_MAX]; CFURLGetFileSystemRepresentation(fileURL, false, buffer, sizeof(buffer)); operation((const char*)buffer); @@ -286,6 +288,11 @@ void WithPathInKeychainDirectory(CFStringRef fileName, void(^operation)(const ch WithPathInDirectory(SecCopyURLForFileInKeychainDirectory(fileName), operation); } +void WithPathInUserCacheDirectory(CFStringRef fileName, void(^operation)(const char *utf8String)) +{ + WithPathInDirectory(SecCopyURLForFileInUserCacheDirectory(fileName), operation); +} + void SetCustomHomeURL(CFURLRef url) { sCustomHomeURL = CFRetainSafe(url); diff --git a/OSX/utilities/src/SecFileLocations.h b/OSX/utilities/src/SecFileLocations.h index d29bbf1a..fb434a23 100644 --- a/OSX/utilities/src/SecFileLocations.h +++ b/OSX/utilities/src/SecFileLocations.h @@ -42,11 +42,14 @@ CFURLRef SecCopyURLForFileInRevocationInfoDirectory(CFStringRef fileName); 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 SetCustomHomePath(const char* path); void SetCustomHomeURLString(CFStringRef path); void SetCustomHomeURL(CFURLRef url); +CFURLRef SecCopyHomeURL(void); + __END_DECLS #endif diff --git a/OSX/utilities/src/SecInternalRelease.c b/OSX/utilities/src/SecInternalRelease.c index 4142f45b..6606e44c 100644 --- a/OSX/utilities/src/SecInternalRelease.c +++ b/OSX/utilities/src/SecInternalRelease.c @@ -24,22 +24,14 @@ #include #include #include -#include -#include +#include #include "SecInternalReleasePriv.h" -static bool void_to_error(enum SecXPCOperation op, CFErrorRef *error) { - __block bool ret = false; - securityd_send_sync_and_do(op, error, NULL, ^bool(xpc_object_t response, CFErrorRef *error) { - return (ret = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, error)); - }); - return ret; -} - bool SecIsInternalRelease(void) { static bool isInternal = false; + return isInternal; } diff --git a/OSX/utilities/src/SecMeta.h b/OSX/utilities/src/SecMeta.h deleted file mode 100644 index b7c05d49..00000000 --- a/OSX/utilities/src/SecMeta.h +++ /dev/null @@ -1,203 +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@ - */ - - -#ifndef _UTILITIES_SECMETA_H_ -#define _UTILITIES_SECMETA_H_ - -#include - -// -// MARK - SecMeta -// MARK - Logging, Trace, Error reporting, action log capture, and more. -// - -#define SecInline static inline - -// Disable all logging. -#define SecDisableLogging() do { _secOptions = _SecClearMask(_secOptions, mask); } while(0) - -// For people who don't like flag1|flag2|flag3 syntax use SecFlags(flag1,flag2,flag3) -#define SecFlags(...) _SecFlags(0, __VA_ARGS__) - -// Set the current scopes log level. -#define SecSetLogLevel(level) _SecSetLogLevel(&secOptions, (level)); - -// Mark that we performed an action for the log and for an generated errors. -#define SecAction(flags, key, action,...) \ - if (_SecLogLevel(flags)) { _SecSetLogLevel(&_secFlags, _SecLogLevel(flags)); } \ - if (_SecSetFlags(flags) \ - if ((_secFlags | flags) & kSecTraceAction) {} \ - if ((_secFlags | flags) & kSecLogEveryActionFlag) { \ - if (flags & kSecLogLevelMask) { \ - - - } \ - } \ -// _SecAction(&_secResult, &_secFlags, &_secName, &_secError, &_secChain, &_secActions, flags, key, action, __VA_ARGS__) - -// Usage: declare a variable that represents the result of your function -#define SecTry(result,flags,humanReadableFunctionNameForLogs) switch (0) case 0: { \ - __typeof__(result) _secResult = result; \ - __typeof__(flags) _secFlags = flags; \ - __typeof__(format) _secName = humanReadableFunctionNameForLogs; \ - CFErrorRef _secError = NULL; \ - CFMutableArrayRef _secChain = NULL; \ - CFMutableStringRef _secActions = NULL; \ - CFMutableDictionaryRef _secFormatOptions = NULL; \ - SecAction(_secFlags, CFSTR("entered")); - - - -#define SecEnableFlags(&_secFlags, flags) _secFlags = (flags); -#define SecDisableFlags(&_secFlags, flags) _secFlags = (flags); - -#define SecSetFlags(flags) _SecSetFlags(&_secFlags, flags) - -#define SecCatch(result, flags, error, ...) } _SecCatch(&_secResult, &_secFlags, &_secName, &_secError, &_secChain, &_secActions, result, flags, error,__VA_ARGS__) - -// Add pending errors to *error Clears any pending errors, and will log anything that was marked as needing to be logged. -#define SecFinally(result, flags, error, ...) _SecFinally(&_secResult, &_secFlags, &_secName, &_secError, &_secChain, &_secActions, result, flags, error, __VA_ARGS__) - -// Boolean function result -#define SecOk(result, flags, format, ...) _SecOK() - -// Log action and it's arguments into the action log. -#if DEBUG -#define SecDebugAction(flags, action...) SecAction(flags, action...) -#else -#define SecDebugAction(flags, action,...) -#endif - -#define SecThrow(result, domain, flags, body, format...) { rtype _r = body(); __security_trace_return_api(__FUNCTION__, format, _r); return _r; } - - -#define SecEnd(rtype, body, error, format...) { rtype _r = body(); __security_trace_return_api(__FUNCTION__, format, _r); return _r; } - -// Internal USE only DO NOT USE directly -#define _SecClearMask(flags, mask) (((flags) | (mask)) ^ (mask)) -#define _SecLogLevel(level) (((level) << 0) & kSecLogLevelMask) -#define _SecLogStyle(style) (((style) << 4) & kSecLogStyleMask) - -__BEGIN_DECLS - -enum SecFlagEnum { - kSecNoFlag = 0, // No flags, no logging nada - kSecLogLevelMask = (15 << 0), // Bits 0-3 contain the log levels 1-15 (since 0 is no flags). - - kSecFirstLogLevel = _SecLogLevel(1), // Lowest log level - kSecDebugLogLevel = _SecLogLevel(1), // log secinfo - kSecInfoLogLevel = _SecLogLevel(2), // log info - kSecNoticeLogLevel = _SecLogLevel(3), // log notice - kSecWarningLogLevel = _SecLogLevel(4), // log warning - kSecErrorLogLevel = _SecLogLevel(5), // log error - kSecCriticalLogLevel = _SecLogLevel(6), // log critical - kSecAlertLogLevel = _SecLogLevel(7), // log alert - kSecLastLogLevel = _SecLogLevel(15),// Max available log level. - - kSecLogStyleMask = ( 0x30), // Bits 4-5 are used to store log style chhoices. The choice is yours. - kSecLogPlainStyle = _SecLogStyle(0), // Log plain message in code only no built in function names. - kSecLogFunctionStyle = _SecLogStyle(1), // Log full __FUNCTION_NAME__ - kSecLogPrettyFuncStyle=_SecLogStyle(2), // Log full ___PRETTY_FUNCTION__ - kSecLogNameStyle = _SecLogStyle(3), // Log name argument to SecWith() - - kSecFlagMask = ( 0xFFC0), // Bits 4-16 are option flags and can be ored together with | - kSecFirstFlag = ( 1 << 6), // First flag defined - - kSecTraceFlag = ( 1 << 6), // trace this api call - kSecChainFlag = ( 1 << 7), // chain multiple errors together in a array with the last error Enclosing all the others. - kSecFlagAssert = ( 1 << 8), // assert that result is not fail without an error having been thrown - kSecSafeModeFlag = ( 1 << 9), // Do not evaluate format arguments to avoid infinite recursion. - kSecClearPendingFlag = ( 1 << 10), // Clear any pending errors. - kSecLogDisabledFlag = ( 1 << 11), // Logging is disabled. - kSecLogAlwaysFlag = ( 1 << 12), // always log regardless of success or failure - kSecLogEveryActionFlag = ( 1 << 13), // log every action - kSecReservedFlag = ( 1 << 14), // Reserved for future use. - kSecLastFlag = ( 1 << 15), // Reserved for future use. - - - kSecActionsMask = (15 << 16), // Bits 4-16 are option flags and can be ored together with | - kSecLowerLogLevelAction = ( 1 << 16), // Allow the log level to be lowered - kSecTraceAction = ( 1 << 17), // Trace this action. - kSecReserved3Action = ( 1 << 18), // Reserved for future use. - kSecReserved4Action = ( 1 << 19), // Reserved for future use. - kSecReserved5Action = ( 1 << 20), // Reserved for future use. - kSecReserved6Action = ( 1 << 21), // Reserved for future use. - kSecReserved7Action = ( 1 << 22), // Reserved for future use. - kSecReserved8Action = ( 1 << 23), // Reserved for future use. - kSecReserved9Action = ( 1 << 24), // Reserved for future use. - kSecReserved10Action = ( 1 << 25), // Reserved for future use. - kSecReserved11Action = ( 1 << 26), // Reserved for future use. - kSecReserved12Action = ( 1 << 27), // Reserved for future use. - kSecReserved13Action = ( 1 << 28), // Reserved for future use. - kSecReserved14Action = ( 1 << 29), // Reserved for future use. - kSecReserved14Action = ( 1 << 30), // Reserved for future use. - kSecLastAction = ( 1 << 31), // The last action defined. - -}; -typedef uint32_t SecFlagType; - -SecInline SecFlagType _SecFlags(flag, ...) { - SecFlagType _flag = flag; - va_list ap; - va_start(ap, flag); - SecFlagType nextFlag; - while ((nextFlag = va_arg(ap, SecFlagType))) _flag |= nextFlag; - va_end(ap); - return _flag; -} - -SecInline void _SecSetLogLevel(SecFlagType flags[1], SecFlagType newFlags) { - SecFlagType newLevel = _SecLogLevel(newFlags); - if (!newLevel || newFlags & kSecLowerLogLevelAction) - *oldFlags = newLevel & _SecClearMask(newFlags, kSecActionsMask); - else if (newLevel > _SecLogLevel(*oldFlags)) - *oldFlags = _SecClearMask(*oldFlags, kSecLogLevelMask) | newLevel; - // Canot lower log level -} - -SecInline void _SecAction(void *_secResult, void *flags, void *name, CFErrorRef *error, CFMutableArrayRef *chain, CFMutableStringRef *actions, SecFlagType flags, key, CFStringRef action, __VA_ARGS__) { -} - -SecInline void _SecSetFlags(SecFlagType oldFlags[1], SecFlagType newFlags) { - // Log level can't be lowered unless kSecLowerLogLevelAction is present in newFlags. - newLevel = newFlags & kSecLogLevelMask - if (!newLevel || newFlags & kSecLowerLogLevelAction) - *oldFlags = newFlags & (kSecLogLevelMask | kSecFlagMask); - else if (newLevel > _SecLogLevel(*oldFlags)) - *oldFlags = _SecClearMask(*oldFlags, kSecLogLevelMask) - (_SecLogLevel(newFlags)) ? _SecClearMask(*oldFlags); - *oldFlags |= newFlags; -} - -SecInline void _SecEnableFlags(SecFlagType oldFlags[1], SecFlagType newFlags) { - (_SecLogLevel(newFlags)) ? _SecClearMask(*oldFlags); - *oldFlags |= newFlags; -} - -SecInline void _SecDisableFlags(SecFlagType oldFlags[1], SecFlagType newFlags) { -} - -__END_DECLS - -#endif /* _UTILITIES_SECMETA_H_ */ diff --git a/OSX/utilities/src/SecNSAdditions.h b/OSX/utilities/src/SecNSAdditions.h new file mode 100644 index 00000000..d3c2d9cb --- /dev/null +++ b/OSX/utilities/src/SecNSAdditions.h @@ -0,0 +1,73 @@ +// +// SecNSAdditions.h +// Security +// + +#ifndef _SECNSADDITIONS_H_ +#define _SECNSADDITIONS_H_ + +#import + +static inline BOOL NSIsEqualSafe(NSObject* obj1, NSObject* obj2) { + return obj1 == nil ? (obj2 == nil) : [obj1 isEqual:obj2]; +} + + +// MARK: NSArray + +@interface NSArray (compactDescription) +- (NSMutableString*) concatenateWithSeparator: (NSString*) separator; +@end + +@interface NSDictionary (SOSDictionaryFormat) +- (NSString*) compactDescription; +@end + +@interface NSMutableDictionary (FindAndRemove) +-(NSObject*)extractObjectForKey:(NSString*)key; +@end + +// MARK: NSSet + +@interface NSSet (Emptiness) +- (bool) isEmpty; +@end + +@interface NSSet (HasElements) +- (bool) containsElementsNotIn: (NSSet*) other; +@end + +@interface NSSet (compactDescription) +- (NSString*) shortDescription; +@end + +@interface NSSet (Stringizing) +- (NSString*) sortedElementsJoinedByString: (NSString*) separator; +- (NSString*) sortedElementsTruncated: (NSUInteger) length JoinedByString: (NSString*) separator; +@end + + + +// MARK: NSString + +static inline NSString* asNSString(NSObject* object) { + return [object isKindOfClass:[NSString class]] ? (NSString*) object : nil; +} + +@interface NSString (FileOutput) +- (void) writeTo: (FILE*) file; +- (void) writeToStdOut; +- (void) writeToStdErr; +@end + +// MARK: NSData + +@interface NSData (Hexinization) +- (NSString*) asHexString; +@end + +@interface NSMutableData (filledAndClipped) ++ (instancetype) dataWithSpace: (NSUInteger) initialSize DEREncode: (uint8_t*(^)(size_t size, uint8_t *buffer)) initialization; +@end + +#endif /* SecNSAdditions_h */ diff --git a/OSX/utilities/src/SecNSAdditions.m b/OSX/utilities/src/SecNSAdditions.m new file mode 100644 index 00000000..82b6cbfd --- /dev/null +++ b/OSX/utilities/src/SecNSAdditions.m @@ -0,0 +1,132 @@ +// +// SecNSAdditions.m +// utilities +// + + +#import +#include + +// MARK: NSArray + +@implementation NSArray (compactDescription) +- (NSMutableString*) concatenateWithSeparator: (NSString*) separator { + NSMutableString* result = [NSMutableString string]; + NSString* currentSeparator = @""; + + for(NSString* string in self) { + [result appendString:currentSeparator]; + [result appendString:[string description]]; + currentSeparator = separator; + } + + return result; +} +@end + +// MARK: NSDictionary + +@implementation NSDictionary (SOSDictionaryFormat) +- (NSString*) compactDescription +{ + NSMutableArray *elements = [NSMutableArray array]; + [self enumerateKeysAndObjectsUsingBlock: ^(NSString *key, id obj, BOOL *stop) { + [elements addObject: [key stringByAppendingString: @":"]]; + if ([obj isKindOfClass:[NSArray class]]) { + [elements addObject: [(NSArray *)obj componentsJoinedByString: @" "]]; + } else { + [elements addObject: [NSString stringWithFormat:@"%@", obj]]; + } + }]; + return [elements componentsJoinedByString: @" "]; +} +@end + + +@implementation NSMutableDictionary (FindAndRemove) +-(NSObject*)extractObjectForKey:(NSString*)key +{ + NSObject* result = [self objectForKey:key]; + [self removeObjectForKey: key]; + return result; +} +@end + + + +// MARK: NSSet + +@implementation NSSet (Emptiness) +- (bool) isEmpty +{ + return [self count] == 0; +} +@end + +@implementation NSSet (HasElements) +- (bool) containsElementsNotIn: (NSSet*) other +{ + __block bool hasElements = false; + [self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { + if (![other containsObject:obj]) { + hasElements = true; + *stop = true; + } + }]; + return hasElements; +} + +@end + +@implementation NSSet (compactDescription) +- (NSString*) shortDescription { + return [NSString stringWithFormat: @"{[%@]}", [[[self allObjects] sortedArrayUsingSelector:@selector(compare:)] concatenateWithSeparator: @", "]]; +} +@end + +@implementation NSSet (Stringizing) +- (NSString*) sortedElementsJoinedByString: (NSString*) separator { + return [self sortedElementsTruncated: 0 JoinedByString: separator]; +} + +- (NSString*) sortedElementsTruncated: (NSUInteger) length JoinedByString: (NSString*) separator +{ + NSMutableArray* strings = [NSMutableArray array]; + + [self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { + NSString *stringToInsert = nil; + if ([obj isKindOfClass: [NSString class]]) { + stringToInsert = obj; + } else { + stringToInsert = [obj description]; + } + + if (length > 0 && length < stringToInsert.length) { + stringToInsert = [stringToInsert substringToIndex:length]; + } + + [strings insertObject:stringToInsert atIndex:0]; + }]; + + [strings sortUsingSelector: @selector(compare:)]; + + return [strings componentsJoinedByString:separator]; +} +@end + +@implementation NSMutableData (filledAndClipped) ++ (instancetype) dataWithSpace: (NSUInteger) initialSize DEREncode: (uint8_t*(^)(size_t size, uint8_t *buffer)) initialization { + NSMutableData* result = [NSMutableData dataWithLength: initialSize]; + + uint8_t* beginning = result.mutableBytes; + uint8_t* encode_begin = initialization(initialSize, beginning); + + if (beginning <= encode_begin && encode_begin <= (encode_begin + initialSize)) { + [result replaceBytesInRange:NSMakeRange(0, encode_begin - beginning) withBytes:NULL length:0]; + } else { + result = nil; + } + + return result; +} +@end diff --git a/OSX/utilities/src/SecPLWrappers.h b/OSX/utilities/src/SecPLWrappers.h new file mode 100644 index 00000000..2922aefd --- /dev/null +++ b/OSX/utilities/src/SecPLWrappers.h @@ -0,0 +1,48 @@ +/* + * 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 SecPLWrapper_h +#define SecPLWrapper_h + + +#if __OBJC__ + +#import + +extern bool SecPLShouldLogRegisteredEvent(NSString *event); + +extern void SecPLLogRegisteredEvent(NSString *eventName, NSDictionary *eventDictionary); +extern void SecPLLogTimeSensitiveRegisteredEvent(NSString *eventName, NSDictionary *eventDictionary); + +#else + +#include + +extern bool SecPLShouldLogRegisteredEvent(CFStringRef event); + +extern void SecPLLogRegisteredEvent(CFStringRef eventName, CFDictionaryRef eventDictionary); +extern void SecPLLogTimeSensitiveRegisteredEvent(CFStringRef eventName, CFDictionaryRef eventDictionary); + +#endif + +#endif /* SecPLWrapper_h */ diff --git a/OSX/utilities/src/SecPLWrappers.m b/OSX/utilities/src/SecPLWrappers.m new file mode 100644 index 00000000..5bdd94bc --- /dev/null +++ b/OSX/utilities/src/SecPLWrappers.m @@ -0,0 +1,99 @@ +/* + * 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@ + */ + +#include +#include +#include "SecPLWrappers.h" + +#if TARGET_OS_EMBEDDED +#include + +static typeof(PLShouldLogRegisteredEvent) *soft_PLShouldLogRegisteredEvent = NULL; +static typeof(PLLogRegisteredEvent) *soft_PLLogRegisteredEvent = NULL; +static typeof(PLLogTimeSensitiveRegisteredEvent) *soft_PLLogTimeSensitiveRegisteredEvent = 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/PowerLog.framework"), kCFURLPOSIXPathStyle, true); + if (url == NULL) + return; + + bundle = CFBundleCreate(kCFAllocatorDefault, url); + CFRelease(url); + if (bundle == NULL) + return; + + soft_PLShouldLogRegisteredEvent = CFBundleGetFunctionPointerForName(bundle, CFSTR("PLShouldLogRegisteredEvent")); + soft_PLLogRegisteredEvent = CFBundleGetFunctionPointerForName(bundle, CFSTR("PLLogRegisteredEvent")); + soft_PLLogTimeSensitiveRegisteredEvent = CFBundleGetFunctionPointerForName(bundle, CFSTR("PLLogTimeSensitiveRegisteredEvent")); + + if (soft_PLShouldLogRegisteredEvent == NULL || + soft_PLLogRegisteredEvent == NULL || + soft_PLLogTimeSensitiveRegisteredEvent == NULL) + { + CFRelease(bundle); + bundle = NULL; + } + }); + return bundle != NULL; +} + + +#endif + +bool SecPLShouldLogRegisteredEvent(NSString *event) +{ +#if TARGET_OS_EMBEDDED + if (setup()) + return soft_PLShouldLogRegisteredEvent(PLClientIDSecurity, (__bridge CFStringRef)event); +#endif + return false; +} + +void SecPLLogRegisteredEvent(NSString *eventName, NSDictionary *eventDictionary) +{ +#if TARGET_OS_EMBEDDED + if (setup()) + soft_PLLogRegisteredEvent(PLClientIDSecurity, + (__bridge CFStringRef)eventName, + (__bridge CFDictionaryRef)eventDictionary, + NULL); +#endif +} + +void SecPLLogTimeSensitiveRegisteredEvent(NSString *eventName, NSDictionary *eventDictionary) +{ +#if TARGET_OS_EMBEDDED + if (setup()) + soft_PLLogTimeSensitiveRegisteredEvent(PLClientIDSecurity, + (__bridge CFStringRef)eventName, + (__bridge CFDictionaryRef)eventDictionary, + NULL); +#endif +} + diff --git a/OSX/utilities/src/SecPaddingConfigurations.c b/OSX/utilities/src/SecPaddingConfigurations.c new file mode 100644 index 00000000..c20e38e8 --- /dev/null +++ b/OSX/utilities/src/SecPaddingConfigurations.c @@ -0,0 +1,94 @@ +/* + * 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@ + */ + +#define SecPaddingDomain CFSTR("com.apple.security.padding") + +typedef enum { + SecPaddingErrorUnknownType = -1 +} SecPaddingError; + +#include "debugging.h" +#include "SecCFError.h" +#include "SecCFWrappers.h" +#include "SecPaddingConfigurationsPriv.h" + +#pragma mark Padding Helper Methods + +// Compute the next power of two +// Requires: v <= UINT64_MAX/2 +static uint64_t nextPowerOfTwo(uint64_t v) +{ + if (v > (UINT64_MAX>>1)) { + secerror("Overflowing uint64_t by requesting nextPowerOfTwo of: %llx", v); + assert(0); + } + if (v & (v - 1)) { + // Not already a power of 2 + return ((uint64_t)1 << ((int)sizeof(v)*8 - __builtin_clzll(v))); + } else { + // Already a power of 2 + return v; + } +} + +// Round to a multiple of n +// Requires: v+n <= UINT64_MAX +static uint64_t nextMultiple(uint64_t v,uint64_t n) +{ + // Multiples of 0 are 0. Preventing division by 0. + if (n == 0) { + return 0; + } + + if (n <= 0 || v > (UINT64_MAX-n)) { + secerror("Overflowing uint64_t by requesting nextMutiple with parameters v: %llx and n: %llx", v, n); + assert(0); + } + return n*((v+n-1)/n); +} + +#pragma mark Padding Configurations + +int64_t SecPaddingCompute(SecPaddingType type, uint32_t size, CFErrorRef *error) { + if (type != SecPaddingTypeMMCS) { + if (error) { + *error = CFErrorCreate(CFAllocatorGetDefault(), SecPaddingDomain, SecPaddingErrorUnknownType, NULL); + } + return SecPaddingErrorUnknownType; + } + + int64_t paddedSize = 0; + + if (size <= 64){ + paddedSize = 64; + } else if (size <= 1024) { + paddedSize = nextPowerOfTwo(size); + } else if (size <= 32000) { + paddedSize = nextMultiple(size, 1024); + } else { + paddedSize = nextMultiple(size, 8192); + } + + assert(paddedSize >= size); + return paddedSize - size; +} diff --git a/OSX/utilities/src/SecPaddingConfigurationsPriv.h b/OSX/utilities/src/SecPaddingConfigurationsPriv.h new file mode 100644 index 00000000..5a736585 --- /dev/null +++ b/OSX/utilities/src/SecPaddingConfigurationsPriv.h @@ -0,0 +1,45 @@ +/* + * 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 SecPaddingConfigurations_h +#define SecPaddingConfigurations_h + +#include + +typedef CF_ENUM(uint8_t, SecPaddingType) { + SecPaddingTypeMMCS CF_ENUM_AVAILABLE(10_13, 11_0) = 0, +} CF_ENUM_AVAILABLE(10_13, 11_0); + +/*! + @function + @abstract Compute the padding size given the size of the content + @param type Type of content to be protected + @param size size before padding + @param error Output parameter to a CFErrorRef + @result number of bytes to add to the message. Only returns a negative value on SecPaddingType mismatch with a CFError assigned + */ +int64_t SecPaddingCompute(SecPaddingType type, uint32_t size, CFErrorRef *error) +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +#endif diff --git a/OSX/utilities/src/debugging.c b/OSX/utilities/src/debugging.c index 22503b41..124fae55 100644 --- a/OSX/utilities/src/debugging.c +++ b/OSX/utilities/src/debugging.c @@ -44,6 +44,7 @@ #include #include #include +#include const char *api_trace = "api_trace"; @@ -412,29 +413,33 @@ static char *copyScopeStr(CFStringRef scope, char *alternative) { return scopeStr; } -static os_log_t logObjForCFScope(CFStringRef scope) { - static dispatch_once_t onceToken = 0; - __block os_log_t retval = OS_LOG_DISABLED; - static dispatch_queue_t logObjectQueue = NULL; +os_log_t +secLogObjForCFScope(CFStringRef scope) +{ + os_log_t retval = OS_LOG_DISABLED; + static os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; static CFMutableDictionaryRef scopeMap = NULL; - - if(scope == NULL) scope = CFSTR("logging"); - - dispatch_once(&onceToken, ^{ - logObjectQueue = dispatch_queue_create("logObjectQueue", DISPATCH_QUEUE_SERIAL); + + if (scope == NULL) { + scope = CFSTR("logging"); + } + + os_unfair_lock_lock_with_options(&lock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); + + if (scopeMap == NULL) { scopeMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, NULL); - }); + } - dispatch_sync(logObjectQueue, ^{ - retval = (os_log_t) CFDictionaryGetValue(scopeMap, scope); - if (retval) return; - + retval = (os_log_t)CFDictionaryGetValue(scopeMap, scope); + if (retval == NULL) { CFStringPerformWithCString(scope, ^(const char *scopeStr) { CFDictionaryAddValue(scopeMap, scope, os_log_create("com.apple.securityd", scopeStr)); }); - retval = (os_log_t) CFDictionaryGetValue(scopeMap, scope); - }); - + retval = (os_log_t)CFDictionaryGetValue(scopeMap, scope); + } + + os_unfair_lock_unlock(&lock); + return retval; } @@ -460,17 +465,12 @@ void secLogEnable(void) { pthread_mutex_unlock(&loggingMutex); } -os_log_t logObjForScope(const char *scope) -{ - return secLogObjForScope(scope); -} - os_log_t secLogObjForScope(const char *scope) { if (!secLogEnabled()) return OS_LOG_DISABLED; CFStringRef cfscope = NULL; if(scope) cfscope = CFStringCreateWithCString(kCFAllocatorDefault, scope, kCFStringEncodingASCII); - os_log_t retval = logObjForCFScope(cfscope); + os_log_t retval = secLogObjForCFScope(cfscope); CFReleaseNull(cfscope); return retval; } @@ -506,7 +506,6 @@ CFStringRef SecLogAPICreate(bool apiIn, const char *api, CFStringRef format, ... } #if TARGET_OS_OSX -#ifdef NO_OS_LOG // Functions for weak-linking os_log functions #include @@ -548,6 +547,5 @@ weak_log_f(os_log_type_enabled, weak_os_log_type_enabled, bool, return false); #undef weak_log_f -#endif // NO_OS_LOG #endif // TARGET_OS_OSX diff --git a/OSX/utilities/src/debugging.h b/OSX/utilities/src/debugging.h index 6a716d53..8c1f411d 100644 --- a/OSX/utilities/src/debugging.h +++ b/OSX/utilities/src/debugging.h @@ -76,31 +76,22 @@ __BEGIN_DECLS #define SECLOG_LEVEL_DEBUG 7 #include -extern os_log_t logObjForScope(const char *scope); /* XXX don't use me, remove */ extern os_log_t secLogObjForScope(const char *scope); +extern os_log_t secLogObjForCFScope(CFStringRef scope); extern bool secLogEnabled(void); extern void secLogDisable(void); extern void secLogEnable(void); #if TARGET_OS_OSX -#define NO_OS_LOG 1 -#ifdef NO_OS_LOG - -// There might be no os_log available. Weak link their internal functions. +// Downstream projects link these, but we no longer use them internally. Keep them here for now. +// Remove weak-linked os_log functions void weak_os_log_impl(void *dso, os_log_t log, os_log_type_t type, const char *format, uint8_t *buf, unsigned int size); -#define _os_log_impl weak_os_log_impl - -#undef os_log_create os_log_t weak_os_log_create(const char *subsystem, const char *category); -#define os_log_create weak_os_log_create - bool weak_os_log_type_enabled(os_log_t oslog, os_log_type_t type); -#define os_log_type_enabled weak_os_log_type_enabled - -#endif // NO_OS_LOG #endif // TARGET_OS_OSX -CFStringRef SecLogAPICreate(bool apiIn, const char *api, CFStringRef format, ...); +CFStringRef SecLogAPICreate(bool apiIn, const char *api, CFStringRef format, ...) + CF_FORMAT_FUNCTION(3, 4); extern const char *api_trace; @@ -163,6 +154,7 @@ void __security_stackshotreport(CFStringRef reason, uint32_t code); #define __sec_exception_code_CKD_nil_pending_keys __sec_exception_code(9) #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) /* For testing only, turns off/on simulated crashes, when turning on, returns number of simulated crashes which were not reported since last turned off. */ diff --git a/OSX/utilities/src/der_plist_internal.c b/OSX/utilities/src/der_plist_internal.c index 1fded953..017834f1 100644 --- a/OSX/utilities/src/der_plist_internal.c +++ b/OSX/utilities/src/der_plist_internal.c @@ -28,7 +28,3 @@ #include CFStringRef sSecDERErrorDomain = CFSTR("com.apple.security.cfder.error"); - -bool SecCFDERCreateError(CFIndex errorCode, CFStringRef descriptionString, CFErrorRef previousError, CFErrorRef *newError) { - return SecCFCreateError(errorCode, sSecDERErrorDomain, descriptionString, previousError, newError); -} diff --git a/OSX/utilities/src/der_plist_internal.h b/OSX/utilities/src/der_plist_internal.h index b5090a15..6b334d8e 100644 --- a/OSX/utilities/src/der_plist_internal.h +++ b/OSX/utilities/src/der_plist_internal.h @@ -26,9 +26,11 @@ #define _DER_PLIST_INTERNAL_H_ #include +#include // Always returns false, to satisfy static analysis -bool SecCFDERCreateError(CFIndex errorCode, CFStringRef descriptionString, CFErrorRef previousError, CFErrorRef *newError); +#define SecCFDERCreateError(errorCode, descriptionString, previousError, newError) \ + SecCFCreateErrorWithFormat(errorCode, sSecDERErrorDomain, previousError, newError, NULL, descriptionString) // CFArray <-> DER diff --git a/OSX/utilities/src/fileIo.c b/OSX/utilities/src/fileIo.c index c92edad9..504ec7c0 100644 --- a/OSX/utilities/src/fileIo.c +++ b/OSX/utilities/src/fileIo.c @@ -37,7 +37,7 @@ int writeFileSizet( } fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600); - if(fd < 0) { + if(fd == -1) { return errno; } wrc = write(fd, bytes, (size_t)numBytes); @@ -72,7 +72,7 @@ int readFileSizet( *numBytes = 0; *bytes = NULL; fd = open(fileName, O_RDONLY); - if(fd < 0) { + if(fd == -1) { return errno; } rtn = fstat(fd, &sb); diff --git a/OSX/utilities/src/iCloudKeychainTrace.c b/OSX/utilities/src/iCloudKeychainTrace.c index 48cc7a3f..8490084d 100644 --- a/OSX/utilities/src/iCloudKeychainTrace.c +++ b/OSX/utilities/src/iCloudKeychainTrace.c @@ -45,11 +45,14 @@ static const char* gTopLevelKeyForiCloudKeychainTracing = "com.apple.icdp.Keycha #endif #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) -#include +#include -static const char* gMessageTracerSetPrefix = "com.apple.message."; +struct msgtracer_instance { + msgtracer_msg_t message; + msgtracer_domain_t domain; +}; -static const char* gMessageTracerDomainField = "com.apple.message.domain"; +static const char* gMessageTracerSetPrefix = "com.apple.message."; /* -------------------------------------------------------------------------- Function: OSX_BeginCloudKeychainLoggingTransaction @@ -60,24 +63,27 @@ static const char* gMessageTracerDomainField = "com.apple.message.domain"; all of the transactions items into a single log making the message tracer folks happy. - The work of this function is to create the aslmsg context - and set the domain field and then return the aslmsg - context as a void* + The work of this function is to ask msgtracer for a domain, + create a message and return the pair as a void *. -------------------------------------------------------------------------- */ -static void* OSX_BeginCloudKeychainLoggingTransaction() +static void *OSX_BeginCloudKeychainLoggingTransaction() { - void* result = NULL; - aslmsg mAsl = NULL; - mAsl = asl_new(ASL_TYPE_MSG); - if (NULL == mAsl) - { - return result; - } - - asl_set(mAsl, gMessageTracerDomainField, gTopLevelKeyForiCloudKeychainTracing); - - result = (void *)mAsl; - return result; + + struct msgtracer_instance *instance = calloc(1, sizeof *instance); + if (!instance) { + return NULL; + } + + instance->domain = msgtracer_domain_new(gTopLevelKeyForiCloudKeychainTracing); + if (instance->domain) { + instance->message = msgtracer_msg_new(instance->domain); + if (instance->message) { + return (void *)instance; + } + msgtracer_domain_free(instance->domain); + } + free(instance); + return NULL; } /* -------------------------------------------------------------------------- @@ -89,16 +95,17 @@ static void* OSX_BeginCloudKeychainLoggingTransaction() NOTE: The key should be a simple key such as "numberOfPeers". This is because this function will - apptend the required prefix of "com.apple.message." + prepend the required prefix of "com.apple.message." -------------------------------------------------------------------------- */ -static bool OSX_AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStringRef key, int64_t value) +static bool OSX_AddKeyValuePairToKeychainLoggingTransaction(void *token, CFStringRef key, int64_t value) { if (NULL == token || NULL == key) { return false; } - - aslmsg mAsl = (aslmsg)token; + + struct msgtracer_instance *instance = (struct msgtracer_instance *)token; + msgtracer_msg_t msg = instance->message; // Fix up the key CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key); @@ -110,7 +117,7 @@ static bool OSX_AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStrin CFIndex key_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key), kCFStringEncodingUTF8); key_length += 1; // For null char key_buffer[key_length]; - memset(key_buffer, 0,key_length); + memset(key_buffer, 0, key_length); if (!CFStringGetCString(real_key, key_buffer, key_length, kCFStringEncodingUTF8)) { CFRelease(real_key); @@ -135,7 +142,7 @@ static bool OSX_AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStrin } CFRelease(value_str); - asl_set(mAsl, key_buffer, value_buffer); + msgtracer_set(msg, key_buffer, value_buffer); return true; } @@ -147,13 +154,15 @@ static bool OSX_AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStrin "bunch" of items being logged, this function will do the real logging and free the aslmsg context. -------------------------------------------------------------------------- */ -static void OSX_CloseCloudKeychainLoggingTransaction(void* token) +static void OSX_CloseCloudKeychainLoggingTransaction(void *token) { if (NULL != token) { - aslmsg mAsl = (aslmsg)token; - asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, ""); - asl_free(mAsl); + struct msgtracer_instance *instance = (struct msgtracer_instance *)token; + msgtracer_log(instance->message, ASL_LEVEL_NOTICE, ""); + msgtracer_msg_free(instance->message); + msgtracer_domain_free(instance->domain); + free(instance); } } @@ -174,15 +183,21 @@ static bool OSX_SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value) { return result; } - - aslmsg mAsl = NULL; - mAsl = asl_new(ASL_TYPE_MSG); - if (NULL == mAsl) - { - return result; - } - - // Fix up the key + + msgtracer_msg_t message = NULL; + msgtracer_domain_t domain = msgtracer_domain_new(gTopLevelKeyForiCloudKeychainTracing); + + if (NULL == domain) { + return result; + } + + message = msgtracer_msg_new(domain); + if (NULL == message) { + msgtracer_domain_free(domain); + return result; + } + + // Fix up the key CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key); if (NULL == real_key) { @@ -204,7 +219,7 @@ static bool OSX_SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value) CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value); if (NULL == value_str) { - asl_free(mAsl); + msgtracer_msg_free(message); return result; } @@ -214,17 +229,16 @@ static bool OSX_SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value) memset(value_buffer, 0, value_str_numBytes); if (!CFStringGetCString(value_str, value_buffer, value_str_numBytes, kCFStringEncodingUTF8)) { - asl_free(mAsl); + msgtracer_msg_free(message); CFRelease(value_str); return result; } CFRelease(value_str); - - asl_set(mAsl, gMessageTracerDomainField, gTopLevelKeyForiCloudKeychainTracing); - - asl_set(mAsl, key_buffer, value_buffer); - asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, "%s is %lld", key_buffer, value); - asl_free(mAsl); + + msgtracer_set(message, key_buffer, value_buffer); + msgtracer_log(message, ASL_LEVEL_NOTICE, "%s is %lld", key_buffer, value); + msgtracer_msg_free(message); + msgtracer_domain_free(domain); return true; } diff --git a/OSX/utilities/src/iOSforOSX-SecAttr.c b/OSX/utilities/src/iOSforOSX-SecAttr.c index f6d1cced..b842012d 100644 --- a/OSX/utilities/src/iOSforOSX-SecAttr.c +++ b/OSX/utilities/src/iOSforOSX-SecAttr.c @@ -52,7 +52,6 @@ SEC_CONST_DECL (kSecUseAuthenticationUIFail, "u_AuthUIF"); SEC_CONST_DECL (kSecUseAuthenticationUISkip, "u_AuthUIS"); SEC_CONST_DECL (kSecUseAuthenticationContext, "u_AuthCtx"); SEC_CONST_DECL (kSecUseToken, "u_Token"); -SEC_CONST_DECL (kSecUseTokenObjectID, "u_TokenOID"); SEC_CONST_DECL (kSecUseCallerName, "u_CallerName"); #endif diff --git a/OSX/utilities/src/sec_action.c b/OSX/utilities/src/sec_action.c new file mode 100644 index 00000000..30a21842 --- /dev/null +++ b/OSX/utilities/src/sec_action.c @@ -0,0 +1,116 @@ +/* + * 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@ + */ + +#include +#include +#include + +#include "sec_action.h" + +struct sec_action_context_s { + dispatch_queue_t queue; + dispatch_source_t source; + dispatch_block_t handler; + uint64_t interval; +}; + +static void _sec_action_event(void *ctx); +static void _sec_action_finalize(void *ctx); + +#pragma mark - + +sec_action_t +sec_action_create_with_queue(dispatch_queue_t queue, const char *label, uint64_t interval) +{ + dispatch_source_t source; + struct sec_action_context_s *context; + if (queue) { + dispatch_retain(queue); + } else { + queue = dispatch_queue_create(label, DISPATCH_QUEUE_SERIAL); + } + source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue); + + context = malloc(sizeof(*context)); + context->queue = queue; + context->source = source; + context->handler = NULL; + context->interval = interval; + dispatch_set_context(source, context); + + dispatch_source_set_event_handler_f(source, _sec_action_event); + dispatch_set_finalizer_f(source, _sec_action_finalize); + + return source; +} + +sec_action_t +sec_action_create(const char *label, uint64_t interval) +{ + return sec_action_create_with_queue(NULL, label, interval); +} + +void +sec_action_set_handler(sec_action_t source, dispatch_block_t handler) +{ + struct sec_action_context_s *context; + + context = dispatch_get_context(source); + context->handler = Block_copy(handler); + + dispatch_activate(source); +} + +void +sec_action_perform(sec_action_t source) +{ + dispatch_source_merge_data(source, 1); +} + +#pragma mark - + +static void +_sec_action_event(void *ctx) +{ + struct sec_action_context_s *context = (struct sec_action_context_s *)ctx; + + if (context->handler != NULL) { + context->handler(); + } + + // Suspend the source; resume after specified interval. + dispatch_suspend(context->source); + dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(context->interval * NSEC_PER_SEC)), context->queue, context->source, (dispatch_function_t)dispatch_resume); +} + +static void +_sec_action_finalize(void *ctx) +{ + struct sec_action_context_s *context = (struct sec_action_context_s *)ctx; + + dispatch_release(context->queue); + if (context->handler != NULL) { + Block_release(context->handler); + } + free(context); +} diff --git a/OSX/utilities/src/sec_action.h b/OSX/utilities/src/sec_action.h new file mode 100644 index 00000000..788902ec --- /dev/null +++ b/OSX/utilities/src/sec_action.h @@ -0,0 +1,80 @@ +/* + * 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_ACTION_H_ +#define _SEC_ACTION_H_ + +#include + +/* + * Simple dispatch-based mechanism to coalesce high-frequency actions like + * notifications. Sample usage: + * + * static void + * notify_frequent_event(void) + * { + * static dispatch_once_t once; + * static sec_action_t action; + * + * dispatch_once(&once, ^{ + * action = sec_action_create("frequent_event", 2); + * sec_action_set_handler(action, ^{ + * (void)notify_post("com.apple.frequent_event"); + * }); + * }); + * + * sec_action_perform(action); + * } + * + * The above will prevent com.apple.frequent_event from being posted more than + * once every 2 seconds. For example, if notify_frequent_event is called 1000 times + * over the span of 1.9s, the handler will be called twice, at 0s and 2s (approx). + * + * Default behavior is to perform actions on a queue with the same QOS as the caller. + * If the action should be performed on a specific serial queue, the function + * sec_action_create_with_queue can alternatively be used. + */ + +typedef dispatch_source_t sec_action_t; + +__BEGIN_DECLS + +DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW +sec_action_t +sec_action_create(const char *label, uint64_t interval); + +DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT DISPATCH_NOTHROW +sec_action_t +sec_action_create_with_queue(dispatch_queue_t queue, const char *label, uint64_t interval); + +DISPATCH_NONNULL_ALL DISPATCH_NOTHROW +void +sec_action_set_handler(sec_action_t action, dispatch_block_t handler); + +DISPATCH_NONNULL_ALL +void +sec_action_perform(sec_action_t action); + +__END_DECLS + +#endif /* _SEC_ACTION_H_ */ diff --git a/OTAPKIAssetTool/OTAPKIAssetTool.xcconfig b/OTAPKIAssetTool/OTAPKIAssetTool.xcconfig index 8d9ab8b2..e4ac768f 100644 --- a/OTAPKIAssetTool/OTAPKIAssetTool.xcconfig +++ b/OTAPKIAssetTool/OTAPKIAssetTool.xcconfig @@ -13,4 +13,4 @@ LAUNCHD_PLIST_INSTALL_DIR = $(DSTROOT)$(SYSTEM_LIBRARY_DIR)/LaunchDaemons // define this for non-sim platforms. OTAPKIASSETTOOL_LAUNCHD_PLIST[sdk=embedded*] = OTAPKIAssetTool/com.apple.OTAPKIAssetTool.plist -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) OSSPINLOCK_USE_INLINED=0 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) CORECRYPTO_DONOT_USE_TRANSPARENT_UNION=1 diff --git a/README b/README index 3732b416..cb203b69 100644 --- a/README +++ b/README @@ -1,3 +1,7 @@ +Update Dec 1, 2016 + +This project wont build without internal headers that are not public. + Update June 17, 2014 Here lie the iOS and OS X versions of Security, including securityd and SecurityTool for OS X. diff --git a/RegressionTests/SecAtomicFile/SecAtomicFile.cpp b/RegressionTests/SecAtomicFile/SecAtomicFile.cpp new file mode 100644 index 00000000..5efea33b --- /dev/null +++ b/RegressionTests/SecAtomicFile/SecAtomicFile.cpp @@ -0,0 +1,62 @@ +// +// Copyright 2017 Apple. All rights reserved. +// + +#include "AtomicFile.h" +#include + +#if 0 +static void +fill_disk(const char *path) +{ + int fd = ::open(path, O_CREAT|O_RDWR, 0600); + if (fd < 0) + errx(1, "failed to create fill file"); + + uint8 buffer[1024] = {}; + ::memset(reinterpret_cast(buffer), 0x77, sizeof(buffer)); + + for (unsigned count = 0; count < 1000; count++) { + if (::write(fd, buffer, sizeof(buffer)) != sizeof(buffer)) { + warn("write fill file failed"); + break; + } + } + if (close(fd) < 0) + warn("close fill file failed"); +} +#endif + +int +main(int argc, char **argv) +{ + int fail = 0; + + if (argc != 2) + errx(1, "argc != 2"); + + try { + AtomicFile file(argv[1]); + + RefPointer temp = file.write(); + + unsigned count = 0; + uint8 buffer[1024] = {}; + ::memset(reinterpret_cast(buffer), 0xff, sizeof(buffer)); + + for (count = 0; count < 1000; count++) { + temp->write(AtomicFile::FromEnd, 0, buffer, sizeof(buffer)); + } + + temp->commit(); + temp = NULL; + } catch (...) { + fail = 1; + } + if (fail) + errx(1, "failed to create new file"); + return 0; +} + + + diff --git a/RegressionTests/Security.plist b/RegressionTests/Security.plist index 36af039c..9542400f 100644 --- a/RegressionTests/Security.plist +++ b/RegressionTests/Security.plist @@ -6,6 +6,14 @@ Security Tests + + TestName + security-sysdiagnose + Command + + /usr/libexec/security-sysdiagnose + + TestName BackupNegativeTest @@ -85,6 +93,50 @@ secd_35_keychain_migrate_inet + + TestName + keychainnetworkextensionsharing-1 + Command + + /AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionstest + + + + TestName + keychainnetworkextensionsharing-2 + Command + + /AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionsystemdaemontest + + + + TestName + keychainnetworkextensionsharing-3 + Command + + /AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionunauthorizedaccesstest + + + + TestName + KCPairingTest + Command + + /AppleInternal/CoreOS/tests/Security/KeychainEntitledTestRunner + -t + KCPairingTests + + + + TestName + AuthorizationTest + Command + + /AppleInternal/CoreOS/tests/Security/authdtest + + EligibleResource + NOT (cpuArchitecture BEGINSWITH 'arm') + diff --git a/RegressionTests/manifeststresstest/Config.h b/RegressionTests/manifeststresstest/Config.h new file mode 100644 index 00000000..d3532bf7 --- /dev/null +++ b/RegressionTests/manifeststresstest/Config.h @@ -0,0 +1,43 @@ +// +// Config.h +// Security +// +// Created by Ben Williamson on 6/2/17. +// +// + +#import + +@interface Config : NSObject + +// Number of distinct item names to chose from. +@property (nonatomic, assign) unsigned distinctNames; + +// Number of distinct data values to chose from. +@property (nonatomic, assign) unsigned distinctValues; + +// Max number of items we are allowed to create. +@property (nonatomic, assign) unsigned maxItems; + +// Probability weighting for adding an item. +@property (nonatomic, assign) unsigned addItemWeight; + +// Probability weighting for updating an item's name. +@property (nonatomic, assign) unsigned updateNameWeight; + +// Probability weighting for updating an item's data. +@property (nonatomic, assign) unsigned updateDataWeight; + +// Probability weighting for updating an item's name and data. +@property (nonatomic, assign) unsigned updateNameAndDataWeight; + +// Probability weighting for deleting an item. +@property (nonatomic, assign) unsigned deleteItemWeight; + +// Additional item name configuration, for isolating changes +@property (nonatomic) NSString *name; + +// Additional view name +@property (nonatomic) NSString *view; + +@end diff --git a/RegressionTests/manifeststresstest/Config.m b/RegressionTests/manifeststresstest/Config.m new file mode 100644 index 00000000..c7f95045 --- /dev/null +++ b/RegressionTests/manifeststresstest/Config.m @@ -0,0 +1,13 @@ +// +// Config.m +// Security +// +// Created by Ben Williamson on 6/2/17. +// +// + +#import "Config.h" + +@implementation Config + +@end diff --git a/RegressionTests/manifeststresstest/Keychain.h b/RegressionTests/manifeststresstest/Keychain.h new file mode 100644 index 00000000..03f6d36f --- /dev/null +++ b/RegressionTests/manifeststresstest/Keychain.h @@ -0,0 +1,31 @@ +// +// Keychain.h +// Security +// +// Created by Ben Williamson on 6/2/17. +// +// + +#import +#import + +@interface Keychain : NSObject + +// Should return errSecSuccess or errSecDuplicateItem +- (OSStatus)addItem:(NSString *)name value:(NSString *)value view:(NSString *)view; +- (OSStatus)addItem:(NSString *)name value:(NSString *)value view:(NSString *)view pRef:(NSArray **)result; + +// Should return errSecSuccess or errSecItemNotFound +- (OSStatus)updateItemWithName:(NSString *)name newValue:(NSString *)newValue; +- (OSStatus)updateItem:(id)pRef newValue:(NSString *)newValue; +- (OSStatus)updateItem:(id)pRef newName:(NSString *)newName; +- (OSStatus)updateItem:(id)pRef newName:(NSString *)newName newValue:(NSString *)newValue; +- (OSStatus)deleteItem:(id)pRef; +- (OSStatus)deleteItemWithName:(NSString *)name; + +// Should return errSecSuccess +- (OSStatus)deleteAllItems; + +- (NSDictionary *)getAllItems; + +@end diff --git a/RegressionTests/manifeststresstest/Keychain.m b/RegressionTests/manifeststresstest/Keychain.m new file mode 100644 index 00000000..fabb306d --- /dev/null +++ b/RegressionTests/manifeststresstest/Keychain.m @@ -0,0 +1,181 @@ +// +// Keychain.m +// Security +// +// Created by Ben Williamson on 6/2/17. +// +// + +#import "Keychain.h" + +/* + * This is to fool os services to not provide the Keychain manager + * interface that doens't work since we don't have unified headers + * between iOS and OS X. rdar://23405418/ + */ +#define __KEYCHAINCORE__ 1 + +#import +#import +#import +#import + +#if SEC_OS_OSX_INCLUDES +#import +#endif + +#import +#import + +static NSString *kAccessGroup = @"manifeststresstest"; +static NSString *kService = @"manifeststresstest"; + + + +@implementation Keychain + +- (OSStatus)addItem:(NSString *)name value:(NSString *)value view:(NSString *)view pRef:(NSArray **)result +{ + NSDictionary *query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : kAccessGroup, + (id)kSecAttrService : kService, + (id)kSecAttrAccount : name, + (id)kSecValueData : [value dataUsingEncoding:NSUTF8StringEncoding], + (id)kSecAttrSynchronizable: (id)kCFBooleanTrue, + (id)kSecAttrNoLegacy : (id)kCFBooleanTrue, + (id)kSecAttrSyncViewHint : view, + (id)kSecReturnPersistentRef: @YES, + }; + CFArrayRef itemRef = NULL; + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, (void *)&itemRef); + if (result) { + *result = CFBridgingRelease(itemRef); + } + + return status; +} + +- (OSStatus)addItem:(NSString *)name value:(NSString *)value view:(NSString *)view +{ + return [self addItem:name value:value view:view pRef:nil]; +} + +- (OSStatus)updateItemWithName:(NSString *)name newValue:(NSString *)newValue +{ + + NSDictionary *query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : kAccessGroup, + (id)kSecAttrService : kService, + (id)kSecAttrAccount : name, + (id)kSecAttrSynchronizable: (id)kCFBooleanTrue, + }; + NSDictionary *modifications = @{ + (id)kSecValueData : [newValue dataUsingEncoding:NSUTF8StringEncoding], + }; + return SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)modifications); +} + +- (OSStatus)updateItem:(id)pRef newValue:(NSString *)newValue +{ + return [self updateItem:pRef modifications:@{ + (id)kSecValueData : [newValue dataUsingEncoding:NSUTF8StringEncoding], + }]; +} + +- (OSStatus)updateItem:(id)pRef newName:(NSString *)newName +{ + return [self updateItem:pRef modifications:@{ + (id)kSecAttrAccount : newName, + }]; +} + +- (OSStatus)updateItem:(id)pRef newName:(NSString *)newName newValue:(NSString *)newValue +{ + return [self updateItem:pRef modifications:@{ + (id)kSecAttrAccount : newName, + (id)kSecValueData : [newValue dataUsingEncoding:NSUTF8StringEncoding], + }]; +} + +- (OSStatus)updateItem:(id)pRef modifications:(NSDictionary *)modifications +{ + NSDictionary *query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecValuePersistentRef: ([pRef isKindOfClass:[NSData class]] ? pRef : pRef[0]), + }; + return SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)modifications); +} + +- (OSStatus)deleteItem:(id)pRef +{ + NSDictionary *query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecValuePersistentRef: ([pRef isKindOfClass:[NSData class]] ? pRef : pRef[0]), + }; + return SecItemDelete((__bridge CFDictionaryRef)query); +} + +- (OSStatus)deleteItemWithName:(NSString *)name +{ + NSDictionary *query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : kAccessGroup, + (id)kSecAttrService : kService, + (id)kSecAttrSynchronizable: (id)kCFBooleanTrue, + (id)kSecAttrAccount : name, + }; + return SecItemDelete((__bridge CFDictionaryRef)query); +} + +- (OSStatus)deleteAllItems +{ + NSDictionary *query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : kAccessGroup, + (id)kSecAttrSynchronizable: (id)kCFBooleanTrue, + }; + return SecItemDelete((__bridge CFDictionaryRef)query); +} + +- (NSDictionary *)getAllItems +{ + CFArrayRef result = NULL; + NSDictionary *query = @{ + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecReturnData : (id)kCFBooleanTrue, + (id)kSecReturnAttributes : (id)kCFBooleanTrue, + (id)kSecReturnPersistentRef : (id)kCFBooleanTrue, + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : kAccessGroup, + (id)kSecAttrService : kService, + (id)kSecAttrNoLegacy : (id)kCFBooleanTrue, + (id)kSecAttrSynchronizable: (id)kCFBooleanTrue, + }; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + if (status == errSecItemNotFound) { + return @{}; + } + if (status != errSecSuccess) { + printf("Error reading items to verify: %d\n", status); + exit(1); + } + NSArray *arr = CFBridgingRelease(result); + + NSMutableDictionary *items = [NSMutableDictionary dictionary]; + for (NSDictionary *dict in arr) { + NSString *name = dict[(id)kSecAttrAccount]; + NSData *data = dict[(id)kSecValueData]; + NSData *ref = dict[(id)kSecValuePersistentRef]; + NSString *value = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (!value) { + printf("Item %s has data that is not valid UTF-8.\n", [name UTF8String]); + exit(1); + } + items[name] = @[ref, value]; + } + return items; +} + +@end diff --git a/RegressionTests/manifeststresstest/Monkey.h b/RegressionTests/manifeststresstest/Monkey.h new file mode 100644 index 00000000..1cc14360 --- /dev/null +++ b/RegressionTests/manifeststresstest/Monkey.h @@ -0,0 +1,52 @@ +// +// Monkey.h +// Security +// +// Created by Ben Williamson on 6/1/17. +// +// + +#import + +@class Config; +@class Keychain; + +// A monkey has an array of items that it has created. +// It can randomly choose to add an item, delete an item, or update the data in an item. +// +// All items exist within the access group "manifeststresstest" +// which is set to have the appropriate view hint so that it syncs via CKKS. +// +// Items are generic password items, having a service, an account and data. +// The service, account and data values are chosen from sets of a limited size, to encourage +// the possibility of collisions. + + +// Adds and deletes generic password items + +@interface Monkey : NSObject + +@property (nonatomic, strong) Keychain *keychain; // if nil, this is a dry run +@property (nonatomic, assign) unsigned step; + +// Incremented when we try to add an item and it already exists. +@property (nonatomic, assign) unsigned addDuplicateCounter; + +// Incremented when we try to update or delete an item and it does not exist. +@property (nonatomic, assign) unsigned notFoundCounter; + +// Peak number of items we have created so far. +@property (nonatomic, assign) unsigned peakItems; + +// Current number of items written +@property (nonatomic, readonly) unsigned itemCount; + +@property (nonatomic, readonly) Config *config; + +- (instancetype)initWithConfig:(Config *)config; + +- (void)advanceOneStep; + +- (void)cleanup; + +@end diff --git a/RegressionTests/manifeststresstest/Monkey.m b/RegressionTests/manifeststresstest/Monkey.m new file mode 100644 index 00000000..5c19899f --- /dev/null +++ b/RegressionTests/manifeststresstest/Monkey.m @@ -0,0 +1,288 @@ +// +// Monkey.m +// Security +// +// Created by Ben Williamson on 6/1/17. +// +// + +#import "Monkey.h" +#import "Config.h" +#import "Keychain.h" + +#import +#import + + +@interface Monkey () + +@property (nonatomic, strong) Config *config; + +// Names that we could choose from when adding a new item. +// When we add an item its name is moved to usedNames. +@property (nonatomic, strong) NSMutableArray *freeNames; + +// Names and persistent references of the items we have written, which we can update or delete. +// When we delete an item its name is moved to freeNames. +@property (nonatomic, strong) NSMutableArray *usedNames; + +@end + + +@implementation Monkey + +- (instancetype)initWithConfig:(Config *)config +{ + if (self = [super init]) { + _config = config; + _freeNames = [NSMutableArray arrayWithCapacity:config.distinctNames]; + _usedNames = [NSMutableArray arrayWithCapacity:config.distinctNames]; + for (unsigned i = 0; i < config.distinctNames; i++) { + if (config.name) { + [_freeNames addObject:[NSString stringWithFormat:@"item-%@-%u", config.name, i]]; + } else { + [_freeNames addObject:[NSString stringWithFormat:@"item-%u", i]]; + } + } + } + return self; +} + +- (void)advanceOneStep +{ + static const int tryLimit = 1000; + for (int tries = 0; tries < tryLimit; tries++) { + if ([self tryAdvanceOneStep]) { + self.step++; + return; + } + } + printf("Chose %d random actions but none of them made sense, giving up!\n", tryLimit); + printf("This is an internal failure of the manifeststresstest tool, not the system under test.\n"); + NSLog(@"Chose %d random actions but none of them made sense, giving up!", tryLimit); + exit(1); +} + +// return YES if it actually took a step, NO if the randomly chosen action was invalid +- (BOOL)tryAdvanceOneStep +{ + unsigned totalWeight = + self.config.addItemWeight + + self.config.updateNameWeight + + self.config.updateDataWeight + + self.config.updateNameAndDataWeight + + self.config.deleteItemWeight; + + if (totalWeight == 0) { + printf("Invalid manifeststresstest configuration:\n" + "At least one weight must be nonzero, or else we cannot choose any action.\n"); + exit(1); + } + if (totalWeight > RAND_MAX) { + printf("Invalid manifeststresstest configuration:\n" + "The total of the weights must not exceed RAND_MAX == %d.\n", RAND_MAX); + exit(1); + } + unsigned r = random() % totalWeight; + + if (r < self.config.addItemWeight) { + return [self addItem]; + } + r -= self.config.addItemWeight; + + if (r < self.config.updateNameWeight) { + return [self updateNameAndValue:NO]; + } + r -= self.config.updateNameWeight; + + if (r < self.config.updateDataWeight) { + return [self updateValue]; + } + r -= self.config.updateDataWeight; + + if (r < self.config.updateNameAndDataWeight) { + return [self updateNameAndValue:YES]; + } + r -= self.config.updateNameAndDataWeight; + + if (r < self.config.deleteItemWeight) { + return [self deleteItem]; + } + NSAssert(false, @"Chosen random number was beyond totalWeight?!?"); + return NO; +} + +- (NSString *)randomValue +{ + if (0 == self.config.distinctValues) { + printf("Invalid manifeststresstest configuration:\n" + "Must allow a nonzero number of distinct values.\n"); + exit(1); + } + unsigned n = random() % self.config.distinctValues; + return [NSString stringWithFormat:@"data-%u", n]; +} + +- (NSString *)prefix +{ + return [NSString stringWithFormat:@"[step:%d items:%d dup:%d gone:%d]", + self.step, + self.itemCount, + self.addDuplicateCounter, + self.notFoundCounter]; +} + +- (void)unexpectedError:(OSStatus)status +{ + NSLog(@"Unexpected error %d at step %d", status, self.step); + exit(1); +} + +- (BOOL)addItem +{ + if ([self.usedNames count] >= self.config.maxItems) { + return NO; + } + NSUInteger freeCount = [self.freeNames count]; + if (freeCount == 0) { + return NO; + } + NSUInteger index = random() % freeCount; + NSString *name = self.freeNames[index]; + NSString *value = [self randomValue]; + + NSLog(@"%@ addItem in %@ %@ = %@", [self prefix], self.config.view, name, value); + NSArray *itemRef = nil; + OSStatus status = [self.keychain addItem:name value:value view:self.config.view pRef:&itemRef]; + switch (status) { + case errSecSuccess: + [self.freeNames removeObjectAtIndex:index]; + [self.usedNames addObject:[NSMutableArray arrayWithArray:@[name, itemRef]]]; + + unsigned usedCount = (unsigned)[self.usedNames count]; + if (self.peakItems < usedCount) { + self.peakItems = usedCount; + } + break; + case errSecDuplicateItem: + self.addDuplicateCounter++; + break; + default: + [self unexpectedError:status]; + } + return YES; +} + +- (BOOL)updateNameAndValue:(BOOL)updateValue +{ + NSUInteger freeCount = [self.freeNames count]; + NSUInteger usedCount = [self.usedNames count]; + if (usedCount == 0 || freeCount == 0) { + return NO; + } + NSUInteger usedIndex = random() % usedCount; + NSUInteger freeIndex = random() % freeCount; + NSMutableArray *oldItem = self.usedNames[usedIndex]; + NSArray *oldRef = oldItem[1]; + NSString *oldName = oldItem[0]; + NSString *newName = self.freeNames[freeIndex]; + + OSStatus status; + if (updateValue) { + NSString *value = [self randomValue]; + NSLog(@"%@ updateNameAndValue %@(%@) -> %@ = %@\n", [self prefix], oldName, oldRef, newName, value); + status = [self.keychain updateItem:oldRef newName:newName newValue:value]; + } else { + NSLog(@"%@ updateName %@(%@) -> %@\n", [self prefix], oldName, oldRef, newName); + status = [self.keychain updateItem:oldRef newName:newName]; + } + switch (status) { + case errSecSuccess: + /* Update tracking arrays */ + [self.freeNames removeObject:newName]; + [self.freeNames addObject:oldName]; + self.usedNames[usedIndex][0] = newName; + break; + case errSecItemNotFound: + /* Update tracking arrays (someone else deleted this item) */ + [self.usedNames removeObject:oldItem]; + [self.freeNames addObject:oldName]; + self.notFoundCounter++; + break; + case errSecDuplicateItem: + self.addDuplicateCounter++; + // newName already exists, which means our attempted updateItem operation + // did not rename oldName to newName, so the item still has oldName. + // No action required. + break; + default: + [self unexpectedError:status]; + } + return YES; +} + +- (BOOL)updateValue +{ + NSUInteger usedCount = [self.usedNames count]; + if (usedCount == 0) { + return NO; + } + NSUInteger usedIndex = random() % usedCount; + NSArray *item = self.usedNames[usedIndex]; + + NSString *value = [self randomValue]; + + NSLog(@"%@ updateValue %@(%@) = %@", [self prefix], item[0], item[1], value); + OSStatus status = [self.keychain updateItem:item[1] newValue:value]; + switch (status) { + case errSecSuccess: + break; + case errSecItemNotFound: + self.notFoundCounter++; + break; + default: + [self unexpectedError:status]; + } + return YES; +} + +- (BOOL)deleteItem +{ + NSUInteger usedCount = [self.usedNames count]; + if (usedCount == 0) { + return NO; + } + NSUInteger usedIndex = random() % usedCount; + NSArray *item = self.usedNames[usedIndex]; + + NSLog(@"%@ deleteItem %@(%@)", [self prefix], item[0], item[1]); + OSStatus status = [self.keychain deleteItem:item[1]]; + switch (status) { + case errSecItemNotFound: + /* someone else deleted this item */ + self.notFoundCounter++; + /* fall through */ + case errSecSuccess: + [self.usedNames removeObjectAtIndex:usedIndex]; + [self.freeNames addObject:item[0]]; + break; + default: + [self unexpectedError:status]; + } + return YES; +} + +- (unsigned)itemCount +{ + return (unsigned)[self.usedNames count]; +} + +- (void)cleanup +{ + for (NSArray *item in self.usedNames) { + NSLog(@"cleanup deleting %@(%@)", item[0], item[1]); + [self.keychain deleteItem:item[1]]; + } +} + +@end diff --git a/RegressionTests/manifeststresstest/manifeststresstest.entitlements b/RegressionTests/manifeststresstest/manifeststresstest.entitlements new file mode 100644 index 00000000..b1f7af78 --- /dev/null +++ b/RegressionTests/manifeststresstest/manifeststresstest.entitlements @@ -0,0 +1,10 @@ + + + + + keychain-access-groups + + manifeststresstest + + + diff --git a/RegressionTests/manifeststresstest/manifeststresstest.m b/RegressionTests/manifeststresstest/manifeststresstest.m new file mode 100644 index 00000000..18782215 --- /dev/null +++ b/RegressionTests/manifeststresstest/manifeststresstest.m @@ -0,0 +1,225 @@ +// +// manifeststresstest.m +// Security +// +// Created by Ben Williamson on 6/1/17. +// +// + +#import +#import + +#import "Monkey.h" +#import "Config.h" +#import "Keychain.h" +#import "mark.h" +#import + +static const char *usage_message = +"Usage: mainfeststresstest [options...]\n" +"\n" +"Commands:\n" +"\n" +" reset Delete all items in the access group. Do this before starting the test.\n" +"\n" +" monkey Randomly add, update and delete items for a while. Then delete those items.\n" +" --seed Seed the random number generator\n" +" --steps Stop after n random actions. Default 1000.\n" +" --maxitems Limit number of items created to n. Default 20.\n" +" --nocleanup Leave the items in place when finished.\n" +" --dryrun Print actions to stdout but don't actually touch the keychain.\n" +" --name Specialize items names (to isolate and avoid interfering changes)\n" +" --view Keychain syncing view name. If not, specified \"Engram\" is used\n" +"\n" +" mark [view] Write some items containing the string , to mark the known finishing\n" +" state for this device. The view argument takes a keychain syncing view name;\n" +" If not specified, the view is \"Engram\".\n" +"\n" +" unmark Delete the items that make up the mark for this id.\n" +"\n" +" update Update the items that make up the mark for this id.\n" +"\n" +" verify ... Check that the access group contains only the marks for the\n" +" given list, corresponding to all the devices being finished.\n" +" If given an empty id list this checks the access group is empty.\n" +" Exits with nonzero status if verification fails.\n" +"\n" +" verify_update ... Check that the access group contains only the updated marks for\n" +" the given list, corresponding to all the devices being\n" +" finished. If given an empty id list this checks the access group\n" +" is empty. Exits with nonzero status if verification fails.\n" +"\n" +"Example:\n" +"\n" +" manifeststresstest reset\n" +" manifeststresstest monkey --seed 12345 --steps 1000 --maxitems 20\n" +" manifeststresstest mark foo\n" +" manifeststresstest verify foo bar baz\n" +"\n" +" One device should run reset to clear the contents of the access group before the test\n" +" begins. Then all devices should run monkey for a while. When each device is finished\n" +" monkeying it should set a pattern with an id that uniquely identifies that device.\n" +" When all devices are finished, one device can verify all the patterns by running the\n" +" verify command with the ids of all of the devices, as it expects to see the patterns\n" +" written by all devices, and no other items.\n" +"\n" +; + +static void usage_exit(void) +{ + printf("%s", usage_message); + exit(1); +} + +int main(int argc, const char ** argv) +{ + @autoreleasepool { + Keychain *keychain = [[Keychain alloc] init]; + + NSArray *args = [[NSProcessInfo processInfo] arguments]; + if ([args count] < 2) { + usage_exit(); + } + NSString *verb = args[1]; + + if ([verb isEqualToString:@"reset"]) { + printf("Reseting\n"); + NSLog(@"reset - deleteAllItems"); + [keychain deleteAllItems]; + + } else if ([verb isEqualToString:@"monkey"]) { + BOOL dryrun = NO; + BOOL cleanup = YES; + unsigned steps = 1000; + Config *config = [[Config alloc] init]; + config.maxItems = 20; + config.distinctNames = 40; + config.distinctValues = 10; + config.addItemWeight = 20; + config.deleteItemWeight = 10; + config.updateNameWeight = 10; + config.updateDataWeight = 10; + config.updateNameAndDataWeight = 10; + config.view = (__bridge NSString *)kSecAttrViewHintEngram; + + NSUInteger i = 2; + while (i < [args count]) { + NSString *opt = args[i++]; + if ([opt isEqualToString:@"--seed"]) { + if (i >= [args count]) { + printf("error: --seed needs a value\n"); + exit(1); + } + unsigned seed = (unsigned)[args[i++] integerValue]; + NSLog(@"Seeding with %d", seed); + srandom(seed); + } else if ([opt isEqualToString:@"--steps"]) { + if (i >= [args count]) { + printf("error: --steps needs a value\n"); + exit(1); + } + steps = (unsigned)[args[i++] integerValue]; + } else if ([opt isEqualToString:@"--maxitems"]) { + if (i >= [args count]) { + printf("error: --maxitems needs a value\n"); + exit(1); + } + config.maxItems = (unsigned)[args[i++] integerValue]; + } else if ([opt isEqualToString:@"--nocleanup"]) { + cleanup = NO; + } else if ([opt isEqualToString:@"--dryrun"]) { + dryrun = YES; + } else if ([opt isEqualToString:@"--name"]) { + if (i >= [args count]) { + printf("error: --name needs a value\n"); + exit(1); + } + config.name = args[i++]; + } else if ([opt isEqualToString:@"--view"]) { + if (i >= [args count]) { + printf("error: --view needs a value\n"); + exit(1); + } + config.view = args[i++]; + } else { + printf("Unrecognised argument %s\n", [opt UTF8String]); + exit(1); + } + } + NSLog(@"steps: %d", steps); + NSLog(@"maxitems: %d", config.maxItems); + NSLog(@"cleanup: %s", cleanup ? "yes" : "no"); + NSLog(@"dryrun: %s", dryrun ? "yes" : "no"); + + Monkey *monkey = [[Monkey alloc] initWithConfig:config]; + if (!dryrun) { + monkey.keychain = keychain; + } + + while (monkey.step < steps) { + [monkey advanceOneStep]; + } + + if (cleanup) { + [monkey cleanup]; + } + + } else if ([verb isEqualToString:@"mark"]) { + if ([args count] < 3) { + printf("mark command needs an identifier\n"); + exit(1); + } + NSString *ident = args[2]; + NSString *view = (__bridge NSString*)kSecAttrViewHintEngram; + if ([args count] == 4) { + view = args[3]; + } + NSLog(@"Writing mark %@", ident); + writeMark(ident, view); + + } else if ([verb isEqualToString:@"unmark"]) { + if ([args count] < 3) { + printf("unmark command needs an identifier\n"); + exit(1); + } + NSString *ident = args[2]; + NSLog(@"Deleting mark %@", ident); + deleteMark(ident); + + } else if ([verb isEqualToString:@"verify"]) { + NSRange range; + range.location = 2; + range.length = args.count - 2; + NSArray *idents = [args subarrayWithRange:range]; + NSLog(@"Verifying, idents = %@", idents); + if (!verifyMarks(idents)) { + NSLog(@"Exiting nonzero status"); + exit(1); + } + + } else if ([verb isEqualToString:@"update"]) { + if ([args count] < 3) { + printf("unmark command needs an identifier\n"); + exit(1); + } + NSString *ident = args[2]; + NSLog(@"Updating mark %@", ident); + updateMark(ident); + + } else if ([verb isEqualToString:@"verify_update"]) { + NSRange range; + range.location = 2; + range.length = args.count - 2; + NSArray *idents = [args subarrayWithRange:range]; + NSLog(@"Verifying, idents = %@", idents); + if (!verifyUpdateMarks(idents)) { + NSLog(@"Exiting nonzero status"); + exit(1); + } + + } else { + usage_exit(); + } + NSLog(@"Done."); + } +} diff --git a/RegressionTests/manifeststresstest/mark.h b/RegressionTests/manifeststresstest/mark.h new file mode 100644 index 00000000..3b0895ef --- /dev/null +++ b/RegressionTests/manifeststresstest/mark.h @@ -0,0 +1,25 @@ +// +// mark.h +// Security +// +// Created by Ben Williamson on 6/2/17. +// +// + +#import + +@class Keychain; + +NSDictionary *markForIdent(NSString *ident); +NSDictionary *updateForIdent(NSString *ident); + +void writeMark(NSString *ident, NSString *view); + +void deleteMark(NSString *ident); + +void updateMark(NSString *ident); + +// Returns YES if the access group contains exactly the expected items +// of the given idents (and no other items) or NO otherwise. +BOOL verifyMarks(NSArray *idents); +BOOL verifyUpdateMarks(NSArray *idents); diff --git a/RegressionTests/manifeststresstest/mark.m b/RegressionTests/manifeststresstest/mark.m new file mode 100644 index 00000000..a5843b5a --- /dev/null +++ b/RegressionTests/manifeststresstest/mark.m @@ -0,0 +1,134 @@ +// +// mark.m +// Security +// +// Created by Ben Williamson on 6/2/17. +// +// + +#import "mark.h" +#import "Keychain.h" + +NSDictionary *markForIdent(NSString *ident) +{ + return @{ + [NSString stringWithFormat:@"mark-%@-a", ident]: @"I", + [NSString stringWithFormat:@"mark-%@-b", ident]: @"am", + [NSString stringWithFormat:@"mark-%@-c", ident]: @"done.", + }; +} + +NSDictionary *updateForIdent(NSString *ident) +{ + return @{ + [NSString stringWithFormat:@"mark-%@-a", ident]: @"Updated,", + [NSString stringWithFormat:@"mark-%@-b", ident]: @"I", + [NSString stringWithFormat:@"mark-%@-c", ident]: @"am.", + }; +} + + +void writeMark(NSString *ident, NSString *view) +{ + Keychain *keychain = [[Keychain alloc] init]; + NSDictionary *dict = markForIdent(ident); + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *stop) { + NSLog(@"Writing mark in %@: %@ = %@", view, name, value); + OSStatus status = [keychain addItem:name value:value view:view]; + switch (status) { + case errSecSuccess: + break; + case errSecDuplicateItem: + NSLog(@"(mark was already there, fine)"); + break; + default: + NSLog(@"Error writing mark %@: %d", name, status); + exit(1); + } + }]; +} + +void deleteMark(NSString *ident) +{ + Keychain *keychain = [[Keychain alloc] init]; + NSDictionary *dict = markForIdent(ident); + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *stop) { + NSLog(@"Deleting mark: %@", name); + [keychain deleteItemWithName:name]; + }]; +} + +void updateMark(NSString *ident) +{ + Keychain *keychain = [[Keychain alloc] init]; + NSDictionary *dict = updateForIdent(ident); + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *stop) { + NSLog(@"Updating mark: %@ = %@", name, value); + OSStatus status = [keychain updateItemWithName:name newValue:value]; + switch (status) { + case errSecSuccess: + break; + case errSecDuplicateItem: + NSLog(@"(updated mark was already there, fine)"); + break; + default: + NSLog(@"Error updating mark %@: %d", name, status); + exit(1); + } + }]; +} + +static BOOL verifyMarksGeneric(NSArray *idents, BOOL updated) +{ + Keychain *keychain = [[Keychain alloc] init]; + + NSMutableDictionary *expected = [NSMutableDictionary dictionary]; + for (NSString *ident in idents) { + NSDictionary *mark = nil; + if (!updated) { + mark = markForIdent(ident); + } else { + mark = updateForIdent(ident); + } + [expected addEntriesFromDictionary:mark]; + } + + NSDictionary *actual = [keychain getAllItems]; + NSMutableDictionary *actualNoPRefs = [NSMutableDictionary dictionary]; + for (NSString *name in actual) { + actualNoPRefs[name] = actual[name][1]; + } + NSLog(@"verifyMarks - getAllItems got %lu items", (unsigned long)actual.count); + + if ([actualNoPRefs isEqualToDictionary:expected]) { + NSLog(@"Verify passed"); + return YES; + } + NSLog(@"Verify failed for idents %@", idents); + + for (NSString *name in actual) { + if (!expected[name]) { + NSLog(@"- unexpected item %@ %@ = %@", actual[name][0], name, actual[name][1]); + } + } + for (NSString *name in expected) { + if (!actual[name]) { + NSLog(@"- missing item %@", name); + continue; + } + if (![actual[name][1] isEqualToString:expected[name]]) { + NSLog(@"- incorrect item %@ %@ = %@ should be %@", actual[name][0], name, actual[name][1], expected[name]); + } + } + return NO; +} + +BOOL verifyMarks(NSArray *idents) +{ + return verifyMarksGeneric(idents, NO); +} + +BOOL verifyUpdateMarks(NSArray *idents) +{ + return verifyMarksGeneric(idents, YES); +} diff --git a/RegressionTests/secitemfunctionality/secitemfunctionality.m b/RegressionTests/secitemfunctionality/secitemfunctionality.m index 53b7556c..96384f8b 100644 --- a/RegressionTests/secitemfunctionality/secitemfunctionality.m +++ b/RegressionTests/secitemfunctionality/secitemfunctionality.m @@ -18,13 +18,8 @@ #include #include -#if !TARGET_OS_IPHONE -/* - * Becuase this file uses the iOS headers and we have no unified the headers - * yet, its not possible to include here because - * of missing type. Pull in prototype needed. - */ -extern OSStatus SecKeychainUnlock(CFTypeRef keychain, UInt32 passwordLength, const void *password, Boolean usePassword); +#if SEC_OS_OSX_INCLUDES +#include #endif static void @@ -35,8 +30,10 @@ static void fail(const char *fmt, ...) { va_list ap; + printf("[FAIL]\n"); + fflush(stdout); + va_start(ap, fmt); - printf("[FAIL] "); verrx(1, fmt, ap); va_end(ap); } @@ -50,7 +47,7 @@ CheckItemAddDeleteMaybeLegacyKeychainNoData(void) { OSStatus status; - printf("[TEST] %s\n", __FUNCTION__); + printf("[BEGIN] %s\n", __FUNCTION__); NSDictionary *query = @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -87,7 +84,7 @@ CheckItemAddDeleteNoData(void) { OSStatus status; - printf("[TEST] %s\n", __FUNCTION__); + printf("[BEGIN] %s\n", __FUNCTION__); NSDictionary *query = @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -123,7 +120,7 @@ CheckItemUpdateAccessGroupGENP(void) { OSStatus status; - printf("[TEST] %s\n", __FUNCTION__); + printf("[BEGIN] %s\n", __FUNCTION__); NSDictionary *clean1 = @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -296,7 +293,7 @@ CheckItemUpdateAccessGroupIdentity(void) OSStatus status; CFTypeRef ref = NULL; - printf("[TEST] %s\n", __FUNCTION__); + printf("[BEGIN] %s\n", __FUNCTION__); NSDictionary *clean1 = @{ (id)kSecClass : (id)kSecClassIdentity, @@ -423,7 +420,7 @@ CheckFindIdentityByReference(void) OSStatus status; CFDataRef pref = NULL, pref2 = NULL; - printf("[TEST] %s\n", __FUNCTION__); + printf("[BEGIN] %s\n", __FUNCTION__); /* * Clean identities @@ -559,11 +556,14 @@ RunCopyPerfTest(NSString *name, NSDictionary *query) CFTypeRef result = NULL; status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); - if (status != 0) - abort(); - uint64_t stop = mach_absolute_time(); + if (status != 0) { + printf("SecItemCopyMatching failed with: %d\n", (int)status); + fflush(stdout); + abort(); + } + if (result) CFRelease(result); @@ -573,12 +573,44 @@ RunCopyPerfTest(NSString *name, NSDictionary *query) name, (unsigned long)us] UTF8String]); } +static void +RunDigestPerfTest(NSString *name, NSString *itemClass, NSString *accessGroup, NSUInteger expectedCount) +{ + uint64_t start = mach_absolute_time(); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + __block uint64_t stop; + + _SecItemFetchDigests(itemClass, accessGroup, ^(NSArray *items, NSError *error) { + stop = mach_absolute_time(); + if (error) { + printf("_SecItemFetchDigests failed with: %ld\n", (long)error.code); + fflush(stdout); + abort(); + } + dispatch_semaphore_signal(sema); + + if (expectedCount != [items count]) { + printf("_SecItemFetchDigests didn't return expected items: %ld\n", (long)[items count]); + fflush(stdout); + abort(); + } + }); + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + + + uint64_t us = timeDiff(start, stop); + + puts([[NSString stringWithFormat:@"[RESULT_KEY] SecItemCopyDigest-%@\n[RESULT_VALUE] %lu\n", + name, (unsigned long)us] UTF8String]); +} + + static void CheckItemPerformance(void) { unsigned n; - printf("[TEST] %s\n", __FUNCTION__); + printf("[BEGIN] %s\n", __FUNCTION__); /* * Clean identities @@ -623,6 +655,7 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecMatchLimit : (id)kSecMatchLimitAll, }); + RunDigestPerfTest(@"Digest1000Items", (id)kSecClassGenericPassword, @"keychain-test1", 1000); RunCopyPerfTest(@"GetAttrOneItemUnique", @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccount : @"account-0", @@ -676,6 +709,8 @@ CheckItemPerformance(void) int main(int argc, const char ** argv) { + printf("[TEST] secitemfunctionality\n"); + #if TARGET_OS_OSX char *user = getenv("USER"); if (user && strcmp("bats", user) == 0) { @@ -691,6 +726,8 @@ main(int argc, const char ** argv) CheckItemUpdateAccessGroupGENP(); CheckItemUpdateAccessGroupIdentity(); + printf("[SUMMARY]\n"); + printf("test completed\n"); return 0; } diff --git a/RegressionTests/seckeychainnetworkextensionstest/main.m b/RegressionTests/seckeychainnetworkextensionstest/main.m new file mode 100644 index 00000000..73caf534 --- /dev/null +++ b/RegressionTests/seckeychainnetworkextensionstest/main.m @@ -0,0 +1,77 @@ +// +// main.m +// seckeychainnetworkextensionstest +// +// Created by Luke Hiesterman on 2/22/17. +// + +#import +#import +#import +#import + +static NSString* NetworkExtensionPersistentRefSharingAccessGroup = @"com.apple.NetworkExtensionPersistentRefSharingAccessGroup"; +static NSString* NetworkExtensionAccessGroup = @"FakeAppPrefix.com.apple.networkextensionsharing"; +static NSString* TestAccount = @"MyTestAccount"; +static NSString* TestPassword = @"MyTestPassword"; + +static void cleanupKeychain() +{ + NSMutableDictionary* attributes = [NSMutableDictionary dictionary]; + attributes[(__bridge NSString*)kSecClass] = (__bridge NSString*)kSecClassGenericPassword; + attributes[(__bridge NSString*)kSecAttrAccessGroup] = NetworkExtensionAccessGroup; + attributes[(__bridge NSString*)kSecAttrAccount] = TestAccount; + attributes[(__bridge NSString*)kSecAttrNoLegacy] = @YES; + SecItemDelete((__bridge CFDictionaryRef)attributes); + + attributes = [NSMutableDictionary dictionary]; + attributes[(__bridge NSString*)kSecClass] = (__bridge NSString*)kSecClassGenericPassword; + attributes[(__bridge NSString*)kSecAttrAccessGroup] = NetworkExtensionPersistentRefSharingAccessGroup; + attributes[(__bridge NSString*)kSecAttrAccount] = TestAccount; + attributes[(__bridge NSString*)kSecAttrNoLegacy] = @YES; + SecItemDelete((__bridge CFDictionaryRef)attributes); + +} + +int main(int argc, const char * argv[]) +{ + @autoreleasepool { + cleanupKeychain(); + + NSMutableDictionary* attributes = [NSMutableDictionary dictionary]; + attributes[(__bridge NSString*)kSecClass] = (__bridge NSString*)kSecClassGenericPassword; + attributes[(__bridge NSString*)kSecAttrAccessGroup] = NetworkExtensionAccessGroup; + attributes[(__bridge NSString*)kSecAttrAccount] = TestAccount; + attributes[(__bridge NSString*)kSecValueData] = [NSData dataWithBytes:TestPassword.UTF8String length:TestPassword.length]; + attributes[(__bridge NSString*)kSecReturnPersistentRef] = @YES; + attributes[(__bridge NSString*)kSecAttrNoLegacy] = @YES; + + CFTypeRef returnData = NULL; + OSStatus result = SecItemAdd((__bridge CFDictionaryRef)attributes, &returnData); + if (result != 0) { + NSLog(@"got an error: %d", (int)result); + errx(1, "failed to add item to keychain"); + } + + if (returnData) { + attributes = [NSMutableDictionary dictionary]; + attributes[(__bridge NSString*)kSecClass] = (__bridge NSString*)kSecClassGenericPassword; + attributes[(__bridge NSString*)kSecAttrAccessGroup] = NetworkExtensionPersistentRefSharingAccessGroup; + attributes[(__bridge NSString*)kSecAttrAccount] = TestAccount; + attributes[(__bridge NSString*)kSecValueData] = (__bridge NSData*)returnData; + attributes[(__bridge NSString*)kSecAttrNoLegacy] = @YES; + + result = SecItemAdd((__bridge CFDictionaryRef)attributes, &returnData); + if (result == 0) { + NSLog(@"successfully stored persistent ref for shared network extension item to keychain"); + } + else { + errx(1, "failed to add persistent ref to keychain"); + } + } + else { + errx(1, "failed to get persistent ref from item added to keychain"); + } + } + return 0; +} diff --git a/RegressionTests/seckeychainnetworkextensionstest/seckeychainnetworkextensionstest.entitlements b/RegressionTests/seckeychainnetworkextensionstest/seckeychainnetworkextensionstest.entitlements new file mode 100644 index 00000000..801fd1fa --- /dev/null +++ b/RegressionTests/seckeychainnetworkextensionstest/seckeychainnetworkextensionstest.entitlements @@ -0,0 +1,11 @@ + + + + + keychain-access-groups + + FakeAppPrefix.com.apple.networkextensionsharing + com.apple.NetworkExtensionPersistentRefSharingAccessGroup + + + diff --git a/RegressionTests/seckeychainnetworkextensionsystemdaemontest/main.m b/RegressionTests/seckeychainnetworkextensionsystemdaemontest/main.m new file mode 100644 index 00000000..c7d13983 --- /dev/null +++ b/RegressionTests/seckeychainnetworkextensionsystemdaemontest/main.m @@ -0,0 +1,50 @@ +// +// main.m +// seckeychainnetworkextensionsystemdaemontest +// +// Created by Luke Hiesterman on 2/23/17. +// + +#import +#import +#import +#import + +static NSString* NetworkExtensionPersistentRefSharingAccessGroup = @"com.apple.NetworkExtensionPersistentRefSharingAccessGroup"; +static NSString* TestAccount = @"MyTestAccount"; + +int main(int argc, const char* argv[]) +{ + @autoreleasepool { + NSMutableDictionary* attributes = [NSMutableDictionary dictionary]; + attributes[(__bridge NSString*)kSecClass] = (__bridge NSString*)kSecClassGenericPassword; + attributes[(__bridge NSString*)kSecAttrAccessGroup] = NetworkExtensionPersistentRefSharingAccessGroup; + attributes[(__bridge NSString*)kSecAttrAccount] = TestAccount; + attributes[(__bridge NSString*)kSecReturnPersistentRef] = @YES; + attributes[(__bridge NSString*)kSecAttrNoLegacy] = @YES; + + CFTypeRef persistentRefData = NULL; + OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &persistentRefData); + if (result != 0 || !persistentRefData) { + NSLog(@"got an error: %d", (int)result); + errx(1, "failed to retrieve persistent ref data from keychain"); + } + + attributes = [NSMutableDictionary dictionary]; + attributes[(__bridge NSString*)kSecClass] = (__bridge NSString*)kSecClassGenericPassword; + attributes[(__bridge NSString*)kSecValuePersistentRef] = (__bridge NSData*)persistentRefData; + attributes[(__bridge NSString*)kSecReturnData] = @YES; + attributes[(__bridge NSString*)kSecAttrNoLegacy] = @YES; + + CFTypeRef passwordData = NULL; + result = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &passwordData); + if (result == 0 && passwordData) { + NSLog(@"successfully fetched shared network extension item from keychain"); + } + else { + NSLog(@"got an error: %d", (int)result); + errx(1, "failed to retrieve password from network extensions access group"); + } + } + return 0; +} diff --git a/RegressionTests/seckeychainnetworkextensionsystemdaemontest/seckeychainnetworkextensionsystemdaemontest.entitlements b/RegressionTests/seckeychainnetworkextensionsystemdaemontest/seckeychainnetworkextensionsystemdaemontest.entitlements new file mode 100644 index 00000000..d1223a5b --- /dev/null +++ b/RegressionTests/seckeychainnetworkextensionsystemdaemontest/seckeychainnetworkextensionsystemdaemontest.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.networkextension.keychain + + keychain-access-groups + + com.apple.NetworkExtensionPersistentRefSharingAccessGroup + + + diff --git a/RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/main.m b/RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/main.m new file mode 100644 index 00000000..8e5609fe --- /dev/null +++ b/RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/main.m @@ -0,0 +1,49 @@ +// +// main.m +// seckeychainnetworkextensionunauthorizedaccesstest +// +// Created by Luke Hiesterman on 2/23/17. +// + +#import +#import +#import +#import + +static NSString* NetworkExtensionPersistentRefSharingAccessGroup = @"com.apple.NetworkExtensionPersistentRefSharingAccessGroup"; +static NSString* TestAccount = @"MyTestAccount"; + +int main(int argc, const char* argv[]) +{ + @autoreleasepool { + NSMutableDictionary* attributes = [NSMutableDictionary dictionary]; + attributes[(__bridge NSString*)kSecClass] = (__bridge NSString*)kSecClassGenericPassword; + attributes[(__bridge NSString*)kSecAttrAccessGroup] = NetworkExtensionPersistentRefSharingAccessGroup; + attributes[(__bridge NSString*)kSecAttrAccount] = TestAccount; + attributes[(__bridge NSString*)kSecReturnData] = @YES; + attributes[(__bridge NSString*)kSecAttrNoLegacy] = @YES; + + CFTypeRef persistentRefData = NULL; + OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &persistentRefData); + if (result != 0 || !persistentRefData) { + NSLog(@"got an error: %d", (int)result); + errx(1, "failed to retrieve persistent ref data from keychain"); + } + + attributes = [NSMutableDictionary dictionary]; + attributes[(__bridge NSString*)kSecClass] = (__bridge NSString*)kSecClassGenericPassword; + attributes[(__bridge NSString*)kSecValuePersistentRef] = (__bridge NSData*)persistentRefData; + attributes[(__bridge NSString*)kSecReturnData] = @YES; + attributes[(__bridge NSString*)kSecAttrNoLegacy] = @YES; + + CFTypeRef passwordData = NULL; + result = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &passwordData); + if (result == 0 && passwordData) { + errx(1, "failed to block unentitled app from accessing network extension keychain item"); + } + else { + NSLog(@"successfully blocked unentitled app from accessing network extension keychain item"); + } + } + return 0; +} diff --git a/RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/seckeychainnetworkextensionunauthorizedaccesstest.entitlements b/RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/seckeychainnetworkextensionunauthorizedaccesstest.entitlements new file mode 100644 index 00000000..eacb4349 --- /dev/null +++ b/RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/seckeychainnetworkextensionunauthorizedaccesstest.entitlements @@ -0,0 +1,10 @@ + + + + + keychain-access-groups + + com.apple.NetworkExtensionPersistentRefSharingAccessGroup + + + diff --git a/SOSCCAuthPlugin/SOSCCAuthPlugin.m b/SOSCCAuthPlugin/SOSCCAuthPlugin.m index ec8a7eef..0de5cbcd 100644 --- a/SOSCCAuthPlugin/SOSCCAuthPlugin.m +++ b/SOSCCAuthPlugin/SOSCCAuthPlugin.m @@ -26,6 +26,7 @@ completion: (dispatch_block_t) completion { BOOL do_auth = NO; + NSString* accountIdentifier = account.identifier; // strong reference secinfo("accounts", "parameters %@", parameters); secinfo("accounts", "account %@", account); @@ -49,10 +50,10 @@ const char *password = [rawPassword cStringUsingEncoding:NSUTF8StringEncoding]; CFDataRef passwordData = CFDataCreate(kCFAllocatorDefault, (const uint8_t *) password, strlen(password)); if (passwordData) { - secinfo("accounts", "Performing SOS circle credential set for account %@: %@", account.identifier, account.username); + secinfo("accounts", "Performing SOS circle credential set for account %@: %@", accountIdentifier, account.username); NSString *dsid = [account aa_personID]; if (!SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef) account.username, passwordData, (__bridge CFStringRef) dsid, &authError)) { - secerror("Unable to set SOS circle credentials for account %@: %@", account.identifier, authError); + secerror("Unable to set SOS circle credentials for account %@: %@", accountIdentifier, authError); CFReleaseNull(authError); } @@ -60,12 +61,12 @@ } } else { if (!SOSCCCanAuthenticate(&authError)) { - secerror("Account %@ did not present a password and we could not authenticate the SOS circle: %@", account.identifier, authError); + secerror("Account %@ did not present a password and we could not authenticate the SOS circle: %@", accountIdentifier, authError); CFReleaseNull(authError); // CFReleaseSafe? } } } else { - secinfo("accounts", "NOT performing SOS circle credential set for account %@: %@", account.identifier, account.username); + secinfo("accounts", "NOT performing SOS circle credential set for account %@: %@", accountIdentifier, account.username); } completion(); diff --git a/Security.exp-in b/Security.exp-in index b74b55f0..7f855391 100644 --- a/Security.exp-in +++ b/Security.exp-in @@ -2,7 +2,7 @@ #include "Security/SecExports.exp-in" #include "Security/SecAccessControlExports.exp-in" -#include "SecureObjectSync/SOSExports.exp-in" +#include "Security/SecureObjectSync/SOSExports.exp-in" #if TARGET_OS_OSX #include "CSSMOID.exp-in" @@ -84,6 +84,8 @@ _SSLGetNPNData _SSLSetALPNData _SSLSetALPNFunc _SSLGetALPNData +_SSLSetALPNProtocols +_SSLCopyALPNProtocols _SSLCopyRequestedPeerName _SSLCopyRequestedPeerNameLength _SSLSetAllowAnonymousCiphers @@ -111,6 +113,9 @@ _SSLWrite _SSLSetDHEEnabled _SSLGetDHEEnabled _SSLSetSessionConfig +_SSLSetSessionTicketsEnabled +_SSLSetError +_SSLSetOCSPResponse _kSSLSessionConfig_default _kSSLSessionConfig_ATSv1 @@ -262,6 +267,9 @@ _SSLGetMinimumDHGroupSize _SSLSetDHEEnabled _SSLGetDHEEnabled _SSLSetSessionConfig +_SSLSetSessionTicketsEnabled +_SSLSetError +_SSLSetOCSPResponse _kSSLSessionConfig_default _kSSLSessionConfig_ATSv1 @@ -289,8 +297,17 @@ _kSSLSessionConfig_anonymous _SecAbsoluteTimeFromDateContent -#if TARGET_OS_IPHONE +/* Internal securityd RPC stuff for tests */ +_OBJC_CLASS_$_SecuritydXPCClient _SecAccessGroupsGetCurrent +_SecAccessGroupsSetCurrent +_SecSecurityClientGet +_securityd_create_message +_securityd_message_with_reply_sync +_securityd_message_no_error +_securityd_send_sync_and_do +#if TARGET_OS_IOS +_SecSecuritySetMusrMode #endif _SecDERItemCopyOIDDecimalRepresentation @@ -414,6 +431,7 @@ _AuthorizationExecuteWithPrivilegesExternalForm _AuthorizationFree _AuthorizationFreeItemSet _AuthorizationMakeExternalForm +_AuthorizationPreauthorizeCredentials _AuthorizationRightGet _AuthorizationRightRemove _AuthorizationRightSet @@ -780,7 +798,6 @@ _SecAccessGetTypeID _SecCopyErrorMessageString _SecCreateRecoveryPassword _SecDigestGetData -_SecDistinguishedNameCopyNormalizedContent _SecFDERecoveryUnwrapCRSKWithPrivKey _SecFDERecoveryWrapCRSKWithPubKey _SecGenericPasswordCreate @@ -804,7 +821,7 @@ _SecIdentityUpdatePreferenceItem _SecInferLabelFromX509Name _SecItemAdd_ios _SecItemCopyMatching_ios -_SecItemCopyParentCertificates +_SecItemCopyParentCertificates_osx _SecItemCopyStoredCertificate #if TARGET_OS_OSX _SecItemCreateFromAttributeDictionary_osx @@ -957,6 +974,8 @@ _kSecACLAuthorizationKeychainItemModify _kSecACLAuthorizationKeychainItemRead _kSecACLAuthorizationLogin _kSecACLAuthorizationMAC +_kSecACLAuthorizationChangeACL +_kSecACLAuthorizationChangeOwner _kSecACLAuthorizationPartitionID _kSecACLAuthorizationSign @@ -1641,15 +1660,33 @@ _secLogDisable #endif _secLogObjForScope -_logObjForScope +_secLogObjForCFScope // // Recovery Key // +_kSecRVSalt +_kSecRVIterations +_kSecRVProtocol +_kSecRVVerifier +_kSecRVMasterID + _SecRKCreateRecoveryKey +_SecRKCreateRecoveryKeyWithError _SecRKCopyAccountRecoveryPassword +_SecRKCopyAccountRecoveryVerifier _SecRKCopyBackupPublicKey _SecRKCopyBackupFullKey _SecRKRegisterBackupPublicKey _SecRKCreateRecoveryKeyString + +// +// Analytics +// + +.objc_class_name_SFSQLite +.objc_class_name_SFAnalyticsLogger + +// Padding +_SecPaddingCompute diff --git a/Security.xcodeproj/project.pbxproj b/Security.xcodeproj/project.pbxproj index 770462c2..585a52c8 100644 --- a/Security.xcodeproj/project.pbxproj +++ b/Security.xcodeproj/project.pbxproj @@ -36,6 +36,9 @@ buildPhases = ( ); dependencies = ( + F621D0831ED6ED5B000EA569 /* PBXTargetDependency */, + 6C24EF4A1E415109000DE79F /* PBXTargetDependency */, + EB27FF261E40716D00EC9E3A /* PBXTargetDependency */, EBF374821DC058B60065D840 /* PBXTargetDependency */, DCE4E7B81D7A456500AFB96E /* PBXTargetDependency */, DC61096D1D78E72C002223DE /* PBXTargetDependency */, @@ -58,7 +61,14 @@ E74583BE1BF66489001B54A4 /* PBXTargetDependency */, E7E7B24B1BFC0CD900B1E66B /* PBXTargetDependency */, EB31EA831D3EF2FB008F952A /* PBXTargetDependency */, + DA30D6821DF8C93500EC6B43 /* PBXTargetDependency */, EBC15EA91BE29AC3001C0C5B /* PBXTargetDependency */, + EBD31B421E0A18A600FBE9FA /* PBXTargetDependency */, + EBD31B3B1E0A186500FBE9FA /* PBXTargetDependency */, + DCB515D91ED3CC6B001F1152 /* PBXTargetDependency */, + 6C24EF4A1E415109000DE79F /* PBXTargetDependency */, + DCB515D71ED3CC52001F1152 /* PBXTargetDependency */, + DC5225001E40295C0021640A /* PBXTargetDependency */, ); name = Security_executables_osx; productName = Security_executables; @@ -93,6 +103,7 @@ dependencies = ( DC71D9E31D95BAD50065FB93 /* PBXTargetDependency */, EB6A6FBD1B90F9170045DC68 /* PBXTargetDependency */, + BE9C38CF1EB115C9007E2AE1 /* PBXTargetDependency */, ); name = Security_frameworks_ios; productName = kernel; @@ -103,6 +114,8 @@ buildPhases = ( ); dependencies = ( + D41257F11E941E7D00781F23 /* PBXTargetDependency */, + EB27FF281E40717400EC9E3A /* PBXTargetDependency */, EBF374841DC058C00065D840 /* PBXTargetDependency */, EBB696D41BE2085700715F16 /* PBXTargetDependency */, 438169E71B4EE4B300C54D58 /* PBXTargetDependency */, @@ -125,6 +138,11 @@ 5346481B17331ED800FE9172 /* PBXTargetDependency */, F94E7AE21ACC8E7700F23132 /* PBXTargetDependency */, EB9C1DB71BDFD51800F89272 /* PBXTargetDependency */, + DCB515DB1ED3CC73001F1152 /* PBXTargetDependency */, + 6C24EF531E415132000DE79F /* PBXTargetDependency */, + DCB515D01ED3CC36001F1152 /* PBXTargetDependency */, + DC5224F91E4029520021640A /* PBXTargetDependency */, + EB0D30FA1EF12BFB00C3C17D /* PBXTargetDependency */, ); name = Security_executables_ios; productName = phase2; @@ -146,6 +164,7 @@ buildPhases = ( ); dependencies = ( + EB58A05E1E74C51F009C10D7 /* PBXTargetDependency */, EB6A6FBB1B90F8EC0045DC68 /* PBXTargetDependency */, 4C541FA10F250C5200E508AE /* PBXTargetDependency */, E7CFF6771C84F66A00E3484E /* PBXTargetDependency */, @@ -159,6 +178,9 @@ buildPhases = ( ); dependencies = ( + BE061EB91EE5EBA000B22118 /* PBXTargetDependency */, + EBA62C1C1EAD34CD0096B33A /* PBXTargetDependency */, + D41257F51E941E8E00781F23 /* PBXTargetDependency */, EBF374881DC058CC0065D840 /* PBXTargetDependency */, D41AD45C1B978A7A008C7270 /* PBXTargetDependency */, D41AD4721B978F76008C7270 /* PBXTargetDependency */, @@ -181,6 +203,9 @@ buildPhases = ( ); dependencies = ( + BE061EB71EE5EB9000B22118 /* PBXTargetDependency */, + EBA62C151EAD34C60096B33A /* PBXTargetDependency */, + D41257F31E941E8600781F23 /* PBXTargetDependency */, EBF374861DC058C50065D840 /* PBXTargetDependency */, D41AD43A1B96721E008C7270 /* PBXTargetDependency */, D41AD4521B9788B2008C7270 /* PBXTargetDependency */, @@ -192,6 +217,7 @@ D41AD4401B96724C008C7270 /* PBXTargetDependency */, D41AD4441B978681008C7270 /* PBXTargetDependency */, D41AD4421B97866C008C7270 /* PBXTargetDependency */, + D419C0261E57EACA008619D1 /* PBXTargetDependency */, D41AD44E1B978791008C7270 /* PBXTargetDependency */, D41AD44A1B9786D8008C7270 /* PBXTargetDependency */, EB9FE08D1BFBC48F004FEAAF /* PBXTargetDependency */, @@ -339,6 +365,7 @@ E745846D1BF68ECB001B54A4 /* PBXTargetDependency */, E74584711BF68ECB001B54A4 /* PBXTargetDependency */, E745846F1BF68ECB001B54A4 /* PBXTargetDependency */, + EB58A05C1E74C517009C10D7 /* PBXTargetDependency */, ); name = osx; productName = macosx; @@ -347,9 +374,17 @@ isa = PBXAggregateTarget; buildConfigurationList = E79EEDD11CD3F87B00C2FBFC /* Build configuration list for PBXAggregateTarget "Security_tests_osx" */; buildPhases = ( - EB0BF1711D25B47A000DEF32 /* CopyFiles */, ); dependencies = ( + EBFF18CE1F02BA66004E58FC /* PBXTargetDependency */, + BE061EAC1EE5EA5600B22118 /* PBXTargetDependency */, + F667EC671E96FA4600203D5C /* PBXTargetDependency */, + EB1C4CA71E85883900404981 /* PBXTargetDependency */, + EB1C4CA91E85883900404981 /* PBXTargetDependency */, + EB1C4CAB1E85883900404981 /* PBXTargetDependency */, + EB58A0601E74C8D9009C10D7 /* PBXTargetDependency */, + EB10557F1E14DFBE0003C309 /* PBXTargetDependency */, + BE9C38D11EB115F4007E2AE1 /* PBXTargetDependency */, ); name = Security_tests_osx; productName = Security_test_macos; @@ -358,9 +393,15 @@ isa = PBXAggregateTarget; buildConfigurationList = E79EEDD31CD3F8AB00C2FBFC /* Build configuration list for PBXAggregateTarget "Security_tests_ios" */; buildPhases = ( - EB0BF1991D25B54B000DEF32 /* CopyFiles */, ); dependencies = ( + BE061EB31EE5EAC800B22118 /* PBXTargetDependency */, + EB1C4CB21E85884300404981 /* PBXTargetDependency */, + EB1C4CB41E85884300404981 /* PBXTargetDependency */, + EB1C4CB61E85884300404981 /* PBXTargetDependency */, + EB58A0621E74C8E4009C10D7 /* PBXTargetDependency */, + EB10557D1E14DFB60003C309 /* PBXTargetDependency */, + BE9C38D31EB11605007E2AE1 /* PBXTargetDependency */, ); name = Security_tests_ios; productName = Security_test_ios; @@ -375,6 +416,7 @@ DC71D9E11D95BAC40065FB93 /* PBXTargetDependency */, DC5AC1341D835C2300CF422C /* PBXTargetDependency */, DC178BF31D77ABE300B50D50 /* PBXTargetDependency */, + BE9C38C81EB115A7007E2AE1 /* PBXTargetDependency */, DC58C4431D77C1F8003C25A4 /* PBXTargetDependency */, ); name = Security_frameworks_osx; @@ -399,6 +441,7 @@ dependencies = ( E7CFF6711C84F62900E3484E /* PBXTargetDependency */, E7CFF6731C84F62900E3484E /* PBXTargetDependency */, + EBFBC2B01E76582C00A34469 /* PBXTargetDependency */, ); name = Security_KeychainCircle; productName = Security_KeychainCircle; @@ -420,6 +463,7 @@ buildPhases = ( ); dependencies = ( + D41257F71E941E9600781F23 /* PBXTargetDependency */, EB6A6FB31B90F89F0045DC68 /* PBXTargetDependency */, ); name = Security_executables_bridge; @@ -468,6 +512,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 09CB49701F2F64E300C8E4DE /* si-44-seckey-fv.m in Sources */ = {isa = PBXBuildFile; fileRef = 09CB496A1F2F64AF00C8E4DE /* si-44-seckey-fv.m */; }; 0C0BDB32175685B000BC1A7E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C0BDB31175685B000BC1A7E /* main.m */; }; 0C0BDB881756A51000BC1A7E /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB740680A4749C800D641BB /* libsqlite3.dylib */; }; 0C0BDB8D1756A66100BC1A7E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; }; @@ -487,24 +532,100 @@ 0C2BCBC91D0648D100ED7A2F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; }; 0C2BCBCA1D0648D100ED7A2F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; 0C2BCBCF1D0648EF00ED7A2F /* dtlsEchoServer.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C2BCBA61D063F7D00ED7A2F /* dtlsEchoServer.c */; }; + 0C3C00731EF3636500AB19FE /* secd-155-otr-negotiation-monitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C00721EF3636300AB19FE /* secd-155-otr-negotiation-monitor.m */; }; + 0C48990B1E0E0FF300C6CF70 /* SOSTransportCircleCK.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C48990A1E0E0FF300C6CF70 /* SOSTransportCircleCK.h */; }; + 0C4899121E0E105D00C6CF70 /* SOSTransportCircleCK.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C4899111E0E105D00C6CF70 /* SOSTransportCircleCK.m */; }; + 0C48991C1E0F384700C6CF70 /* SOSAccountTrustClassic.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C48991B1E0F384700C6CF70 /* SOSAccountTrustClassic.m */; }; + 0C4899231E0F386900C6CF70 /* SOSAccountTrustClassic.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C4899221E0F386900C6CF70 /* SOSAccountTrustClassic.h */; }; + 0C4899251E0F38FA00C6CF70 /* SOSAccountTrustOctagon.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C4899241E0F38FA00C6CF70 /* SOSAccountTrustOctagon.m */; }; + 0C4899271E0F399B00C6CF70 /* SOSAccountTrustOctagon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C4899261E0F399B00C6CF70 /* SOSAccountTrustOctagon.h */; }; + 0C5D62F11E81E74800AA4D02 /* SOSInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D8D1D8085F200865A7C /* SOSInternal.m */; }; 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 */; }; - 0C869B431C865E4D006A2873 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C869B421C865E4D006A2873 /* CoreCDP.framework */; }; + 0CAC5DBF1EB3DA4C00AD884B /* SOSPeerRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CAC5DBE1EB3DA4C00AD884B /* SOSPeerRateLimiter.m */; }; + 0CAD1E1C1E032ADB00537693 /* SOSCloudCircleServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CAA1D8085D800865A7C /* SOSCloudCircleServer.m */; }; + 0CAD1E581E1C5C6C00537693 /* SOSCloudCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D891D8085F200865A7C /* SOSCloudCircle.m */; }; + 0CAD1E591E1C5CBD00537693 /* secd-52-offering-gencount-reset.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4F1D8085D800865A7C /* secd-52-offering-gencount-reset.m */; }; + 0CAD1E5A1E1C5CD100537693 /* secd-71-engine-save.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C641D8085D800865A7C /* secd-71-engine-save.m */; }; + 0CAD1E5B1E1C5CE100537693 /* secd-76-idstransport.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C681D8085D800865A7C /* secd-76-idstransport.m */; }; + 0CAD1E5C1E1C5CEB00537693 /* secd_77_ids_messaging.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C691D8085D800865A7C /* secd_77_ids_messaging.m */; }; + 0CAD1E5D1E1C5CF900537693 /* secd-80-views-alwayson.m in Sources */ = {isa = PBXBuildFile; fileRef = 7281E08B1DFD0A380021E1B7 /* secd-80-views-alwayson.m */; }; + 0CAD1E5E1E1C5D0600537693 /* secd-95-escrow-persistence.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.m */; }; 0CC319241DA46FBF005D42EA /* ProtectedCloudStorage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43DB542E1BB1F85B0083C3F1 /* ProtectedCloudStorage.framework */; }; + 0CCDE7171EEB08220021A946 /* secd-156-timers.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CCDE7161EEB08220021A946 /* secd-156-timers.m */; }; + 0CD8CB051ECA50780076F37F /* SOSPeerOTRTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */; }; + 0CD8CB0B1ECA50920076F37F /* SOSPeerOTRTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */; }; + 0CE760481E12F2F300B4381E /* SOSAccountTrustClassic+Expansion.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE760471E12F2F200B4381E /* SOSAccountTrustClassic+Expansion.m */; }; + 0CE7604A1E12F30200B4381E /* SOSAccountTrustClassic+Circle.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE760491E12F30200B4381E /* SOSAccountTrustClassic+Circle.m */; }; + 0CE7604C1E12F56800B4381E /* SOSAccountTrustClassic+Identity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE7604B1E12F56800B4381E /* SOSAccountTrustClassic+Identity.m */; }; + 0CE7604E1E12F5BA00B4381E /* SOSAccountTrustClassic+Retirement.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE7604D1E12F5BA00B4381E /* SOSAccountTrustClassic+Retirement.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 */; }; + 0CE760561E1316E900B4381E /* SOSAccountTrustClassic+Retirement.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CE760551E1316E900B4381E /* SOSAccountTrustClassic+Retirement.h */; }; 0CFC029C1D41650700E6283B /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; 0CFC02C21D41651E00E6283B /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; 107226D30D91DB32003CF14F /* SecTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 107226D10D91DB32003CF14F /* SecTask.h */; settings = {ATTRIBUTES = (Private, ); }; }; 18F7F67914D77F4400F88A12 /* NtlmGenerator.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C999BA10AB5F0BB0010451D /* NtlmGenerator.c */; }; 18F7F67A14D77F4400F88A12 /* ntlmBlobPriv.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C999BA30AB5F0BB0010451D /* ntlmBlobPriv.c */; }; - 18F7F67C14D77F5000F88A12 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; }; + 220179E31E3BEB7100EFB6F3 /* dirscanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067FD1D8CDF7E007602F1 /* dirscanner.cpp */; }; + 220179E91E3BF03200EFB6F3 /* dummy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC1789A41D779E3B00B50D50 /* dummy.cpp */; }; + 220179EA1E3BF16000EFB6F3 /* slcrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067DB1D8CDF7E007602F1 /* slcrep.cpp */; }; + 220179EB1E3BF1F100EFB6F3 /* detachedrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067E11D8CDF7E007602F1 /* detachedrep.cpp */; }; + 222F239F1DAC15C5007ACB90 /* SecTaskPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 222F23A01DAC1603007ACB90 /* SecTaskPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 225394B71E3081F900D3CD9B /* cskernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067CA1D8CDF7E007602F1 /* cskernel.cpp */; }; + 225394B81E30820900D3CD9B /* Code.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067A01D8CDF7E007602F1 /* Code.cpp */; }; + 225394B91E30821400D3CD9B /* bundlediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067D51D8CDF7E007602F1 /* bundlediskrep.cpp */; }; + 225394BA1E30821E00D3CD9B /* cdbuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067B01D8CDF7E007602F1 /* cdbuilder.cpp */; }; + 225394BB1E30822700D3CD9B /* codedirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067AE1D8CDF7E007602F1 /* codedirectory.cpp */; }; + 225394BC1E30823E00D3CD9B /* cs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD0679E1D8CDF7E007602F1 /* cs.cpp */; }; + 225394BD1E30824C00D3CD9B /* SecCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD0678F1D8CDF7E007602F1 /* SecCode.cpp */; }; + 225394BE1E30825500D3CD9B /* SecStaticCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067921D8CDF7E007602F1 /* SecStaticCode.cpp */; }; + 225394BF1E30826100D3CD9B /* SecRequirement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067951D8CDF7E007602F1 /* SecRequirement.cpp */; }; + 225394C01E30826B00D3CD9B /* diskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067D11D8CDF7E007602F1 /* diskrep.cpp */; }; + 225394C11E30827600D3CD9B /* filediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067D31D8CDF7E007602F1 /* filediskrep.cpp */; }; + 225394C21E30827E00D3CD9B /* kerneldiskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067D71D8CDF7E007602F1 /* kerneldiskrep.cpp */; }; + 225394C31E30828800D3CD9B /* StaticCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067A21D8CDF7E007602F1 /* StaticCode.cpp */; }; + 225394C41E30829300D3CD9B /* reqparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067C31D8CDF7E007602F1 /* reqparser.cpp */; }; + 225394C51E3082A100D3CD9B /* requirement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067BB1D8CDF7E007602F1 /* requirement.cpp */; }; + 225394C61E3082AB00D3CD9B /* Requirements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067A41D8CDF7E007602F1 /* Requirements.cpp */; }; + 225394C71E3082B600D3CD9B /* reqdumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067C51D8CDF7E007602F1 /* reqdumper.cpp */; }; + 225394C81E3082BE00D3CD9B /* reqinterp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067C11D8CDF7E007602F1 /* reqinterp.cpp */; }; + 225394C91E3082C900D3CD9B /* reqmaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067BD1D8CDF7E007602F1 /* reqmaker.cpp */; }; + 225394CA1E3082D500D3CD9B /* macho++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B131D8E0D7D007602F1 /* macho++.cpp */; }; + 225394CB1E30831D00D3CD9B /* machorep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067D91D8CDF7E007602F1 /* machorep.cpp */; }; + 225394CC1E30832A00D3CD9B /* sigblob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067F51D8CDF7E007602F1 /* sigblob.cpp */; }; + 225394CD1E30833400D3CD9B /* resources.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067F31D8CDF7E007602F1 /* resources.cpp */; }; + 225394CE1E30833F00D3CD9B /* cfmunge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B211D8E0D7D007602F1 /* cfmunge.cpp */; }; + 225394CF1E30835700D3CD9B /* csutilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067F71D8CDF7E007602F1 /* csutilities.cpp */; }; + 225394D01E30836200D3CD9B /* singlediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067DF1D8CDF7E007602F1 /* singlediskrep.cpp */; }; + 225394D11E30836F00D3CD9B /* reqreader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067BF1D8CDF7E007602F1 /* reqreader.cpp */; }; + 225394D21E30837900D3CD9B /* cserror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067F11D8CDF7E007602F1 /* cserror.cpp */; }; + 225394D31E3083C600D3CD9B /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785841D778B8000B50D50 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 225394D41E3083D000D3CD9B /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785811D778B7F00B50D50 /* CodeSigning.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 225394D51E3083DA00D3CD9B /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785821D778B7F00B50D50 /* CSCommon.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 225394D61E3083E300D3CD9B /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785831D778B7F00B50D50 /* SecCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 225394D71E3083ED00D3CD9B /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785861D778B8000B50D50 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 225394D81E3083F700D3CD9B /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785851D778B8000B50D50 /* SecRequirement.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 225394DB1E30864B00D3CD9B /* CSCommonPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0678C1D8CDF7E007602F1 /* CSCommonPriv.h */; }; + 226A8B461DEF5905004C35E3 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD06AB01D8E0D53007602F1 /* libsecurity_utilities.a */; }; + 2296B0E61E32EF08000D1EA7 /* requirement.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067BA1D8CDF7E007602F1 /* requirement.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 2296B0EC1E32EF10000D1EA7 /* cs.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0679D1D8CDF7E007602F1 /* cs.h */; }; + 22A23B3A1E3AAC9800C41830 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0678A1D8CDF7E007602F1 /* CodeSigning.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 22A23B3B1E3AAC9800C41830 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0678B1D8CDF7E007602F1 /* CSCommon.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 22A23B3C1E3AAC9800C41830 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0678D1D8CDF7E007602F1 /* SecCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 22A23B3D1E3AAC9800C41830 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067901D8CDF7E007602F1 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 22A23B3E1E3AAC9800C41830 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067931D8CDF7E007602F1 /* SecRequirement.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 22A23B3F1E3AAC9800C41830 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067981D8CDF7E007602F1 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 22E337DA1E37FD66001D5637 /* libsecurity_codesigning_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 225394B41E3080A600D3CD9B /* libsecurity_codesigning_ios.a */; }; 24CBF8751E9D4E6100F09F0E /* kc-44-secrecoverypassword.c in Sources */ = {isa = PBXBuildFile; fileRef = 24CBF8731E9D4E4500F09F0E /* kc-44-secrecoverypassword.c */; }; 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 */; }; - 4381603C1B4DCF9E00C54D58 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; }; 438166ED1B4ECF9400C54D58 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; 438168941B4ED42300C54D58 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; 438168BB1B4ED42300C54D58 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; @@ -539,22 +660,80 @@ 44A655831AA4B4BB0059D185 /* libctkclient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient.a */; }; 44A655A51AA4B4C70059D185 /* libctkclient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient.a */; }; 44A655A61AA4B4C80059D185 /* libctkclient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient.a */; }; - 483E798F1DC87605005C0008 /* secd-67-prefixedKeyIDs.c in Sources */ = {isa = PBXBuildFile; fileRef = 483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.c */; }; - 485B640B1DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 485B64091DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h */; }; - 485B64111DC16ED600B771B9 /* SOSKeyedPubKeyIdentifier.c in Sources */ = {isa = PBXBuildFile; fileRef = 485B64081DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.c */; }; - 485B64121DC16EDA00B771B9 /* SOSKeyedPubKeyIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 485B64091DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h */; }; - 48776C7A1DA5BB4C00CC09B9 /* SOSRecoveryKeyBag.c in Sources */ = {isa = PBXBuildFile; fileRef = 48776C731DA5BB4200CC09B9 /* SOSRecoveryKeyBag.c */; }; - 48776C7B1DA5BB4C00CC09B9 /* SOSRecoveryKeyBag.h in Headers */ = {isa = PBXBuildFile; fileRef = 48776C741DA5BB4200CC09B9 /* SOSRecoveryKeyBag.h */; }; - 48776C7E1DA5BB7600CC09B9 /* SOSRingRecovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.c */; }; - 48776C7F1DA5BB7600CC09B9 /* SOSRingRecovery.h in Headers */ = {isa = PBXBuildFile; fileRef = 48776C7D1DA5BB5F00CC09B9 /* SOSRingRecovery.h */; }; - 48776C811DA5BC0E00CC09B9 /* SOSAccountRecovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.c */; }; - 48AFBA7C1DEF8D4800436D08 /* secd-80-views-alwayson.c in Sources */ = {isa = PBXBuildFile; fileRef = 48AFBA751DEF8D3100436D08 /* secd-80-views-alwayson.c */; }; - 48BC0F651DFA2B5B00DDDFF9 /* accountCirclesViewsPrint.c in Sources */ = {isa = PBXBuildFile; fileRef = 48BC0F5C1DFA2B4500DDDFF9 /* accountCirclesViewsPrint.c */; }; - 48BC0F661DFA2B5B00DDDFF9 /* accountCirclesViewsPrint.h in Headers */ = {isa = PBXBuildFile; fileRef = 48BC0F5D1DFA2B4500DDDFF9 /* accountCirclesViewsPrint.h */; }; - 48BC0F6A1DFA357000DDDFF9 /* accountCirclesViewsPrint.c in Sources */ = {isa = PBXBuildFile; fileRef = 48BC0F5C1DFA2B4500DDDFF9 /* accountCirclesViewsPrint.c */; }; - 48BC0F6B1DFA357200DDDFF9 /* accountCirclesViewsPrint.c in Sources */ = {isa = PBXBuildFile; fileRef = 48BC0F5C1DFA2B4500DDDFF9 /* accountCirclesViewsPrint.c */; }; - 48CC589F1DA5FF2700EBD9DB /* secd-66-account-recovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.c */; }; - 48E617211DBEC6BA0098EAAD /* SOSBackupInformation.c in Sources */ = {isa = PBXBuildFile; fileRef = 48E6171A1DBEC40D0098EAAD /* SOSBackupInformation.c */; }; + 470415DC1E5E1534001F3D95 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 470415DB1E5E1534001F3D95 /* main.m */; }; + 4710A6D91F34F21700745267 /* CrashReporterSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E9391D7F3DF200AFB96E /* CrashReporterSupport.framework */; }; + 4723C9C21F152EB50082882F /* SFObjCType.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9C01F152EB10082882F /* SFObjCType.h */; }; + 4723C9C31F152EB60082882F /* SFObjCType.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9C01F152EB10082882F /* SFObjCType.h */; }; + 4723C9C41F152EBB0082882F /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; }; + 4723C9C51F152EBC0082882F /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; }; + 4723C9C61F152EC00082882F /* SFSQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9BD1F152EB10082882F /* SFSQLite.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4723C9C71F152EC10082882F /* SFSQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9BD1F152EB10082882F /* SFSQLite.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4723C9C81F152ECA0082882F /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; }; + 4723C9C91F152ECA0082882F /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; }; + 4723C9CA1F152ECE0082882F /* SFSQLiteStatement.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9C11F152EB10082882F /* SFSQLiteStatement.h */; }; + 4723C9CB1F152ECF0082882F /* SFSQLiteStatement.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9C11F152EB10082882F /* SFSQLiteStatement.h */; }; + 4723C9CC1F152ED30082882F /* SFSQLiteStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */; }; + 4723C9CD1F152ED40082882F /* SFSQLiteStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */; }; + 4723C9D41F1531A30082882F /* CKKSLoggerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9D11F1531970082882F /* CKKSLoggerTests.m */; }; + 4723C9DC1F1540CE0082882F /* SFAnalyticsLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9DA1F1540CE0082882F /* SFAnalyticsLogger.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4723C9DD1F1540CE0082882F /* SFAnalyticsLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9DA1F1540CE0082882F /* SFAnalyticsLogger.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4723C9E01F1540CE0082882F /* SFAnalyticsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalyticsLogger.m */; }; + 4723C9E11F1540CE0082882F /* SFAnalyticsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalyticsLogger.m */; }; + 474B5FC61E662E48007546F8 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; }; + 474B5FC71E662E67007546F8 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 474B5FBF1E662E21007546F8 /* SecurityFoundation.framework */; }; + 474B5FC81E662E79007546F8 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; }; + 475F37201EE8F23900248FB5 /* SFAnalyticsLogging.plist in Resources */ = {isa = PBXBuildFile; fileRef = 475F371F1EE8F23900248FB5 /* SFAnalyticsLogging.plist */; }; + 475F37211EE8F23900248FB5 /* SFAnalyticsLogging.plist in Resources */ = {isa = PBXBuildFile; fileRef = 475F371F1EE8F23900248FB5 /* SFAnalyticsLogging.plist */; }; + 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 */; }; + 4765419B1F33ED7E00413F65 /* 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 */; }; + 47702B191E5E58EF00B29577 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB10557A1E14DF640003C309 /* Security.framework */; }; + 47702B281E5F412500B29577 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 47702B261E5F412500B29577 /* main.m */; }; + 47702B291E5F463400B29577 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; + 47702B371E5F495C00B29577 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 47702B351E5F495C00B29577 /* main.m */; }; + 47702B391E5F4B2200B29577 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; + 4771ECCC1F17CD0E00840998 /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; }; + 4771ECCD1F17CD0E00840998 /* SFSQLiteStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */; }; + 4771ECCE1F17CD2100840998 /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; }; + 4771ECD91F17CE5100840998 /* SFAnalyticsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalyticsLogger.m */; }; + 479108B71EE879F9008CEFA0 /* CKKSAnalyticsLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 479108B51EE879F9008CEFA0 /* CKKSAnalyticsLogger.h */; }; + 479108B81EE879F9008CEFA0 /* CKKSAnalyticsLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 479108B51EE879F9008CEFA0 /* CKKSAnalyticsLogger.h */; }; + 479108B91EE879F9008CEFA0 /* CKKSAnalyticsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 479108B61EE879F9008CEFA0 /* CKKSAnalyticsLogger.m */; }; + 479108BA1EE879F9008CEFA0 /* CKKSAnalyticsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 479108B61EE879F9008CEFA0 /* CKKSAnalyticsLogger.m */; }; + 479DA1721EBBA8D10065C98F /* CKKSManifest.m in Sources */ = {isa = PBXBuildFile; fileRef = 47CEED1F1E60DE900044EAB4 /* CKKSManifest.m */; }; + 479DA1781EBBA8D30065C98F /* CKKSManifest.m in Sources */ = {isa = PBXBuildFile; fileRef = 47CEED1F1E60DE900044EAB4 /* CKKSManifest.m */; }; + 47A0ABA81E6F7B24001B388C /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 474B5FBF1E662E21007546F8 /* SecurityFoundation.framework */; }; + 47B011971F17D7810030B49F /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; }; + 47B011981F17D78D0030B49F /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; }; + 47B011991F17D78D0030B49F /* SFSQLiteStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */; }; + 47B0119A1F17D7E80030B49F /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; }; + 47B0119B1F17D7F10030B49F /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; }; + 47B0119C1F17D7F10030B49F /* SFSQLiteStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */; }; + 47B011A71F17D8980030B49F /* SFAnalyticsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalyticsLogger.m */; }; + 47B011AD1F17D8A00030B49F /* SFAnalyticsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalyticsLogger.m */; }; + 47B90C901F350966006500BC /* CrashReporterSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E9391D7F3DF200AFB96E /* CrashReporterSupport.framework */; }; + 47B90C951F3509C1006500BC /* CrashReporterSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E9391D7F3DF200AFB96E /* CrashReporterSupport.framework */; }; + 47C51B871EEA657D0032D9E5 /* SecurityUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 47C51B861EEA657D0032D9E5 /* SecurityUnitTests.m */; }; + 47C51B891EEA657D0032D9E5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; + 47D13F631E8447FB0063B6E2 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; }; + 47E553741EDF674700749715 /* CKKSManifestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 476E918D1E7343B200B4E4D3 /* CKKSManifestTests.m */; }; + 483E798F1DC87605005C0008 /* secd-67-prefixedKeyIDs.m in Sources */ = {isa = PBXBuildFile; fileRef = 483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.m */; }; + 48776C811DA5BC0E00CC09B9 /* SOSAccountRecovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.m */; }; + 48C2F9391E4BCFDA0093D70C /* accountCirclesViewsPrint.m in Sources */ = {isa = PBXBuildFile; fileRef = 48C2F9321E4BCFC30093D70C /* accountCirclesViewsPrint.m */; }; + 48C2F93A1E4BCFDC0093D70C /* accountCirclesViewsPrint.m in Sources */ = {isa = PBXBuildFile; fileRef = 48C2F9321E4BCFC30093D70C /* accountCirclesViewsPrint.m */; }; + 48C2F93B1E4BCFE80093D70C /* accountCirclesViewsPrint.m in Sources */ = {isa = PBXBuildFile; fileRef = 48C2F9321E4BCFC30093D70C /* accountCirclesViewsPrint.m */; }; + 48C2F93C1E4BD00F0093D70C /* accountCirclesViewsPrint.h in Headers */ = {isa = PBXBuildFile; fileRef = 48C2F9331E4BCFC30093D70C /* accountCirclesViewsPrint.h */; }; + 48CC589F1DA5FF2700EBD9DB /* secd-66-account-recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.m */; }; + 48E617211DBEC6BA0098EAAD /* SOSBackupInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 48E6171A1DBEC40D0098EAAD /* SOSBackupInformation.m */; }; 48E617221DBEC6C60098EAAD /* SOSBackupInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = 48E6171B1DBEC40D0098EAAD /* SOSBackupInformation.h */; }; 4AF7000015AFB73800B9D400 /* SecOTRIdentityPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF7FFF615AFB73800B9D400 /* SecOTRIdentityPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4AF7000115AFB73800B9D400 /* SecOTRMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF7FFF715AFB73800B9D400 /* SecOTRMath.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -671,10 +850,9 @@ 4C52D0E916EFCCF80079966E /* com.apple.security.CircleJoinRequested.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C52D0E416EFCCA20079966E /* com.apple.security.CircleJoinRequested.plist */; }; 4C52D0EC16EFCD300079966E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; 4C6416D50BB34F00001C83FD /* SecPolicyPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C6416D40BB34F00001C83FD /* SecPolicyPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 4C6416F10BB357D5001C83FD /* SecInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C6416F00BB357D5001C83FD /* SecInternal.h */; }; + 4C6416F10BB357D5001C83FD /* SecInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C6416F00BB357D5001C83FD /* SecInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4C64E01C0B8FBC71009B306C /* SecIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CAC87D60B8F82720009C9FC /* SecIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C64E01D0B8FBC7E009B306C /* Security.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C64E00B0B8FBBF3009B306C /* Security.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4C70664C0DDDFED9004DA56B /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 107227350D91FE89003CF14F /* libbsm.dylib */; }; 4C7072860AC9EA4F007CC205 /* SecKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C7072840AC9EA4E007CC205 /* SecKey.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C7072D40AC9ED5A007CC205 /* SecKeyPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C7072D30AC9ED5A007CC205 /* SecKeyPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4C7073CA0ACB2BAD007CC205 /* SecRSAKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C7073C80ACB2BAD007CC205 /* SecRSAKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -739,10 +917,14 @@ 4CF048800A5F016300268236 /* SecItemPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CF0487F0A5F016300268236 /* SecItemPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4CF41D0C0BBB4022005F3248 /* SecCertificatePath.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CF41D0A0BBB4022005F3248 /* SecCertificatePath.h */; }; 4CF4C19D171E0EA600877419 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4C19C171E0EA600877419 /* Accounts.framework */; }; - 4CF730320EF9CDE300E17471 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; }; 4CFBF6100D5A951100969BBE /* SecPolicyInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CFBF5F10D5A92E100969BBE /* SecPolicyInternal.h */; }; 52222CD0167BDAEC00EDD09C /* SpringBoardServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52222CC0167BDAE100EDD09C /* SpringBoardServices.framework */; }; + 522B280E1E64B4BF002B5638 /* secd-230-keybagtable.m in Sources */ = {isa = PBXBuildFile; fileRef = 522B28081E64B48E002B5638 /* secd-230-keybagtable.m */; }; 524492941AFD6D480043695A /* der_plist.h in Headers */ = {isa = PBXBuildFile; fileRef = 524492931AFD6D480043695A /* der_plist.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 5269658D1E6A154700627F9D /* SecBackupKeybagEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 52AA92881E662A4A004301A6 /* SecBackupKeybagEntry.m */; }; + 5269658E1E6A154800627F9D /* SecBackupKeybagEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 52AA92881E662A4A004301A6 /* SecBackupKeybagEntry.m */; }; + 526965D21E6E284400627F9D /* AsymKeybagBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 526965CC1E6E283100627F9D /* AsymKeybagBackup.m */; }; + 526965D31E6E284500627F9D /* AsymKeybagBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 526965CC1E6E283100627F9D /* AsymKeybagBackup.m */; }; 5296CB4E1655B8F5009912AF /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; 5296CB4F1655B92F009912AF /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; 5296CB501655B990009912AF /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; @@ -770,15 +952,106 @@ 5E43C4981B00D49700E5ECB2 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB740680A4749C800D641BB /* libsqlite3.dylib */; }; 5E43C49A1B00D4D800E5ECB2 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; }; 5E4E05A41B0CA0FD001C4A31 /* sec_acl_stress.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E4E05A31B0CA0FD001C4A31 /* sec_acl_stress.c */; }; + 5E7793751E5F025A0074A2D1 /* si-44-seckey-aks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E77936E1E5EFEB20074A2D1 /* si-44-seckey-aks.m */; }; 5E8B53A51AA0B8A600345E7B /* libcoreauthd_test_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8B53A41AA0B8A600345E7B /* libcoreauthd_test_client.a */; }; + 5EAFA4D31EF1605A002DC188 /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EAFA4CD1EF16059002DC188 /* LocalAuthentication.framework */; }; 5EBE247D1B00CCAE0007DB0E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 5EBE247C1B00CCAE0007DB0E /* main.c */; }; + 6C0B0C491E253832007F95E5 /* AwdMetadata-0x60-Keychain.bin in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6C3446551E2534E800F9522B /* AwdMetadata-0x60-Keychain.bin */; }; + 6C0B0C4B1E253848007F95E5 /* AwdMetadata-0x60-Keychain.bin in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6C3446551E2534E800F9522B /* AwdMetadata-0x60-Keychain.bin */; }; + 6C1520D41DCCF71400C85C6D /* secd.8 in Install man8 page */ = {isa = PBXBuildFile; fileRef = 6C1520CD1DCCF57A00C85C6D /* secd.8 */; }; + 6C1F93111DD5E41A00585608 /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3C1D78F25C002223DE /* libDiagnosticMessagesClient.dylib */; }; + 6C3446301E24F6BE00F9522B /* CKKSRateLimiterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C34462F1E24F6BE00F9522B /* CKKSRateLimiterTests.m */; }; + 6C3446461E25346C00F9522B /* CKKSRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */; }; + 6C3446471E25346C00F9522B /* CKKSRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */; }; + 6C588D7F1EAA14AA00D7E322 /* RateLimiterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C588D791EAA149F00D7E322 /* RateLimiterTests.m */; }; + 6C588D801EAA20AB00D7E322 /* RateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CC7F5B31E9F99EE0014AE63 /* RateLimiter.m */; }; + 6C588D811EAA20AC00D7E322 /* 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, ); }; }; + 6C8CC3AB1E2F913C009025C5 /* AWDKeychainCKKSRateLimiterAggregatedScores.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C3446501E2534E800F9522B /* AWDKeychainCKKSRateLimiterAggregatedScores.m */; }; + 6C8CC3AC1E2F913C009025C5 /* AWDKeychainCKKSRateLimiterOverload.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C3446521E2534E800F9522B /* AWDKeychainCKKSRateLimiterOverload.m */; }; + 6C8CC3AD1E2F913C009025C5 /* AWDKeychainCKKSRateLimiterTopWriters.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C3446541E2534E800F9522B /* AWDKeychainCKKSRateLimiterTopWriters.m */; }; + 6C8CC3B31E2F913D009025C5 /* AWDKeychainCKKSRateLimiterAggregatedScores.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C3446501E2534E800F9522B /* AWDKeychainCKKSRateLimiterAggregatedScores.m */; }; + 6C8CC3B41E2F913D009025C5 /* AWDKeychainCKKSRateLimiterOverload.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C3446521E2534E800F9522B /* AWDKeychainCKKSRateLimiterOverload.m */; }; + 6C8CC3B51E2F913D009025C5 /* AWDKeychainCKKSRateLimiterTopWriters.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C3446541E2534E800F9522B /* AWDKeychainCKKSRateLimiterTopWriters.m */; }; + 6C8CC3B61E2F98C2009025C5 /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 6C98083E1E788AEB00E70590 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; + 6C9808491E788AEB00E70590 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; + 6C98084A1E788AEB00E70590 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; + 6C98084C1E788AEB00E70590 /* libsecurityd_ios_NO_AKS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC222C771E034D1F00B09171 /* libsecurityd_ios_NO_AKS.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.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient.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 */; }; + 6C9808851E788AFD00E70590 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; + 6C9808861E788AFD00E70590 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; + 6C9808881E788AFD00E70590 /* libsecurityd_ios_NO_AKS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC222C771E034D1F00B09171 /* libsecurityd_ios_NO_AKS.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.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient.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 */; }; + 6CAB39C71E521BEA00566A79 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + 6CB5F47B1E402E6700DBF3F0 /* KeychainEntitledTestRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB5F47A1E402E5700DBF3F0 /* KeychainEntitledTestRunner.m */; }; + 6CC1859E1E24E8EB009657D8 /* CKKSRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */; }; + 6CC1859F1E24E8EB009657D8 /* CKKSRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */; }; + 6CCDF78C1E3C26BC003F2555 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CCDF78B1E3C26BC003F2555 /* XCTest.framework */; }; + 6CCDF78D1E3C26C2003F2555 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B6A881E2B5F9900CD6EE5 /* Foundation.framework */; }; + 6CE22D701E49206600974785 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE22D6F1E49206600974785 /* UIKit.framework */; }; + 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 */; }; + 6CF4A0C01E45488B00ECD7B5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0BF1E45488B00ECD7B5 /* Assets.xcassets */; }; + 6CF4A0C31E45488B00ECD7B5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0C11E45488B00ECD7B5 /* Main.storyboard */; }; + 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 */; }; + 6CF4A0ED1E4549F300ECD7B5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0EB1E4549F300ECD7B5 /* Main.storyboard */; }; + 6CF4A0EF1E4549F300ECD7B5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0EE1E4549F300ECD7B5 /* Assets.xcassets */; }; + 6CF4A0F21E4549F300ECD7B5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0F01E4549F300ECD7B5 /* LaunchScreen.storyboard */; }; 7200D76F177B9999009BB396 /* ManagedConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72C3EC2D1705F24E0040C87C /* ManagedConfiguration.framework */; }; + 724340BA1ED3FEC800F8F566 /* SecSMIME.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17870D1D778FA900B50D50 /* SecSMIME.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 7281E0871DFD01800021E1B7 /* SOSAccountGetSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7281E0861DFD015A0021E1B7 /* SOSAccountGetSet.m */; }; + 7281E0881DFD06480021E1B7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + 7281E08D1DFD0B520021E1B7 /* XPCNotificationDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E7C787331DD0FED50087FC34 /* XPCNotificationDispatcher.m */; }; + 7281E08F1DFD0DBB0021E1B7 /* secd-210-keyinterest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7281E08E1DFD0D810021E1B7 /* secd-210-keyinterest.m */; }; + 7281E0901DFD0E0A0021E1B7 /* CKDKVSProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = E7A5F4C71C0CFF3200F3BEBB /* CKDKVSProxy.m */; }; + 7281E0911DFD0E510021E1B7 /* CKDSimulatedStore.m in Sources */ = {isa = PBXBuildFile; fileRef = E7FE40C41DC804E400F0F5B6 /* CKDSimulatedStore.m */; }; + 7281E0971DFD0FD00021E1B7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; 728B56A216D59979008FA3AB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; 72C3EC2E1705F24E0040C87C /* ManagedConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72C3EC2D1705F24E0040C87C /* ManagedConfiguration.framework */; }; 72CD2BBE16D59AE30064EEE1 /* OTAServiceApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 72CD2BBB16D59AE30064EEE1 /* OTAServiceApp.m */; }; 72CD2BBF16D59AE30064EEE1 /* OTAServicemain.m in Sources */ = {isa = PBXBuildFile; fileRef = 72CD2BBD16D59AE30064EEE1 /* OTAServicemain.m */; }; 72CD2BCD16D59AF30064EEE1 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; }; 72CD2BCE16D59B010064EEE1 /* MobileAsset.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7273402816CAFB3C0096622A /* MobileAsset.framework */; }; + 72CDF5131EC679A4002D233B /* sec_action.h in Headers */ = {isa = PBXBuildFile; fileRef = 7221843F1EC6782A004C7BED /* sec_action.h */; }; + 72CDF5191EC679A8002D233B /* sec_action.c in Sources */ = {isa = PBXBuildFile; fileRef = 7221843E1EC6782A004C7BED /* sec_action.c */; }; 72DF9EFE178360230054641E /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; 78F92F11195128D70023B54B /* SecECKeyPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 78F92F10195128D70023B54B /* SecECKeyPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; 7901791812D51F7200CA4D44 /* SecCmsBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 7901790E12D51F7200CA4D44 /* SecCmsBase.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -814,7 +1087,17 @@ 79EF5B730D3D6AFE009F5270 /* p12import.h in Headers */ = {isa = PBXBuildFile; fileRef = 79EF5B720D3D6AFE009F5270 /* p12import.h */; }; 8E02FA6B1107BE460043545E /* pbkdf2.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E02FA691107BE460043545E /* pbkdf2.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8ED6F6CA110904E300D2B368 /* SecPBKDF.h in Headers */ = {isa = PBXBuildFile; fileRef = 8ED6F6C8110904E300D2B368 /* SecPBKDF.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 8EECC6601DAC699900972D50 /* MobileKeyBag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FC30AB1332DE9000802946 /* MobileKeyBag.framework */; }; + ACBAF6EE1E941AE00007BA2F /* transform_regressions.h in Headers */ = {isa = PBXBuildFile; fileRef = ACBAF6E31E941AE00007BA2F /* transform_regressions.h */; }; + ACBAF6EF1E941AE00007BA2F /* transform_regressions.h in Headers */ = {isa = PBXBuildFile; fileRef = ACBAF6E31E941AE00007BA2F /* transform_regressions.h */; }; + ACBAF6F91E941B020007BA2F /* transform-01-sigverify.m in Sources */ = {isa = PBXBuildFile; fileRef = ACBAF6E51E941AE00007BA2F /* transform-01-sigverify.m */; }; + ACBAF6FC1E941B620007BA2F /* libsecurity_transform_regressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ACBAF6DD1E9417F40007BA2F /* libsecurity_transform_regressions.a */; }; + B61577E81F20151C004A3930 /* SecPaddingConfigurations.c in Sources */ = {isa = PBXBuildFile; fileRef = B61F67551F1FCFCA00E2FDBB /* SecPaddingConfigurations.c */; }; + B61577EA1F201542004A3930 /* SecPaddingConfigurationsPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = B61F67541F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; + B61577EC1F201562004A3930 /* SecPaddingConfigurationsPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = B61F67541F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h */; }; + B61577ED1F202049004A3930 /* SecPaddingConfigurations.c in Sources */ = {isa = PBXBuildFile; fileRef = B61F67551F1FCFCA00E2FDBB /* SecPaddingConfigurations.c */; }; + B61577F41F20513C004A3930 /* padding-00-mmcs.c in Sources */ = {isa = PBXBuildFile; fileRef = B61577EE1F2021BC004A3930 /* padding-00-mmcs.c */; }; + B61F67561F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = B61F67541F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; + B61F67571F1FCFCB00E2FDBB /* SecPaddingConfigurations.c in Sources */ = {isa = PBXBuildFile; fileRef = B61F67551F1FCFCA00E2FDBB /* SecPaddingConfigurations.c */; }; BE061FE11899ECEE00C739F6 /* SecSharedCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; BE197F2C19116FD100BA91D1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BE197F2A19116FD100BA91D1 /* InfoPlist.strings */; }; BE197F2E19116FD100BA91D1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BE197F2D19116FD100BA91D1 /* main.m */; }; @@ -823,6 +1106,10 @@ 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 */; }; + BE22FC041EE3584400893431 /* mark.m in Sources */ = {isa = PBXBuildFile; fileRef = BE22FBFC1EE23D9100893431 /* mark.m */; }; BE25C41618B83491003320E0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; BE405EE21DC2F10E00E227B1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; BE405EE31DC2F11E00E227B1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; @@ -836,50 +1123,167 @@ BE4AC9A218B7FFAD00B84964 /* swcagent.m in Sources */ = {isa = PBXBuildFile; fileRef = BE4AC9A118B7FFAD00B84964 /* swcagent.m */; }; BE4AC9AE18B7FFC800B84964 /* com.apple.security.swcagent.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BE4AC9AD18B7FFC800B84964 /* com.apple.security.swcagent.plist */; }; BE4AC9BA18B8273600B84964 /* SharedWebCredentials.strings in Resources */ = {isa = PBXBuildFile; fileRef = BE4AC9B818B8273600B84964 /* SharedWebCredentials.strings */; }; - BE6D96B71DB14B65001B76D4 /* cnnic_certs.h in Headers */ = {isa = PBXBuildFile; fileRef = BE6D96B41DB14B65001B76D4 /* cnnic_certs.h */; }; - BE6D96B81DB14B65001B76D4 /* date_testing_certs.h in Headers */ = {isa = PBXBuildFile; fileRef = BE6D96B51DB14B65001B76D4 /* date_testing_certs.h */; }; - BE6D96B91DB14B65001B76D4 /* wosign_certs.h in Headers */ = {isa = PBXBuildFile; fileRef = BE6D96B61DB14B65001B76D4 /* wosign_certs.h */; }; - BE6D96BB1DB14B9F001B76D4 /* si-84-sectrust-allowlist.m in Sources */ = {isa = PBXBuildFile; fileRef = BE6D96BA1DB14B9F001B76D4 /* si-84-sectrust-allowlist.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 */; }; BE759DCB1917E38D00801E02 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE451314471B000DE34E /* CoreGraphics.framework */; }; BE8ABDD81DC2DD9100EC2D58 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; - BEE523D61DA610F500DD0AA3 /* SecRevocationDb.c in Sources */ = {isa = PBXBuildFile; fileRef = BEE523CF1DA610D800DD0AA3 /* SecRevocationDb.c */; }; - BEE523D71DACA97600DD0AA3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789221D7799A600B50D50 /* libz.dylib */; }; + BED208D81EDF950E00753952 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; + BED208D91EDF950E00753952 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + BED208E81EDF974500753952 /* manifeststresstest.m in Sources */ = {isa = PBXBuildFile; fileRef = BED208E71EDF971600753952 /* manifeststresstest.m */; }; BEE523D91DACAA2500DD0AA3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789221D7799A600B50D50 /* libz.dylib */; }; - BEE523DA1DACAA5700DD0AA3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789221D7799A600B50D50 /* libz.dylib */; }; - BEE523DB1DACAA8C00DD0AA3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789221D7799A600B50D50 /* libz.dylib */; }; BEE523DC1DACAA9200DD0AA3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789221D7799A600B50D50 /* libz.dylib */; }; - BEE523DD1DACAA9800DD0AA3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789221D7799A600B50D50 /* libz.dylib */; }; + BEEB47D91EA189F5004AA5C6 /* SecTrustStatusCodes.c in Sources */ = {isa = PBXBuildFile; fileRef = BEEB47D71EA189F5004AA5C6 /* SecTrustStatusCodes.c */; }; + BEEB47DA1EA189F5004AA5C6 /* SecTrustStatusCodes.c in Sources */ = {isa = PBXBuildFile; fileRef = BEEB47D71EA189F5004AA5C6 /* SecTrustStatusCodes.c */; }; + BEEB47DB1EA189F5004AA5C6 /* SecTrustStatusCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = BEEB47D81EA189F5004AA5C6 /* SecTrustStatusCodes.h */; }; + BEEB47DC1EA189F5004AA5C6 /* SecTrustStatusCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = BEEB47D81EA189F5004AA5C6 /* SecTrustStatusCodes.h */; }; + BEF88C311EAFFC3F00357577 /* TrustedPeers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEF88C281EAFFC3F00357577 /* TrustedPeers.framework */; }; + BEF88C771EB000BE00357577 /* TPCategoryRule.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C481EB0005E00357577 /* TPCategoryRule.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C781EB000BE00357577 /* TPCategoryRule.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C491EB0005E00357577 /* TPCategoryRule.m */; }; + BEF88C791EB000BE00357577 /* TPCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C4A1EB0005E00357577 /* TPCircle.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C7A1EB000BE00357577 /* TPCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C4B1EB0005E00357577 /* TPCircle.m */; }; + BEF88C7B1EB000BE00357577 /* TPDecrypter.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C4C1EB0005E00357577 /* TPDecrypter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C7C1EB000BE00357577 /* TPEncrypter.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C4D1EB0005E00357577 /* TPEncrypter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C7D1EB000BE00357577 /* TPHash.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C4E1EB0005E00357577 /* TPHash.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C7E1EB000BE00357577 /* TPHash.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C4F1EB0005E00357577 /* TPHash.m */; }; + BEF88C7F1EB000BE00357577 /* TPModel.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C501EB0005E00357577 /* TPModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C801EB000BE00357577 /* TPModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C511EB0005E00357577 /* TPModel.m */; }; + BEF88C811EB000BE00357577 /* TPPeer.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C521EB0005E00357577 /* TPPeer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C821EB000BE00357577 /* TPPeer.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C531EB0005E00357577 /* TPPeer.m */; }; + BEF88C831EB000BE00357577 /* TPPeerDynamicInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C541EB0005E00357577 /* TPPeerDynamicInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C841EB000BE00357577 /* TPPeerDynamicInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C551EB0005E00357577 /* TPPeerDynamicInfo.m */; }; + BEF88C851EB000BE00357577 /* TPPeerPermanentInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C561EB0005E00357577 /* TPPeerPermanentInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C861EB000BE00357577 /* TPPeerPermanentInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C571EB0005E00357577 /* TPPeerPermanentInfo.m */; }; + BEF88C871EB000BE00357577 /* TPPeerStableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C581EB0005E00357577 /* TPPeerStableInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C881EB000BE00357577 /* TPPeerStableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C591EB0005E00357577 /* TPPeerStableInfo.m */; }; + BEF88C891EB000BE00357577 /* TPPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C5A1EB0005E00357577 /* TPPolicy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C8A1EB000BE00357577 /* TPPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C5B1EB0005E00357577 /* TPPolicy.m */; }; + BEF88C8B1EB000BE00357577 /* TPPolicyDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C5C1EB0005E00357577 /* TPPolicyDocument.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C8C1EB000BE00357577 /* TPPolicyDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C5D1EB0005E00357577 /* TPPolicyDocument.m */; }; + BEF88C8D1EB000BE00357577 /* TPSigningKey.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C5E1EB0005E00357577 /* TPSigningKey.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C8E1EB000BE00357577 /* TPTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C5F1EB0005E00357577 /* TPTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C8F1EB000BE00357577 /* TPUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C601EB0005E00357577 /* TPUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C901EB000BE00357577 /* TPUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C611EB0005E00357577 /* TPUtils.m */; }; + BEF88C911EB000BE00357577 /* TPVoucher.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C621EB0005E00357577 /* TPVoucher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BEF88C921EB000BE00357577 /* TPVoucher.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C631EB0005F00357577 /* TPVoucher.m */; }; + BEF88C931EB000FD00357577 /* TPCircleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C671EB0008E00357577 /* TPCircleTests.m */; }; + BEF88C941EB000FD00357577 /* TPDummyDecrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C691EB0008E00357577 /* TPDummyDecrypter.m */; }; + BEF88C951EB000FD00357577 /* TPDummyEncrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C6B1EB0008E00357577 /* TPDummyEncrypter.m */; }; + BEF88C961EB000FD00357577 /* TPDummySigningKey.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C6D1EB0008E00357577 /* TPDummySigningKey.m */; }; + BEF88C971EB000FD00357577 /* TPDummySigningKeyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C6E1EB0008E00357577 /* TPDummySigningKeyTests.m */; }; + BEF88C981EB000FD00357577 /* TPModelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C701EB0008E00357577 /* TPModelTests.m */; }; + BEF88C991EB000FD00357577 /* TPPeerPermanentInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C711EB0008E00357577 /* TPPeerPermanentInfoTests.m */; }; + BEF88C9A1EB000FD00357577 /* TPPeerStableInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C721EB0008E00357577 /* TPPeerStableInfoTests.m */; }; + BEF88C9B1EB000FD00357577 /* TPPeerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C731EB0008E00357577 /* TPPeerTests.m */; }; + BEF88C9C1EB000FD00357577 /* TPPolicyDocumentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C741EB0008E00357577 /* TPPolicyDocumentTests.m */; }; + BEF88C9D1EB000FD00357577 /* TPUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C751EB0008E00357577 /* TPUtilsTests.m */; }; + BEF88C9E1EB000FD00357577 /* TPVoucherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF88C761EB0008E00357577 /* TPVoucherTests.m */; }; CD0637551A84060600C81E74 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; CD0637561A84065F00C81E74 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; }; CD0637571A84068F00C81E74 /* IDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD744683195A00BB00FB01C0 /* IDS.framework */; }; + CD112FC51DDA31AD00C77A07 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4C19C171E0EA600877419 /* Accounts.framework */; }; + CD198F971DE27B9E00F6FB83 /* SOSAccountPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = CD9021471DE27A9E00F81DC4 /* SOSAccountPriv.h */; }; CD23B49E1DA06EB40047EDE9 /* IDSPersistentState.m in Sources */ = {isa = PBXBuildFile; fileRef = CD23B4931DA06EB30047EDE9 /* IDSPersistentState.m */; }; CD23B4A01DA06EB40047EDE9 /* IDSProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = CD23B4951DA06EB30047EDE9 /* IDSProxy.m */; }; CD23B4A11DA06EB40047EDE9 /* keychainsyncingoveridsproxy.m in Sources */ = {isa = PBXBuildFile; fileRef = CD23B4961DA06EB30047EDE9 /* keychainsyncingoveridsproxy.m */; }; CD23B4A31DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+ReceiveMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = CD23B4981DA06EB30047EDE9 /* KeychainSyncingOverIDSProxy+ReceiveMessage.m */; }; CD23B4A51DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+SendMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = CD23B49A1DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+SendMessage.m */; }; - CD23B4A71DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+Throttle.m in Sources */ = {isa = PBXBuildFile; fileRef = CD23B49C1DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+Throttle.m */; }; CD276C281A83F60C003226BC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; - CD31F89E1DCE86D600414B46 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4C19C171E0EA600877419 /* Accounts.framework */; }; - CD51245E1DA1C67000962524 /* com.apple.private.alloy.keychainsync.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = CD23B4A81DA06ED10047EDE9 /* com.apple.private.alloy.keychainsync.plist */; }; + CD51245E1DA1C67000962524 /* com.apple.private.alloy.keychainsync.plist in Install alloy plist */ = {isa = PBXBuildFile; fileRef = CD23B4A81DA06ED10047EDE9 /* com.apple.private.alloy.keychainsync.plist */; }; + CD791B3C1DFC9A7600F0E5DC /* libsqlite3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2F99D91DFC995B00769430 /* libsqlite3.0.dylib */; }; + CD791B3D1DFC9AB200F0E5DC /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB740680A4749C800D641BB /* libsqlite3.dylib */; }; + CD9F2AF81DF23CA600AD3577 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + CD9F2AF91DF249B400AD3577 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + CD9F2AFA1DF249CF00AD3577 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + CD9F2AFB1DF24BAF00AD3577 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; CDB9FCAB179CD098000AAD66 /* Info.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = CDB9FCA9179CC757000AAD66 /* Info.plist */; }; CDDE9BD11729ABFA0013B0E8 /* SecPasswordGenerate.h in Headers */ = {isa = PBXBuildFile; fileRef = CDDE9BC31729AB910013B0E8 /* SecPasswordGenerate.h */; settings = {ATTRIBUTES = (Private, ); }; }; + D4096E011ED5F0B5000AC459 /* si-60-cms.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD81D8085FC00865A7C /* si-60-cms.c */; }; + D4096E021ED5F207000AC459 /* si-64-ossl-cms.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DE71D8085FC00865A7C /* si-64-ossl-cms.c */; }; + D4096E031ED5F21C000AC459 /* si-65-cms-cert-policy.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DE81D8085FC00865A7C /* si-65-cms-cert-policy.c */; }; + D40B6A821E2B5F5600CD6EE5 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; + D40B6A831E2B5F5B00CD6EE5 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; + D40B6A8D1E2B63D900CD6EE5 /* libtrustd.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4ADA3191E2B41670031CEA3 /* libtrustd.a */; }; + D40B6A8E1E2B643500CD6EE5 /* libtrustd.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4ADA3191E2B41670031CEA3 /* libtrustd.a */; }; + D40B6A8F1E2B643D00CD6EE5 /* libtrustd.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4ADA3191E2B41670031CEA3 /* libtrustd.a */; }; + D40B6A901E2B673500CD6EE5 /* libtrustd.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4ADA3191E2B41670031CEA3 /* libtrustd.a */; }; + D40B6A931E2B67E500CD6EE5 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; + D40B6A971E2B684900CD6EE5 /* libsqlite3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2F99D91DFC995B00769430 /* libsqlite3.0.dylib */; }; + D40B6A981E2B687F00CD6EE5 /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3C1D78F25C002223DE /* libDiagnosticMessagesClient.dylib */; }; + 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 */; }; + D40C2C241E94342A009D793B /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDA43D251DFCA0790038E038 /* AggregateDictionary.framework */; }; + D41257D01E9410A300781F23 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B6A881E2B5F9900CD6EE5 /* Foundation.framework */; }; + D41257D91E9412B800781F23 /* trustd.c in Sources */ = {isa = PBXBuildFile; fileRef = D4BEECE61E93093A00F76D1A /* trustd.c */; }; + D41257DA1E9412DC00781F23 /* libtrustd.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4ADA3191E2B41670031CEA3 /* libtrustd.a */; }; + D41257DB1E9412E700781F23 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; + D41257DC1E94130C00781F23 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; + D41257DE1E94132900781F23 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB740680A4749C800D641BB /* libsqlite3.dylib */; }; + D41257DF1E94133600781F23 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; }; + D41257E01E94136000781F23 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; + D41257E21E94138600781F23 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; + D41257EF1E941E4E00781F23 /* com.apple.trustd.plist in Copy LaunchDaemon */ = {isa = PBXBuildFile; fileRef = D41257EE1E941DA800781F23 /* com.apple.trustd.plist */; }; + D41258011E94230400781F23 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; }; + 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 */; }; D425EC1D1DD3C3CF00DE5DEC /* SecInternalRelease.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC761D8C68CF00070CB0 /* SecInternalRelease.c */; }; D425EC231DD3FFF200DE5DEC /* SecInternalRelease.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC761D8C68CF00070CB0 /* SecInternalRelease.c */; }; D42CDC351DC12FE90090E2C9 /* si-66-smime.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DEB1D8085FC00865A7C /* si-66-smime.c */; }; + D43761661EB2996C00954447 /* SecRevocationNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = D43761641EB2996C00954447 /* SecRevocationNetworking.h */; }; + D43761671EB2996C00954447 /* SecRevocationNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = D43761651EB2996C00954447 /* SecRevocationNetworking.m */; }; + D43B88721E72298500F86F19 /* MobileAsset.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7273402816CAFB3C0096622A /* MobileAsset.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + D43DBEFB1E99D1CA00C04AEA /* asynchttp.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBED51E99D17100C04AEA /* asynchttp.c */; }; + D43DBEFC1E99D1CA00C04AEA /* nameconstraints.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBED71E99D17100C04AEA /* nameconstraints.c */; }; + D43DBEFD1E99D1CA00C04AEA /* OTATrustUtilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBED91E99D17100C04AEA /* OTATrustUtilities.c */; }; + D43DBEFE1E99D1CA00C04AEA /* personalization.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEDB1E99D17100C04AEA /* personalization.c */; }; + D43DBEFF1E99D1CA00C04AEA /* policytree.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEDD1E99D17100C04AEA /* policytree.c */; }; + D43DBF001E99D1CA00C04AEA /* SecCAIssuerCache.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEDF1E99D17200C04AEA /* SecCAIssuerCache.c */; }; + D43DBF011E99D1CA00C04AEA /* SecCAIssuerRequest.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEE11E99D17200C04AEA /* SecCAIssuerRequest.c */; }; + D43DBF021E99D1CA00C04AEA /* SecCertificateServer.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEE31E99D17200C04AEA /* SecCertificateServer.c */; }; + D43DBF031E99D1CA00C04AEA /* SecCertificateSource.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEE51E99D17200C04AEA /* SecCertificateSource.c */; }; + D43DBF041E99D1CA00C04AEA /* SecOCSPCache.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEE71E99D17200C04AEA /* SecOCSPCache.c */; }; + D43DBF051E99D1CA00C04AEA /* SecOCSPRequest.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEE91E99D17200C04AEA /* SecOCSPRequest.c */; }; + D43DBF061E99D1CA00C04AEA /* SecOCSPResponse.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEEB1E99D17200C04AEA /* SecOCSPResponse.c */; }; + D43DBF071E99D1CA00C04AEA /* SecPinningDb.m in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEEE1E99D17200C04AEA /* SecPinningDb.m */; }; + D43DBF081E99D1CA00C04AEA /* SecPolicyServer.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEEF1E99D17300C04AEA /* SecPolicyServer.c */; }; + D43DBF091E99D1CA00C04AEA /* SecRevocationDb.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEF11E99D17300C04AEA /* SecRevocationDb.c */; }; + D43DBF0A1E99D1CA00C04AEA /* SecRevocationServer.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEF31E99D17300C04AEA /* SecRevocationServer.c */; }; + D43DBF0B1E99D1CA00C04AEA /* SecTrustLoggingServer.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEF51E99D17300C04AEA /* SecTrustLoggingServer.c */; }; + D43DBF0C1E99D1CA00C04AEA /* SecTrustServer.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEF71E99D17300C04AEA /* SecTrustServer.c */; }; + D43DBF0D1E99D1CA00C04AEA /* SecTrustStoreServer.c in Sources */ = {isa = PBXBuildFile; fileRef = D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */; }; D447C4101D3094740082FC1D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; }; + D450686A1E948D2200FA7675 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; }; D45917E41DC13E6700752D25 /* SecCertificateRequest.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E3E1D8085FC00865A7C /* SecCertificateRequest.c */; }; - D46F315A1E00A27D0065B550 /* SecTrustLoggingServer.c in Sources */ = {isa = PBXBuildFile; fileRef = D46F31581E00A27D0065B550 /* SecTrustLoggingServer.c */; }; - D46F315B1E00A27D0065B550 /* SecTrustLoggingServer.h in Headers */ = {isa = PBXBuildFile; fileRef = D46F31591E00A27D0065B550 /* SecTrustLoggingServer.h */; }; - D46F31631E00CCD20065B550 /* SecCertificateSource.c in Sources */ = {isa = PBXBuildFile; fileRef = D46F31611E00CCD20065B550 /* SecCertificateSource.c */; }; - D46F31641E00CCD20065B550 /* SecCertificateSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D46F31621E00CCD20065B550 /* SecCertificateSource.h */; }; + D459A1781E9FFE60009ED74B /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E9411D7F3E6E00AFB96E /* CoreCDP.framework */; }; + D47CA65D1EB036450038E2BB /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */; }; + D47E69401E92F75D002C8CF6 /* si-61-pkcs12.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD91D8085FC00865A7C /* si-61-pkcs12.c */; }; D47F514C1C3B812500A7CEFE /* SecCFAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; D487B9821DFA28DB000410A1 /* SecInternalReleasePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC771D8C68CF00070CB0 /* SecInternalReleasePriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; D487B9881DFA2902000410A1 /* SecInternalReleasePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC771D8C68CF00070CB0 /* SecInternalReleasePriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; D487FBB81DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m in Sources */ = {isa = PBXBuildFile; fileRef = D487FBB71DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m */; }; D487FBBA1DB835B500D4BB0B /* si-29-sectrust-sha1-deprecation.h in Headers */ = {isa = PBXBuildFile; fileRef = D487FBB91DB835B500D4BB0B /* si-29-sectrust-sha1-deprecation.h */; }; D48E4E241E42F0620011B4BA /* si-62-csr.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DDA1D8085FC00865A7C /* si-62-csr.c */; }; + D4AA64361E95D92600D317ED /* com.apple.trustd.sb in Copy Sandbox */ = {isa = PBXBuildFile; fileRef = D41257EB1E941CF200781F23 /* com.apple.trustd.sb */; }; + D4AA643C1E95D93100D317ED /* com.apple.trustd.plist in Copy LaunchDaemon Files */ = {isa = PBXBuildFile; fileRef = D41257EA1E941CF200781F23 /* com.apple.trustd.plist */; }; + D4AA643D1E95D93900D317ED /* com.apple.trustd.agent.plist in Copy LaunchAgent */ = {isa = PBXBuildFile; fileRef = D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */; }; + D4AA643E1E95D94400D317ED /* trustd.8 in Install man8 page */ = {isa = PBXBuildFile; fileRef = D41257EC1E941CF200781F23 /* trustd.8 */; }; + D4AA64861E97273D00D317ED /* si-18-certificate-parse in Resources */ = {isa = PBXBuildFile; fileRef = D4AA64831E97270300D317ED /* si-18-certificate-parse */; }; + D4AA64871E97274900D317ED /* si-18-certificate-parse in Resources */ = {isa = PBXBuildFile; fileRef = D4AA64831E97270300D317ED /* si-18-certificate-parse */; }; + D4AA64881E97275200D317ED /* si-18-certificate-parse in Resources */ = {isa = PBXBuildFile; fileRef = D4AA64831E97270300D317ED /* si-18-certificate-parse */; }; + D4AA64891E9727EB00D317ED /* si-18-certificate-parse.m in Sources */ = {isa = PBXBuildFile; fileRef = D4AA647C1E97144700D317ED /* si-18-certificate-parse.m */; }; D4AA9D121C3B1B1900A5640C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; }; + D4AD87701E452CE000CA1B7F /* si-68-secmatchissuer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DF81D8085FC00865A7C /* si-68-secmatchissuer.c */; }; + D4ADA32E1E2B43220031CEA3 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; + D4ADA32F1E2B43220031CEA3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + D4ADA3301E2B433B0031CEA3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; + D4ADA3311E2B43450031CEA3 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; }; D4B858671D370D9A003B2D95 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4B858661D370D9A003B2D95 /* MobileCoreServices.framework */; }; + D4BEECE81E93094500F76D1A /* trustd.c in Sources */ = {isa = PBXBuildFile; fileRef = D4BEECE61E93093A00F76D1A /* trustd.c */; }; + D4C7CD661E71E92D00139817 /* MobileAsset.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7273402816CAFB3C0096622A /* MobileAsset.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + D4CFAA7E1E660BB3004746AA /* si-32-sectrust-pinning-required.m in Sources */ = {isa = PBXBuildFile; fileRef = D4CFAA7D1E660BB3004746AA /* si-32-sectrust-pinning-required.m */; }; D4D718351E04A721000AE7A6 /* spbkdf-01-hmac-sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = D4D718341E04A721000AE7A6 /* spbkdf-01-hmac-sha256.c */; }; D4D886BF1CEB9F3B00DC7583 /* ssl-policy-certs in Resources */ = {isa = PBXBuildFile; fileRef = D4D886BE1CEB9F3B00DC7583 /* ssl-policy-certs */; }; D4D886C01CEB9F7200DC7583 /* ssl-policy-certs in Resources */ = {isa = PBXBuildFile; fileRef = D4D886BE1CEB9F3B00DC7583 /* ssl-policy-certs */; }; @@ -887,29 +1291,24 @@ D4D886EA1CEBDE0800DC7583 /* nist-certs in Resources */ = {isa = PBXBuildFile; fileRef = D4D886E81CEBDD2A00DC7583 /* nist-certs */; }; D4EC94FB1CEA482D0083E753 /* si-20-sectrust-policies-data in Resources */ = {isa = PBXBuildFile; fileRef = D4EC94FA1CEA482D0083E753 /* si-20-sectrust-policies-data */; }; D4EC94FE1CEA48760083E753 /* si-20-sectrust-policies-data in Resources */ = {isa = PBXBuildFile; fileRef = D4EC94FA1CEA482D0083E753 /* si-20-sectrust-policies-data */; }; + D4FBBD621DD661A7004408F7 /* CMSEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = D4FBBD601DD66196004408F7 /* CMSEncoder.h */; settings = {ATTRIBUTES = (Private, ); }; }; + D4FBBD631DD661AD004408F7 /* CMSDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = D4FBBD611DD66196004408F7 /* CMSDecoder.h */; settings = {ATTRIBUTES = (Private, ); }; }; + DA30D6851DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30D6841DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m */; }; DC0067C11D87879D005AF8DB /* ucspServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC6A82811D87734600418608 /* ucspServer.cpp */; }; DC0067C21D8787A4005AF8DB /* ucspNotifyReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC6A82831D87734600418608 /* ucspNotifyReceiver.cpp */; }; DC0067D11D8788B7005AF8DB /* ucspClientC.c in Sources */ = {isa = PBXBuildFile; fileRef = DC6A82801D87734600418608 /* ucspClientC.c */; }; - DC00AB611D821BE600513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; - DC00AB621D821BEC00513D74 /* libsecipc_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */; }; DC00AB631D821BEF00513D74 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; DC00AB641D821BF300513D74 /* liblogging.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC5C1D80D05200B0A59C /* liblogging.a */; }; DC00AB6B1D821C1A00513D74 /* libSecTrustOSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD66D731D8204A700DB1393 /* libSecTrustOSX.a */; }; - DC00AB6C1D821C1F00513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; DC00AB6D1D821C2300513D74 /* liblogging.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC5C1D80D05200B0A59C /* liblogging.a */; }; - DC00AB6E1D821C2700513D74 /* libsecipc_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */; }; DC00AB6F1D821C3400513D74 /* libSecItemShimOSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EE6E1D80D82600B0A59C /* libSecItemShimOSX.a */; }; DC00AB701D821C3800513D74 /* libSecOtrOSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD66DDB1D8205C400DB1393 /* libSecOtrOSX.a */; }; - DC00AB791D821C6700513D74 /* libsecipc_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */; }; - DC00AB7A1D821C6B00513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DC00AB7A1D821C6B00513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC00AB7B1D821C6E00513D74 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; DC00AB7C1D821C7100513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; DC00AB811D821C9100513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DC00AB821D821C9500513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DC00AB821D821C9500513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC00AB831D821C9A00513D74 /* libSWCAgent.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC4D1D80D00800B0A59C /* libSWCAgent.a */; }; - DC00AB8A1D821CB800513D74 /* libsecipc_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */; }; - DC00AB8B1D821CBE00513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; - DC00AB8D1D821CC500513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; DC00AB8E1D821D4900513D74 /* libSOSCommands.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC341D80CFB200B0A59C /* libSOSCommands.a */; }; DC00AB8F1D821D4D00513D74 /* libSecurityTool.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EA4C1D80CB7000B0A59C /* libSecurityTool.a */; }; DC00AB901D821D5600513D74 /* libSecurityCommands.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EBD51D80CEF100B0A59C /* libSecurityCommands.a */; }; @@ -920,45 +1319,43 @@ DC00AB9B1D821D9F00513D74 /* libSWCAgent.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC4D1D80D00800B0A59C /* libSWCAgent.a */; }; DC00AB9C1D821DA400513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; DC00ABA51D821DCD00513D74 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; - DC00ABA61D821DD000513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DC00ABA71D821DD300513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; - DC00ABA81D821DD900513D74 /* libsecipc_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */; }; DC00ABB31D821E0400513D74 /* libSharedRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EE411D80D6DD00B0A59C /* libSharedRegressions.a */; }; DC00ABB41D821E0700513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DC00ABB51D821E0B00513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DC00ABB51D821E0B00513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC00ABB71D821E2F00513D74 /* libiOSSecurityRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC971D80D1A800B0A59C /* libiOSSecurityRegressions.a */; }; DC00ABB81D821E3300513D74 /* libiOSsecuritydRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52ED9D1D80D4CD00B0A59C /* libiOSsecuritydRegressions.a */; }; DC00ABB91D821E3A00513D74 /* libSOSRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC681D80D0C400B0A59C /* libSOSRegressions.a */; }; DC00ABC01D821EBE00513D74 /* libSharedRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EE411D80D6DD00B0A59C /* libSharedRegressions.a */; }; DC00ABC11D821EC300513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DC00ABC21D821EC600513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DC00ABC21D821EC600513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC00ABC41D821ED900513D74 /* libiOSSecurityRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC971D80D1A800B0A59C /* libiOSSecurityRegressions.a */; }; DC00ABC51D821EDC00513D74 /* libiOSsecuritydRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52ED9D1D80D4CD00B0A59C /* libiOSsecuritydRegressions.a */; }; DC00ABC61D821EE500513D74 /* libSOSRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC681D80D0C400B0A59C /* libSOSRegressions.a */; }; DC00ABC71D821EF400513D74 /* libSharedRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EE411D80D6DD00B0A59C /* libSharedRegressions.a */; }; DC00ABCC1D821F0B00513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DC00ABCD1D821F0D00513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; - DC00ABD61D821F3200513D74 /* libsecipc_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */; }; + DC00ABCD1D821F0D00513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC00ABD71D821F3F00513D74 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; DC00ABD81D821F4300513D74 /* libsecdRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EDB11D80D58400B0A59C /* libsecdRegressions.a */; }; DC00ABD91D821F4700513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DC00ABDA1D821F4A00513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; - DC00ABE51D821F7200513D74 /* libsecipc_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */; }; + DC00ABDA1D821F4A00513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC00ABE61D821F7700513D74 /* libsecdRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EDB11D80D58400B0A59C /* libsecdRegressions.a */; }; - DC00ABE71D821F7A00513D74 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; DC00ABE81D821F7D00513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DC00ABE91D821F8000513D74 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DC00ABE91D821F8000513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC00ABEC1D821FA600513D74 /* libSecurityTool.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EA4C1D80CB7000B0A59C /* libSecurityTool.a */; }; 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 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DC00ABF31D821FCD00513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; + DC08D1C41E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC08D1C31E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m */; }; + DC08D1CC1E64FCC5006237DA /* CKKSSOSTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC08D1CB1E64FCC5006237DA /* CKKSSOSTests.m */; }; + DC0950411E38271300B2C8AC /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; }; + DC0984FD1E1DB6DF00140ADC /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DC0984FE1E1DB70100140ADC /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC0B62281D90974300D43BCB /* si-25-cms-skid.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0B62261D90973900D43BCB /* si-25-cms-skid.h */; }; DC0B62291D90974600D43BCB /* si-25-cms-skid.m in Sources */ = {isa = PBXBuildFile; fileRef = DC0B62271D90973900D43BCB /* si-25-cms-skid.m */; }; DC0B622A1D9097C600D43BCB /* libsecurity_cms_regressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1002CB1D8E19D70025549C /* libsecurity_cms_regressions.a */; }; - DC0B622C1D90982C00D43BCB /* secd-201-coders.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0B622B1D90982100D43BCB /* secd-201-coders.c */; }; + DC0B622C1D90982C00D43BCB /* secd-201-coders.m in Sources */ = {isa = PBXBuildFile; fileRef = DC0B622B1D90982100D43BCB /* secd-201-coders.m */; }; DC0B622F1D909C4600D43BCB /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC0B622D1D909C4600D43BCB /* MainMenu.xib */; }; DC0B62301D909C4600D43BCB /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC0B622D1D909C4600D43BCB /* MainMenu.xib */; }; - DC0BC55C1D8B6D2E00070CB0 /* XPCKeychainSandboxCheck.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = DC0BC5511D8B6D2D00070CB0 /* XPCKeychainSandboxCheck.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; DC0BC5611D8B6D6000070CB0 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BC5461D8B6AFE00070CB0 /* main.c */; }; DC0BC5621D8B6D7000070CB0 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789241D7799CD00B50D50 /* CoreFoundation.framework */; }; DC0BC5671D8B6E3D00070CB0 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789241D7799CD00B50D50 /* CoreFoundation.framework */; }; @@ -966,7 +1363,6 @@ DC0BC5751D8B6E7700070CB0 /* timestampclient.m in Sources */ = {isa = PBXBuildFile; fileRef = DC0BC5721D8B6E7700070CB0 /* timestampclient.m */; }; DC0BC5761D8B6E9300070CB0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; DC0BC5771D8B6EC300070CB0 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; - DC0BC57A1D8B6EF500070CB0 /* XPCTimeStampingService.xpc in Embed XPC Services */ = {isa = PBXBuildFile; fileRef = DC0BC56C1D8B6E3D00070CB0 /* XPCTimeStampingService.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; DC0BC57B1D8B6FF100070CB0 /* SecFDERecoveryAsymmetricCrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17872A1D77903700B50D50 /* SecFDERecoveryAsymmetricCrypto.h */; }; DC0BC57C1D8B700A00070CB0 /* AuthSession.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785201D7789AF00B50D50 /* AuthSession.h */; }; DC0BC57D1D8B701B00070CB0 /* Authorization.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17851C1D7789AF00B50D50 /* Authorization.h */; }; @@ -1258,7 +1654,6 @@ DC0BCA0C1D8B827200070CB0 /* sslMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BC9EB1D8B827200070CB0 /* sslMemory.h */; }; DC0BCA0D1D8B827200070CB0 /* sslPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BC9EC1D8B827200070CB0 /* sslPriv.h */; }; DC0BCA0E1D8B827200070CB0 /* sslRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BC9ED1D8B827200070CB0 /* sslRecord.h */; }; - DC0BCA0F1D8B827200070CB0 /* sslUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BC9EE1D8B827200070CB0 /* sslUtils.h */; }; DC0BCA101D8B827200070CB0 /* sslCrypto.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BC9F01D8B827200070CB0 /* sslCrypto.c */; }; DC0BCA111D8B827200070CB0 /* sslMemory.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BC9F21D8B827200070CB0 /* sslMemory.c */; }; DC0BCA491D8B82CD00070CB0 /* CA-ECC_Cert.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCA1B1D8B82CD00070CB0 /* CA-ECC_Cert.h */; }; @@ -1414,7 +1809,6 @@ DC0BCD711D8C69A000070CB0 /* su-16-cfdate-der.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCD541D8C697100070CB0 /* su-16-cfdate-der.c */; }; DC0BCD721D8C69A000070CB0 /* su-40-secdb.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCD551D8C697100070CB0 /* su-40-secdb.c */; }; DC0BCD731D8C69A000070CB0 /* su-41-secdb-stress.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCD561D8C697100070CB0 /* su-41-secdb-stress.c */; }; - DC0BCD741D8C6A1E00070CB0 /* SecMeta.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC391D8C68CF00070CB0 /* SecMeta.h */; }; DC0BCD751D8C6A1E00070CB0 /* iCloudKeychainTrace.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC3A1D8C68CF00070CB0 /* iCloudKeychainTrace.c */; }; DC0BCD761D8C6A1E00070CB0 /* iCloudKeychainTrace.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC3B1D8C68CF00070CB0 /* iCloudKeychainTrace.h */; }; DC0BCD771D8C6A1E00070CB0 /* SecAKSWrappers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC3C1D8C68CF00070CB0 /* SecAKSWrappers.c */; }; @@ -1423,8 +1817,6 @@ DC0BCD7A1D8C6A1E00070CB0 /* SecBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC3F1D8C68CF00070CB0 /* SecBuffer.h */; }; DC0BCD7B1D8C6A1E00070CB0 /* SecCoreCrypto.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC401D8C68CF00070CB0 /* SecCoreCrypto.c */; }; DC0BCD7C1D8C6A1E00070CB0 /* SecCoreCrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC411D8C68CF00070CB0 /* SecCoreCrypto.h */; }; - DC0BCD7D1D8C6A1E00070CB0 /* SecCertificateTrace.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC421D8C68CF00070CB0 /* SecCertificateTrace.c */; }; - DC0BCD7E1D8C6A1E00070CB0 /* SecCertificateTrace.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC431D8C68CF00070CB0 /* SecCertificateTrace.h */; }; DC0BCD7F1D8C6A1E00070CB0 /* SecCFCCWrappers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC441D8C68CF00070CB0 /* SecCFCCWrappers.c */; }; DC0BCD801D8C6A1E00070CB0 /* SecCFCCWrappers.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC451D8C68CF00070CB0 /* SecCFCCWrappers.h */; }; DC0BCD811D8C6A1E00070CB0 /* SecCFRelease.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC461D8C68CF00070CB0 /* SecCFRelease.h */; }; @@ -1475,6 +1867,11 @@ DC0BCDB51D8C6A5B00070CB0 /* not_on_this_platorm.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCDB41D8C6A5B00070CB0 /* not_on_this_platorm.c */; }; DC1002AF1D8E18870025549C /* libsecurity_codesigning.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD0677F1D8CDF19007602F1 /* libsecurity_codesigning.a */; }; DC1002D81D8E1A670025549C /* SecTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 107226D10D91DB32003CF14F /* SecTask.h */; }; + DC15F7661E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC15F7641E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.h */; }; + DC15F7671E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC15F7641E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.h */; }; + DC15F7681E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC15F7651E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m */; }; + DC15F7691E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC15F7651E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m */; }; + DC15F79C1E68EAD5003B9A40 /* CKKSTests+API.m in Sources */ = {isa = PBXBuildFile; fileRef = DC15F79B1E68EAD5003B9A40 /* CKKSTests+API.m */; }; DC1785161D77895A00B50D50 /* oidsalg.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785111D77895A00B50D50 /* oidsalg.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC1785171D77895A00B50D50 /* oidsattr.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785121D77895A00B50D50 /* oidsattr.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC1785181D77895A00B50D50 /* SecAsn1Coder.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785131D77895A00B50D50 /* SecAsn1Coder.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1597,11 +1994,8 @@ DC1787501D7790A500B50D50 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787461D7790A500B50D50 /* SecCodeHostLib.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC1787511D7790A500B50D50 /* SecCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787471D7790A500B50D50 /* SecCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC1787521D7790A500B50D50 /* SecCodeSigner.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787481D7790A500B50D50 /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; }; - DC1787531D7790A500B50D50 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787491D7790A500B50D50 /* SecIntegrity.h */; settings = {ATTRIBUTES = (Private, ); }; }; - DC1787541D7790A500B50D50 /* SecIntegrityLib.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17874A1D7790A500B50D50 /* SecIntegrityLib.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC1787551D7790A500B50D50 /* SecRequirementPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17874B1D7790A500B50D50 /* SecRequirementPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC1787561D7790A500B50D50 /* SecStaticCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17874C1D7790A500B50D50 /* SecStaticCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; - DC1787571D7790A500B50D50 /* SecTaskPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17874D1D7790A500B50D50 /* SecTaskPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC1787591D7790B600B50D50 /* CMSPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787581D7790B600B50D50 /* CMSPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC17875C1D7790CE00B50D50 /* checkpw.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17875B1D7790CE00B50D50 /* checkpw.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC17875F1D7790E500B50D50 /* AuthorizationPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17875D1D7790E500B50D50 /* AuthorizationPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1638,7 +2032,6 @@ DC1789151D77997F00B50D50 /* libOpenScriptingUtil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789141D77997F00B50D50 /* libOpenScriptingUtil.dylib */; settings = {ATTRIBUTES = (Weak, ); }; }; DC1789171D77998700B50D50 /* libauto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789161D77998700B50D50 /* libauto.dylib */; }; DC1789191D77998C00B50D50 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789181D77998C00B50D50 /* libbsm.dylib */; }; - DC17891B1D77999200B50D50 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891A1D77999200B50D50 /* libobjc.dylib */; }; DC17891D1D77999700B50D50 /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891C1D77999700B50D50 /* libpam.dylib */; }; DC17891F1D77999D00B50D50 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891E1D77999D00B50D50 /* libsqlite3.dylib */; }; DC1789211D7799A100B50D50 /* libxar.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789201D7799A100B50D50 /* libxar.dylib */; }; @@ -1669,7 +2062,6 @@ DC178A2D1D77A1E700B50D50 /* tp_policyOids.mdsinfo in Resources */ = {isa = PBXBuildFile; fileRef = DC178A1C1D77A1E700B50D50 /* tp_policyOids.mdsinfo */; }; DC178A2E1D77A1E700B50D50 /* tp_primary.mdsinfo in Resources */ = {isa = PBXBuildFile; fileRef = DC178A1D1D77A1E700B50D50 /* tp_primary.mdsinfo */; }; DC178A2F1D77A1E700B50D50 /* sd_cspdl_common.mdsinfo in Resources */ = {isa = PBXBuildFile; fileRef = DC178A1E1D77A1E700B50D50 /* sd_cspdl_common.mdsinfo */; }; - DC178A411D77A1F500B50D50 /* iToolsTrustedApps.plist in Resources */ = {isa = PBXBuildFile; fileRef = DC178A301D77A1F500B50D50 /* iToolsTrustedApps.plist */; }; 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 */; }; @@ -1679,6 +2071,95 @@ DC178A491D77A1F600B50D50 /* authorization.dfr.prompts-BBBAA77A32-C4EBFEA440.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC178A3B1D77A1F500B50D50 /* authorization.dfr.prompts-BBBAA77A32-C4EBFEA440.strings */; }; DC178A4A1D77A1F600B50D50 /* authorization.buttons.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC178A3D1D77A1F500B50D50 /* authorization.buttons.strings */; }; DC178A4B1D77A1F600B50D50 /* authorization.prompts.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC178A3F1D77A1F500B50D50 /* authorization.prompts.strings */; }; + DC18F76F1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC18F76D1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h */; }; + DC18F7701E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC18F76D1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h */; }; + DC18F7711E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC18F76E1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m */; }; + DC18F7721E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC18F76E1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m */; }; + DC1DA65E1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1DA65C1E4554620094CE7F /* CKKSScanLocalItemsOperation.h */; }; + DC1DA65F1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1DA65C1E4554620094CE7F /* CKKSScanLocalItemsOperation.h */; }; + DC1DA6681E4555D80094CE7F /* CKKSScanLocalItemsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1DA6671E4555D80094CE7F /* CKKSScanLocalItemsOperation.m */; }; + DC1DA6691E4555D80094CE7F /* CKKSScanLocalItemsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1DA6671E4555D80094CE7F /* CKKSScanLocalItemsOperation.m */; }; + DC1ED8C11DD5197E002BDCFA /* CKKSItemEncrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */; }; + DC1ED8C61DD55476002BDCFA /* CKKS.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8C51DD55476002BDCFA /* CKKS.m */; }; + DC222C321E0240D300B09171 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; + DC222C351E02418100B09171 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; }; + DC222C361E02419B00B09171 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 107227350D91FE89003CF14F /* libbsm.dylib */; }; + DC222C3A1E034D1F00B09171 /* CKKSItemEncrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */; }; + DC222C3B1E034D1F00B09171 /* SOSChangeTracker.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D4F1D8085F200865A7C /* SOSChangeTracker.c */; }; + DC222C3D1E034D1F00B09171 /* SOSEngine.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D561D8085F200865A7C /* SOSEngine.c */; }; + DC222C401E034D1F00B09171 /* SecDbItem.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C8E1D8085D800865A7C /* SecDbItem.c */; }; + DC222C411E034D1F00B09171 /* SecDbKeychainItem.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C901D8085D800865A7C /* SecDbKeychainItem.c */; }; + DC222C421E034D1F00B09171 /* SecDbQuery.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C921D8085D800865A7C /* SecDbQuery.c */; }; + DC222C431E034D1F00B09171 /* SecItemBackupServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9C1D8085D800865A7C /* SecItemBackupServer.c */; }; + DC222C441E034D1F00B09171 /* SecItemDataSource.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C941D8085D800865A7C /* SecItemDataSource.c */; }; + DC222C451E034D1F00B09171 /* CKKSIncomingQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B3B1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m */; }; + DC222C461E034D1F00B09171 /* SecItemDb.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C961D8085D800865A7C /* SecItemDb.c */; }; + DC222C471E034D1F00B09171 /* SecItemSchema.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C981D8085D800865A7C /* SecItemSchema.c */; }; + DC222C481E034D1F00B09171 /* SecItemServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9A1D8085D800865A7C /* SecItemServer.c */; }; + DC222C491E034D1F00B09171 /* SecKeybagSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9E1D8085D800865A7C /* SecKeybagSupport.c */; }; + DC222C4A1E034D1F00B09171 /* SecLogSettingsServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.m */; }; + DC222C4D1E034D1F00B09171 /* CKKSOutgoingQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9B7AE41DCBF604004E9385 /* CKKSOutgoingQueueEntry.m */; }; + DC222C4E1E034D1F00B09171 /* CKKS.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8C51DD55476002BDCFA /* CKKS.m */; }; + DC222C501E034D1F00B09171 /* SecOTRRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB41D8085D800865A7C /* SecOTRRemote.m */; }; + DC222C511E034D1F00B09171 /* CKKSItem.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDCCB8E1DF7B8D4006E840E /* CKKSItem.m */; }; + DC222C541E034D1F00B09171 /* CKKSSQLDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = DC797E131DD3F88300CC9E42 /* CKKSSQLDatabaseObject.m */; }; + DC222C571E034D1F00B09171 /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E9A1D8085FC00865A7C /* SecuritydXPC.c */; }; + DC222C5A1E034D1F00B09171 /* iCloudTrace.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB31D8085D800865A7C /* iCloudTrace.c */; }; + DC222C5D1E034D1F00B09171 /* CKKSMirrorEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B2E1DEF9E0E00A3DAFA /* CKKSMirrorEntry.m */; }; + DC222C611E034D1F00B09171 /* swcagent_client.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78EA01D80860C00865A7C /* swcagent_client.c */; }; + DC222C621E034D1F00B09171 /* CKKSZoneStateEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B371DEFADB500A3DAFA /* CKKSZoneStateEntry.m */; }; + DC222C651E034D1F00B09171 /* SOSChangeTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D501D8085F200865A7C /* SOSChangeTracker.h */; }; + DC222C661E034D1F00B09171 /* SOSEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D571D8085F200865A7C /* SOSEngine.h */; }; + DC222C671E034D1F00B09171 /* SecDbKeychainItem.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C911D8085D800865A7C /* SecDbKeychainItem.h */; }; + DC222C681E034D1F00B09171 /* SecDbQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C931D8085D800865A7C /* SecDbQuery.h */; }; + DC222C691E034D1F00B09171 /* CKKSMirrorEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC378B2C1DEF9DF000A3DAFA /* CKKSMirrorEntry.h */; }; + DC222C6A1E034D1F00B09171 /* CKKSZoneStateEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC378B361DEFADB500A3DAFA /* CKKSZoneStateEntry.h */; }; + DC222C6B1E034D1F00B09171 /* SecItemDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C951D8085D800865A7C /* SecItemDataSource.h */; }; + DC222C6C1E034D1F00B09171 /* CKKSIncomingQueueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC378B3A1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.h */; }; + DC222C6D1E034D1F00B09171 /* SecItemDb.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C971D8085D800865A7C /* SecItemDb.h */; }; + DC222C6E1E034D1F00B09171 /* SecItemSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C991D8085D800865A7C /* SecItemSchema.h */; }; + DC222C6F1E034D1F00B09171 /* SecKeybagSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C9F1D8085D800865A7C /* SecKeybagSupport.h */; }; + DC222C701E034D1F00B09171 /* iCloudTrace.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78CB21D8085D800865A7C /* iCloudTrace.h */; }; + DC222C711E034D1F00B09171 /* CKKSOutgoingQueueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC9B7AE61DCBF651004E9385 /* CKKSOutgoingQueueEntry.h */; }; + DC222C731E034D1F00B09171 /* CKKSItem.h in Headers */ = {isa = PBXBuildFile; fileRef = DCDCCB8D1DF7B8D4006E840E /* CKKSItem.h */; }; + DC222C7A1E034EF700B09171 /* libsecurityd_ios_NO_AKS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC222C771E034D1F00B09171 /* libsecurityd_ios_NO_AKS.a */; }; + 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.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC2353311ECA658B00D7C1BE /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + 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 */; }; + DC2C5F4B1F0D935200FEBDA7 /* CKKSControlProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF7A89F1F04502300CABE89 /* CKKSControlProtocol.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 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 */; }; + DC2C5F5E1F0EB97E00FEBDA7 /* CKKSNotifier.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2C5F5A1F0EB97E00FEBDA7 /* CKKSNotifier.h */; }; + DC2C5F601F0EB97E00FEBDA7 /* CKKSNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = DC2C5F5B1F0EB97E00FEBDA7 /* CKKSNotifier.m */; }; + DC2C5F611F0EB97E00FEBDA7 /* 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 */; }; + DC3502B81E0208BE00BC0587 /* CKKSTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3502B71E0208BE00BC0587 /* CKKSTests.m */; }; + DC3502C51E020D5100BC0587 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; + DC3502C81E020D5B00BC0587 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; + DC3502CA1E020DC100BC0587 /* libsqlite3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC27B57D1DDFC24500599261 /* libsqlite3.0.dylib */; }; + DC3502CF1E020E2900BC0587 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; + DC3502D21E02113900BC0587 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; }; + DC3502D31E02115200BC0587 /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3A1D78F228002223DE /* libACM.a */; }; + DC3502D61E02118000BC0587 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; + DC3502DF1E02129F00BC0587 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + DC3502E21E0212D100BC0587 /* libctkclient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient.a */; }; + DC3502E31E0212E600BC0587 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; }; + DC3502E41E02130600BC0587 /* libcoreauthd_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */; }; + DC3502E71E0214C800BC0587 /* MockCloudKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3502E61E0214C800BC0587 /* MockCloudKit.m */; }; + DC3502E91E02172C00BC0587 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC3502E81E02172C00BC0587 /* OCMock.framework */; }; + DC378B2D1DEF9DF000A3DAFA /* CKKSMirrorEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC378B2C1DEF9DF000A3DAFA /* CKKSMirrorEntry.h */; }; + DC378B2F1DEF9E0E00A3DAFA /* CKKSMirrorEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B2E1DEF9E0E00A3DAFA /* CKKSMirrorEntry.m */; }; + DC378B381DEFADB500A3DAFA /* CKKSZoneStateEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC378B361DEFADB500A3DAFA /* CKKSZoneStateEntry.h */; }; + DC378B391DEFADB500A3DAFA /* CKKSZoneStateEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B371DEFADB500A3DAFA /* CKKSZoneStateEntry.m */; }; + DC378B3C1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC378B3A1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.h */; }; + DC378B3D1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B3B1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m */; }; + DC3832DA1DB7050900385F63 /* module.modulemap in Headers */ = {isa = PBXBuildFile; fileRef = DC3832C01DB6E69800385F63 /* module.modulemap */; settings = {ATTRIBUTES = (Public, ); }; }; DC3A4B4B1D91E30400E46D4A /* sec_xdr.h in Headers */ = {isa = PBXBuildFile; fileRef = DC6A825A1D87732E00418608 /* sec_xdr.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC3A4B531D91E8EB00E46D4A /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD06AB01D8E0D53007602F1 /* libsecurity_utilities.a */; }; DC3A4B641D91EADC00E46D4A /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC3A4B621D91EAC500E46D4A /* main.cpp */; }; @@ -1686,6 +2167,11 @@ DC3A4B661D91EB0E00E46D4A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; DC3A4B671D91EB1200E46D4A /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789241D7799CD00B50D50 /* CoreFoundation.framework */; }; DC3A4B691D91EB1F00E46D4A /* com.apple.CodeSigningHelper.sb in CopyFiles */ = {isa = PBXBuildFile; fileRef = DC3A4B601D91EAC500E46D4A /* com.apple.CodeSigningHelper.sb */; }; + DC3A81D31D99D561000C7419 /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; + DC3A81D51D99D568000C7419 /* libcoretls_cfhelpers.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC3A81D41D99D567000C7419 /* libcoretls_cfhelpers.dylib */; }; + DC3A81D61D99D57F000C7419 /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; + DC3A81D71D99D58A000C7419 /* libcoretls_cfhelpers.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC3A81D41D99D567000C7419 /* libcoretls_cfhelpers.dylib */; }; + DC3A81EC1D99F568000C7419 /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; DC3C72E21D8374D600F6A832 /* SecureTransportPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1786FD1D778F5000B50D50 /* SecureTransportPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC3C72E31D8376D700F6A832 /* SOSTypes.h in Copy SecurityObjectSync Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8F1D8085F200865A7C /* SOSTypes.h */; }; DC3C72E41D8376DE00F6A832 /* SOSBackupSliceKeyBag.h in Copy SecurityObjectSync Headers */ = {isa = PBXBuildFile; fileRef = DCC78D2A1D8085F200865A7C /* SOSBackupSliceKeyBag.h */; }; @@ -1700,20 +2186,12 @@ DC3C72ED1D83778100F6A832 /* SOSViews.h in Copy SecureObjectSync Headers */ = {isa = PBXBuildFile; fileRef = DCC78D4B1D8085F200865A7C /* SOSViews.h */; }; DC3C72EE1D83778600F6A832 /* SOSTypes.h in Copy SecureObjectSync Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8F1D8085F200865A7C /* SOSTypes.h */; }; DC3C72EF1D83778B00F6A832 /* SOSCloudCircleInternal.h in Copy SecureObjectSync Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8B1D8085F200865A7C /* SOSCloudCircleInternal.h */; }; - DC3C72F01D83779A00F6A832 /* SOSTypes.h in Old SOS header location */ = {isa = PBXBuildFile; fileRef = DCC78D8F1D8085F200865A7C /* SOSTypes.h */; }; - DC3C72F11D8377A300F6A832 /* SOSPeerInfo.h in Old SOS header location */ = {isa = PBXBuildFile; fileRef = DCC78D641D8085F200865A7C /* SOSPeerInfo.h */; }; - DC3C72F21D8377BE00F6A832 /* SOSTypes.h in Old SOS header location */ = {isa = PBXBuildFile; fileRef = DCC78D8F1D8085F200865A7C /* SOSTypes.h */; }; - DC3C72F31D8377C400F6A832 /* SOSPeerInfo.h in Old SOS header location */ = {isa = PBXBuildFile; fileRef = DCC78D641D8085F200865A7C /* SOSPeerInfo.h */; }; - DC3C73531D837AF800F6A832 /* SOSPeerInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D641D8085F200865A7C /* SOSPeerInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; - DC3C73541D837B1900F6A832 /* SOSCloudCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8A1D8085F200865A7C /* SOSCloudCircle.h */; settings = {ATTRIBUTES = (Private, ); }; }; + DC3C73531D837AF800F6A832 /* SOSPeerInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D641D8085F200865A7C /* SOSPeerInfo.h */; }; + DC3C73541D837B1900F6A832 /* SOSCloudCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8A1D8085F200865A7C /* SOSCloudCircle.h */; }; DC3C73551D837B2C00F6A832 /* SOSPeerInfoPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D691D8085F200865A7C /* SOSPeerInfoPriv.h */; }; DC3C73561D837B9B00F6A832 /* SOSPeerInfoPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D691D8085F200865A7C /* SOSPeerInfoPriv.h */; }; - DC3C73571D837BCE00F6A832 /* SOSCloudCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8A1D8085F200865A7C /* SOSCloudCircle.h */; }; DC3C73581D837BDC00F6A832 /* SOSCloudCircleInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8B1D8085F200865A7C /* SOSCloudCircleInternal.h */; }; - DC3C73591D837BEC00F6A832 /* SOSPeerInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D641D8085F200865A7C /* SOSPeerInfo.h */; }; DC3C735A1D837C0000F6A832 /* SOSPeerInfoPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D691D8085F200865A7C /* SOSPeerInfoPriv.h */; }; - DC3C735B1D837C0F00F6A832 /* SOSTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8F1D8085F200865A7C /* SOSTypes.h */; }; - DC3C789B1D83854700F6A832 /* SOSCloudKeychainConstants.c in Sources */ = {isa = PBXBuildFile; fileRef = E7A5F4D71C0D01B000F3BEBB /* SOSCloudKeychainConstants.c */; }; DC3C7AB21D838B6D00F6A832 /* SecureTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785A41D778D0D00B50D50 /* SecureTransport.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC3C7AB31D838BC300F6A832 /* CipherSuite.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785A31D778D0D00B50D50 /* CipherSuite.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC3C7AB41D838BEB00F6A832 /* SecAsn1Coder.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785131D77895A00B50D50 /* SecAsn1Coder.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1724,38 +2202,45 @@ DC3C7AB91D838C8D00F6A832 /* oids.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785421D778A7400B50D50 /* oids.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC3C7ABA1D838C9F00F6A832 /* sslTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1786FB1D778F3C00B50D50 /* sslTypes.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC3C7C901D83957F00F6A832 /* NSFileHandle+Formatting.m in Sources */ = {isa = PBXBuildFile; fileRef = E78A9AD91D34959200006B5B /* NSFileHandle+Formatting.m */; }; - DC52E7C31D80BCA600B0A59C /* personalization.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C881D8085D800865A7C /* personalization.c */; }; + 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 */; }; + DC4268FF1E82038C002B7110 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; + DC4269001E82038D002B7110 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; + DC4269011E82038D002B7110 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; + DC4269041E82EDAC002B7110 /* SecItem.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269031E82EDAC002B7110 /* SecItem.m */; }; + DC4269051E82EDC4002B7110 /* SecItem.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269031E82EDAC002B7110 /* SecItem.m */; }; + DC4269081E82FD8B002B7110 /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC4269091E82FD8C002B7110 /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC42690C1E82FD9A002B7110 /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC42690D1E82FD9B002B7110 /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC42690F1E82FD9C002B7110 /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC4269101E82FD9F002B7110 /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC4269111E82FDA0002B7110 /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC4269121E82FDA1002B7110 /* server_security_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.c */; }; + DC4DB1501E24692100CD6769 /* CKKSKey.h in Headers */ = {isa = PBXBuildFile; fileRef = DC4DB14E1E24692100CD6769 /* CKKSKey.h */; }; + DC4DB1511E24692100CD6769 /* CKKSKey.h in Headers */ = {isa = PBXBuildFile; fileRef = DC4DB14E1E24692100CD6769 /* CKKSKey.h */; }; + DC4DB1521E24692100CD6769 /* CKKSKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4DB14F1E24692100CD6769 /* CKKSKey.m */; }; + DC4DB1531E24692100CD6769 /* CKKSKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4DB14F1E24692100CD6769 /* CKKSKey.m */; }; + DC4DB15F1E2590B100CD6769 /* CKKSEncryptionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4DB15E1E2590B100CD6769 /* CKKSEncryptionTests.m */; }; + DC4DB1691E26E99E00CD6769 /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + DC4DB16A1E26E9F900CD6769 /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + DC4EA5961E70A237008840B4 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; DC52E7C41D80BCAD00B0A59C /* SecDbItem.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C8E1D8085D800865A7C /* SecDbItem.c */; }; DC52E7C51D80BCB300B0A59C /* swcagent_client.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78EA01D80860C00865A7C /* swcagent_client.c */; }; - DC52E7C61D80BCBA00B0A59C /* SOSCloudCircleServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CAA1D8085D800865A7C /* SOSCloudCircleServer.c */; }; - DC52E7C71D80BCBE00B0A59C /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; - DC52E7C81D80BCC600B0A59C /* SecTrustStoreServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CAC1D8085D800865A7C /* SecTrustStoreServer.c */; }; - DC52E7C91D80BCCB00B0A59C /* nameconstraints.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C861D8085D800865A7C /* nameconstraints.c */; }; - DC52E7CA1D80BCD300B0A59C /* SecTrustServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CA81D8085D800865A7C /* SecTrustServer.c */; }; DC52E7CB1D80BCD800B0A59C /* SecItemBackupServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9C1D8085D800865A7C /* SecItemBackupServer.c */; }; DC52E7CC1D80BCDF00B0A59C /* SecDbQuery.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C921D8085D800865A7C /* SecDbQuery.c */; }; DC52E7CD1D80BCE700B0A59C /* SecItemDataSource.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C941D8085D800865A7C /* SecItemDataSource.c */; }; - DC52E7CE1D80BCF800B0A59C /* SecKeybagSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9E1D8085D800865A7C /* SecKeybagSupport.c */; }; DC52E7CF1D80BCFD00B0A59C /* SOSEngine.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D561D8085F200865A7C /* SOSEngine.c */; }; - DC52E7D01D80BD0200B0A59C /* SecPolicyServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CA61D8085D800865A7C /* SecPolicyServer.c */; }; - DC52E7D11D80BD0C00B0A59C /* SecOCSPResponse.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CA41D8085D800865A7C /* SecOCSPResponse.c */; }; - DC52E7D21D80BD1200B0A59C /* SecOCSPRequest.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CA21D8085D800865A7C /* SecOCSPRequest.c */; }; DC52E7D31D80BD1800B0A59C /* SecDbKeychainItem.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C901D8085D800865A7C /* SecDbKeychainItem.c */; }; DC52E7D41D80BD1D00B0A59C /* iCloudTrace.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB31D8085D800865A7C /* iCloudTrace.c */; }; - DC52E7D51D80BD2300B0A59C /* SecOCSPCache.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CA01D8085D800865A7C /* SecOCSPCache.c */; }; DC52E7D61D80BD2800B0A59C /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E9A1D8085FC00865A7C /* SecuritydXPC.c */; }; DC52E7D71D80BD2D00B0A59C /* SecItemServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9A1D8085D800865A7C /* SecItemServer.c */; }; - DC52E7D81D80BD3800B0A59C /* SecCAIssuerRequest.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C8C1D8085D800865A7C /* SecCAIssuerRequest.c */; }; - DC52E7D91D80BD3C00B0A59C /* SecCAIssuerCache.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C8A1D8085D800865A7C /* SecCAIssuerCache.c */; }; - DC52E7DA1D80BD4400B0A59C /* policytree.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C841D8085D800865A7C /* policytree.c */; }; - DC52E7DB1D80BD4A00B0A59C /* asynchttp.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C7F1D8085D800865A7C /* asynchttp.c */; }; - DC52E7DC1D80BD4F00B0A59C /* SecOTRRemote.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB41D8085D800865A7C /* SecOTRRemote.c */; }; - DC52E7DD1D80BD5500B0A59C /* OTATrustUtilities.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C821D8085D800865A7C /* OTATrustUtilities.c */; }; + DC52E7DC1D80BD4F00B0A59C /* SecOTRRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB41D8085D800865A7C /* SecOTRRemote.m */; }; DC52E7DE1D80BD7F00B0A59C /* SecItemDb.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C961D8085D800865A7C /* SecItemDb.c */; }; DC52E7DF1D80BD8700B0A59C /* SOSChangeTracker.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D4F1D8085F200865A7C /* SOSChangeTracker.c */; }; DC52E7E01D80BD8D00B0A59C /* SecItemSchema.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C981D8085D800865A7C /* SecItemSchema.c */; }; - DC52E7E11D80BD9300B0A59C /* SecLogSettingsServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.c */; }; - DC52E7E21D80BDA000B0A59C /* personalization.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C891D8085D800865A7C /* personalization.h */; }; + DC52E7E11D80BD9300B0A59C /* SecLogSettingsServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.m */; }; DC52E7E31D80BDA600B0A59C /* SecDbQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C931D8085D800865A7C /* SecDbQuery.h */; }; DC52E7E41D80BE6E00B0A59C /* SecDbKeychainItem.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C911D8085D800865A7C /* SecDbKeychainItem.h */; }; DC52E7E51D80BE7400B0A59C /* SOSEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D571D8085F200865A7C /* SOSEngine.h */; }; @@ -1765,121 +2250,52 @@ DC52E7E91D80BE8D00B0A59C /* SecKeybagSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C9F1D8085D800865A7C /* SecKeybagSupport.h */; }; DC52E7EA1D80BE9500B0A59C /* SecItemSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C991D8085D800865A7C /* SecItemSchema.h */; }; DC52E7EB1D80BE9B00B0A59C /* iCloudTrace.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78CB21D8085D800865A7C /* iCloudTrace.h */; }; - DC52E8BB1D80C21700B0A59C /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; }; - DC52E8C71D80C2FD00B0A59C /* SOSKVSKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D721D8085F200865A7C /* SOSKVSKeys.c */; }; - DC52E8C81D80C2FD00B0A59C /* SOSTransport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D741D8085F200865A7C /* SOSTransport.c */; }; - DC52E8C91D80C2FD00B0A59C /* SOSTransportBackupPeer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D761D8085F200865A7C /* SOSTransportBackupPeer.c */; }; - DC52E8CA1D80C2FD00B0A59C /* SOSTransportCircle.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D781D8085F200865A7C /* SOSTransportCircle.c */; }; - DC52E8CB1D80C2FD00B0A59C /* SOSTransportCircleKVS.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D7A1D8085F200865A7C /* SOSTransportCircleKVS.c */; }; - DC52E8CC1D80C2FD00B0A59C /* SOSTransportKeyParameter.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D7C1D8085F200865A7C /* SOSTransportKeyParameter.c */; }; - DC52E8CD1D80C2FD00B0A59C /* SOSTransportKeyParameterKVS.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D7E1D8085F200865A7C /* SOSTransportKeyParameterKVS.c */; }; - DC52E8CE1D80C2FD00B0A59C /* SOSTransportMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D801D8085F200865A7C /* SOSTransportMessage.c */; }; - DC52E8CF1D80C2FD00B0A59C /* SOSTransportMessageIDS.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D821D8085F200865A7C /* SOSTransportMessageIDS.c */; }; - DC52E8D01D80C2FD00B0A59C /* SOSTransportMessageKVS.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D841D8085F200865A7C /* SOSTransportMessageKVS.c */; }; - DC52E8D11D80C30500B0A59C /* SOSECWrapUnwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D881D8085F200865A7C /* SOSECWrapUnwrap.c */; }; - DC52E8D31D80C30500B0A59C /* SOSSysdiagnose.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D8C1D8085F200865A7C /* SOSSysdiagnose.c */; }; - DC52E8D41D80C30500B0A59C /* SOSInternal.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D8D1D8085F200865A7C /* SOSInternal.c */; }; - DC52E8D51D80C31500B0A59C /* SOSFullPeerInfo.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D611D8085F200865A7C /* SOSFullPeerInfo.c */; }; - DC52E8D61D80C31500B0A59C /* SOSPeerInfo.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D631D8085F200865A7C /* SOSPeerInfo.c */; }; - DC52E8D71D80C31500B0A59C /* SOSPeerInfoDER.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D651D8085F200865A7C /* SOSPeerInfoDER.c */; }; - DC52E8D81D80C31500B0A59C /* SOSPeerInfoV2.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D671D8085F200865A7C /* SOSPeerInfoV2.c */; }; - DC52E8D91D80C31500B0A59C /* SOSPeerInfoCollections.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D6A1D8085F200865A7C /* SOSPeerInfoCollections.c */; }; - DC52E8DA1D80C31500B0A59C /* SOSPeerInfoRingState.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D6D1D8085F200865A7C /* SOSPeerInfoRingState.c */; }; - DC52E8DB1D80C31500B0A59C /* SOSPeerInfoSecurityProperties.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D6F1D8085F200865A7C /* SOSPeerInfoSecurityProperties.c */; }; + DC52E8C91D80C2FD00B0A59C /* SOSTransportBackupPeer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D761D8085F200865A7C /* SOSTransportBackupPeer.m */; }; + DC52E8CA1D80C2FD00B0A59C /* SOSTransportCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D781D8085F200865A7C /* SOSTransportCircle.m */; }; + DC52E8CB1D80C2FD00B0A59C /* SOSTransportCircleKVS.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D7A1D8085F200865A7C /* SOSTransportCircleKVS.m */; }; + DC52E8CC1D80C2FD00B0A59C /* SOSTransportKeyParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D7C1D8085F200865A7C /* SOSTransportKeyParameter.m */; }; + DC52E8CE1D80C2FD00B0A59C /* SOSTransportMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D801D8085F200865A7C /* SOSTransportMessage.m */; }; + DC52E8CF1D80C2FD00B0A59C /* SOSTransportMessageIDS.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D821D8085F200865A7C /* SOSTransportMessageIDS.m */; }; + DC52E8D01D80C2FD00B0A59C /* SOSTransportMessageKVS.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D841D8085F200865A7C /* SOSTransportMessageKVS.m */; }; DC52E8DD1D80C31F00B0A59C /* SOSCoder.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D511D8085F200865A7C /* SOSCoder.c */; }; DC52E8DE1D80C31F00B0A59C /* SOSDigestVector.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D541D8085F200865A7C /* SOSDigestVector.c */; }; DC52E8E01D80C31F00B0A59C /* SOSManifest.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D581D8085F200865A7C /* SOSManifest.c */; }; DC52E8E11D80C31F00B0A59C /* SOSMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D5A1D8085F200865A7C /* SOSMessage.c */; }; - DC52E8E21D80C31F00B0A59C /* SOSPeer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D5C1D8085F200865A7C /* SOSPeer.c */; }; - DC52E8E31D80C31F00B0A59C /* SOSPeerCoder.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D5E1D8085F200865A7C /* SOSPeerCoder.c */; }; - DC52E8E41D80C33000B0A59C /* SOSCircle.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D2E1D8085F200865A7C /* SOSCircle.c */; }; - DC52E8E51D80C33000B0A59C /* SOSCircleV2.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D2F1D8085F200865A7C /* SOSCircleV2.c */; }; - DC52E8E61D80C33000B0A59C /* SOSCircleDer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D351D8085F200865A7C /* SOSCircleDer.c */; }; - DC52E8E71D80C33000B0A59C /* SOSGenCount.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D371D8085F200865A7C /* SOSGenCount.c */; }; - DC52E8E81D80C33000B0A59C /* SOSRingBackup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D3A1D8085F200865A7C /* SOSRingBackup.c */; }; - DC52E8E91D80C33000B0A59C /* SOSRingBasic.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D3C1D8085F200865A7C /* SOSRingBasic.c */; }; - DC52E8EA1D80C33000B0A59C /* SOSRingConcordanceTrust.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D3E1D8085F200865A7C /* SOSRingConcordanceTrust.c */; }; - DC52E8EB1D80C33000B0A59C /* SOSRingDER.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D401D8085F200865A7C /* SOSRingDER.c */; }; - DC52E8EC1D80C33000B0A59C /* SOSRingPeerInfoUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D421D8085F200865A7C /* SOSRingPeerInfoUtils.c */; }; - DC52E8ED1D80C33000B0A59C /* SOSRingTypes.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D441D8085F200865A7C /* SOSRingTypes.c */; }; - DC52E8EE1D80C33000B0A59C /* SOSRingUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D461D8085F200865A7C /* SOSRingUtils.c */; }; - DC52E8EF1D80C33000B0A59C /* SOSRingV0.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D481D8085F200865A7C /* SOSRingV0.c */; }; - DC52E8F01D80C33000B0A59C /* SOSViews.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D4A1D8085F200865A7C /* SOSViews.c */; }; - DC52E8F11D80C34000B0A59C /* SOSAccount.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D121D8085F200865A7C /* SOSAccount.c */; }; - DC52E8F21D80C34000B0A59C /* SOSAccountTransaction.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D141D8085F200865A7C /* SOSAccountTransaction.c */; }; - DC52E8F31D80C34000B0A59C /* SOSAccountBackup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D161D8085F200865A7C /* SOSAccountBackup.c */; }; - DC52E8F41D80C34000B0A59C /* SOSAccountCircles.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D171D8085F200865A7C /* SOSAccountCircles.c */; }; - DC52E8F51D80C34000B0A59C /* SOSAccountHSAJoin.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D181D8085F200865A7C /* SOSAccountHSAJoin.c */; }; - DC52E8F61D80C34000B0A59C /* SOSAccountCloudParameters.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1A1D8085F200865A7C /* SOSAccountCloudParameters.c */; }; - DC52E8F71D80C34000B0A59C /* SOSAccountCredentials.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1B1D8085F200865A7C /* SOSAccountCredentials.c */; }; - DC52E8F81D80C34000B0A59C /* SOSAccountDer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1C1D8085F200865A7C /* SOSAccountDer.c */; }; - DC52E8F91D80C34000B0A59C /* SOSAccountFullPeerInfo.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1D1D8085F200865A7C /* SOSAccountFullPeerInfo.c */; }; - DC52E8FA1D80C34000B0A59C /* SOSAccountPeers.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1E1D8085F200865A7C /* SOSAccountPeers.c */; }; - DC52E8FB1D80C34000B0A59C /* SOSAccountPersistence.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1F1D8085F200865A7C /* SOSAccountPersistence.c */; }; - DC52E8FC1D80C34000B0A59C /* SOSAccountLog.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D201D8085F200865A7C /* SOSAccountLog.c */; }; - DC52E8FD1D80C34000B0A59C /* SOSAccountUpdate.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D231D8085F200865A7C /* SOSAccountUpdate.c */; }; - DC52E8FE1D80C34000B0A59C /* SOSAccountRings.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D241D8085F200865A7C /* SOSAccountRings.c */; }; - DC52E8FF1D80C34000B0A59C /* SOSAccountRingUpdate.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D251D8085F200865A7C /* SOSAccountRingUpdate.c */; }; - DC52E9001D80C34000B0A59C /* SOSAccountViewSync.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D261D8085F200865A7C /* SOSAccountViewSync.c */; }; + DC52E8E21D80C31F00B0A59C /* SOSPeer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D5C1D8085F200865A7C /* SOSPeer.m */; }; + DC52E8E31D80C31F00B0A59C /* SOSPeerCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D5E1D8085F200865A7C /* SOSPeerCoder.m */; }; + DC52E8F11D80C34000B0A59C /* SOSAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D121D8085F200865A7C /* SOSAccount.m */; }; + DC52E8F21D80C34000B0A59C /* SOSAccountTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D141D8085F200865A7C /* SOSAccountTransaction.m */; }; + DC52E8F31D80C34000B0A59C /* SOSAccountBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D161D8085F200865A7C /* SOSAccountBackup.m */; }; + DC52E8F41D80C34000B0A59C /* SOSAccountCircles.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D171D8085F200865A7C /* SOSAccountCircles.m */; }; + DC52E8F71D80C34000B0A59C /* SOSAccountCredentials.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1B1D8085F200865A7C /* SOSAccountCredentials.m */; }; + DC52E8F91D80C34000B0A59C /* SOSAccountFullPeerInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1D1D8085F200865A7C /* SOSAccountFullPeerInfo.m */; }; + DC52E8FA1D80C34000B0A59C /* SOSAccountPeers.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1E1D8085F200865A7C /* SOSAccountPeers.m */; }; + DC52E8FB1D80C34000B0A59C /* SOSAccountPersistence.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1F1D8085F200865A7C /* SOSAccountPersistence.m */; }; + DC52E8FC1D80C34000B0A59C /* SOSAccountLog.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D201D8085F200865A7C /* SOSAccountLog.m */; }; + DC52E8FD1D80C34000B0A59C /* SOSAccountUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D231D8085F200865A7C /* SOSAccountUpdate.m */; }; + DC52E8FE1D80C34000B0A59C /* SOSAccountRings.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D241D8085F200865A7C /* SOSAccountRings.m */; }; + DC52E8FF1D80C34000B0A59C /* SOSAccountRingUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D251D8085F200865A7C /* SOSAccountRingUpdate.m */; }; + DC52E9001D80C34000B0A59C /* SOSAccountViewSync.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D261D8085F200865A7C /* SOSAccountViewSync.m */; }; DC52E9011D80C34000B0A59C /* SOSBackupEvent.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D271D8085F200865A7C /* SOSBackupEvent.c */; }; - DC52E9021D80C34000B0A59C /* SOSBackupSliceKeyBag.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D291D8085F200865A7C /* SOSBackupSliceKeyBag.c */; }; - DC52E9031D80C34000B0A59C /* SOSUserKeygen.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D2B1D8085F200865A7C /* SOSUserKeygen.c */; }; - DC52E9051D80C36A00B0A59C /* secViewDisplay.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9E1D8085F200865A7C /* secViewDisplay.c */; }; DC52E9061D80C3AD00B0A59C /* SOSDigestVector.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D551D8085F200865A7C /* SOSDigestVector.h */; }; DC52E9071D80C3B300B0A59C /* SOSARCDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D871D8085F200865A7C /* SOSARCDefines.h */; }; - DC52E9091D80C3C600B0A59C /* SOSFullPeerInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D621D8085F200865A7C /* SOSFullPeerInfo.h */; }; DC52E90A1D80C3CC00B0A59C /* SOSAccountTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D151D8085F200865A7C /* SOSAccountTransaction.h */; }; DC52E90B1D80C3D400B0A59C /* SOSMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D5B1D8085F200865A7C /* SOSMessage.h */; }; DC52E90C1D80C3D900B0A59C /* SOSBackupEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D281D8085F200865A7C /* SOSBackupEvent.h */; }; - DC52E90D1D80C3DF00B0A59C /* SOSPeerInfoV2.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D681D8085F200865A7C /* SOSPeerInfoV2.h */; }; - DC52E90E1D80C3E400B0A59C /* SOSGenCount.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D381D8085F200865A7C /* SOSGenCount.h */; }; - DC52E90F1D80C3EA00B0A59C /* SOSCircleRings.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D331D8085F200865A7C /* SOSCircleRings.h */; }; DC52E9101D80C3EF00B0A59C /* SOSAccountLog.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D211D8085F200865A7C /* SOSAccountLog.h */; }; - DC52E9111D80C3F800B0A59C /* SOSAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D131D8085F200865A7C /* SOSAccount.h */; }; - DC52E9121D80C3FE00B0A59C /* SOSRingUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D471D8085F200865A7C /* SOSRingUtils.h */; }; - DC52E9131D80C40300B0A59C /* SOSBackupSliceKeyBag.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D2A1D8085F200865A7C /* SOSBackupSliceKeyBag.h */; }; - DC52E9141D80C40B00B0A59C /* SOSCloudKeychainClient.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78CF71D8085F200865A7C /* SOSCloudKeychainClient.h */; }; - DC52E9151D80C41200B0A59C /* SOSCloudKeychainConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78CF91D8085F200865A7C /* SOSCloudKeychainConstants.h */; }; DC52E9161D80C41A00B0A59C /* SOSPeerInfoInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D6C1D8085F200865A7C /* SOSPeerInfoInternal.h */; }; - DC52E9171D80C41F00B0A59C /* SOSPeerInfoRingState.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D6E1D8085F200865A7C /* SOSPeerInfoRingState.h */; }; - DC52E9181D80C42600B0A59C /* SOSAccountHSAJoin.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D191D8085F200865A7C /* SOSAccountHSAJoin.h */; }; DC52E9191D80C42F00B0A59C /* SOSTransportMessageIDS.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D831D8085F200865A7C /* SOSTransportMessageIDS.h */; }; DC52E91A1D80C43500B0A59C /* SOSRing.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D391D8085F200865A7C /* SOSRing.h */; }; - DC52E91B1D80C43A00B0A59C /* SOSViews.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D4B1D8085F200865A7C /* SOSViews.h */; }; DC52E91C1D80C43F00B0A59C /* SOSPeerCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D5F1D8085F200865A7C /* SOSPeerCoder.h */; }; DC52E91D1D80C44400B0A59C /* SOSCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D521D8085F200865A7C /* SOSCoder.h */; }; - DC52E91E1D80C44A00B0A59C /* SOSCircleDer.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D341D8085F200865A7C /* SOSCircleDer.h */; }; - DC52E91F1D80C45100B0A59C /* SOSAccountPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D221D8085F200865A7C /* SOSAccountPriv.h */; }; - DC52E9201D80C45800B0A59C /* SOSPeerInfoSecurityProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D701D8085F200865A7C /* SOSPeerInfoSecurityProperties.h */; }; - DC52E9221D80C46800B0A59C /* SOSRingBackup.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D3B1D8085F200865A7C /* SOSRingBackup.h */; }; DC52E9231D80C47100B0A59C /* SOSTransportCircleKVS.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D7B1D8085F200865A7C /* SOSTransportCircleKVS.h */; }; DC52E9241D80C47900B0A59C /* SOSTransportMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D811D8085F200865A7C /* SOSTransportMessage.h */; }; - DC52E9251D80C48000B0A59C /* SOSPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D901D8085F200865A7C /* SOSPlatform.h */; }; - DC52E9261D80C48700B0A59C /* SOSUserKeygen.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D2C1D8085F200865A7C /* SOSUserKeygen.h */; }; - DC52E9271D80C48D00B0A59C /* SOSCircleV2.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D301D8085F200865A7C /* SOSCircleV2.h */; }; DC52E9281D80C49300B0A59C /* SOSManifest.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D591D8085F200865A7C /* SOSManifest.h */; }; - DC52E9291D80C49A00B0A59C /* SOSRingTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D451D8085F200865A7C /* SOSRingTypes.h */; }; - DC52E92A1D80C4A200B0A59C /* SOSTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D751D8085F200865A7C /* SOSTransport.h */; }; DC52E92B1D80C4A800B0A59C /* SOSConcordanceTrust.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D361D8085F200865A7C /* SOSConcordanceTrust.h */; }; DC52E92C1D80C4AF00B0A59C /* SOSTransportKeyParameter.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D7D1D8085F200865A7C /* SOSTransportKeyParameter.h */; }; - DC52E92D1D80C4BC00B0A59C /* SOSPeerInfoCollections.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D6B1D8085F200865A7C /* SOSPeerInfoCollections.h */; }; - DC52E92E1D80C4C300B0A59C /* SOSPeerInfoDER.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D661D8085F200865A7C /* SOSPeerInfoDER.h */; }; - DC52E92F1D80C4C900B0A59C /* SOSRingV0.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D491D8085F200865A7C /* SOSRingV0.h */; }; - DC52E9301D80C4D000B0A59C /* SOSRingPeerInfoUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D431D8085F200865A7C /* SOSRingPeerInfoUtils.h */; }; DC52E9321D80C4DF00B0A59C /* SOSTransportMessageKVS.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D851D8085F200865A7C /* SOSTransportMessageKVS.h */; }; DC52E9331D80C4E500B0A59C /* SOSDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D531D8085F200865A7C /* SOSDataSource.h */; }; - DC52E9341D80C4EC00B0A59C /* SOSInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8E1D8085F200865A7C /* SOSInternal.h */; }; - DC52E9351D80C4F300B0A59C /* SOSKVSKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D731D8085F200865A7C /* SOSKVSKeys.h */; }; - DC52E9361D80C4FD00B0A59C /* SOSRingConcordanceTrust.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D3F1D8085F200865A7C /* SOSRingConcordanceTrust.h */; }; - DC52E9371D80C50300B0A59C /* SOSRingBasic.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D3D1D8085F200865A7C /* SOSRingBasic.h */; }; DC52E9381D80C50800B0A59C /* SOSPeer.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D5D1D8085F200865A7C /* SOSPeer.h */; }; - DC52E9391D80C50E00B0A59C /* SOSCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D321D8085F200865A7C /* SOSCircle.h */; }; - DC52E93D1D80C53C00B0A59C /* SOSTransportCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D791D8085F200865A7C /* SOSTransportCircle.h */; }; - DC52E93E1D80C54300B0A59C /* SOSCirclePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D311D8085F200865A7C /* SOSCirclePriv.h */; }; - DC52E9401D80C55200B0A59C /* SOSRingDER.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D411D8085F200865A7C /* SOSRingDER.h */; }; - DC52E9431D80C5AA00B0A59C /* SOSTransportKeyParameterKVS.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D7F1D8085F200865A7C /* SOSTransportKeyParameterKVS.h */; }; - DC52E9E21D80C62D00B0A59C /* secToolFileIO.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D931D8085F200865A7C /* secToolFileIO.c */; }; - DC52E9E31D80CAFE00B0A59C /* SOSCloudKeychainClient.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CF61D8085F200865A7C /* SOSCloudKeychainClient.c */; }; DC52EA9C1D80CC8300B0A59C /* print_cert.c in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA951D80CC2A00B0A59C /* print_cert.c */; }; DC52EA9D1D80CC9700B0A59C /* syncbubble.m in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA921D80CC2A00B0A59C /* syncbubble.m */; }; DC52EA9E1D80CC9B00B0A59C /* leaks.c in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA931D80CC2A00B0A59C /* leaks.c */; }; @@ -1897,37 +2313,35 @@ DC52EC161D80CF3B00B0A59C /* scep.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E231D8085FC00865A7C /* scep.c */; }; DC52EC171D80CF4200B0A59C /* pkcs12_util.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E221D8085FC00865A7C /* pkcs12_util.c */; }; DC52EC181D80CF4700B0A59C /* log_control.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1D1D8085FC00865A7C /* log_control.c */; }; - DC52EC191D80CF4C00B0A59C /* keychain_find.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E201D8085FC00865A7C /* keychain_find.c */; }; + DC52EC191D80CF4C00B0A59C /* keychain_find.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E201D8085FC00865A7C /* keychain_find.m */; }; DC52EC1A1D80CF5100B0A59C /* keychain_add.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1F1D8085FC00865A7C /* keychain_add.c */; }; DC52EC1B1D80CF5600B0A59C /* codesign.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1E1D8085FC00865A7C /* codesign.c */; }; DC52EC1C1D80CF5D00B0A59C /* add_internet_password.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1C1D8085FC00865A7C /* add_internet_password.c */; }; DC52EC1D1D80CF6200B0A59C /* keychain_util.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1A1D8085FC00865A7C /* keychain_util.c */; }; DC52EC1E1D80CF6700B0A59C /* verify_cert.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E191D8085FC00865A7C /* verify_cert.c */; }; DC52EC2F1D80CFB200B0A59C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; - DC52EC361D80CFD000B0A59C /* keychain_sync.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D971D8085F200865A7C /* keychain_sync.c */; }; + DC52EC361D80CFD000B0A59C /* keychain_sync.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D971D8085F200865A7C /* keychain_sync.m */; }; DC52EC371D80CFD400B0A59C /* keychain_sync_test.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D991D8085F200865A7C /* keychain_sync_test.m */; }; DC52EC381D80CFDB00B0A59C /* secToolFileIO.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D931D8085F200865A7C /* secToolFileIO.c */; }; DC52EC391D80CFDF00B0A59C /* secViewDisplay.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9E1D8085F200865A7C /* secViewDisplay.c */; }; - DC52EC3A1D80CFE400B0A59C /* keychain_log.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9B1D8085F200865A7C /* keychain_log.c */; }; - DC52EC3B1D80CFE900B0A59C /* syncbackup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9D1D8085F200865A7C /* syncbackup.c */; }; + DC52EC3A1D80CFE400B0A59C /* keychain_log.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9B1D8085F200865A7C /* keychain_log.m */; }; + DC52EC3B1D80CFE900B0A59C /* syncbackup.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9D1D8085F200865A7C /* syncbackup.m */; }; DC52EC4E1D80D01F00B0A59C /* swcagent_client.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78EA01D80860C00865A7C /* swcagent_client.c */; }; DC52EC4F1D80D02400B0A59C /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E9A1D8085FC00865A7C /* SecuritydXPC.c */; }; DC52EC5D1D80D06300B0A59C /* SecLogging.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E651D8085FC00865A7C /* SecLogging.c */; }; - DC52EC691D80D0DD00B0A59C /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; DC52EC6B1D80D0E300B0A59C /* IDSFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC6A1D80D0E300B0A59C /* IDSFoundation.framework */; }; DC52EC6C1D80D0E800B0A59C /* IDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD744683195A00BB00FB01C0 /* IDS.framework */; }; DC52EC6D1D80D0F100B0A59C /* sc-31-peerinfo-simplefuzz.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D001D8085F200865A7C /* sc-31-peerinfo-simplefuzz.c */; }; DC52EC6E1D80D0F700B0A59C /* SOSTestDevice.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0E1D8085F200865A7C /* SOSTestDevice.c */; }; DC52EC6F1D80D11800B0A59C /* sc-25-soskeygen.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CFE1D8085F200865A7C /* sc-25-soskeygen.c */; }; - DC52EC701D80D11C00B0A59C /* sc-140-hsa2.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D051D8085F200865A7C /* sc-140-hsa2.c */; }; DC52EC711D80D12200B0A59C /* sc-153-backupslicekeybag.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D081D8085F200865A7C /* sc-153-backupslicekeybag.c */; }; DC52EC721D80D12900B0A59C /* sc-150-backupkeyderivation.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D071D8085F200865A7C /* sc-150-backupkeyderivation.c */; }; - DC52EC731D80D12E00B0A59C /* sc-20-keynames.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CFD1D8085F200865A7C /* sc-20-keynames.c */; }; + DC52EC731D80D12E00B0A59C /* sc-20-keynames.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CFD1D8085F200865A7C /* sc-20-keynames.m */; }; DC52EC741D80D13500B0A59C /* SOSTestDataSource.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0C1D8085F200865A7C /* SOSTestDataSource.c */; }; DC52EC751D80D13B00B0A59C /* sc-42-circlegencount.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D021D8085F200865A7C /* sc-42-circlegencount.c */; }; - DC52EC761D80D13F00B0A59C /* sc-150-ring.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D061D8085F200865A7C /* sc-150-ring.c */; }; + DC52EC761D80D13F00B0A59C /* sc-150-ring.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D061D8085F200865A7C /* sc-150-ring.m */; }; DC52EC771D80D14400B0A59C /* sc-130-resignationticket.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D041D8085F200865A7C /* sc-130-resignationticket.c */; }; - DC52EC781D80D14800B0A59C /* SOSRegressionUtilities.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.c */; }; + DC52EC781D80D14800B0A59C /* SOSRegressionUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.m */; }; DC52EC791D80D14D00B0A59C /* sc-45-digestvector.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D031D8085F200865A7C /* sc-45-digestvector.c */; }; DC52EC7A1D80D15200B0A59C /* sc-40-circle.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D011D8085F200865A7C /* sc-40-circle.c */; }; DC52EC7B1D80D15600B0A59C /* sc-30-peerinfo.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CFF1D8085F200865A7C /* sc-30-peerinfo.c */; }; @@ -1953,12 +2367,7 @@ DC52ECBD1D80D22600B0A59C /* si-42-identity.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD11D8085FC00865A7C /* si-42-identity.c */; }; DC52ECBE1D80D22600B0A59C /* si-43-persistent.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD21D8085FC00865A7C /* si-43-persistent.c */; }; DC52ECC31D80D22600B0A59C /* si-50-secrandom.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD71D8085FC00865A7C /* si-50-secrandom.c */; }; - DC52ECC41D80D22600B0A59C /* si-60-cms.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD81D8085FC00865A7C /* si-60-cms.c */; }; - DC52ECC51D80D22600B0A59C /* si-61-pkcs12.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD91D8085FC00865A7C /* si-61-pkcs12.c */; }; DC52ECC71D80D22600B0A59C /* si-63-scep.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DDE1D8085FC00865A7C /* si-63-scep.c */; }; - DC52ECC81D80D22600B0A59C /* si-64-ossl-cms.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DE71D8085FC00865A7C /* si-64-ossl-cms.c */; }; - DC52ECC91D80D22600B0A59C /* si-65-cms-cert-policy.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DE81D8085FC00865A7C /* si-65-cms-cert-policy.c */; }; - DC52ECCC1D80D22600B0A59C /* si-68-secmatchissuer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DF81D8085FC00865A7C /* si-68-secmatchissuer.c */; }; DC52ECCD1D80D22600B0A59C /* si-69-keydesc.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DF91D8085FC00865A7C /* si-69-keydesc.c */; }; DC52ECD01D80D22600B0A59C /* si-72-syncableitems.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DFC1D8085FC00865A7C /* si-72-syncableitems.c */; }; DC52ECD11D80D22600B0A59C /* si-73-secpasswordgenerate.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DFD1D8085FC00865A7C /* si-73-secpasswordgenerate.c */; }; @@ -1980,71 +2389,69 @@ DC52ECE81D80D2FA00B0A59C /* pbkdf2-00-hmac-sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DA41D8085FC00865A7C /* pbkdf2-00-hmac-sha1.c */; }; DC52ECE91D80D2FA00B0A59C /* spbkdf-00-hmac-sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DA51D8085FC00865A7C /* spbkdf-00-hmac-sha1.c */; }; DC52ECEA1D80D30900B0A59C /* so_01_serverencryption.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E171D8085FC00865A7C /* so_01_serverencryption.c */; }; - DC52ED9E1D80D4ED00B0A59C /* secd-95-escrow-persistence.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.c */; }; - DC52ED9F1D80D4F200B0A59C /* SOSTransportTestTransports.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C7C1D8085D800865A7C /* SOSTransportTestTransports.c */; }; - DC52EDA01D80D4F700B0A59C /* sd-10-policytree.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C3D1D8085D800865A7C /* sd-10-policytree.c */; }; + DC52ED9E1D80D4ED00B0A59C /* secd-95-escrow-persistence.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.m */; }; + DC52ED9F1D80D4F200B0A59C /* SOSTransportTestTransports.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C7C1D8085D800865A7C /* SOSTransportTestTransports.m */; }; + DC52EDA01D80D4F700B0A59C /* sd-10-policytree.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C3D1D8085D800865A7C /* sd-10-policytree.m */; }; DC52EDA11D80D4FC00B0A59C /* IDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD744683195A00BB00FB01C0 /* IDS.framework */; }; DC52EDAC1D80D58400B0A59C /* IDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD744683195A00BB00FB01C0 /* IDS.framework */; }; DC52EDB21D80D59700B0A59C /* IDSFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC6A1D80D0E300B0A59C /* IDSFoundation.framework */; }; - DC52EDB51D80D5C500B0A59C /* secd-03-corrupted-items.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C391D8085D800865A7C /* secd-03-corrupted-items.c */; }; - DC52EDB61D80D5C500B0A59C /* secd-04-corrupted-items.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C3A1D8085D800865A7C /* secd-04-corrupted-items.c */; }; + DC52EDB51D80D5C500B0A59C /* secd-03-corrupted-items.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C391D8085D800865A7C /* secd-03-corrupted-items.m */; }; + DC52EDB61D80D5C500B0A59C /* secd-04-corrupted-items.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C3A1D8085D800865A7C /* secd-04-corrupted-items.m */; }; DC52EDB71D80D5C500B0A59C /* secd-05-corrupted-items.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C3B1D8085D800865A7C /* secd-05-corrupted-items.m */; }; - DC52EDBB1D80D5C500B0A59C /* secd-01-items.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C3F1D8085D800865A7C /* secd-01-items.c */; }; - DC52EDBC1D80D5C500B0A59C /* secd-02-upgrade-while-locked.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C401D8085D800865A7C /* secd-02-upgrade-while-locked.c */; }; + DC52EDBB1D80D5C500B0A59C /* secd-01-items.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C3F1D8085D800865A7C /* secd-01-items.m */; }; + DC52EDBC1D80D5C500B0A59C /* secd-02-upgrade-while-locked.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C401D8085D800865A7C /* secd-02-upgrade-while-locked.m */; }; DC52EDBD1D80D5C500B0A59C /* secd-20-keychain_upgrade.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C411D8085D800865A7C /* secd-20-keychain_upgrade.m */; }; DC52EDBE1D80D5C500B0A59C /* secd-21-transmogrify.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C421D8085D800865A7C /* secd-21-transmogrify.m */; }; - DC52EDBF1D80D5C500B0A59C /* secd-30-keychain-upgrade.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C431D8085D800865A7C /* secd-30-keychain-upgrade.c */; }; - DC52EDC01D80D5C500B0A59C /* secd-31-keychain-bad.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C441D8085D800865A7C /* secd-31-keychain-bad.c */; }; - DC52EDC11D80D5C500B0A59C /* secd-31-keychain-unreadable.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C451D8085D800865A7C /* secd-31-keychain-unreadable.c */; }; - DC52EDC21D80D5C500B0A59C /* secd-32-restore-bad-backup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C461D8085D800865A7C /* secd-32-restore-bad-backup.c */; }; + DC52EDBF1D80D5C500B0A59C /* secd-30-keychain-upgrade.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C431D8085D800865A7C /* secd-30-keychain-upgrade.m */; }; + DC52EDC01D80D5C500B0A59C /* secd-31-keychain-bad.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C441D8085D800865A7C /* secd-31-keychain-bad.m */; }; + DC52EDC11D80D5C500B0A59C /* secd-31-keychain-unreadable.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C451D8085D800865A7C /* secd-31-keychain-unreadable.m */; }; + DC52EDC21D80D5C500B0A59C /* secd-32-restore-bad-backup.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C461D8085D800865A7C /* secd-32-restore-bad-backup.m */; }; DC52EDC31D80D5C500B0A59C /* secd-33-keychain-ctk.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C471D8085D800865A7C /* secd-33-keychain-ctk.m */; }; - DC52EDC41D80D5C500B0A59C /* secd-34-backup-der-parse.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C481D8085D800865A7C /* secd-34-backup-der-parse.c */; }; - DC52EDC51D80D5C500B0A59C /* secd-35-keychain-migrate-inet.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C491D8085D800865A7C /* secd-35-keychain-migrate-inet.c */; }; - DC52EDC61D80D5C500B0A59C /* secd-40-cc-gestalt.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4A1D8085D800865A7C /* secd-40-cc-gestalt.c */; }; - DC52EDC71D80D5C500B0A59C /* secd-50-account.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4B1D8085D800865A7C /* secd-50-account.c */; }; - DC52EDC81D80D5C500B0A59C /* secd-49-manifests.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4C1D8085D800865A7C /* secd-49-manifests.c */; }; - DC52EDC91D80D5C500B0A59C /* secd-50-message.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4D1D8085D800865A7C /* secd-50-message.c */; }; - DC52EDCA1D80D5C500B0A59C /* secd-51-account-inflate.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4E1D8085D800865A7C /* secd-51-account-inflate.c */; }; - DC52EDCC1D80D5C500B0A59C /* secd-52-account-changed.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C501D8085D800865A7C /* secd-52-account-changed.c */; }; - DC52EDCD1D80D5C500B0A59C /* secd-55-account-circle.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C511D8085D800865A7C /* secd-55-account-circle.c */; }; - DC52EDCE1D80D5C500B0A59C /* secd-55-account-incompatibility.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C521D8085D800865A7C /* secd-55-account-incompatibility.c */; }; - DC52EDCF1D80D5C500B0A59C /* secd-56-account-apply.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C531D8085D800865A7C /* secd-56-account-apply.c */; }; - DC52EDD01D80D5C500B0A59C /* secd-57-account-leave.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C541D8085D800865A7C /* secd-57-account-leave.c */; }; - DC52EDD11D80D5C500B0A59C /* secd-57-1-account-last-standing.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C551D8085D800865A7C /* secd-57-1-account-last-standing.c */; }; - DC52EDD21D80D5C500B0A59C /* secd-58-password-change.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C561D8085D800865A7C /* secd-58-password-change.c */; }; - DC52EDD31D80D5C500B0A59C /* secd-59-account-cleanup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C571D8085D800865A7C /* secd-59-account-cleanup.c */; }; - DC52EDD41D80D5C500B0A59C /* secd-60-account-cloud-identity.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C581D8085D800865A7C /* secd-60-account-cloud-identity.c */; }; - DC52EDD51D80D5C500B0A59C /* secd60-account-cloud-exposure.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C591D8085D800865A7C /* secd60-account-cloud-exposure.c */; }; - DC52EDD61D80D5C500B0A59C /* secd-61-account-leave-not-in-kansas-anymore.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5A1D8085D800865A7C /* secd-61-account-leave-not-in-kansas-anymore.c */; }; - DC52EDD71D80D5C500B0A59C /* secd-62-account-backup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5B1D8085D800865A7C /* secd-62-account-backup.c */; }; - DC52EDD81D80D5C500B0A59C /* secd-62-account-hsa-join.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5C1D8085D800865A7C /* secd-62-account-hsa-join.c */; }; - DC52EDD91D80D5C500B0A59C /* secd-63-account-resurrection.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5D1D8085D800865A7C /* secd-63-account-resurrection.c */; }; - DC52EDDA1D80D5C500B0A59C /* secd-65-account-retirement-reset.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5E1D8085D800865A7C /* secd-65-account-retirement-reset.c */; }; - DC52EDDB1D80D5C500B0A59C /* secd-64-circlereset.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5F1D8085D800865A7C /* secd-64-circlereset.c */; }; - DC52EDDC1D80D5C500B0A59C /* secd-70-engine.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C601D8085D800865A7C /* secd-70-engine.c */; }; - DC52EDDD1D80D5C500B0A59C /* secd-70-engine-corrupt.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C611D8085D800865A7C /* secd-70-engine-corrupt.c */; }; - DC52EDDE1D80D5C500B0A59C /* secd-70-engine-smash.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C621D8085D800865A7C /* secd-70-engine-smash.c */; }; - DC52EDDF1D80D5C500B0A59C /* secd-70-otr-remote.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C631D8085D800865A7C /* secd-70-otr-remote.c */; }; - DC52EDE21D80D5C500B0A59C /* secd-74-engine-beer-servers.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C661D8085D800865A7C /* secd-74-engine-beer-servers.c */; }; - DC52EDE31D80D5C500B0A59C /* secd-75-engine-views.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C671D8085D800865A7C /* secd-75-engine-views.c */; }; - DC52EDE61D80D5C500B0A59C /* secd-80-views-basic.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6A1D8085D800865A7C /* secd-80-views-basic.c */; }; - DC52EDE71D80D5C500B0A59C /* secd-82-secproperties-basic.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6B1D8085D800865A7C /* secd-82-secproperties-basic.c */; }; - DC52EDE81D80D5C500B0A59C /* secd-81-item-acl-stress.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6C1D8085D800865A7C /* secd-81-item-acl-stress.c */; }; - DC52EDE91D80D5C500B0A59C /* secd-81-item-acl.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6D1D8085D800865A7C /* secd-81-item-acl.c */; }; - DC52EDEA1D80D5C500B0A59C /* secd-82-persistent-ref.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6E1D8085D800865A7C /* secd-82-persistent-ref.c */; }; + DC52EDC41D80D5C500B0A59C /* secd-34-backup-der-parse.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C481D8085D800865A7C /* secd-34-backup-der-parse.m */; }; + DC52EDC51D80D5C500B0A59C /* secd-35-keychain-migrate-inet.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C491D8085D800865A7C /* secd-35-keychain-migrate-inet.m */; }; + DC52EDC61D80D5C500B0A59C /* secd-40-cc-gestalt.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4A1D8085D800865A7C /* secd-40-cc-gestalt.m */; }; + DC52EDC71D80D5C500B0A59C /* secd-50-account.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4B1D8085D800865A7C /* secd-50-account.m */; }; + DC52EDC81D80D5C500B0A59C /* secd-49-manifests.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4C1D8085D800865A7C /* secd-49-manifests.m */; }; + DC52EDC91D80D5C500B0A59C /* secd-50-message.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4D1D8085D800865A7C /* secd-50-message.m */; }; + DC52EDCA1D80D5C500B0A59C /* secd-51-account-inflate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4E1D8085D800865A7C /* secd-51-account-inflate.m */; }; + DC52EDCC1D80D5C500B0A59C /* secd-52-account-changed.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C501D8085D800865A7C /* secd-52-account-changed.m */; }; + DC52EDCD1D80D5C500B0A59C /* secd-55-account-circle.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C511D8085D800865A7C /* secd-55-account-circle.m */; }; + DC52EDCE1D80D5C500B0A59C /* secd-55-account-incompatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C521D8085D800865A7C /* secd-55-account-incompatibility.m */; }; + DC52EDCF1D80D5C500B0A59C /* secd-56-account-apply.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C531D8085D800865A7C /* secd-56-account-apply.m */; }; + DC52EDD01D80D5C500B0A59C /* secd-57-account-leave.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C541D8085D800865A7C /* secd-57-account-leave.m */; }; + DC52EDD11D80D5C500B0A59C /* secd-57-1-account-last-standing.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C551D8085D800865A7C /* secd-57-1-account-last-standing.m */; }; + DC52EDD21D80D5C500B0A59C /* secd-58-password-change.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C561D8085D800865A7C /* secd-58-password-change.m */; }; + DC52EDD31D80D5C500B0A59C /* secd-59-account-cleanup.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C571D8085D800865A7C /* secd-59-account-cleanup.m */; }; + DC52EDD41D80D5C500B0A59C /* secd-60-account-cloud-identity.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C581D8085D800865A7C /* secd-60-account-cloud-identity.m */; }; + DC52EDD51D80D5C500B0A59C /* secd60-account-cloud-exposure.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C591D8085D800865A7C /* secd60-account-cloud-exposure.m */; }; + DC52EDD61D80D5C500B0A59C /* secd-61-account-leave-not-in-kansas-anymore.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5A1D8085D800865A7C /* secd-61-account-leave-not-in-kansas-anymore.m */; }; + DC52EDD71D80D5C500B0A59C /* secd-62-account-backup.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5B1D8085D800865A7C /* secd-62-account-backup.m */; }; + DC52EDD91D80D5C500B0A59C /* secd-63-account-resurrection.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5D1D8085D800865A7C /* secd-63-account-resurrection.m */; }; + DC52EDDA1D80D5C500B0A59C /* secd-65-account-retirement-reset.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5E1D8085D800865A7C /* secd-65-account-retirement-reset.m */; }; + DC52EDDB1D80D5C500B0A59C /* secd-64-circlereset.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C5F1D8085D800865A7C /* secd-64-circlereset.m */; }; + DC52EDDC1D80D5C500B0A59C /* secd-70-engine.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C601D8085D800865A7C /* secd-70-engine.m */; }; + DC52EDDD1D80D5C500B0A59C /* secd-70-engine-corrupt.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C611D8085D800865A7C /* secd-70-engine-corrupt.m */; }; + DC52EDDE1D80D5C500B0A59C /* secd-70-engine-smash.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C621D8085D800865A7C /* secd-70-engine-smash.m */; }; + DC52EDDF1D80D5C500B0A59C /* secd-70-otr-remote.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C631D8085D800865A7C /* secd-70-otr-remote.m */; }; + DC52EDE21D80D5C500B0A59C /* secd-74-engine-beer-servers.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C661D8085D800865A7C /* secd-74-engine-beer-servers.m */; }; + DC52EDE31D80D5C500B0A59C /* secd-75-engine-views.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C671D8085D800865A7C /* secd-75-engine-views.m */; }; + DC52EDE61D80D5C500B0A59C /* secd-80-views-basic.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6A1D8085D800865A7C /* secd-80-views-basic.m */; }; + DC52EDE71D80D5C500B0A59C /* secd-82-secproperties-basic.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6B1D8085D800865A7C /* secd-82-secproperties-basic.m */; }; + DC52EDE81D80D5C500B0A59C /* secd-81-item-acl-stress.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6C1D8085D800865A7C /* secd-81-item-acl-stress.m */; }; + DC52EDE91D80D5C500B0A59C /* secd-81-item-acl.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6D1D8085D800865A7C /* secd-81-item-acl.m */; }; + DC52EDEA1D80D5C500B0A59C /* secd-82-persistent-ref.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6E1D8085D800865A7C /* secd-82-persistent-ref.m */; }; DC52EDEB1D80D5C500B0A59C /* secd-83-item-match-policy.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C6F1D8085D800865A7C /* secd-83-item-match-policy.m */; }; DC52EDEC1D80D5C500B0A59C /* secd-83-item-match-valid-on-date.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C701D8085D800865A7C /* secd-83-item-match-valid-on-date.m */; }; DC52EDED1D80D5C600B0A59C /* secd-83-item-match-trusted.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C711D8085D800865A7C /* secd-83-item-match-trusted.m */; }; - DC52EDEF1D80D5C600B0A59C /* secd-90-hsa2.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C731D8085D800865A7C /* secd-90-hsa2.c */; }; - DC52EDF11D80D5C600B0A59C /* secd-100-initialsync.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C751D8085D800865A7C /* secd-100-initialsync.c */; }; - DC52EDF21D80D5C600B0A59C /* secd-130-other-peer-views.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C761D8085D800865A7C /* secd-130-other-peer-views.c */; }; - DC52EDF41D80D5C600B0A59C /* secd-200-logstate.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C781D8085D800865A7C /* secd-200-logstate.c */; }; + DC52EDF11D80D5C600B0A59C /* secd-100-initialsync.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C751D8085D800865A7C /* secd-100-initialsync.m */; }; + DC52EDF21D80D5C600B0A59C /* secd-130-other-peer-views.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C761D8085D800865A7C /* secd-130-other-peer-views.m */; }; + DC52EDF41D80D5C600B0A59C /* secd-200-logstate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C781D8085D800865A7C /* secd-200-logstate.m */; }; DC52EDF51D80D62E00B0A59C /* SecdTestKeychainUtilities.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C7A1D8085D800865A7C /* SecdTestKeychainUtilities.c */; }; - DC52EDF61D80D62E00B0A59C /* SOSTransportTestTransports.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C7C1D8085D800865A7C /* SOSTransportTestTransports.c */; }; + DC52EDF61D80D62E00B0A59C /* SOSTransportTestTransports.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C7C1D8085D800865A7C /* SOSTransportTestTransports.m */; }; DC52EDF71D80D65700B0A59C /* si-90-emcs.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E0D1D8085FC00865A7C /* si-90-emcs.m */; }; DC52EDF81D80D65C00B0A59C /* SOSTestDevice.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0E1D8085F200865A7C /* SOSTestDevice.c */; }; DC52EDF91D80D66000B0A59C /* SOSTestDataSource.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0C1D8085F200865A7C /* SOSTestDataSource.c */; }; - DC52EDFA1D80D66600B0A59C /* SOSRegressionUtilities.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.c */; }; + DC52EDFA1D80D66600B0A59C /* SOSRegressionUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.m */; }; DC52EE421D80D71900B0A59C /* si-20-sectrust.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DBB1D8085FC00865A7C /* si-20-sectrust.c */; }; 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 */; }; @@ -2063,13 +2470,13 @@ 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-blacklist.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DF71D8085FC00865A7C /* si-67-sectrust-blacklist.c */; }; + 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 */; }; DC52EE591D80D73800B0A59C /* si-82-seccertificate-ct.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E031D8085FC00865A7C /* si-82-seccertificate-ct.c */; }; DC52EE5A1D80D73800B0A59C /* si-83-seccertificate-sighashalg.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E061D8085FC00865A7C /* si-83-seccertificate-sighashalg.c */; }; DC52EE5B1D80D73800B0A59C /* si-97-sectrust-path-scoring.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E101D8085FC00865A7C /* si-97-sectrust-path-scoring.m */; }; DC52EE5C1D80D76300B0A59C /* si-20-sectrust-policies.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DBA1D8085FC00865A7C /* si-20-sectrust-policies.m */; }; - DC52EE5D1D80D76B00B0A59C /* si-87-sectrust-name-constraints.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E091D8085FC00865A7C /* si-87-sectrust-name-constraints.c */; }; + DC52EE5D1D80D76B00B0A59C /* si-87-sectrust-name-constraints.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E091D8085FC00865A7C /* si-87-sectrust-name-constraints.m */; }; DC52EE5E1D80D78C00B0A59C /* si-82-sectrust-ct.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E041D8085FC00865A7C /* si-82-sectrust-ct.m */; }; DC52EE5F1D80D79400B0A59C /* si-85-sectrust-ssl-policy.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E071D8085FC00865A7C /* si-85-sectrust-ssl-policy.c */; }; DC52EE601D80D79900B0A59C /* si-74-OTAPKISigner.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DFE1D8085FC00865A7C /* si-74-OTAPKISigner.c */; }; @@ -2080,7 +2487,6 @@ DC52EE721D80D86400B0A59C /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E9A1D8085FC00865A7C /* SecuritydXPC.c */; }; DC52EE731D80D86800B0A59C /* SecKey.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E601D8085FC00865A7C /* SecKey.c */; }; DC52EE741D80D86F00B0A59C /* SecAccessControl.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E301D8085FC00865A7C /* SecAccessControl.c */; }; - DC52EE751D80D87900B0A59C /* SOSCloudCircle.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D891D8085F200865A7C /* SOSCloudCircle.c */; }; DC52EE761D80D87F00B0A59C /* SecCTKKey.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E441D8085FC00865A7C /* SecCTKKey.c */; }; DC52EE771D80D88300B0A59C /* SecDH.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E461D8085FC00865A7C /* SecDH.c */; }; DC52EE781D80D88800B0A59C /* SecRSAKey.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E851D8085FC00865A7C /* SecRSAKey.c */; }; @@ -2088,8 +2494,9 @@ DC52EE7A1D80D89400B0A59C /* SecCFAllocator.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E401D8085FC00865A7C /* SecCFAllocator.c */; }; DC52EE7B1D80D89900B0A59C /* SecKeyAdaptors.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E621D8085FC00865A7C /* SecKeyAdaptors.c */; }; DC52EE7C1D80D89E00B0A59C /* SecItemBackup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E5A1D8085FC00865A7C /* SecItemBackup.c */; }; + DC54DD0F1EA7D9E700108E92 /* CKKSManifestLeafRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 476D873A1E6750E200190352 /* CKKSManifestLeafRecord.m */; }; + DC54DD101EA7D9E800108E92 /* CKKSManifestLeafRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 476D873A1E6750E200190352 /* CKKSManifestLeafRecord.m */; }; DC55329B1DDAA28600B6A6A7 /* XPCNotificationDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E7C787331DD0FED50087FC34 /* XPCNotificationDispatcher.m */; }; - DC55329C1DDAA28800B6A6A7 /* XPCNotificationDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E7C787331DD0FED50087FC34 /* XPCNotificationDispatcher.m */; }; DC58C4331D77BE2E003C25A4 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789241D7799CD00B50D50 /* CoreFoundation.framework */; }; DC58C43E1D77BED0003C25A4 /* csparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC58C43B1D77BED0003C25A4 /* csparser.cpp */; }; DC59E9A41D91C6F0001BDDF5 /* libCMS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1002D71D8E19F20025549C /* libCMS.a */; }; @@ -2119,7 +2526,6 @@ DC59EA771D91CC6D001BDDF5 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; DC59EA7B1D91CC9F001BDDF5 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; DC59EA7E1D91CCB2001BDDF5 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; - DC59EA7F1D91CCCA001BDDF5 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; DC59EA821D91CD24001BDDF5 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; DC59EA851D91CD35001BDDF5 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; DC59EA881D91CD7E001BDDF5 /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.a */; }; @@ -2136,13 +2542,13 @@ DC5ABDD01D832E4000CF422C /* db_commands.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD801D832D5800CF422C /* db_commands.cpp */; }; DC5ABDD11D832E4000CF422C /* display_error_code.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD821D832D5800CF422C /* display_error_code.c */; }; DC5ABDD21D832E4000CF422C /* trusted_cert_dump.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD841D832D5800CF422C /* trusted_cert_dump.c */; }; - DC5ABDD31D832E4000CF422C /* identity_find.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD861D832D5800CF422C /* identity_find.c */; }; + DC5ABDD31D832E4000CF422C /* identity_find.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD861D832D5800CF422C /* identity_find.m */; }; DC5ABDD41D832E4000CF422C /* identity_prefs.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD881D832D5800CF422C /* identity_prefs.c */; }; DC5ABDD51D832E4000CF422C /* key_create.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD8A1D832D5800CF422C /* key_create.c */; }; DC5ABDD61D832E4000CF422C /* keychain_add.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD8C1D832D5800CF422C /* keychain_add.c */; }; DC5ABDD71D832E4000CF422C /* keychain_create.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD8E1D832D5800CF422C /* keychain_create.c */; }; DC5ABDD81D832E4000CF422C /* keychain_delete.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD901D832D5800CF422C /* keychain_delete.c */; }; - DC5ABDD91D832E4000CF422C /* keychain_export.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD921D832D5800CF422C /* keychain_export.c */; }; + DC5ABDD91D832E4000CF422C /* keychain_export.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD921D832D5800CF422C /* keychain_export.m */; }; DC5ABDDA1D832E4000CF422C /* keychain_find.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD941D832D5800CF422C /* keychain_find.c */; }; DC5ABDDB1D832E4000CF422C /* keychain_import.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD961D832D5800CF422C /* keychain_import.c */; }; DC5ABDDC1D832E4000CF422C /* keychain_list.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABD981D832D5800CF422C /* keychain_list.c */; }; @@ -2209,7 +2615,6 @@ DC5AC0C71D8353C800CF422C /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0C61D8353C800CF422C /* PCSC.framework */; }; DC5AC0C91D8353D100CF422C /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789181D77998C00B50D50 /* libbsm.dylib */; }; DC5AC0CE1D83542B00CF422C /* libsecurity_tokend_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0CD1D83542700CF422C /* libsecurity_tokend_client.a */; }; - DC5AC0D11D83544200CF422C /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891A1D77999200B50D50 /* libobjc.dylib */; }; DC5AC0D21D83544800CF422C /* libauto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789161D77998700B50D50 /* libauto.dylib */; }; DC5AC0D31D83544D00CF422C /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891E1D77999D00B50D50 /* libsqlite3.dylib */; }; DC5AC0D41D83547A00CF422C /* libsecuritydservice_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0B91D83533400CF422C /* libsecuritydservice_client.a */; }; @@ -2293,6 +2698,27 @@ DC5AC12A1D83555A00CF422C /* SharedMemoryServer.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5ABFD21D83511A00CF422C /* SharedMemoryServer.h */; }; DC5AC12B1D83555A00CF422C /* self.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5AC0FF1D83550300CF422C /* self.h */; }; DC5AC12D1D83560100CF422C /* securityd_dtrace.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5ABFD91D83512A00CF422C /* securityd_dtrace.h */; }; + DC5BB4FA1E0C90DE0010F836 /* CKKSIncomingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4F11E0C86800010F836 /* CKKSIncomingQueueOperation.m */; }; + DC5BB4FB1E0C90DF0010F836 /* CKKSIncomingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4F11E0C86800010F836 /* CKKSIncomingQueueOperation.m */; }; + DC5BB4FE1E0C98320010F836 /* CKKSOutgoingQueueOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5BB4FC1E0C98320010F836 /* CKKSOutgoingQueueOperation.h */; }; + DC5BB4FF1E0C98320010F836 /* CKKSOutgoingQueueOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5BB4FC1E0C98320010F836 /* CKKSOutgoingQueueOperation.h */; }; + DC5BB5001E0C98320010F836 /* CKKSOutgoingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4FD1E0C98320010F836 /* CKKSOutgoingQueueOperation.m */; }; + DC5BB5011E0C98320010F836 /* CKKSOutgoingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4FD1E0C98320010F836 /* CKKSOutgoingQueueOperation.m */; }; + DC5BCC481E53820200649140 /* SecArgParse.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5BCC461E5380EA00649140 /* SecArgParse.c */; }; + DC5BD5831E8C6FC800C5EC49 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; }; + DC5BD5841E8C6FD100C5EC49 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; }; + DC5F35A61EE0F25000900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; + DC5F35A71EE0F25100900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; + DC5F35A81EE0F25300900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; + DC5F35A91EE0F25300900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; + DC5F35AA1EE0F27100900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; + DC5F35AB1EE0F27100900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; + DC5F35AC1EE0F27900900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; + 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 */; }; DC610A181D78F129002223DE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C0BDB31175685B000BC1A7E /* main.m */; }; DC610A1D1D78F129002223DE /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; DC610A1E1D78F129002223DE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; @@ -2317,11 +2743,11 @@ DC610AB11D7910C3002223DE /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789241D7799CD00B50D50 /* CoreFoundation.framework */; }; DC610ABA1D7910F8002223DE /* gk_reset_check.c in Sources */ = {isa = PBXBuildFile; fileRef = DC610AB91D7910F8002223DE /* gk_reset_check.c */; }; DC63CAF81D91A15F00C03317 /* libsecurity_cms_regressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1002CB1D8E19D70025549C /* libsecurity_cms_regressions.a */; }; + DC6593D11ED8DAB900C19462 /* CKKSTests+CurrentPointerAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6593C91ED8DA9200C19462 /* CKKSTests+CurrentPointerAPI.m */; }; DC65E7231D8CB28900152EF0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DC65E7241D8CB29E00152EF0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DC65E7271D8CB2EC00152EF0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DC65E72A1D8CB2FC00152EF0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; - DC65E72D1D8CB31B00152EF0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DC65E7301D8CB32D00152EF0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DC65E7311D8CB33800152EF0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DC65E7361D8CB35E00152EF0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; @@ -2330,7 +2756,7 @@ DC65E7751D8CB81000152EF0 /* libregressionBase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCBFD1D8C648C00070CB0 /* libregressionBase.a */; }; DC65E7761D8CB81A00152EF0 /* libregressionBase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCBFD1D8C648C00070CB0 /* libregressionBase.a */; }; DC65E7771D8CB82500152EF0 /* libregressionBase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCBFD1D8C648C00070CB0 /* libregressionBase.a */; }; - DC65E7781D8CB8A500152EF0 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DC65E7781D8CB8A500152EF0 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DC65E77A1D8CB8D200152EF0 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB740680A4749C800D641BB /* libsqlite3.dylib */; }; DC65E77B1D8CB8E800152EF0 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; DC65E77C1D8CB8F100152EF0 /* MobileKeyBag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FC30AB1332DE9000802946 /* MobileKeyBag.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; @@ -2376,7 +2802,12 @@ DC6A82C11D8776B900418608 /* cshostingClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC6A82851D87734600418608 /* cshostingClient.cpp */; }; DC6A82C21D8776B900418608 /* cshostingServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC6A82861D87734600418608 /* cshostingServer.cpp */; }; DC6A82C41D8776D800418608 /* ssblob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC6A82571D87732E00418608 /* ssblob.cpp */; }; + DC6ACC461E81E08D00125DC5 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; + DC6ACC471E81E08E00125DC5 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; DC6BC2721D90D05900DD57B3 /* com.apple.securityd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DC5ABFE41D83514700CF422C /* com.apple.securityd.plist */; }; + DC6D2C921DD2835A00BE372D /* CKKSOutgoingQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9B7AE41DCBF604004E9385 /* CKKSOutgoingQueueEntry.m */; }; + DC6D2C931DD2836500BE372D /* CKKSOutgoingQueueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC9B7AE61DCBF651004E9385 /* CKKSOutgoingQueueEntry.h */; }; + DC7162D21EB413F2000D2BB5 /* KeychainCKKS.plist in Copy BATS Test Discovery plist */ = {isa = PBXBuildFile; fileRef = 6CB5F4781E402E5700DBF3F0 /* KeychainCKKS.plist */; }; DC71D85C1D94CCD40065FB93 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; DC71D8F51D959F150065FB93 /* com.apple.securityd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */; }; DC71D9A11D95BA6C0065FB93 /* SecAsn1Coder.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785131D77895A00B50D50 /* SecAsn1Coder.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -2451,8 +2882,15 @@ DC71D9F41D95BB0A0065FB93 /* DER_Digest.c in Sources */ = {isa = PBXBuildFile; fileRef = DC59E9F91D91CA0A001BDDF5 /* DER_Digest.c */; }; DC71D9F51D95BB0A0065FB93 /* oids.c in Sources */ = {isa = PBXBuildFile; fileRef = DC59E9FA1D91CA0A001BDDF5 /* oids.c */; }; DC71D9F61D95BB0A0065FB93 /* DER_CertCrl.c in Sources */ = {isa = PBXBuildFile; fileRef = DC59E9F01D91CA0A001BDDF5 /* DER_CertCrl.c */; }; - DC84E0BC1D9B2B6A004C57F7 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD06AB01D8E0D53007602F1 /* libsecurity_utilities.a */; }; - DC84E0BD1D9B2B8C004C57F7 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB740680A4749C800D641BB /* libsqlite3.dylib */; }; + DC762A9E1E57A86A00B03A2C /* CKKSRecordHolder.h in Headers */ = {isa = PBXBuildFile; fileRef = DC762A9C1E57A86A00B03A2C /* CKKSRecordHolder.h */; }; + DC762A9F1E57A86A00B03A2C /* CKKSRecordHolder.h in Headers */ = {isa = PBXBuildFile; fileRef = DC762A9C1E57A86A00B03A2C /* CKKSRecordHolder.h */; }; + DC762AA01E57A86A00B03A2C /* CKKSRecordHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = DC762A9D1E57A86A00B03A2C /* CKKSRecordHolder.m */; }; + DC762AA11E57A86A00B03A2C /* CKKSRecordHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = DC762A9D1E57A86A00B03A2C /* CKKSRecordHolder.m */; }; + DC797E1A1DD3F9A400CC9E42 /* CKKSSQLDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = DC797E131DD3F88300CC9E42 /* CKKSSQLDatabaseObject.m */; }; + DC7A17ED1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC7A17EB1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h */; }; + DC7A17EE1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC7A17EB1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h */; }; + DC7A17EF1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC7A17EC1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m */; }; + DC7A17F01E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC7A17EC1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.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 */; }; @@ -2477,12 +2915,47 @@ DC8834931D8A21AB00CE0ACA /* oidsattr.c in Sources */ = {isa = PBXBuildFile; fileRef = DC88344B1D8A21AA00CE0ACA /* oidsattr.c */; }; DC8834961D8A21AB00CE0ACA /* oidsocsp.c in Sources */ = {isa = PBXBuildFile; fileRef = DC88344E1D8A21AA00CE0ACA /* oidsocsp.c */; }; DC9036B31D9DFED600B6C234 /* ss_types.defs in Headers */ = {isa = PBXBuildFile; fileRef = DC6A82771D87733C00418608 /* ss_types.defs */; settings = {ATTRIBUTES = (Public, ); }; }; + DC9082C41EA0277600D0C1C5 /* CKKSZoneChangeFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9082C31EA0276000D0C1C5 /* CKKSZoneChangeFetcher.m */; }; + DC9082C51EA0277700D0C1C5 /* CKKSZoneChangeFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9082C31EA0276000D0C1C5 /* CKKSZoneChangeFetcher.m */; }; + DC9082C61EA027DB00D0C1C5 /* CKKSZoneChangeFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = DC9082C21EA0276000D0C1C5 /* CKKSZoneChangeFetcher.h */; }; + DC9082C71EA027DC00D0C1C5 /* CKKSZoneChangeFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = DC9082C21EA0276000D0C1C5 /* CKKSZoneChangeFetcher.h */; }; + DC94BCCA1F10448600E07CEB /* CloudKitCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = DC94BCC81F10448600E07CEB /* CloudKitCategories.h */; }; + DC94BCCB1F10448600E07CEB /* CloudKitCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = DC94BCC81F10448600E07CEB /* CloudKitCategories.h */; }; + DC94BCCC1F10448600E07CEB /* CloudKitCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = DC94BCC91F10448600E07CEB /* CloudKitCategories.m */; }; + DC94BCCD1F10448600E07CEB /* CloudKitCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = DC94BCC91F10448600E07CEB /* CloudKitCategories.m */; }; + DC96053F1ECA2D6400AF9BDA /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; }; DC963E7E1D95EBB1008A153E /* libsecurity_apple_csp.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCF784F81D88B63800E694BB /* libsecurity_apple_csp.plist */; }; DC963E801D95EBD1008A153E /* libsecurity_apple_csp.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCF784F91D88B63800E694BB /* libsecurity_apple_csp.txt */; }; 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 */; }; DC963EC51D95F52C008A153E /* oids.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1785421D778A7400B50D50 /* oids.h */; settings = {ATTRIBUTES = (Public, ); }; }; DC963EC61D95F646008A153E /* der_plist.h in Headers */ = {isa = PBXBuildFile; fileRef = 524492931AFD6D480043695A /* der_plist.h */; }; + DC9A2C5F1EB3F557008FAC27 /* CKKSTests+Coalesce.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9A2C5E1EB3F556008FAC27 /* CKKSTests+Coalesce.m */; }; + DC9A2C7F1EB40A76008FAC27 /* OCMock.framework in Embed OCMock */ = {isa = PBXBuildFile; fileRef = DC3502E81E02172C00BC0587 /* OCMock.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + DC9C75161E4BCE1800F1CA0D /* CKKSOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9C750F1E4BCC5100F1CA0D /* CKKSOperationTests.m */; }; + DCA4D1FF1E552DD50056214F /* CKKSCurrentKeyPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA4D1F41E5520550056214F /* CKKSCurrentKeyPointer.m */; }; + DCA4D2001E552DD50056214F /* CKKSCurrentKeyPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA4D1F41E5520550056214F /* CKKSCurrentKeyPointer.m */; }; + DCA4D2151E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCA4D2131E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h */; }; + DCA4D2161E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCA4D2131E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h */; }; + DCA4D2171E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA4D2141E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m */; }; + DCA4D2181E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA4D2141E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m */; }; + DCA85B931E8D97E400BA7241 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; }; + DCA85B941E8D97E400BA7241 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; }; + DCA85B961E8D980100BA7241 /* 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 */; }; + DCA85B9A1E8D981100BA7241 /* 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 */; }; + DCAB14271E40039600C81511 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; + DCB221501E8B08A5001598BC /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DCB221511E8B08A6001598BC /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DCB221531E8B08BC001598BC /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DCB221541E8B08BE001598BC /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DCB221561E8B08BF001598BC /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DCB221581E8B08C9001598BC /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DCB221591E8B08CA001598BC /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DCB2215A1E8B08CB001598BC /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; DCB3407D1D8A24F70054D16E /* Authorization.c in Sources */ = {isa = PBXBuildFile; fileRef = DCB3406F1D8A24F70054D16E /* Authorization.c */; }; DCB340841D8A24F70054D16E /* Authorization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB340761D8A24F70054D16E /* Authorization.cpp */; }; DCB340871D8A24F70054D16E /* trampolineClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB340791D8A24F70054D16E /* trampolineClient.cpp */; }; @@ -2652,7 +3125,6 @@ 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 */; }; - DCB342FF1D8A32A20054D16E /* SecCertificateRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342481D8A32A20054D16E /* SecCertificateRequest.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 */; }; @@ -2677,8 +3149,6 @@ DCB3433E1D8A32A20054D16E /* ACL.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342891D8A32A20054D16E /* ACL.h */; }; DCB3433F1D8A32A20054D16E /* Certificate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB3428A1D8A32A20054D16E /* Certificate.cpp */; }; DCB343401D8A32A20054D16E /* Certificate.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB3428B1D8A32A20054D16E /* Certificate.h */; }; - DCB343411D8A32A20054D16E /* CertificateRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB3428C1D8A32A20054D16E /* CertificateRequest.cpp */; }; - DCB343421D8A32A20054D16E /* CertificateRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB3428D1D8A32A20054D16E /* CertificateRequest.h */; }; DCB343431D8A32A20054D16E /* CertificateValues.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB3428E1D8A32A20054D16E /* CertificateValues.cpp */; }; DCB343441D8A32A20054D16E /* CertificateValues.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB3428F1D8A32A20054D16E /* CertificateValues.h */; }; DCB343451D8A32A20054D16E /* ExtendedAttribute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342901D8A32A20054D16E /* ExtendedAttribute.cpp */; }; @@ -2716,7 +3186,6 @@ DCB343651D8A32A20054D16E /* TrustSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342B11D8A32A20054D16E /* TrustSettings.h */; }; DCB343661D8A32A20054D16E /* TrustKeychains.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342B21D8A32A20054D16E /* TrustKeychains.h */; }; DCB343671D8A32A20054D16E /* SecTrustOSXEntryPoints.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342B31D8A32A20054D16E /* SecTrustOSXEntryPoints.cpp */; }; - DCB343681D8A32A20054D16E /* SecTrustOSXEntryPoints.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342B41D8A32A20054D16E /* SecTrustOSXEntryPoints.h */; }; DCB3436A1D8A32A20054D16E /* CCallbackMgr.cp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342B71D8A32A20054D16E /* CCallbackMgr.cp */; }; DCB3436B1D8A32A20054D16E /* CCallbackMgr.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342B81D8A32A20054D16E /* CCallbackMgr.h */; }; DCB3436C1D8A32A20054D16E /* cssmdatetime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342B91D8A32A20054D16E /* cssmdatetime.cpp */; }; @@ -2832,10 +3301,29 @@ DCB344A51D8A35270054D16E /* si-20-sectrust-provisioning.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB344701D8A35270054D16E /* si-20-sectrust-provisioning.h */; }; DCB344A61D8A35270054D16E /* si-33-keychain-backup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCB344711D8A35270054D16E /* si-33-keychain-backup.c */; }; DCB344A71D8A35270054D16E /* si-34-one-true-keychain.c in Sources */ = {isa = PBXBuildFile; fileRef = DCB344721D8A35270054D16E /* si-34-one-true-keychain.c */; }; + 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 */; }; + DCB5D93B1E4A9A3400BE22AB /* CKKSSynchronizeOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB5D9391E4A9A3400BE22AB /* CKKSSynchronizeOperation.h */; }; + DCB5D93C1E4A9A3400BE22AB /* CKKSSynchronizeOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB5D9391E4A9A3400BE22AB /* CKKSSynchronizeOperation.h */; }; + DCB5D93D1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB5D93A1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m */; }; + DCB5D93E1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB5D93A1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m */; }; DCB7D8C31D8E181B00867385 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD06AB01D8E0D53007602F1 /* libsecurity_utilities.a */; }; DCB7D8D01D8E183C00867385 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD06AB01D8E0D53007602F1 /* libsecurity_utilities.a */; }; DCB7D8D11D8E185900867385 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD06AB01D8E0D53007602F1 /* libsecurity_utilities.a */; }; + DCB837321ED5045000015C07 /* CKKSLockStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = DC207EB71ED4EAB600D46873 /* CKKSLockStateTracker.m */; }; + DCB837381ED5045100015C07 /* CKKSLockStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = DC207EB71ED4EAB600D46873 /* CKKSLockStateTracker.m */; }; DCBB8AC41D80DD95007ED154 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; + DCBDB3B71E57C82300B61300 /* CKKSKeychainView.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */; }; + DCBDB3B81E57C82300B61300 /* CKKSKeychainView.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */; }; + DCBDB3BB1E57CA7A00B61300 /* CKKSViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DCBDB3B91E57CA7A00B61300 /* CKKSViewManager.h */; }; + DCBDB3BC1E57CA7A00B61300 /* CKKSViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DCBDB3B91E57CA7A00B61300 /* CKKSViewManager.h */; }; + DCBDB3BD1E57CA7A00B61300 /* CKKSViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBDB3BA1E57CA7A00B61300 /* CKKSViewManager.m */; }; + DCBDB3BE1E57CA7A00B61300 /* CKKSViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBDB3BA1E57CA7A00B61300 /* CKKSViewManager.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 */; }; @@ -2844,6 +3332,7 @@ DCC0937E1D80B0A700F984E4 /* SecOTRPacketData.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF7FFF915AFB73800B9D400 /* SecOTRPacketData.h */; }; DCC0937F1D80B0B100F984E4 /* SecOTRMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF7FFF715AFB73800B9D400 /* SecOTRMath.h */; }; DCC093801D80B0B700F984E4 /* SecCFAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */; }; + DCC19F711EB9151B00B7D70F /* KeychainCKKS.plist in Copy BATS Test Discovery Plist */ = {isa = PBXBuildFile; fileRef = 6CB5F4781E402E5700DBF3F0 /* KeychainCKKS.plist */; }; DCC5BF1B1D93723A008D1E84 /* libsecurity_apple_csp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCF783141D88B4DE00E694BB /* libsecurity_apple_csp.a */; }; DCC5BF1C1D937242008D1E84 /* libsecurity_apple_cspdl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCF785E51D88B95500E694BB /* libsecurity_apple_cspdl.a */; }; DCC5BF1D1D937249008D1E84 /* libsecurity_apple_file_dl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCF7883B1D88C8C400E694BB /* libsecurity_apple_file_dl.a */; }; @@ -2862,11 +3351,6 @@ DCC5BF2A1D93729E008D1E84 /* libsecurity_ssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BC9CF1D8B824700070CB0 /* libsecurity_ssl.a */; }; DCC5BF2B1D9372A4008D1E84 /* libsecurity_transform.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCA801D8B858600070CB0 /* libsecurity_transform.a */; }; DCC5BF2C1D9372AA008D1E84 /* libsecurity_translocate.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCB081D8B894F00070CB0 /* libsecurity_translocate.a */; }; - DCC78EB21D80890800865A7C /* secd_77_ids_messaging.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C691D8085D800865A7C /* secd_77_ids_messaging.c */; }; - DCC78EB31D80890E00865A7C /* secd-95-escrow-persistence.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.c */; }; - DCC78EB41D80897E00865A7C /* secd-76-idstransport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C681D8085D800865A7C /* secd-76-idstransport.c */; }; - DCC78EB51D80898500865A7C /* secd-71-engine-save.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C641D8085D800865A7C /* secd-71-engine-save.c */; }; - DCC78EB61D80898E00865A7C /* secd-52-offering-gencount-reset.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C4F1D8085D800865A7C /* secd-52-offering-gencount-reset.c */; }; DCC78EB81D80899C00865A7C /* vmdh.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E9C1D8085FC00865A7C /* vmdh.c */; }; DCC78EB91D8089A700865A7C /* pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E2E1D8085FC00865A7C /* pbkdf2.c */; }; DCC78EBA1D8089BD00865A7C /* p12pbegen.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E2C1D8085FC00865A7C /* p12pbegen.c */; }; @@ -2915,8 +3399,22 @@ DCC78EE61D808B2A00865A7C /* SecAccessControl.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E301D8085FC00865A7C /* SecAccessControl.c */; }; DCC78EE71D808B2F00865A7C /* secViewDisplay.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9E1D8085F200865A7C /* secViewDisplay.c */; }; DCC78EE81D808B3500865A7C /* secToolFileIO.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D931D8085F200865A7C /* secToolFileIO.c */; }; - DCC78EE91D808B4100865A7C /* SOSCloudCircle.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D891D8085F200865A7C /* SOSCloudCircle.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 */; }; + DCCD33CE1E3FEF1700AA4AD1 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; + DCCD33CF1E3FEF1800AA4AD1 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; + DCCD33D01E3FEF2A00AA4AD1 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; + DCCD33D11E3FEF2C00AA4AD1 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; + DCCD33D21E3FF0D800AA4AD1 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; + DCCD33D31E3FF0D800AA4AD1 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; + DCCD33E91E3FFDBF00AA4AD1 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; + DCCD34001E4001AD00AA4AD1 /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3A1D78F228002223DE /* libACM.a */; }; + DCCD88E81E42622200F5AA71 /* CKKSGroupOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCCD88E61E42622200F5AA71 /* CKKSGroupOperation.h */; }; + DCCD88E91E42622200F5AA71 /* CKKSGroupOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCCD88E61E42622200F5AA71 /* CKKSGroupOperation.h */; }; + DCCD88EA1E42622200F5AA71 /* CKKSGroupOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCCD88E71E42622200F5AA71 /* CKKSGroupOperation.m */; }; + DCCD88EB1E42622200F5AA71 /* CKKSGroupOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCCD88E71E42622200F5AA71 /* CKKSGroupOperation.m */; }; DCD0676E1D8CDECD007602F1 /* gkmerge in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCD067631D8CDEB2007602F1 /* gkmerge */; }; DCD0676F1D8CDED1007602F1 /* gkhandmake in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCD067641D8CDEB2007602F1 /* gkhandmake */; }; DCD067701D8CDED5007602F1 /* gklist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCD067651D8CDEB2007602F1 /* gklist */; }; @@ -2941,7 +3439,6 @@ DCD068221D8CDF7E007602F1 /* SecCodeSigner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067971D8CDF7E007602F1 /* SecCodeSigner.cpp */; }; DCD068231D8CDF7E007602F1 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067981D8CDF7E007602F1 /* SecCodeHost.h */; }; DCD068241D8CDF7E007602F1 /* SecCodeHost.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067991D8CDF7E007602F1 /* SecCodeHost.cpp */; }; - DCD068251D8CDF7E007602F1 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0679A1D8CDF7E007602F1 /* SecIntegrity.h */; }; DCD068271D8CDF7E007602F1 /* cs.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0679D1D8CDF7E007602F1 /* cs.h */; }; DCD068281D8CDF7E007602F1 /* cs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD0679E1D8CDF7E007602F1 /* cs.cpp */; }; DCD068291D8CDF7E007602F1 /* Code.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0679F1D8CDF7E007602F1 /* Code.h */; }; @@ -3006,7 +3503,6 @@ DCD068641D8CDF7E007602F1 /* detachedrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067E11D8CDF7E007602F1 /* detachedrep.cpp */; }; DCD068651D8CDF7E007602F1 /* piddiskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067E21D8CDF7E007602F1 /* piddiskrep.h */; }; DCD068661D8CDF7E007602F1 /* piddiskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067E31D8CDF7E007602F1 /* piddiskrep.cpp */; }; - DCD068671D8CDF7E007602F1 /* SecIntegrityLib.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067E51D8CDF7E007602F1 /* SecIntegrityLib.h */; }; DCD068691D8CDF7E007602F1 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067E71D8CDF7E007602F1 /* SecCodeHostLib.h */; }; DCD0686E1D8CDF7E007602F1 /* csdatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067EE1D8CDF7E007602F1 /* csdatabase.h */; }; DCD0686F1D8CDF7E007602F1 /* csdatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD067EF1D8CDF7E007602F1 /* csdatabase.cpp */; }; @@ -3027,7 +3523,6 @@ DCD0687E1D8CDF7E007602F1 /* antlrplugin.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067FF1D8CDF7E007602F1 /* antlrplugin.h */; }; DCD0687F1D8CDF7E007602F1 /* antlrplugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD068001D8CDF7E007602F1 /* antlrplugin.cpp */; }; DCD068811D8CDF7E007602F1 /* SecTaskPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */; }; - DCD068821D8CDF7E007602F1 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD068041D8CDF7E007602F1 /* SecTask.c */; }; DCD068831D8CDF7E007602F1 /* SecAssessment.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD068061D8CDF7E007602F1 /* SecAssessment.h */; }; DCD068841D8CDF7E007602F1 /* SecAssessment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD068071D8CDF7E007602F1 /* SecAssessment.cpp */; }; DCD068851D8CDF7E007602F1 /* evaluationmanager.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD068081D8CDF7E007602F1 /* evaluationmanager.h */; }; @@ -3119,8 +3614,6 @@ DCD069431D8CDFFF007602F1 /* TokenStreamRewriteEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD068EF1D8CDFFE007602F1 /* TokenStreamRewriteEngine.cpp */; }; DCD069441D8CDFFF007602F1 /* TokenStreamSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD068F01D8CDFFE007602F1 /* TokenStreamSelector.cpp */; }; DCD069451D8CDFFF007602F1 /* TreeParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD068F11D8CDFFE007602F1 /* TreeParser.cpp */; }; - DCD06A401D8CE245007602F1 /* SecIntegrityLib.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD067E61D8CDF7E007602F1 /* SecIntegrityLib.c */; }; - DCD06A411D8CE251007602F1 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0679A1D8CDF7E007602F1 /* SecIntegrity.h */; }; DCD06A521D8CE29C007602F1 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067E71D8CDF7E007602F1 /* SecCodeHostLib.h */; }; DCD06A531D8CE2A4007602F1 /* SecCodeHostLib.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD067E81D8CDF7E007602F1 /* SecCodeHostLib.c */; }; DCD06A751D8CE2F0007602F1 /* gkunpack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD0676B1D8CDEB2007602F1 /* gkunpack.cpp */; }; @@ -3161,9 +3654,6 @@ DCD06B5B1D8E0D7D007602F1 /* globalizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06ACF1D8E0D7D007602F1 /* globalizer.cpp */; }; DCD06B5C1D8E0D7D007602F1 /* hashing.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AD01D8E0D7D007602F1 /* hashing.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B5D1D8E0D7D007602F1 /* hashing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AD11D8E0D7D007602F1 /* hashing.cpp */; }; - DCD06B5E1D8E0D7D007602F1 /* iodevices.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AD21D8E0D7D007602F1 /* iodevices.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06B5F1D8E0D7D007602F1 /* iodevices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AD31D8E0D7D007602F1 /* iodevices.cpp */; }; - DCD06B601D8E0D7D007602F1 /* ktracecodes.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AD41D8E0D7D007602F1 /* ktracecodes.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B611D8E0D7D007602F1 /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AD51D8E0D7D007602F1 /* logging.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B621D8E0D7D007602F1 /* logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AD61D8E0D7D007602F1 /* logging.cpp */; }; DCD06B631D8E0D7D007602F1 /* memstreams.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AD71D8E0D7D007602F1 /* memstreams.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -3195,23 +3685,15 @@ DCD06B7D1D8E0D7D007602F1 /* trackingallocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AF11D8E0D7D007602F1 /* trackingallocator.cpp */; }; DCD06B7E1D8E0D7D007602F1 /* transactions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AF21D8E0D7D007602F1 /* transactions.cpp */; }; DCD06B7F1D8E0D7D007602F1 /* transactions.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AF31D8E0D7D007602F1 /* transactions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06B801D8E0D7D007602F1 /* typedvalue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AF41D8E0D7D007602F1 /* typedvalue.cpp */; }; - DCD06B811D8E0D7D007602F1 /* typedvalue.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AF51D8E0D7D007602F1 /* typedvalue.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B821D8E0D7D007602F1 /* utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AF61D8E0D7D007602F1 /* utilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B831D8E0D7D007602F1 /* utilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AF71D8E0D7D007602F1 /* utilities.cpp */; }; DCD06B841D8E0D7D007602F1 /* utility_config.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AF81D8E0D7D007602F1 /* utility_config.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06B851D8E0D7D007602F1 /* fdmover.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AF91D8E0D7D007602F1 /* fdmover.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06B861D8E0D7D007602F1 /* fdmover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AFA1D8E0D7D007602F1 /* fdmover.cpp */; }; - DCD06B871D8E0D7D007602F1 /* fdsel.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AFB1D8E0D7D007602F1 /* fdsel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06B881D8E0D7D007602F1 /* fdsel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AFC1D8E0D7D007602F1 /* fdsel.cpp */; }; DCD06B891D8E0D7D007602F1 /* kq++.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AFD1D8E0D7D007602F1 /* kq++.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B8A1D8E0D7D007602F1 /* kq++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06AFE1D8E0D7D007602F1 /* kq++.cpp */; }; DCD06B8B1D8E0D7D007602F1 /* muscle++.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06AFF1D8E0D7D007602F1 /* muscle++.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B8C1D8E0D7D007602F1 /* muscle++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B001D8E0D7D007602F1 /* muscle++.cpp */; }; DCD06B8D1D8E0D7D007602F1 /* pcsc++.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B011D8E0D7D007602F1 /* pcsc++.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B8E1D8E0D7D007602F1 /* pcsc++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B021D8E0D7D007602F1 /* pcsc++.cpp */; }; - DCD06B8F1D8E0D7D007602F1 /* selector.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B031D8E0D7D007602F1 /* selector.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06B901D8E0D7D007602F1 /* selector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B041D8E0D7D007602F1 /* selector.cpp */; }; DCD06B911D8E0D7D007602F1 /* unix++.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B051D8E0D7D007602F1 /* unix++.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06B921D8E0D7D007602F1 /* unix++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B061D8E0D7D007602F1 /* unix++.cpp */; }; DCD06B931D8E0D7D007602F1 /* unixchild.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B071D8E0D7D007602F1 /* unixchild.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -3241,26 +3723,6 @@ DCD06BAB1D8E0D7D007602F1 /* cfmunge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B211D8E0D7D007602F1 /* cfmunge.cpp */; }; DCD06BAC1D8E0D7D007602F1 /* cfutilities.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B221D8E0D7D007602F1 /* cfutilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06BAD1D8E0D7D007602F1 /* cfutilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B231D8E0D7D007602F1 /* cfutilities.cpp */; }; - DCD06BAE1D8E0D7D007602F1 /* bufferfifo.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B251D8E0D7D007602F1 /* bufferfifo.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BAF1D8E0D7D007602F1 /* bufferfifo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B261D8E0D7D007602F1 /* bufferfifo.cpp */; }; - DCD06BB01D8E0D7D007602F1 /* buffers.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B271D8E0D7D007602F1 /* buffers.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BB11D8E0D7D007602F1 /* buffers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B281D8E0D7D007602F1 /* buffers.cpp */; }; - DCD06BB21D8E0D7D007602F1 /* headermap.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B291D8E0D7D007602F1 /* headermap.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BB31D8E0D7D007602F1 /* headermap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B2A1D8E0D7D007602F1 /* headermap.cpp */; }; - DCD06BB41D8E0D7D007602F1 /* hosts.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B2B1D8E0D7D007602F1 /* hosts.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BB51D8E0D7D007602F1 /* hosts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B2C1D8E0D7D007602F1 /* hosts.cpp */; }; - DCD06BB61D8E0D7D007602F1 /* inetreply.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B2D1D8E0D7D007602F1 /* inetreply.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BB71D8E0D7D007602F1 /* inetreply.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B2E1D8E0D7D007602F1 /* inetreply.cpp */; }; - DCD06BB81D8E0D7D007602F1 /* ip++.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B2F1D8E0D7D007602F1 /* ip++.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BB91D8E0D7D007602F1 /* ip++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B301D8E0D7D007602F1 /* ip++.cpp */; }; - DCD06BBA1D8E0D7D007602F1 /* url.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B311D8E0D7D007602F1 /* url.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BBB1D8E0D7D007602F1 /* url.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B321D8E0D7D007602F1 /* url.cpp */; }; - DCD06BBC1D8E0D7D007602F1 /* socks++.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B331D8E0D7D007602F1 /* socks++.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BBD1D8E0D7D007602F1 /* socks++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B341D8E0D7D007602F1 /* socks++.cpp */; }; - DCD06BBE1D8E0D7D007602F1 /* socks++4.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B351D8E0D7D007602F1 /* socks++4.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BBF1D8E0D7D007602F1 /* socks++4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B361D8E0D7D007602F1 /* socks++4.cpp */; }; - DCD06BC01D8E0D7D007602F1 /* socks++5.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06B371D8E0D7D007602F1 /* socks++5.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCD06BC11D8E0D7D007602F1 /* socks++5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCD06B381D8E0D7D007602F1 /* socks++5.cpp */; }; DCD06BC41D8E0DC2007602F1 /* utilities_dtrace.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD06BC21D8E0DC2007602F1 /* utilities_dtrace.h */; settings = {ATTRIBUTES = (Public, ); }; }; DCD06BD01D8E15BB007602F1 /* libsecurity_keychain.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCB342411D8A32820054D16E /* libsecurity_keychain.a */; }; DCD06BD11D8E15ED007602F1 /* libsecurity_pkcs12.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BC96D1D8B810A00070CB0 /* libsecurity_pkcs12.a */; }; @@ -3290,7 +3752,6 @@ DCD22D5F1D8CC294001C9B81 /* libsecurity_ssl_regressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCA1A1D8B82B000070CB0 /* libsecurity_ssl_regressions.a */; }; DCD22D601D8CC2EF001C9B81 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; DCD22D611D8CC2F8001C9B81 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 107227350D91FE89003CF14F /* libbsm.dylib */; }; - DCD22D621D8CC326001C9B81 /* libSecItemShimOSX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EE6E1D80D82600B0A59C /* libSecItemShimOSX.a */; }; DCD22D631D8CC33A001C9B81 /* libSOSRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC681D80D0C400B0A59C /* libSOSRegressions.a */; }; DCD22D641D8CC341001C9B81 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DCD22D651D8CC349001C9B81 /* libutilitiesRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCD481D8C694700070CB0 /* libutilitiesRegressions.a */; }; @@ -3303,8 +3764,6 @@ DCD22D701D8CC733001C9B81 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DCD22D711D8CC78E001C9B81 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; DCD22D721D8CC804001C9B81 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; }; - DCD22D731D8CC828001C9B81 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; }; - DCD22D741D8CC85E001C9B81 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; DCD22D751D8CC8A5001C9B81 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DCD22D761D8CC8CF001C9B81 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DCD22D771D8CC9CD001C9B81 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; @@ -3312,11 +3771,11 @@ DCD22D791D8CC9F1001C9B81 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DCD22D801D8CCB0F001C9B81 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DCD22D851D8CCBB6001C9B81 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DCD22D861D8CCBBB001C9B81 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DCD22D861D8CCBBB001C9B81 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DCD22D871D8CCBEA001C9B81 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; settings = {ATTRIBUTES = (Weak, ); }; }; - DCD22D881D8CCBEF001C9B81 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; settings = {ATTRIBUTES = (Weak, ); }; }; + DCD22D881D8CCBEF001C9B81 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; settings = {ATTRIBUTES = (Weak, ); }; }; DCD22D891D8CCC1F001C9B81 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; - DCD22D8A1D8CCC23001C9B81 /* libSecureObjectSync.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; }; + DCD22D8A1D8CCC23001C9B81 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; DCD22D8B1D8CCC58001C9B81 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; DCD22D8C1D8CCC63001C9B81 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DCD22D8D1D8CCC79001C9B81 /* libregressionBase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCBFD1D8C648C00070CB0 /* libregressionBase.a */; }; @@ -3333,6 +3792,11 @@ DCD22D9A1D8CCFC1001C9B81 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; DCD22D9B1D8CCFCB001C9B81 /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; DCD22D9C1D8CCFD6001C9B81 /* libutilitiesRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCD481D8C694700070CB0 /* libutilitiesRegressions.a */; }; + DCD3EABA1DB599B800DF59BE /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; }; + DCD662F51E329B6800188186 /* CKKSNewTLKOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD662F31E329B6800188186 /* CKKSNewTLKOperation.h */; }; + DCD662F61E329B6800188186 /* CKKSNewTLKOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD662F31E329B6800188186 /* CKKSNewTLKOperation.h */; }; + DCD662F71E329B6800188186 /* CKKSNewTLKOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD662F41E329B6800188186 /* CKKSNewTLKOperation.m */; }; + DCD662F81E329B6800188186 /* CKKSNewTLKOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD662F41E329B6800188186 /* CKKSNewTLKOperation.m */; }; DCD66DB21D8204F500DB1393 /* SecSignatureVerificationSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E8E1D8085FC00865A7C /* SecSignatureVerificationSupport.c */; }; DCD66DB31D8204FB00DB1393 /* SecServerEncryptionSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E8A1D8085FC00865A7C /* SecServerEncryptionSupport.c */; }; DCD66DB41D82050000DB1393 /* SecRSAKey.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E851D8085FC00865A7C /* SecRSAKey.c */; }; @@ -3357,9 +3821,130 @@ DCD66DE21D8205FB00DB1393 /* SecOTRPublicIdentity.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E741D8085FC00865A7C /* SecOTRPublicIdentity.c */; }; DCD66DE31D8205FB00DB1393 /* SecOTRSession.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E751D8085FC00865A7C /* SecOTRSession.c */; }; DCD66DE41D8205FB00DB1393 /* SecOTRSessionAKE.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E771D8085FC00865A7C /* SecOTRSessionAKE.c */; }; + DCD6C4B21EC5302500414FEE /* CKKSNearFutureScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD6C4B01EC5302400414FEE /* CKKSNearFutureScheduler.h */; }; + DCD6C4B31EC5302500414FEE /* CKKSNearFutureScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD6C4B01EC5302400414FEE /* CKKSNearFutureScheduler.h */; }; + DCD6C4B41EC5302500414FEE /* CKKSNearFutureScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD6C4B11EC5302500414FEE /* CKKSNearFutureScheduler.m */; }; + DCD6C4B51EC5302500414FEE /* CKKSNearFutureScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD6C4B11EC5302500414FEE /* CKKSNearFutureScheduler.m */; }; + DCD6C4B71EC5319600414FEE /* CKKSNearFutureSchedulerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD6C4B61EC5319600414FEE /* CKKSNearFutureSchedulerTests.m */; }; + DCD8A0CF1E09EA1800E4FA0A /* SecKeybagSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9E1D8085D800865A7C /* SecKeybagSupport.c */; }; + DCD8A1321E09EE0F00E4FA0A /* SOSPeerInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D631D8085F200865A7C /* SOSPeerInfo.m */; }; + DCD8A1511E09EE0F00E4FA0A /* SOSViews.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D4A1D8085F200865A7C /* SOSViews.m */; }; + DCD8A15A1E09EE0F00E4FA0A /* SOSAccountTransaction.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D151D8085F200865A7C /* SOSAccountTransaction.h */; }; + DCD8A15C1E09EE0F00E4FA0A /* SOSBackupSliceKeyBag.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D2A1D8085F200865A7C /* SOSBackupSliceKeyBag.h */; }; + DCD8A15D1E09EE0F00E4FA0A /* SOSCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D321D8085F200865A7C /* SOSCircle.h */; }; + DCD8A15E1E09EE0F00E4FA0A /* SOSCircleDer.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D341D8085F200865A7C /* SOSCircleDer.h */; }; + DCD8A15F1E09EE0F00E4FA0A /* SOSCirclePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D311D8085F200865A7C /* SOSCirclePriv.h */; }; + DCD8A1601E09EE0F00E4FA0A /* SOSCircleRings.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D331D8085F200865A7C /* SOSCircleRings.h */; }; + DCD8A1611E09EE0F00E4FA0A /* SOSCircleV2.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D301D8085F200865A7C /* SOSCircleV2.h */; }; + DCD8A1621E09EE0F00E4FA0A /* SOSCloudCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8A1D8085F200865A7C /* SOSCloudCircle.h */; }; + DCD8A1631E09EE0F00E4FA0A /* SOSCloudCircleInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8B1D8085F200865A7C /* SOSCloudCircleInternal.h */; }; + DCD8A1641E09EE0F00E4FA0A /* SOSCloudKeychainClient.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78CF71D8085F200865A7C /* SOSCloudKeychainClient.h */; }; + DCD8A1651E09EE0F00E4FA0A /* SOSCloudKeychainConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78CF91D8085F200865A7C /* SOSCloudKeychainConstants.h */; }; + DCD8A1661E09EE0F00E4FA0A /* SOSRingRecovery.h in Headers */ = {isa = PBXBuildFile; fileRef = 48776C7D1DA5BB5F00CC09B9 /* SOSRingRecovery.h */; }; + DCD8A16C1E09EE0F00E4FA0A /* SOSFullPeerInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D621D8085F200865A7C /* SOSFullPeerInfo.h */; }; + DCD8A16D1E09EE0F00E4FA0A /* SOSGenCount.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D381D8085F200865A7C /* SOSGenCount.h */; }; + DCD8A16E1E09EE0F00E4FA0A /* SOSInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8E1D8085F200865A7C /* SOSInternal.h */; }; + DCD8A16F1E09EE0F00E4FA0A /* SOSKVSKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D731D8085F200865A7C /* SOSKVSKeys.h */; }; + DCD8A1741E09EE0F00E4FA0A /* SOSPeerInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D641D8085F200865A7C /* SOSPeerInfo.h */; }; + DCD8A17C1E09EE0F00E4FA0A /* SOSPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D901D8085F200865A7C /* SOSPlatform.h */; }; + DCD8A17D1E09EE0F00E4FA0A /* SOSRing.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D391D8085F200865A7C /* SOSRing.h */; }; + DCD8A17E1E09EE0F00E4FA0A /* SOSRingBackup.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D3B1D8085F200865A7C /* SOSRingBackup.h */; }; + DCD8A17F1E09EE0F00E4FA0A /* SOSKeyedPubKeyIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 485B64091DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h */; }; + DCD8A1801E09EE0F00E4FA0A /* SOSRingBasic.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D3D1D8085F200865A7C /* SOSRingBasic.h */; }; + DCD8A1821E09EE0F00E4FA0A /* SOSAccountGhost.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFAEDC91D999851005187E4 /* SOSAccountGhost.h */; }; + DCD8A1831E09EE0F00E4FA0A /* SOSRingConcordanceTrust.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D3F1D8085F200865A7C /* SOSRingConcordanceTrust.h */; }; + DCD8A1841E09EE0F00E4FA0A /* SOSRecoveryKeyBag.h in Headers */ = {isa = PBXBuildFile; fileRef = 48776C741DA5BB4200CC09B9 /* SOSRecoveryKeyBag.h */; }; + DCD8A1851E09EE0F00E4FA0A /* SOSRingDER.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D411D8085F200865A7C /* SOSRingDER.h */; }; + DCD8A1861E09EE0F00E4FA0A /* SOSRingPeerInfoUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D431D8085F200865A7C /* SOSRingPeerInfoUtils.h */; }; + DCD8A1871E09EE0F00E4FA0A /* SOSRingTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D451D8085F200865A7C /* SOSRingTypes.h */; }; + DCD8A1881E09EE0F00E4FA0A /* SOSAccountPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = CD9021471DE27A9E00F81DC4 /* SOSAccountPriv.h */; }; + DCD8A1891E09EE0F00E4FA0A /* SOSRingUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D471D8085F200865A7C /* SOSRingUtils.h */; }; + DCD8A18A1E09EE0F00E4FA0A /* SOSRingV0.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D491D8085F200865A7C /* SOSRingV0.h */; }; + DCD8A18B1E09EE0F00E4FA0A /* SOSTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D751D8085F200865A7C /* SOSTransport.h */; }; + DCD8A1901E09EE0F00E4FA0A /* SOSAccountTrust.h in Headers */ = {isa = PBXBuildFile; fileRef = CD31F8611DCD4C1400414B46 /* SOSAccountTrust.h */; }; + DCD8A1931E09EE0F00E4FA0A /* SOSTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D8F1D8085F200865A7C /* SOSTypes.h */; }; + DCD8A1941E09EE0F00E4FA0A /* SOSUserKeygen.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D2C1D8085F200865A7C /* SOSUserKeygen.h */; }; + DCD8A1951E09EE0F00E4FA0A /* SOSViews.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D4B1D8085F200865A7C /* SOSViews.h */; }; + DCD8A19A1E09EE9800E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A19D1E09EEC800E4FA0A /* SOSBackupSliceKeyBag.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D291D8085F200865A7C /* SOSBackupSliceKeyBag.m */; }; + DCD8A19E1E09EEDA00E4FA0A /* SecRecoveryKey.m in Sources */ = {isa = PBXBuildFile; fileRef = EB6928BF1D9C9C5900062A18 /* SecRecoveryKey.m */; }; + DCD8A19F1E09EF0F00E4FA0A /* SOSInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D8D1D8085F200865A7C /* SOSInternal.m */; }; + DCD8A1A01E09EF3500E4FA0A /* SOSCloudKeychainClient.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CF61D8085F200865A7C /* SOSCloudKeychainClient.c */; }; + DCD8A1A11E09EF5C00E4FA0A /* SOSCloudKeychainConstants.c in Sources */ = {isa = PBXBuildFile; fileRef = E7A5F4D71C0D01B000F3BEBB /* SOSCloudKeychainConstants.c */; }; + DCD8A1A31E09EF7800E4FA0A /* SOSSysdiagnose.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D8C1D8085F200865A7C /* SOSSysdiagnose.m */; }; + DCD8A1A41E09EF9000E4FA0A /* SOSPeerInfoCollections.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D6A1D8085F200865A7C /* SOSPeerInfoCollections.c */; }; + DCD8A1A51E09EFAE00E4FA0A /* SOSPeerInfoV2.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D671D8085F200865A7C /* SOSPeerInfoV2.m */; }; + DCD8A1A61E09EFD700E4FA0A /* SOSKVSKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D721D8085F200865A7C /* SOSKVSKeys.m */; }; + DCD8A1A71E09F01300E4FA0A /* SOSPeerInfoSecurityProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D6F1D8085F200865A7C /* SOSPeerInfoSecurityProperties.m */; }; + DCD8A1A81E09F03100E4FA0A /* SOSUserKeygen.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D2B1D8085F200865A7C /* SOSUserKeygen.m */; }; + DCD8A1A91E09F04700E4FA0A /* SOSECWrapUnwrap.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D881D8085F200865A7C /* SOSECWrapUnwrap.c */; }; + DCD8A1AC1E09F09200E4FA0A /* SOSCircleDer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D351D8085F200865A7C /* SOSCircleDer.c */; }; + DCD8A1AE1E09F0C500E4FA0A /* SOSRingDER.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D401D8085F200865A7C /* SOSRingDER.c */; }; + DCD8A1AF1E09F0DC00E4FA0A /* SOSRingUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D461D8085F200865A7C /* SOSRingUtils.c */; }; + DCD8A1B01E09F0F400E4FA0A /* SOSRingTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D441D8085F200865A7C /* SOSRingTypes.m */; }; + DCD8A1B11E09F11900E4FA0A /* SOSPeerInfoDER.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D651D8085F200865A7C /* SOSPeerInfoDER.m */; }; + DCD8A1B21E09F11900E4FA0A /* SOSPeerInfoRingState.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D6D1D8085F200865A7C /* SOSPeerInfoRingState.m */; }; + DCD8A1B31E09F12D00E4FA0A /* SOSCircle.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D2E1D8085F200865A7C /* SOSCircle.c */; }; + DCD8A1B41E09F12D00E4FA0A /* SOSCircleV2.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D2F1D8085F200865A7C /* SOSCircleV2.c */; }; + DCD8A1B51E09F15400E4FA0A /* SOSGenCount.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D371D8085F200865A7C /* SOSGenCount.c */; }; + DCD8A1B61E09F16C00E4FA0A /* SOSKeyedPubKeyIdentifier.c in Sources */ = {isa = PBXBuildFile; fileRef = 485B64081DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.c */; }; + DCD8A1B71E09F19100E4FA0A /* SOSRingV0.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D481D8085F200865A7C /* SOSRingV0.m */; }; + DCD8A1B81E09F1BB00E4FA0A /* SOSRingBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D3A1D8085F200865A7C /* SOSRingBackup.m */; }; + DCD8A1B91E09F1BB00E4FA0A /* SOSRingBasic.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D3C1D8085F200865A7C /* SOSRingBasic.m */; }; + DCD8A1BA1E09F1BB00E4FA0A /* SOSRingRecovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.m */; }; + DCD8A1BB1E09F1BB00E4FA0A /* SOSRingConcordanceTrust.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D3E1D8085F200865A7C /* SOSRingConcordanceTrust.c */; }; + DCD8A1BC1E09F1BB00E4FA0A /* SOSRingPeerInfoUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D421D8085F200865A7C /* SOSRingPeerInfoUtils.c */; }; + DCD8A1BD1E09F1D600E4FA0A /* SOSFullPeerInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D611D8085F200865A7C /* SOSFullPeerInfo.m */; }; + DCD8A1C21E09F23B00E4FA0A /* SOSRecoveryKeyBag.m in Sources */ = {isa = PBXBuildFile; fileRef = 48776C731DA5BB4200CC09B9 /* SOSRecoveryKeyBag.m */; }; + DCD8A1C71E09F2B400E4FA0A /* SOSTransport.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D741D8085F200865A7C /* SOSTransport.m */; }; + DCD8A1DA1E09F54700E4FA0A /* SOSAccountDer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1C1D8085F200865A7C /* SOSAccountDer.m */; }; + DCD8A1DB1E09F5D100E4FA0A /* SOSAccountTrust.m in Sources */ = {isa = PBXBuildFile; fileRef = CD31F8601DCD4C1400414B46 /* SOSAccountTrust.m */; }; + DCD8A1DC1E09F5E500E4FA0A /* SOSAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D131D8085F200865A7C /* SOSAccount.h */; }; + DCD8A1DD1E09F73F00E4FA0A /* SOSPeerInfoDER.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D661D8085F200865A7C /* SOSPeerInfoDER.h */; }; + DCD8A1DE1E09F74700E4FA0A /* SOSPeerInfoV2.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D681D8085F200865A7C /* SOSPeerInfoV2.h */; }; + DCD8A1DF1E09F76000E4FA0A /* SOSPeerInfoCollections.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D6B1D8085F200865A7C /* SOSPeerInfoCollections.h */; }; + DCD8A1E01E09F76800E4FA0A /* SOSPeerInfoRingState.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D6E1D8085F200865A7C /* SOSPeerInfoRingState.h */; }; + DCD8A1E11E09F76D00E4FA0A /* SOSPeerInfoSecurityProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D701D8085F200865A7C /* SOSPeerInfoSecurityProperties.h */; }; + DCD8A1E21E09F78A00E4FA0A /* SOSTransportCircle.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78D791D8085F200865A7C /* SOSTransportCircle.h */; }; + DCD8A1E31E09F7E700E4FA0A /* SOSAccountCloudParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D1A1D8085F200865A7C /* SOSAccountCloudParameters.m */; }; + DCD8A1E41E09F80B00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1E71E09F85400E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1EA1E09F87B00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1ED1E09F8B500E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1F01E09F8D100E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1F31E09F91700E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1F61E09F96900E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1F91E09F98E00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1FC1E09FA0B00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A1FF1E09FA6100E4FA0A /* secViewDisplay.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9E1D8085F200865A7C /* secViewDisplay.c */; }; + DCD8A2001E09FA7900E4FA0A /* secToolFileIO.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D931D8085F200865A7C /* secToolFileIO.c */; }; + DCD8A2011E09FAD900E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + DCD8A2041E09FB0D00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; + 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 */; }; DCDCC7E31D9B54EE006487E8 /* secd-202-recoverykey.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDCC7DD1D9B54DF006487E8 /* secd-202-recoverykey.m */; }; - DCDCC7E51D9B5526006487E8 /* SOSAccountSync.c in Sources */ = {isa = PBXBuildFile; fileRef = DCDCC7E41D9B551C006487E8 /* SOSAccountSync.c */; }; + DCDCC7E51D9B5526006487E8 /* SOSAccountSync.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDCC7E41D9B551C006487E8 /* SOSAccountSync.m */; }; + DCDCC8331D9B6A00006487E8 /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; + DCDCCB361DF25C8D006E840E /* ApplePushService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */; }; + DCDCCB371DF25CE5006E840E /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA311DEE768000D0F733 /* CloudKit.framework */; }; + DCDCCB381DF25CEE006E840E /* ApplePushService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */; }; + 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 */; }; + 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 */; }; DCDF0A4F1D81D76F007AF174 /* Security.exp-in in Sources */ = {isa = PBXBuildFile; fileRef = 4CB7405F0A47498100D641BB /* Security.exp-in */; }; + DCE278DD1ED789EF0083B485 /* CKKSCurrentItemPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = DCE278DB1ED789EF0083B485 /* CKKSCurrentItemPointer.h */; }; + DCE278DE1ED789EF0083B485 /* CKKSCurrentItemPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = DCE278DB1ED789EF0083B485 /* CKKSCurrentItemPointer.h */; }; + DCE278DF1ED789EF0083B485 /* CKKSCurrentItemPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE278DC1ED789EF0083B485 /* CKKSCurrentItemPointer.m */; }; + DCE278E01ED789EF0083B485 /* CKKSCurrentItemPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE278DC1ED789EF0083B485 /* CKKSCurrentItemPointer.m */; }; + DCE278E81ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCE278E61ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h */; }; + DCE278E91ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCE278E61ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h */; }; + DCE278EA1ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE278E71ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m */; }; + DCE278EB1ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE278E71ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m */; }; DCE4E6921D7A37FA00AFB96E /* security_tool_commands.c in Sources */ = {isa = PBXBuildFile; fileRef = E7104A0B169E171900DB0045 /* security_tool_commands.c */; }; DCE4E6931D7A37FA00AFB96E /* NSFileHandle+Formatting.m in Sources */ = {isa = PBXBuildFile; fileRef = E78A9AD91D34959200006B5B /* NSFileHandle+Formatting.m */; }; DCE4E6961D7A37FA00AFB96E /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; @@ -3452,38 +4037,19 @@ DCE4E7EC1D7A4BB800AFB96E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; DCE4E7EF1D7A4BCB00AFB96E /* libaks.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB2CA4D81D2C28C800AB770F /* libaks.a */; }; DCE4E8071D7A4DE200AFB96E /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = 790850840CA87CF00083CC4D /* server.c */; }; - DCE4E80A1D7A4E1D00AFB96E /* com.apple.secd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */; }; - DCE4E80E1D7A4E3B00AFB96E /* com.apple.securityd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */; }; + DCE4E80A1D7A4E1D00AFB96E /* com.apple.secd.plist in Copy LaunchAgents files */ = {isa = PBXBuildFile; fileRef = DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */; }; + DCE4E80E1D7A4E3B00AFB96E /* com.apple.securityd.plist in Copy Logging Files */ = {isa = PBXBuildFile; fileRef = DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */; }; DCE4E80F1D7A4E4600AFB96E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; DCE4E8121D7A4E4F00AFB96E /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789261D7799D300B50D50 /* IOKit.framework */; }; DCE4E8131D7A4E5300AFB96E /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789241D7799CD00B50D50 /* CoreFoundation.framework */; }; - DCE4E8151D7A4E6F00AFB96E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E8141D7A4E6F00AFB96E /* CFNetwork.framework */; }; DCE4E81C1D7A4E8F00AFB96E /* libsqlite3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E81B1D7A4E8F00AFB96E /* libsqlite3.0.dylib */; }; DCE4E81F1D7A4EA700AFB96E /* libctkclient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient.a */; }; DCE4E8201D7A4EAC00AFB96E /* libcoreauthd_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */; }; - DCE4E8211D7A4EB800AFB96E /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789181D77998C00B50D50 /* libbsm.dylib */; }; DCE4E8231D7A4EC900AFB96E /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; }; DCE4E8241D7A4ECD00AFB96E /* libaks.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB2CA4D81D2C28C800AB770F /* libaks.a */; }; DCE4E8251D7A4EE400AFB96E /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3A1D78F228002223DE /* libACM.a */; }; - DCE4E8261D7A4EEC00AFB96E /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789121D7798B300B50D50 /* libDiagnosticMessagesClient.dylib */; }; DCE4E8281D7A4F1600AFB96E /* login.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E8271D7A4F0E00AFB96E /* login.framework */; }; DCE4E82C1D7A56FF00AFB96E /* AppleSystemInfo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3F1D78F2FF002223DE /* AppleSystemInfo.framework */; }; - DCE4E8391D7A57AE00AFB96E /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = 790850840CA87CF00083CC4D /* server.c */; }; - DCE4E83B1D7A57AE00AFB96E /* login.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E8271D7A4F0E00AFB96E /* login.framework */; }; - DCE4E83C1D7A57AE00AFB96E /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789121D7798B300B50D50 /* libDiagnosticMessagesClient.dylib */; }; - DCE4E83D1D7A57AE00AFB96E /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3A1D78F228002223DE /* libACM.a */; }; - DCE4E83E1D7A57AE00AFB96E /* libaks.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB2CA4D81D2C28C800AB770F /* libaks.a */; }; - DCE4E83F1D7A57AE00AFB96E /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; }; - DCE4E8411D7A57AE00AFB96E /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789181D77998C00B50D50 /* libbsm.dylib */; }; - DCE4E8421D7A57AE00AFB96E /* libcoreauthd_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */; }; - DCE4E8431D7A57AE00AFB96E /* libctkclient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient.a */; }; - DCE4E84C1D7A57AE00AFB96E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E8141D7A4E6F00AFB96E /* CFNetwork.framework */; }; - DCE4E84D1D7A57AE00AFB96E /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789241D7799CD00B50D50 /* CoreFoundation.framework */; }; - DCE4E84E1D7A57AE00AFB96E /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789261D7799D300B50D50 /* IOKit.framework */; }; - DCE4E8501D7A57AE00AFB96E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; - DCE4E8511D7A57AE00AFB96E /* AppleSystemInfo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3F1D78F2FF002223DE /* AppleSystemInfo.framework */; }; - DCE4E85F1D7A586200AFB96E /* com.apple.trustd.agent.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCE4E85B1D7A583A00AFB96E /* com.apple.trustd.agent.plist */; }; - DCE4E8601D7A586A00AFB96E /* com.apple.trustd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCE4E85C1D7A584000AFB96E /* com.apple.trustd.plist */; }; DCE4E8B31D7F353900AFB96E /* agent.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8A11D7F353900AFB96E /* agent.c */; }; DCE4E8B41D7F353900AFB96E /* authdb.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8A21D7F353900AFB96E /* authdb.c */; }; DCE4E8B51D7F353900AFB96E /* authitems.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8A31D7F353900AFB96E /* authitems.c */; }; @@ -3492,7 +4058,6 @@ DCE4E8B81D7F353900AFB96E /* ccaudit.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8A61D7F353900AFB96E /* ccaudit.c */; }; DCE4E8B91D7F353900AFB96E /* crc.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8A71D7F353900AFB96E /* crc.c */; }; DCE4E8BA1D7F353900AFB96E /* credential.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8A81D7F353900AFB96E /* credential.c */; }; - DCE4E8BB1D7F353900AFB96E /* debugging.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8A91D7F353900AFB96E /* debugging.c */; }; DCE4E8BC1D7F353900AFB96E /* engine.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8AA1D7F353900AFB96E /* engine.c */; }; DCE4E8BD1D7F353900AFB96E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8AB1D7F353900AFB96E /* main.c */; }; DCE4E8BE1D7F353900AFB96E /* mechanism.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E8AC1D7F353900AFB96E /* mechanism.c */; }; @@ -3544,8 +4109,19 @@ DCE4E9491D7F3E8E00AFB96E /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DCE4E9441D7F3E8700AFB96E /* Localizable.strings */; }; DCE4E94A1D7F3E8E00AFB96E /* com.apple.security.keychain-circle-notification.plist in Resources */ = {isa = PBXBuildFile; fileRef = DCE4E9461D7F3E8700AFB96E /* com.apple.security.keychain-circle-notification.plist */; }; DCE4E94B1D7F3E8E00AFB96E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DCE4E9471D7F3E8700AFB96E /* InfoPlist.strings */; }; - DCE4E9711D7F3EBB00AFB96E /* com.apple.security.keychain-circle-notification.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCE4E9461D7F3E8700AFB96E /* com.apple.security.keychain-circle-notification.plist */; }; + DCE4E9711D7F3EBB00AFB96E /* com.apple.security.keychain-circle-notification.plist in Install launchd plist */ = {isa = PBXBuildFile; fileRef = DCE4E9461D7F3E8700AFB96E /* com.apple.security.keychain-circle-notification.plist */; }; + DCE7F2091F21726500DDB0F7 /* CKKSAPSReceiverTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE7F2081F21726500DDB0F7 /* CKKSAPSReceiverTests.m */; }; DCE809F31D9342BE00F91177 /* com.apple.securityd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCEE1E851D93424D00DC0EB7 /* com.apple.securityd.plist */; }; + DCEA5D551E2826DB0089CF55 /* CKKSSIV.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEA5D531E2826DB0089CF55 /* CKKSSIV.h */; }; + DCEA5D561E2826DB0089CF55 /* CKKSSIV.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEA5D531E2826DB0089CF55 /* CKKSSIV.h */; }; + DCEA5D571E2826DB0089CF55 /* CKKSSIV.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D541E2826DB0089CF55 /* CKKSSIV.m */; }; + DCEA5D581E2826DB0089CF55 /* CKKSSIV.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D541E2826DB0089CF55 /* CKKSSIV.m */; }; + DCEA5D851E2F14810089CF55 /* CKKSAPSReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEA5D831E2F14810089CF55 /* CKKSAPSReceiver.h */; }; + DCEA5D861E2F14810089CF55 /* CKKSAPSReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEA5D831E2F14810089CF55 /* CKKSAPSReceiver.h */; }; + DCEA5D871E2F14810089CF55 /* CKKSAPSReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D841E2F14810089CF55 /* CKKSAPSReceiver.m */; }; + DCEA5D881E2F14810089CF55 /* CKKSAPSReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D841E2F14810089CF55 /* CKKSAPSReceiver.m */; }; + DCEA5D971E3015830089CF55 /* CKKSZone.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D961E3014250089CF55 /* CKKSZone.m */; }; + DCEA5D981E3015840089CF55 /* 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 */; }; @@ -3866,11 +4442,32 @@ DCF789431D88CD6700E694BB /* tpTime.c in Sources */ = {isa = PBXBuildFile; fileRef = DCF788F91D88CD4200E694BB /* tpTime.c */; }; DCF789441D88CD6700E694BB /* tpTime.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF788FA1D88CD4200E694BB /* tpTime.h */; }; DCF789481D88D17C00E694BB /* AppleX509TPBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCF789471D88D17C00E694BB /* AppleX509TPBuiltin.cpp */; }; - DCFAEDCF1D999859005187E4 /* SOSAccountGhost.c in Sources */ = {isa = PBXBuildFile; fileRef = DCFAEDC81D999851005187E4 /* SOSAccountGhost.c */; }; - DCFAEDD01D999863005187E4 /* SOSAccountGhost.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFAEDC91D999851005187E4 /* SOSAccountGhost.h */; }; - DCFAEDD21D99991F005187E4 /* secd-668-ghosts.c in Sources */ = {isa = PBXBuildFile; fileRef = DCFAEDD11D9998DD005187E4 /* secd-668-ghosts.c */; }; + DCF7A8A01F04502400CABE89 /* CKKSControlProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF7A89F1F04502300CABE89 /* CKKSControlProtocol.h */; }; + DCF7A8A11F04502400CABE89 /* CKKSControlProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF7A89F1F04502300CABE89 /* CKKSControlProtocol.h */; }; + DCF7A8A31F0450EB00CABE89 /* CKKSControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */; }; + DCF7A8A41F0450EB00CABE89 /* CKKSControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */; }; + DCF7A8A51F0451AC00CABE89 /* CKKSControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.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.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C771D8085D800865A7C /* secd-154-engine-backoff.c */; }; + DCFAEDD71D99A4AB005187E4 /* secd-154-engine-backoff.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C771D8085D800865A7C /* secd-154-engine-backoff.m */; }; + DCFB12C51E95A4C000510F5F /* CKKSCKAccountStateTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFB12C31E95A4C000510F5F /* CKKSCKAccountStateTracker.h */; }; + DCFB12C61E95A4C000510F5F /* CKKSCKAccountStateTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFB12C31E95A4C000510F5F /* CKKSCKAccountStateTracker.h */; }; + DCFB12C71E95A4C000510F5F /* CKKSCKAccountStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFB12C41E95A4C000510F5F /* CKKSCKAccountStateTracker.m */; }; + DCFB12C81E95A4C000510F5F /* CKKSCKAccountStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFB12C41E95A4C000510F5F /* CKKSCKAccountStateTracker.m */; }; + DCFE1C271F17E455007640C8 /* CKKSDeviceStateEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFE1C251F17E455007640C8 /* CKKSDeviceStateEntry.h */; }; + DCFE1C281F17E455007640C8 /* CKKSDeviceStateEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFE1C251F17E455007640C8 /* CKKSDeviceStateEntry.h */; }; + DCFE1C291F17E455007640C8 /* CKKSDeviceStateEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C261F17E455007640C8 /* CKKSDeviceStateEntry.m */; }; + DCFE1C2A1F17E455007640C8 /* CKKSDeviceStateEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C261F17E455007640C8 /* CKKSDeviceStateEntry.m */; }; + DCFE1C341F17ECE5007640C8 /* CKKSCondition.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFE1C321F17ECE5007640C8 /* CKKSCondition.h */; }; + DCFE1C351F17ECE5007640C8 /* CKKSCondition.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFE1C321F17ECE5007640C8 /* CKKSCondition.h */; }; + DCFE1C361F17ECE5007640C8 /* CKKSCondition.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C331F17ECE5007640C8 /* CKKSCondition.m */; }; + DCFE1C371F17ECE5007640C8 /* CKKSCondition.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C331F17ECE5007640C8 /* CKKSCondition.m */; }; + DCFE1C3D1F17EFB5007640C8 /* CKKSConditionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C3C1F17EFB5007640C8 /* CKKSConditionTests.m */; }; + DCFE1C511F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFE1C4F1F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h */; }; + DCFE1C521F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFE1C4F1F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h */; }; + DCFE1C531F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C501F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m */; }; + DCFE1C541F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C501F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m */; }; E7104A0C169E171900DB0045 /* security_tool_commands.c in Sources */ = {isa = PBXBuildFile; fileRef = E7104A0B169E171900DB0045 /* security_tool_commands.c */; }; E71454EF1C741E0800B5B20B /* KCError.h in Headers */ = {isa = PBXBuildFile; fileRef = E71454ED1C741E0800B5B20B /* KCError.h */; settings = {ATTRIBUTES = (Private, ); }; }; E71454F01C741E0800B5B20B /* KCError.m in Sources */ = {isa = PBXBuildFile; fileRef = E71454EE1C741E0800B5B20B /* KCError.m */; }; @@ -3882,10 +4479,7 @@ E71F3E4216EA6A6300FAF9B4 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; }; E722E9121CE92DFC005AD94B /* CKDKVSStore.m in Sources */ = {isa = PBXBuildFile; fileRef = E722E9111CE92DFC005AD94B /* CKDKVSStore.m */; }; E72D462B175FBF3E00F70B9B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; }; - E73A7E8B1DC81DF700A5B2D1 /* secd-210-keyinterest.m in Sources */ = {isa = PBXBuildFile; fileRef = E7FE40BD1DC803FD00F0F5B6 /* secd-210-keyinterest.m */; }; - E73A7E8F1DC81E0300A5B2D1 /* CKDSimulatedStore.m in Sources */ = {isa = PBXBuildFile; fileRef = E7FE40C41DC804E400F0F5B6 /* CKDSimulatedStore.m */; }; E73A7E911DC81E0300A5B2D1 /* CKDSimulatedAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = E7FE40C81DC8084600F0F5B6 /* CKDSimulatedAccount.m */; }; - E73A7E921DC81E0F00A5B2D1 /* CKDKVSProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = E7A5F4C71C0CFF3200F3BEBB /* CKDKVSProxy.m */; }; E745836E1BF3CA13001B54A4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; E75C0E821C6FC31D00E6953B /* KCSRPContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E75C0E801C6FC31D00E6953B /* KCSRPContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; E75C0E831C6FC31D00E6953B /* KCSRPContext.m in Sources */ = {isa = PBXBuildFile; fileRef = E75C0E811C6FC31D00E6953B /* KCSRPContext.m */; }; @@ -3896,6 +4490,7 @@ E772FD471CC15EFA00D63E41 /* NSData+SecRandom.m in Sources */ = {isa = PBXBuildFile; fileRef = E772FD461CC15EFA00D63E41 /* NSData+SecRandom.m */; }; E772FD701CC15F1F00D63E41 /* NSData+SecRandom.h in Headers */ = {isa = PBXBuildFile; fileRef = E772FD6F1CC15F1F00D63E41 /* NSData+SecRandom.h */; }; E78A9ADA1D34959200006B5B /* NSFileHandle+Formatting.m in Sources */ = {isa = PBXBuildFile; fileRef = E78A9AD91D34959200006B5B /* NSFileHandle+Formatting.m */; }; + E78CCDC71E737F6700C1CFAA /* SecNSAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = E78CCDC61E737F6700C1CFAA /* SecNSAdditions.m */; }; E794BA6F1C7424D800339A0F /* KCDer.m in Sources */ = {isa = PBXBuildFile; fileRef = E794BA6E1C7424D800339A0F /* KCDer.m */; }; E794BB001C7598F900339A0F /* KCJoiningMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = E794BAFF1C7598F900339A0F /* KCJoiningMessages.m */; }; E794BB011C759B1200339A0F /* KCJoiningMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = E794BAD91C7598E400339A0F /* KCJoiningMessages.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -3921,14 +4516,12 @@ E7C787351DD0FEF90087FC34 /* NSURL+SOSPlistStore.m in Sources */ = {isa = PBXBuildFile; fileRef = E7C787311DD0FED50087FC34 /* NSURL+SOSPlistStore.m */; }; E7D690921652E06A0079537A /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; E7D690A11652E07B0079537A /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; - E7D690A21652E0870079537A /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; E7D848051C6BEFCD0025BB44 /* KCSRPTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E7D848041C6BEFC10025BB44 /* KCSRPTests.m */; }; E7D848561C6C1E830025BB44 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D848541C6C1D9C0025BB44 /* Foundation.framework */; }; E7D8489F1C6C244B0025BB44 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D848541C6C1D9C0025BB44 /* Foundation.framework */; }; E7DC73B71C890F0E0008BF73 /* KeychainCircle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D847C51C6BE9710025BB44 /* KeychainCircle.framework */; }; E7E3EFBA1CBC192A00E79A5D /* KCAccountKCCircleDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E7E3EFB91CBC192A00E79A5D /* KCAccountKCCircleDelegate.m */; }; E7E3EFE31CBC195700E79A5D /* KCAccountKCCircleDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = E7E3EFE21CBC195700E79A5D /* KCAccountKCCircleDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E7E5B55F1DC7ACAE00C03FFB /* SOSAccountGetSet.c in Sources */ = {isa = PBXBuildFile; fileRef = E7E5B55E1DC7ACAE00C03FFB /* SOSAccountGetSet.c */; }; E7EBDEBC1C87C0DB001BAA62 /* KeychainCircle.plist in Install BATS Tests */ = {isa = PBXBuildFile; fileRef = E7CFF7221C8660A000E3484E /* KeychainCircle.plist */; }; E7F480121C729C7B00390FDB /* NSError+KCCreationHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = E7F480111C729C7B00390FDB /* NSError+KCCreationHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; }; E7F480151C73980D00390FDB /* KCJoiningRequestSession.m in Sources */ = {isa = PBXBuildFile; fileRef = E7F480141C73980D00390FDB /* KCJoiningRequestSession.m */; }; @@ -3949,17 +4542,46 @@ E7FEEEFB1332B8300025EB06 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; }; EB0BC93A1C3C791500785842 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EB0BC9671C3C798600785842 /* secedumodetest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB0BC9661C3C794700785842 /* secedumodetest.m */; }; - EB0BF1981D25B4BE000DEF32 /* README in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C4CE9120AF81F0E0056B01D /* README */; }; - EB0BF19A1D25B551000DEF32 /* README in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C4CE9120AF81F0E0056B01D /* README */; }; + EB0DB37D1DCBC99100EAB6AE /* Keychain Circle Notification.8 in Install man8 page */ = {isa = PBXBuildFile; fileRef = EB76B75A1DCB0CDA00C43FBC /* Keychain Circle Notification.8 */; }; + EB1055791E14DF570003C309 /* SecCertificateFuzzer.c in Sources */ = {isa = PBXBuildFile; fileRef = EB10556B1E14DC0F0003C309 /* SecCertificateFuzzer.c */; }; + EB1055831E14E1F90003C309 /* Digisign-Server-ID-Enrich-GTETrust-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7947431C146214E500D638A3 /* Digisign-Server-ID-Enrich-GTETrust-Cert.crt */; }; + EB1055841E14E1F90003C309 /* Invalid-www.cybersecurity.my.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 794743191462137C00D638A3 /* Invalid-www.cybersecurity.my.crt */; }; + EB1055851E14E1F90003C309 /* Digisign-Server-ID-Enrich-Entrust-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 79679E251462028800CF997F /* Digisign-Server-ID-Enrich-Entrust-Cert.crt */; }; + EB1055861E14E1F90003C309 /* Invalid-webmail.jaring.my.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 79679E261462028800CF997F /* Invalid-webmail.jaring.my.crt */; }; + EB1055871E14E2060003C309 /* DigiNotar_Root_CA_G2-RootCertificate.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECF21416E20400947741 /* DigiNotar_Root_CA_G2-RootCertificate.crt */; }; + EB1055881E14E2060003C309 /* Invalid-CertiID_Enterprise_Certificate_Authority.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECEA1416DB2200947741 /* Invalid-CertiID_Enterprise_Certificate_Authority.crt */; }; + EB1055891E14E2060003C309 /* Invalid-DigiNotar_PKIoverheid_CA_Organisatie_-_G2-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECEB1416DB2200947741 /* Invalid-DigiNotar_PKIoverheid_CA_Organisatie_-_G2-Cert.crt */; }; + EB10558A1E14E2060003C309 /* Invalid-diginotarpkioverheidcaoverheid.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECEC1416DB2200947741 /* Invalid-diginotarpkioverheidcaoverheid.crt */; }; + EB10558B1E14E2060003C309 /* Invalid-diginotarpkioverheidcaoverheidenbedrijven-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECED1416DB2200947741 /* Invalid-diginotarpkioverheidcaoverheidenbedrijven-Cert.crt */; }; + EB10558C1E14E2060003C309 /* Ministerie_van_Defensie_Certificatie_Autoriteit_G2.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECEE1416DB2200947741 /* Ministerie_van_Defensie_Certificatie_Autoriteit_G2.crt */; }; + EB10558D1E14E2060003C309 /* Ministerie_van_Defensie_Certificatie_Autoriteit.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECEF1416DB2200947741 /* Ministerie_van_Defensie_Certificatie_Autoriteit.crt */; }; + EB10558E1E14E2060003C309 /* staatdernederlandenorganisatieca-g2-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECF01416DB2200947741 /* staatdernederlandenorganisatieca-g2-Cert.crt */; }; + EB10558F1E14E2060003C309 /* staatdernederlandenoverheidca-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C3CECF11416DB2200947741 /* staatdernederlandenoverheidca-Cert.crt */; }; + EB1055901E14E2060003C309 /* Invalid-webmail.portofamsterdam.nl.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C8B91C51416EB6A00A254E2 /* Invalid-webmail.portofamsterdam.nl.crt */; }; + EB1055921E14E2060003C309 /* DigiNotarCA2007RootCertificate.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50ACFC1410671D00EE92DE /* DigiNotarCA2007RootCertificate.crt */; }; + EB1055931E14E2060003C309 /* Invalid-asterisk.google.com.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50ACFD1410671D00EE92DE /* Invalid-asterisk.google.com.crt */; }; + EB1055941E14E2060003C309 /* Invalid-muisonline.omnyacc-denhelder.nl-diginotar.cyberca.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50ACFE1410671D00EE92DE /* Invalid-muisonline.omnyacc-denhelder.nl-diginotar.cyberca.crt */; }; + EB1055951E14E2060003C309 /* Invalid-webmail.terneuzen.nl-diginotar-services.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50ACFF1410671D00EE92DE /* Invalid-webmail.terneuzen.nl-diginotar-services.crt */; }; + EB1055961E14E2060003C309 /* Invalid-www.maestre.com-diginotal.extended.validation.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50AD001410671D00EE92DE /* Invalid-www.maestre.com-diginotal.extended.validation.crt */; }; + EB1055971E14E2060003C309 /* Invalid-www.mobilehostingservices.nl-diginotar-services-1024.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50AD011410671D00EE92DE /* Invalid-www.mobilehostingservices.nl-diginotar-services-1024.crt */; }; + EB1055981E14E2060003C309 /* diginotar-public-ca-2025-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50AD021410671D00EE92DE /* diginotar-public-ca-2025-Cert.crt */; }; + EB1055991E14E2060003C309 /* diginotar-services-1024-entrust-secure-server-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50AD031410671D00EE92DE /* diginotar-services-1024-entrust-secure-server-Cert.crt */; }; + EB10559A1E14E2060003C309 /* diginotar-services-diginotar-root-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50AD041410671D00EE92DE /* diginotar-services-diginotar-root-Cert.crt */; }; + EB10559B1E14E2060003C309 /* diginotar.cyberca-gte.global.root-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50AD051410671D00EE92DE /* diginotar.cyberca-gte.global.root-Cert.crt */; }; + EB10559C1E14E2060003C309 /* diginotar.extended.validation-diginotar.root.ca-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50AD061410671D00EE92DE /* diginotar.extended.validation-diginotar.root.ca-Cert.crt */; }; + EB10559D1E14E2060003C309 /* diginotar.root.ca-entrust-secure-server-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C50AD071410671D00EE92DE /* diginotar.root.ca-entrust-secure-server-Cert.crt */; }; + EB10559E1E14E39D0003C309 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; + EB10559F1E14E3A80003C309 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; + EB108F261E6CE4D2003B0456 /* KCPairingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB413B7E1E663A8300592085 /* KCPairingTest.m */; }; + EB27FF2D1E407FF600EC9E3A /* ckksctl.m in Sources */ = {isa = PBXBuildFile; fileRef = EB27FF0C1E402C8000EC9E3A /* ckksctl.m */; }; + EB27FF311E408DC700EC9E3A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; EB2CA4DA1D2C28F100AB770F /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; }; EB2CA5571D2C36D400AB770F /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; }; + EB2D54AB1F02A47200E46890 /* SecAtomicFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB2D54A01F02A28200E46890 /* SecAtomicFile.cpp */; }; EB3409B01C1D627400D77661 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EB3A8DFF1BEEC66F001A89AA /* Security_edumode.plist in Install BATS plist */ = {isa = PBXBuildFile; fileRef = EB3A8DD71BEEC4D6001A89AA /* Security_edumode.plist */; }; - EB3EBF101DBD413600620B2C /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3EBF0F1DBD413600620B2C /* libobjc.dylib */; }; - EB3EBF111DBD413F00620B2C /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3EBF0F1DBD413600620B2C /* libobjc.dylib */; }; - EB3EBF131DBD417A00620B2C /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3EBF0F1DBD413600620B2C /* libobjc.dylib */; }; - EB3EBF141DBD41BD00620B2C /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3EBF0F1DBD413600620B2C /* libobjc.dylib */; }; - EB3EBF151DBD85A600620B2C /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3EBF0F1DBD413600620B2C /* libobjc.dylib */; }; + EB413B801E663AEB00592085 /* PairingChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = EB413B761E6624A500592085 /* PairingChannel.m */; }; + EB413B821E663AFA00592085 /* PairingChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = EB413B751E6624A400592085 /* PairingChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB425CA21C65846D000ECE53 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EB425CCF1C658554000ECE53 /* secbackuptest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB425CCE1C65854F000ECE53 /* secbackuptest.m */; }; EB425CDE1C658668000ECE53 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; @@ -3967,35 +4589,80 @@ EB433A291CC3244C00A7EACE /* secitemstresstest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB433A1E1CC3242C00A7EACE /* secitemstresstest.m */; }; EB433A2A1CC3246800A7EACE /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; EB433A2E1CC325E900A7EACE /* secitemstresstest.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = EB433A2D1CC325E900A7EACE /* secitemstresstest.entitlements */; }; + EB48C1A51E573EE400EC5E57 /* whoami.m in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA911D80CC2A00B0A59C /* whoami.m */; }; + EB48C1A61E573EEC00EC5E57 /* sos.m in Sources */ = {isa = PBXBuildFile; fileRef = EB48C19E1E573EDC00EC5E57 /* sos.m */; }; EB4B6E201DC0682A00AFC494 /* SecADWrapper.c in Sources */ = {isa = PBXBuildFile; fileRef = EBF3749A1DC064200065D840 /* SecADWrapper.c */; }; EB4B6E261DC0683600AFC494 /* SecADWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = EBF3749B1DC064200065D840 /* SecADWrapper.h */; }; + EB58A0511E74BF07009C10D7 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; + EB59D6731E95F01600997EAC /* libcompression.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB59D66B1E95EF2900997EAC /* libcompression.dylib */; }; EB6928C51D9C9C6E00062A18 /* SecRecoveryKey.h in Headers */ = {isa = PBXBuildFile; fileRef = EB6928BE1D9C9C5900062A18 /* SecRecoveryKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; EB6928C61D9C9C6F00062A18 /* SecRecoveryKey.h in Headers */ = {isa = PBXBuildFile; fileRef = EB6928BE1D9C9C5900062A18 /* SecRecoveryKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; EB6928CA1D9C9E1800062A18 /* rk_01_recoverykey.m in Sources */ = {isa = PBXBuildFile; fileRef = EB6928C91D9C9D9D00062A18 /* rk_01_recoverykey.m */; }; EB6928F91D9ED5BA00062A18 /* SecRecoveryKey.m in Sources */ = {isa = PBXBuildFile; fileRef = EB6928BF1D9C9C5900062A18 /* SecRecoveryKey.m */; }; EB69AB301BF4348000913AF1 /* SecEMCSPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = EB69AB091BF4347700913AF1 /* SecEMCSPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; + EB75B4821E753EAA00E469CC /* KeychainCircle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D847C51C6BE9710025BB44 /* KeychainCircle.framework */; }; + EB75B4871E75400200E469CC /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; }; + EB75B4881E75401700E469CC /* ApplePushService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */; }; + EB75B4891E75402400E469CC /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; }; + EB75B48A1E75405100E469CC /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; + EB75B48C1E75407C00E469CC /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; + EB75B48D1E75408900E469CC /* libASN1_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */; }; + EB75B48E1E75408C00E469CC /* libDER_not_installed.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC59E9EC1D91C9DC001BDDF5 /* libDER_not_installed.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 */; }; + EB75B4961E75A44100E469CC /* SOSPiggyback.m in Sources */ = {isa = PBXBuildFile; fileRef = EB75B4941E75A44100E469CC /* SOSPiggyback.m */; }; + EB76B7571DCB0C8300C43FBC /* KeychainSyncingOverIDSProxy.8 in Install man8 page */ = {isa = PBXBuildFile; fileRef = DC24B5841DA432C600330B48 /* KeychainSyncingOverIDSProxy.8 */; }; + EB76B7591DCB0CA200C43FBC /* CloudKeychainProxy.8 in Install man8 page */ = {isa = PBXBuildFile; fileRef = DC24B5851DA432E900330B48 /* CloudKeychainProxy.8 */; }; + 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 */; }; EB7F50C51DB8800A003D787D /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E9411D7F3E6E00AFB96E /* CoreCDP.framework */; }; EB7F50CC1DB88A03003D787D /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E9411D7F3E6E00AFB96E /* CoreCDP.framework */; }; + EB9C02481E8A15B40040D3C6 /* secd-37-pairing-initial-sync.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */; }; EB9C1D7B1BDFD0E000F89272 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EB9C1D7E1BDFD0E100F89272 /* secbackupntest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9C1D7D1BDFD0E100F89272 /* secbackupntest.m */; }; EB9C1DB51BDFD50100F89272 /* Security.plist in Install BATS plist */ = {isa = PBXBuildFile; fileRef = EB9C1DAD1BDFD49400F89272 /* Security.plist */; }; + EBA689031E74732700FF90A7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EBA9AA811CE30E58004E2B68 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; EBA9AA821CE30E58004E2B68 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EBA9AA871CE30E6F004E2B68 /* secitemnotifications.m in Sources */ = {isa = PBXBuildFile; fileRef = EBA9AA7C1CE30CE7004E2B68 /* secitemnotifications.m */; }; + EBB407B31EBA46B200A541A5 /* CKKSPowerCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = EBB407B01EBA433A00A541A5 /* CKKSPowerCollection.m */; }; + EBB407B41EBA46B300A541A5 /* CKKSPowerCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = EBB407B01EBA433A00A541A5 /* CKKSPowerCollection.m */; }; + EBB839B01E2968AB00853BAC /* secfuzzer.m in Sources */ = {isa = PBXBuildFile; fileRef = EBB8399B1E295B8F00853BAC /* secfuzzer.m */; }; + EBB839B11E2968B400853BAC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + EBC15B1D1DB432F800126882 /* com.apple.secd.sb in Copy Sandbox profile */ = {isa = PBXBuildFile; fileRef = EBC15B1B1DB4306C00126882 /* com.apple.secd.sb */; }; EBCF73F71CE45F9C00BED7CA /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; EBCF73F81CE45F9C00BED7CA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EBCF73FD1CE45FAC00BED7CA /* secitemfunctionality.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCF73F21CE45F8600BED7CA /* secitemfunctionality.m */; }; - EBE54D761BE32F6F000C4856 /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; }; EBE901721C2283F7007308C6 /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; }; EBE9019A1C22852C007308C6 /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; }; EBE9019B1C2285D4007308C6 /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; }; EBE9019C1C2285DB007308C6 /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; }; EBE9019E1C228610007308C6 /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; }; + EBEEEE3C1EA31D9600E15F5C /* SOSControlHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = EBEEEE361EA31A8300E15F5C /* SOSControlHelper.m */; }; + EBEEEE3D1EA31DB000E15F5C /* SOSControlHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = EBEEEE361EA31A8300E15F5C /* SOSControlHelper.m */; }; + EBEEEE3E1EA31DB100E15F5C /* SOSControlHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = EBEEEE361EA31A8300E15F5C /* SOSControlHelper.m */; }; + EBEEEE3F1EA31E6D00E15F5C /* SOSControlHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = EBEEEE361EA31A8300E15F5C /* SOSControlHelper.m */; }; EBF2D73C1C1E2B47006AB6FF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; + EBF3745F1DBFB32A0065D840 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EBF3745E1DBFB32A0065D840 /* libobjc.dylib */; }; EBF374751DC055590065D840 /* security-sysdiagnose.m in Sources */ = {isa = PBXBuildFile; fileRef = EBF374741DC055590065D840 /* security-sysdiagnose.m */; }; EBF3747E1DC057B40065D840 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; EBF374801DC058070065D840 /* security-sysdiagnose.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EBF3747F1DC057FE0065D840 /* security-sysdiagnose.1 */; }; + EBFF18C41F02A4EF004E58FC /* libsecurity_filedb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BC89F1D8B7CBD00070CB0 /* libsecurity_filedb.a */; }; + EBFF18CA1F02A677004E58FC /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD06AB01D8E0D53007602F1 /* libsecurity_utilities.a */; }; + EBFF18CB1F02A68B004E58FC /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; }; + EBFF18CC1F02A6AE004E58FC /* libsecurity_cdsa_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCB341821D8A2B860054D16E /* libsecurity_cdsa_utilities.a */; }; + F619D71E1ED70BC1005B5F46 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F619D71D1ED70BB0005B5F46 /* main.m */; }; + F667EC5A1E96E9B100203D5C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB10557A1E14DF640003C309 /* Security.framework */; }; + F667EC5B1E96E9B100203D5C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B6A881E2B5F9900CD6EE5 /* Foundation.framework */; }; + 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 */; }; + F6AF96681E646CAF00917214 /* libcoreauthd_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */; }; F93C493B1AB8FF530047E01A /* ckcdiagnose.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = F93C493A1AB8FF530047E01A /* ckcdiagnose.sh */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + F964772C1E5832540019E4EB /* SecCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0678E1D8CDF7E007602F1 /* SecCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ @@ -4073,6 +4740,27 @@ remoteGlobalIDString = E710C7411331946400F85568; remoteInfo = SecurityTests; }; + 225394B51E30811400D3CD9B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 225394AC1E3080A600D3CD9B; + remoteInfo = security_codesigning_ios; + }; + 225394D91E30846800D3CD9B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD067561D8CDCF3007602F1; + remoteInfo = codesigning_DTrace; + }; + 226A8B441DEF58EE004C35E3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD06AA91D8E0D53007602F1; + remoteInfo = security_utilities; + }; 438169E61B4EE4B300C54D58 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4080,6 +4768,13 @@ remoteGlobalIDString = 4381690B1B4EDCBD00C54D58; remoteInfo = SOSCCAuthPlugin; }; + 47C51B8A1EEA657D0032D9E5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC1789031D77980500B50D50; + remoteInfo = Security_osx; + }; 4C52D0ED16EFCD720079966E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4164,6 +4859,167 @@ remoteGlobalIDString = 5EBE24791B00CCAE0007DB0E; remoteInfo = secacltests; }; + 6C24EF491E415109000DE79F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6CCDF7831E3C25FA003F2555; + remoteInfo = KeychainEntitledTestRunner; + }; + 6C24EF521E415132000DE79F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6CCDF7831E3C25FA003F2555; + remoteInfo = KeychainEntitledTestRunner; + }; + 6C98082E1E788AEB00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC59E9AC1D91C9DC001BDDF5; + remoteInfo = DER_not_installed; + }; + 6C9808301E788AEB00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC8834011D8A218F00CE0ACA; + remoteInfo = ASN1_not_installed; + }; + 6C9808321E788AEB00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BCC211D8C684F00070CB0; + remoteInfo = utilities; + }; + 6C9808361E788AEB00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + 6C9808381E788AEB00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; + remoteInfo = SecureObjectSyncServer; + }; + 6C98083A1E788AEB00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCC78EA81D8088E200865A7C; + remoteInfo = security; + }; + 6C98083C1E788AEB00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC222C371E034D1F00B09171; + remoteInfo = libsecurityd_ios_NO_AKS; + }; + 6C98086A1E788AFD00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC59E9AC1D91C9DC001BDDF5; + remoteInfo = DER_not_installed; + }; + 6C98086C1E788AFD00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC8834011D8A218F00CE0ACA; + remoteInfo = ASN1_not_installed; + }; + 6C98086E1E788AFD00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BCC211D8C684F00070CB0; + remoteInfo = utilities; + }; + 6C9808721E788AFD00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + 6C9808741E788AFD00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; + remoteInfo = SecureObjectSyncServer; + }; + 6C9808761E788AFD00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCC78EA81D8088E200865A7C; + remoteInfo = security; + }; + 6C9808781E788AFD00E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC222C371E034D1F00B09171; + remoteInfo = libsecurityd_ios_NO_AKS; + }; + 6C98089F1E788B9400E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6CF4A0B31E45488B00ECD7B5; + remoteInfo = KeychainEntitledTestApp_mac; + }; + 6C9808A31E788CB100E70590 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6CF4A0DF1E4549F200ECD7B5; + remoteInfo = KeychainEntitledTestApp_ios; + }; + ACBAF6FD1E941E090007BA2F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = ACBAF6991E9417F40007BA2F; + remoteInfo = security_transform_regressions; + }; + BE061EAB1EE5EA5600B22118 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BED208D41EDF950E00753952; + remoteInfo = manifeststresstest; + }; + BE061EB21EE5EAC800B22118 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BED208D41EDF950E00753952; + remoteInfo = manifeststresstest; + }; + BE061EB61EE5EB9000B22118 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BED208D41EDF950E00753952; + remoteInfo = manifeststresstest; + }; + BE061EB81EE5EBA000B22118 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BED208D41EDF950E00753952; + remoteInfo = manifeststresstest; + }; BE197F621911742900BA91D1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4178,6 +5034,41 @@ remoteGlobalIDString = BE442BA018B7FDB800F24DAE; remoteInfo = swcagent; }; + BE9C38C71EB115A7007E2AE1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BEF88C271EAFFC3F00357577; + remoteInfo = TrustedPeers; + }; + BE9C38CE1EB115C9007E2AE1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BEF88C271EAFFC3F00357577; + remoteInfo = TrustedPeers; + }; + BE9C38D01EB115F4007E2AE1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BEF88C2F1EAFFC3F00357577; + remoteInfo = TrustedPeersTests; + }; + BE9C38D21EB11605007E2AE1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BEF88C2F1EAFFC3F00357577; + remoteInfo = TrustedPeersTests; + }; + BEF88C321EAFFC3F00357577 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = BEF88C271EAFFC3F00357577; + remoteInfo = TrustedPeers; + }; CD6130EC1DA1C0CC00E1E42F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4192,6 +5083,104 @@ remoteGlobalIDString = CD276C261A83F60C003226BC; remoteInfo = KeychainSyncingOverIDSProxy; }; + D40B6A7E1E2B5F3D00CD6EE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D4ADA3181E2B41670031CEA3; + remoteInfo = libtrustd; + }; + D40B6A801E2B5F4700CD6EE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D4ADA3181E2B41670031CEA3; + remoteInfo = libtrustd; + }; + D40B6A851E2B5F7600CD6EE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D4ADA3181E2B41670031CEA3; + remoteInfo = libtrustd; + }; + D40B6A8B1E2B63D100CD6EE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D4ADA3181E2B41670031CEA3; + remoteInfo = libtrustd; + }; + D40B6A911E2B678D00CD6EE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D4ADA3181E2B41670031CEA3; + remoteInfo = libtrustd; + }; + D40B6A941E2B67FF00CD6EE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D4ADA3181E2B41670031CEA3; + remoteInfo = libtrustd; + }; + D41257E31E941A8400781F23 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC59E9AC1D91C9DC001BDDF5; + remoteInfo = DER_not_installed; + }; + D41257E51E941ACC00781F23 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BCC211D8C684F00070CB0; + remoteInfo = utilities; + }; + D41257E71E941AD200781F23 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D4ADA3181E2B41670031CEA3; + remoteInfo = libtrustd; + }; + D41257F01E941E7D00781F23 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D41257CE1E9410A300781F23; + remoteInfo = trustd_ios; + }; + D41257F21E941E8600781F23 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D41257CE1E9410A300781F23; + remoteInfo = trustd_ios; + }; + D41257F41E941E8E00781F23 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D41257CE1E9410A300781F23; + remoteInfo = trustd_ios; + }; + D41257F61E941E9600781F23 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D41257CE1E9410A300781F23; + remoteInfo = trustd_ios; + }; + D419C0251E57EACA008619D1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4CE5A54C09C796E100D27A3F; + remoteInfo = sslViewer; + }; D41AD4391B96721E008C7270 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4346,6 +5335,13 @@ remoteGlobalIDString = 728B56A016D59979008FA3AB; remoteInfo = OTAPKIAssetTool; }; + DA30D6811DF8C93500EC6B43 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DA30D6751DF8C8FB00EC6B43; + remoteInfo = KeychainSyncAccountUpdater; + }; DC00678F1D878132005AF8DB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4395,20 +5391,6 @@ remoteGlobalIDString = DC008B451D90CE53004002A3; remoteInfo = securityd_macos_mig_nomake; }; - DC00AB651D821BFD00513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E88A1D80C1EB00B0A59C; - remoteInfo = libsecipc_client; - }; - DC00AB671D821C0500513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; - remoteInfo = libSecureObjectSync; - }; DC00AB691D821C0700513D74 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4437,13 +5419,6 @@ remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; remoteInfo = libSecureObjectSync; }; - DC00AB771D821C5000513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E88A1D80C1EB00B0A59C; - remoteInfo = libsecipc_client; - }; DC00AB7D1D821C7F00513D74 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4458,27 +5433,6 @@ remoteGlobalIDString = DC52EC3E1D80D00800B0A59C; remoteInfo = libSWCAgent; }; - DC00AB841D821CA300513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; - remoteInfo = libSecureObjectSync; - }; - DC00AB861D821CA900513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E7731D80BC8000B0A59C; - remoteInfo = libsecurityd; - }; - DC00AB881D821CAD00513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E88A1D80C1EB00B0A59C; - remoteInfo = libsecipc_client; - }; DC00AB911D821D6000513D74 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4507,27 +5461,6 @@ remoteGlobalIDString = DCC78EA81D8088E200865A7C; remoteInfo = libsecurity; }; - DC00AB9F1D821DBC00513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E7731D80BC8000B0A59C; - remoteInfo = libsecurityd; - }; - DC00ABA11D821DBF00513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; - remoteInfo = libSecureObjectSync; - }; - DC00ABA31D821DC400513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E88A1D80C1EB00B0A59C; - remoteInfo = libsecipc_client; - }; DC00ABA91D821DE600513D74 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4598,13 +5531,6 @@ remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; remoteInfo = libSecureObjectSync; }; - DC00ABCE1D821F1700513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E88A1D80C1EB00B0A59C; - remoteInfo = libsecipc_client; - }; DC00ABD01D821F1A00513D74 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4626,20 +5552,6 @@ remoteGlobalIDString = DC52E7731D80BC8000B0A59C; remoteInfo = libsecurityd; }; - DC00ABDB1D821F5300513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52E88A1D80C1EB00B0A59C; - remoteInfo = libsecipc_client; - }; - DC00ABDD1D821F5600513D74 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DCC78EA81D8088E200865A7C; - remoteInfo = libsecurity; - }; DC00ABDF1D821F5C00513D74 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4675,26 +5587,33 @@ remoteGlobalIDString = DC52EC601D80D0C400B0A59C; remoteInfo = libSOSRegressions; }; - DC0B62951D90B6DB00D43BCB /* PBXContainerItemProxy */ = { + DC0984F61E1DB6D400140ADC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; proxyType = 1; - remoteGlobalIDString = DC1785041D77873100B50D50; - remoteInfo = copyHeadersToSystem; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; }; - DC0BC55A1D8B6D2E00070CB0 /* PBXContainerItemProxy */ = { + DC0984FF1E1DB70A00140ADC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; proxyType = 1; - remoteGlobalIDString = DC0BC5501D8B6D2D00070CB0; - remoteInfo = XPCKeychainSandboxCheck; + remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; + remoteInfo = SecureObjectSyncServer; }; - DC0BC5781D8B6EE200070CB0 /* PBXContainerItemProxy */ = { + DC0B62951D90B6DB00D43BCB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; proxyType = 1; - remoteGlobalIDString = DC0BC5631D8B6E3D00070CB0; - remoteInfo = XPCTimeStampingService; + remoteGlobalIDString = DC1785041D77873100B50D50; + remoteInfo = copyHeadersToSystem; + }; + DC0BB4431ED4D74A0035F886 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCC78EA81D8088E200865A7C; + remoteInfo = security; }; DC0BC5AE1D8B714000070CB0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -4906,6 +5825,41 @@ remoteGlobalIDString = DC1789031D77980500B50D50; remoteInfo = Security_osx; }; + DC222C781E034EE700B09171 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC222C371E034D1F00B09171; + remoteInfo = libsecurityd_ios_NO_AKS; + }; + DC3502C31E020D4D00BC0587 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC8834011D8A218F00CE0ACA; + remoteInfo = ASN1_not_installed; + }; + DC3502C61E020D5600BC0587 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC59E9AC1D91C9DC001BDDF5; + remoteInfo = DER_not_installed; + }; + DC3502CD1E020E2200BC0587 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BCC211D8C684F00070CB0; + remoteInfo = utilities; + }; + DC3502D41E02117600BC0587 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCC78EA81D8088E200865A7C; + remoteInfo = security; + }; DC3A4B6A1D91EBEE00E46D4A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -4913,26 +5867,26 @@ remoteGlobalIDString = DC3A4B571D91E9FB00E46D4A; remoteInfo = CodeSigningHelper; }; - DC52E84A1D80BF1100B0A59C /* PBXContainerItemProxy */ = { + DC5224F81E4029520021640A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; proxyType = 1; - remoteGlobalIDString = DC52E7731D80BC8000B0A59C; - remoteInfo = libsecurityd; + remoteGlobalIDString = DC3502B41E0208BE00BC0587; + remoteInfo = CKKSTests; }; - DC52E8BC1D80C23300B0A59C /* PBXContainerItemProxy */ = { + DC5224FF1E40295C0021640A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; proxyType = 1; - remoteGlobalIDString = DC52E88A1D80C1EB00B0A59C; - remoteInfo = libsecipc_client; + remoteGlobalIDString = DC3502B41E0208BE00BC0587; + remoteInfo = CKKSTests; }; - DC52E9A21D80C5EE00B0A59C /* PBXContainerItemProxy */ = { + DC52E84A1D80BF1100B0A59C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; proxyType = 1; - remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; - remoteInfo = libSecureObjectSync; + remoteGlobalIDString = DC52E7731D80BC8000B0A59C; + remoteInfo = libsecurityd; }; DC52EAA41D80CCF600B0A59C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -5655,13 +6609,6 @@ remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; remoteInfo = SecureObjectSync; }; - DC71DA0E1D95E1210065FB93 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DC52EE661D80D82600B0A59C; - remoteInfo = SecItemShimOSX; - }; DC82FFEA1D90D4640085674B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -5676,6 +6623,13 @@ remoteGlobalIDString = DC82FFEC1D90D4D20085674B; remoteInfo = security_ocspd_macos_mig_nomake; }; + DC89998A1E410DBF00E6E604 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC8834011D8A218F00CE0ACA; + remoteInfo = ASN1_not_installed; + }; DCB340181D8A248C0054D16E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -5725,6 +6679,34 @@ remoteGlobalIDString = DCB343AD1D8A34FD0054D16E; remoteInfo = security_keychain_regressions; }; + DCB515CF1ED3CC36001F1152 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6C9808681E788AFD00E70590; + remoteInfo = CKKSCloudKitTests_ios; + }; + DCB515D61ED3CC52001F1152 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6C98082C1E788AEB00E70590; + remoteInfo = CKKSCloudKitTests_mac; + }; + DCB515D81ED3CC6B001F1152 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6CF4A0B31E45488B00ECD7B5; + remoteInfo = KeychainEntitledTestApp_mac; + }; + DCB515DA1ED3CC73001F1152 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6CF4A0DF1E4549F200ECD7B5; + remoteInfo = KeychainEntitledTestApp_ios; + }; DCBE6E491D91E23D00A3E5E5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -5900,6 +6882,90 @@ remoteGlobalIDString = DCD66DC41D8205C400DB1393; remoteInfo = libSecOtrOSX; }; + DCD8A19B1E09EEA200E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1E51E09F81300E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1E81E09F85B00E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1EB1E09F88400E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1EE1E09F8BC00E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1F11E09F8DB00E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1F41E09F91F00E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1F71E09F97300E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1FA1E09F99700E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A1FD1E09FA1800E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A2021E09FAE500E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + DCD8A2061E09FB1F00E4FA0A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; DCE4E6A91D7A38E700AFB96E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -6103,6 +7169,90 @@ remoteGlobalIDString = E7D847C41C6BE9710025BB44; remoteInfo = KeychainCircle; }; + EB0D30F91EF12BFB00C3C17D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E79EEDD21CD3F8AB00C2FBFC; + remoteInfo = Security_tests_ios; + }; + EB10557C1E14DFB60003C309 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EB1055741E14DF430003C309; + remoteInfo = SecCertificateFuzzer; + }; + EB10557E1E14DFBE0003C309 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EB1055741E14DF430003C309; + remoteInfo = SecCertificateFuzzer; + }; + EB108F201E6CE4D2003B0456 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BCC211D8C684F00070CB0; + remoteInfo = utilities; + }; + EB1C4CA61E85883900404981 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 470415CE1E5E14B5001F3D95; + remoteInfo = seckeychainnetworkextensionstest; + }; + EB1C4CA81E85883900404981 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 47702B1D1E5F409700B29577; + remoteInfo = seckeychainnetworkextensionsystemdaemontest; + }; + EB1C4CAA1E85883900404981 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 47702B2D1E5F492C00B29577; + remoteInfo = seckeychainnetworkextensionunauthorizedaccesstest; + }; + EB1C4CB11E85884300404981 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 470415CE1E5E14B5001F3D95; + remoteInfo = seckeychainnetworkextensionstest; + }; + EB1C4CB31E85884300404981 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 47702B1D1E5F409700B29577; + remoteInfo = seckeychainnetworkextensionsystemdaemontest; + }; + EB1C4CB51E85884300404981 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 47702B2D1E5F492C00B29577; + remoteInfo = seckeychainnetworkextensionunauthorizedaccesstest; + }; + EB27FF251E40716D00EC9E3A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EB27FF101E402CD300EC9E3A; + remoteInfo = ckksctl; + }; + EB27FF271E40717400EC9E3A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EB27FF101E402CD300EC9E3A; + remoteInfo = ckksctl; + }; EB31EA821D3EF2FB008F952A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -6131,6 +7281,34 @@ remoteGlobalIDString = EB433A201CC3243600A7EACE; remoteInfo = secitemstresstest; }; + EB58A05B1E74C517009C10D7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E79EEDA71CD3F87B00C2FBFC; + remoteInfo = Security_tests_osx; + }; + EB58A05D1E74C51F009C10D7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E79EEDD21CD3F8AB00C2FBFC; + remoteInfo = Security_tests_ios; + }; + EB58A05F1E74C8D9009C10D7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EBB839A41E29665D00853BAC; + remoteInfo = secfuzzer; + }; + EB58A0611E74C8E4009C10D7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EBB839A41E29665D00853BAC; + remoteInfo = secfuzzer; + }; EB63ADE01C3E74F900C45A69 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -6194,6 +7372,20 @@ remoteGlobalIDString = EB9C1DAE1BDFD4DE00F89272; remoteInfo = SecurityBatsTests; }; + EBA62C141EAD34C60096B33A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6CCDF7831E3C25FA003F2555; + remoteInfo = KeychainEntitledTestRunner; + }; + EBA62C1B1EAD34CD0096B33A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6CCDF7831E3C25FA003F2555; + remoteInfo = KeychainEntitledTestRunner; + }; EBA9AA881CE3E76C004E2B68 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -6222,6 +7414,20 @@ remoteGlobalIDString = EBCF73F31CE45F9C00BED7CA; remoteInfo = secitemfunctionality; }; + EBD31B3A1E0A186500FBE9FA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BC5631D8B6E3D00070CB0; + remoteInfo = XPCTimeStampingService; + }; + EBD31B411E0A18A600FBE9FA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BC5501D8B6D2D00070CB0; + remoteInfo = XPCKeychainSandboxCheck; + }; EBD849351B242C8900C5FD1E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -6257,6 +7463,83 @@ remoteGlobalIDString = EBF374711DC055580065D840; remoteInfo = "security-sysdiagnose"; }; + EBFBC2AF1E76582C00A34469 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EB108F181E6CE4D2003B0456; + remoteInfo = KCPairingTests; + }; + EBFBC2B11E76585500A34469 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E7D847C41C6BE9710025BB44; + remoteInfo = KeychainCircle; + }; + EBFBC2B31E76586700A34469 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCC78EA81D8088E200865A7C; + remoteInfo = security; + }; + EBFBC2B51E76587800A34469 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A; + remoteInfo = SecureObjectSyncFramework; + }; + EBFBC2B71E76588200A34469 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC59E9AC1D91C9DC001BDDF5; + remoteInfo = DER_not_installed; + }; + EBFBC2B91E76588A00A34469 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC8834011D8A218F00CE0ACA; + remoteInfo = ASN1_not_installed; + }; + EBFF18CD1F02BA66004E58FC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EB2D54A11F02A45E00E46890; + remoteInfo = secatomicfile; + }; + EBFF18CF1F02C2FE004E58FC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BC8981D8B7CBD00070CB0; + remoteInfo = security_filedb; + }; + F621D0821ED6ED5B000EA569 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F621D0271ED6DCE7000EA569; + remoteInfo = AuthorizationTestTool; + }; + F667EC641E96EDCF00203D5C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DC0BCBD91D8C648C00070CB0; + remoteInfo = regressionBase; + }; + F667EC661E96FA4600203D5C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4C35DB69094F906D002917C4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F667EC561E96E9B100203D5C; + remoteInfo = authdtest; + }; F94E7AE11ACC8E7700F23132 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -6276,6 +7559,33 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 470415CD1E5E14B5001F3D95 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 47702B1C1E5F409700B29577 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 47702B2C1E5F492C00B29577 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 4814D8691CAA059E002FFC36 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -6470,6 +7780,48 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 6C0B0C481E2537E2007F95E5 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /System/Library/AWD/Metadata; + dstSubfolderSpec = 0; + files = ( + 6C0B0C491E253832007F95E5 /* AwdMetadata-0x60-Keychain.bin in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 6C0B0C4A1E253840007F95E5 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /System/Library/AWD/Metadata; + dstSubfolderSpec = 0; + files = ( + 6C0B0C4B1E253848007F95E5 /* AwdMetadata-0x60-Keychain.bin in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 6C1520D31DCCF6F000C85C6D /* Install man8 page */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + 6C1520D41DCCF71400C85C6D /* secd.8 in Install man8 page */, + ); + name = "Install man8 page"; + runOnlyForDeploymentPostprocessing = 1; + }; + 6CCDF7821E3C25FA003F2555 /* Copy BATS Test Discovery plist */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /AppleInternal/CoreOS/BATS/unit_tests; + dstSubfolderSpec = 0; + files = ( + DC7162D21EB413F2000D2BB5 /* KeychainCKKS.plist in Copy BATS Test Discovery plist */, + ); + name = "Copy BATS Test Discovery plist"; + runOnlyForDeploymentPostprocessing = 1; + }; 79679E231462023800CF997F /* Copy DigiCertMalaysia Resources */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -6518,6 +7870,17 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + BEB463AD1E64F3C1008EB77E /* Copy Sandbox */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /System/Library/Sandbox/Profiles; + dstSubfolderSpec = 0; + files = ( + D4AA64361E95D92600D317ED /* com.apple.trustd.sb in Copy Sandbox */, + ); + name = "Copy Sandbox"; + runOnlyForDeploymentPostprocessing = 1; + }; CDB9FCAA179CD054000AAD66 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -6528,27 +7891,38 @@ ); runOnlyForDeploymentPostprocessing = 1; }; - CDF91EA61AAE019800E88CF7 /* CopyFiles */ = { + CDF91EA61AAE019800E88CF7 /* Install alloy plist */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; dstPath = /System/Library/IdentityServices/ServiceDefinitions; dstSubfolderSpec = 0; files = ( - CD51245E1DA1C67000962524 /* com.apple.private.alloy.keychainsync.plist in CopyFiles */, + CD51245E1DA1C67000962524 /* com.apple.private.alloy.keychainsync.plist in Install alloy plist */, ); + name = "Install alloy plist"; runOnlyForDeploymentPostprocessing = 1; }; - DC0BC5601D8B6D2E00070CB0 /* Embed XPC Services */ = { + D41257CD1E9410A300781F23 /* Copy LaunchDaemon */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; - dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices"; - dstSubfolderSpec = 16; + dstPath = /System/Library/LaunchDaemons; + dstSubfolderSpec = 0; files = ( - DC0BC57A1D8B6EF500070CB0 /* XPCTimeStampingService.xpc in Embed XPC Services */, - DC0BC55C1D8B6D2E00070CB0 /* XPCKeychainSandboxCheck.xpc in Embed XPC Services */, + D41257EF1E941E4E00781F23 /* com.apple.trustd.plist in Copy LaunchDaemon */, ); - name = "Embed XPC Services"; - runOnlyForDeploymentPostprocessing = 0; + name = "Copy LaunchDaemon"; + runOnlyForDeploymentPostprocessing = 1; + }; + D4ADA3111E2B209C0031CEA3 /* Install man8 page */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + D4AA643E1E95D94400D317ED /* trustd.8 in Install man8 page */, + ); + name = "Install man8 page"; + runOnlyForDeploymentPostprocessing = 1; }; DC0BC5C41D8B72E700070CB0 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; @@ -6594,18 +7968,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - DC178B8A1D77A54000B50D50 /* Old SOS header location */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 8; - dstPath = /usr/local/include; - dstSubfolderSpec = 0; - files = ( - DC3C72F31D8377C400F6A832 /* SOSPeerInfo.h in Old SOS header location */, - DC3C72F21D8377BE00F6A832 /* SOSTypes.h in Old SOS header location */, - ); - name = "Old SOS header location"; - runOnlyForDeploymentPostprocessing = 1; - }; DC3A4B681D91EB1700E46D4A /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -6713,6 +8075,17 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + DC7162D41EB4154D000D2BB5 /* Copy BATS Test Discovery Plist */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /AppleInternal/CoreOS/BATS/unit_tests; + dstSubfolderSpec = 0; + files = ( + DCC19F711EB9151B00B7D70F /* KeychainCKKS.plist in Copy BATS Test Discovery Plist */, + ); + name = "Copy BATS Test Discovery Plist"; + runOnlyForDeploymentPostprocessing = 1; + }; DC963E7D1D95EBA8008A153E /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -6753,6 +8126,17 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + DC9A2C791EB40A64008FAC27 /* Embed OCMock */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + DC9A2C7F1EB40A76008FAC27 /* OCMock.framework in Embed OCMock */, + ); + name = "Embed OCMock"; + runOnlyForDeploymentPostprocessing = 0; + }; DCD0676D1D8CDEC1007602F1 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -6894,44 +8278,48 @@ name = "Copy DigiCertMalaysia Resources"; runOnlyForDeploymentPostprocessing = 0; }; - DCE4E7F41D7A4DA800AFB96E /* CopyFiles */ = { + DCE4E7F41D7A4DA800AFB96E /* Copy LaunchAgents files */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /System/Library/LaunchAgents; dstSubfolderSpec = 0; files = ( - DCE4E80A1D7A4E1D00AFB96E /* com.apple.secd.plist in CopyFiles */, + DCE4E80A1D7A4E1D00AFB96E /* com.apple.secd.plist in Copy LaunchAgents files */, ); + name = "Copy LaunchAgents files"; runOnlyForDeploymentPostprocessing = 1; }; - DCE4E80B1D7A4E2900AFB96E /* CopyFiles */ = { + DCE4E80B1D7A4E2900AFB96E /* Copy Logging Files */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; dstPath = /System/Library/Preferences/Logging/Subsystems; dstSubfolderSpec = 0; files = ( - DCE4E80E1D7A4E3B00AFB96E /* com.apple.securityd.plist in CopyFiles */, + DCE4E80E1D7A4E3B00AFB96E /* com.apple.securityd.plist in Copy Logging Files */, ); + name = "Copy Logging Files"; runOnlyForDeploymentPostprocessing = 1; }; - DCE4E8521D7A57AE00AFB96E /* CopyFiles */ = { + DCE4E8521D7A57AE00AFB96E /* Copy LaunchAgent */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /System/Library/LaunchAgents; dstSubfolderSpec = 0; files = ( - DCE4E85F1D7A586200AFB96E /* com.apple.trustd.agent.plist in CopyFiles */, + D4AA643D1E95D93900D317ED /* com.apple.trustd.agent.plist in Copy LaunchAgent */, ); + name = "Copy LaunchAgent"; runOnlyForDeploymentPostprocessing = 1; }; - DCE4E8541D7A57AE00AFB96E /* CopyFiles */ = { + DCE4E8541D7A57AE00AFB96E /* Copy LaunchDaemon Files */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; dstPath = /System/Library/LaunchDaemons; dstSubfolderSpec = 0; files = ( - DCE4E8601D7A586A00AFB96E /* com.apple.trustd.plist in CopyFiles */, + D4AA643C1E95D93100D317ED /* com.apple.trustd.plist in Copy LaunchDaemon Files */, ); + name = "Copy LaunchDaemon Files"; runOnlyForDeploymentPostprocessing = 1; }; DCE4E8CC1D7F358C00AFB96E /* Copy authorization.plist */ = { @@ -6977,14 +8365,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; - DCE4E9701D7F3EA700AFB96E /* CopyFiles */ = { + DCE4E9701D7F3EA700AFB96E /* Install launchd plist */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; dstPath = /System/Library/LaunchAgents; dstSubfolderSpec = 0; files = ( - DCE4E9711D7F3EBB00AFB96E /* com.apple.security.keychain-circle-notification.plist in CopyFiles */, + DCE4E9711D7F3EBB00AFB96E /* com.apple.security.keychain-circle-notification.plist in Install launchd plist */, ); + name = "Install launchd plist"; runOnlyForDeploymentPostprocessing = 1; }; E73288DD1AED7215008CE839 /* Copy SecureObjectSync Headers */ = { @@ -7015,37 +8404,81 @@ name = "Install BATS Tests"; runOnlyForDeploymentPostprocessing = 1; }; - EB0BF1711D25B47A000DEF32 /* CopyFiles */ = { + EB1055801E14DFE40003C309 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /AppleInternal/CoreOS/tests/Security; + dstPath = "$(SECURITY_FUZZER_BASE_DIR)/data/$(TARGET_NAME)"; dstSubfolderSpec = 0; files = ( - 485B640B1DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h in CopyFiles */, - EB0BF1981D25B4BE000DEF32 /* README in CopyFiles */, + EB1055831E14E1F90003C309 /* Digisign-Server-ID-Enrich-GTETrust-Cert.crt in CopyFiles */, + EB1055841E14E1F90003C309 /* Invalid-www.cybersecurity.my.crt in CopyFiles */, + EB1055851E14E1F90003C309 /* Digisign-Server-ID-Enrich-Entrust-Cert.crt in CopyFiles */, + EB1055861E14E1F90003C309 /* Invalid-webmail.jaring.my.crt in CopyFiles */, + EB1055871E14E2060003C309 /* DigiNotar_Root_CA_G2-RootCertificate.crt in CopyFiles */, + EB1055881E14E2060003C309 /* Invalid-CertiID_Enterprise_Certificate_Authority.crt in CopyFiles */, + EB1055891E14E2060003C309 /* Invalid-DigiNotar_PKIoverheid_CA_Organisatie_-_G2-Cert.crt in CopyFiles */, + EB10558A1E14E2060003C309 /* Invalid-diginotarpkioverheidcaoverheid.crt in CopyFiles */, + EB10558B1E14E2060003C309 /* Invalid-diginotarpkioverheidcaoverheidenbedrijven-Cert.crt in CopyFiles */, + EB10558C1E14E2060003C309 /* Ministerie_van_Defensie_Certificatie_Autoriteit_G2.crt in CopyFiles */, + EB10558D1E14E2060003C309 /* Ministerie_van_Defensie_Certificatie_Autoriteit.crt in CopyFiles */, + EB10558E1E14E2060003C309 /* staatdernederlandenorganisatieca-g2-Cert.crt in CopyFiles */, + EB10558F1E14E2060003C309 /* staatdernederlandenoverheidca-Cert.crt in CopyFiles */, + EB1055901E14E2060003C309 /* Invalid-webmail.portofamsterdam.nl.crt in CopyFiles */, + EB1055921E14E2060003C309 /* DigiNotarCA2007RootCertificate.crt in CopyFiles */, + EB1055931E14E2060003C309 /* Invalid-asterisk.google.com.crt in CopyFiles */, + EB1055941E14E2060003C309 /* Invalid-muisonline.omnyacc-denhelder.nl-diginotar.cyberca.crt in CopyFiles */, + EB1055951E14E2060003C309 /* Invalid-webmail.terneuzen.nl-diginotar-services.crt in CopyFiles */, + EB1055961E14E2060003C309 /* Invalid-www.maestre.com-diginotal.extended.validation.crt in CopyFiles */, + EB1055971E14E2060003C309 /* Invalid-www.mobilehostingservices.nl-diginotar-services-1024.crt in CopyFiles */, + EB1055981E14E2060003C309 /* diginotar-public-ca-2025-Cert.crt in CopyFiles */, + EB1055991E14E2060003C309 /* diginotar-services-1024-entrust-secure-server-Cert.crt in CopyFiles */, + EB10559A1E14E2060003C309 /* diginotar-services-diginotar-root-Cert.crt in CopyFiles */, + EB10559B1E14E2060003C309 /* diginotar.cyberca-gte.global.root-Cert.crt in CopyFiles */, + EB10559C1E14E2060003C309 /* diginotar.extended.validation-diginotar.root.ca-Cert.crt in CopyFiles */, + EB10559D1E14E2060003C309 /* diginotar.root.ca-entrust-secure-server-Cert.crt in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; - EB0BF1991D25B54B000DEF32 /* CopyFiles */ = { + EB27FF0F1E402CD300EC9E3A /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + EB76B7561DCB0C6900C43FBC /* Install man8 page */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /AppleInternal/CoreOS/tests/Security; + dstPath = /usr/share/man/man8; dstSubfolderSpec = 0; files = ( - EB0BF19A1D25B551000DEF32 /* README in CopyFiles */, + EB76B7571DCB0C8300C43FBC /* KeychainSyncingOverIDSProxy.8 in Install man8 page */, ); + name = "Install man8 page"; runOnlyForDeploymentPostprocessing = 1; }; - EB5D72ED1B0CB082009CAA47 /* Old SOS header location */ = { + EB76B7581DCB0C8B00C43FBC /* Install man8 page */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; - dstPath = /usr/local/include; + dstPath = /usr/share/man/man8; dstSubfolderSpec = 0; files = ( - DC3C72F11D8377A300F6A832 /* SOSPeerInfo.h in Old SOS header location */, - DC3C72F01D83779A00F6A832 /* SOSTypes.h in Old SOS header location */, + EB76B7591DCB0CA200C43FBC /* CloudKeychainProxy.8 in Install man8 page */, ); - name = "Old SOS header location"; + name = "Install man8 page"; + runOnlyForDeploymentPostprocessing = 1; + }; + EB76B75B1DCB0DD500C43FBC /* Install man8 page */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + EB0DB37D1DCBC99100EAB6AE /* Keychain Circle Notification.8 in Install man8 page */, + ); + name = "Install man8 page"; runOnlyForDeploymentPostprocessing = 1; }; EB9C1DB41BDFD4F200F89272 /* Install BATS plist */ = { @@ -7060,6 +8493,26 @@ name = "Install BATS plist"; runOnlyForDeploymentPostprocessing = 1; }; + EBB839A31E29665D00853BAC /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + EBC15B1C1DB432E600126882 /* Copy Sandbox profile */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /System/Library/Sandbox/Profiles; + dstSubfolderSpec = 0; + files = ( + EBC15B1D1DB432F800126882 /* com.apple.secd.sb in Copy Sandbox profile */, + ); + name = "Copy Sandbox profile"; + runOnlyForDeploymentPostprocessing = 1; + }; EBF374701DC055580065D840 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -7070,6 +8523,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + F667EC5C1E96E9B100203D5C /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; F93C49061AB8FCE50047E01A /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -7083,6 +8545,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 09CB496A1F2F64AF00C8E4DE /* si-44-seckey-fv.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "si-44-seckey-fv.m"; path = "OSX/shared_regressions/si-44-seckey-fv.m"; sourceTree = SOURCE_ROOT; }; 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 = ""; }; 0C0BDB441756868B00BC1A7E /* testlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testlist.h; sourceTree = ""; }; @@ -7094,17 +8557,38 @@ 0C2BCBA71D063F7D00ED7A2F /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = ""; }; 0C2BCBB91D06401F00ED7A2F /* dtlsEchoClient */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dtlsEchoClient; sourceTree = BUILT_PRODUCTS_DIR; }; 0C2BCBCE1D0648D100ED7A2F /* dtlsEchoServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dtlsEchoServer; sourceTree = BUILT_PRODUCTS_DIR; }; + 0C3C00721EF3636300AB19FE /* secd-155-otr-negotiation-monitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-155-otr-negotiation-monitor.m"; sourceTree = ""; }; + 0C48990A1E0E0FF300C6CF70 /* SOSTransportCircleCK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircleCK.h; sourceTree = ""; }; + 0C4899111E0E105D00C6CF70 /* SOSTransportCircleCK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportCircleCK.m; sourceTree = ""; }; + 0C48991B1E0F384700C6CF70 /* SOSAccountTrustClassic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SOSAccountTrustClassic.m; path = SecureObjectSync/SOSAccountTrustClassic.m; sourceTree = ""; }; + 0C4899221E0F386900C6CF70 /* SOSAccountTrustClassic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SOSAccountTrustClassic.h; path = SecureObjectSync/SOSAccountTrustClassic.h; sourceTree = ""; }; + 0C4899241E0F38FA00C6CF70 /* SOSAccountTrustOctagon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SOSAccountTrustOctagon.m; path = SecureObjectSync/SOSAccountTrustOctagon.m; sourceTree = ""; }; + 0C4899261E0F399B00C6CF70 /* SOSAccountTrustOctagon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SOSAccountTrustOctagon.h; path = SecureObjectSync/SOSAccountTrustOctagon.h; sourceTree = ""; }; 0C664AB2175926B20092D3D9 /* secdtests-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "secdtests-entitlements.plist"; sourceTree = ""; }; 0C78F1C916A5E13400654E08 /* sectask_regressions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sectask_regressions.h; sourceTree = ""; }; 0C78F1CA16A5E1BF00654E08 /* sectask-10-sectask.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sectask-10-sectask.c"; sourceTree = ""; }; 0C78F1CB16A5E1BF00654E08 /* sectask_ipc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = sectask_ipc.defs; sourceTree = ""; }; - 0C869B421C865E4D006A2873 /* CoreCDP.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreCDP.framework; path = System/Library/PrivateFrameworks/CoreCDP.framework; sourceTree = SDKROOT; }; + 0CAC5DBE1EB3DA4C00AD884B /* SOSPeerRateLimiter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSPeerRateLimiter.m; sourceTree = ""; }; + 0CAC5DC51EB3DB3C00AD884B /* SOSPeerRateLimiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerRateLimiter.h; sourceTree = ""; }; + 0CAD1E221E032D4000537693 /* AggregateDictionary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AggregateDictionary.framework; path = "../../Library/Developer/Xcode/iOS DeviceSupport/11.0 (15A168)/Symbols/System/Library/PrivateFrameworks/AggregateDictionary.framework"; sourceTree = ""; }; 0CB321F01464A95F00587CD3 /* CreateCerts.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = CreateCerts.sh; sourceTree = ""; }; + 0CCDE7161EEB08220021A946 /* secd-156-timers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-156-timers.m"; sourceTree = ""; }; + 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSPeerOTRTimer.m; sourceTree = ""; }; + 0CD8CB0C1ECA50D10076F37F /* SOSPeerOTRTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerOTRTimer.h; sourceTree = ""; }; + 0CE760471E12F2F200B4381E /* SOSAccountTrustClassic+Expansion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Expansion.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Expansion.m"; sourceTree = ""; }; + 0CE760491E12F30200B4381E /* SOSAccountTrustClassic+Circle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Circle.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Circle.m"; sourceTree = ""; }; + 0CE7604B1E12F56800B4381E /* SOSAccountTrustClassic+Identity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Identity.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Identity.m"; sourceTree = ""; }; + 0CE7604D1E12F5BA00B4381E /* SOSAccountTrustClassic+Retirement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Retirement.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Retirement.m"; sourceTree = ""; }; + 0CE7604F1E1301DC00B4381E /* SOSAccountTrustClassic+Expansion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SOSAccountTrustClassic+Expansion.h"; path = "SecureObjectSync/SOSAccountTrustClassic+Expansion.h"; sourceTree = ""; }; + 0CE760511E1314F700B4381E /* SOSAccountTrustClassic+Identity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SOSAccountTrustClassic+Identity.h"; path = "SecureObjectSync/SOSAccountTrustClassic+Identity.h"; sourceTree = ""; }; + 0CE760531E13155100B4381E /* SOSAccountTrustClassic+Circle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SOSAccountTrustClassic+Circle.h"; path = "SecureObjectSync/SOSAccountTrustClassic+Circle.h"; sourceTree = ""; }; + 0CE760551E1316E900B4381E /* SOSAccountTrustClassic+Retirement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SOSAccountTrustClassic+Retirement.h"; path = "SecureObjectSync/SOSAccountTrustClassic+Retirement.h"; sourceTree = ""; }; 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 = ""; }; 107226D10D91DB32003CF14F /* SecTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTask.h; path = sectask/SecTask.h; sourceTree = ""; }; 107227350D91FE89003CF14F /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = usr/lib/libbsm.dylib; sourceTree = SDKROOT; }; 18351B8F14CB65870097860E /* SecBase64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecBase64.h; sourceTree = ""; }; + 225394B41E3080A600D3CD9B /* libsecurity_codesigning_ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurity_codesigning_ios.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2281820D17B4686C0067C9C9 /* BackgroundTaskAgent.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BackgroundTaskAgent.framework; path = System/Library/PrivateFrameworks/BackgroundTaskAgent.framework; sourceTree = SDKROOT; }; 22C002A31AC9D33100B3469E /* OTAPKIAssetTool.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = OTAPKIAssetTool.xcconfig; sourceTree = ""; }; 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 = ""; }; @@ -7116,24 +8600,57 @@ 43DB542E1BB1F85B0083C3F1 /* ProtectedCloudStorage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ProtectedCloudStorage.framework; path = System/Library/PrivateFrameworks/ProtectedCloudStorage.framework; sourceTree = SDKROOT; }; 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libcoreauthd_client.a; path = usr/local/lib/libcoreauthd_client.a; sourceTree = SDKROOT; }; 4432AF8C1A01472C000958DC /* libaks_acl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libaks_acl.a; path = usr/local/lib/libaks_acl.a; sourceTree = SDKROOT; }; - 443381D918A3D81400215606 /* SecAccessControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecAccessControl.h; sourceTree = ""; }; + 443381D918A3D81400215606 /* SecAccessControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecAccessControl.h; path = ../../../keychain/SecAccessControl.h; sourceTree = ""; }; 443381DA18A3D81400215606 /* SecAccessControlPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecAccessControlPriv.h; sourceTree = ""; }; 4469FBDC1AA0A45C0021AA26 /* libctkclient_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkclient_test.a; path = usr/local/lib/libctkclient_test.a; sourceTree = SDKROOT; }; 4469FBDD1AA0A45C0021AA26 /* libctkclient.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkclient.a; path = usr/local/lib/libctkclient.a; sourceTree = SDKROOT; }; + 470415CF1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = seckeychainnetworkextensionstest; sourceTree = BUILT_PRODUCTS_DIR; }; + 470415DB1E5E1534001F3D95 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = RegressionTests/seckeychainnetworkextensionstest/main.m; sourceTree = SOURCE_ROOT; }; + 470415DD1E5E15B3001F3D95 /* seckeychainnetworkextensionstest.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; name = seckeychainnetworkextensionstest.entitlements; path = RegressionTests/seckeychainnetworkextensionstest/seckeychainnetworkextensionstest.entitlements; sourceTree = SOURCE_ROOT; }; + 471024D91E79CB6D00844C09 /* CKKSTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSTests.h; sourceTree = ""; }; + 4723C9BC1F152EB10082882F /* SFSQLite.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFSQLite.m; sourceTree = ""; }; + 4723C9BD1F152EB10082882F /* SFSQLite.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFSQLite.h; sourceTree = ""; }; + 4723C9BE1F152EB10082882F /* SFObjCType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFObjCType.m; sourceTree = ""; }; + 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFSQLiteStatement.m; sourceTree = ""; }; + 4723C9C01F152EB10082882F /* SFObjCType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFObjCType.h; sourceTree = ""; }; + 4723C9C11F152EB10082882F /* SFSQLiteStatement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFSQLiteStatement.h; sourceTree = ""; }; + 4723C9D11F1531970082882F /* CKKSLoggerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSLoggerTests.m; sourceTree = ""; }; + 4723C9DA1F1540CE0082882F /* SFAnalyticsLogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFAnalyticsLogger.h; sourceTree = ""; }; + 4723C9DB1F1540CE0082882F /* SFAnalyticsLogger.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFAnalyticsLogger.m; sourceTree = ""; }; + 4738AE241E732D7E006BD53D /* SharedWebCredentials.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SharedWebCredentials.framework; path = System/Library/PrivateFrameworks/SharedWebCredentials.framework; sourceTree = SDKROOT; }; + 474B5FBF1E662E21007546F8 /* SecurityFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityFoundation.framework; path = ../../Builds/iphoneos11.0.internal/SecurityFoundation.framework; sourceTree = ""; }; + 475F371F1EE8F23900248FB5 /* SFAnalyticsLogging.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SFAnalyticsLogging.plist; sourceTree = ""; }; + 476541631F339F6300413F65 /* SecdWatchdog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecdWatchdog.h; sourceTree = ""; }; + 476541641F339F6300413F65 /* SecdWatchdog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecdWatchdog.m; sourceTree = ""; }; + 476D87391E6750E200190352 /* CKKSManifestLeafRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSManifestLeafRecord.h; sourceTree = ""; }; + 476D873A1E6750E200190352 /* CKKSManifestLeafRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSManifestLeafRecord.m; sourceTree = ""; }; + 476E918D1E7343B200B4E4D3 /* CKKSManifestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSManifestTests.m; sourceTree = ""; }; + 47702B1E1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = seckeychainnetworkextensionsystemdaemontest; sourceTree = BUILT_PRODUCTS_DIR; }; + 47702B261E5F412500B29577 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = RegressionTests/seckeychainnetworkextensionsystemdaemontest/main.m; sourceTree = SOURCE_ROOT; }; + 47702B271E5F412500B29577 /* seckeychainnetworkextensionsystemdaemontest.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; name = seckeychainnetworkextensionsystemdaemontest.entitlements; path = RegressionTests/seckeychainnetworkextensionsystemdaemontest/seckeychainnetworkextensionsystemdaemontest.entitlements; sourceTree = SOURCE_ROOT; }; + 47702B2E1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = seckeychainnetworkextensionunauthorizedaccesstest; sourceTree = BUILT_PRODUCTS_DIR; }; + 47702B351E5F495C00B29577 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/main.m; sourceTree = SOURCE_ROOT; }; + 47702B381E5F499A00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; name = seckeychainnetworkextensionunauthorizedaccesstest.entitlements; path = RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/seckeychainnetworkextensionunauthorizedaccesstest.entitlements; sourceTree = SOURCE_ROOT; }; + 479108B51EE879F9008CEFA0 /* CKKSAnalyticsLogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CKKSAnalyticsLogger.h; path = ckks/CKKSAnalyticsLogger.h; sourceTree = ""; }; + 479108B61EE879F9008CEFA0 /* CKKSAnalyticsLogger.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CKKSAnalyticsLogger.m; path = ckks/CKKSAnalyticsLogger.m; sourceTree = ""; }; + 47C51B841EEA657D0032D9E5 /* SecurityUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecurityUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 47C51B861EEA657D0032D9E5 /* SecurityUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecurityUnitTests.m; sourceTree = ""; }; + 47C51B881EEA657D0032D9E5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 47CEED1E1E60DE900044EAB4 /* CKKSManifest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSManifest.h; sourceTree = ""; }; + 47CEED1F1E60DE900044EAB4 /* CKKSManifest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSManifest.m; sourceTree = ""; }; 48284A041D1DB06E00C76CB7 /* README_os_log_prefs.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README_os_log_prefs.txt; path = OSX/sec/os_log/README_os_log_prefs.txt; sourceTree = ""; }; - 483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "secd-67-prefixedKeyIDs.c"; sourceTree = ""; }; + 483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-67-prefixedKeyIDs.m"; sourceTree = ""; }; 485B64081DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSKeyedPubKeyIdentifier.c; sourceTree = ""; }; 485B64091DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSKeyedPubKeyIdentifier.h; sourceTree = ""; }; - 48776C731DA5BB4200CC09B9 /* SOSRecoveryKeyBag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRecoveryKeyBag.c; sourceTree = ""; }; + 48776C731DA5BB4200CC09B9 /* SOSRecoveryKeyBag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRecoveryKeyBag.m; sourceTree = ""; }; 48776C741DA5BB4200CC09B9 /* SOSRecoveryKeyBag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRecoveryKeyBag.h; sourceTree = ""; }; - 48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRingRecovery.c; sourceTree = ""; }; + 48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRingRecovery.m; sourceTree = ""; }; 48776C7D1DA5BB5F00CC09B9 /* SOSRingRecovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingRecovery.h; sourceTree = ""; }; - 48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountRecovery.c; sourceTree = ""; }; - 48AFBA751DEF8D3100436D08 /* secd-80-views-alwayson.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-80-views-alwayson.c"; sourceTree = ""; }; - 48BC0F5C1DFA2B4500DDDFF9 /* accountCirclesViewsPrint.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = accountCirclesViewsPrint.c; sourceTree = ""; }; - 48BC0F5D1DFA2B4500DDDFF9 /* accountCirclesViewsPrint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = accountCirclesViewsPrint.h; sourceTree = ""; }; - 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-66-account-recovery.c"; sourceTree = ""; }; - 48E6171A1DBEC40D0098EAAD /* SOSBackupInformation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSBackupInformation.c; sourceTree = ""; }; + 48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountRecovery.m; sourceTree = ""; }; + 48C2F9321E4BCFC30093D70C /* accountCirclesViewsPrint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = accountCirclesViewsPrint.m; sourceTree = ""; }; + 48C2F9331E4BCFC30093D70C /* accountCirclesViewsPrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = accountCirclesViewsPrint.h; sourceTree = ""; }; + 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-66-account-recovery.m"; sourceTree = ""; }; + 48E6171A1DBEC40D0098EAAD /* SOSBackupInformation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSBackupInformation.m; sourceTree = ""; }; 48E6171B1DBEC40D0098EAAD /* SOSBackupInformation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSBackupInformation.h; sourceTree = ""; }; 4AF7FFF315AFB73800B9D400 /* SecOTR.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecOTR.h; sourceTree = ""; }; 4AF7FFF415AFB73800B9D400 /* SecOTRDHKey.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecOTRDHKey.h; sourceTree = ""; }; @@ -7259,8 +8776,13 @@ 4CF730310EF9CDE300E17471 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 4CFBF5F10D5A92E100969BBE /* SecPolicyInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPolicyInternal.h; sourceTree = ""; }; 52222CC0167BDAE100EDD09C /* SpringBoardServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SpringBoardServices.framework; path = System/Library/PrivateFrameworks/SpringBoardServices.framework; sourceTree = SDKROOT; }; + 522B28081E64B48E002B5638 /* secd-230-keybagtable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-230-keybagtable.m"; sourceTree = ""; }; 524492931AFD6D480043695A /* der_plist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = der_plist.h; path = src/der_plist.h; sourceTree = ""; }; + 526965CB1E6E283100627F9D /* AsymKeybagBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsymKeybagBackup.h; sourceTree = ""; }; + 526965CC1E6E283100627F9D /* AsymKeybagBackup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AsymKeybagBackup.m; sourceTree = ""; }; 52A23EDB161DEC3700E271E0 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "SecurityTests/Default-568h@2x.png"; sourceTree = SOURCE_ROOT; }; + 52AA92871E662A4A004301A6 /* SecBackupKeybagEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecBackupKeybagEntry.h; sourceTree = ""; }; + 52AA92881E662A4A004301A6 /* SecBackupKeybagEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecBackupKeybagEntry.m; sourceTree = ""; }; 52D82BD316A5EADA0078DFE5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 52D82BDE16A621F70078DFE5 /* CloudKeychainProxy.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CloudKeychainProxy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 5346480117331E1200FE9172 /* KeychainSyncAccountNotification.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeychainSyncAccountNotification.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -7279,14 +8801,71 @@ 5E10995019A5E5CE00A60E2B /* ISProtectedItemsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ISProtectedItemsController.m; sourceTree = ""; }; 5E11CAB919A759BD008A3664 /* KeychainItemsAclTest.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = KeychainItemsAclTest.sh; sourceTree = ""; }; 5E1D7E0319A5EBB700D322DA /* Preferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Preferences.framework; path = System/Library/PrivateFrameworks/Preferences.framework; sourceTree = SDKROOT; }; + 5E3A59421E60283C0006722E /* SecurityTests-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "SecurityTests-Entitlements.plist"; path = "OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist"; sourceTree = ""; }; 5E43C4881B00CF4600E5ECB2 /* secacltests-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "secacltests-entitlements.plist"; sourceTree = ""; }; 5E43C4891B00CF4600E5ECB2 /* testlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testlist.h; sourceTree = ""; }; 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 5E4E05A31B0CA0FD001C4A31 /* sec_acl_stress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sec_acl_stress.c; sourceTree = ""; }; + 5E77936E1E5EFEB20074A2D1 /* si-44-seckey-aks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "si-44-seckey-aks.m"; path = "OSX/shared_regressions/si-44-seckey-aks.m"; sourceTree = SOURCE_ROOT; }; 5E8B53A41AA0B8A600345E7B /* libcoreauthd_test_client.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcoreauthd_test_client.a; path = usr/local/lib/libcoreauthd_test_client.a; sourceTree = SDKROOT; }; + 5EAFA4CD1EF16059002DC188 /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = System/Library/Frameworks/LocalAuthentication.framework; sourceTree = SDKROOT; }; 5EBE247A1B00CCAE0007DB0E /* secacltests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secacltests; sourceTree = BUILT_PRODUCTS_DIR; }; 5EBE247C1B00CCAE0007DB0E /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + 6C0B0C3D1E2537C6007F95E5 /* WirelessDiagnostics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WirelessDiagnostics.framework; path = System/Library/PrivateFrameworks/WirelessDiagnostics.framework; sourceTree = SDKROOT; }; + 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ProtocolBuffer.framework; path = System/Library/PrivateFrameworks/ProtocolBuffer.framework; sourceTree = SDKROOT; }; + 6C1520CD1DCCF57A00C85C6D /* secd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = secd.8; sourceTree = ""; }; + 6C34462F1E24F6BE00F9522B /* CKKSRateLimiterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSRateLimiterTests.m; sourceTree = ""; }; + 6C34464F1E2534E800F9522B /* AWDKeychainCKKSRateLimiterAggregatedScores.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AWDKeychainCKKSRateLimiterAggregatedScores.h; path = analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.h; sourceTree = ""; }; + 6C3446501E2534E800F9522B /* AWDKeychainCKKSRateLimiterAggregatedScores.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AWDKeychainCKKSRateLimiterAggregatedScores.m; path = analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.m; sourceTree = ""; }; + 6C3446511E2534E800F9522B /* AWDKeychainCKKSRateLimiterOverload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AWDKeychainCKKSRateLimiterOverload.h; path = analytics/awd/AWDKeychainCKKSRateLimiterOverload.h; sourceTree = ""; }; + 6C3446521E2534E800F9522B /* AWDKeychainCKKSRateLimiterOverload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AWDKeychainCKKSRateLimiterOverload.m; path = analytics/awd/AWDKeychainCKKSRateLimiterOverload.m; sourceTree = ""; }; + 6C3446531E2534E800F9522B /* AWDKeychainCKKSRateLimiterTopWriters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AWDKeychainCKKSRateLimiterTopWriters.h; path = analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.h; sourceTree = ""; }; + 6C3446541E2534E800F9522B /* AWDKeychainCKKSRateLimiterTopWriters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AWDKeychainCKKSRateLimiterTopWriters.m; path = analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.m; sourceTree = ""; }; + 6C3446551E2534E800F9522B /* AwdMetadata-0x60-Keychain.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = "AwdMetadata-0x60-Keychain.bin"; path = "analytics/awd/AwdMetadata-0x60-Keychain.bin"; sourceTree = ""; }; + 6C3446561E2534E800F9522B /* AWDMetricIds_Keychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AWDMetricIds_Keychain.h; path = analytics/awd/AWDMetricIds_Keychain.h; sourceTree = ""; }; + 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; }; + 6C588D791EAA149F00D7E322 /* RateLimiterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RateLimiterTests.m; sourceTree = ""; }; + 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; }; + 6CA2B9431E9F9F5700C43444 /* RateLimiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RateLimiter.h; sourceTree = ""; }; + 6CB5F4751E4025AB00DBF3F0 /* CKKSCloudKitTestsInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = CKKSCloudKitTestsInfo.plist; sourceTree = ""; }; + 6CB5F4781E402E5700DBF3F0 /* KeychainCKKS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = KeychainCKKS.plist; path = testrunner/KeychainCKKS.plist; sourceTree = ""; }; + 6CB5F4791E402E5700DBF3F0 /* KeychainEntitledTestRunner-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "KeychainEntitledTestRunner-Entitlements.plist"; sourceTree = ""; }; + 6CB5F47A1E402E5700DBF3F0 /* KeychainEntitledTestRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeychainEntitledTestRunner.m; sourceTree = ""; }; + 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSRateLimiter.h; sourceTree = ""; }; + 6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSRateLimiter.m; sourceTree = ""; }; + 6CC7F5B31E9F99EE0014AE63 /* RateLimiter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RateLimiter.m; sourceTree = ""; }; + 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 = ""; }; + 6CD8D3B11EB22114009AC7DC /* AWDKeychainSecDbMarkedCorrupt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AWDKeychainSecDbMarkedCorrupt.h; path = analytics/awd/AWDKeychainSecDbMarkedCorrupt.h; sourceTree = ""; }; + 6CD8D3B21EB22114009AC7DC /* AWDKeychainSecDbMarkedCorrupt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AWDKeychainSecDbMarkedCorrupt.m; path = analytics/awd/AWDKeychainSecDbMarkedCorrupt.m; sourceTree = ""; }; + 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; }; + 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 = ""; }; + 6CF4A0B71E45488B00ECD7B5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 6CF4A0BA1E45488B00ECD7B5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 6CF4A0BC1E45488B00ECD7B5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 6CF4A0BD1E45488B00ECD7B5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 6CF4A0BF1E45488B00ECD7B5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 6CF4A0C21E45488B00ECD7B5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 6CF4A0C41E45488B00ECD7B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 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 = ""; }; + 6CF4A0E51E4549F200ECD7B5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 6CF4A0E61E4549F300ECD7B5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 6CF4A0E81E4549F300ECD7B5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 6CF4A0E91E4549F300ECD7B5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 6CF4A0EC1E4549F300ECD7B5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 6CF4A0EE1E4549F300ECD7B5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 6CF4A0F11E4549F300ECD7B5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 6CF4A0F31E4549F300ECD7B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 7221843E1EC6782A004C7BED /* sec_action.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sec_action.c; path = src/sec_action.c; sourceTree = ""; }; + 7221843F1EC6782A004C7BED /* sec_action.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sec_action.h; path = src/sec_action.h; sourceTree = ""; }; 7273402816CAFB3C0096622A /* MobileAsset.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileAsset.framework; path = System/Library/PrivateFrameworks/MobileAsset.framework; sourceTree = SDKROOT; }; + 7281E0861DFD015A0021E1B7 /* SOSAccountGetSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountGetSet.m; sourceTree = ""; }; + 7281E08B1DFD0A380021E1B7 /* secd-80-views-alwayson.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-80-views-alwayson.m"; sourceTree = ""; }; + 7281E08E1DFD0D810021E1B7 /* secd-210-keyinterest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-210-keyinterest.m"; sourceTree = ""; }; 728B56A116D59979008FA3AB /* OTAPKIAssetTool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = OTAPKIAssetTool; sourceTree = BUILT_PRODUCTS_DIR; }; 72B368BD179891FC004C37CE /* AggregateDictionary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AggregateDictionary.framework; path = System/Library/PrivateFrameworks/AggregateDictionary.framework; sourceTree = SDKROOT; }; 72C3EC2D1705F24E0040C87C /* ManagedConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ManagedConfiguration.framework; path = System/Library/PrivateFrameworks/ManagedConfiguration.framework; sourceTree = SDKROOT; }; @@ -7325,7 +8904,14 @@ 8E64DB4C1C17CD3F0076C9DF /* com.apple.security.cloudkeychainproxy3.ios.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.security.cloudkeychainproxy3.ios.plist; path = KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.ios.plist; sourceTree = ""; }; 8E64DB4D1C17CD400076C9DF /* com.apple.security.cloudkeychainproxy3.osx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.security.cloudkeychainproxy3.osx.plist; path = KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.osx.plist; sourceTree = ""; }; 8ED6F6C8110904E300D2B368 /* SecPBKDF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPBKDF.h; sourceTree = ""; }; - BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecSharedCredential.h; sourceTree = ""; }; + ACBAF6DD1E9417F40007BA2F /* libsecurity_transform_regressions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurity_transform_regressions.a; sourceTree = BUILT_PRODUCTS_DIR; }; + ACBAF6E31E941AE00007BA2F /* transform_regressions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = transform_regressions.h; path = OSX/libsecurity_transform/regressions/transform_regressions.h; sourceTree = ""; }; + ACBAF6E51E941AE00007BA2F /* transform-01-sigverify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "transform-01-sigverify.m"; path = "OSX/libsecurity_transform/regressions/transform-01-sigverify.m"; sourceTree = ""; }; + ACBAF6FF1E947E860007BA2F /* testlist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = testlist.h; path = OSX/SecurityTestsOSX/testlist.h; sourceTree = ""; }; + B61577EE1F2021BC004A3930 /* padding-00-mmcs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "padding-00-mmcs.c"; sourceTree = ""; }; + B61F67541F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecPaddingConfigurationsPriv.h; path = src/SecPaddingConfigurationsPriv.h; sourceTree = ""; }; + B61F67551F1FCFCA00E2FDBB /* SecPaddingConfigurations.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = SecPaddingConfigurations.c; path = src/SecPaddingConfigurations.c; sourceTree = ""; }; + BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecSharedCredential.h; path = ../../../keychain/SecSharedCredential.h; sourceTree = ""; }; BE197F2619116FD100BA91D1 /* SharedWebCredentialViewService.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SharedWebCredentialViewService.app; sourceTree = BUILT_PRODUCTS_DIR; }; BE197F2919116FD100BA91D1 /* SharedWebCredentialViewService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SharedWebCredentialViewService-Info.plist"; sourceTree = ""; }; BE197F2B19116FD100BA91D1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -7337,17 +8923,75 @@ BE197F5D191173A800BA91D1 /* SWCViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWCViewController.m; sourceTree = ""; }; BE197F5F191173C100BA91D1 /* SWCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SWCViewController.h; sourceTree = ""; }; BE197F60191173F200BA91D1 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; + BE22FBC41EE0E8AB00893431 /* Monkey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Monkey.h; path = manifeststresstest/Monkey.h; sourceTree = ""; }; + BE22FBC51EE0E8AB00893431 /* Monkey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Monkey.m; path = manifeststresstest/Monkey.m; sourceTree = ""; }; + BE22FBCC1EE1E26600893431 /* Keychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Keychain.h; path = manifeststresstest/Keychain.h; sourceTree = ""; }; + BE22FBCD1EE1E26600893431 /* Keychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Keychain.m; path = manifeststresstest/Keychain.m; sourceTree = ""; }; + BE22FBCF1EE2084100893431 /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Config.h; path = manifeststresstest/Config.h; sourceTree = ""; }; + BE22FBD01EE2084100893431 /* Config.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Config.m; path = manifeststresstest/Config.m; sourceTree = ""; }; + BE22FBFC1EE23D9100893431 /* mark.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = mark.m; path = manifeststresstest/mark.m; sourceTree = ""; }; + BE22FC031EE23DA600893431 /* mark.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mark.h; path = manifeststresstest/mark.h; sourceTree = ""; }; BE442BC118B7FDB800F24DAE /* swcagent */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = swcagent; sourceTree = BUILT_PRODUCTS_DIR; }; BE4AC9A118B7FFAD00B84964 /* swcagent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = swcagent.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; BE4AC9AD18B7FFC800B84964 /* com.apple.security.swcagent.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.swcagent.plist; sourceTree = ""; }; BE4AC9B918B8273600B84964 /* English */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/SharedWebCredentials.strings; sourceTree = ""; }; - BE6D96B41DB14B65001B76D4 /* cnnic_certs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cnnic_certs.h; sourceTree = ""; }; - BE6D96B51DB14B65001B76D4 /* date_testing_certs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = date_testing_certs.h; sourceTree = ""; }; - BE6D96B61DB14B65001B76D4 /* wosign_certs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wosign_certs.h; sourceTree = ""; }; - BE6D96BA1DB14B9F001B76D4 /* si-84-sectrust-allowlist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-84-sectrust-allowlist.m"; sourceTree = ""; }; + BE6215BD1DB6E69100961E15 /* si-84-sectrust-allowlist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-84-sectrust-allowlist.m"; sourceTree = ""; }; + 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 = ""; }; BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; - BEE523CF1DA610D800DD0AA3 /* SecRevocationDb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecRevocationDb.c; sourceTree = ""; }; - BEE523D01DA610D800DD0AA3 /* SecRevocationDb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecRevocationDb.h; sourceTree = ""; }; + BED208DD1EDF950E00753952 /* manifeststresstest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = manifeststresstest; sourceTree = BUILT_PRODUCTS_DIR; }; + BED208E61EDF971600753952 /* manifeststresstest.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; name = manifeststresstest.entitlements; path = manifeststresstest/manifeststresstest.entitlements; sourceTree = ""; }; + BED208E71EDF971600753952 /* manifeststresstest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = manifeststresstest.m; path = manifeststresstest/manifeststresstest.m; sourceTree = ""; }; + BEEB47D71EA189F5004AA5C6 /* SecTrustStatusCodes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTrustStatusCodes.c; sourceTree = ""; }; + BEEB47D81EA189F5004AA5C6 /* SecTrustStatusCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustStatusCodes.h; sourceTree = ""; }; + BEF88C281EAFFC3F00357577 /* TrustedPeers.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TrustedPeers.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BEF88C301EAFFC3F00357577 /* TrustedPeersTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TrustedPeersTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + BEF88C471EB0005E00357577 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = keychain/trust/TrustedPeers/Info.plist; sourceTree = SOURCE_ROOT; }; + BEF88C481EB0005E00357577 /* TPCategoryRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPCategoryRule.h; path = keychain/trust/TrustedPeers/TPCategoryRule.h; sourceTree = SOURCE_ROOT; }; + BEF88C491EB0005E00357577 /* TPCategoryRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPCategoryRule.m; path = keychain/trust/TrustedPeers/TPCategoryRule.m; sourceTree = SOURCE_ROOT; }; + BEF88C4A1EB0005E00357577 /* TPCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPCircle.h; path = keychain/trust/TrustedPeers/TPCircle.h; sourceTree = SOURCE_ROOT; }; + BEF88C4B1EB0005E00357577 /* TPCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPCircle.m; path = keychain/trust/TrustedPeers/TPCircle.m; sourceTree = SOURCE_ROOT; }; + BEF88C4C1EB0005E00357577 /* TPDecrypter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPDecrypter.h; path = keychain/trust/TrustedPeers/TPDecrypter.h; sourceTree = SOURCE_ROOT; }; + BEF88C4D1EB0005E00357577 /* TPEncrypter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPEncrypter.h; path = keychain/trust/TrustedPeers/TPEncrypter.h; sourceTree = SOURCE_ROOT; }; + BEF88C4E1EB0005E00357577 /* TPHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPHash.h; path = keychain/trust/TrustedPeers/TPHash.h; sourceTree = SOURCE_ROOT; }; + BEF88C4F1EB0005E00357577 /* TPHash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPHash.m; path = keychain/trust/TrustedPeers/TPHash.m; sourceTree = SOURCE_ROOT; }; + BEF88C501EB0005E00357577 /* TPModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPModel.h; path = keychain/trust/TrustedPeers/TPModel.h; sourceTree = SOURCE_ROOT; }; + BEF88C511EB0005E00357577 /* TPModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPModel.m; path = keychain/trust/TrustedPeers/TPModel.m; sourceTree = SOURCE_ROOT; }; + BEF88C521EB0005E00357577 /* TPPeer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPPeer.h; path = keychain/trust/TrustedPeers/TPPeer.h; sourceTree = SOURCE_ROOT; }; + BEF88C531EB0005E00357577 /* TPPeer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPeer.m; path = keychain/trust/TrustedPeers/TPPeer.m; sourceTree = SOURCE_ROOT; }; + BEF88C541EB0005E00357577 /* TPPeerDynamicInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPPeerDynamicInfo.h; path = keychain/trust/TrustedPeers/TPPeerDynamicInfo.h; sourceTree = SOURCE_ROOT; }; + BEF88C551EB0005E00357577 /* TPPeerDynamicInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPeerDynamicInfo.m; path = keychain/trust/TrustedPeers/TPPeerDynamicInfo.m; sourceTree = SOURCE_ROOT; }; + BEF88C561EB0005E00357577 /* TPPeerPermanentInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPPeerPermanentInfo.h; path = keychain/trust/TrustedPeers/TPPeerPermanentInfo.h; sourceTree = SOURCE_ROOT; }; + BEF88C571EB0005E00357577 /* TPPeerPermanentInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPeerPermanentInfo.m; path = keychain/trust/TrustedPeers/TPPeerPermanentInfo.m; sourceTree = SOURCE_ROOT; }; + BEF88C581EB0005E00357577 /* TPPeerStableInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPPeerStableInfo.h; path = keychain/trust/TrustedPeers/TPPeerStableInfo.h; sourceTree = SOURCE_ROOT; }; + BEF88C591EB0005E00357577 /* TPPeerStableInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPeerStableInfo.m; path = keychain/trust/TrustedPeers/TPPeerStableInfo.m; sourceTree = SOURCE_ROOT; }; + BEF88C5A1EB0005E00357577 /* TPPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPPolicy.h; path = keychain/trust/TrustedPeers/TPPolicy.h; sourceTree = SOURCE_ROOT; }; + BEF88C5B1EB0005E00357577 /* TPPolicy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPolicy.m; path = keychain/trust/TrustedPeers/TPPolicy.m; sourceTree = SOURCE_ROOT; }; + BEF88C5C1EB0005E00357577 /* TPPolicyDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPPolicyDocument.h; path = keychain/trust/TrustedPeers/TPPolicyDocument.h; sourceTree = SOURCE_ROOT; }; + BEF88C5D1EB0005E00357577 /* TPPolicyDocument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPolicyDocument.m; path = keychain/trust/TrustedPeers/TPPolicyDocument.m; sourceTree = SOURCE_ROOT; }; + BEF88C5E1EB0005E00357577 /* TPSigningKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPSigningKey.h; path = keychain/trust/TrustedPeers/TPSigningKey.h; sourceTree = SOURCE_ROOT; }; + BEF88C5F1EB0005E00357577 /* TPTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPTypes.h; path = keychain/trust/TrustedPeers/TPTypes.h; sourceTree = SOURCE_ROOT; }; + BEF88C601EB0005E00357577 /* TPUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPUtils.h; path = keychain/trust/TrustedPeers/TPUtils.h; sourceTree = SOURCE_ROOT; }; + BEF88C611EB0005E00357577 /* TPUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPUtils.m; path = keychain/trust/TrustedPeers/TPUtils.m; sourceTree = SOURCE_ROOT; }; + BEF88C621EB0005E00357577 /* TPVoucher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPVoucher.h; path = keychain/trust/TrustedPeers/TPVoucher.h; sourceTree = SOURCE_ROOT; }; + BEF88C631EB0005F00357577 /* TPVoucher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPVoucher.m; path = keychain/trust/TrustedPeers/TPVoucher.m; sourceTree = SOURCE_ROOT; }; + BEF88C641EB0005F00357577 /* TrustedPeers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TrustedPeers.h; path = keychain/trust/TrustedPeers/TrustedPeers.h; sourceTree = SOURCE_ROOT; }; + BEF88C661EB0008E00357577 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = keychain/trust/TrustedPeersTests/Info.plist; sourceTree = SOURCE_ROOT; }; + BEF88C671EB0008E00357577 /* TPCircleTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPCircleTests.m; path = keychain/trust/TrustedPeersTests/TPCircleTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C681EB0008E00357577 /* TPDummyDecrypter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPDummyDecrypter.h; path = keychain/trust/TrustedPeersTests/TPDummyDecrypter.h; sourceTree = SOURCE_ROOT; }; + BEF88C691EB0008E00357577 /* TPDummyDecrypter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPDummyDecrypter.m; path = keychain/trust/TrustedPeersTests/TPDummyDecrypter.m; sourceTree = SOURCE_ROOT; }; + BEF88C6A1EB0008E00357577 /* TPDummyEncrypter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPDummyEncrypter.h; path = keychain/trust/TrustedPeersTests/TPDummyEncrypter.h; sourceTree = SOURCE_ROOT; }; + BEF88C6B1EB0008E00357577 /* TPDummyEncrypter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPDummyEncrypter.m; path = keychain/trust/TrustedPeersTests/TPDummyEncrypter.m; sourceTree = SOURCE_ROOT; }; + BEF88C6C1EB0008E00357577 /* TPDummySigningKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPDummySigningKey.h; path = keychain/trust/TrustedPeersTests/TPDummySigningKey.h; sourceTree = SOURCE_ROOT; }; + BEF88C6D1EB0008E00357577 /* TPDummySigningKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPDummySigningKey.m; path = keychain/trust/TrustedPeersTests/TPDummySigningKey.m; sourceTree = SOURCE_ROOT; }; + BEF88C6E1EB0008E00357577 /* TPDummySigningKeyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPDummySigningKeyTests.m; path = keychain/trust/TrustedPeersTests/TPDummySigningKeyTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C6F1EB0008E00357577 /* TPHashTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPHashTests.m; path = keychain/trust/TrustedPeersTests/TPHashTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C701EB0008E00357577 /* TPModelTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPModelTests.m; path = keychain/trust/TrustedPeersTests/TPModelTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C711EB0008E00357577 /* TPPeerPermanentInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPeerPermanentInfoTests.m; path = keychain/trust/TrustedPeersTests/TPPeerPermanentInfoTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C721EB0008E00357577 /* TPPeerStableInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPeerStableInfoTests.m; path = keychain/trust/TrustedPeersTests/TPPeerStableInfoTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C731EB0008E00357577 /* TPPeerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPeerTests.m; path = keychain/trust/TrustedPeersTests/TPPeerTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C741EB0008E00357577 /* TPPolicyDocumentTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPPolicyDocumentTests.m; path = keychain/trust/TrustedPeersTests/TPPolicyDocumentTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C751EB0008E00357577 /* TPUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPUtilsTests.m; path = keychain/trust/TrustedPeersTests/TPUtilsTests.m; sourceTree = SOURCE_ROOT; }; + BEF88C761EB0008E00357577 /* TPVoucherTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPVoucherTests.m; path = keychain/trust/TrustedPeersTests/TPVoucherTests.m; sourceTree = SOURCE_ROOT; }; CD23B4921DA06EB30047EDE9 /* IDSPersistentState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IDSPersistentState.h; path = KeychainSyncingOverIDSProxy/IDSPersistentState.h; sourceTree = ""; }; CD23B4931DA06EB30047EDE9 /* IDSPersistentState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = IDSPersistentState.m; path = KeychainSyncingOverIDSProxy/IDSPersistentState.m; sourceTree = ""; }; CD23B4941DA06EB30047EDE9 /* IDSProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IDSProxy.h; path = KeychainSyncingOverIDSProxy/IDSProxy.h; sourceTree = ""; }; @@ -7357,42 +9001,110 @@ CD23B4981DA06EB30047EDE9 /* KeychainSyncingOverIDSProxy+ReceiveMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "KeychainSyncingOverIDSProxy+ReceiveMessage.m"; path = "KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+ReceiveMessage.m"; sourceTree = ""; }; CD23B4991DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+SendMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "KeychainSyncingOverIDSProxy+SendMessage.h"; path = "KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+SendMessage.h"; sourceTree = ""; }; CD23B49A1DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+SendMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "KeychainSyncingOverIDSProxy+SendMessage.m"; path = "KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+SendMessage.m"; sourceTree = ""; }; - CD23B49B1DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+Throttle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "KeychainSyncingOverIDSProxy+Throttle.h"; path = "KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+Throttle.h"; sourceTree = ""; }; - CD23B49C1DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+Throttle.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "KeychainSyncingOverIDSProxy+Throttle.m"; path = "KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy+Throttle.m"; sourceTree = ""; }; CD23B4A81DA06ED10047EDE9 /* com.apple.private.alloy.keychainsync.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = com.apple.private.alloy.keychainsync.plist; path = KeychainSyncingOverIDSProxy/com.apple.private.alloy.keychainsync.plist; sourceTree = ""; }; CD276C271A83F60C003226BC /* KeychainSyncingOverIDSProxy.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeychainSyncingOverIDSProxy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + CD2F99D91DFC995B00769430 /* libsqlite3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.0.dylib; path = usr/lib/libsqlite3.0.dylib; sourceTree = SDKROOT; }; + CD31F8601DCD4C1400414B46 /* SOSAccountTrust.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SOSAccountTrust.m; path = SecureObjectSync/SOSAccountTrust.m; sourceTree = ""; }; + CD31F8611DCD4C1400414B46 /* SOSAccountTrust.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SOSAccountTrust.h; path = SecureObjectSync/SOSAccountTrust.h; sourceTree = ""; }; CD6130D31DA06FC600E1E42F /* com.apple.security.keychainsyncingoveridsproxy.ios.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.security.keychainsyncingoveridsproxy.ios.plist; path = KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.ios.plist; sourceTree = ""; }; CD6130D41DA06FC600E1E42F /* com.apple.security.keychainsyncingoveridsproxy.osx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.security.keychainsyncingoveridsproxy.osx.plist; path = KeychainSyncingOverIDSProxy/com.apple.security.keychainsyncingoveridsproxy.osx.plist; sourceTree = ""; }; CD6130D71DA06FC600E1E42F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = InfoPlist.strings; sourceTree = ""; }; CD6130D81DA06FC600E1E42F /* KeychainSyncingOverIDSProxy-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "KeychainSyncingOverIDSProxy-Info.plist"; path = "KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy-Info.plist"; sourceTree = ""; }; CD6130D91DA06FC600E1E42F /* keychainsyncingoveridsproxy.entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = keychainsyncingoveridsproxy.entitlements.plist; path = KeychainSyncingOverIDSProxy/keychainsyncingoveridsproxy.entitlements.plist; sourceTree = ""; }; CD744683195A00BB00FB01C0 /* IDS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IDS.framework; path = System/Library/PrivateFrameworks/IDS.framework; sourceTree = SDKROOT; }; + CD9021471DE27A9E00F81DC4 /* SOSAccountPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSAccountPriv.h; sourceTree = ""; }; + CDA43D251DFCA0790038E038 /* AggregateDictionary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AggregateDictionary.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.Internal.sdk/System/Library/PrivateFrameworks/AggregateDictionary.framework; sourceTree = DEVELOPER_DIR; }; CDB9FCA9179CC757000AAD66 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CDDE9BC31729AB910013B0E8 /* SecPasswordGenerate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPasswordGenerate.h; sourceTree = ""; }; - D46F31581E00A27D0065B550 /* SecTrustLoggingServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTrustLoggingServer.c; sourceTree = ""; }; - D46F31591E00A27D0065B550 /* SecTrustLoggingServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustLoggingServer.h; sourceTree = ""; }; - D46F31611E00CCD20065B550 /* SecCertificateSource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCertificateSource.c; sourceTree = ""; }; - D46F31621E00CCD20065B550 /* SecCertificateSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCertificateSource.h; sourceTree = ""; }; + D40B6A871E2B5F9900CD6EE5 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; }; + D40B6A881E2B5F9900CD6EE5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + D41149A01E7C935D00C078C7 /* AppleiPhoneDeviceCACertificates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleiPhoneDeviceCACertificates.h; sourceTree = ""; }; + D41257CF1E9410A300781F23 /* trustd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = trustd; sourceTree = BUILT_PRODUCTS_DIR; }; + D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.trustd.agent.plist; path = OSX/trustd/macOS/com.apple.trustd.agent.plist; sourceTree = ""; }; + D41257EA1E941CF200781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.trustd.plist; path = OSX/trustd/macOS/com.apple.trustd.plist; sourceTree = ""; }; + D41257EB1E941CF200781F23 /* com.apple.trustd.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = com.apple.trustd.sb; path = OSX/trustd/macOS/com.apple.trustd.sb; sourceTree = ""; }; + D41257EC1E941CF200781F23 /* trustd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = trustd.8; path = OSX/trustd/macOS/trustd.8; sourceTree = ""; }; + D41257ED1E941D5B00781F23 /* SecTrustOSXEntryPoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustOSXEntryPoints.h; path = OSX/trustd/macOS/SecTrustOSXEntryPoints.h; sourceTree = SOURCE_ROOT; }; + D41257EE1E941DA800781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.trustd.plist; path = OSX/trustd/iOS/com.apple.trustd.plist; sourceTree = ""; }; + D41D36701EB14D87007FA978 /* libDiagnosticMessagesClient.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libDiagnosticMessagesClient.tbd; path = usr/lib/libDiagnosticMessagesClient.tbd; sourceTree = SDKROOT; }; + D43761641EB2996C00954447 /* SecRevocationNetworking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecRevocationNetworking.h; path = OSX/sec/securityd/SecRevocationNetworking.h; sourceTree = ""; }; + D43761651EB2996C00954447 /* SecRevocationNetworking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecRevocationNetworking.m; path = OSX/sec/securityd/SecRevocationNetworking.m; sourceTree = ""; }; + D43DBED51E99D17100C04AEA /* asynchttp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = asynchttp.c; path = OSX/sec/securityd/asynchttp.c; sourceTree = ""; }; + D43DBED61E99D17100C04AEA /* asynchttp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = asynchttp.h; path = OSX/sec/securityd/asynchttp.h; sourceTree = ""; }; + D43DBED71E99D17100C04AEA /* nameconstraints.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nameconstraints.c; path = OSX/sec/securityd/nameconstraints.c; sourceTree = ""; }; + D43DBED81E99D17100C04AEA /* nameconstraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nameconstraints.h; path = OSX/sec/securityd/nameconstraints.h; sourceTree = ""; }; + D43DBED91E99D17100C04AEA /* OTATrustUtilities.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = OTATrustUtilities.c; path = OSX/sec/securityd/OTATrustUtilities.c; sourceTree = ""; }; + D43DBEDA1E99D17100C04AEA /* OTATrustUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OTATrustUtilities.h; path = OSX/sec/securityd/OTATrustUtilities.h; sourceTree = ""; }; + D43DBEDB1E99D17100C04AEA /* personalization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = personalization.c; path = OSX/sec/securityd/personalization.c; sourceTree = ""; }; + D43DBEDC1E99D17100C04AEA /* personalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = personalization.h; path = OSX/sec/securityd/personalization.h; sourceTree = ""; }; + D43DBEDD1E99D17100C04AEA /* policytree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = policytree.c; path = OSX/sec/securityd/policytree.c; sourceTree = ""; }; + D43DBEDE1E99D17200C04AEA /* policytree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = policytree.h; path = OSX/sec/securityd/policytree.h; sourceTree = ""; }; + D43DBEDF1E99D17200C04AEA /* SecCAIssuerCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCAIssuerCache.c; path = OSX/sec/securityd/SecCAIssuerCache.c; sourceTree = ""; }; + D43DBEE01E99D17200C04AEA /* SecCAIssuerCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCAIssuerCache.h; path = OSX/sec/securityd/SecCAIssuerCache.h; sourceTree = ""; }; + D43DBEE11E99D17200C04AEA /* SecCAIssuerRequest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCAIssuerRequest.c; path = OSX/sec/securityd/SecCAIssuerRequest.c; sourceTree = ""; }; + D43DBEE21E99D17200C04AEA /* SecCAIssuerRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCAIssuerRequest.h; path = OSX/sec/securityd/SecCAIssuerRequest.h; sourceTree = ""; }; + D43DBEE31E99D17200C04AEA /* SecCertificateServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCertificateServer.c; path = OSX/sec/securityd/SecCertificateServer.c; sourceTree = ""; }; + D43DBEE41E99D17200C04AEA /* SecCertificateServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateServer.h; path = OSX/sec/securityd/SecCertificateServer.h; sourceTree = ""; }; + D43DBEE51E99D17200C04AEA /* SecCertificateSource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCertificateSource.c; path = OSX/sec/securityd/SecCertificateSource.c; sourceTree = ""; }; + D43DBEE61E99D17200C04AEA /* SecCertificateSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateSource.h; path = OSX/sec/securityd/SecCertificateSource.h; sourceTree = ""; }; + D43DBEE71E99D17200C04AEA /* SecOCSPCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPCache.c; path = OSX/sec/securityd/SecOCSPCache.c; sourceTree = ""; }; + D43DBEE81E99D17200C04AEA /* SecOCSPCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPCache.h; path = OSX/sec/securityd/SecOCSPCache.h; sourceTree = ""; }; + D43DBEE91E99D17200C04AEA /* SecOCSPRequest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPRequest.c; path = OSX/sec/securityd/SecOCSPRequest.c; sourceTree = ""; }; + D43DBEEA1E99D17200C04AEA /* SecOCSPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPRequest.h; path = OSX/sec/securityd/SecOCSPRequest.h; sourceTree = ""; }; + D43DBEEB1E99D17200C04AEA /* SecOCSPResponse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPResponse.c; path = OSX/sec/securityd/SecOCSPResponse.c; sourceTree = ""; }; + D43DBEEC1E99D17200C04AEA /* SecOCSPResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPResponse.h; path = OSX/sec/securityd/SecOCSPResponse.h; sourceTree = ""; }; + D43DBEED1E99D17200C04AEA /* SecPinningDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPinningDb.h; path = OSX/sec/securityd/SecPinningDb.h; sourceTree = ""; }; + D43DBEEE1E99D17200C04AEA /* SecPinningDb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecPinningDb.m; path = OSX/sec/securityd/SecPinningDb.m; sourceTree = ""; }; + D43DBEEF1E99D17300C04AEA /* SecPolicyServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecPolicyServer.c; path = OSX/sec/securityd/SecPolicyServer.c; sourceTree = ""; }; + D43DBEF01E99D17300C04AEA /* SecPolicyServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicyServer.h; path = OSX/sec/securityd/SecPolicyServer.h; sourceTree = ""; }; + D43DBEF11E99D17300C04AEA /* SecRevocationDb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecRevocationDb.c; path = OSX/sec/securityd/SecRevocationDb.c; sourceTree = ""; }; + D43DBEF21E99D17300C04AEA /* SecRevocationDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecRevocationDb.h; path = OSX/sec/securityd/SecRevocationDb.h; sourceTree = ""; }; + D43DBEF31E99D17300C04AEA /* SecRevocationServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecRevocationServer.c; path = OSX/sec/securityd/SecRevocationServer.c; sourceTree = ""; }; + D43DBEF41E99D17300C04AEA /* SecRevocationServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecRevocationServer.h; path = OSX/sec/securityd/SecRevocationServer.h; sourceTree = ""; }; + D43DBEF51E99D17300C04AEA /* SecTrustLoggingServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecTrustLoggingServer.c; path = OSX/sec/securityd/SecTrustLoggingServer.c; sourceTree = ""; }; + D43DBEF61E99D17300C04AEA /* SecTrustLoggingServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustLoggingServer.h; path = OSX/sec/securityd/SecTrustLoggingServer.h; sourceTree = ""; }; + D43DBEF71E99D17300C04AEA /* SecTrustServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecTrustServer.c; path = OSX/sec/securityd/SecTrustServer.c; sourceTree = ""; }; + D43DBEF81E99D17300C04AEA /* SecTrustServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustServer.h; path = OSX/sec/securityd/SecTrustServer.h; sourceTree = ""; }; + D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecTrustStoreServer.c; path = OSX/sec/securityd/SecTrustStoreServer.c; sourceTree = ""; }; + D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustStoreServer.h; path = OSX/sec/securityd/SecTrustStoreServer.h; sourceTree = ""; }; + D45068681E948A9E00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/macOS/entitlements.plist; sourceTree = ""; }; + D45068691E948ACE00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/iOS/entitlements.plist; sourceTree = ""; }; D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64.xcconfig; path = xcconfig/lib_ios_x64.xcconfig; sourceTree = ""; }; - D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_debug.xcconfig; path = xcconfig/lib_ios_x64_debug.xcconfig; sourceTree = ""; }; - D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_release.xcconfig; path = xcconfig/lib_ios_x64_release.xcconfig; sourceTree = ""; }; - D47C56AF1DCA841D00E18518 /* lib_ios_x64_debug_shim.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_debug_shim.xcconfig; path = xcconfig/lib_ios_x64_debug_shim.xcconfig; sourceTree = ""; }; - D47C56B01DCA843800E18518 /* lib_ios_x64_release_shim.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_release_shim.xcconfig; path = xcconfig/lib_ios_x64_release_shim.xcconfig; sourceTree = ""; }; + D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_shim.xcconfig; path = xcconfig/lib_ios_x64_shim.xcconfig; sourceTree = ""; }; D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = all_arches.xcconfig; path = xcconfig/all_arches.xcconfig; sourceTree = ""; }; + D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMobileGestalt.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.Internal.sdk/usr/lib/libMobileGestalt.dylib; sourceTree = DEVELOPER_DIR; }; D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecCFAllocator.h; sourceTree = ""; }; D487FBB71DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-29-sectrust-sha1-deprecation.m"; sourceTree = ""; }; D487FBB91DB835B500D4BB0B /* si-29-sectrust-sha1-deprecation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-29-sectrust-sha1-deprecation.h"; sourceTree = ""; }; + D48F029B1EA1671B00ACC3C9 /* si-61-pkcs12.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-61-pkcs12.h"; sourceTree = ""; }; + D4AA647C1E97144700D317ED /* si-18-certificate-parse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-18-certificate-parse.m"; sourceTree = ""; }; + D4AA64831E97270300D317ED /* si-18-certificate-parse */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-18-certificate-parse"; path = "OSX/shared_regressions/si-18-certificate-parse"; sourceTree = SOURCE_ROOT; }; + D4ADA30E1E2B1E650031CEA3 /* trustd-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "trustd-Info.plist"; path = "OSX/trustd/trustd-Info.plist"; sourceTree = ""; }; + D4ADA3191E2B41670031CEA3 /* libtrustd.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtrustd.a; sourceTree = BUILT_PRODUCTS_DIR; }; D4B858661D370D9A003B2D95 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; + D4BEECE61E93093A00F76D1A /* trustd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trustd.c; path = OSX/trustd/trustd.c; sourceTree = ""; }; + D4C8A1511E66709800CD6DF1 /* si-32-sectrust-pinning-required.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-32-sectrust-pinning-required.h"; sourceTree = ""; }; + D4CFAA7D1E660BB3004746AA /* si-32-sectrust-pinning-required.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-32-sectrust-pinning-required.m"; sourceTree = ""; }; D4D718341E04A721000AE7A6 /* spbkdf-01-hmac-sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "spbkdf-01-hmac-sha256.c"; sourceTree = ""; }; D4D886BE1CEB9F3B00DC7583 /* ssl-policy-certs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "ssl-policy-certs"; sourceTree = ""; }; D4D886E81CEBDD2A00DC7583 /* nist-certs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "nist-certs"; sourceTree = ""; }; D4EC94FA1CEA482D0083E753 /* si-20-sectrust-policies-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-20-sectrust-policies-data"; path = "../OSX/shared_regressions/si-20-sectrust-policies-data"; sourceTree = ""; }; + D4FBBD601DD66196004408F7 /* CMSEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMSEncoder.h; sourceTree = ""; }; + D4FBBD611DD66196004408F7 /* CMSDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMSDecoder.h; sourceTree = ""; }; + D4FC521C1EC3E05B00E99785 /* smime_attr_emails.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = smime_attr_emails.h; sourceTree = ""; }; + 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 = ""; }; + DA30D6831DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeychainSyncAccountUpdater.h; sourceTree = ""; }; + DA30D6841DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeychainSyncAccountUpdater.m; sourceTree = ""; }; DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = macos_legacy_lib.xcconfig; path = xcconfig/macos_legacy_lib.xcconfig; sourceTree = ""; }; DC0067C01D87876F005AF8DB /* libsecurityd_server.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurityd_server.a; sourceTree = BUILT_PRODUCTS_DIR; }; DC0067D01D878898005AF8DB /* libsecurityd_ucspc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurityd_ucspc.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DC08D1C21E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CloudKitKeychainSyncingMockXCTest.h; sourceTree = ""; }; + DC08D1C31E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CloudKitKeychainSyncingMockXCTest.m; sourceTree = ""; }; + DC08D1CB1E64FCC5006237DA /* CKKSSOSTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSSOSTests.m; sourceTree = ""; }; DC0B62261D90973900D43BCB /* si-25-cms-skid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-25-cms-skid.h"; sourceTree = ""; }; DC0B62271D90973900D43BCB /* si-25-cms-skid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-25-cms-skid.m"; sourceTree = ""; }; - DC0B622B1D90982100D43BCB /* secd-201-coders.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-201-coders.c"; sourceTree = ""; }; + DC0B622B1D90982100D43BCB /* secd-201-coders.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-201-coders.m"; sourceTree = ""; }; DC0B622E1D909C4600D43BCB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; DC0BC5461D8B6AFE00070CB0 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; DC0BC5471D8B6AFE00070CB0 /* XPCKeychainSandboxCheck-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "XPCKeychainSandboxCheck-Info.plist"; sourceTree = ""; }; @@ -7680,7 +9392,6 @@ DC0BC9EB1D8B827200070CB0 /* sslMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sslMemory.h; sourceTree = ""; }; DC0BC9EC1D8B827200070CB0 /* sslPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sslPriv.h; sourceTree = ""; }; DC0BC9ED1D8B827200070CB0 /* sslRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sslRecord.h; sourceTree = ""; }; - DC0BC9EE1D8B827200070CB0 /* sslUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sslUtils.h; sourceTree = ""; }; DC0BC9F01D8B827200070CB0 /* sslCrypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sslCrypto.c; sourceTree = ""; }; DC0BC9F21D8B827200070CB0 /* sslMemory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sslMemory.c; sourceTree = ""; }; DC0BC9F31D8B827200070CB0 /* sslUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sslUtils.c; sourceTree = ""; }; @@ -7826,7 +9537,6 @@ DC0BCC091D8C64B500070CB0 /* testpolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = testpolicy.h; path = OSX/regressions/test/testpolicy.h; sourceTree = ""; }; DC0BCC0A1D8C64B500070CB0 /* testpolicy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = testpolicy.m; path = OSX/regressions/test/testpolicy.m; sourceTree = ""; }; DC0BCC361D8C684F00070CB0 /* libutilities.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libutilities.a; sourceTree = BUILT_PRODUCTS_DIR; }; - DC0BCC391D8C68CF00070CB0 /* SecMeta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = SecMeta.h; path = src/SecMeta.h; sourceTree = ""; }; DC0BCC3A1D8C68CF00070CB0 /* iCloudKeychainTrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = iCloudKeychainTrace.c; path = src/iCloudKeychainTrace.c; sourceTree = ""; }; DC0BCC3B1D8C68CF00070CB0 /* iCloudKeychainTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iCloudKeychainTrace.h; path = src/iCloudKeychainTrace.h; sourceTree = ""; }; DC0BCC3C1D8C68CF00070CB0 /* SecAKSWrappers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecAKSWrappers.c; path = src/SecAKSWrappers.c; sourceTree = ""; }; @@ -7835,8 +9545,6 @@ DC0BCC3F1D8C68CF00070CB0 /* SecBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecBuffer.h; path = src/SecBuffer.h; sourceTree = ""; }; DC0BCC401D8C68CF00070CB0 /* SecCoreCrypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCoreCrypto.c; path = src/SecCoreCrypto.c; sourceTree = ""; }; DC0BCC411D8C68CF00070CB0 /* SecCoreCrypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCoreCrypto.h; path = src/SecCoreCrypto.h; sourceTree = ""; }; - DC0BCC421D8C68CF00070CB0 /* SecCertificateTrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCertificateTrace.c; path = src/SecCertificateTrace.c; sourceTree = ""; }; - DC0BCC431D8C68CF00070CB0 /* SecCertificateTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateTrace.h; path = src/SecCertificateTrace.h; sourceTree = ""; }; DC0BCC441D8C68CF00070CB0 /* SecCFCCWrappers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCFCCWrappers.c; path = src/SecCFCCWrappers.c; sourceTree = ""; }; DC0BCC451D8C68CF00070CB0 /* SecCFCCWrappers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCFCCWrappers.h; path = src/SecCFCCWrappers.h; sourceTree = ""; }; DC0BCC461D8C68CF00070CB0 /* SecCFRelease.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCFRelease.h; path = src/SecCFRelease.h; sourceTree = ""; }; @@ -7901,7 +9609,10 @@ DC0BCD541D8C697100070CB0 /* su-16-cfdate-der.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "su-16-cfdate-der.c"; sourceTree = ""; }; DC0BCD551D8C697100070CB0 /* su-40-secdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "su-40-secdb.c"; sourceTree = ""; }; DC0BCD561D8C697100070CB0 /* su-41-secdb-stress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "su-41-secdb-stress.c"; sourceTree = ""; }; - DC0BCDB41D8C6A5B00070CB0 /* not_on_this_platorm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = not_on_this_platorm.c; path = ../../utilities/SecurityTool/not_on_this_platorm.c; sourceTree = ""; }; + DC0BCDB41D8C6A5B00070CB0 /* not_on_this_platorm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = not_on_this_platorm.c; sourceTree = ""; }; + DC15F7641E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSHealKeyHierarchyOperation.h; sourceTree = ""; }; + DC15F7651E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSHealKeyHierarchyOperation.m; sourceTree = ""; }; + DC15F79B1E68EAD5003B9A40 /* CKKSTests+API.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CKKSTests+API.m"; sourceTree = ""; }; DC1784421D77869A00B50D50 /* libsecurity_smime.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libsecurity_smime.xcodeproj; path = OSX/libsecurity_smime/libsecurity_smime.xcodeproj; sourceTree = ""; }; DC1784AE1D7786C700B50D50 /* libsecurity_cms.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libsecurity_cms.xcodeproj; path = OSX/libsecurity_cms/libsecurity_cms.xcodeproj; sourceTree = ""; }; DC1785051D77873100B50D50 /* Security.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Security.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -8013,11 +9724,8 @@ DC1787461D7790A500B50D50 /* SecCodeHostLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCodeHostLib.h; path = lib/SecCodeHostLib.h; sourceTree = ""; }; DC1787471D7790A500B50D50 /* SecCodePriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCodePriv.h; path = lib/SecCodePriv.h; sourceTree = ""; }; DC1787481D7790A500B50D50 /* SecCodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCodeSigner.h; path = lib/SecCodeSigner.h; sourceTree = ""; }; - DC1787491D7790A500B50D50 /* SecIntegrity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIntegrity.h; path = lib/SecIntegrity.h; sourceTree = ""; }; - DC17874A1D7790A500B50D50 /* SecIntegrityLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIntegrityLib.h; path = lib/SecIntegrityLib.h; sourceTree = ""; }; DC17874B1D7790A500B50D50 /* SecRequirementPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecRequirementPriv.h; path = lib/SecRequirementPriv.h; sourceTree = ""; }; DC17874C1D7790A500B50D50 /* SecStaticCodePriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecStaticCodePriv.h; path = lib/SecStaticCodePriv.h; sourceTree = ""; }; - DC17874D1D7790A500B50D50 /* SecTaskPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTaskPriv.h; path = lib/SecTaskPriv.h; sourceTree = ""; }; DC1787581D7790B600B50D50 /* CMSPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CMSPrivate.h; path = OSX/libsecurity_cms/lib/CMSPrivate.h; sourceTree = ""; }; DC17875B1D7790CE00B50D50 /* checkpw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = checkpw.h; path = OSX/libsecurity_checkpw/lib/checkpw.h; sourceTree = ""; }; DC17875D1D7790E500B50D50 /* AuthorizationPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AuthorizationPriv.h; path = OSX/libsecurity_authorization/lib/AuthorizationPriv.h; sourceTree = ""; }; @@ -8037,7 +9745,6 @@ DC1789141D77997F00B50D50 /* libOpenScriptingUtil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libOpenScriptingUtil.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libOpenScriptingUtil.dylib; sourceTree = DEVELOPER_DIR; }; DC1789161D77998700B50D50 /* libauto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauto.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libauto.dylib; sourceTree = DEVELOPER_DIR; }; DC1789181D77998C00B50D50 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libbsm.dylib; sourceTree = DEVELOPER_DIR; }; - DC17891A1D77999200B50D50 /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libobjc.dylib; sourceTree = DEVELOPER_DIR; }; DC17891C1D77999700B50D50 /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libpam.dylib; sourceTree = DEVELOPER_DIR; }; DC17891E1D77999D00B50D50 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libsqlite3.dylib; sourceTree = DEVELOPER_DIR; }; DC1789201D7799A100B50D50 /* libxar.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxar.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libxar.dylib; sourceTree = DEVELOPER_DIR; }; @@ -8063,7 +9770,6 @@ DC178A1C1D77A1E700B50D50 /* tp_policyOids.mdsinfo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = tp_policyOids.mdsinfo; path = OSX/libsecurity_apple_x509_tp/mds/tp_policyOids.mdsinfo; sourceTree = ""; }; DC178A1D1D77A1E700B50D50 /* tp_primary.mdsinfo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = tp_primary.mdsinfo; path = OSX/libsecurity_apple_x509_tp/mds/tp_primary.mdsinfo; sourceTree = ""; }; DC178A1E1D77A1E700B50D50 /* sd_cspdl_common.mdsinfo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = sd_cspdl_common.mdsinfo; path = OSX/libsecurity_sd_cspdl/mds/sd_cspdl_common.mdsinfo; sourceTree = ""; }; - DC178A301D77A1F500B50D50 /* iToolsTrustedApps.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = iToolsTrustedApps.plist; path = OSX/libsecurity_keychain/plist/iToolsTrustedApps.plist; sourceTree = ""; }; DC178A311D77A1F500B50D50 /* FDEPrefs.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = FDEPrefs.plist; path = OSX/lib/FDEPrefs.plist; sourceTree = ""; }; DC178A321D77A1F500B50D50 /* SecDebugErrorMessages.strings */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = SecDebugErrorMessages.strings; path = derived_src/SecDebugErrorMessages.strings; sourceTree = BUILT_PRODUCTS_DIR; }; DC178A341D77A1F500B50D50 /* SecErrorMessages.strings */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = SecErrorMessages.strings; path = derived_src/en.lproj/SecErrorMessages.strings; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -8074,6 +9780,21 @@ DC178A3E1D77A1F500B50D50 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = OSX/lib/en.lproj/authorization.buttons.strings; sourceTree = ""; }; DC178A401D77A1F500B50D50 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = OSX/lib/en.lproj/authorization.prompts.strings; sourceTree = ""; }; DC178BB11D77A5F500B50D50 /* security_framework_macos.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = security_framework_macos.xcconfig; path = OSX/config/security_framework_macos.xcconfig; sourceTree = ""; }; + DC18F76D1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSFetchAllRecordZoneChangesOperation.h; sourceTree = ""; }; + DC18F76E1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSFetchAllRecordZoneChangesOperation.m; sourceTree = ""; }; + DC1DA65C1E4554620094CE7F /* CKKSScanLocalItemsOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSScanLocalItemsOperation.h; sourceTree = ""; }; + DC1DA6671E4555D80094CE7F /* CKKSScanLocalItemsOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSScanLocalItemsOperation.m; sourceTree = ""; }; + DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSItemEncrypter.m; sourceTree = ""; }; + DC1ED8C01DD51890002BDCFA /* CKKSItemEncrypter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSItemEncrypter.h; sourceTree = ""; }; + DC1ED8C21DD5538C002BDCFA /* CKKS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKS.h; sourceTree = ""; }; + DC1ED8C51DD55476002BDCFA /* CKKS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKS.m; sourceTree = ""; }; + DC207EB61ED4EAB600D46873 /* CKKSLockStateTracker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSLockStateTracker.h; sourceTree = ""; }; + DC207EB71ED4EAB600D46873 /* CKKSLockStateTracker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSLockStateTracker.m; sourceTree = ""; }; + DC222C771E034D1F00B09171 /* libsecurityd_ios_NO_AKS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurityd_ios_NO_AKS.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DC222C891E089BAE00B09171 /* CKKSSQLTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSSQLTests.m; sourceTree = ""; }; + DC222CA61E08A7D900B09171 /* CloudKitMockXCTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CloudKitMockXCTest.h; sourceTree = ""; }; + DC222CA71E08A7D900B09171 /* CloudKitMockXCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CloudKitMockXCTest.m; sourceTree = ""; }; + DC222CA91E08C57400B09171 /* CloudKitDependencies.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CloudKitDependencies.h; sourceTree = ""; }; DC24B5581DA326B900330B48 /* agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = agent.h; path = OSX/authd/agent.h; sourceTree = ""; }; DC24B5591DA326B900330B48 /* authdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = authdb.h; path = OSX/authd/authdb.h; sourceTree = ""; }; DC24B55A1DA326B900330B48 /* authitems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = authitems.h; path = OSX/authd/authitems.h; sourceTree = ""; }; @@ -8113,15 +9834,39 @@ DC24B5811DA420D700330B48 /* SOSEnginePriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSEnginePriv.h; sourceTree = ""; }; DC24B5821DA420D700330B48 /* SOSPersist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPersist.h; sourceTree = ""; }; DC24B5831DA422BE00330B48 /* base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = base.xcconfig; path = OSX/config/base.xcconfig; sourceTree = ""; }; - DC24B5841DA432C600330B48 /* IDSKeychainSyncingProxy.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = IDSKeychainSyncingProxy.1; path = OSX/sec/IDSKeychainSyncingProxy/IDSKeychainSyncingProxy.1; sourceTree = SOURCE_ROOT; }; - DC24B5851DA432E900330B48 /* CloudKeychainProxy.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = CloudKeychainProxy.1; path = OSX/sec/CloudKeychainProxy/CloudKeychainProxy.1; sourceTree = ""; }; + DC24B5841DA432C600330B48 /* KeychainSyncingOverIDSProxy.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = KeychainSyncingOverIDSProxy.8; path = KeychainSyncingOverIDSProxy/KeychainSyncingOverIDSProxy.8; sourceTree = SOURCE_ROOT; }; + DC24B5851DA432E900330B48 /* CloudKeychainProxy.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CloudKeychainProxy.8; path = OSX/sec/CloudKeychainProxy/CloudKeychainProxy.8; sourceTree = ""; }; + DC27B57D1DDFC24500599261 /* libsqlite3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.0.dylib; path = usr/lib/libsqlite3.0.dylib; sourceTree = SDKROOT; }; + DC2C5F5A1F0EB97E00FEBDA7 /* CKKSNotifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSNotifier.h; sourceTree = ""; }; + DC2C5F5B1F0EB97E00FEBDA7 /* CKKSNotifier.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSNotifier.m; sourceTree = ""; }; + 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 = ""; }; + DC3502B91E0208BE00BC0587 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DC3502DA1E02121800BC0587 /* CryptoTokenKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CryptoTokenKit.framework; path = System/Library/Frameworks/CryptoTokenKit.framework; sourceTree = SDKROOT; }; + DC3502E51E0214C800BC0587 /* MockCloudKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockCloudKit.h; sourceTree = ""; }; + DC3502E61E0214C800BC0587 /* MockCloudKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MockCloudKit.m; sourceTree = ""; }; + DC3502E81E02172C00BC0587 /* OCMock.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OCMock.framework; path = ../../AppleInternal/Library/Frameworks/OCMock.framework; sourceTree = SDKROOT; }; + DC378B2C1DEF9DF000A3DAFA /* CKKSMirrorEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSMirrorEntry.h; sourceTree = ""; }; + DC378B2E1DEF9E0E00A3DAFA /* CKKSMirrorEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSMirrorEntry.m; sourceTree = ""; }; + DC378B361DEFADB500A3DAFA /* CKKSZoneStateEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSZoneStateEntry.h; sourceTree = ""; }; + DC378B371DEFADB500A3DAFA /* CKKSZoneStateEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSZoneStateEntry.m; sourceTree = ""; }; + DC378B3A1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSIncomingQueueEntry.h; sourceTree = ""; }; + DC378B3B1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSIncomingQueueEntry.m; sourceTree = ""; }; + DC3832C01DB6E69800385F63 /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; DC3A4B581D91E9FB00E46D4A /* com.apple.CodeSigningHelper.xpc */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = com.apple.CodeSigningHelper.xpc; sourceTree = BUILT_PRODUCTS_DIR; }; DC3A4B5F1D91EAC500E46D4A /* CodeSigningHelper-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "CodeSigningHelper-Info.plist"; sourceTree = ""; }; DC3A4B601D91EAC500E46D4A /* com.apple.CodeSigningHelper.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = com.apple.CodeSigningHelper.sb; sourceTree = ""; }; DC3A4B621D91EAC500E46D4A /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + DC3A81D41D99D567000C7419 /* libcoretls_cfhelpers.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcoretls_cfhelpers.dylib; path = usr/lib/libcoretls_cfhelpers.dylib; sourceTree = SDKROOT; }; + DC4269031E82EDAC002B7110 /* SecItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecItem.m; sourceTree = ""; }; + DC4269061E82FBDF002B7110 /* server_security_helpers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = server_security_helpers.c; sourceTree = ""; }; + DC4269071E82FBDF002B7110 /* server_security_helpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = server_security_helpers.h; sourceTree = ""; }; + DC4DB14E1E24692100CD6769 /* CKKSKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSKey.h; sourceTree = ""; }; + DC4DB14F1E24692100CD6769 /* CKKSKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSKey.m; sourceTree = ""; }; + DC4DB15E1E2590B100CD6769 /* CKKSEncryptionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSEncryptionTests.m; sourceTree = ""; }; + DC5225091E402D8B0021640A /* PlatformLibraries.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = PlatformLibraries.xcconfig; path = xcconfig/PlatformLibraries.xcconfig; sourceTree = ""; }; DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecurityd_ios.a; sourceTree = BUILT_PRODUCTS_DIR; }; - DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecipc_client.a; sourceTree = BUILT_PRODUCTS_DIR; }; - DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecureObjectSync.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecureObjectSyncServer.a; sourceTree = BUILT_PRODUCTS_DIR; }; DC52EA4C1D80CB7000B0A59C /* libSecurityTool.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecurityTool.a; sourceTree = BUILT_PRODUCTS_DIR; }; DC52EA8E1D80CC2A00B0A59C /* builtin_commands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = builtin_commands.h; sourceTree = ""; }; DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = digest_calc.c; sourceTree = ""; }; @@ -8199,7 +9944,7 @@ DC5ABD831D832D5800CF422C /* display_error_code.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = display_error_code.h; sourceTree = ""; }; DC5ABD841D832D5800CF422C /* trusted_cert_dump.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = trusted_cert_dump.c; sourceTree = ""; }; DC5ABD851D832D5800CF422C /* trusted_cert_dump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = trusted_cert_dump.h; sourceTree = ""; }; - DC5ABD861D832D5800CF422C /* identity_find.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = identity_find.c; sourceTree = ""; }; + DC5ABD861D832D5800CF422C /* identity_find.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = identity_find.m; sourceTree = ""; }; DC5ABD871D832D5800CF422C /* identity_find.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = identity_find.h; sourceTree = ""; }; DC5ABD881D832D5800CF422C /* identity_prefs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = identity_prefs.c; sourceTree = ""; }; DC5ABD891D832D5800CF422C /* identity_prefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = identity_prefs.h; sourceTree = ""; }; @@ -8211,7 +9956,7 @@ DC5ABD8F1D832D5800CF422C /* keychain_create.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keychain_create.h; sourceTree = ""; }; DC5ABD901D832D5800CF422C /* keychain_delete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = keychain_delete.c; sourceTree = ""; }; DC5ABD911D832D5800CF422C /* keychain_delete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keychain_delete.h; sourceTree = ""; }; - DC5ABD921D832D5800CF422C /* keychain_export.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = keychain_export.c; sourceTree = ""; }; + DC5ABD921D832D5800CF422C /* keychain_export.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = keychain_export.m; sourceTree = ""; }; DC5ABD931D832D5800CF422C /* keychain_export.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = keychain_export.h; sourceTree = ""; }; DC5ABD941D832D5800CF422C /* keychain_find.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = keychain_find.c; sourceTree = ""; }; DC5ABD951D832D5800CF422C /* keychain_find.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keychain_find.h; sourceTree = ""; }; @@ -8349,6 +10094,14 @@ DC5AC0FF1D83550300CF422C /* self.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = self.h; path = derived_src/self.h; sourceTree = BUILT_PRODUCTS_DIR; }; DC5AC1001D83550300CF422C /* selfServer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = selfServer.cpp; path = derived_src/selfServer.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; DC5AC1011D83550300CF422C /* selfUser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = selfUser.cpp; path = derived_src/selfUser.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; + DC5BB4F01E0C86800010F836 /* CKKSIncomingQueueOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSIncomingQueueOperation.h; sourceTree = ""; }; + DC5BB4F11E0C86800010F836 /* CKKSIncomingQueueOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSIncomingQueueOperation.m; sourceTree = ""; }; + DC5BB4FC1E0C98320010F836 /* CKKSOutgoingQueueOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSOutgoingQueueOperation.h; sourceTree = ""; }; + DC5BB4FD1E0C98320010F836 /* CKKSOutgoingQueueOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSOutgoingQueueOperation.m; sourceTree = ""; }; + DC5BCC461E5380EA00649140 /* SecArgParse.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = SecArgParse.c; path = lib/SecArgParse.c; sourceTree = ""; }; + DC5BCC471E5380EA00649140 /* SecArgParse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecArgParse.h; path = lib/SecArgParse.h; sourceTree = ""; }; + DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = server_entitlement_helpers.c; sourceTree = ""; }; + DC5F35A51EE0F1A900900966 /* server_entitlement_helpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = server_entitlement_helpers.h; sourceTree = ""; }; DC610A341D78F129002223DE /* secdtests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secdtests; sourceTree = BUILT_PRODUCTS_DIR; }; DC610A3A1D78F228002223DE /* libACM.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libACM.a; path = usr/local/lib/libACM.a; sourceTree = SDKROOT; }; DC610A3C1D78F25C002223DE /* libDiagnosticMessagesClient.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libDiagnosticMessagesClient.dylib; path = usr/lib/libDiagnosticMessagesClient.dylib; sourceTree = SDKROOT; }; @@ -8363,8 +10116,10 @@ DC610A681D78FA87002223DE /* validation.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = validation.sh; path = OSX/codesign_tests/validation.sh; sourceTree = ""; }; DC610AB71D7910C3002223DE /* gk_reset_check */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gk_reset_check; sourceTree = BUILT_PRODUCTS_DIR; }; DC610AB91D7910F8002223DE /* gk_reset_check.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gk_reset_check.c; path = OSX/gk_reset_check/gk_reset_check.c; sourceTree = ""; }; - DC65E7BE1D8CBB1500152EF0 /* readline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = readline.c; path = ../../utilities/SecurityTool/readline.c; sourceTree = ""; }; - DC65E7BF1D8CBB1500152EF0 /* readline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = readline.h; path = ../../utilities/SecurityTool/readline.h; sourceTree = ""; }; + DC6593C91ED8DA9200C19462 /* CKKSTests+CurrentPointerAPI.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CKKSTests+CurrentPointerAPI.m"; sourceTree = ""; }; + DC6593D21ED8DBCE00C19462 /* CKKSTests+API.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CKKSTests+API.h"; sourceTree = ""; }; + DC65E7BE1D8CBB1500152EF0 /* readline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readline.c; sourceTree = ""; }; + DC65E7BF1D8CBB1500152EF0 /* readline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = readline.h; sourceTree = ""; }; DC6A82531D87732E00418608 /* SharedMemoryCommon.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SharedMemoryCommon.h; path = lib/SharedMemoryCommon.h; sourceTree = ""; }; DC6A82541D87732E00418608 /* handletypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handletypes.h; path = lib/handletypes.h; sourceTree = ""; }; DC6A82551D87732E00418608 /* sscommon.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = sscommon.h; path = lib/sscommon.h; sourceTree = ""; }; @@ -8411,10 +10166,17 @@ DC6A82851D87734600418608 /* cshostingClient.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = cshostingClient.cpp; path = derived_src/securityd_client/cshostingClient.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; DC6A82861D87734600418608 /* cshostingServer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = cshostingServer.cpp; path = derived_src/securityd_client/cshostingServer.cpp; sourceTree = BUILT_PRODUCTS_DIR; }; DC6A82921D87749900418608 /* libsecurityd_client.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurityd_client.a; sourceTree = BUILT_PRODUCTS_DIR; }; - DC71D8DD1D94CF3C0065FB93 /* lib_ios_debug_shim.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = lib_ios_debug_shim.xcconfig; path = xcconfig/lib_ios_debug_shim.xcconfig; sourceTree = ""; }; - DC71D8DE1D94CF6A0065FB93 /* lib_ios_release_shim.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_release_shim.xcconfig; path = xcconfig/lib_ios_release_shim.xcconfig; sourceTree = ""; }; + DC6ACC401E81DF9400125DC5 /* server_endpoint.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = server_endpoint.m; sourceTree = ""; }; + DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = lib_ios_shim.xcconfig; path = xcconfig/lib_ios_shim.xcconfig; sourceTree = ""; }; DC71D9DF1D95BA6C0065FB93 /* libASN1.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libASN1.a; sourceTree = BUILT_PRODUCTS_DIR; }; DC71D9FB1D95BB0A0065FB93 /* libDER.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDER.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DC762A9C1E57A86A00B03A2C /* CKKSRecordHolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSRecordHolder.h; sourceTree = ""; }; + DC762A9D1E57A86A00B03A2C /* CKKSRecordHolder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSRecordHolder.m; sourceTree = ""; }; + DC797E131DD3F88300CC9E42 /* CKKSSQLDatabaseObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSSQLDatabaseObject.m; sourceTree = ""; }; + DC797E191DD3F89E00CC9E42 /* CKKSSQLDatabaseObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSSQLDatabaseObject.h; sourceTree = ""; }; + DC7A17EB1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSProcessReceivedKeysOperation.h; sourceTree = ""; }; + DC7A17EC1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSProcessReceivedKeysOperation.m; sourceTree = ""; }; + DC844AEC1E81F315007AAB71 /* client_endpoint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = client_endpoint.m; sourceTree = ""; }; DC8834081D8A218F00CE0ACA /* libASN1_not_installed.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libASN1_not_installed.a; sourceTree = BUILT_PRODUCTS_DIR; }; DC88340A1D8A21AA00CE0ACA /* SecAsn1Coder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecAsn1Coder.c; sourceTree = ""; }; DC88340C1D8A21AA00CE0ACA /* SecAsn1Templates.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecAsn1Templates.c; sourceTree = ""; }; @@ -8473,6 +10235,24 @@ DC88344E1D8A21AA00CE0ACA /* oidsocsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = oidsocsp.c; sourceTree = ""; }; DC88344F1D8A21AA00CE0ACA /* oidsocsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = oidsocsp.h; sourceTree = ""; }; DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios.xcconfig; path = xcconfig/lib_ios.xcconfig; sourceTree = ""; }; + DC9082C21EA0276000D0C1C5 /* CKKSZoneChangeFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSZoneChangeFetcher.h; sourceTree = ""; }; + DC9082C31EA0276000D0C1C5 /* CKKSZoneChangeFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSZoneChangeFetcher.m; sourceTree = ""; }; + DC94BCC81F10448600E07CEB /* CloudKitCategories.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CloudKitCategories.h; sourceTree = ""; }; + DC94BCC91F10448600E07CEB /* CloudKitCategories.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CloudKitCategories.m; sourceTree = ""; }; + DC976C581E3AC5E50012A6DD /* PlatformFeatures.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = PlatformFeatures.xcconfig; path = xcconfig/PlatformFeatures.xcconfig; sourceTree = ""; }; + DC9A2C5E1EB3F556008FAC27 /* CKKSTests+Coalesce.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CKKSTests+Coalesce.m"; sourceTree = ""; }; + DC9B7AE41DCBF604004E9385 /* CKKSOutgoingQueueEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSOutgoingQueueEntry.m; sourceTree = ""; }; + DC9B7AE61DCBF651004E9385 /* CKKSOutgoingQueueEntry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSOutgoingQueueEntry.h; sourceTree = ""; }; + DC9C750F1E4BCC5100F1CA0D /* CKKSOperationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSOperationTests.m; sourceTree = ""; }; + DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplePushService.framework; path = System/Library/PrivateFrameworks/ApplePushService.framework; sourceTree = SDKROOT; }; + DC9EBA2F1DEE651500D0F733 /* Info-macOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; }; + DC9EBA311DEE768000D0F733 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; }; + DCA4D1F31E5520550056214F /* CKKSCurrentKeyPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSCurrentKeyPointer.h; sourceTree = ""; }; + DCA4D1F41E5520550056214F /* CKKSCurrentKeyPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSCurrentKeyPointer.m; sourceTree = ""; }; + DCA4D2131E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSReencryptOutgoingItemsOperation.h; sourceTree = ""; }; + DCA4D2141E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSReencryptOutgoingItemsOperation.m; sourceTree = ""; }; + DCB2214A1E8B0861001598BC /* server_xpc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = server_xpc.m; sourceTree = ""; }; + DCB2215B1E8B098D001598BC /* server_endpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = server_endpoint.h; sourceTree = ""; }; DCB3406D1D8A24DF0054D16E /* libsecurity_authorization.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurity_authorization.a; sourceTree = BUILT_PRODUCTS_DIR; }; DCB3406F1D8A24F70054D16E /* Authorization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Authorization.c; path = lib/Authorization.c; sourceTree = ""; }; DCB340761D8A24F70054D16E /* Authorization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Authorization.cpp; path = lib/Authorization.cpp; sourceTree = ""; }; @@ -8653,7 +10433,6 @@ DCB342451D8A32A20054D16E /* SecBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecBridge.h; sourceTree = ""; }; DCB342461D8A32A20054D16E /* SecCertificate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecCertificate.cpp; sourceTree = ""; }; DCB342471D8A32A20054D16E /* SecCertificateBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecCertificateBundle.cpp; sourceTree = ""; }; - DCB342481D8A32A20054D16E /* SecCertificateRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecCertificateRequest.cpp; sourceTree = ""; }; DCB342491D8A32A20054D16E /* SecIdentity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecIdentity.cpp; sourceTree = ""; }; DCB3424A1D8A32A20054D16E /* SecIdentitySearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecIdentitySearch.cpp; sourceTree = ""; }; DCB3424B1D8A32A20054D16E /* SecItemConstants.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecItemConstants.c; sourceTree = ""; }; @@ -8678,8 +10457,6 @@ DCB342891D8A32A20054D16E /* ACL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ACL.h; sourceTree = ""; }; DCB3428A1D8A32A20054D16E /* Certificate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Certificate.cpp; sourceTree = ""; }; DCB3428B1D8A32A20054D16E /* Certificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Certificate.h; sourceTree = ""; }; - DCB3428C1D8A32A20054D16E /* CertificateRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CertificateRequest.cpp; sourceTree = ""; }; - DCB3428D1D8A32A20054D16E /* CertificateRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CertificateRequest.h; sourceTree = ""; }; DCB3428E1D8A32A20054D16E /* CertificateValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CertificateValues.cpp; sourceTree = ""; }; DCB3428F1D8A32A20054D16E /* CertificateValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CertificateValues.h; sourceTree = ""; }; DCB342901D8A32A20054D16E /* ExtendedAttribute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExtendedAttribute.cpp; sourceTree = ""; }; @@ -8717,7 +10494,6 @@ DCB342B11D8A32A20054D16E /* TrustSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrustSettings.h; sourceTree = ""; }; DCB342B21D8A32A20054D16E /* TrustKeychains.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrustKeychains.h; sourceTree = ""; }; DCB342B31D8A32A20054D16E /* SecTrustOSXEntryPoints.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecTrustOSXEntryPoints.cpp; sourceTree = ""; }; - DCB342B41D8A32A20054D16E /* SecTrustOSXEntryPoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustOSXEntryPoints.h; path = ../../trustd/SecTrustOSXEntryPoints.h; sourceTree = ""; }; DCB342B71D8A32A20054D16E /* CCallbackMgr.cp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCallbackMgr.cp; sourceTree = ""; }; DCB342B81D8A32A20054D16E /* CCallbackMgr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCallbackMgr.h; sourceTree = ""; }; DCB342B91D8A32A20054D16E /* cssmdatetime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cssmdatetime.cpp; sourceTree = ""; }; @@ -8833,93 +10609,83 @@ DCB344701D8A35270054D16E /* si-20-sectrust-provisioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "si-20-sectrust-provisioning.h"; path = "regressions/si-20-sectrust-provisioning.h"; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; + DCB5D9391E4A9A3400BE22AB /* CKKSSynchronizeOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSSynchronizeOperation.h; sourceTree = ""; }; + DCB5D93A1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSSynchronizeOperation.m; sourceTree = ""; }; + DCBDB3B01E57C67500B61300 /* CKKSKeychainView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSKeychainView.h; sourceTree = ""; }; + DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSKeychainView.m; sourceTree = ""; }; + DCBDB3B91E57CA7A00B61300 /* CKKSViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSViewManager.h; sourceTree = ""; }; + DCBDB3BA1E57CA7A00B61300 /* CKKSViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSViewManager.m; sourceTree = ""; }; DCC0800D1CFF7903005C35C8 /* CSSMOID.exp-in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "CSSMOID.exp-in"; sourceTree = ""; }; DCC78C371D8085D800865A7C /* ios6_1_keychain_2_db.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios6_1_keychain_2_db.h; sourceTree = ""; }; DCC78C381D8085D800865A7C /* ios8-inet-keychain-2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ios8-inet-keychain-2.h"; sourceTree = ""; }; - DCC78C391D8085D800865A7C /* secd-03-corrupted-items.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-03-corrupted-items.c"; sourceTree = ""; }; - DCC78C3A1D8085D800865A7C /* secd-04-corrupted-items.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-04-corrupted-items.c"; sourceTree = ""; }; + DCC78C391D8085D800865A7C /* secd-03-corrupted-items.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-03-corrupted-items.m"; sourceTree = ""; }; + DCC78C3A1D8085D800865A7C /* secd-04-corrupted-items.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-04-corrupted-items.m"; sourceTree = ""; }; DCC78C3B1D8085D800865A7C /* secd-05-corrupted-items.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-05-corrupted-items.m"; sourceTree = ""; }; DCC78C3C1D8085D800865A7C /* securityd_regressions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = securityd_regressions.h; sourceTree = ""; }; - DCC78C3D1D8085D800865A7C /* sd-10-policytree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sd-10-policytree.c"; sourceTree = ""; }; + DCC78C3D1D8085D800865A7C /* sd-10-policytree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "sd-10-policytree.m"; sourceTree = ""; }; DCC78C3E1D8085D800865A7C /* secd_regressions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = secd_regressions.h; sourceTree = ""; }; - DCC78C3F1D8085D800865A7C /* secd-01-items.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-01-items.c"; sourceTree = ""; }; - DCC78C401D8085D800865A7C /* secd-02-upgrade-while-locked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = "secd-02-upgrade-while-locked.c"; sourceTree = ""; }; + DCC78C3F1D8085D800865A7C /* secd-01-items.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-01-items.m"; sourceTree = ""; }; + DCC78C401D8085D800865A7C /* secd-02-upgrade-while-locked.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "secd-02-upgrade-while-locked.m"; sourceTree = ""; }; DCC78C411D8085D800865A7C /* secd-20-keychain_upgrade.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-20-keychain_upgrade.m"; sourceTree = ""; }; DCC78C421D8085D800865A7C /* secd-21-transmogrify.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-21-transmogrify.m"; sourceTree = ""; }; - DCC78C431D8085D800865A7C /* secd-30-keychain-upgrade.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-30-keychain-upgrade.c"; sourceTree = ""; }; - DCC78C441D8085D800865A7C /* secd-31-keychain-bad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-31-keychain-bad.c"; sourceTree = ""; }; - DCC78C451D8085D800865A7C /* secd-31-keychain-unreadable.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-31-keychain-unreadable.c"; sourceTree = ""; }; - DCC78C461D8085D800865A7C /* secd-32-restore-bad-backup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-32-restore-bad-backup.c"; sourceTree = ""; }; + DCC78C431D8085D800865A7C /* secd-30-keychain-upgrade.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-30-keychain-upgrade.m"; sourceTree = ""; }; + DCC78C441D8085D800865A7C /* secd-31-keychain-bad.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-31-keychain-bad.m"; sourceTree = ""; }; + DCC78C451D8085D800865A7C /* secd-31-keychain-unreadable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-31-keychain-unreadable.m"; sourceTree = ""; }; + DCC78C461D8085D800865A7C /* secd-32-restore-bad-backup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-32-restore-bad-backup.m"; sourceTree = ""; }; DCC78C471D8085D800865A7C /* secd-33-keychain-ctk.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-33-keychain-ctk.m"; sourceTree = ""; }; - DCC78C481D8085D800865A7C /* secd-34-backup-der-parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-34-backup-der-parse.c"; sourceTree = ""; }; - DCC78C491D8085D800865A7C /* secd-35-keychain-migrate-inet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-35-keychain-migrate-inet.c"; sourceTree = ""; }; - DCC78C4A1D8085D800865A7C /* secd-40-cc-gestalt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-40-cc-gestalt.c"; sourceTree = ""; }; - DCC78C4B1D8085D800865A7C /* secd-50-account.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "secd-50-account.c"; sourceTree = ""; }; - DCC78C4C1D8085D800865A7C /* secd-49-manifests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-49-manifests.c"; sourceTree = ""; }; - DCC78C4D1D8085D800865A7C /* secd-50-message.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-50-message.c"; sourceTree = ""; }; - DCC78C4E1D8085D800865A7C /* secd-51-account-inflate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-51-account-inflate.c"; sourceTree = ""; }; - DCC78C4F1D8085D800865A7C /* secd-52-offering-gencount-reset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-52-offering-gencount-reset.c"; sourceTree = ""; }; - DCC78C501D8085D800865A7C /* secd-52-account-changed.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-52-account-changed.c"; sourceTree = ""; }; - DCC78C511D8085D800865A7C /* secd-55-account-circle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-55-account-circle.c"; sourceTree = ""; }; - DCC78C521D8085D800865A7C /* secd-55-account-incompatibility.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-55-account-incompatibility.c"; sourceTree = ""; }; - DCC78C531D8085D800865A7C /* secd-56-account-apply.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-56-account-apply.c"; sourceTree = ""; }; - DCC78C541D8085D800865A7C /* secd-57-account-leave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-57-account-leave.c"; sourceTree = ""; }; - DCC78C551D8085D800865A7C /* secd-57-1-account-last-standing.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-57-1-account-last-standing.c"; sourceTree = ""; }; - DCC78C561D8085D800865A7C /* secd-58-password-change.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-58-password-change.c"; sourceTree = ""; }; - DCC78C571D8085D800865A7C /* secd-59-account-cleanup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-59-account-cleanup.c"; sourceTree = ""; }; - DCC78C581D8085D800865A7C /* secd-60-account-cloud-identity.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-60-account-cloud-identity.c"; sourceTree = ""; }; - DCC78C591D8085D800865A7C /* secd60-account-cloud-exposure.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd60-account-cloud-exposure.c"; sourceTree = ""; }; - DCC78C5A1D8085D800865A7C /* secd-61-account-leave-not-in-kansas-anymore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-61-account-leave-not-in-kansas-anymore.c"; sourceTree = ""; }; - DCC78C5B1D8085D800865A7C /* secd-62-account-backup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-62-account-backup.c"; sourceTree = ""; }; - DCC78C5C1D8085D800865A7C /* secd-62-account-hsa-join.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-62-account-hsa-join.c"; sourceTree = ""; }; - DCC78C5D1D8085D800865A7C /* secd-63-account-resurrection.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-63-account-resurrection.c"; sourceTree = ""; }; - DCC78C5E1D8085D800865A7C /* secd-65-account-retirement-reset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-65-account-retirement-reset.c"; sourceTree = ""; }; - DCC78C5F1D8085D800865A7C /* secd-64-circlereset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-64-circlereset.c"; sourceTree = ""; }; - DCC78C601D8085D800865A7C /* secd-70-engine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-70-engine.c"; sourceTree = ""; }; - DCC78C611D8085D800865A7C /* secd-70-engine-corrupt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-70-engine-corrupt.c"; sourceTree = ""; }; - DCC78C621D8085D800865A7C /* secd-70-engine-smash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-70-engine-smash.c"; sourceTree = ""; }; - DCC78C631D8085D800865A7C /* secd-70-otr-remote.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-70-otr-remote.c"; sourceTree = ""; }; - DCC78C641D8085D800865A7C /* secd-71-engine-save.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-71-engine-save.c"; sourceTree = ""; }; + DCC78C481D8085D800865A7C /* secd-34-backup-der-parse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-34-backup-der-parse.m"; sourceTree = ""; }; + DCC78C491D8085D800865A7C /* secd-35-keychain-migrate-inet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-35-keychain-migrate-inet.m"; sourceTree = ""; }; + DCC78C4A1D8085D800865A7C /* secd-40-cc-gestalt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-40-cc-gestalt.m"; sourceTree = ""; }; + DCC78C4B1D8085D800865A7C /* secd-50-account.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-50-account.m"; sourceTree = ""; }; + DCC78C4C1D8085D800865A7C /* secd-49-manifests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-49-manifests.m"; sourceTree = ""; }; + DCC78C4D1D8085D800865A7C /* secd-50-message.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-50-message.m"; sourceTree = ""; }; + DCC78C4E1D8085D800865A7C /* secd-51-account-inflate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-51-account-inflate.m"; sourceTree = ""; }; + DCC78C4F1D8085D800865A7C /* secd-52-offering-gencount-reset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-52-offering-gencount-reset.m"; sourceTree = ""; }; + DCC78C501D8085D800865A7C /* secd-52-account-changed.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-52-account-changed.m"; sourceTree = ""; }; + DCC78C511D8085D800865A7C /* secd-55-account-circle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-55-account-circle.m"; sourceTree = ""; }; + DCC78C521D8085D800865A7C /* secd-55-account-incompatibility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-55-account-incompatibility.m"; sourceTree = ""; }; + DCC78C531D8085D800865A7C /* secd-56-account-apply.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-56-account-apply.m"; sourceTree = ""; }; + DCC78C541D8085D800865A7C /* secd-57-account-leave.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-57-account-leave.m"; sourceTree = ""; }; + DCC78C551D8085D800865A7C /* secd-57-1-account-last-standing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-57-1-account-last-standing.m"; sourceTree = ""; }; + DCC78C561D8085D800865A7C /* secd-58-password-change.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-58-password-change.m"; sourceTree = ""; }; + DCC78C571D8085D800865A7C /* secd-59-account-cleanup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-59-account-cleanup.m"; sourceTree = ""; }; + DCC78C581D8085D800865A7C /* secd-60-account-cloud-identity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-60-account-cloud-identity.m"; sourceTree = ""; }; + DCC78C591D8085D800865A7C /* secd60-account-cloud-exposure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd60-account-cloud-exposure.m"; sourceTree = ""; }; + DCC78C5A1D8085D800865A7C /* secd-61-account-leave-not-in-kansas-anymore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-61-account-leave-not-in-kansas-anymore.m"; sourceTree = ""; }; + DCC78C5B1D8085D800865A7C /* secd-62-account-backup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-62-account-backup.m"; sourceTree = ""; }; + DCC78C5D1D8085D800865A7C /* secd-63-account-resurrection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-63-account-resurrection.m"; sourceTree = ""; }; + DCC78C5E1D8085D800865A7C /* secd-65-account-retirement-reset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-65-account-retirement-reset.m"; sourceTree = ""; }; + DCC78C5F1D8085D800865A7C /* secd-64-circlereset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-64-circlereset.m"; sourceTree = ""; }; + DCC78C601D8085D800865A7C /* secd-70-engine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-70-engine.m"; sourceTree = ""; }; + DCC78C611D8085D800865A7C /* secd-70-engine-corrupt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-70-engine-corrupt.m"; sourceTree = ""; }; + DCC78C621D8085D800865A7C /* secd-70-engine-smash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-70-engine-smash.m"; sourceTree = ""; }; + DCC78C631D8085D800865A7C /* secd-70-otr-remote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-70-otr-remote.m"; sourceTree = ""; }; + DCC78C641D8085D800865A7C /* secd-71-engine-save.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-71-engine-save.m"; sourceTree = ""; }; DCC78C651D8085D800865A7C /* secd-71-engine-save-sample1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "secd-71-engine-save-sample1.h"; sourceTree = ""; }; - DCC78C661D8085D800865A7C /* secd-74-engine-beer-servers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-74-engine-beer-servers.c"; sourceTree = ""; }; - DCC78C671D8085D800865A7C /* secd-75-engine-views.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-75-engine-views.c"; sourceTree = ""; }; - DCC78C681D8085D800865A7C /* secd-76-idstransport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-76-idstransport.c"; sourceTree = ""; }; - DCC78C691D8085D800865A7C /* secd_77_ids_messaging.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = secd_77_ids_messaging.c; sourceTree = ""; }; - DCC78C6A1D8085D800865A7C /* secd-80-views-basic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-80-views-basic.c"; sourceTree = ""; }; - DCC78C6B1D8085D800865A7C /* secd-82-secproperties-basic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-82-secproperties-basic.c"; sourceTree = ""; }; - DCC78C6C1D8085D800865A7C /* secd-81-item-acl-stress.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "secd-81-item-acl-stress.c"; sourceTree = ""; }; - DCC78C6D1D8085D800865A7C /* secd-81-item-acl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-81-item-acl.c"; sourceTree = ""; }; - DCC78C6E1D8085D800865A7C /* secd-82-persistent-ref.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "secd-82-persistent-ref.c"; sourceTree = ""; }; + DCC78C661D8085D800865A7C /* secd-74-engine-beer-servers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-74-engine-beer-servers.m"; sourceTree = ""; }; + DCC78C671D8085D800865A7C /* secd-75-engine-views.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-75-engine-views.m"; sourceTree = ""; }; + DCC78C681D8085D800865A7C /* secd-76-idstransport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-76-idstransport.m"; sourceTree = ""; }; + DCC78C691D8085D800865A7C /* secd_77_ids_messaging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = secd_77_ids_messaging.m; sourceTree = ""; }; + DCC78C6A1D8085D800865A7C /* secd-80-views-basic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-80-views-basic.m"; sourceTree = ""; }; + DCC78C6B1D8085D800865A7C /* secd-82-secproperties-basic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-82-secproperties-basic.m"; sourceTree = ""; }; + DCC78C6C1D8085D800865A7C /* secd-81-item-acl-stress.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-81-item-acl-stress.m"; sourceTree = ""; }; + DCC78C6D1D8085D800865A7C /* secd-81-item-acl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-81-item-acl.m"; sourceTree = ""; }; + DCC78C6E1D8085D800865A7C /* secd-82-persistent-ref.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-82-persistent-ref.m"; sourceTree = ""; }; DCC78C6F1D8085D800865A7C /* secd-83-item-match-policy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-83-item-match-policy.m"; sourceTree = ""; }; DCC78C701D8085D800865A7C /* secd-83-item-match-valid-on-date.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-83-item-match-valid-on-date.m"; sourceTree = ""; }; DCC78C711D8085D800865A7C /* secd-83-item-match-trusted.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-83-item-match-trusted.m"; sourceTree = ""; }; DCC78C721D8085D800865A7C /* secd-83-item-match.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "secd-83-item-match.h"; sourceTree = ""; }; - DCC78C731D8085D800865A7C /* secd-90-hsa2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-90-hsa2.c"; sourceTree = ""; }; - DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-95-escrow-persistence.c"; sourceTree = ""; }; - DCC78C751D8085D800865A7C /* secd-100-initialsync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-100-initialsync.c"; sourceTree = ""; }; - DCC78C761D8085D800865A7C /* secd-130-other-peer-views.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-130-other-peer-views.c"; sourceTree = ""; }; - DCC78C771D8085D800865A7C /* secd-154-engine-backoff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-154-engine-backoff.c"; sourceTree = ""; }; - DCC78C781D8085D800865A7C /* secd-200-logstate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-200-logstate.c"; sourceTree = ""; }; + DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-95-escrow-persistence.m"; sourceTree = ""; }; + DCC78C751D8085D800865A7C /* secd-100-initialsync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-100-initialsync.m"; sourceTree = ""; }; + DCC78C761D8085D800865A7C /* secd-130-other-peer-views.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-130-other-peer-views.m"; sourceTree = ""; }; + DCC78C771D8085D800865A7C /* secd-154-engine-backoff.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-154-engine-backoff.m"; sourceTree = ""; }; + DCC78C781D8085D800865A7C /* secd-200-logstate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-200-logstate.m"; sourceTree = ""; }; DCC78C791D8085D800865A7C /* SOSAccountTesting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSAccountTesting.h; sourceTree = ""; }; DCC78C7A1D8085D800865A7C /* SecdTestKeychainUtilities.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecdTestKeychainUtilities.c; sourceTree = ""; }; DCC78C7B1D8085D800865A7C /* SecdTestKeychainUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecdTestKeychainUtilities.h; sourceTree = ""; }; - DCC78C7C1D8085D800865A7C /* SOSTransportTestTransports.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportTestTransports.c; sourceTree = ""; }; + DCC78C7C1D8085D800865A7C /* SOSTransportTestTransports.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportTestTransports.m; sourceTree = ""; }; DCC78C7D1D8085D800865A7C /* SOSTransportTestTransports.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportTestTransports.h; sourceTree = ""; }; - DCC78C7F1D8085D800865A7C /* asynchttp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = asynchttp.c; sourceTree = ""; }; - DCC78C801D8085D800865A7C /* asynchttp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = asynchttp.h; sourceTree = ""; }; DCC78C811D8085D800865A7C /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; - DCC78C821D8085D800865A7C /* OTATrustUtilities.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = OTATrustUtilities.c; sourceTree = ""; }; - DCC78C831D8085D800865A7C /* OTATrustUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTATrustUtilities.h; sourceTree = ""; }; - DCC78C841D8085D800865A7C /* policytree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = policytree.c; sourceTree = ""; }; - DCC78C851D8085D800865A7C /* policytree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = policytree.h; sourceTree = ""; }; - DCC78C861D8085D800865A7C /* nameconstraints.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nameconstraints.c; sourceTree = ""; }; - DCC78C871D8085D800865A7C /* nameconstraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nameconstraints.h; sourceTree = ""; }; - DCC78C881D8085D800865A7C /* personalization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = personalization.c; sourceTree = ""; }; - DCC78C891D8085D800865A7C /* personalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = personalization.h; sourceTree = ""; }; - DCC78C8A1D8085D800865A7C /* SecCAIssuerCache.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecCAIssuerCache.c; sourceTree = ""; }; - DCC78C8B1D8085D800865A7C /* SecCAIssuerCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecCAIssuerCache.h; sourceTree = ""; }; - DCC78C8C1D8085D800865A7C /* SecCAIssuerRequest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecCAIssuerRequest.c; sourceTree = ""; }; - DCC78C8D1D8085D800865A7C /* SecCAIssuerRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecCAIssuerRequest.h; sourceTree = ""; }; DCC78C8E1D8085D800865A7C /* SecDbItem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecDbItem.c; sourceTree = ""; }; DCC78C8F1D8085D800865A7C /* SecDbItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecDbItem.h; sourceTree = ""; }; DCC78C901D8085D800865A7C /* SecDbKeychainItem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecDbKeychainItem.c; sourceTree = ""; }; @@ -8938,32 +10704,20 @@ DCC78C9D1D8085D800865A7C /* SecItemBackupServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemBackupServer.h; sourceTree = ""; }; DCC78C9E1D8085D800865A7C /* SecKeybagSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecKeybagSupport.c; sourceTree = ""; }; DCC78C9F1D8085D800865A7C /* SecKeybagSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecKeybagSupport.h; sourceTree = ""; }; - DCC78CA01D8085D800865A7C /* SecOCSPCache.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecOCSPCache.c; sourceTree = ""; }; - DCC78CA11D8085D800865A7C /* SecOCSPCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecOCSPCache.h; sourceTree = ""; }; - DCC78CA21D8085D800865A7C /* SecOCSPRequest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecOCSPRequest.c; sourceTree = ""; }; - DCC78CA31D8085D800865A7C /* SecOCSPRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecOCSPRequest.h; sourceTree = ""; }; - DCC78CA41D8085D800865A7C /* SecOCSPResponse.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecOCSPResponse.c; sourceTree = ""; }; - DCC78CA51D8085D800865A7C /* SecOCSPResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecOCSPResponse.h; sourceTree = ""; }; - DCC78CA61D8085D800865A7C /* SecPolicyServer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecPolicyServer.c; sourceTree = ""; }; - DCC78CA71D8085D800865A7C /* SecPolicyServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecPolicyServer.h; sourceTree = ""; }; - DCC78CA81D8085D800865A7C /* SecTrustServer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = SecTrustServer.c; sourceTree = ""; }; - DCC78CA91D8085D800865A7C /* SecTrustServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecTrustServer.h; sourceTree = ""; }; - DCC78CAA1D8085D800865A7C /* SOSCloudCircleServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = SOSCloudCircleServer.c; sourceTree = ""; }; + DCC78CAA1D8085D800865A7C /* SOSCloudCircleServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SOSCloudCircleServer.m; sourceTree = ""; }; DCC78CAB1D8085D800865A7C /* SOSCloudCircleServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSCloudCircleServer.h; sourceTree = ""; }; - DCC78CAC1D8085D800865A7C /* SecTrustStoreServer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecTrustStoreServer.c; sourceTree = ""; }; - DCC78CAD1D8085D800865A7C /* SecTrustStoreServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecTrustStoreServer.h; sourceTree = ""; }; - DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecLogSettingsServer.c; sourceTree = ""; }; + DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecLogSettingsServer.m; sourceTree = ""; }; DCC78CAF1D8085D800865A7C /* SecLogSettingsServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecLogSettingsServer.h; sourceTree = ""; }; DCC78CB01D8085D800865A7C /* spi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = spi.c; sourceTree = ""; }; DCC78CB11D8085D800865A7C /* spi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = spi.h; sourceTree = ""; }; DCC78CB21D8085D800865A7C /* iCloudTrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iCloudTrace.h; sourceTree = ""; }; DCC78CB31D8085D800865A7C /* iCloudTrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iCloudTrace.c; sourceTree = ""; }; - DCC78CB41D8085D800865A7C /* SecOTRRemote.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOTRRemote.c; sourceTree = ""; }; + DCC78CB41D8085D800865A7C /* SecOTRRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecOTRRemote.m; sourceTree = ""; }; DCC78CB51D8085D800865A7C /* SecOTRRemote.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecOTRRemote.h; sourceTree = ""; }; DCC78CF61D8085F200865A7C /* SOSCloudKeychainClient.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = SOSCloudKeychainClient.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; DCC78CF71D8085F200865A7C /* SOSCloudKeychainClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SOSCloudKeychainClient.h; sourceTree = ""; }; DCC78CF91D8085F200865A7C /* SOSCloudKeychainConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSCloudKeychainConstants.h; sourceTree = ""; }; - DCC78CFD1D8085F200865A7C /* sc-20-keynames.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-20-keynames.c"; sourceTree = ""; }; + DCC78CFD1D8085F200865A7C /* sc-20-keynames.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "sc-20-keynames.m"; sourceTree = ""; }; DCC78CFE1D8085F200865A7C /* sc-25-soskeygen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-25-soskeygen.c"; sourceTree = ""; }; DCC78CFF1D8085F200865A7C /* sc-30-peerinfo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-30-peerinfo.c"; sourceTree = ""; }; DCC78D001D8085F200865A7C /* sc-31-peerinfo-simplefuzz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-31-peerinfo-simplefuzz.c"; sourceTree = ""; }; @@ -8971,44 +10725,40 @@ DCC78D021D8085F200865A7C /* sc-42-circlegencount.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-42-circlegencount.c"; sourceTree = ""; }; DCC78D031D8085F200865A7C /* sc-45-digestvector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-45-digestvector.c"; sourceTree = ""; }; DCC78D041D8085F200865A7C /* sc-130-resignationticket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-130-resignationticket.c"; sourceTree = ""; }; - DCC78D051D8085F200865A7C /* sc-140-hsa2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "sc-140-hsa2.c"; sourceTree = ""; }; - DCC78D061D8085F200865A7C /* sc-150-ring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-150-ring.c"; sourceTree = ""; }; + DCC78D061D8085F200865A7C /* sc-150-ring.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "sc-150-ring.m"; sourceTree = ""; }; DCC78D071D8085F200865A7C /* sc-150-backupkeyderivation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-150-backupkeyderivation.c"; sourceTree = ""; }; DCC78D081D8085F200865A7C /* sc-153-backupslicekeybag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sc-153-backupslicekeybag.c"; sourceTree = ""; }; DCC78D091D8085F200865A7C /* SOSCircle_regressions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSCircle_regressions.h; sourceTree = ""; }; - DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRegressionUtilities.c; sourceTree = ""; }; + DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRegressionUtilities.m; sourceTree = ""; }; DCC78D0B1D8085F200865A7C /* SOSRegressionUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSRegressionUtilities.h; sourceTree = ""; }; DCC78D0C1D8085F200865A7C /* SOSTestDataSource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTestDataSource.c; sourceTree = ""; }; DCC78D0D1D8085F200865A7C /* SOSTestDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSTestDataSource.h; sourceTree = ""; }; DCC78D0E1D8085F200865A7C /* SOSTestDevice.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTestDevice.c; sourceTree = ""; }; DCC78D0F1D8085F200865A7C /* SOSTestDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTestDevice.h; sourceTree = ""; }; DCC78D111D8085F200865A7C /* SOSExports.exp-in */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; path = "SOSExports.exp-in"; sourceTree = ""; }; - DCC78D121D8085F200865A7C /* SOSAccount.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccount.c; sourceTree = ""; }; + DCC78D121D8085F200865A7C /* SOSAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccount.m; sourceTree = ""; }; DCC78D131D8085F200865A7C /* SOSAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSAccount.h; sourceTree = ""; }; - DCC78D141D8085F200865A7C /* SOSAccountTransaction.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountTransaction.c; sourceTree = ""; }; + DCC78D141D8085F200865A7C /* SOSAccountTransaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountTransaction.m; sourceTree = ""; }; DCC78D151D8085F200865A7C /* SOSAccountTransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSAccountTransaction.h; sourceTree = ""; }; - DCC78D161D8085F200865A7C /* SOSAccountBackup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountBackup.c; sourceTree = ""; }; - DCC78D171D8085F200865A7C /* SOSAccountCircles.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountCircles.c; sourceTree = ""; }; - DCC78D181D8085F200865A7C /* SOSAccountHSAJoin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountHSAJoin.c; sourceTree = ""; }; - DCC78D191D8085F200865A7C /* SOSAccountHSAJoin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSAccountHSAJoin.h; sourceTree = ""; }; - DCC78D1A1D8085F200865A7C /* SOSAccountCloudParameters.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountCloudParameters.c; sourceTree = ""; }; - DCC78D1B1D8085F200865A7C /* SOSAccountCredentials.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountCredentials.c; sourceTree = ""; }; - DCC78D1C1D8085F200865A7C /* SOSAccountDer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountDer.c; sourceTree = ""; }; - DCC78D1D1D8085F200865A7C /* SOSAccountFullPeerInfo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountFullPeerInfo.c; sourceTree = ""; }; - DCC78D1E1D8085F200865A7C /* SOSAccountPeers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountPeers.c; sourceTree = ""; }; - DCC78D1F1D8085F200865A7C /* SOSAccountPersistence.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountPersistence.c; sourceTree = ""; }; - DCC78D201D8085F200865A7C /* SOSAccountLog.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SOSAccountLog.c; sourceTree = ""; }; + DCC78D161D8085F200865A7C /* SOSAccountBackup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountBackup.m; sourceTree = ""; }; + DCC78D171D8085F200865A7C /* SOSAccountCircles.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountCircles.m; sourceTree = ""; }; + DCC78D1A1D8085F200865A7C /* SOSAccountCloudParameters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountCloudParameters.m; sourceTree = ""; }; + DCC78D1B1D8085F200865A7C /* SOSAccountCredentials.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountCredentials.m; sourceTree = ""; }; + DCC78D1C1D8085F200865A7C /* SOSAccountDer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountDer.m; sourceTree = ""; }; + DCC78D1D1D8085F200865A7C /* SOSAccountFullPeerInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountFullPeerInfo.m; sourceTree = ""; }; + DCC78D1E1D8085F200865A7C /* SOSAccountPeers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountPeers.m; sourceTree = ""; }; + DCC78D1F1D8085F200865A7C /* SOSAccountPersistence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountPersistence.m; sourceTree = ""; }; + DCC78D201D8085F200865A7C /* SOSAccountLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSAccountLog.m; sourceTree = ""; }; DCC78D211D8085F200865A7C /* SOSAccountLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSAccountLog.h; sourceTree = ""; }; - DCC78D221D8085F200865A7C /* SOSAccountPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSAccountPriv.h; sourceTree = ""; }; - DCC78D231D8085F200865A7C /* SOSAccountUpdate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountUpdate.c; sourceTree = ""; }; - DCC78D241D8085F200865A7C /* SOSAccountRings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountRings.c; sourceTree = ""; }; - DCC78D251D8085F200865A7C /* SOSAccountRingUpdate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountRingUpdate.c; sourceTree = ""; }; - DCC78D261D8085F200865A7C /* SOSAccountViewSync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountViewSync.c; sourceTree = ""; }; + DCC78D231D8085F200865A7C /* SOSAccountUpdate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountUpdate.m; sourceTree = ""; }; + DCC78D241D8085F200865A7C /* SOSAccountRings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountRings.m; sourceTree = ""; }; + DCC78D251D8085F200865A7C /* SOSAccountRingUpdate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountRingUpdate.m; sourceTree = ""; }; + DCC78D261D8085F200865A7C /* SOSAccountViewSync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountViewSync.m; sourceTree = ""; }; DCC78D271D8085F200865A7C /* SOSBackupEvent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSBackupEvent.c; sourceTree = ""; }; DCC78D281D8085F200865A7C /* SOSBackupEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSBackupEvent.h; sourceTree = ""; }; - DCC78D291D8085F200865A7C /* SOSBackupSliceKeyBag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSBackupSliceKeyBag.c; sourceTree = ""; }; + DCC78D291D8085F200865A7C /* SOSBackupSliceKeyBag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSBackupSliceKeyBag.m; sourceTree = ""; }; DCC78D2A1D8085F200865A7C /* SOSBackupSliceKeyBag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSBackupSliceKeyBag.h; sourceTree = ""; }; - DCC78D2B1D8085F200865A7C /* SOSUserKeygen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSUserKeygen.c; sourceTree = ""; }; + DCC78D2B1D8085F200865A7C /* SOSUserKeygen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSUserKeygen.m; sourceTree = ""; }; DCC78D2C1D8085F200865A7C /* SOSUserKeygen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSUserKeygen.h; sourceTree = ""; }; DCC78D2E1D8085F200865A7C /* SOSCircle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSCircle.c; sourceTree = ""; }; DCC78D2F1D8085F200865A7C /* SOSCircleV2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSCircleV2.c; sourceTree = ""; }; @@ -9022,9 +10772,9 @@ DCC78D371D8085F200865A7C /* SOSGenCount.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSGenCount.c; sourceTree = ""; }; DCC78D381D8085F200865A7C /* SOSGenCount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSGenCount.h; sourceTree = ""; }; DCC78D391D8085F200865A7C /* SOSRing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRing.h; sourceTree = ""; }; - DCC78D3A1D8085F200865A7C /* SOSRingBackup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRingBackup.c; sourceTree = ""; }; + DCC78D3A1D8085F200865A7C /* SOSRingBackup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRingBackup.m; sourceTree = ""; }; DCC78D3B1D8085F200865A7C /* SOSRingBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingBackup.h; sourceTree = ""; }; - DCC78D3C1D8085F200865A7C /* SOSRingBasic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRingBasic.c; sourceTree = ""; }; + DCC78D3C1D8085F200865A7C /* SOSRingBasic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRingBasic.m; sourceTree = ""; }; DCC78D3D1D8085F200865A7C /* SOSRingBasic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingBasic.h; sourceTree = ""; }; DCC78D3E1D8085F200865A7C /* SOSRingConcordanceTrust.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRingConcordanceTrust.c; sourceTree = ""; }; DCC78D3F1D8085F200865A7C /* SOSRingConcordanceTrust.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingConcordanceTrust.h; sourceTree = ""; }; @@ -9032,13 +10782,13 @@ DCC78D411D8085F200865A7C /* SOSRingDER.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingDER.h; sourceTree = ""; }; DCC78D421D8085F200865A7C /* SOSRingPeerInfoUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRingPeerInfoUtils.c; sourceTree = ""; }; DCC78D431D8085F200865A7C /* SOSRingPeerInfoUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingPeerInfoUtils.h; sourceTree = ""; }; - DCC78D441D8085F200865A7C /* SOSRingTypes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRingTypes.c; sourceTree = ""; }; + DCC78D441D8085F200865A7C /* SOSRingTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRingTypes.m; sourceTree = ""; }; DCC78D451D8085F200865A7C /* SOSRingTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingTypes.h; sourceTree = ""; }; DCC78D461D8085F200865A7C /* SOSRingUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRingUtils.c; sourceTree = ""; }; DCC78D471D8085F200865A7C /* SOSRingUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingUtils.h; sourceTree = ""; }; - DCC78D481D8085F200865A7C /* SOSRingV0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSRingV0.c; sourceTree = ""; }; + DCC78D481D8085F200865A7C /* SOSRingV0.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRingV0.m; sourceTree = ""; }; DCC78D491D8085F200865A7C /* SOSRingV0.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingV0.h; sourceTree = ""; }; - DCC78D4A1D8085F200865A7C /* SOSViews.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSViews.c; sourceTree = ""; }; + DCC78D4A1D8085F200865A7C /* SOSViews.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSViews.m; sourceTree = ""; }; DCC78D4B1D8085F200865A7C /* SOSViews.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSViews.h; sourceTree = ""; }; DCC78D4C1D8085F200865A7C /* ViewList.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = ViewList.list; sourceTree = ""; }; DCC78D4D1D8085F200865A7C /* SOSViews.exp-in */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SOSViews.exp-in"; sourceTree = ""; }; @@ -9055,66 +10805,64 @@ DCC78D591D8085F200865A7C /* SOSManifest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSManifest.h; sourceTree = ""; }; DCC78D5A1D8085F200865A7C /* SOSMessage.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSMessage.c; sourceTree = ""; }; DCC78D5B1D8085F200865A7C /* SOSMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSMessage.h; sourceTree = ""; }; - DCC78D5C1D8085F200865A7C /* SOSPeer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeer.c; sourceTree = ""; }; + DCC78D5C1D8085F200865A7C /* SOSPeer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSPeer.m; sourceTree = ""; }; DCC78D5D1D8085F200865A7C /* SOSPeer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeer.h; sourceTree = ""; }; - DCC78D5E1D8085F200865A7C /* SOSPeerCoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerCoder.c; sourceTree = ""; }; + DCC78D5E1D8085F200865A7C /* SOSPeerCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSPeerCoder.m; sourceTree = ""; }; DCC78D5F1D8085F200865A7C /* SOSPeerCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeerCoder.h; sourceTree = ""; }; - DCC78D611D8085F200865A7C /* SOSFullPeerInfo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSFullPeerInfo.c; sourceTree = ""; }; + DCC78D611D8085F200865A7C /* SOSFullPeerInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSFullPeerInfo.m; sourceTree = ""; }; DCC78D621D8085F200865A7C /* SOSFullPeerInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSFullPeerInfo.h; sourceTree = ""; }; - DCC78D631D8085F200865A7C /* SOSPeerInfo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerInfo.c; sourceTree = ""; }; + DCC78D631D8085F200865A7C /* SOSPeerInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSPeerInfo.m; sourceTree = ""; }; DCC78D641D8085F200865A7C /* SOSPeerInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerInfo.h; sourceTree = ""; }; - DCC78D651D8085F200865A7C /* SOSPeerInfoDER.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerInfoDER.c; sourceTree = ""; }; + DCC78D651D8085F200865A7C /* SOSPeerInfoDER.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSPeerInfoDER.m; sourceTree = ""; }; DCC78D661D8085F200865A7C /* SOSPeerInfoDER.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeerInfoDER.h; sourceTree = ""; }; - DCC78D671D8085F200865A7C /* SOSPeerInfoV2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerInfoV2.c; sourceTree = ""; }; + DCC78D671D8085F200865A7C /* SOSPeerInfoV2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSPeerInfoV2.m; sourceTree = ""; }; DCC78D681D8085F200865A7C /* SOSPeerInfoV2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeerInfoV2.h; sourceTree = ""; }; DCC78D691D8085F200865A7C /* SOSPeerInfoPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerInfoPriv.h; sourceTree = ""; }; DCC78D6A1D8085F200865A7C /* SOSPeerInfoCollections.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerInfoCollections.c; sourceTree = ""; }; DCC78D6B1D8085F200865A7C /* SOSPeerInfoCollections.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerInfoCollections.h; sourceTree = ""; }; DCC78D6C1D8085F200865A7C /* SOSPeerInfoInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerInfoInternal.h; sourceTree = ""; }; - DCC78D6D1D8085F200865A7C /* SOSPeerInfoRingState.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerInfoRingState.c; sourceTree = ""; }; + DCC78D6D1D8085F200865A7C /* SOSPeerInfoRingState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSPeerInfoRingState.m; sourceTree = ""; }; DCC78D6E1D8085F200865A7C /* SOSPeerInfoRingState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeerInfoRingState.h; sourceTree = ""; }; - DCC78D6F1D8085F200865A7C /* SOSPeerInfoSecurityProperties.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSPeerInfoSecurityProperties.c; sourceTree = ""; }; + DCC78D6F1D8085F200865A7C /* SOSPeerInfoSecurityProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSPeerInfoSecurityProperties.m; sourceTree = ""; }; DCC78D701D8085F200865A7C /* SOSPeerInfoSecurityProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPeerInfoSecurityProperties.h; sourceTree = ""; }; - DCC78D721D8085F200865A7C /* SOSKVSKeys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSKVSKeys.c; sourceTree = ""; }; + DCC78D721D8085F200865A7C /* SOSKVSKeys.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSKVSKeys.m; sourceTree = ""; }; DCC78D731D8085F200865A7C /* SOSKVSKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSKVSKeys.h; sourceTree = ""; }; - DCC78D741D8085F200865A7C /* SOSTransport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransport.c; sourceTree = ""; }; + DCC78D741D8085F200865A7C /* SOSTransport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransport.m; sourceTree = ""; }; DCC78D751D8085F200865A7C /* SOSTransport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransport.h; sourceTree = ""; }; - DCC78D761D8085F200865A7C /* SOSTransportBackupPeer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportBackupPeer.c; sourceTree = ""; }; + DCC78D761D8085F200865A7C /* SOSTransportBackupPeer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportBackupPeer.m; sourceTree = ""; }; DCC78D771D8085F200865A7C /* SOSTransportBackupPeer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportBackupPeer.h; sourceTree = ""; }; - DCC78D781D8085F200865A7C /* SOSTransportCircle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportCircle.c; sourceTree = ""; }; + DCC78D781D8085F200865A7C /* SOSTransportCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportCircle.m; sourceTree = ""; }; DCC78D791D8085F200865A7C /* SOSTransportCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircle.h; sourceTree = ""; }; - DCC78D7A1D8085F200865A7C /* SOSTransportCircleKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportCircleKVS.c; sourceTree = ""; }; + DCC78D7A1D8085F200865A7C /* SOSTransportCircleKVS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportCircleKVS.m; sourceTree = ""; }; DCC78D7B1D8085F200865A7C /* SOSTransportCircleKVS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircleKVS.h; sourceTree = ""; }; - DCC78D7C1D8085F200865A7C /* SOSTransportKeyParameter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportKeyParameter.c; sourceTree = ""; }; + DCC78D7C1D8085F200865A7C /* SOSTransportKeyParameter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportKeyParameter.m; sourceTree = ""; }; DCC78D7D1D8085F200865A7C /* SOSTransportKeyParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportKeyParameter.h; sourceTree = ""; }; - DCC78D7E1D8085F200865A7C /* SOSTransportKeyParameterKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportKeyParameterKVS.c; sourceTree = ""; }; - DCC78D7F1D8085F200865A7C /* SOSTransportKeyParameterKVS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportKeyParameterKVS.h; sourceTree = ""; }; - DCC78D801D8085F200865A7C /* SOSTransportMessage.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportMessage.c; sourceTree = ""; }; + DCC78D801D8085F200865A7C /* SOSTransportMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportMessage.m; sourceTree = ""; }; DCC78D811D8085F200865A7C /* SOSTransportMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessage.h; sourceTree = ""; }; - DCC78D821D8085F200865A7C /* SOSTransportMessageIDS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportMessageIDS.c; sourceTree = ""; }; + DCC78D821D8085F200865A7C /* SOSTransportMessageIDS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportMessageIDS.m; sourceTree = ""; }; DCC78D831D8085F200865A7C /* SOSTransportMessageIDS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessageIDS.h; sourceTree = ""; }; - DCC78D841D8085F200865A7C /* SOSTransportMessageKVS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSTransportMessageKVS.c; sourceTree = ""; }; + DCC78D841D8085F200865A7C /* SOSTransportMessageKVS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportMessageKVS.m; sourceTree = ""; }; DCC78D851D8085F200865A7C /* SOSTransportMessageKVS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportMessageKVS.h; sourceTree = ""; }; DCC78D871D8085F200865A7C /* SOSARCDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSARCDefines.h; sourceTree = ""; }; DCC78D881D8085F200865A7C /* SOSECWrapUnwrap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSECWrapUnwrap.c; sourceTree = ""; }; - DCC78D891D8085F200865A7C /* SOSCloudCircle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = SOSCloudCircle.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; + DCC78D891D8085F200865A7C /* SOSCloudCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SOSCloudCircle.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; DCC78D8A1D8085F200865A7C /* SOSCloudCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSCloudCircle.h; sourceTree = ""; }; DCC78D8B1D8085F200865A7C /* SOSCloudCircleInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SOSCloudCircleInternal.h; sourceTree = ""; }; - DCC78D8C1D8085F200865A7C /* SOSSysdiagnose.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSSysdiagnose.c; sourceTree = ""; }; - DCC78D8D1D8085F200865A7C /* SOSInternal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSInternal.c; sourceTree = ""; }; + DCC78D8C1D8085F200865A7C /* SOSSysdiagnose.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSSysdiagnose.m; sourceTree = ""; }; + DCC78D8D1D8085F200865A7C /* SOSInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSInternal.m; sourceTree = ""; }; DCC78D8E1D8085F200865A7C /* SOSInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSInternal.h; sourceTree = ""; }; DCC78D8F1D8085F200865A7C /* SOSTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSTypes.h; sourceTree = ""; }; DCC78D901D8085F200865A7C /* SOSPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPlatform.h; sourceTree = ""; }; DCC78D921D8085F200865A7C /* secToolFileIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = secToolFileIO.h; sourceTree = ""; }; DCC78D931D8085F200865A7C /* secToolFileIO.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = secToolFileIO.c; sourceTree = ""; }; DCC78D961D8085F200865A7C /* keychain_sync.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = keychain_sync.h; sourceTree = ""; }; - DCC78D971D8085F200865A7C /* keychain_sync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = keychain_sync.c; sourceTree = ""; }; + DCC78D971D8085F200865A7C /* keychain_sync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = keychain_sync.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; DCC78D981D8085F200865A7C /* keychain_sync_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keychain_sync_test.h; sourceTree = ""; }; DCC78D991D8085F200865A7C /* keychain_sync_test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = keychain_sync_test.m; sourceTree = ""; }; DCC78D9A1D8085F200865A7C /* keychain_log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keychain_log.h; sourceTree = ""; }; - DCC78D9B1D8085F200865A7C /* keychain_log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = keychain_log.c; sourceTree = ""; }; + DCC78D9B1D8085F200865A7C /* keychain_log.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = keychain_log.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; DCC78D9C1D8085F200865A7C /* syncbackup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = syncbackup.h; sourceTree = ""; }; - DCC78D9D1D8085F200865A7C /* syncbackup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = syncbackup.c; sourceTree = ""; }; + DCC78D9D1D8085F200865A7C /* syncbackup.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = syncbackup.m; sourceTree = ""; }; DCC78D9E1D8085F200865A7C /* secViewDisplay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = secViewDisplay.c; sourceTree = ""; }; DCC78D9F1D8085F200865A7C /* secViewDisplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = secViewDisplay.h; sourceTree = ""; }; DCC78DA21D8085FC00865A7C /* Security_regressions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Security_regressions.h; path = Regressions/Security_regressions.h; sourceTree = ""; }; @@ -9196,7 +10944,7 @@ DCC78DF31D8085FC00865A7C /* login.yahoo.com.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.yahoo.com.cer.h; sourceTree = ""; }; DCC78DF41D8085FC00865A7C /* mail.google.com.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mail.google.com.cer.h; sourceTree = ""; }; DCC78DF51D8085FC00865A7C /* www.google.com.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = www.google.com.cer.h; sourceTree = ""; }; - DCC78DF71D8085FC00865A7C /* si-67-sectrust-blacklist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-67-sectrust-blacklist.c"; sourceTree = ""; }; + DCC78DF71D8085FC00865A7C /* si-67-sectrust-blocklist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-67-sectrust-blocklist.c"; sourceTree = ""; }; DCC78DF81D8085FC00865A7C /* si-68-secmatchissuer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-68-secmatchissuer.c"; sourceTree = ""; }; DCC78DF91D8085FC00865A7C /* si-69-keydesc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-69-keydesc.c"; sourceTree = ""; }; DCC78DFA1D8085FC00865A7C /* si-70-sectrust-unified.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-70-sectrust-unified.c"; sourceTree = ""; }; @@ -9214,7 +10962,7 @@ DCC78E061D8085FC00865A7C /* si-83-seccertificate-sighashalg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-83-seccertificate-sighashalg.c"; sourceTree = ""; }; DCC78E071D8085FC00865A7C /* si-85-sectrust-ssl-policy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-85-sectrust-ssl-policy.c"; sourceTree = ""; }; DCC78E081D8085FC00865A7C /* si-85-sectrust-ssl-policy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-85-sectrust-ssl-policy.h"; sourceTree = ""; }; - DCC78E091D8085FC00865A7C /* si-87-sectrust-name-constraints.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-87-sectrust-name-constraints.c"; sourceTree = ""; }; + DCC78E091D8085FC00865A7C /* si-87-sectrust-name-constraints.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-87-sectrust-name-constraints.m"; sourceTree = ""; }; DCC78E0A1D8085FC00865A7C /* si-87-sectrust-name-constraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-87-sectrust-name-constraints.h"; sourceTree = ""; }; DCC78E0B1D8085FC00865A7C /* si-89-cms-hash-agility.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-89-cms-hash-agility.c"; sourceTree = ""; }; DCC78E0C1D8085FC00865A7C /* si-89-cms-hash-agility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-89-cms-hash-agility.h"; sourceTree = ""; }; @@ -9234,7 +10982,7 @@ DCC78E1D1D8085FC00865A7C /* log_control.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = log_control.c; sourceTree = ""; }; DCC78E1E1D8085FC00865A7C /* codesign.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = codesign.c; sourceTree = ""; }; DCC78E1F1D8085FC00865A7C /* keychain_add.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = keychain_add.c; sourceTree = ""; }; - DCC78E201D8085FC00865A7C /* keychain_find.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = keychain_find.c; sourceTree = ""; }; + DCC78E201D8085FC00865A7C /* keychain_find.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = keychain_find.m; sourceTree = ""; }; DCC78E211D8085FC00865A7C /* keychain_backup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = keychain_backup.c; path = ../Security/Tool/keychain_backup.c; sourceTree = ""; }; DCC78E221D8085FC00865A7C /* pkcs12_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pkcs12_util.c; sourceTree = ""; }; DCC78E231D8085FC00865A7C /* scep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scep.c; sourceTree = ""; }; @@ -9301,10 +11049,11 @@ DCC78E9F1D80860C00865A7C /* swcagent_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = swcagent_client.h; sourceTree = ""; }; DCC78EA01D80860C00865A7C /* swcagent_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = swcagent_client.c; sourceTree = ""; }; DCC78EA11D80860C00865A7C /* swcagent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = swcagent.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - DCC78EA31D80870D00865A7C /* lib_ios_debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_debug.xcconfig; path = xcconfig/lib_ios_debug.xcconfig; sourceTree = ""; }; - DCC78EA41D80870D00865A7C /* lib_ios_release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_release.xcconfig; path = xcconfig/lib_ios_release.xcconfig; sourceTree = ""; }; DCC78EA91D8088E200865A7C /* libsecurity.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsecurity.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DCCA5E831E539EE7009EE93D /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; DCCBFA1D1DBA95CD001DD54D /* kc-20-item-delete-stress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "kc-20-item-delete-stress.c"; path = "regressions/kc-20-item-delete-stress.c"; sourceTree = ""; }; + DCCD88E61E42622200F5AA71 /* CKKSGroupOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSGroupOperation.h; sourceTree = ""; }; + DCCD88E71E42622200F5AA71 /* CKKSGroupOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSGroupOperation.m; sourceTree = ""; }; DCD067631D8CDEB2007602F1 /* gkmerge */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = gkmerge; sourceTree = ""; }; DCD067641D8CDEB2007602F1 /* gkhandmake */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gkhandmake; sourceTree = ""; }; DCD067651D8CDEB2007602F1 /* gklist */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gklist; sourceTree = ""; }; @@ -9331,8 +11080,6 @@ DCD067971D8CDF7E007602F1 /* SecCodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecCodeSigner.cpp; sourceTree = ""; }; DCD067981D8CDF7E007602F1 /* SecCodeHost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCodeHost.h; sourceTree = ""; }; DCD067991D8CDF7E007602F1 /* SecCodeHost.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecCodeHost.cpp; sourceTree = ""; }; - DCD0679A1D8CDF7E007602F1 /* SecIntegrity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecIntegrity.h; sourceTree = ""; }; - DCD0679B1D8CDF7E007602F1 /* SecIntegrity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecIntegrity.cpp; sourceTree = ""; }; DCD0679D1D8CDF7E007602F1 /* cs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cs.h; sourceTree = ""; }; DCD0679E1D8CDF7E007602F1 /* cs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cs.cpp; sourceTree = ""; }; DCD0679F1D8CDF7E007602F1 /* Code.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Code.h; sourceTree = ""; }; @@ -9383,7 +11130,7 @@ DCD067D11D8CDF7E007602F1 /* diskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = diskrep.cpp; sourceTree = ""; }; DCD067D21D8CDF7E007602F1 /* filediskrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filediskrep.h; sourceTree = ""; }; DCD067D31D8CDF7E007602F1 /* filediskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filediskrep.cpp; sourceTree = ""; }; - DCD067D41D8CDF7E007602F1 /* bundlediskrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bundlediskrep.h; sourceTree = ""; }; + DCD067D41D8CDF7E007602F1 /* bundlediskrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bundlediskrep.h; sourceTree = ""; usesTabs = 1; }; DCD067D51D8CDF7E007602F1 /* bundlediskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bundlediskrep.cpp; sourceTree = ""; }; DCD067D61D8CDF7E007602F1 /* kerneldiskrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kerneldiskrep.h; sourceTree = ""; }; DCD067D71D8CDF7E007602F1 /* kerneldiskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = kerneldiskrep.cpp; sourceTree = ""; }; @@ -9399,8 +11146,6 @@ DCD067E11D8CDF7E007602F1 /* detachedrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = detachedrep.cpp; sourceTree = ""; }; DCD067E21D8CDF7E007602F1 /* piddiskrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = piddiskrep.h; sourceTree = ""; }; DCD067E31D8CDF7E007602F1 /* piddiskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = piddiskrep.cpp; sourceTree = ""; }; - DCD067E51D8CDF7E007602F1 /* SecIntegrityLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecIntegrityLib.h; sourceTree = ""; }; - DCD067E61D8CDF7E007602F1 /* SecIntegrityLib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecIntegrityLib.c; sourceTree = ""; }; DCD067E71D8CDF7E007602F1 /* SecCodeHostLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCodeHostLib.h; sourceTree = ""; }; DCD067E81D8CDF7E007602F1 /* SecCodeHostLib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCodeHostLib.c; sourceTree = ""; }; DCD067EA1D8CDF7E007602F1 /* sp-watch.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "sp-watch.d"; path = "../dtrace/sp-watch.d"; sourceTree = ""; }; @@ -9424,8 +11169,7 @@ DCD067FD1D8CDF7E007602F1 /* dirscanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dirscanner.cpp; sourceTree = ""; }; DCD067FF1D8CDF7E007602F1 /* antlrplugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = antlrplugin.h; path = lib/antlrplugin.h; sourceTree = ""; }; DCD068001D8CDF7E007602F1 /* antlrplugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = antlrplugin.cpp; path = lib/antlrplugin.cpp; sourceTree = ""; }; - DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTaskPriv.h; sourceTree = ""; }; - DCD068041D8CDF7E007602F1 /* SecTask.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTask.c; sourceTree = ""; }; + DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTaskPriv.h; path = sectask/SecTaskPriv.h; sourceTree = ""; }; DCD068061D8CDF7E007602F1 /* SecAssessment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SecAssessment.h; sourceTree = ""; }; DCD068071D8CDF7E007602F1 /* SecAssessment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = SecAssessment.cpp; sourceTree = ""; }; DCD068081D8CDF7E007602F1 /* evaluationmanager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = evaluationmanager.h; sourceTree = ""; }; @@ -9572,9 +11316,6 @@ DCD06ACF1D8E0D7D007602F1 /* globalizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = globalizer.cpp; sourceTree = ""; }; DCD06AD01D8E0D7D007602F1 /* hashing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hashing.h; sourceTree = ""; }; DCD06AD11D8E0D7D007602F1 /* hashing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hashing.cpp; sourceTree = ""; }; - DCD06AD21D8E0D7D007602F1 /* iodevices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iodevices.h; sourceTree = ""; }; - DCD06AD31D8E0D7D007602F1 /* iodevices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iodevices.cpp; sourceTree = ""; }; - DCD06AD41D8E0D7D007602F1 /* ktracecodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ktracecodes.h; sourceTree = ""; }; DCD06AD51D8E0D7D007602F1 /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = logging.h; sourceTree = ""; }; DCD06AD61D8E0D7D007602F1 /* logging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = logging.cpp; sourceTree = ""; }; DCD06AD71D8E0D7D007602F1 /* memstreams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memstreams.h; sourceTree = ""; }; @@ -9606,23 +11347,15 @@ DCD06AF11D8E0D7D007602F1 /* trackingallocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = trackingallocator.cpp; sourceTree = ""; }; DCD06AF21D8E0D7D007602F1 /* transactions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transactions.cpp; sourceTree = ""; }; DCD06AF31D8E0D7D007602F1 /* transactions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = transactions.h; sourceTree = ""; }; - DCD06AF41D8E0D7D007602F1 /* typedvalue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = typedvalue.cpp; sourceTree = ""; }; - DCD06AF51D8E0D7D007602F1 /* typedvalue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = typedvalue.h; sourceTree = ""; }; DCD06AF61D8E0D7D007602F1 /* utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utilities.h; sourceTree = ""; }; DCD06AF71D8E0D7D007602F1 /* utilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utilities.cpp; sourceTree = ""; }; DCD06AF81D8E0D7D007602F1 /* utility_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utility_config.h; sourceTree = ""; }; - DCD06AF91D8E0D7D007602F1 /* fdmover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fdmover.h; sourceTree = ""; }; - DCD06AFA1D8E0D7D007602F1 /* fdmover.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fdmover.cpp; sourceTree = ""; }; - DCD06AFB1D8E0D7D007602F1 /* fdsel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fdsel.h; sourceTree = ""; }; - DCD06AFC1D8E0D7D007602F1 /* fdsel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fdsel.cpp; sourceTree = ""; }; DCD06AFD1D8E0D7D007602F1 /* kq++.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "kq++.h"; sourceTree = ""; }; DCD06AFE1D8E0D7D007602F1 /* kq++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "kq++.cpp"; sourceTree = ""; }; DCD06AFF1D8E0D7D007602F1 /* muscle++.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "muscle++.h"; sourceTree = ""; }; DCD06B001D8E0D7D007602F1 /* muscle++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "muscle++.cpp"; sourceTree = ""; }; DCD06B011D8E0D7D007602F1 /* pcsc++.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "pcsc++.h"; sourceTree = ""; }; DCD06B021D8E0D7D007602F1 /* pcsc++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "pcsc++.cpp"; sourceTree = ""; }; - DCD06B031D8E0D7D007602F1 /* selector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = selector.h; sourceTree = ""; }; - DCD06B041D8E0D7D007602F1 /* selector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = selector.cpp; sourceTree = ""; }; DCD06B051D8E0D7D007602F1 /* unix++.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "unix++.h"; sourceTree = ""; }; DCD06B061D8E0D7D007602F1 /* unix++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "unix++.cpp"; sourceTree = ""; }; DCD06B071D8E0D7D007602F1 /* unixchild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unixchild.h; sourceTree = ""; }; @@ -9652,37 +11385,28 @@ DCD06B211D8E0D7D007602F1 /* cfmunge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfmunge.cpp; sourceTree = ""; }; DCD06B221D8E0D7D007602F1 /* cfutilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfutilities.h; sourceTree = ""; }; DCD06B231D8E0D7D007602F1 /* cfutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = cfutilities.cpp; sourceTree = ""; }; - DCD06B251D8E0D7D007602F1 /* bufferfifo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bufferfifo.h; sourceTree = ""; }; - DCD06B261D8E0D7D007602F1 /* bufferfifo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bufferfifo.cpp; sourceTree = ""; }; - DCD06B271D8E0D7D007602F1 /* buffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = buffers.h; sourceTree = ""; }; - DCD06B281D8E0D7D007602F1 /* buffers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = buffers.cpp; sourceTree = ""; }; - DCD06B291D8E0D7D007602F1 /* headermap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = headermap.h; sourceTree = ""; }; - DCD06B2A1D8E0D7D007602F1 /* headermap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = headermap.cpp; sourceTree = ""; }; - DCD06B2B1D8E0D7D007602F1 /* hosts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hosts.h; sourceTree = ""; }; - DCD06B2C1D8E0D7D007602F1 /* hosts.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hosts.cpp; sourceTree = ""; }; - DCD06B2D1D8E0D7D007602F1 /* inetreply.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inetreply.h; sourceTree = ""; }; - DCD06B2E1D8E0D7D007602F1 /* inetreply.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inetreply.cpp; sourceTree = ""; }; - DCD06B2F1D8E0D7D007602F1 /* ip++.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ip++.h"; sourceTree = ""; }; - DCD06B301D8E0D7D007602F1 /* ip++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "ip++.cpp"; sourceTree = ""; }; - DCD06B311D8E0D7D007602F1 /* url.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url.h; sourceTree = ""; }; - DCD06B321D8E0D7D007602F1 /* url.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = url.cpp; sourceTree = ""; }; - DCD06B331D8E0D7D007602F1 /* socks++.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "socks++.h"; sourceTree = ""; }; - DCD06B341D8E0D7D007602F1 /* socks++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "socks++.cpp"; sourceTree = ""; }; - DCD06B351D8E0D7D007602F1 /* socks++4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "socks++4.h"; sourceTree = ""; }; - DCD06B361D8E0D7D007602F1 /* socks++4.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "socks++4.cpp"; sourceTree = ""; }; - DCD06B371D8E0D7D007602F1 /* socks++5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "socks++5.h"; sourceTree = ""; }; - DCD06B381D8E0D7D007602F1 /* socks++5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "socks++5.cpp"; sourceTree = ""; }; DCD06BC21D8E0DC2007602F1 /* utilities_dtrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utilities_dtrace.h; path = derived_src/security_utilities/utilities_dtrace.h; sourceTree = BUILT_PRODUCTS_DIR; }; DCD06BC51D8E0DD3007602F1 /* security_utilities.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = security_utilities.d; path = lib/security_utilities.d; sourceTree = ""; }; + DCD662F31E329B6800188186 /* CKKSNewTLKOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSNewTLKOperation.h; sourceTree = ""; }; + DCD662F41E329B6800188186 /* CKKSNewTLKOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSNewTLKOperation.m; sourceTree = ""; }; DCD66D731D8204A700DB1393 /* libSecTrustOSX.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecTrustOSX.a; sourceTree = BUILT_PRODUCTS_DIR; }; DCD66DDB1D8205C400DB1393 /* libSecOtrOSX.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecOtrOSX.a; sourceTree = BUILT_PRODUCTS_DIR; }; + DCD6C4B01EC5302400414FEE /* CKKSNearFutureScheduler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSNearFutureScheduler.h; sourceTree = ""; }; + DCD6C4B11EC5302500414FEE /* CKKSNearFutureScheduler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSNearFutureScheduler.m; sourceTree = ""; }; + DCD6C4B61EC5319600414FEE /* CKKSNearFutureSchedulerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSNearFutureSchedulerTests.m; sourceTree = ""; }; + DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSecureObjectSyncFramework.a; sourceTree = BUILT_PRODUCTS_DIR; }; DCDCC7DD1D9B54DF006487E8 /* secd-202-recoverykey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-202-recoverykey.m"; sourceTree = ""; }; - DCDCC7E41D9B551C006487E8 /* SOSAccountSync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountSync.c; sourceTree = ""; }; + DCDCC7E41D9B551C006487E8 /* SOSAccountSync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountSync.m; sourceTree = ""; }; + DCDCCB8D1DF7B8D4006E840E /* CKKSItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSItem.h; sourceTree = ""; }; + DCDCCB8E1DF7B8D4006E840E /* CKKSItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSItem.m; sourceTree = ""; }; + DCE278DB1ED789EF0083B485 /* CKKSCurrentItemPointer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSCurrentItemPointer.h; sourceTree = ""; }; + DCE278DC1ED789EF0083B485 /* CKKSCurrentItemPointer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSCurrentItemPointer.m; sourceTree = ""; }; + DCE278E61ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSUpdateCurrentItemPointerOperation.h; sourceTree = ""; }; + DCE278E71ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSUpdateCurrentItemPointerOperation.m; sourceTree = ""; }; 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; name = security2.1; path = ../OSX/security2/security2.1; sourceTree = ""; }; 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 = ""; }; DCE4E6D71D7A420D00AFB96E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = OSX/SecurityTestsOSX/main.m; sourceTree = ""; }; - DCE4E6D91D7A421D00AFB96E /* libcoretls.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcoretls.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libcoretls.dylib; sourceTree = DEVELOPER_DIR; }; 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; }; DCE4E7B21D7A43B500AFB96E /* SecurityTestsOSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecurityTestsOSX.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -9697,8 +11421,6 @@ DCE4E8271D7A4F0E00AFB96E /* login.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = login.framework; path = System/Library/PrivateFrameworks/login.framework; sourceTree = SDKROOT; }; DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ios_on_macos.xcconfig; path = xcconfig/ios_on_macos.xcconfig; sourceTree = ""; }; DCE4E8591D7A57AE00AFB96E /* trustd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = trustd; sourceTree = BUILT_PRODUCTS_DIR; }; - DCE4E85B1D7A583A00AFB96E /* com.apple.trustd.agent.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.trustd.agent.plist; path = OSX/trustd/com.apple.trustd.agent.plist; sourceTree = ""; }; - DCE4E85C1D7A584000AFB96E /* com.apple.trustd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.trustd.plist; path = OSX/trustd/com.apple.trustd.plist; sourceTree = ""; }; DCE4E8941D7F34F600AFB96E /* authd.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = authd.xpc; sourceTree = BUILT_PRODUCTS_DIR; }; DCE4E8A11D7F353900AFB96E /* agent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = agent.c; path = OSX/authd/agent.c; sourceTree = ""; }; DCE4E8A21D7F353900AFB96E /* authdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = authdb.c; path = OSX/authd/authdb.c; sourceTree = ""; }; @@ -9708,7 +11430,6 @@ DCE4E8A61D7F353900AFB96E /* ccaudit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ccaudit.c; path = OSX/authd/ccaudit.c; sourceTree = ""; }; DCE4E8A71D7F353900AFB96E /* crc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crc.c; path = OSX/authd/crc.c; sourceTree = ""; }; DCE4E8A81D7F353900AFB96E /* credential.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = credential.c; path = OSX/authd/credential.c; sourceTree = ""; }; - DCE4E8A91D7F353900AFB96E /* debugging.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debugging.c; path = OSX/authd/debugging.c; sourceTree = ""; }; DCE4E8AA1D7F353900AFB96E /* engine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = engine.c; path = OSX/authd/engine.c; sourceTree = ""; }; DCE4E8AB1D7F353900AFB96E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = OSX/authd/main.c; sourceTree = ""; }; DCE4E8AC1D7F353900AFB96E /* mechanism.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mechanism.c; path = OSX/authd/mechanism.c; sourceTree = ""; }; @@ -9750,6 +11471,13 @@ DCE4E9451D7F3E8700AFB96E /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = "OSX/Keychain Circle Notification/en.lproj/Localizable.strings"; sourceTree = SOURCE_ROOT; }; DCE4E9461D7F3E8700AFB96E /* com.apple.security.keychain-circle-notification.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "com.apple.security.keychain-circle-notification.plist"; sourceTree = ""; }; DCE4E9481D7F3E8700AFB96E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = "OSX/Keychain Circle Notification/en.lproj/InfoPlist.strings"; sourceTree = SOURCE_ROOT; }; + DCE7F2081F21726500DDB0F7 /* CKKSAPSReceiverTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSAPSReceiverTests.m; sourceTree = ""; }; + DCEA5D531E2826DB0089CF55 /* CKKSSIV.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSSIV.h; sourceTree = ""; }; + DCEA5D541E2826DB0089CF55 /* CKKSSIV.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSSIV.m; sourceTree = ""; }; + DCEA5D831E2F14810089CF55 /* CKKSAPSReceiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSAPSReceiver.h; sourceTree = ""; }; + DCEA5D841E2F14810089CF55 /* CKKSAPSReceiver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSAPSReceiver.m; sourceTree = ""; }; + DCEA5D951E3014250089CF55 /* CKKSZone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSZone.h; sourceTree = ""; }; + DCEA5D961E3014250089CF55 /* CKKSZone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSZone.m; sourceTree = ""; }; 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; }; DCF783141D88B4DE00E694BB /* libsecurity_apple_csp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurity_apple_csp.a; sourceTree = BUILT_PRODUCTS_DIR; }; DCF783151D88B60D00E694BB /* aesCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aesCommon.h; sourceTree = ""; }; @@ -10082,10 +11810,21 @@ DCF788F91D88CD4200E694BB /* tpTime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tpTime.c; sourceTree = ""; }; DCF788FA1D88CD4200E694BB /* tpTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tpTime.h; sourceTree = ""; }; DCF789471D88D17C00E694BB /* AppleX509TPBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AppleX509TPBuiltin.cpp; path = OSX/libsecurity_apple_x509_tp/lib/AppleX509TPBuiltin.cpp; sourceTree = ""; }; - DCFAEDC81D999851005187E4 /* SOSAccountGhost.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountGhost.c; sourceTree = ""; }; + DCF7A89F1F04502300CABE89 /* CKKSControlProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSControlProtocol.h; sourceTree = ""; }; + DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSControlProtocol.m; sourceTree = ""; }; + DCFAEDC81D999851005187E4 /* SOSAccountGhost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountGhost.m; sourceTree = ""; }; DCFAEDC91D999851005187E4 /* SOSAccountGhost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSAccountGhost.h; sourceTree = ""; }; - DCFAEDD11D9998DD005187E4 /* secd-668-ghosts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "secd-668-ghosts.c"; sourceTree = ""; }; + DCFAEDD11D9998DD005187E4 /* secd-668-ghosts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-668-ghosts.m"; sourceTree = ""; }; DCFAEDD51D99A464005187E4 /* secd-36-ks-encrypt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-36-ks-encrypt.m"; sourceTree = ""; }; + DCFB12C31E95A4C000510F5F /* CKKSCKAccountStateTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSCKAccountStateTracker.h; sourceTree = ""; }; + DCFB12C41E95A4C000510F5F /* CKKSCKAccountStateTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSCKAccountStateTracker.m; sourceTree = ""; }; + DCFE1C251F17E455007640C8 /* CKKSDeviceStateEntry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSDeviceStateEntry.h; sourceTree = ""; }; + DCFE1C261F17E455007640C8 /* CKKSDeviceStateEntry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSDeviceStateEntry.m; sourceTree = ""; }; + DCFE1C321F17ECE5007640C8 /* CKKSCondition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSCondition.h; sourceTree = ""; }; + DCFE1C331F17ECE5007640C8 /* CKKSCondition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSCondition.m; sourceTree = ""; }; + DCFE1C3C1F17EFB5007640C8 /* CKKSConditionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSConditionTests.m; sourceTree = ""; }; + DCFE1C4F1F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSUpdateDeviceStateOperation.h; sourceTree = ""; }; + DCFE1C501F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSUpdateDeviceStateOperation.m; sourceTree = ""; }; E7104A0B169E171900DB0045 /* security_tool_commands.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = security_tool_commands.c; sourceTree = ""; }; E710C7421331946400F85568 /* SecurityTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecurityTests.app; sourceTree = BUILT_PRODUCTS_DIR; }; E710C74C1331946500F85568 /* SecurityTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SecurityTests-Info.plist"; sourceTree = ""; }; @@ -10107,6 +11846,8 @@ E772FD6F1CC15F1F00D63E41 /* NSData+SecRandom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+SecRandom.h"; sourceTree = ""; }; E78A9AD81D34959200006B5B /* NSFileHandle+Formatting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSFileHandle+Formatting.h"; path = "../OSX/sec/SOSCircle/Tool/NSFileHandle+Formatting.h"; sourceTree = ""; }; E78A9AD91D34959200006B5B /* NSFileHandle+Formatting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSFileHandle+Formatting.m"; path = "../OSX/sec/SOSCircle/Tool/NSFileHandle+Formatting.m"; sourceTree = ""; }; + E78CCDC61E737F6700C1CFAA /* SecNSAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecNSAdditions.m; path = src/SecNSAdditions.m; sourceTree = ""; }; + E78CCDCD1E737F8100C1CFAA /* SecNSAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecNSAdditions.h; path = src/SecNSAdditions.h; sourceTree = ""; }; E794BA6E1C7424D800339A0F /* KCDer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KCDer.m; sourceTree = ""; }; E794BAD91C7598E400339A0F /* KCJoiningMessages.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KCJoiningMessages.h; sourceTree = ""; }; E794BAFF1C7598F900339A0F /* KCJoiningMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KCJoiningMessages.m; sourceTree = ""; }; @@ -10139,7 +11880,6 @@ E7E3EFB91CBC192A00E79A5D /* KCAccountKCCircleDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KCAccountKCCircleDelegate.m; sourceTree = ""; }; E7E3EFE21CBC195700E79A5D /* KCAccountKCCircleDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KCAccountKCCircleDelegate.h; sourceTree = ""; }; E7E4318813319C0700AF0CFD /* SecurityTests-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SecurityTests-Entitlements.plist"; sourceTree = ""; }; - E7E5B55E1DC7ACAE00C03FFB /* SOSAccountGetSet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SOSAccountGetSet.c; sourceTree = ""; }; E7F480111C729C7B00390FDB /* NSError+KCCreationHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+KCCreationHelpers.h"; sourceTree = ""; }; E7F480131C7397CE00390FDB /* KCJoiningSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KCJoiningSession.h; sourceTree = ""; }; E7F480141C73980D00390FDB /* KCJoiningRequestSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KCJoiningRequestSession.m; sourceTree = ""; }; @@ -10156,7 +11896,6 @@ E7FCBE411314471B000DE34E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; E7FCBE431314471B000DE34E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; E7FCBE451314471B000DE34E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - E7FE40BD1DC803FD00F0F5B6 /* secd-210-keyinterest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "secd-210-keyinterest.m"; path = "../../SOSCircle/Regressions/secd-210-keyinterest.m"; sourceTree = ""; }; E7FE40C41DC804E400F0F5B6 /* CKDSimulatedStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedStore.m; path = ../../SOSCircle/SecureObjectSync/CKDSimulatedStore.m; sourceTree = ""; }; E7FE40C61DC804FA00F0F5B6 /* CKDSimulatedStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedStore.h; path = ../../SOSCircle/SecureObjectSync/CKDSimulatedStore.h; sourceTree = ""; }; E7FE40C71DC8084600F0F5B6 /* CKDSimulatedAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedAccount.h; path = ../../SOSCircle/Regressions/CKDSimulatedAccount.h; sourceTree = ""; }; @@ -10165,38 +11904,74 @@ EB0BC93E1C3C791500785842 /* secedumodetest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secedumodetest; sourceTree = BUILT_PRODUCTS_DIR; }; EB0BC9651C3C794700785842 /* secedumodetest.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = secedumodetest.entitlements; path = secedumodetest/secedumodetest.entitlements; sourceTree = ""; }; EB0BC9661C3C794700785842 /* secedumodetest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = secedumodetest.m; path = secedumodetest/secedumodetest.m; sourceTree = ""; }; + EB10556B1E14DC0F0003C309 /* SecCertificateFuzzer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCertificateFuzzer.c; sourceTree = ""; }; + EB1055751E14DF430003C309 /* libSecCertificateFuzzer.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libSecCertificateFuzzer.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + EB10557A1E14DF640003C309 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + EB108F121E6CE48B003B0456 /* KCParing.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = KCParing.plist; path = Tests/KCParing.plist; sourceTree = ""; }; + EB108F411E6CE4D2003B0456 /* KCPairingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KCPairingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + EB27FF0B1E402C8000EC9E3A /* ckksctl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ckksctl.h; sourceTree = ""; }; + EB27FF0C1E402C8000EC9E3A /* ckksctl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ckksctl.m; sourceTree = ""; }; + EB27FF111E402CD300EC9E3A /* ckksctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ckksctl; sourceTree = BUILT_PRODUCTS_DIR; }; + EB27FF2F1E408CC900EC9E3A /* ckksctl-Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "ckksctl-Entitlements.plist"; sourceTree = ""; }; EB2CA4D81D2C28C800AB770F /* libaks.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libaks.a; path = usr/local/lib/libaks.a; sourceTree = SDKROOT; }; EB2CA5561D2C30F700AB770F /* Security.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Security.xcconfig; path = xcconfig/Security.xcconfig; sourceTree = ""; }; + EB2D54A01F02A28200E46890 /* SecAtomicFile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SecAtomicFile.cpp; sourceTree = ""; }; + EB2D54AA1F02A45E00E46890 /* secatomicfile */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secatomicfile; sourceTree = BUILT_PRODUCTS_DIR; }; EB3A8DD71BEEC4D6001A89AA /* Security_edumode.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Security_edumode.plist; sourceTree = ""; }; - EB3EBF0F1DBD413600620B2C /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = usr/lib/libobjc.dylib; sourceTree = SDKROOT; }; + EB413B751E6624A400592085 /* PairingChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PairingChannel.h; sourceTree = ""; }; + EB413B761E6624A500592085 /* PairingChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PairingChannel.m; sourceTree = ""; }; + EB413B7E1E663A8300592085 /* KCPairingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KCPairingTest.m; path = Tests/KCPairingTest.m; sourceTree = ""; }; EB425CA61C65846D000ECE53 /* secbackuptest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secbackuptest; sourceTree = BUILT_PRODUCTS_DIR; }; EB425CCD1C65854F000ECE53 /* secbackuptest.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = secbackuptest.entitlements; path = secbackuptest/secbackuptest.entitlements; sourceTree = ""; }; EB425CCE1C65854F000ECE53 /* secbackuptest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = secbackuptest.m; path = secbackuptest/secbackuptest.m; sourceTree = ""; }; EB433A1E1CC3242C00A7EACE /* secitemstresstest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = secitemstresstest.m; path = secitemstresstest/secitemstresstest.m; sourceTree = ""; }; 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 = ""; }; + EB48C19E1E573EDC00EC5E57 /* sos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = sos.m; sourceTree = ""; }; + EB59D66B1E95EF2900997EAC /* libcompression.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcompression.dylib; path = usr/lib/libcompression.dylib; sourceTree = SDKROOT; }; EB6928BE1D9C9C5900062A18 /* SecRecoveryKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRecoveryKey.h; sourceTree = ""; }; EB6928BF1D9C9C5900062A18 /* SecRecoveryKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecRecoveryKey.m; sourceTree = ""; }; EB6928C91D9C9D9D00062A18 /* rk_01_recoverykey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = rk_01_recoverykey.m; path = Regressions/rk_01_recoverykey.m; sourceTree = ""; }; EB69AB091BF4347700913AF1 /* SecEMCSPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecEMCSPriv.h; sourceTree = ""; }; + EB75B4931E75A44100E469CC /* SOSPiggyback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSPiggyback.h; sourceTree = ""; }; + EB75B4941E75A44100E469CC /* SOSPiggyback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSPiggyback.m; sourceTree = ""; }; + EB76B75A1DCB0CDA00C43FBC /* Keychain Circle Notification.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Keychain Circle Notification.8"; sourceTree = ""; }; + EB7AE6F61E86D55400B80B15 /* SecPLWrappers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecPLWrappers.m; path = src/SecPLWrappers.m; sourceTree = ""; }; + EB7AE6F71E86D55400B80B15 /* SecPLWrappers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecPLWrappers.h; path = src/SecPLWrappers.h; sourceTree = ""; }; EB8021411D3D90BB008540C4 /* Security.iOS.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = Security.iOS.modulemap; path = Modules/Security.iOS.modulemap; sourceTree = ""; }; EB8021421D3D90BB008540C4 /* Security.macOS.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = Security.macOS.modulemap; path = Modules/Security.macOS.modulemap; sourceTree = ""; }; + EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-37-pairing-initial-sync.m"; sourceTree = ""; }; EB9C1D7A1BDFD0E000F89272 /* secbackupntest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secbackupntest; sourceTree = BUILT_PRODUCTS_DIR; }; EB9C1D7D1BDFD0E100F89272 /* secbackupntest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = secbackupntest.m; sourceTree = ""; }; EB9C1DAD1BDFD49400F89272 /* Security.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Security.plist; sourceTree = ""; }; EBA9AA7B1CE30CE7004E2B68 /* secitemnotifications.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = secitemnotifications.entitlements; path = secitemnotifications/secitemnotifications.entitlements; sourceTree = ""; }; EBA9AA7C1CE30CE7004E2B68 /* secitemnotifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = secitemnotifications.m; path = secitemnotifications/secitemnotifications.m; sourceTree = ""; }; EBA9AA861CE30E58004E2B68 /* secitemnotifications */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secitemnotifications; sourceTree = BUILT_PRODUCTS_DIR; }; + EBB407AF1EBA433A00A541A5 /* CKKSPowerCollection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CKKSPowerCollection.h; path = analytics/CKKSPowerCollection.h; sourceTree = ""; }; + EBB407B01EBA433A00A541A5 /* CKKSPowerCollection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CKKSPowerCollection.m; path = analytics/CKKSPowerCollection.m; sourceTree = ""; }; + EBB8399B1E295B8F00853BAC /* secfuzzer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = secfuzzer.m; sourceTree = ""; }; + EBB839A51E29665D00853BAC /* secfuzzer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secfuzzer; sourceTree = BUILT_PRODUCTS_DIR; }; + EBC15B1B1DB4306C00126882 /* com.apple.secd.sb */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.secd.sb; sourceTree = ""; }; EBCF01001DF501310055AF97 /* swcagent-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "swcagent-entitlements.plist"; sourceTree = ""; }; EBCF73F11CE45F8600BED7CA /* secitemfunctionality.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = secitemfunctionality.entitlements; path = secitemfunctionality/secitemfunctionality.entitlements; sourceTree = ""; }; EBCF73F21CE45F8600BED7CA /* secitemfunctionality.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = secitemfunctionality.m; path = secitemfunctionality/secitemfunctionality.m; sourceTree = ""; }; EBCF73FC1CE45F9C00BED7CA /* secitemfunctionality */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secitemfunctionality; sourceTree = BUILT_PRODUCTS_DIR; }; EBE54D771BE33227000C4856 /* libmis.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmis.dylib; path = usr/lib/libmis.dylib; sourceTree = SDKROOT; }; + EBEEEE351EA31A8300E15F5C /* SOSControlHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSControlHelper.h; sourceTree = ""; }; + EBEEEE361EA31A8300E15F5C /* SOSControlHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSControlHelper.m; sourceTree = ""; }; + EBF3745E1DBFB32A0065D840 /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = usr/lib/libobjc.dylib; 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 = ""; }; EBF3747F1DC057FE0065D840 /* security-sysdiagnose.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = "security-sysdiagnose.1"; sourceTree = ""; }; EBF3749A1DC064200065D840 /* SecADWrapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = SecADWrapper.c; path = src/SecADWrapper.c; sourceTree = ""; }; EBF3749B1DC064200065D840 /* SecADWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecADWrapper.h; path = src/SecADWrapper.h; sourceTree = ""; }; + F619D71D1ED70BB0005B5F46 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = OSX/authorizationdump/main.m; sourceTree = ""; }; + 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 = ""; }; + F667EC601E96E9B100203D5C /* authdtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = authdtest; sourceTree = BUILT_PRODUCTS_DIR; }; + F6A0971E1E953A1500B1E7D6 /* authdtestlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = authdtestlist.h; path = OSX/authd/tests/authdtestlist.h; sourceTree = ""; }; + F6A0971F1E953ABD00B1E7D6 /* authdtests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = authdtests.m; path = OSX/authd/tests/authdtests.m; sourceTree = ""; }; + F6A3CB0D1E7062BA00E7821F /* authd-Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "authd-Entitlements.plist"; path = "OSX/authd/authd-Entitlements.plist"; sourceTree = ""; }; F93C493A1AB8FF530047E01A /* ckcdiagnose.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = ckcdiagnose.sh; sourceTree = ""; }; /* End PBXFileReference section */ @@ -10205,8 +11980,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 474B5FC71E662E67007546F8 /* SecurityFoundation.framework in Frameworks */, + 6C8CC3B61E2F98C2009025C5 /* ProtocolBuffer.framework in Frameworks */, + D40B6A8D1E2B63D900CD6EE5 /* libtrustd.a in Frameworks */, EBE901721C2283F7007308C6 /* AggregateDictionary.framework in Frameworks */, - DC00ABD61D821F3200513D74 /* libsecipc_client.a in Frameworks */, DCD22D8D1D8CCC79001C9B81 /* libregressionBase.a in Frameworks */, 438168C51B4ED43B00C54D58 /* CoreFoundation.framework in Frameworks */, EB3409B01C1D627400D77661 /* Foundation.framework in Frameworks */, @@ -10216,8 +11993,10 @@ DC00ABD71D821F3F00513D74 /* libsecurity.a in Frameworks */, DC00ABD81D821F4300513D74 /* libsecdRegressions.a in Frameworks */, DC00ABD91D821F4700513D74 /* libsecurityd_ios.a in Frameworks */, - DC00ABDA1D821F4A00513D74 /* libSecureObjectSync.a in Frameworks */, + DC00ABDA1D821F4A00513D74 /* libSecureObjectSyncServer.a in Frameworks */, + DCD8A1ED1E09F8B500E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DCD22D8C1D8CCC63001C9B81 /* libutilities.a in Frameworks */, + DCDCCB3E1DF25DA0006E840E /* ApplePushService.framework in Frameworks */, D447C4101D3094740082FC1D /* Security.framework in Frameworks */, 0C0BDB8D1756A66100BC1A7E /* CFNetwork.framework in Frameworks */, 0C0BDB911756A8A400BC1A7E /* IOKit.framework in Frameworks */, @@ -10251,6 +12030,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 225394AF1E3080A600D3CD9B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 438169091B4EDCBD00C54D58 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -10261,24 +12047,60 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 470415CC1E5E14B5001F3D95 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 47702B191E5E58EF00B29577 /* Security.framework in Frameworks */, + 47702B181E5E58E600B29577 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 47702B1B1E5F409700B29577 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 47702B291E5F463400B29577 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 47702B2B1E5F492C00B29577 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 47702B391E5F4B2200B29577 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 47C51B811EEA657D0032D9E5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 47C51B891EEA657D0032D9E5 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4C32C0AD0A4975F6002891BD /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EB3EBF111DBD413F00620B2C /* libobjc.dylib in Frameworks */, - DC00AB611D821BE600513D74 /* libSecureObjectSync.a in Frameworks */, + CD791B3C1DFC9A7600F0E5DC /* libsqlite3.0.dylib in Frameworks */, + DC3A81D31D99D561000C7419 /* libcoretls.dylib in Frameworks */, + DC3A81D51D99D568000C7419 /* libcoretls_cfhelpers.dylib in Frameworks */, 5296CB4E1655B8F5009912AF /* libMobileGestalt.dylib in Frameworks */, - 0C78F1D016A5E3EB00654E08 /* libbsm.dylib in Frameworks */, - BEE523D71DACA97600DD0AA3 /* libz.dylib in Frameworks */, + DCD8A19A1E09EE9800E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DC59EA771D91CC6D001BDDF5 /* libDER_not_installed.a in Frameworks */, + 0C78F1D016A5E3EB00654E08 /* libbsm.dylib in Frameworks */, DCD22D771D8CC9CD001C9B81 /* libASN1_not_installed.a in Frameworks */, 44A655831AA4B4BB0059D185 /* libctkclient.a in Frameworks */, DC59E9A41D91C6F0001BDDF5 /* libCMS.a in Frameworks */, DCD22D781D8CC9D8001C9B81 /* libsecurity_ssl.a in Frameworks */, - DC00AB621D821BEC00513D74 /* libsecipc_client.a in Frameworks */, + CD791B3D1DFC9AB200F0E5DC /* libsqlite3.dylib in Frameworks */, DC00AB631D821BEF00513D74 /* libsecurity.a in Frameworks */, DCD22D791D8CC9F1001C9B81 /* libutilities.a in Frameworks */, DC00AB641D821BF300513D74 /* liblogging.a in Frameworks */, + 226A8B461DEF5905004C35E3 /* libsecurity_utilities.a in Frameworks */, + 22E337DA1E37FD66001D5637 /* libsecurity_codesigning_ios.a in Frameworks */, 4432AF8B1A014664000958DC /* libcoreauthd_client.a in Frameworks */, 4432AF8D1A01472C000958DC /* libaks_acl.a in Frameworks */, 438166ED1B4ECF9400C54D58 /* CoreFoundation.framework in Frameworks */, @@ -10290,7 +12112,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0C869B431C865E4D006A2873 /* CoreCDP.framework in Frameworks */, + D459A1781E9FFE60009ED74B /* CoreCDP.framework in Frameworks */, 43DB54551BB1F8920083C3F1 /* ProtectedCloudStorage.framework in Frameworks */, 4C8A38C917B93DF10001B4C0 /* CloudServices.framework in Frameworks */, 4C7913251799A5CC00A9633E /* MobileCoreServices.framework in Frameworks */, @@ -10313,13 +12135,16 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 47B90C951F3509C1006500BC /* CrashReporterSupport.framework in Frameworks */, + D40B6A8E1E2B643500CD6EE5 /* libtrustd.a in Frameworks */, DC00ABB31D821E0400513D74 /* libSharedRegressions.a in Frameworks */, EBE9019C1C2285DB007308C6 /* AggregateDictionary.framework in Frameworks */, E7D690A11652E07B0079537A /* libMobileGestalt.dylib in Frameworks */, DCD22D991D8CCFB4001C9B81 /* libsecurity_ssl_regressions.a in Frameworks */, DC00ABB41D821E0700513D74 /* libsecurityd_ios.a in Frameworks */, DCD22D9A1D8CCFC1001C9B81 /* libutilities.a in Frameworks */, - DC00ABB51D821E0B00513D74 /* libSecureObjectSync.a in Frameworks */, + DC00ABB51D821E0B00513D74 /* libSecureObjectSyncServer.a in Frameworks */, + DCD8A1F91E09F98E00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DCD22D9B1D8CCFCB001C9B81 /* libASN1_not_installed.a in Frameworks */, DC59EA851D91CD35001BDDF5 /* libDER_not_installed.a in Frameworks */, DC65E7771D8CB82500152EF0 /* libregressionBase.a in Frameworks */, @@ -10338,6 +12163,7 @@ 4C711D7013AFCD0900FE865D /* IOKit.framework in Frameworks */, E7A011AF14E1B78C00765C29 /* Foundation.framework in Frameworks */, 4C711D6D13AFCD0900FE865D /* Security.framework in Frameworks */, + D418CC701E690CAD00330A44 /* MobileAsset.framework in Frameworks */, E71F3E4216EA6A6300FAF9B4 /* SystemConfiguration.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -10346,12 +12172,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DCD22D8A1D8CCC23001C9B81 /* libSecureObjectSync.a in Frameworks */, + DCD22D8A1D8CCC23001C9B81 /* libSecureObjectSyncServer.a in Frameworks */, DCD22D891D8CCC1F001C9B81 /* libsecurityd_ios.a in Frameworks */, 5296CB521655B9B5009912AF /* libMobileGestalt.dylib in Frameworks */, 4432B1C91A024273000958DC /* libaks_acl.a in Frameworks */, 438168BE1B4ED42700C54D58 /* CoreFoundation.framework in Frameworks */, 4C9DEA451181B34C00CF5C27 /* Security.framework in Frameworks */, + DCD8A20B1E09FB5A00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, E71F3E4016EA6A1800FAF9B4 /* SystemConfiguration.framework in Frameworks */, 4C9DEAA71181B37500CF5C27 /* CFNetwork.framework in Frameworks */, ); @@ -10361,6 +12188,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 47D13F631E8447FB0063B6E2 /* SecurityFoundation.framework in Frameworks */, EB7F50C51DB8800A003D787D /* CoreCDP.framework in Frameworks */, EBE9019A1C22852C007308C6 /* AggregateDictionary.framework in Frameworks */, 438168BB1B4ED42300C54D58 /* CoreFoundation.framework in Frameworks */, @@ -10370,7 +12198,8 @@ 5296CB4F1655B92F009912AF /* libMobileGestalt.dylib in Frameworks */, 4432B0B71A014987000958DC /* libaks_acl.a in Frameworks */, DC65E7361D8CB35E00152EF0 /* libutilities.a in Frameworks */, - DCD22D861D8CCBBB001C9B81 /* libSecureObjectSync.a in Frameworks */, + DCD22D861D8CCBBB001C9B81 /* libSecureObjectSyncServer.a in Frameworks */, + DCD8A1EA1E09F87B00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DCD22D851D8CCBB6001C9B81 /* libsecurityd_ios.a in Frameworks */, 4C32C1A60A497A21002891BD /* Security.framework in Frameworks */, 4CAE95DC0F3D6E020075278E /* CFNetwork.framework in Frameworks */, @@ -10423,13 +12252,15 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DCCD34001E4001AD00AA4AD1 /* libACM.a in Frameworks */, + DCAB14271E40039600C81511 /* libASN1_not_installed.a in Frameworks */, DC59EA8E1D91CDC1001BDDF5 /* libDER_not_installed.a in Frameworks */, EBF2D73C1C1E2B47006AB6FF /* Foundation.framework in Frameworks */, DCD22D801D8CCB0F001C9B81 /* libutilities.a in Frameworks */, DC00ABCC1D821F0B00513D74 /* libsecurityd_ios.a in Frameworks */, - DC00ABCD1D821F0D00513D74 /* libSecureObjectSync.a in Frameworks */, + DC00ABCD1D821F0D00513D74 /* libSecureObjectSyncServer.a in Frameworks */, + DCD8A1E41E09F80B00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DC65E7C41D8CBC0900152EF0 /* libregressionBase.a in Frameworks */, - 4381603C1B4DCF9E00C54D58 /* CFNetwork.framework in Frameworks */, 4381603A1B4DCE8F00C54D58 /* SystemConfiguration.framework in Frameworks */, 5E43C4981B00D49700E5ECB2 /* libsqlite3.dylib in Frameworks */, 5E43C4931B00D0DB00E5ECB2 /* libcoreauthd_client.a in Frameworks */, @@ -10440,6 +12271,86 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 6C9808481E788AEB00E70590 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6C9808491E788AEB00E70590 /* libDER_not_installed.a in Frameworks */, + 6C98084A1E788AEB00E70590 /* libASN1_not_installed.a in Frameworks */, + 6C98084C1E788AEB00E70590 /* libsecurityd_ios_NO_AKS.a in Frameworks */, + 6C98084D1E788AEB00E70590 /* libSecureObjectSyncFramework.a in Frameworks */, + 6C98084E1E788AEB00E70590 /* libSecureObjectSyncServer.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.a in Frameworks */, + 6C98085B1E788AEB00E70590 /* libsqlite3.0.dylib in Frameworks */, + 6C98085C1E788AEB00E70590 /* libz.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6C9808841E788AFD00E70590 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6C9808851E788AFD00E70590 /* libDER_not_installed.a in Frameworks */, + 6C9808861E788AFD00E70590 /* libASN1_not_installed.a in Frameworks */, + 6C9808881E788AFD00E70590 /* libsecurityd_ios_NO_AKS.a in Frameworks */, + 6C9808891E788AFD00E70590 /* libSecureObjectSyncFramework.a in Frameworks */, + 6C98088A1E788AFD00E70590 /* libSecureObjectSyncServer.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.a in Frameworks */, + 6C9808971E788AFD00E70590 /* libsqlite3.0.dylib in Frameworks */, + 6C9808981E788AFD00E70590 /* libz.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6CCDF7811E3C25FA003F2555 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6CCDF78D1E3C26C2003F2555 /* Foundation.framework in Frameworks */, + 6CCDF78C1E3C26BC003F2555 /* XCTest.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6CF4A0B11E45488B00ECD7B5 /* Frameworks */ = { + 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; + }; 728B569E16D59979008FA3AB /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -10456,23 +12367,20 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EB3EBF151DBD85A600620B2C /* libobjc.dylib in Frameworks */, + D47CA65D1EB036450038E2BB /* libMobileGestalt.dylib in Frameworks */, + CD9F2AF81DF23CA600AD3577 /* Foundation.framework in Frameworks */, DC65E72A1D8CB2FC00152EF0 /* libutilities.a in Frameworks */, - EBE54D761BE32F6F000C4856 /* AggregateDictionary.framework in Frameworks */, 438168941B4ED42300C54D58 /* CoreFoundation.framework in Frameworks */, - E7D690A21652E0870079537A /* libMobileGestalt.dylib in Frameworks */, DC00AB811D821C9100513D74 /* libsecurityd_ios.a in Frameworks */, - DC00AB821D821C9500513D74 /* libSecureObjectSync.a in Frameworks */, + DC00AB821D821C9500513D74 /* libSecureObjectSyncServer.a in Frameworks */, + DCD8A1E71E09F85400E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DC00AB831D821C9A00513D74 /* libSWCAgent.a in Frameworks */, DC59EA7E1D91CCB2001BDDF5 /* libDER_not_installed.a in Frameworks */, 790851EE0CA9B3410083CC4D /* Security.framework in Frameworks */, E71F3E3116EA69A900FAF9B4 /* SystemConfiguration.framework in Frameworks */, - 4CF730320EF9CDE300E17471 /* CFNetwork.framework in Frameworks */, 4CAF66190F3A6FCD0064A534 /* IOKit.framework in Frameworks */, 4432B15E1A014D37000958DC /* libaks_acl.a in Frameworks */, 4C2215220F3A612C00835155 /* libsqlite3.dylib in Frameworks */, - BEE523DD1DACAA9800DD0AA3 /* libz.dylib in Frameworks */, - 4C70664C0DDDFED9004DA56B /* libbsm.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -10480,7 +12388,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DCD22D881D8CCBEF001C9B81 /* libSecureObjectSync.a in Frameworks */, + DCD22D881D8CCBEF001C9B81 /* libSecureObjectSyncServer.a in Frameworks */, DCD22D871D8CCBEA001C9B81 /* libsecurityd_ios.a in Frameworks */, DC00ABEC1D821FA600513D74 /* libSecurityTool.a in Frameworks */, 5296CB501655B990009912AF /* libMobileGestalt.dylib in Frameworks */, @@ -10490,6 +12398,14 @@ 7913B2080D172B3900601FE9 /* Security.framework in Frameworks */, E71F3E3E16EA69CF00FAF9B4 /* SystemConfiguration.framework in Frameworks */, 4CAE95D80F3D6DFC0075278E /* CFNetwork.framework in Frameworks */, + DCD8A20A1E09FB5900E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + ACBAF6D91E9417F40007BA2F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( ); runOnlyForDeploymentPostprocessing = 0; }; @@ -10511,6 +12427,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5EAFA4D31EF1605A002DC188 /* LocalAuthentication.framework in Frameworks */, BE442BAE18B7FDB800F24DAE /* libMobileGestalt.dylib in Frameworks */, DC00AB9A1D821D8800513D74 /* libSWCAgent.a in Frameworks */, DCD22D981D8CCF78001C9B81 /* libutilities.a in Frameworks */, @@ -10526,6 +12443,30 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BED208D71EDF950E00753952 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BED208D81EDF950E00753952 /* Security.framework in Frameworks */, + BED208D91EDF950E00753952 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BEF88C241EAFFC3F00357577 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BEF88C2D1EAFFC3F00357577 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BEF88C311EAFFC3F00357577 /* TrustedPeers.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD276C241A83F60C003226BC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -10538,6 +12479,38 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D41257CC1E9410A300781F23 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D40C2C241E94342A009D793B /* AggregateDictionary.framework in Frameworks */, + D41258011E94230400781F23 /* IOKit.framework in Frameworks */, + D41257E01E94136000781F23 /* libz.dylib in Frameworks */, + D41257DF1E94133600781F23 /* CFNetwork.framework in Frameworks */, + D41257DE1E94132900781F23 /* libsqlite3.dylib in Frameworks */, + D41257DC1E94130C00781F23 /* libDER_not_installed.a in Frameworks */, + D41257DB1E9412E700781F23 /* libutilities.a in Frameworks */, + D41257DA1E9412DC00781F23 /* libtrustd.a in Frameworks */, + D41257E21E94138600781F23 /* CoreFoundation.framework in Frameworks */, + D41257D01E9410A300781F23 /* Foundation.framework in Frameworks */, + D450686A1E948D2200FA7675 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D4ADA3161E2B41670031CEA3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DA30D6731DF8C8FB00EC6B43 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC0067BC1D87876F005AF8DB /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -10721,14 +12694,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EB3EBF101DBD413600620B2C /* libobjc.dylib in Frameworks */, + CD9F2AFB1DF24BAF00AD3577 /* Foundation.framework in Frameworks */, DCD22D4B1D8CBF54001C9B81 /* libASN1_not_installed.a in Frameworks */, DC00AB6F1D821C3400513D74 /* libSecItemShimOSX.a in Frameworks */, DC00AB701D821C3800513D74 /* libSecOtrOSX.a in Frameworks */, DC00AB6B1D821C1A00513D74 /* libSecTrustOSX.a in Frameworks */, - DC00AB6C1D821C1F00513D74 /* libSecureObjectSync.a in Frameworks */, + DCD8A1FC1E09FA0B00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DC00AB6D1D821C2300513D74 /* liblogging.a in Frameworks */, - DC00AB6E1D821C2700513D74 /* libsecipc_client.a in Frameworks */, DCC5BF1B1D93723A008D1E84 /* libsecurity_apple_csp.a in Frameworks */, DCC5BF1C1D937242008D1E84 /* libsecurity_apple_cspdl.a in Frameworks */, DCC5BF1D1D937249008D1E84 /* libsecurity_apple_file_dl.a in Frameworks */, @@ -10765,8 +12737,9 @@ DC1789171D77998700B50D50 /* libauto.dylib in Frameworks */, DC1789191D77998C00B50D50 /* libbsm.dylib in Frameworks */, DC17892A1D779A3200B50D50 /* libcoreauthd_client.a in Frameworks */, + DC3A81D61D99D57F000C7419 /* libcoretls.dylib in Frameworks */, + DC3A81D71D99D58A000C7419 /* libcoretls_cfhelpers.dylib in Frameworks */, DC1789291D779A2800B50D50 /* libctkclient.a in Frameworks */, - DC17891B1D77999200B50D50 /* libobjc.dylib in Frameworks */, DC17891D1D77999700B50D50 /* libpam.dylib in Frameworks */, DC17891F1D77999D00B50D50 /* libsqlite3.dylib in Frameworks */, DC1789211D7799A100B50D50 /* libxar.dylib in Frameworks */, @@ -10776,24 +12749,52 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - DC3A4B551D91E9FB00E46D4A /* Frameworks */ = { + DC222C631E034D1F00B09171 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DC3A4B671D91EB1200E46D4A /* CoreFoundation.framework in Frameworks */, - DC3A4B661D91EB0E00E46D4A /* Security.framework in Frameworks */, - DC3A4B651D91EB0800E46D4A /* libsecurity_utilities.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - DC52E7AD1D80BC8000B0A59C /* Frameworks */ = { + DC3502B21E0208BE00BC0587 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 47A0ABA81E6F7B24001B388C /* SecurityFoundation.framework in Frameworks */, + DC3502C81E020D5B00BC0587 /* libDER_not_installed.a in Frameworks */, + DC3502C51E020D5100BC0587 /* libASN1_not_installed.a in Frameworks */, + DC222C7A1E034EF700B09171 /* libsecurityd_ios_NO_AKS.a in Frameworks */, + DC0984FD1E1DB6DF00140ADC /* libSecureObjectSyncFramework.a in Frameworks */, + DC0984FE1E1DB70100140ADC /* libSecureObjectSyncServer.a in Frameworks */, + DC3502D61E02118000BC0587 /* libsecurity.a in Frameworks */, + DC3502CF1E020E2900BC0587 /* libutilities.a in Frameworks */, + DC222C351E02418100B09171 /* CFNetwork.framework in Frameworks */, + DC3502DF1E02129F00BC0587 /* Foundation.framework in Frameworks */, + DC3502D21E02113900BC0587 /* IOKit.framework in Frameworks */, + DC3502E91E02172C00BC0587 /* OCMock.framework in Frameworks */, + DC3502E31E0212E600BC0587 /* SystemConfiguration.framework in Frameworks */, + DC3502D31E02115200BC0587 /* libACM.a in Frameworks */, + DC0950411E38271300B2C8AC /* libaks_acl.a in Frameworks */, + DC222C361E02419B00B09171 /* libbsm.dylib in Frameworks */, + DC3502E41E02130600BC0587 /* libcoreauthd_client.a in Frameworks */, + DC3502E21E0212D100BC0587 /* libctkclient.a in Frameworks */, + DC3502CA1E020DC100BC0587 /* libsqlite3.0.dylib in Frameworks */, + DC222C321E0240D300B09171 /* libz.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DC3A4B551D91E9FB00E46D4A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DCD3EABA1DB599B800DF59BE /* IOKit.framework in Frameworks */, + DC3A4B671D91EB1200E46D4A /* CoreFoundation.framework in Frameworks */, + DC3A4B661D91EB0E00E46D4A /* Security.framework in Frameworks */, + DC3A4B651D91EB0800E46D4A /* libsecurity_utilities.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - DC52E8AB1D80C1EB00B0A59C /* Frameworks */ = { + DC52E7AD1D80BC8000B0A59C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( @@ -10849,9 +12850,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 7281E0971DFD0FD00021E1B7 /* Foundation.framework in Frameworks */, DC52EC6C1D80D0E800B0A59C /* IDS.framework in Frameworks */, DC52EC6B1D80D0E300B0A59C /* IDSFoundation.framework in Frameworks */, - DC52EC691D80D0DD00B0A59C /* libSecureObjectSync.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -10874,6 +12875,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 7281E0881DFD06480021E1B7 /* Foundation.framework in Frameworks */, DC52EDB21D80D59700B0A59C /* IDSFoundation.framework in Frameworks */, DC52EDAC1D80D58400B0A59C /* IDS.framework in Frameworks */, ); @@ -10966,12 +12968,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CD9F2AFA1DF249CF00AD3577 /* Foundation.framework in Frameworks */, + EBF3745F1DBFB32A0065D840 /* libobjc.dylib in Frameworks */, DC5AC0D61D83548300CF422C /* libDiagnosticMessagesClient.dylib in Frameworks */, DC5AC0D41D83547A00CF422C /* libsecuritydservice_client.a in Frameworks */, DC5AC0D31D83544D00CF422C /* libsqlite3.dylib in Frameworks */, BEE523DC1DACAA9200DD0AA3 /* libz.dylib in Frameworks */, DC5AC0D21D83544800CF422C /* libauto.dylib in Frameworks */, - DC5AC0D11D83544200CF422C /* libobjc.dylib in Frameworks */, DC1002AF1D8E18870025549C /* libsecurity_codesigning.a in Frameworks */, DCB7D8D11D8E185900867385 /* libsecurity_utilities.a in Frameworks */, DCD22D6C1D8CC6FD001C9B81 /* libsecurityd_client.a in Frameworks */, @@ -10993,6 +12996,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 47B90C901F350966006500BC /* CrashReporterSupport.framework in Frameworks */, + 474B5FC81E662E79007546F8 /* SecurityFoundation.framework in Frameworks */, + D43B88721E72298500F86F19 /* MobileAsset.framework in Frameworks */, + DC4EA5961E70A237008840B4 /* libsecurity.a in Frameworks */, + 6C5B36BA1E2F9B95008AD443 /* WirelessDiagnostics.framework in Frameworks */, DC610A3D1D78F25C002223DE /* libDiagnosticMessagesClient.dylib in Frameworks */, DC610A3B1D78F234002223DE /* libACM.a in Frameworks */, DC610A391D78F1B7002223DE /* libaks.a in Frameworks */, @@ -11006,18 +13014,20 @@ BEE523D91DACAA2500DD0AA3 /* libz.dylib in Frameworks */, DC65E7C31D8CBBA200152EF0 /* libregressionBase.a in Frameworks */, DC00ABE61D821F7700513D74 /* libsecdRegressions.a in Frameworks */, - DC00ABE51D821F7200513D74 /* libsecipc_client.a in Frameworks */, - DCD22D621D8CC326001C9B81 /* libSecItemShimOSX.a in Frameworks */, - DC00ABE91D821F8000513D74 /* libSecureObjectSync.a in Frameworks */, - DC00ABE71D821F7A00513D74 /* libsecurity.a in Frameworks */, + DCD8A1F01E09F8D100E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, + DC00ABE91D821F8000513D74 /* libSecureObjectSyncServer.a in Frameworks */, DC00ABE81D821F7D00513D74 /* libsecurityd_ios.a in Frameworks */, + D40B6A901E2B673500CD6EE5 /* libtrustd.a in Frameworks */, DCD22D631D8CC33A001C9B81 /* libSOSRegressions.a in Frameworks */, DCD22D641D8CC341001C9B81 /* libutilities.a in Frameworks */, DCD22D651D8CC349001C9B81 /* libutilitiesRegressions.a in Frameworks */, + DCDCCB3A1DF25D1D006E840E /* ApplePushService.framework in Frameworks */, DC610A281D78F129002223DE /* CFNetwork.framework in Frameworks */, + DCDCCB391DF25D18006E840E /* CloudKit.framework in Frameworks */, DC610A1D1D78F129002223DE /* CoreFoundation.framework in Frameworks */, DC610A1E1D78F129002223DE /* Foundation.framework in Frameworks */, DCD22D6A1D8CC601001C9B81 /* SystemConfiguration.framework in Frameworks */, + DC4DB1691E26E99E00CD6769 /* ProtocolBuffer.framework in Frameworks */, DCD22D6B1D8CC685001C9B81 /* AppleSystemInfo.framework in Frameworks */, DC610A291D78F129002223DE /* IOKit.framework in Frameworks */, DC610A271D78F129002223DE /* Security.framework in Frameworks */, @@ -11180,10 +13190,18 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCD8A1541E09EE0F00E4FA0A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; DCE4E6941D7A37FA00AFB96E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 6C1F93111DD5E41A00585608 /* libDiagnosticMessagesClient.dylib in Frameworks */, EB7F50CC1DB88A03003D787D /* CoreCDP.framework in Frameworks */, DCE4E6AE1D7A3C6A00AFB96E /* AppleSystemInfo.framework in Frameworks */, DCE4E6AD1D7A3B9700AFB96E /* libaks.a in Frameworks */, @@ -11191,19 +13209,22 @@ DCE4E6AB1D7A3B0800AFB96E /* libbsm.dylib in Frameworks */, DCE4E6961D7A37FA00AFB96E /* CoreFoundation.framework in Frameworks */, DC65E7BD1D8CBA6C00152EF0 /* libsecurityd_ios.a in Frameworks */, - DC65E7781D8CB8A500152EF0 /* libSecureObjectSync.a in Frameworks */, + DC65E7781D8CB8A500152EF0 /* libSecureObjectSyncServer.a in Frameworks */, DC00AB971D821D7100513D74 /* libSOSCommands.a in Frameworks */, DC00AB981D821D7400513D74 /* libSecurityTool.a in Frameworks */, DC00AB991D821D7700513D74 /* libSecurityCommands.a in Frameworks */, DC65E7371D8CB37500152EF0 /* libutilities.a in Frameworks */, DC65E77A1D8CB8D200152EF0 /* libsqlite3.dylib in Frameworks */, DCE4E69B1D7A37FA00AFB96E /* libaks_acl.a in Frameworks */, + DCDCCB381DF25CEE006E840E /* ApplePushService.framework in Frameworks */, + DCDCCB371DF25CE5006E840E /* CloudKit.framework in Frameworks */, DCBB8AC41D80DD95007ED154 /* Security.framework in Frameworks */, DCE4E69E1D7A37FA00AFB96E /* CFNetwork.framework in Frameworks */, DCE4E69F1D7A37FA00AFB96E /* SystemConfiguration.framework in Frameworks */, DCE4E6A01D7A37FA00AFB96E /* Foundation.framework in Frameworks */, DC65E77B1D8CB8E800152EF0 /* IOKit.framework in Frameworks */, DC65E77C1D8CB8F100152EF0 /* MobileKeyBag.framework in Frameworks */, + DCD8A2011E09FAD900E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -11211,6 +13232,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DC3A81EC1D99F568000C7419 /* libcoretls.dylib in Frameworks */, DCE4E7C61D7A468300AFB96E /* libaks.a in Frameworks */, DCE4E75E1D7A43B500AFB96E /* CoreFoundation.framework in Frameworks */, DCE4E7BF1D7A463400AFB96E /* Security.framework in Frameworks */, @@ -11224,6 +13246,7 @@ DC63CAF81D91A15F00C03317 /* libsecurity_cms_regressions.a in Frameworks */, DCE4E7C41D7A465500AFB96E /* libsecurity_smime_regressions.a in Frameworks */, DCD22D571D8CC196001C9B81 /* libsecurity_ssl_regressions.a in Frameworks */, + ACBAF6FC1E941B620007BA2F /* libsecurity_transform_regressions.a in Frameworks */, DCD22D561D8CC154001C9B81 /* libutilities.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -11244,6 +13267,7 @@ DCE4E7E81D7A4BA400AFB96E /* libsecurity_smime_regressions.a in Frameworks */, DC0B622A1D9097C600D43BCB /* libsecurity_cms_regressions.a in Frameworks */, DCE4E7E71D7A4B9C00AFB96E /* IOKit.framework in Frameworks */, + DCDCC8331D9B6A00006487E8 /* libcoretls.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -11251,29 +13275,32 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EB3EBF131DBD417A00620B2C /* libobjc.dylib in Frameworks */, + 4710A6D91F34F21700745267 /* CrashReporterSupport.framework in Frameworks */, + D41D36711EB14D87007FA978 /* libDiagnosticMessagesClient.tbd in Frameworks */, + 474B5FC61E662E48007546F8 /* SecurityFoundation.framework in Frameworks */, + 6C5B36C01E2F9BEA008AD443 /* WirelessDiagnostics.framework in Frameworks */, + CD9F2AF91DF249B400AD3577 /* Foundation.framework in Frameworks */, DCE4E8281D7A4F1600AFB96E /* login.framework in Frameworks */, - DCE4E8261D7A4EEC00AFB96E /* libDiagnosticMessagesClient.dylib in Frameworks */, DCE4E8251D7A4EE400AFB96E /* libACM.a in Frameworks */, DCE4E8241D7A4ECD00AFB96E /* libaks.a in Frameworks */, DCE4E8231D7A4EC900AFB96E /* libaks_acl.a in Frameworks */, DCD22D711D8CC78E001C9B81 /* libASN1_not_installed.a in Frameworks */, DC59EA7B1D91CC9F001BDDF5 /* libDER_not_installed.a in Frameworks */, - DCE4E8211D7A4EB800AFB96E /* libbsm.dylib in Frameworks */, DCE4E8201D7A4EAC00AFB96E /* libcoreauthd_client.a in Frameworks */, DCE4E81F1D7A4EA700AFB96E /* libctkclient.a in Frameworks */, DCE4E81C1D7A4E8F00AFB96E /* libsqlite3.0.dylib in Frameworks */, - BEE523DA1DACAA5700DD0AA3 /* libz.dylib in Frameworks */, - DC00AB791D821C6700513D74 /* libsecipc_client.a in Frameworks */, - DC00AB7A1D821C6B00513D74 /* libSecureObjectSync.a in Frameworks */, + DCD8A2041E09FB0D00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, + DC00AB7A1D821C6B00513D74 /* libSecureObjectSyncServer.a in Frameworks */, DC00AB7B1D821C6E00513D74 /* libsecurity.a in Frameworks */, DC65E7271D8CB2EC00152EF0 /* libutilities.a in Frameworks */, DC00AB7C1D821C7100513D74 /* libsecurityd_ios.a in Frameworks */, - DCE4E8151D7A4E6F00AFB96E /* CFNetwork.framework in Frameworks */, DCE4E8131D7A4E5300AFB96E /* CoreFoundation.framework in Frameworks */, DCE4E8121D7A4E4F00AFB96E /* IOKit.framework in Frameworks */, + DCDCCB3C1DF25D74006E840E /* ApplePushService.framework in Frameworks */, + DCDCCB3B1DF25D69006E840E /* CloudKit.framework in Frameworks */, DCD22D721D8CC804001C9B81 /* SystemConfiguration.framework in Frameworks */, DCE4E80F1D7A4E4600AFB96E /* Security.framework in Frameworks */, + DC4DB16A1E26E9F900CD6769 /* ProtocolBuffer.framework in Frameworks */, DCE4E82C1D7A56FF00AFB96E /* AppleSystemInfo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -11282,31 +13309,20 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EB3EBF141DBD41BD00620B2C /* libobjc.dylib in Frameworks */, - 8EECC6601DAC699900972D50 /* MobileKeyBag.framework in Frameworks */, - DCE4E83B1D7A57AE00AFB96E /* login.framework in Frameworks */, - DC00AB8B1D821CBE00513D74 /* libSecureObjectSync.a in Frameworks */, - DCE4E83C1D7A57AE00AFB96E /* libDiagnosticMessagesClient.dylib in Frameworks */, - DCE4E83D1D7A57AE00AFB96E /* libACM.a in Frameworks */, - DCE4E8421D7A57AE00AFB96E /* libcoreauthd_client.a in Frameworks */, - DCE4E83E1D7A57AE00AFB96E /* libaks.a in Frameworks */, - DCD22D731D8CC828001C9B81 /* SystemConfiguration.framework in Frameworks */, - DC84E0BC1D9B2B6A004C57F7 /* libsecurity_utilities.a in Frameworks */, - DC65E72D1D8CB31B00152EF0 /* libutilities.a in Frameworks */, - DCE4E83F1D7A57AE00AFB96E /* libaks_acl.a in Frameworks */, - DCD22D741D8CC85E001C9B81 /* libASN1_not_installed.a in Frameworks */, - DC59EA7F1D91CCCA001BDDF5 /* libDER_not_installed.a in Frameworks */, - DCE4E84E1D7A57AE00AFB96E /* IOKit.framework in Frameworks */, - DCE4E8411D7A57AE00AFB96E /* libbsm.dylib in Frameworks */, - DC84E0BD1D9B2B8C004C57F7 /* libsqlite3.dylib in Frameworks */, - BEE523DB1DACAA8C00DD0AA3 /* libz.dylib in Frameworks */, - DC00AB8D1D821CC500513D74 /* libsecurityd_ios.a in Frameworks */, - DC00AB8A1D821CB800513D74 /* libsecipc_client.a in Frameworks */, - DCE4E8431D7A57AE00AFB96E /* libctkclient.a in Frameworks */, - DCE4E84C1D7A57AE00AFB96E /* CFNetwork.framework in Frameworks */, - DCE4E84D1D7A57AE00AFB96E /* CoreFoundation.framework in Frameworks */, - DCE4E8501D7A57AE00AFB96E /* Security.framework in Frameworks */, - DCE4E8511D7A57AE00AFB96E /* AppleSystemInfo.framework in Frameworks */, + D40B6A9A1E2B68E800CD6EE5 /* libbsm.dylib in Frameworks */, + D40B6A991E2B68A400CD6EE5 /* libz.dylib in Frameworks */, + D40B6A981E2B687F00CD6EE5 /* libDiagnosticMessagesClient.dylib in Frameworks */, + D40B6A971E2B684900CD6EE5 /* libsqlite3.0.dylib in Frameworks */, + D40B6A9E1E2B6A6F00CD6EE5 /* libtrustd.a in Frameworks */, + D40B6A931E2B67E500CD6EE5 /* libutilities.a in Frameworks */, + D40B6A831E2B5F5B00CD6EE5 /* libASN1_not_installed.a in Frameworks */, + D40B6A821E2B5F5600CD6EE5 /* libDER_not_installed.a in Frameworks */, + D40B6A9D1E2B6A2700CD6EE5 /* login.framework in Frameworks */, + D4ADA3311E2B43450031CEA3 /* CFNetwork.framework in Frameworks */, + D4ADA3301E2B433B0031CEA3 /* Security.framework in Frameworks */, + D4ADA32E1E2B43220031CEA3 /* CoreFoundation.framework in Frameworks */, + D4ADA32F1E2B43220031CEA3 /* Foundation.framework in Frameworks */, + D4C7CD661E71E92D00139817 /* MobileAsset.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -11319,6 +13335,7 @@ DCE4E8C71D7F355900AFB96E /* Security.framework in Frameworks */, DCE4E8C61D7F354700AFB96E /* CoreFoundation.framework in Frameworks */, DCE4E8C51D7F354300AFB96E /* IOKit.framework in Frameworks */, + F6AF96681E646CAF00917214 /* libcoreauthd_client.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -11337,12 +13354,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CD31F89E1DCE86D600414B46 /* Accounts.framework in Frameworks */, - DCE4E93F1D7F3E4000AFB96E /* AOSAccounts.framework in Frameworks */, - DCE4E93C1D7F3E0C00AFB96E /* AOSUI.framework in Frameworks */, + CD112FC51DDA31AD00C77A07 /* Accounts.framework in Frameworks */, 0CC319241DA46FBF005D42EA /* ProtectedCloudStorage.framework in Frameworks */, DCE4E9401D7F3E4D00AFB96E /* Security.framework in Frameworks */, + DCE4E93F1D7F3E4000AFB96E /* AOSAccounts.framework in Frameworks */, DCE4E93D1D7F3E1600AFB96E /* AppleSystemInfo.framework in Frameworks */, + DCE4E93C1D7F3E0C00AFB96E /* AOSUI.framework in Frameworks */, DCE4E93A1D7F3DF500AFB96E /* CrashReporterSupport.framework in Frameworks */, DCE4E9381D7F3DB500AFB96E /* Cocoa.framework in Frameworks */, DCE4E9371D7F3DAF00AFB96E /* CloudServices.framework in Frameworks */, @@ -11403,6 +13420,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D40B6A8F1E2B643D00CD6EE5 /* libtrustd.a in Frameworks */, DC00ABC01D821EBE00513D74 /* libSharedRegressions.a in Frameworks */, EBE9019B1C2285D4007308C6 /* AggregateDictionary.framework in Frameworks */, E7A011AE14E1B78800765C29 /* Foundation.framework in Frameworks */, @@ -11410,7 +13428,8 @@ DCD22D921D8CCD09001C9B81 /* libsecurity_ssl_regressions.a in Frameworks */, DC65E7761D8CB81A00152EF0 /* libregressionBase.a in Frameworks */, DC00ABC11D821EC300513D74 /* libsecurityd_ios.a in Frameworks */, - DC00ABC21D821EC600513D74 /* libSecureObjectSync.a in Frameworks */, + DC00ABC21D821EC600513D74 /* libSecureObjectSyncServer.a in Frameworks */, + DCD8A1F31E09F91700E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DC59EA881D91CD7E001BDDF5 /* libDER_not_installed.a in Frameworks */, DCD22D931D8CCD17001C9B81 /* libASN1_not_installed.a in Frameworks */, DCD22D941D8CCDFA001C9B81 /* libutilities.a in Frameworks */, @@ -11428,6 +13447,7 @@ E7FEEEFA1332B8210025EB06 /* CFNetwork.framework in Frameworks */, E7FEEEFB1332B8300025EB06 /* IOKit.framework in Frameworks */, E71F3E4116EA6A5100FAF9B4 /* SystemConfiguration.framework in Frameworks */, + D418CC711E690CBC00330A44 /* MobileAsset.framework in Frameworks */, 0CFC029C1D41650700E6283B /* libcoretls.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -11444,9 +13464,10 @@ E7B01BD6166594AB000485F1 /* libMobileGestalt.dylib in Frameworks */, DC00ABF11D821FC400513D74 /* libsecurityd_ios.a in Frameworks */, DC00ABF21D821FC800513D74 /* libSOSRegressions.a in Frameworks */, - DC00ABF31D821FCD00513D74 /* libSecureObjectSync.a in Frameworks */, + DC00ABF31D821FCD00513D74 /* libSecureObjectSyncServer.a in Frameworks */, 438168C31B4ED43200C54D58 /* CoreFoundation.framework in Frameworks */, E7B01BDE166594AB000485F1 /* UIKit.framework in Frameworks */, + DCD8A20C1E09FB6600E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, E7B01BDF166594AB000485F1 /* Foundation.framework in Frameworks */, E7B01BE0166594AB000485F1 /* CoreGraphics.framework in Frameworks */, ); @@ -11456,6 +13477,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EB59D6731E95F01600997EAC /* libcompression.dylib in Frameworks */, DC65E7231D8CB28900152EF0 /* libutilities.a in Frameworks */, E7D8489F1C6C244B0025BB44 /* Foundation.framework in Frameworks */, E7650E6F1C7699DA00378669 /* Security.framework in Frameworks */, @@ -11470,15 +13492,14 @@ EB2CA4DA1D2C28F100AB770F /* libaks_acl.a in Frameworks */, E7DC73B71C890F0E0008BF73 /* KeychainCircle.framework in Frameworks */, E7D848561C6C1E830025BB44 /* Foundation.framework in Frameworks */, + DCDCCB361DF25C8D006E840E /* ApplePushService.framework in Frameworks */, E7F482E61C7640D300390FDB /* IOKit.framework in Frameworks */, DC00ABA51D821DCD00513D74 /* libsecurity.a in Frameworks */, - DC00ABA61D821DD000513D74 /* libsecurityd_ios.a in Frameworks */, - DC00ABA71D821DD300513D74 /* libSecureObjectSync.a in Frameworks */, + DCD8A1F61E09F96900E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */, DCD22D541D8CC0FC001C9B81 /* libutilities.a in Frameworks */, DC59EA821D91CD24001BDDF5 /* libDER_not_installed.a in Frameworks */, DCD22D531D8CC0EF001C9B81 /* libASN1_not_installed.a in Frameworks */, E7F482A11C7543E500390FDB /* libsqlite3.dylib in Frameworks */, - DC00ABA81D821DD900513D74 /* libsecipc_client.a in Frameworks */, E7F482A31C7544E600390FDB /* libctkclient_test.a in Frameworks */, E7F482A61C75453900390FDB /* libcoreauthd_test_client.a in Frameworks */, ); @@ -11492,6 +13513,54 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EB1055721E14DF430003C309 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EB10559F1E14E3A80003C309 /* Security.framework in Frameworks */, + EB10559E1E14E39D0003C309 /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB108F2B1E6CE4D2003B0456 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EB58A0511E74BF07009C10D7 /* Security.framework in Frameworks */, + EB75B4871E75400200E469CC /* libaks_acl.a in Frameworks */, + EB75B4821E753EAA00E469CC /* KeychainCircle.framework in Frameworks */, + EBA689031E74732700FF90A7 /* Foundation.framework in Frameworks */, + EB75B4881E75401700E469CC /* ApplePushService.framework in Frameworks */, + EB75B4891E75402400E469CC /* IOKit.framework in Frameworks */, + EB75B48A1E75405100E469CC /* libsecurity.a in Frameworks */, + EB75B48C1E75407C00E469CC /* libutilities.a in Frameworks */, + EB75B48E1E75408C00E469CC /* libDER_not_installed.a in Frameworks */, + EB75B48D1E75408900E469CC /* libASN1_not_installed.a in Frameworks */, + EB75B48F1E75409A00E469CC /* libsqlite3.dylib in Frameworks */, + EB75B4901E7540AA00E469CC /* libctkclient_test.a in Frameworks */, + EB75B4911E7540BF00E469CC /* libcoreauthd_test_client.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB27FF0E1E402CD300EC9E3A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EB27FF311E408DC700EC9E3A /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB2D54A41F02A45E00E46890 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EBFF18CC1F02A6AE004E58FC /* libsecurity_cdsa_utilities.a in Frameworks */, + EBFF18CB1F02A68B004E58FC /* CoreFoundation.framework in Frameworks */, + EBFF18CA1F02A677004E58FC /* libsecurity_utilities.a in Frameworks */, + EBFF18C41F02A4EF004E58FC /* libsecurity_filedb.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; EB425CA11C65846D000ECE53 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -11527,6 +13596,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EBB839A21E29665D00853BAC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EBB839B11E2968B400853BAC /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; EBCF73F61CE45F9C00BED7CA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -11545,6 +13622,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F621D04E1ED6DCE7000EA569 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F667EC591E96E9B100203D5C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F667EC631E96EDC500203D5C /* libregressionBase.a in Frameworks */, + F667EC5A1E96E9B100203D5C /* Security.framework in Frameworks */, + F667EC5B1E96E9B100203D5C /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -11599,6 +13693,66 @@ path = SOSCCAuthPlugin; sourceTree = ""; }; + 470415D01E5E14B6001F3D95 /* seckeychainnetworkextensionstest */ = { + isa = PBXGroup; + children = ( + 470415DD1E5E15B3001F3D95 /* seckeychainnetworkextensionstest.entitlements */, + 470415DB1E5E1534001F3D95 /* main.m */, + ); + name = seckeychainnetworkextensionstest; + sourceTree = ""; + }; + 4723C9B51F152E8E0082882F /* Analytics */ = { + isa = PBXGroup; + children = ( + 4723C9BB1F152E9E0082882F /* SQLite */, + 4723C9DA1F1540CE0082882F /* SFAnalyticsLogger.h */, + 4723C9DB1F1540CE0082882F /* SFAnalyticsLogger.m */, + 475F371F1EE8F23900248FB5 /* SFAnalyticsLogging.plist */, + ); + path = Analytics; + sourceTree = ""; + }; + 4723C9BB1F152E9E0082882F /* SQLite */ = { + isa = PBXGroup; + children = ( + 4723C9C01F152EB10082882F /* SFObjCType.h */, + 4723C9BE1F152EB10082882F /* SFObjCType.m */, + 4723C9BD1F152EB10082882F /* SFSQLite.h */, + 4723C9BC1F152EB10082882F /* SFSQLite.m */, + 4723C9C11F152EB10082882F /* SFSQLiteStatement.h */, + 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */, + ); + path = SQLite; + sourceTree = ""; + }; + 47702B1F1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */ = { + isa = PBXGroup; + children = ( + 47702B271E5F412500B29577 /* seckeychainnetworkextensionsystemdaemontest.entitlements */, + 47702B261E5F412500B29577 /* main.m */, + ); + name = seckeychainnetworkextensionsystemdaemontest; + sourceTree = ""; + }; + 47702B2F1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */ = { + isa = PBXGroup; + children = ( + 47702B381E5F499A00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest.entitlements */, + 47702B351E5F495C00B29577 /* main.m */, + ); + name = seckeychainnetworkextensionunauthorizedaccesstest; + sourceTree = ""; + }; + 47C51B851EEA657D0032D9E5 /* SecurityUnitTests */ = { + isa = PBXGroup; + children = ( + 47C51B861EEA657D0032D9E5 /* SecurityUnitTests.m */, + 47C51B881EEA657D0032D9E5 /* Info.plist */, + ); + path = SecurityUnitTests; + sourceTree = ""; + }; 4814D86C1CAA064F002FFC36 /* os_log */ = { isa = PBXGroup; children = ( @@ -11624,6 +13778,7 @@ 4C35DB67094F906D002917C4 = { isa = PBXGroup; children = ( + DC6D2C941DD3B20400BE372D /* keychain */, DC5AC2021D83668700CF422C /* Security.framework */, DC5AC1FD1D83647300CF422C /* SecureObjectSync */, DCE4E8A01D7F352600AFB96E /* authd */, @@ -11692,8 +13847,7 @@ DCE4E9111D7F3D5300AFB96E /* Keychain Circle Notification.app */, DCC78EA91D8088E200865A7C /* libsecurity.a */, DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */, - DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */, - DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */, + DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */, DC52EA4C1D80CB7000B0A59C /* libSecurityTool.a */, DC52EBD51D80CEF100B0A59C /* libSecurityCommands.a */, DC52EC341D80CFB200B0A59C /* libSOSCommands.a */, @@ -11762,6 +13916,33 @@ DC71D9DF1D95BA6C0065FB93 /* libASN1.a */, DC71D9FB1D95BB0A0065FB93 /* libDER.a */, EBF374721DC055580065D840 /* security-sysdiagnose */, + DA30D6761DF8C8FB00EC6B43 /* KeychainSyncAccountUpdater.bundle */, + DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */, + EB1055751E14DF430003C309 /* libSecCertificateFuzzer.dylib */, + DC3502B51E0208BE00BC0587 /* CKKSTests.xctest */, + DC222C771E034D1F00B09171 /* libsecurityd_ios_NO_AKS.a */, + EBB839A51E29665D00853BAC /* secfuzzer */, + 225394B41E3080A600D3CD9B /* libsecurity_codesigning_ios.a */, + D4ADA3191E2B41670031CEA3 /* libtrustd.a */, + 6CCDF7841E3C25FA003F2555 /* KeychainEntitledTestRunner */, + 6CF4A0B41E45488B00ECD7B5 /* KeychainEntitledTestApp.app */, + 6CF4A0E01E4549F200ECD7B5 /* KeychainEntitledTestApp.app */, + EB27FF111E402CD300EC9E3A /* ckksctl */, + 470415CF1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */, + 47702B1E1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */, + 47702B2E1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */, + EB108F411E6CE4D2003B0456 /* KCPairingTests.xctest */, + F667EC601E96E9B100203D5C /* authdtest */, + D41257CF1E9410A300781F23 /* trustd */, + 6C9808611E788AEB00E70590 /* CKKSCloudKitTests.xctest */, + 6C98089D1E788AFD00E70590 /* CKKSCloudKitTests.xctest */, + ACBAF6DD1E9417F40007BA2F /* libsecurity_transform_regressions.a */, + BEF88C281EAFFC3F00357577 /* TrustedPeers.framework */, + BEF88C301EAFFC3F00357577 /* TrustedPeersTests.xctest */, + F621D07F1ED6DCE7000EA569 /* authorizationdump */, + BED208DD1EDF950E00753952 /* manifeststresstest */, + 47C51B841EEA657D0032D9E5 /* SecurityUnitTests.xctest */, + EB2D54AA1F02A45E00E46890 /* secatomicfile */, ); name = Products; sourceTree = ""; @@ -11827,6 +14008,7 @@ 4C8BC620097DBC1B00C781D5 /* Libraries */ = { isa = PBXGroup; children = ( + DC5BCC401E5380AD00649140 /* src */, DC5AC0CD1D83542700CF422C /* libsecurity_tokend_client.a */, DC610A3A1D78F228002223DE /* libACM.a */, 4CA692640DA4027F001094C2 /* libCMS.a */, @@ -11864,6 +14046,7 @@ 4C6416D40BB34F00001C83FD /* SecPolicyPriv.h */, 4C2F81D40BF121D2003C4F77 /* SecRandom.h */, 107226D10D91DB32003CF14F /* SecTask.h */, + DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */, 4C8FD03E099D5C91006867B6 /* SecTrust.h */, 4C87F3A70D611C26000E7104 /* SecTrustPriv.h */, 4C4296300BB0A68200491999 /* SecTrustSettings.h */, @@ -11972,6 +14155,93 @@ path = secacltests; sourceTree = ""; }; + 6C34464D1E2534C200F9522B /* Analytics */ = { + isa = PBXGroup; + children = ( + 6C34464E1E2534D200F9522B /* AWD */, + EBB407AF1EBA433A00A541A5 /* CKKSPowerCollection.h */, + EBB407B01EBA433A00A541A5 /* CKKSPowerCollection.m */, + 479108B51EE879F9008CEFA0 /* CKKSAnalyticsLogger.h */, + 479108B61EE879F9008CEFA0 /* CKKSAnalyticsLogger.m */, + ); + name = Analytics; + sourceTree = ""; + }; + 6C34464E1E2534D200F9522B /* AWD */ = { + isa = PBXGroup; + children = ( + 6CD8D3B11EB22114009AC7DC /* AWDKeychainSecDbMarkedCorrupt.h */, + 6CD8D3B21EB22114009AC7DC /* AWDKeychainSecDbMarkedCorrupt.m */, + 6C34464F1E2534E800F9522B /* AWDKeychainCKKSRateLimiterAggregatedScores.h */, + 6C3446501E2534E800F9522B /* AWDKeychainCKKSRateLimiterAggregatedScores.m */, + 6C3446511E2534E800F9522B /* AWDKeychainCKKSRateLimiterOverload.h */, + 6C3446521E2534E800F9522B /* AWDKeychainCKKSRateLimiterOverload.m */, + 6C3446531E2534E800F9522B /* AWDKeychainCKKSRateLimiterTopWriters.h */, + 6C3446541E2534E800F9522B /* AWDKeychainCKKSRateLimiterTopWriters.m */, + 6C3446551E2534E800F9522B /* AwdMetadata-0x60-Keychain.bin */, + 6C3446561E2534E800F9522B /* AWDMetricIds_Keychain.h */, + ); + name = AWD; + sourceTree = ""; + }; + 6CB5F4771E402D6D00DBF3F0 /* testrunner */ = { + isa = PBXGroup; + children = ( + 6CB5F4791E402E5700DBF3F0 /* KeychainEntitledTestRunner-Entitlements.plist */, + 6CB5F47A1E402E5700DBF3F0 /* KeychainEntitledTestRunner.m */, + ); + path = testrunner; + sourceTree = ""; + }; + 6CF4A0B51E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */ = { + isa = PBXGroup; + children = ( + 6CF4A0B61E45488B00ECD7B5 /* AppDelegate.h */, + 6CF4A0B71E45488B00ECD7B5 /* AppDelegate.m */, + 6CF4A0BC1E45488B00ECD7B5 /* ViewController.h */, + 6CF4A0BD1E45488B00ECD7B5 /* ViewController.m */, + 6CF4A0BF1E45488B00ECD7B5 /* Assets.xcassets */, + 6CF4A0C11E45488B00ECD7B5 /* Main.storyboard */, + 6CF4A0C41E45488B00ECD7B5 /* Info.plist */, + 6CF4A0B91E45488B00ECD7B5 /* Supporting Files */, + ); + name = KeychainEntitledTestApp_mac; + path = ../../../KeychainEntitledTestApp_mac; + sourceTree = ""; + }; + 6CF4A0B91E45488B00ECD7B5 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 6CF4A0BA1E45488B00ECD7B5 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 6CF4A0E11E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */ = { + isa = PBXGroup; + children = ( + 6CF4A0E51E4549F200ECD7B5 /* AppDelegate.h */, + 6CF4A0E61E4549F300ECD7B5 /* AppDelegate.m */, + 6CF4A0E81E4549F300ECD7B5 /* ViewController.h */, + 6CF4A0E91E4549F300ECD7B5 /* ViewController.m */, + 6CF4A0EB1E4549F300ECD7B5 /* Main.storyboard */, + 6CF4A0EE1E4549F300ECD7B5 /* Assets.xcassets */, + 6CF4A0F01E4549F300ECD7B5 /* LaunchScreen.storyboard */, + 6CF4A0F31E4549F300ECD7B5 /* Info.plist */, + 6CF4A0E21E4549F200ECD7B5 /* Supporting Files */, + ); + name = KeychainEntitledTestApp_ios; + path = ../../../KeychainEntitledTestApp_ios; + sourceTree = ""; + }; + 6CF4A0E21E4549F200ECD7B5 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 6CF4A0E31E4549F200ECD7B5 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; 728B56A316D59979008FA3AB /* OTAPKIAssetTool */ = { isa = PBXGroup; children = ( @@ -11998,7 +14268,18 @@ children = ( 790850820CA87CF00083CC4D /* securityd_client.h */, 7908507F0CA87CF00083CC4D /* client.c */, + DC844AEC1E81F315007AAB71 /* client_endpoint.m */, 790850840CA87CF00083CC4D /* server.c */, + DCB2215B1E8B098D001598BC /* server_endpoint.h */, + DC6ACC401E81DF9400125DC5 /* server_endpoint.m */, + DCB2214A1E8B0861001598BC /* server_xpc.m */, + 6C1520CD1DCCF57A00C85C6D /* secd.8 */, + DC4269061E82FBDF002B7110 /* server_security_helpers.c */, + DC4269071E82FBDF002B7110 /* server_security_helpers.h */, + DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */, + DC5F35A51EE0F1A900900966 /* server_entitlement_helpers.h */, + 476541631F339F6300413F65 /* SecdWatchdog.h */, + 476541641F339F6300413F65 /* SecdWatchdog.m */, ); name = ipc; path = ../ipc; @@ -12015,6 +14296,15 @@ path = DigicertMalaysia; sourceTree = ""; }; + ACBAF6DF1E941A800007BA2F /* regressions */ = { + isa = PBXGroup; + children = ( + ACBAF6E31E941AE00007BA2F /* transform_regressions.h */, + ACBAF6E51E941AE00007BA2F /* transform-01-sigverify.m */, + ); + name = regressions; + sourceTree = ""; + }; BE197F2719116FD100BA91D1 /* SharedWebCredentialViewService */ = { isa = PBXGroup; children = ( @@ -12039,14 +14329,107 @@ name = "Supporting Files"; sourceTree = ""; }; - BE6D96B31DB14B65001B76D4 /* si-84-sectrust-allowlist */ = { + BED208E31EDF95BB00753952 /* manifeststresstest */ = { + isa = PBXGroup; + children = ( + BED208E61EDF971600753952 /* manifeststresstest.entitlements */, + BED208E71EDF971600753952 /* manifeststresstest.m */, + BE22FC031EE23DA600893431 /* mark.h */, + BE22FBFC1EE23D9100893431 /* mark.m */, + BE22FBCF1EE2084100893431 /* Config.h */, + BE22FBD01EE2084100893431 /* Config.m */, + BE22FBC41EE0E8AB00893431 /* Monkey.h */, + BE22FBC51EE0E8AB00893431 /* Monkey.m */, + BE22FBCC1EE1E26600893431 /* Keychain.h */, + BE22FBCD1EE1E26600893431 /* Keychain.m */, + ); + name = manifeststresstest; + sourceTree = ""; + }; + BEF88C451EAFFFED00357577 /* TrustedPeers */ = { + isa = PBXGroup; + children = ( + BEF88C641EB0005F00357577 /* TrustedPeers.h */, + BEF88C481EB0005E00357577 /* TPCategoryRule.h */, + BEF88C491EB0005E00357577 /* TPCategoryRule.m */, + BEF88C4A1EB0005E00357577 /* TPCircle.h */, + BEF88C4B1EB0005E00357577 /* TPCircle.m */, + BEF88C4C1EB0005E00357577 /* TPDecrypter.h */, + BEF88C4D1EB0005E00357577 /* TPEncrypter.h */, + BEF88C4E1EB0005E00357577 /* TPHash.h */, + BEF88C4F1EB0005E00357577 /* TPHash.m */, + BEF88C501EB0005E00357577 /* TPModel.h */, + BEF88C511EB0005E00357577 /* TPModel.m */, + BEF88C521EB0005E00357577 /* TPPeer.h */, + BEF88C531EB0005E00357577 /* TPPeer.m */, + BEF88C541EB0005E00357577 /* TPPeerDynamicInfo.h */, + BEF88C551EB0005E00357577 /* TPPeerDynamicInfo.m */, + BEF88C561EB0005E00357577 /* TPPeerPermanentInfo.h */, + BEF88C571EB0005E00357577 /* TPPeerPermanentInfo.m */, + BEF88C581EB0005E00357577 /* TPPeerStableInfo.h */, + BEF88C591EB0005E00357577 /* TPPeerStableInfo.m */, + BEF88C5A1EB0005E00357577 /* TPPolicy.h */, + BEF88C5B1EB0005E00357577 /* TPPolicy.m */, + BEF88C5C1EB0005E00357577 /* TPPolicyDocument.h */, + BEF88C5D1EB0005E00357577 /* TPPolicyDocument.m */, + BEF88C5E1EB0005E00357577 /* TPSigningKey.h */, + BEF88C5F1EB0005E00357577 /* TPTypes.h */, + BEF88C601EB0005E00357577 /* TPUtils.h */, + BEF88C611EB0005E00357577 /* TPUtils.m */, + BEF88C621EB0005E00357577 /* TPVoucher.h */, + BEF88C631EB0005F00357577 /* TPVoucher.m */, + BEF88C471EB0005E00357577 /* Info.plist */, + BEF88C651EB0006C00357577 /* Tests */, + ); + name = TrustedPeers; + path = trust/TrustedPeers; + sourceTree = ""; + }; + BEF88C651EB0006C00357577 /* Tests */ = { + isa = PBXGroup; + children = ( + BEF88C671EB0008E00357577 /* TPCircleTests.m */, + BEF88C681EB0008E00357577 /* TPDummyDecrypter.h */, + BEF88C691EB0008E00357577 /* TPDummyDecrypter.m */, + BEF88C6A1EB0008E00357577 /* TPDummyEncrypter.h */, + BEF88C6B1EB0008E00357577 /* TPDummyEncrypter.m */, + BEF88C6C1EB0008E00357577 /* TPDummySigningKey.h */, + BEF88C6D1EB0008E00357577 /* TPDummySigningKey.m */, + BEF88C6E1EB0008E00357577 /* TPDummySigningKeyTests.m */, + BEF88C6F1EB0008E00357577 /* TPHashTests.m */, + BEF88C701EB0008E00357577 /* TPModelTests.m */, + BEF88C711EB0008E00357577 /* TPPeerPermanentInfoTests.m */, + BEF88C721EB0008E00357577 /* TPPeerStableInfoTests.m */, + BEF88C731EB0008E00357577 /* TPPeerTests.m */, + BEF88C741EB0008E00357577 /* TPPolicyDocumentTests.m */, + BEF88C751EB0008E00357577 /* TPUtilsTests.m */, + BEF88C761EB0008E00357577 /* TPVoucherTests.m */, + BEF88C661EB0008E00357577 /* Info.plist */, + ); + name = Tests; + path = ../TrustedPeersTests; + sourceTree = ""; + }; + CD1D64461DD386C9006D4139 /* AccountTrust */ = { isa = PBXGroup; children = ( - BE6D96B41DB14B65001B76D4 /* cnnic_certs.h */, - BE6D96B51DB14B65001B76D4 /* date_testing_certs.h */, - BE6D96B61DB14B65001B76D4 /* wosign_certs.h */, + CD31F8611DCD4C1400414B46 /* SOSAccountTrust.h */, + CD31F8601DCD4C1400414B46 /* SOSAccountTrust.m */, + 0C4899221E0F386900C6CF70 /* SOSAccountTrustClassic.h */, + 0C48991B1E0F384700C6CF70 /* SOSAccountTrustClassic.m */, + 0CE760491E12F30200B4381E /* SOSAccountTrustClassic+Circle.m */, + 0CE760531E13155100B4381E /* SOSAccountTrustClassic+Circle.h */, + 0CE7604D1E12F5BA00B4381E /* SOSAccountTrustClassic+Retirement.m */, + 0CE760551E1316E900B4381E /* SOSAccountTrustClassic+Retirement.h */, + 0CE7604B1E12F56800B4381E /* SOSAccountTrustClassic+Identity.m */, + 0CE760511E1314F700B4381E /* SOSAccountTrustClassic+Identity.h */, + 0CE760471E12F2F200B4381E /* SOSAccountTrustClassic+Expansion.m */, + 0CE7604F1E1301DC00B4381E /* SOSAccountTrustClassic+Expansion.h */, + 0C4899261E0F399B00C6CF70 /* SOSAccountTrustOctagon.h */, + 0C4899241E0F38FA00C6CF70 /* SOSAccountTrustOctagon.m */, ); - path = "si-84-sectrust-allowlist"; + name = AccountTrust; + path = ..; sourceTree = ""; }; CD6130CC1DA06F5700E1E42F /* KeychainSyncingOverIDSProxy */ = { @@ -12057,8 +14440,6 @@ CD23B4981DA06EB30047EDE9 /* KeychainSyncingOverIDSProxy+ReceiveMessage.m */, CD23B4991DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+SendMessage.h */, CD23B49A1DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+SendMessage.m */, - CD23B49B1DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+Throttle.h */, - CD23B49C1DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+Throttle.m */, CD23B4931DA06EB30047EDE9 /* IDSPersistentState.m */, CD23B4921DA06EB30047EDE9 /* IDSPersistentState.h */, CD23B4951DA06EB30047EDE9 /* IDSProxy.m */, @@ -12077,7 +14458,7 @@ CD6130D81DA06FC600E1E42F /* KeychainSyncingOverIDSProxy-Info.plist */, CD6130D91DA06FC600E1E42F /* keychainsyncingoveridsproxy.entitlements.plist */, CD23B4A81DA06ED10047EDE9 /* com.apple.private.alloy.keychainsync.plist */, - DC24B5841DA432C600330B48 /* IDSKeychainSyncingProxy.1 */, + DC24B5841DA432C600330B48 /* KeychainSyncingOverIDSProxy.8 */, ); name = "Supporting Files"; sourceTree = ""; @@ -12091,9 +14472,20 @@ path = KeychainSyncingOverIDSProxy/en.lproj; sourceTree = ""; }; + DA30D6771DF8C8FB00EC6B43 /* KeychainSyncAccountUpdater */ = { + isa = PBXGroup; + children = ( + DA30D6831DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.h */, + DA30D6841DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m */, + DA30D6781DF8C8FB00EC6B43 /* Info.plist */, + ); + path = KeychainSyncAccountUpdater; + sourceTree = ""; + }; DC0BC4E51D8B6AA600070CB0 /* applications */ = { isa = PBXGroup; children = ( + F621D0801ED6EA4C000EA569 /* authorizationdump */, DC58C4391D77BEA1003C25A4 /* csparser */, 5E10992719A5E55800A60E2B /* ISACLProtectedItems */, 728B56A316D59979008FA3AB /* OTAPKIAssetTool */, @@ -12674,7 +15066,6 @@ DC0BC9EB1D8B827200070CB0 /* sslMemory.h */, DC0BC9EC1D8B827200070CB0 /* sslPriv.h */, DC0BC9ED1D8B827200070CB0 /* sslRecord.h */, - DC0BC9EE1D8B827200070CB0 /* sslUtils.h */, ); name = "Project Headers"; sourceTree = ""; @@ -12774,6 +15165,7 @@ DC0BCA811D8B859D00070CB0 /* transform */ = { isa = PBXGroup; children = ( + ACBAF6DF1E941A800007BA2F /* regressions */, DC0BCAC01D8B85BC00070CB0 /* lib */, DC1786F51D778F2500B50D50 /* SecExternalSourceTransform.h */, DC1786F61D778F2500B50D50 /* SecNullTransform.h */, @@ -12920,17 +15312,16 @@ isa = PBXGroup; children = ( DC0BCDB31D8C6A4A00070CB0 /* SecurityTool */, - DC0BCC391D8C68CF00070CB0 /* SecMeta.h */, DC0BCC3A1D8C68CF00070CB0 /* iCloudKeychainTrace.c */, DC0BCC3B1D8C68CF00070CB0 /* iCloudKeychainTrace.h */, + EBF3749A1DC064200065D840 /* SecADWrapper.c */, + EBF3749B1DC064200065D840 /* SecADWrapper.h */, DC0BCC3C1D8C68CF00070CB0 /* SecAKSWrappers.c */, DC0BCC3D1D8C68CF00070CB0 /* SecAKSWrappers.h */, DC0BCC3E1D8C68CF00070CB0 /* SecBuffer.c */, DC0BCC3F1D8C68CF00070CB0 /* SecBuffer.h */, DC0BCC401D8C68CF00070CB0 /* SecCoreCrypto.c */, DC0BCC411D8C68CF00070CB0 /* SecCoreCrypto.h */, - DC0BCC421D8C68CF00070CB0 /* SecCertificateTrace.c */, - DC0BCC431D8C68CF00070CB0 /* SecCertificateTrace.h */, DC0BCC441D8C68CF00070CB0 /* SecCFCCWrappers.c */, DC0BCC451D8C68CF00070CB0 /* SecCFCCWrappers.h */, DC0BCC461D8C68CF00070CB0 /* SecCFRelease.h */, @@ -12940,8 +15331,12 @@ DC0BCC4A1D8C68CF00070CB0 /* SecCFError.h */, DC0BCC4B1D8C68CF00070CB0 /* SecDispatchRelease.h */, DC0BCC4C1D8C68CF00070CB0 /* SecIOFormat.h */, + E78CCDC61E737F6700C1CFAA /* SecNSAdditions.m */, + E78CCDCD1E737F8100C1CFAA /* SecNSAdditions.h */, DC0BCC4D1D8C68CF00070CB0 /* SecTrace.c */, DC0BCC4E1D8C68CF00070CB0 /* SecTrace.h */, + EB7AE6F61E86D55400B80B15 /* SecPLWrappers.m */, + EB7AE6F71E86D55400B80B15 /* SecPLWrappers.h */, DC0BCC4F1D8C68CF00070CB0 /* array_size.h */, DC0BCC521D8C68CF00070CB0 /* debugging.c */, DC0BCC531D8C68CF00070CB0 /* debugging.h */, @@ -12963,6 +15358,8 @@ DC0BCC631D8C68CF00070CB0 /* der_string.c */, DC0BCC641D8C68CF00070CB0 /* fileIo.c */, DC0BCC651D8C68CF00070CB0 /* fileIo.h */, + 7221843E1EC6782A004C7BED /* sec_action.c */, + 7221843F1EC6782A004C7BED /* sec_action.h */, DC0BCC661D8C68CF00070CB0 /* sqlutils.h */, DC0BCC671D8C68CF00070CB0 /* iOSforOSX.h */, DC0BCC681D8C68CF00070CB0 /* iOSforOSX.c */, @@ -12983,8 +15380,8 @@ DC0BCC751D8C68CF00070CB0 /* SecAppleAnchorPriv.h */, DC0BCC761D8C68CF00070CB0 /* SecInternalRelease.c */, DC0BCC771D8C68CF00070CB0 /* SecInternalReleasePriv.h */, - EBF3749A1DC064200065D840 /* SecADWrapper.c */, - EBF3749B1DC064200065D840 /* SecADWrapper.h */, + B61F67541F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h */, + B61F67551F1FCFCA00E2FDBB /* SecPaddingConfigurations.c */, ); name = utilities; path = OSX/utilities; @@ -12994,6 +15391,7 @@ isa = PBXGroup; children = ( DCC78E281D8085FC00865A7C /* AppleBaselineEscrowCertificates.h */, + D41149A01E7C935D00C078C7 /* AppleiPhoneDeviceCACertificates.h */, DCC78E301D8085FC00865A7C /* SecAccessControl.c */, 443381D918A3D81400215606 /* SecAccessControl.h */, 443381DA18A3D81400215606 /* SecAccessControlPriv.h */, @@ -13024,8 +15422,11 @@ DCC78E521D8085FC00865A7C /* SecIdentity.c */, DCC78E551D8085FC00865A7C /* SecImportExport.c */, DCC78E581D8085FC00865A7C /* SecItem.c */, + DC4269031E82EDAC002B7110 /* SecItem.m */, DCC78E5A1D8085FC00865A7C /* SecItemBackup.c */, 4CE7EA561AEAE8D60067F5BD /* SecItemBackup.h */, + 52AA92881E662A4A004301A6 /* SecBackupKeybagEntry.m */, + 52AA92871E662A4A004301A6 /* SecBackupKeybagEntry.h */, DCC78E5C1D8085FC00865A7C /* SecItemConstants.c */, 4CEDF7370F3A6CFB0027C4FE /* SecItemInternal.h */, DCC78E5F1D8085FC00865A7C /* SecItemShim.h */, @@ -13074,6 +15475,8 @@ DCC78E8F1D8085FC00865A7C /* SecSignatureVerificationSupport.h */, DCC78E901D8085FC00865A7C /* SecTrust.c */, DCC78E921D8085FC00865A7C /* SecTrustInternal.h */, + BEEB47D71EA189F5004AA5C6 /* SecTrustStatusCodes.c */, + BEEB47D81EA189F5004AA5C6 /* SecTrustStatusCodes.h */, DCC78E971D8085FC00865A7C /* SecTrustStore.c */, 4C1B442C0BB9CAF900461B82 /* SecTrustStore.h */, EB6928BE1D9C9C5900062A18 /* SecRecoveryKey.h */, @@ -13129,8 +15532,7 @@ DC65E7BF1D8CBB1500152EF0 /* readline.h */, DC0BCDB41D8C6A5B00070CB0 /* not_on_this_platorm.c */, ); - name = SecurityTool; - path = ../sec/Security; + path = SecurityTool; sourceTree = ""; }; DC1002C41D8E19D70025549C /* Products */ = { @@ -13227,7 +15629,6 @@ DCB3417A1D8A2B7A0054D16E /* cdsa_utilities */, DC0BC5841D8B70D100070CB0 /* cdsa_utils */, DC0BC5B81D8B721900070CB0 /* checkpw */, - DCD067621D8CDE9B007602F1 /* codesigning */, DC0BC5EA1D8B743F00070CB0 /* comcryption */, DC0BC6001D8B754000070CB0 /* cryptkit */, DC0BC7441D8B76E500070CB0 /* cssm */, @@ -13241,7 +15642,6 @@ DC0BC9D01D8B825900070CB0 /* ssl */, DC0BCA811D8B859D00070CB0 /* transform */, DC0BCB091D8B896500070CB0 /* translocate */, - DCD06AA81D8E0D3D007602F1 /* utilities */, DC1784421D77869A00B50D50 /* libsecurity_smime.xcodeproj */, DC1786FF1D778F7800B50D50 /* libsecurity_smime_headers */, DC1784AE1D7786C700B50D50 /* libsecurity_cms.xcodeproj */, @@ -13257,7 +15657,6 @@ DC1789A81D77A06800B50D50 /* Resources */ = { isa = PBXGroup; children = ( - DC178A301D77A1F500B50D50 /* iToolsTrustedApps.plist */, DC178A311D77A1F500B50D50 /* FDEPrefs.plist */, DC178A321D77A1F500B50D50 /* SecDebugErrorMessages.strings */, DC178A331D77A1F500B50D50 /* SecErrorMessages.strings */, @@ -13296,6 +15695,55 @@ name = mds; sourceTree = ""; }; + DC35021A1E009E0700BC0587 /* Database Helpers */ = { + isa = PBXGroup; + children = ( + DC762A9C1E57A86A00B03A2C /* CKKSRecordHolder.h */, + DC762A9D1E57A86A00B03A2C /* CKKSRecordHolder.m */, + DC797E191DD3F89E00CC9E42 /* CKKSSQLDatabaseObject.h */, + DC797E131DD3F88300CC9E42 /* CKKSSQLDatabaseObject.m */, + DCDCCB8D1DF7B8D4006E840E /* CKKSItem.h */, + DCDCCB8E1DF7B8D4006E840E /* CKKSItem.m */, + 47CEED1E1E60DE900044EAB4 /* CKKSManifest.h */, + 47CEED1F1E60DE900044EAB4 /* CKKSManifest.m */, + 476D87391E6750E200190352 /* CKKSManifestLeafRecord.h */, + 476D873A1E6750E200190352 /* CKKSManifestLeafRecord.m */, + ); + name = "Database Helpers"; + sourceTree = ""; + }; + DC3502B61E0208BE00BC0587 /* Tests (Local) */ = { + isa = PBXGroup; + children = ( + 471024D91E79CB6D00844C09 /* CKKSTests.h */, + DC3502B71E0208BE00BC0587 /* CKKSTests.m */, + DC6593D21ED8DBCE00C19462 /* CKKSTests+API.h */, + DC15F79B1E68EAD5003B9A40 /* CKKSTests+API.m */, + DC6593C91ED8DA9200C19462 /* CKKSTests+CurrentPointerAPI.m */, + DC9A2C5E1EB3F556008FAC27 /* CKKSTests+Coalesce.m */, + DC08D1CB1E64FCC5006237DA /* CKKSSOSTests.m */, + DC9C750F1E4BCC5100F1CA0D /* CKKSOperationTests.m */, + DC222C891E089BAE00B09171 /* CKKSSQLTests.m */, + DC4DB15E1E2590B100CD6769 /* CKKSEncryptionTests.m */, + 6C34462F1E24F6BE00F9522B /* CKKSRateLimiterTests.m */, + DCD6C4B61EC5319600414FEE /* CKKSNearFutureSchedulerTests.m */, + DCFE1C3C1F17EFB5007640C8 /* CKKSConditionTests.m */, + 476E918D1E7343B200B4E4D3 /* CKKSManifestTests.m */, + DC3502B91E0208BE00BC0587 /* Info.plist */, + DC3502E51E0214C800BC0587 /* MockCloudKit.h */, + DC3502E61E0214C800BC0587 /* MockCloudKit.m */, + DC222CA61E08A7D900B09171 /* CloudKitMockXCTest.h */, + DC222CA71E08A7D900B09171 /* CloudKitMockXCTest.m */, + DC08D1C21E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.h */, + DC08D1C31E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m */, + 6C588D791EAA149F00D7E322 /* RateLimiterTests.m */, + 4723C9D11F1531970082882F /* CKKSLoggerTests.m */, + DCE7F2081F21726500DDB0F7 /* CKKSAPSReceiverTests.m */, + ); + name = "Tests (Local)"; + path = tests; + sourceTree = ""; + }; DC3A4B5E1D91EAA500E46D4A /* CodeSigningHelper */ = { isa = PBXGroup; children = ( @@ -13339,6 +15787,7 @@ DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */, DC52EA901D80CC2A00B0A59C /* entitlements.plist */, DC52EA911D80CC2A00B0A59C /* whoami.m */, + EB48C19E1E573EDC00EC5E57 /* sos.m */, DC52EA921D80CC2A00B0A59C /* syncbubble.m */, DC52EA931D80CC2A00B0A59C /* leaks.c */, DC52EA941D80CC2A00B0A59C /* leaks.h */, @@ -13376,6 +15825,9 @@ DC59E9AA1D91C9BE001BDDF5 /* Security.framework (Shared) */ = { isa = PBXGroup; children = ( + 4723C9B51F152E8E0082882F /* Analytics */, + DCD067621D8CDE9B007602F1 /* codesigning */, + DCD06AA81D8E0D3D007602F1 /* security_utilities */, E7450BB216D42BD4009C07B8 /* Headers */, DC59E9AB1D91C9CE001BDDF5 /* DER */, DC8834001D8A217200CE0ACA /* ASN1 */, @@ -13398,6 +15850,7 @@ DC59E9FD1D91CA0A001BDDF5 /* libDER */ = { isa = PBXGroup; children = ( + DC3832C01DB6E69800385F63 /* module.modulemap */, DC59E9ED1D91CA0A001BDDF5 /* DER_Keys.c */, DC59E9EE1D91CA0A001BDDF5 /* DER_Keys.h */, DC59E9EF1D91CA0A001BDDF5 /* asn1Types.h */, @@ -13473,7 +15926,7 @@ DC5ABD831D832D5800CF422C /* display_error_code.h */, DC5ABD841D832D5800CF422C /* trusted_cert_dump.c */, DC5ABD851D832D5800CF422C /* trusted_cert_dump.h */, - DC5ABD861D832D5800CF422C /* identity_find.c */, + DC5ABD861D832D5800CF422C /* identity_find.m */, DC5ABD871D832D5800CF422C /* identity_find.h */, DC5ABD881D832D5800CF422C /* identity_prefs.c */, DC5ABD891D832D5800CF422C /* identity_prefs.h */, @@ -13485,7 +15938,7 @@ DC5ABD8F1D832D5800CF422C /* keychain_create.h */, DC5ABD901D832D5800CF422C /* keychain_delete.c */, DC5ABD911D832D5800CF422C /* keychain_delete.h */, - DC5ABD921D832D5800CF422C /* keychain_export.c */, + DC5ABD921D832D5800CF422C /* keychain_export.m */, DC5ABD931D832D5800CF422C /* keychain_export.h */, DC5ABD941D832D5800CF422C /* keychain_find.c */, DC5ABD951D832D5800CF422C /* keychain_find.h */, @@ -13822,6 +16275,7 @@ F93C49391AB8FF530047E01A /* ckcdiagnose */, 4C52D0B616EFC61E0079966E /* CircleJoinRequested */, 5346480317331E1200FE9172 /* KeychainSyncAccountNotification */, + DA30D6771DF8C8FB00EC6B43 /* KeychainSyncAccountUpdater */, E7D847C61C6BE9710025BB44 /* KeychainCircle.framework */, DCE4E9121D7F3D5400AFB96E /* Keychain Circle Notification */, DCE4E8DE1D7F39DB00AFB96E /* Cloud Keychain Utility */, @@ -13857,6 +16311,7 @@ children = ( DCEE1E851D93424D00DC0EB7 /* com.apple.securityd.plist */, DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */, + DC9EBA2F1DEE651500D0F733 /* Info-macOS.plist */, ); name = resources; sourceTree = ""; @@ -13864,6 +16319,9 @@ DC5AC2011D83663C00CF422C /* tests */ = { isa = PBXGroup; children = ( + 47C51B851EEA657D0032D9E5 /* SecurityUnitTests */, + F667EC541E96E8C800203D5C /* authdtests */, + EB1055641E14DB370003C309 /* secfuzzer */, DC0BCBD81D8C646700070CB0 /* regressionBase */, DC59EA4B1D91CACE001BDDF5 /* libDER */, DC0BCCB81D8C68F000070CB0 /* utilitiesRegressions */, @@ -13893,6 +16351,15 @@ name = Security.framework; sourceTree = ""; }; + DC5BCC401E5380AD00649140 /* src */ = { + isa = PBXGroup; + children = ( + DC5BCC461E5380EA00649140 /* SecArgParse.c */, + DC5BCC471E5380EA00649140 /* SecArgParse.h */, + ); + name = src; + sourceTree = ""; + }; DC610A4E1D78F702002223DE /* codesign_tests */ = { isa = PBXGroup; children = ( @@ -14032,6 +16499,17 @@ path = derived_src; sourceTree = BUILT_PRODUCTS_DIR; }; + DC6D2C941DD3B20400BE372D /* keychain */ = { + isa = PBXGroup; + children = ( + EB27FF051E402C3C00EC9E3A /* ckksctl */, + 6C34464D1E2534C200F9522B /* Analytics */, + BEF88C451EAFFFED00357577 /* TrustedPeers */, + DC9B7AD31DCBF336004E9385 /* CloudKit Syncing */, + ); + path = keychain; + sourceTree = ""; + }; DC8834001D8A217200CE0ACA /* ASN1 */ = { isa = PBXGroup; children = ( @@ -14105,6 +16583,59 @@ path = OSX/libsecurity_asn1/lib; sourceTree = ""; }; + DC9B7AD31DCBF336004E9385 /* CloudKit Syncing */ = { + isa = PBXGroup; + children = ( + DCD662F21E3294DE00188186 /* CloudKit Support */, + DCFE1C311F17ECC3007640C8 /* dispatch Support */, + DCD662EB1E32946000188186 /* Sync Objects */, + DCD662F11E32946E00188186 /* Operations */, + DC3502B61E0208BE00BC0587 /* Tests (Local) */, + DCA4D2121E5651950056214F /* Tests (Live CloudKit) */, + DC1ED8C21DD5538C002BDCFA /* CKKS.h */, + DC1ED8C51DD55476002BDCFA /* CKKS.m */, + DCF7A89F1F04502300CABE89 /* CKKSControlProtocol.h */, + DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */, + DCBDB3B91E57CA7A00B61300 /* CKKSViewManager.h */, + DCBDB3BA1E57CA7A00B61300 /* CKKSViewManager.m */, + DCBDB3B01E57C67500B61300 /* CKKSKeychainView.h */, + DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */, + DC1ED8C01DD51890002BDCFA /* CKKSItemEncrypter.h */, + DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */, + 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */, + 6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */, + 6CA2B9431E9F9F5700C43444 /* RateLimiter.h */, + 6CC7F5B31E9F99EE0014AE63 /* RateLimiter.m */, + ); + name = "CloudKit Syncing"; + path = ckks; + sourceTree = ""; + }; + DCA4D2121E5651950056214F /* Tests (Live CloudKit) */ = { + isa = PBXGroup; + children = ( + 6CB5F4781E402E5700DBF3F0 /* KeychainCKKS.plist */, + 6CF4A0B51E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */, + 6CF4A0E11E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */, + 6CB5F4771E402D6D00DBF3F0 /* testrunner */, + 6CCDF7911E3C2D69003F2555 /* CKKSCloudKitTests.m */, + 6CB5F4751E4025AB00DBF3F0 /* CKKSCloudKitTestsInfo.plist */, + ); + name = "Tests (Live CloudKit)"; + path = tests; + sourceTree = ""; + }; + DCA4D2191E569FFE0056214F /* Helpers */ = { + isa = PBXGroup; + children = ( + DC207EB61ED4EAB600D46873 /* CKKSLockStateTracker.h */, + DC207EB71ED4EAB600D46873 /* CKKSLockStateTracker.m */, + DCCD88E61E42622200F5AA71 /* CKKSGroupOperation.h */, + DCCD88E71E42622200F5AA71 /* CKKSGroupOperation.m */, + ); + name = Helpers; + sourceTree = ""; + }; DCB340651D8A24CC0054D16E /* authorization */ = { isa = PBXGroup; children = ( @@ -14409,7 +16940,6 @@ DCB342451D8A32A20054D16E /* SecBridge.h */, DCB342461D8A32A20054D16E /* SecCertificate.cpp */, DCB342471D8A32A20054D16E /* SecCertificateBundle.cpp */, - DCB342481D8A32A20054D16E /* SecCertificateRequest.cpp */, DCB342491D8A32A20054D16E /* SecIdentity.cpp */, DCB3424A1D8A32A20054D16E /* SecIdentitySearch.cpp */, DCB3424B1D8A32A20054D16E /* SecItemConstants.c */, @@ -14441,8 +16971,6 @@ DCB342891D8A32A20054D16E /* ACL.h */, DCB3428A1D8A32A20054D16E /* Certificate.cpp */, DCB3428B1D8A32A20054D16E /* Certificate.h */, - DCB3428C1D8A32A20054D16E /* CertificateRequest.cpp */, - DCB3428D1D8A32A20054D16E /* CertificateRequest.h */, DCB3428E1D8A32A20054D16E /* CertificateValues.cpp */, DCB3428F1D8A32A20054D16E /* CertificateValues.h */, DCB342901D8A32A20054D16E /* ExtendedAttribute.cpp */, @@ -14480,7 +17008,7 @@ DCB342B11D8A32A20054D16E /* TrustSettings.h */, DCB342B21D8A32A20054D16E /* TrustKeychains.h */, DCB342B31D8A32A20054D16E /* SecTrustOSXEntryPoints.cpp */, - DCB342B41D8A32A20054D16E /* SecTrustOSXEntryPoints.h */, + D41257ED1E941D5B00781F23 /* SecTrustOSXEntryPoints.h */, ); name = "API Classes"; sourceTree = ""; @@ -14640,82 +17168,84 @@ children = ( DCC78C371D8085D800865A7C /* ios6_1_keychain_2_db.h */, DCC78C381D8085D800865A7C /* ios8-inet-keychain-2.h */, - DCC78C391D8085D800865A7C /* secd-03-corrupted-items.c */, - DCC78C3A1D8085D800865A7C /* secd-04-corrupted-items.c */, + DCC78C391D8085D800865A7C /* secd-03-corrupted-items.m */, + DCC78C3A1D8085D800865A7C /* secd-04-corrupted-items.m */, DCC78C3B1D8085D800865A7C /* secd-05-corrupted-items.m */, DCC78C3C1D8085D800865A7C /* securityd_regressions.h */, - DCC78C3D1D8085D800865A7C /* sd-10-policytree.c */, + DCC78C3D1D8085D800865A7C /* sd-10-policytree.m */, DCC78C3E1D8085D800865A7C /* secd_regressions.h */, - DCC78C3F1D8085D800865A7C /* secd-01-items.c */, - DCC78C401D8085D800865A7C /* secd-02-upgrade-while-locked.c */, + DCC78C3F1D8085D800865A7C /* secd-01-items.m */, + DCC78C401D8085D800865A7C /* secd-02-upgrade-while-locked.m */, DCC78C411D8085D800865A7C /* secd-20-keychain_upgrade.m */, DCC78C421D8085D800865A7C /* secd-21-transmogrify.m */, - DCC78C431D8085D800865A7C /* secd-30-keychain-upgrade.c */, - DCC78C441D8085D800865A7C /* secd-31-keychain-bad.c */, - DCC78C451D8085D800865A7C /* secd-31-keychain-unreadable.c */, - DCC78C461D8085D800865A7C /* secd-32-restore-bad-backup.c */, + DCC78C431D8085D800865A7C /* secd-30-keychain-upgrade.m */, + DCC78C441D8085D800865A7C /* secd-31-keychain-bad.m */, + DCC78C451D8085D800865A7C /* secd-31-keychain-unreadable.m */, + DCC78C461D8085D800865A7C /* secd-32-restore-bad-backup.m */, DCC78C471D8085D800865A7C /* secd-33-keychain-ctk.m */, - DCC78C481D8085D800865A7C /* secd-34-backup-der-parse.c */, - DCC78C491D8085D800865A7C /* secd-35-keychain-migrate-inet.c */, + DCC78C481D8085D800865A7C /* secd-34-backup-der-parse.m */, + DCC78C491D8085D800865A7C /* secd-35-keychain-migrate-inet.m */, DCFAEDD51D99A464005187E4 /* secd-36-ks-encrypt.m */, - DCC78C4A1D8085D800865A7C /* secd-40-cc-gestalt.c */, - DCC78C4B1D8085D800865A7C /* secd-50-account.c */, - DCC78C4C1D8085D800865A7C /* secd-49-manifests.c */, - DCC78C4D1D8085D800865A7C /* secd-50-message.c */, - DCC78C4E1D8085D800865A7C /* secd-51-account-inflate.c */, - DCC78C4F1D8085D800865A7C /* secd-52-offering-gencount-reset.c */, - DCC78C501D8085D800865A7C /* secd-52-account-changed.c */, - DCC78C511D8085D800865A7C /* secd-55-account-circle.c */, - DCC78C521D8085D800865A7C /* secd-55-account-incompatibility.c */, - DCC78C531D8085D800865A7C /* secd-56-account-apply.c */, - DCC78C541D8085D800865A7C /* secd-57-account-leave.c */, - DCC78C551D8085D800865A7C /* secd-57-1-account-last-standing.c */, - DCC78C561D8085D800865A7C /* secd-58-password-change.c */, - DCC78C571D8085D800865A7C /* secd-59-account-cleanup.c */, - DCC78C581D8085D800865A7C /* secd-60-account-cloud-identity.c */, - DCC78C591D8085D800865A7C /* secd60-account-cloud-exposure.c */, - DCC78C5A1D8085D800865A7C /* secd-61-account-leave-not-in-kansas-anymore.c */, - DCC78C5B1D8085D800865A7C /* secd-62-account-backup.c */, - DCC78C5C1D8085D800865A7C /* secd-62-account-hsa-join.c */, - DCC78C5D1D8085D800865A7C /* secd-63-account-resurrection.c */, - DCC78C5E1D8085D800865A7C /* secd-65-account-retirement-reset.c */, - DCC78C5F1D8085D800865A7C /* secd-64-circlereset.c */, - 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.c */, - 483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.c */, - DCC78C601D8085D800865A7C /* secd-70-engine.c */, - DCC78C611D8085D800865A7C /* secd-70-engine-corrupt.c */, - DCC78C621D8085D800865A7C /* secd-70-engine-smash.c */, - DCC78C631D8085D800865A7C /* secd-70-otr-remote.c */, - DCC78C641D8085D800865A7C /* secd-71-engine-save.c */, + EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */, + DCC78C4A1D8085D800865A7C /* secd-40-cc-gestalt.m */, + DCC78C4B1D8085D800865A7C /* secd-50-account.m */, + DCC78C4C1D8085D800865A7C /* secd-49-manifests.m */, + DCC78C4D1D8085D800865A7C /* secd-50-message.m */, + DCC78C4E1D8085D800865A7C /* secd-51-account-inflate.m */, + DCC78C4F1D8085D800865A7C /* secd-52-offering-gencount-reset.m */, + DCC78C501D8085D800865A7C /* secd-52-account-changed.m */, + DCC78C511D8085D800865A7C /* secd-55-account-circle.m */, + DCC78C521D8085D800865A7C /* secd-55-account-incompatibility.m */, + DCC78C531D8085D800865A7C /* secd-56-account-apply.m */, + DCC78C541D8085D800865A7C /* secd-57-account-leave.m */, + DCC78C551D8085D800865A7C /* secd-57-1-account-last-standing.m */, + DCC78C561D8085D800865A7C /* secd-58-password-change.m */, + DCC78C571D8085D800865A7C /* secd-59-account-cleanup.m */, + DCC78C581D8085D800865A7C /* secd-60-account-cloud-identity.m */, + DCC78C591D8085D800865A7C /* secd60-account-cloud-exposure.m */, + DCC78C5A1D8085D800865A7C /* secd-61-account-leave-not-in-kansas-anymore.m */, + DCC78C5B1D8085D800865A7C /* secd-62-account-backup.m */, + DCC78C5D1D8085D800865A7C /* secd-63-account-resurrection.m */, + DCC78C5E1D8085D800865A7C /* secd-65-account-retirement-reset.m */, + DCC78C5F1D8085D800865A7C /* secd-64-circlereset.m */, + 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.m */, + 483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.m */, + DCC78C601D8085D800865A7C /* secd-70-engine.m */, + DCC78C611D8085D800865A7C /* secd-70-engine-corrupt.m */, + DCC78C621D8085D800865A7C /* secd-70-engine-smash.m */, + DCC78C631D8085D800865A7C /* secd-70-otr-remote.m */, + DCC78C641D8085D800865A7C /* secd-71-engine-save.m */, DCC78C651D8085D800865A7C /* secd-71-engine-save-sample1.h */, - DCC78C661D8085D800865A7C /* secd-74-engine-beer-servers.c */, - DCC78C671D8085D800865A7C /* secd-75-engine-views.c */, - DCC78C681D8085D800865A7C /* secd-76-idstransport.c */, - DCC78C691D8085D800865A7C /* secd_77_ids_messaging.c */, - DCC78C6A1D8085D800865A7C /* secd-80-views-basic.c */, - 48AFBA751DEF8D3100436D08 /* secd-80-views-alwayson.c */, - DCC78C6B1D8085D800865A7C /* secd-82-secproperties-basic.c */, - DCC78C6C1D8085D800865A7C /* secd-81-item-acl-stress.c */, - DCC78C6D1D8085D800865A7C /* secd-81-item-acl.c */, - DCC78C6E1D8085D800865A7C /* secd-82-persistent-ref.c */, + DCC78C661D8085D800865A7C /* secd-74-engine-beer-servers.m */, + DCC78C671D8085D800865A7C /* secd-75-engine-views.m */, + DCC78C681D8085D800865A7C /* secd-76-idstransport.m */, + DCC78C691D8085D800865A7C /* secd_77_ids_messaging.m */, + 7281E08B1DFD0A380021E1B7 /* secd-80-views-alwayson.m */, + DCC78C6A1D8085D800865A7C /* secd-80-views-basic.m */, + DCC78C6B1D8085D800865A7C /* secd-82-secproperties-basic.m */, + DCC78C6C1D8085D800865A7C /* secd-81-item-acl-stress.m */, + DCC78C6D1D8085D800865A7C /* secd-81-item-acl.m */, + DCC78C6E1D8085D800865A7C /* secd-82-persistent-ref.m */, DCC78C6F1D8085D800865A7C /* secd-83-item-match-policy.m */, DCC78C701D8085D800865A7C /* secd-83-item-match-valid-on-date.m */, DCC78C711D8085D800865A7C /* secd-83-item-match-trusted.m */, DCC78C721D8085D800865A7C /* secd-83-item-match.h */, - DCC78C731D8085D800865A7C /* secd-90-hsa2.c */, - DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.c */, - DCC78C751D8085D800865A7C /* secd-100-initialsync.c */, - DCC78C761D8085D800865A7C /* secd-130-other-peer-views.c */, - DCC78C771D8085D800865A7C /* secd-154-engine-backoff.c */, - DCC78C781D8085D800865A7C /* secd-200-logstate.c */, - DC0B622B1D90982100D43BCB /* secd-201-coders.c */, + DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.m */, + DCC78C751D8085D800865A7C /* secd-100-initialsync.m */, + DCC78C761D8085D800865A7C /* secd-130-other-peer-views.m */, + DCC78C771D8085D800865A7C /* secd-154-engine-backoff.m */, + 0C3C00721EF3636300AB19FE /* secd-155-otr-negotiation-monitor.m */, + 0CCDE7161EEB08220021A946 /* secd-156-timers.m */, + DCC78C781D8085D800865A7C /* secd-200-logstate.m */, + DC0B622B1D90982100D43BCB /* secd-201-coders.m */, DCDCC7DD1D9B54DF006487E8 /* secd-202-recoverykey.m */, - E7FE40BD1DC803FD00F0F5B6 /* secd-210-keyinterest.m */, - DCFAEDD11D9998DD005187E4 /* secd-668-ghosts.c */, + 7281E08E1DFD0D810021E1B7 /* secd-210-keyinterest.m */, + 522B28081E64B48E002B5638 /* secd-230-keybagtable.m */, + DCFAEDD11D9998DD005187E4 /* secd-668-ghosts.m */, DCC78C791D8085D800865A7C /* SOSAccountTesting.h */, DCC78C7A1D8085D800865A7C /* SecdTestKeychainUtilities.c */, DCC78C7B1D8085D800865A7C /* SecdTestKeychainUtilities.h */, - DCC78C7C1D8085D800865A7C /* SOSTransportTestTransports.c */, + DCC78C7C1D8085D800865A7C /* SOSTransportTestTransports.m */, DCC78C7D1D8085D800865A7C /* SOSTransportTestTransports.h */, E7FE40C61DC804FA00F0F5B6 /* CKDSimulatedStore.h */, E7FE40C41DC804E400F0F5B6 /* CKDSimulatedStore.m */, @@ -14731,21 +17261,7 @@ 4814D86C1CAA064F002FFC36 /* os_log */, DC5AC2001D83653E00CF422C /* resources */, DCC78C7E1D8085D800865A7C /* Regressions */, - DCC78C7F1D8085D800865A7C /* asynchttp.c */, - DCC78C801D8085D800865A7C /* asynchttp.h */, DCC78C811D8085D800865A7C /* entitlements.plist */, - DCC78C821D8085D800865A7C /* OTATrustUtilities.c */, - DCC78C831D8085D800865A7C /* OTATrustUtilities.h */, - DCC78C841D8085D800865A7C /* policytree.c */, - DCC78C851D8085D800865A7C /* policytree.h */, - DCC78C861D8085D800865A7C /* nameconstraints.c */, - DCC78C871D8085D800865A7C /* nameconstraints.h */, - DCC78C881D8085D800865A7C /* personalization.c */, - DCC78C891D8085D800865A7C /* personalization.h */, - DCC78C8A1D8085D800865A7C /* SecCAIssuerCache.c */, - DCC78C8B1D8085D800865A7C /* SecCAIssuerCache.h */, - DCC78C8C1D8085D800865A7C /* SecCAIssuerRequest.c */, - DCC78C8D1D8085D800865A7C /* SecCAIssuerRequest.h */, DCC78C8E1D8085D800865A7C /* SecDbItem.c */, DCC78C8F1D8085D800865A7C /* SecDbItem.h */, DCC78C901D8085D800865A7C /* SecDbKeychainItem.c */, @@ -14764,34 +17280,19 @@ DCC78C9D1D8085D800865A7C /* SecItemBackupServer.h */, DCC78C9E1D8085D800865A7C /* SecKeybagSupport.c */, DCC78C9F1D8085D800865A7C /* SecKeybagSupport.h */, - DCC78CA01D8085D800865A7C /* SecOCSPCache.c */, - DCC78CA11D8085D800865A7C /* SecOCSPCache.h */, - DCC78CA21D8085D800865A7C /* SecOCSPRequest.c */, - DCC78CA31D8085D800865A7C /* SecOCSPRequest.h */, - DCC78CA41D8085D800865A7C /* SecOCSPResponse.c */, - DCC78CA51D8085D800865A7C /* SecOCSPResponse.h */, - DCC78CA61D8085D800865A7C /* SecPolicyServer.c */, - DCC78CA71D8085D800865A7C /* SecPolicyServer.h */, - BEE523CF1DA610D800DD0AA3 /* SecRevocationDb.c */, - BEE523D01DA610D800DD0AA3 /* SecRevocationDb.h */, - DCC78CA81D8085D800865A7C /* SecTrustServer.c */, - DCC78CA91D8085D800865A7C /* SecTrustServer.h */, - DCC78CAA1D8085D800865A7C /* SOSCloudCircleServer.c */, + DCC78CAA1D8085D800865A7C /* SOSCloudCircleServer.m */, DCC78CAB1D8085D800865A7C /* SOSCloudCircleServer.h */, - DCC78CAC1D8085D800865A7C /* SecTrustStoreServer.c */, - DCC78CAD1D8085D800865A7C /* SecTrustStoreServer.h */, - DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.c */, + DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.m */, DCC78CAF1D8085D800865A7C /* SecLogSettingsServer.h */, DCC78CB01D8085D800865A7C /* spi.c */, DCC78CB11D8085D800865A7C /* spi.h */, DCC78CB21D8085D800865A7C /* iCloudTrace.h */, DCC78CB31D8085D800865A7C /* iCloudTrace.c */, - DCC78CB41D8085D800865A7C /* SecOTRRemote.c */, + DCC78CB41D8085D800865A7C /* SecOTRRemote.m */, DCC78CB51D8085D800865A7C /* SecOTRRemote.h */, - D46F31581E00A27D0065B550 /* SecTrustLoggingServer.c */, - D46F31591E00A27D0065B550 /* SecTrustLoggingServer.h */, - D46F31611E00CCD20065B550 /* SecCertificateSource.c */, - D46F31621E00CCD20065B550 /* SecCertificateSource.h */, + EBC15B1B1DB4306C00126882 /* com.apple.secd.sb */, + 526965CB1E6E283100627F9D /* AsymKeybagBackup.h */, + 526965CC1E6E283100627F9D /* AsymKeybagBackup.m */, ); name = "securityd iOS"; path = OSX/sec/securityd; @@ -14811,7 +17312,7 @@ DCC78D101D8085F200865A7C /* Regressions */ = { isa = PBXGroup; children = ( - DCC78CFD1D8085F200865A7C /* sc-20-keynames.c */, + DCC78CFD1D8085F200865A7C /* sc-20-keynames.m */, DCC78CFE1D8085F200865A7C /* sc-25-soskeygen.c */, DCC78CFF1D8085F200865A7C /* sc-30-peerinfo.c */, DCC78D001D8085F200865A7C /* sc-31-peerinfo-simplefuzz.c */, @@ -14819,12 +17320,11 @@ DCC78D021D8085F200865A7C /* sc-42-circlegencount.c */, DCC78D031D8085F200865A7C /* sc-45-digestvector.c */, DCC78D041D8085F200865A7C /* sc-130-resignationticket.c */, - DCC78D051D8085F200865A7C /* sc-140-hsa2.c */, - DCC78D061D8085F200865A7C /* sc-150-ring.c */, + DCC78D061D8085F200865A7C /* sc-150-ring.m */, DCC78D071D8085F200865A7C /* sc-150-backupkeyderivation.c */, DCC78D081D8085F200865A7C /* sc-153-backupslicekeybag.c */, DCC78D091D8085F200865A7C /* SOSCircle_regressions.h */, - DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.c */, + DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.m */, DCC78D0B1D8085F200865A7C /* SOSRegressionUtilities.h */, DCC78D0C1D8085F200865A7C /* SOSTestDataSource.c */, DCC78D0D1D8085F200865A7C /* SOSTestDataSource.h */, @@ -14837,44 +17337,43 @@ DCC78D2D1D8085F200865A7C /* Account */ = { isa = PBXGroup; children = ( - DCFAEDC81D999851005187E4 /* SOSAccountGhost.c */, - DCFAEDC91D999851005187E4 /* SOSAccountGhost.h */, - DCC78D121D8085F200865A7C /* SOSAccount.c */, + DCC78D121D8085F200865A7C /* SOSAccount.m */, DCC78D131D8085F200865A7C /* SOSAccount.h */, - DCDCC7E41D9B551C006487E8 /* SOSAccountSync.c */, - DCC78D141D8085F200865A7C /* SOSAccountTransaction.c */, - DCC78D151D8085F200865A7C /* SOSAccountTransaction.h */, - DCC78D161D8085F200865A7C /* SOSAccountBackup.c */, - 48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.c */, - DCC78D171D8085F200865A7C /* SOSAccountCircles.c */, - DCC78D181D8085F200865A7C /* SOSAccountHSAJoin.c */, - DCC78D191D8085F200865A7C /* SOSAccountHSAJoin.h */, - DCC78D1A1D8085F200865A7C /* SOSAccountCloudParameters.c */, - DCC78D1B1D8085F200865A7C /* SOSAccountCredentials.c */, - DCC78D1C1D8085F200865A7C /* SOSAccountDer.c */, - DCC78D1D1D8085F200865A7C /* SOSAccountFullPeerInfo.c */, - E7E5B55E1DC7ACAE00C03FFB /* SOSAccountGetSet.c */, - DCC78D1E1D8085F200865A7C /* SOSAccountPeers.c */, - DCC78D1F1D8085F200865A7C /* SOSAccountPersistence.c */, - DCC78D201D8085F200865A7C /* SOSAccountLog.c */, + CD9021471DE27A9E00F81DC4 /* SOSAccountPriv.h */, + DCC78D161D8085F200865A7C /* SOSAccountBackup.m */, + DCC78D171D8085F200865A7C /* SOSAccountCircles.m */, + DCC78D1A1D8085F200865A7C /* SOSAccountCloudParameters.m */, + DCC78D1B1D8085F200865A7C /* SOSAccountCredentials.m */, + DCC78D1C1D8085F200865A7C /* SOSAccountDer.m */, + DCC78D1D1D8085F200865A7C /* SOSAccountFullPeerInfo.m */, + 7281E0861DFD015A0021E1B7 /* SOSAccountGetSet.m */, + DCFAEDC81D999851005187E4 /* SOSAccountGhost.m */, + DCFAEDC91D999851005187E4 /* SOSAccountGhost.h */, + DCC78D201D8085F200865A7C /* SOSAccountLog.m */, DCC78D211D8085F200865A7C /* SOSAccountLog.h */, - DCC78D221D8085F200865A7C /* SOSAccountPriv.h */, - DCC78D231D8085F200865A7C /* SOSAccountUpdate.c */, - DCC78D241D8085F200865A7C /* SOSAccountRings.c */, - DCC78D251D8085F200865A7C /* SOSAccountRingUpdate.c */, - DCC78D261D8085F200865A7C /* SOSAccountViewSync.c */, + DCC78D1E1D8085F200865A7C /* SOSAccountPeers.m */, + DCC78D1F1D8085F200865A7C /* SOSAccountPersistence.m */, + 48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.m */, + DCC78D241D8085F200865A7C /* SOSAccountRings.m */, + DCC78D251D8085F200865A7C /* SOSAccountRingUpdate.m */, + DCDCC7E41D9B551C006487E8 /* SOSAccountSync.m */, + DCC78D141D8085F200865A7C /* SOSAccountTransaction.m */, + DCC78D151D8085F200865A7C /* SOSAccountTransaction.h */, + DCC78D231D8085F200865A7C /* SOSAccountUpdate.m */, + DCC78D261D8085F200865A7C /* SOSAccountViewSync.m */, DCC78D271D8085F200865A7C /* SOSBackupEvent.c */, DCC78D281D8085F200865A7C /* SOSBackupEvent.h */, - DCC78D291D8085F200865A7C /* SOSBackupSliceKeyBag.c */, + DCC78D291D8085F200865A7C /* SOSBackupSliceKeyBag.m */, DCC78D2A1D8085F200865A7C /* SOSBackupSliceKeyBag.h */, - 48776C731DA5BB4200CC09B9 /* SOSRecoveryKeyBag.c */, + 48776C731DA5BB4200CC09B9 /* SOSRecoveryKeyBag.m */, 48776C741DA5BB4200CC09B9 /* SOSRecoveryKeyBag.h */, - 48E6171A1DBEC40D0098EAAD /* SOSBackupInformation.c */, + 48E6171A1DBEC40D0098EAAD /* SOSBackupInformation.m */, 48E6171B1DBEC40D0098EAAD /* SOSBackupInformation.h */, - DCC78D2B1D8085F200865A7C /* SOSUserKeygen.c */, + DCC78D2B1D8085F200865A7C /* SOSUserKeygen.m */, DCC78D2C1D8085F200865A7C /* SOSUserKeygen.h */, 485B64081DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.c */, 485B64091DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h */, + DCC78D111D8085F200865A7C /* SOSExports.exp-in */, ); name = Account; sourceTree = ""; @@ -14894,11 +17393,11 @@ DCC78D371D8085F200865A7C /* SOSGenCount.c */, DCC78D381D8085F200865A7C /* SOSGenCount.h */, DCC78D391D8085F200865A7C /* SOSRing.h */, - DCC78D3A1D8085F200865A7C /* SOSRingBackup.c */, + DCC78D3A1D8085F200865A7C /* SOSRingBackup.m */, DCC78D3B1D8085F200865A7C /* SOSRingBackup.h */, - DCC78D3C1D8085F200865A7C /* SOSRingBasic.c */, + DCC78D3C1D8085F200865A7C /* SOSRingBasic.m */, DCC78D3D1D8085F200865A7C /* SOSRingBasic.h */, - 48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.c */, + 48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.m */, 48776C7D1DA5BB5F00CC09B9 /* SOSRingRecovery.h */, DCC78D3E1D8085F200865A7C /* SOSRingConcordanceTrust.c */, DCC78D3F1D8085F200865A7C /* SOSRingConcordanceTrust.h */, @@ -14906,13 +17405,15 @@ DCC78D411D8085F200865A7C /* SOSRingDER.h */, DCC78D421D8085F200865A7C /* SOSRingPeerInfoUtils.c */, DCC78D431D8085F200865A7C /* SOSRingPeerInfoUtils.h */, - DCC78D441D8085F200865A7C /* SOSRingTypes.c */, + DCC78D441D8085F200865A7C /* SOSRingTypes.m */, DCC78D451D8085F200865A7C /* SOSRingTypes.h */, DCC78D461D8085F200865A7C /* SOSRingUtils.c */, DCC78D471D8085F200865A7C /* SOSRingUtils.h */, - DCC78D481D8085F200865A7C /* SOSRingV0.c */, + DCC78D481D8085F200865A7C /* SOSRingV0.m */, DCC78D491D8085F200865A7C /* SOSRingV0.h */, - DCC78D4A1D8085F200865A7C /* SOSViews.c */, + EB75B4931E75A44100E469CC /* SOSPiggyback.h */, + EB75B4941E75A44100E469CC /* SOSPiggyback.m */, + DCC78D4A1D8085F200865A7C /* SOSViews.m */, DCC78D4B1D8085F200865A7C /* SOSViews.h */, DCC78D4C1D8085F200865A7C /* ViewList.list */, DCC78D4D1D8085F200865A7C /* SOSViews.exp-in */, @@ -14937,10 +17438,12 @@ DCC78D591D8085F200865A7C /* SOSManifest.h */, DCC78D5A1D8085F200865A7C /* SOSMessage.c */, DCC78D5B1D8085F200865A7C /* SOSMessage.h */, - DCC78D5C1D8085F200865A7C /* SOSPeer.c */, + DCC78D5C1D8085F200865A7C /* SOSPeer.m */, DCC78D5D1D8085F200865A7C /* SOSPeer.h */, - DCC78D5E1D8085F200865A7C /* SOSPeerCoder.c */, + DCC78D5E1D8085F200865A7C /* SOSPeerCoder.m */, DCC78D5F1D8085F200865A7C /* SOSPeerCoder.h */, + 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */, + 0CD8CB0C1ECA50D10076F37F /* SOSPeerOTRTimer.h */, DC24B5821DA420D700330B48 /* SOSPersist.h */, ); name = Engine; @@ -14949,21 +17452,21 @@ DCC78D711D8085F200865A7C /* PeerInfo */ = { isa = PBXGroup; children = ( - DCC78D611D8085F200865A7C /* SOSFullPeerInfo.c */, + DCC78D611D8085F200865A7C /* SOSFullPeerInfo.m */, DCC78D621D8085F200865A7C /* SOSFullPeerInfo.h */, - DCC78D631D8085F200865A7C /* SOSPeerInfo.c */, + DCC78D631D8085F200865A7C /* SOSPeerInfo.m */, DCC78D641D8085F200865A7C /* SOSPeerInfo.h */, - DCC78D651D8085F200865A7C /* SOSPeerInfoDER.c */, + DCC78D651D8085F200865A7C /* SOSPeerInfoDER.m */, DCC78D661D8085F200865A7C /* SOSPeerInfoDER.h */, - DCC78D671D8085F200865A7C /* SOSPeerInfoV2.c */, + DCC78D671D8085F200865A7C /* SOSPeerInfoV2.m */, DCC78D681D8085F200865A7C /* SOSPeerInfoV2.h */, DCC78D691D8085F200865A7C /* SOSPeerInfoPriv.h */, DCC78D6A1D8085F200865A7C /* SOSPeerInfoCollections.c */, DCC78D6B1D8085F200865A7C /* SOSPeerInfoCollections.h */, DCC78D6C1D8085F200865A7C /* SOSPeerInfoInternal.h */, - DCC78D6D1D8085F200865A7C /* SOSPeerInfoRingState.c */, + DCC78D6D1D8085F200865A7C /* SOSPeerInfoRingState.m */, DCC78D6E1D8085F200865A7C /* SOSPeerInfoRingState.h */, - DCC78D6F1D8085F200865A7C /* SOSPeerInfoSecurityProperties.c */, + DCC78D6F1D8085F200865A7C /* SOSPeerInfoSecurityProperties.m */, DCC78D701D8085F200865A7C /* SOSPeerInfoSecurityProperties.h */, ); name = PeerInfo; @@ -14972,26 +17475,28 @@ DCC78D861D8085F200865A7C /* Transport */ = { isa = PBXGroup; children = ( - DCC78D721D8085F200865A7C /* SOSKVSKeys.c */, + DCC78D721D8085F200865A7C /* SOSKVSKeys.m */, DCC78D731D8085F200865A7C /* SOSKVSKeys.h */, - DCC78D741D8085F200865A7C /* SOSTransport.c */, + DCC78D741D8085F200865A7C /* SOSTransport.m */, DCC78D751D8085F200865A7C /* SOSTransport.h */, - DCC78D761D8085F200865A7C /* SOSTransportBackupPeer.c */, + DCC78D761D8085F200865A7C /* SOSTransportBackupPeer.m */, DCC78D771D8085F200865A7C /* SOSTransportBackupPeer.h */, - DCC78D781D8085F200865A7C /* SOSTransportCircle.c */, + DCC78D781D8085F200865A7C /* SOSTransportCircle.m */, DCC78D791D8085F200865A7C /* SOSTransportCircle.h */, - DCC78D7A1D8085F200865A7C /* SOSTransportCircleKVS.c */, + DCC78D7A1D8085F200865A7C /* SOSTransportCircleKVS.m */, DCC78D7B1D8085F200865A7C /* SOSTransportCircleKVS.h */, - DCC78D7C1D8085F200865A7C /* SOSTransportKeyParameter.c */, + 0C48990A1E0E0FF300C6CF70 /* SOSTransportCircleCK.h */, + 0C4899111E0E105D00C6CF70 /* SOSTransportCircleCK.m */, + DCC78D7C1D8085F200865A7C /* SOSTransportKeyParameter.m */, DCC78D7D1D8085F200865A7C /* SOSTransportKeyParameter.h */, - DCC78D7E1D8085F200865A7C /* SOSTransportKeyParameterKVS.c */, - DCC78D7F1D8085F200865A7C /* SOSTransportKeyParameterKVS.h */, - DCC78D801D8085F200865A7C /* SOSTransportMessage.c */, + DCC78D801D8085F200865A7C /* SOSTransportMessage.m */, DCC78D811D8085F200865A7C /* SOSTransportMessage.h */, - DCC78D821D8085F200865A7C /* SOSTransportMessageIDS.c */, + DCC78D821D8085F200865A7C /* SOSTransportMessageIDS.m */, DCC78D831D8085F200865A7C /* SOSTransportMessageIDS.h */, - DCC78D841D8085F200865A7C /* SOSTransportMessageKVS.c */, + DCC78D841D8085F200865A7C /* SOSTransportMessageKVS.m */, DCC78D851D8085F200865A7C /* SOSTransportMessageKVS.h */, + 0CAC5DBE1EB3DA4C00AD884B /* SOSPeerRateLimiter.m */, + 0CAC5DC51EB3DB3C00AD884B /* SOSPeerRateLimiter.h */, ); name = Transport; sourceTree = ""; @@ -14999,7 +17504,7 @@ DCC78D911D8085F200865A7C /* SecureObjectSync */ = { isa = PBXGroup; children = ( - DCC78D111D8085F200865A7C /* SOSExports.exp-in */, + CD1D64461DD386C9006D4139 /* AccountTrust */, DCC78D2D1D8085F200865A7C /* Account */, DCC78D4E1D8085F200865A7C /* Circle */, DCC78D601D8085F200865A7C /* Engine */, @@ -15007,14 +17512,16 @@ DCC78D861D8085F200865A7C /* Transport */, DCC78D871D8085F200865A7C /* SOSARCDefines.h */, DCC78D881D8085F200865A7C /* SOSECWrapUnwrap.c */, - DCC78D891D8085F200865A7C /* SOSCloudCircle.c */, + DCC78D891D8085F200865A7C /* SOSCloudCircle.m */, DCC78D8A1D8085F200865A7C /* SOSCloudCircle.h */, DCC78D8B1D8085F200865A7C /* SOSCloudCircleInternal.h */, - DCC78D8C1D8085F200865A7C /* SOSSysdiagnose.c */, - DCC78D8D1D8085F200865A7C /* SOSInternal.c */, + DCC78D8C1D8085F200865A7C /* SOSSysdiagnose.m */, + DCC78D8D1D8085F200865A7C /* SOSInternal.m */, DCC78D8E1D8085F200865A7C /* SOSInternal.h */, DCC78D8F1D8085F200865A7C /* SOSTypes.h */, DCC78D901D8085F200865A7C /* SOSPlatform.h */, + EBEEEE351EA31A8300E15F5C /* SOSControlHelper.h */, + EBEEEE361EA31A8300E15F5C /* SOSControlHelper.m */, ); path = SecureObjectSync; sourceTree = ""; @@ -15024,20 +17531,20 @@ children = ( DCC78D921D8085F200865A7C /* secToolFileIO.h */, DCC78D931D8085F200865A7C /* secToolFileIO.c */, - 48BC0F5C1DFA2B4500DDDFF9 /* accountCirclesViewsPrint.c */, - 48BC0F5D1DFA2B4500DDDFF9 /* accountCirclesViewsPrint.h */, DCC78D961D8085F200865A7C /* keychain_sync.h */, - DCC78D971D8085F200865A7C /* keychain_sync.c */, + DCC78D971D8085F200865A7C /* keychain_sync.m */, DCC78D981D8085F200865A7C /* keychain_sync_test.h */, DCC78D991D8085F200865A7C /* keychain_sync_test.m */, DCC78D9A1D8085F200865A7C /* keychain_log.h */, - DCC78D9B1D8085F200865A7C /* keychain_log.c */, + DCC78D9B1D8085F200865A7C /* keychain_log.m */, 0C0CEC9D1DA45EA200C22FBC /* recovery_key.h */, 0C0CEC9E1DA45EA200C22FBC /* recovery_key.m */, - DCC78D9D1D8085F200865A7C /* syncbackup.c */, + DCC78D9D1D8085F200865A7C /* syncbackup.m */, DCC78D9C1D8085F200865A7C /* syncbackup.h */, DCC78D9E1D8085F200865A7C /* secViewDisplay.c */, DCC78D9F1D8085F200865A7C /* secViewDisplay.h */, + 48C2F9321E4BCFC30093D70C /* accountCirclesViewsPrint.m */, + 48C2F9331E4BCFC30093D70C /* accountCirclesViewsPrint.h */, ); path = Tool; sourceTree = ""; @@ -15060,6 +17567,7 @@ DCC78DA41D8085FC00865A7C /* pbkdf2-00-hmac-sha1.c */, DCC78DA51D8085FC00865A7C /* spbkdf-00-hmac-sha1.c */, D4D718341E04A721000AE7A6 /* spbkdf-01-hmac-sha256.c */, + B61577EE1F2021BC004A3930 /* padding-00-mmcs.c */, ); name = crypto; path = Regressions/crypto; @@ -15106,11 +17614,12 @@ isa = PBXGroup; children = ( DCC78DE91D8085FC00865A7C /* signed-receipt.h */, + D4FC521C1EC3E05B00E99785 /* smime_attr_emails.h */, ); path = "si-66-smime"; sourceTree = ""; }; - DCC78DF61D8085FC00865A7C /* si-67-sectrust-blacklist */ = { + DCC78DF61D8085FC00865A7C /* si-67-sectrust-blocklist */ = { isa = PBXGroup; children = ( DCC78DEC1D8085FC00865A7C /* Global Trustee.cer.h */, @@ -15124,7 +17633,7 @@ DCC78DF41D8085FC00865A7C /* mail.google.com.cer.h */, DCC78DF51D8085FC00865A7C /* www.google.com.cer.h */, ); - path = "si-67-sectrust-blacklist"; + path = "si-67-sectrust-blocklist"; sourceTree = ""; }; DCC78E121D8085FC00865A7C /* secitem */ = { @@ -15141,6 +17650,7 @@ DCC78DB71D8085FC00865A7C /* si-15-certificate.c */, DCC78DB81D8085FC00865A7C /* si-16-ec-certificate.c */, DCC78DB91D8085FC00865A7C /* si-17-item-system-bluetooth.m */, + D4AA647C1E97144700D317ED /* si-18-certificate-parse.m */, DCC78DBA1D8085FC00865A7C /* si-20-sectrust-policies.m */, DCC78DBB1D8085FC00865A7C /* si-20-sectrust.c */, DCC78DBC1D8085FC00865A7C /* si-20-sectrust.h */, @@ -15164,6 +17674,8 @@ DCC78DCA1D8085FC00865A7C /* si-30-keychain-upgrade.c */, DCC78DCB1D8085FC00865A7C /* si-31-keychain-bad.c */, DCC78DCC1D8085FC00865A7C /* si-31-keychain-unreadable.c */, + D4CFAA7D1E660BB3004746AA /* si-32-sectrust-pinning-required.m */, + D4C8A1511E66709800CD6DF1 /* si-32-sectrust-pinning-required.h */, DCC78DCD1D8085FC00865A7C /* si-33-keychain-backup.c */, DCC78DCE1D8085FC00865A7C /* si-40-seckey-custom.c */, DCC78DCF1D8085FC00865A7C /* si-40-seckey.c */, @@ -15174,9 +17686,12 @@ DCC78DD41D8085FC00865A7C /* si-44-seckey-rsa.m */, DCC78DD51D8085FC00865A7C /* si-44-seckey-ec.m */, DCC78DD61D8085FC00865A7C /* si-44-seckey-ies.m */, + 5E77936E1E5EFEB20074A2D1 /* si-44-seckey-aks.m */, + 09CB496A1F2F64AF00C8E4DE /* si-44-seckey-fv.m */, DCC78DD71D8085FC00865A7C /* si-50-secrandom.c */, DCC78DD81D8085FC00865A7C /* si-60-cms.c */, DCC78DD91D8085FC00865A7C /* si-61-pkcs12.c */, + D48F029B1EA1671B00ACC3C9 /* si-61-pkcs12.h */, DCC78DDA1D8085FC00865A7C /* si-62-csr.c */, DCC78DDD1D8085FC00865A7C /* si-63-scep */, DCC78DDE1D8085FC00865A7C /* si-63-scep.c */, @@ -15186,8 +17701,8 @@ DCC78DE81D8085FC00865A7C /* si-65-cms-cert-policy.c */, DCC78DEA1D8085FC00865A7C /* si-66-smime */, DCC78DEB1D8085FC00865A7C /* si-66-smime.c */, - DCC78DF61D8085FC00865A7C /* si-67-sectrust-blacklist */, - DCC78DF71D8085FC00865A7C /* si-67-sectrust-blacklist.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 */, @@ -15203,11 +17718,10 @@ DCC78E041D8085FC00865A7C /* si-82-sectrust-ct.m */, DCC78E051D8085FC00865A7C /* si-82-token-ag.c */, DCC78E061D8085FC00865A7C /* si-83-seccertificate-sighashalg.c */, - BE6D96B31DB14B65001B76D4 /* si-84-sectrust-allowlist */, - BE6D96BA1DB14B9F001B76D4 /* si-84-sectrust-allowlist.m */, + BE6215BD1DB6E69100961E15 /* si-84-sectrust-allowlist.m */, DCC78E071D8085FC00865A7C /* si-85-sectrust-ssl-policy.c */, DCC78E081D8085FC00865A7C /* si-85-sectrust-ssl-policy.h */, - DCC78E091D8085FC00865A7C /* si-87-sectrust-name-constraints.c */, + DCC78E091D8085FC00865A7C /* si-87-sectrust-name-constraints.m */, DCC78E0A1D8085FC00865A7C /* si-87-sectrust-name-constraints.h */, DCC78E0B1D8085FC00865A7C /* si-89-cms-hash-agility.c */, DCC78E0C1D8085FC00865A7C /* si-89-cms-hash-agility.h */, @@ -15257,7 +17771,7 @@ DCC78E1D1D8085FC00865A7C /* log_control.c */, DCC78E1E1D8085FC00865A7C /* codesign.c */, DCC78E1F1D8085FC00865A7C /* keychain_add.c */, - DCC78E201D8085FC00865A7C /* keychain_find.c */, + DCC78E201D8085FC00865A7C /* keychain_find.m */, DCC78E221D8085FC00865A7C /* pkcs12_util.c */, DCC78E231D8085FC00865A7C /* scep.c */, DCC78E241D8085FC00865A7C /* SecurityCommands.h */, @@ -15307,11 +17821,8 @@ DC1787461D7790A500B50D50 /* SecCodeHostLib.h */, DC1787471D7790A500B50D50 /* SecCodePriv.h */, DC1787481D7790A500B50D50 /* SecCodeSigner.h */, - DC1787491D7790A500B50D50 /* SecIntegrity.h */, - DC17874A1D7790A500B50D50 /* SecIntegrityLib.h */, DC17874B1D7790A500B50D50 /* SecRequirementPriv.h */, DC17874C1D7790A500B50D50 /* SecStaticCodePriv.h */, - DC17874D1D7790A500B50D50 /* SecTaskPriv.h */, DC1785811D778B7F00B50D50 /* CodeSigning.h */, DC1785821D778B7F00B50D50 /* CSCommon.h */, DC1785831D778B7F00B50D50 /* SecCode.h */, @@ -15362,8 +17873,6 @@ DCD067971D8CDF7E007602F1 /* SecCodeSigner.cpp */, DCD067981D8CDF7E007602F1 /* SecCodeHost.h */, DCD067991D8CDF7E007602F1 /* SecCodeHost.cpp */, - DCD0679A1D8CDF7E007602F1 /* SecIntegrity.h */, - DCD0679B1D8CDF7E007602F1 /* SecIntegrity.cpp */, ); name = API; sourceTree = ""; @@ -15395,6 +17904,7 @@ ); name = "Signing Operations"; sourceTree = ""; + usesTabs = 1; }; DCD067B11D8CDF7E007602F1 /* Code Directory */ = { isa = PBXGroup; @@ -15475,12 +17985,11 @@ ); name = "Disk Representations"; sourceTree = ""; + usesTabs = 1; }; DCD067E91D8CDF7E007602F1 /* Static Support */ = { isa = PBXGroup; children = ( - DCD067E51D8CDF7E007602F1 /* SecIntegrityLib.h */, - DCD067E61D8CDF7E007602F1 /* SecIntegrityLib.c */, DCD067E71D8CDF7E007602F1 /* SecCodeHostLib.h */, DCD067E81D8CDF7E007602F1 /* SecCodeHostLib.c */, ); @@ -15533,8 +18042,6 @@ DCD068051D8CDF7E007602F1 /* Entitlements */ = { isa = PBXGroup; children = ( - DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */, - DCD068041D8CDF7E007602F1 /* SecTask.c */, ); name = Entitlements; sourceTree = ""; @@ -15578,6 +18085,7 @@ ); path = lib; sourceTree = ""; + usesTabs = 1; }; DCD068C21D8CDFFE007602F1 /* antlr */ = { isa = PBXGroup; @@ -15722,31 +18230,25 @@ path = antlr2; sourceTree = ""; }; - DCD06AA81D8E0D3D007602F1 /* utilities */ = { + DCD06AA81D8E0D3D007602F1 /* security_utilities */ = { isa = PBXGroup; children = ( DCD06B3C1D8E0D7D007602F1 /* lib */, DCD06BC31D8E0DC2007602F1 /* derived_src */, DCD06BC71D8E0DD3007602F1 /* DTrace */, ); - name = utilities; + name = security_utilities; sourceTree = ""; }; DCD06B0B1D8E0D7D007602F1 /* Unix */ = { isa = PBXGroup; children = ( - DCD06AF91D8E0D7D007602F1 /* fdmover.h */, - DCD06AFA1D8E0D7D007602F1 /* fdmover.cpp */, - DCD06AFB1D8E0D7D007602F1 /* fdsel.h */, - DCD06AFC1D8E0D7D007602F1 /* fdsel.cpp */, DCD06AFD1D8E0D7D007602F1 /* kq++.h */, DCD06AFE1D8E0D7D007602F1 /* kq++.cpp */, DCD06AFF1D8E0D7D007602F1 /* muscle++.h */, DCD06B001D8E0D7D007602F1 /* muscle++.cpp */, DCD06B011D8E0D7D007602F1 /* pcsc++.h */, DCD06B021D8E0D7D007602F1 /* pcsc++.cpp */, - DCD06B031D8E0D7D007602F1 /* selector.h */, - DCD06B041D8E0D7D007602F1 /* selector.cpp */, DCD06B051D8E0D7D007602F1 /* unix++.h */, DCD06B061D8E0D7D007602F1 /* unix++.cpp */, DCD06B071D8E0D7D007602F1 /* unixchild.h */, @@ -15794,41 +18296,6 @@ name = CoreFoundation; sourceTree = ""; }; - DCD06B391D8E0D7D007602F1 /* Socks */ = { - isa = PBXGroup; - children = ( - DCD06B331D8E0D7D007602F1 /* socks++.h */, - DCD06B341D8E0D7D007602F1 /* socks++.cpp */, - DCD06B351D8E0D7D007602F1 /* socks++4.h */, - DCD06B361D8E0D7D007602F1 /* socks++4.cpp */, - DCD06B371D8E0D7D007602F1 /* socks++5.h */, - DCD06B381D8E0D7D007602F1 /* socks++5.cpp */, - ); - name = Socks; - sourceTree = ""; - }; - DCD06B3A1D8E0D7D007602F1 /* Network */ = { - isa = PBXGroup; - children = ( - DCD06B251D8E0D7D007602F1 /* bufferfifo.h */, - DCD06B261D8E0D7D007602F1 /* bufferfifo.cpp */, - DCD06B271D8E0D7D007602F1 /* buffers.h */, - DCD06B281D8E0D7D007602F1 /* buffers.cpp */, - DCD06B291D8E0D7D007602F1 /* headermap.h */, - DCD06B2A1D8E0D7D007602F1 /* headermap.cpp */, - DCD06B2B1D8E0D7D007602F1 /* hosts.h */, - DCD06B2C1D8E0D7D007602F1 /* hosts.cpp */, - DCD06B2D1D8E0D7D007602F1 /* inetreply.h */, - DCD06B2E1D8E0D7D007602F1 /* inetreply.cpp */, - DCD06B2F1D8E0D7D007602F1 /* ip++.h */, - DCD06B301D8E0D7D007602F1 /* ip++.cpp */, - DCD06B311D8E0D7D007602F1 /* url.h */, - DCD06B321D8E0D7D007602F1 /* url.cpp */, - DCD06B391D8E0D7D007602F1 /* Socks */, - ); - name = Network; - sourceTree = ""; - }; DCD06B3C1D8E0D7D007602F1 /* lib */ = { isa = PBXGroup; children = ( @@ -15865,9 +18332,6 @@ DCD06ACF1D8E0D7D007602F1 /* globalizer.cpp */, DCD06AD01D8E0D7D007602F1 /* hashing.h */, DCD06AD11D8E0D7D007602F1 /* hashing.cpp */, - DCD06AD21D8E0D7D007602F1 /* iodevices.h */, - DCD06AD31D8E0D7D007602F1 /* iodevices.cpp */, - DCD06AD41D8E0D7D007602F1 /* ktracecodes.h */, DCD06AD51D8E0D7D007602F1 /* logging.h */, DCD06AD61D8E0D7D007602F1 /* logging.cpp */, DCD06AD71D8E0D7D007602F1 /* memstreams.h */, @@ -15899,15 +18363,12 @@ DCD06AF11D8E0D7D007602F1 /* trackingallocator.cpp */, DCD06AF21D8E0D7D007602F1 /* transactions.cpp */, DCD06AF31D8E0D7D007602F1 /* transactions.h */, - DCD06AF41D8E0D7D007602F1 /* typedvalue.cpp */, - DCD06AF51D8E0D7D007602F1 /* typedvalue.h */, DCD06AF61D8E0D7D007602F1 /* utilities.h */, DCD06AF71D8E0D7D007602F1 /* utilities.cpp */, DCD06AF81D8E0D7D007602F1 /* utility_config.h */, DCD06B0B1D8E0D7D007602F1 /* Unix */, DCD06B1B1D8E0D7D007602F1 /* Mach */, DCD06B241D8E0D7D007602F1 /* CoreFoundation */, - DCD06B3A1D8E0D7D007602F1 /* Network */, ); name = lib; path = OSX/libsecurity_utilities/lib; @@ -15930,10 +18391,88 @@ path = OSX/libsecurity_utilities; sourceTree = ""; }; + DCD662EB1E32946000188186 /* Sync Objects */ = { + isa = PBXGroup; + children = ( + DC35021A1E009E0700BC0587 /* Database Helpers */, + DC378B3A1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.h */, + DC378B3B1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m */, + DC9B7AE61DCBF651004E9385 /* CKKSOutgoingQueueEntry.h */, + DC9B7AE41DCBF604004E9385 /* CKKSOutgoingQueueEntry.m */, + DC378B2C1DEF9DF000A3DAFA /* CKKSMirrorEntry.h */, + DC378B2E1DEF9E0E00A3DAFA /* CKKSMirrorEntry.m */, + DC378B361DEFADB500A3DAFA /* CKKSZoneStateEntry.h */, + DC378B371DEFADB500A3DAFA /* CKKSZoneStateEntry.m */, + DCFE1C251F17E455007640C8 /* CKKSDeviceStateEntry.h */, + DCFE1C261F17E455007640C8 /* CKKSDeviceStateEntry.m */, + DC4DB14E1E24692100CD6769 /* CKKSKey.h */, + DC4DB14F1E24692100CD6769 /* CKKSKey.m */, + DCA4D1F31E5520550056214F /* CKKSCurrentKeyPointer.h */, + DCA4D1F41E5520550056214F /* CKKSCurrentKeyPointer.m */, + DCEA5D531E2826DB0089CF55 /* CKKSSIV.h */, + DCEA5D541E2826DB0089CF55 /* CKKSSIV.m */, + DCE278DB1ED789EF0083B485 /* CKKSCurrentItemPointer.h */, + DCE278DC1ED789EF0083B485 /* CKKSCurrentItemPointer.m */, + ); + name = "Sync Objects"; + sourceTree = ""; + }; + DCD662F11E32946E00188186 /* Operations */ = { + isa = PBXGroup; + children = ( + DCA4D2191E569FFE0056214F /* Helpers */, + DC5BB4F01E0C86800010F836 /* CKKSIncomingQueueOperation.h */, + DC5BB4F11E0C86800010F836 /* CKKSIncomingQueueOperation.m */, + DC5BB4FC1E0C98320010F836 /* CKKSOutgoingQueueOperation.h */, + DC5BB4FD1E0C98320010F836 /* CKKSOutgoingQueueOperation.m */, + DC15F7641E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.h */, + DC15F7651E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m */, + DCD662F31E329B6800188186 /* CKKSNewTLKOperation.h */, + DCD662F41E329B6800188186 /* CKKSNewTLKOperation.m */, + DC7A17EB1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h */, + DC7A17EC1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m */, + DCA4D2131E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h */, + DCA4D2141E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m */, + DC1DA65C1E4554620094CE7F /* CKKSScanLocalItemsOperation.h */, + DC1DA6671E4555D80094CE7F /* CKKSScanLocalItemsOperation.m */, + DCB5D9391E4A9A3400BE22AB /* CKKSSynchronizeOperation.h */, + DCB5D93A1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m */, + DCE278E61ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h */, + DCE278E71ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m */, + DCFE1C4F1F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h */, + DCFE1C501F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m */, + ); + name = Operations; + sourceTree = ""; + }; + DCD662F21E3294DE00188186 /* CloudKit Support */ = { + isa = PBXGroup; + children = ( + DC9082C21EA0276000D0C1C5 /* CKKSZoneChangeFetcher.h */, + DC9082C31EA0276000D0C1C5 /* CKKSZoneChangeFetcher.m */, + DC222CA91E08C57400B09171 /* CloudKitDependencies.h */, + DCEA5D831E2F14810089CF55 /* CKKSAPSReceiver.h */, + DCEA5D841E2F14810089CF55 /* CKKSAPSReceiver.m */, + DCEA5D951E3014250089CF55 /* CKKSZone.h */, + DCEA5D961E3014250089CF55 /* CKKSZone.m */, + DC18F76D1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h */, + DC18F76E1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m */, + DCFB12C31E95A4C000510F5F /* CKKSCKAccountStateTracker.h */, + DCFB12C41E95A4C000510F5F /* CKKSCKAccountStateTracker.m */, + DC2C5F5A1F0EB97E00FEBDA7 /* CKKSNotifier.h */, + DC2C5F5B1F0EB97E00FEBDA7 /* CKKSNotifier.m */, + DC94BCC81F10448600E07CEB /* CloudKitCategories.h */, + DC94BCC91F10448600E07CEB /* CloudKitCategories.m */, + ); + name = "CloudKit Support"; + sourceTree = ""; + }; DCE4E6D61D7A420100AFB96E /* SecurityTestsOSX */ = { isa = PBXGroup; children = ( + ACBAF6FF1E947E860007BA2F /* testlist.h */, DCE4E6D71D7A420D00AFB96E /* main.m */, + 5E3A59421E60283C0006722E /* SecurityTests-Entitlements.plist */, ); name = SecurityTestsOSX; path = ..; @@ -15951,31 +18490,79 @@ DCE4E85A1D7A583100AFB96E /* trustd */ = { isa = PBXGroup; children = ( - DCE4E85E1D7A585300AFB96E /* launchdaemon */, - DCE4E85D1D7A584D00AFB96E /* launchagent */, + D4BEECE61E93093A00F76D1A /* trustd.c */, + D43DBED51E99D17100C04AEA /* asynchttp.c */, + D43DBED61E99D17100C04AEA /* asynchttp.h */, + D43DBED71E99D17100C04AEA /* nameconstraints.c */, + D43DBED81E99D17100C04AEA /* nameconstraints.h */, + D43DBED91E99D17100C04AEA /* OTATrustUtilities.c */, + D43DBEDA1E99D17100C04AEA /* OTATrustUtilities.h */, + D43DBEDB1E99D17100C04AEA /* personalization.c */, + D43DBEDC1E99D17100C04AEA /* personalization.h */, + D43DBEDD1E99D17100C04AEA /* policytree.c */, + D43DBEDE1E99D17200C04AEA /* policytree.h */, + D43DBEDF1E99D17200C04AEA /* SecCAIssuerCache.c */, + D43DBEE01E99D17200C04AEA /* SecCAIssuerCache.h */, + D43DBEE11E99D17200C04AEA /* SecCAIssuerRequest.c */, + D43DBEE21E99D17200C04AEA /* SecCAIssuerRequest.h */, + D43DBEE31E99D17200C04AEA /* SecCertificateServer.c */, + D43DBEE41E99D17200C04AEA /* SecCertificateServer.h */, + D43DBEE51E99D17200C04AEA /* SecCertificateSource.c */, + D43DBEE61E99D17200C04AEA /* SecCertificateSource.h */, + D43DBEE71E99D17200C04AEA /* SecOCSPCache.c */, + D43DBEE81E99D17200C04AEA /* SecOCSPCache.h */, + D43DBEE91E99D17200C04AEA /* SecOCSPRequest.c */, + D43DBEEA1E99D17200C04AEA /* SecOCSPRequest.h */, + D43DBEEB1E99D17200C04AEA /* SecOCSPResponse.c */, + D43DBEEC1E99D17200C04AEA /* SecOCSPResponse.h */, + D43DBEED1E99D17200C04AEA /* SecPinningDb.h */, + D43DBEEE1E99D17200C04AEA /* SecPinningDb.m */, + D43DBEEF1E99D17300C04AEA /* SecPolicyServer.c */, + D43DBEF01E99D17300C04AEA /* SecPolicyServer.h */, + D43DBEF11E99D17300C04AEA /* SecRevocationDb.c */, + D43DBEF21E99D17300C04AEA /* SecRevocationDb.h */, + D43761641EB2996C00954447 /* SecRevocationNetworking.h */, + D43761651EB2996C00954447 /* SecRevocationNetworking.m */, + D43DBEF31E99D17300C04AEA /* SecRevocationServer.c */, + D43DBEF41E99D17300C04AEA /* SecRevocationServer.h */, + D43DBEF51E99D17300C04AEA /* SecTrustLoggingServer.c */, + D43DBEF61E99D17300C04AEA /* SecTrustLoggingServer.h */, + D43DBEF71E99D17300C04AEA /* SecTrustServer.c */, + D43DBEF81E99D17300C04AEA /* SecTrustServer.h */, + D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */, + D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */, + D4ADA30E1E2B1E650031CEA3 /* trustd-Info.plist */, + DCE4E85E1D7A585300AFB96E /* macOS */, + DCE4E85D1D7A584D00AFB96E /* iOS */, ); name = trustd; sourceTree = ""; }; - DCE4E85D1D7A584D00AFB96E /* launchagent */ = { + DCE4E85D1D7A584D00AFB96E /* iOS */ = { isa = PBXGroup; children = ( - DCE4E85B1D7A583A00AFB96E /* com.apple.trustd.agent.plist */, + D41257EE1E941DA800781F23 /* com.apple.trustd.plist */, + D45068691E948ACE00FA7675 /* entitlements.plist */, ); - name = launchagent; + name = iOS; sourceTree = ""; }; - DCE4E85E1D7A585300AFB96E /* launchdaemon */ = { + DCE4E85E1D7A585300AFB96E /* macOS */ = { isa = PBXGroup; children = ( - DCE4E85C1D7A584000AFB96E /* com.apple.trustd.plist */, + D45068681E948A9E00FA7675 /* entitlements.plist */, + D41257EC1E941CF200781F23 /* trustd.8 */, + D41257EB1E941CF200781F23 /* com.apple.trustd.sb */, + D41257EA1E941CF200781F23 /* com.apple.trustd.plist */, + D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */, ); - name = launchdaemon; + name = macOS; sourceTree = ""; }; DCE4E8A01D7F352600AFB96E /* authd */ = { isa = PBXGroup; children = ( + F6A3CB0D1E7062BA00E7821F /* authd-Entitlements.plist */, DC24B5581DA326B900330B48 /* agent.h */, DC24B5591DA326B900330B48 /* authdb.h */, DC24B55A1DA326B900330B48 /* authitems.h */, @@ -16005,7 +18592,6 @@ DCE4E8A61D7F353900AFB96E /* ccaudit.c */, DCE4E8A71D7F353900AFB96E /* crc.c */, DCE4E8A81D7F353900AFB96E /* credential.c */, - DCE4E8A91D7F353900AFB96E /* debugging.c */, DCE4E8AA1D7F353900AFB96E /* engine.c */, DCE4E8AB1D7F353900AFB96E /* main.c */, DCE4E8AC1D7F353900AFB96E /* mechanism.c */, @@ -16093,6 +18679,7 @@ DCE4E9441D7F3E8700AFB96E /* Localizable.strings */, DCE4E9461D7F3E8700AFB96E /* com.apple.security.keychain-circle-notification.plist */, DCE4E9471D7F3E8700AFB96E /* InfoPlist.strings */, + EB76B75A1DCB0CDA00C43FBC /* Keychain Circle Notification.8 */, ); name = resources; sourceTree = ""; @@ -16729,6 +19316,17 @@ path = OSX/libsecurity_apple_x509_tp/lib; sourceTree = ""; }; + DCFE1C311F17ECC3007640C8 /* dispatch Support */ = { + isa = PBXGroup; + children = ( + DCD6C4B01EC5302400414FEE /* CKKSNearFutureScheduler.h */, + DCD6C4B11EC5302500414FEE /* CKKSNearFutureScheduler.m */, + DCFE1C321F17ECE5007640C8 /* CKKSCondition.h */, + DCFE1C331F17ECE5007640C8 /* CKKSCondition.m */, + ); + name = "dispatch Support"; + sourceTree = ""; + }; E710C74A1331946500F85568 /* SecurityTests */ = { isa = PBXGroup; children = ( @@ -16737,6 +19335,7 @@ 4CC92B1B15A3BF2F00C6D578 /* testmain.c */, D4D886E81CEBDD2A00DC7583 /* nist-certs */, D4D886BE1CEB9F3B00DC7583 /* ssl-policy-certs */, + D4AA64831E97270300D317ED /* si-18-certificate-parse */, D4EC94FA1CEA482D0083E753 /* si-20-sectrust-policies-data */, 0C0C88771CCEC5BD00617D1B /* si-82-sectrust-ct-data */, DCE4E72E1D7A436300AFB96E /* si-82-sectrust-ct-logs.plist */, @@ -16796,7 +19395,7 @@ E7A5F4CB1C0CFF3300F3BEBB /* cloudkeychain.entitlements.plist */, 8E64DB4C1C17CD3F0076C9DF /* com.apple.security.cloudkeychainproxy3.ios.plist */, 8E64DB4D1C17CD400076C9DF /* com.apple.security.cloudkeychainproxy3.osx.plist */, - DC24B5851DA432E900330B48 /* CloudKeychainProxy.1 */, + DC24B5851DA432E900330B48 /* CloudKeychainProxy.8 */, ); name = "Supporting Files"; sourceTree = ""; @@ -16808,6 +19407,8 @@ 7901790F12D51F7200CA4D44 /* SecCmsContentInfo.h */, 7901791012D51F7200CA4D44 /* SecCmsDecoder.h */, 7901791112D51F7200CA4D44 /* SecCmsDigestContext.h */, + D4FBBD601DD66196004408F7 /* CMSEncoder.h */, + D4FBBD611DD66196004408F7 /* CMSDecoder.h */, 7901791212D51F7200CA4D44 /* SecCmsEncoder.h */, 7901791312D51F7200CA4D44 /* SecCmsEnvelopedData.h */, 7901791412D51F7200CA4D44 /* SecCmsMessage.h */, @@ -16844,6 +19445,8 @@ E75C0E841C71325000E6953B /* KeychainCircle.h */, E7F480301C73FC4C00390FDB /* KCAESGCMDuplexSession.h */, E7F480311C73FC4C00390FDB /* KCAESGCMDuplexSession.m */, + EB413B751E6624A400592085 /* PairingChannel.h */, + EB413B761E6624A500592085 /* PairingChannel.m */, ); name = KeychainCircle.framework; path = KeychainCircle; @@ -16866,6 +19469,8 @@ E7F4809B1C74E85200390FDB /* KCDerTest.m */, E7F4809D1C74E86D00390FDB /* KCAESGCMTest.m */, E7F4826F1C74FDD100390FDB /* KCJoiningSessionTest.m */, + EB108F121E6CE48B003B0456 /* KCParing.plist */, + EB413B7E1E663A8300592085 /* KCPairingTest.m */, ); name = Tests; sourceTree = ""; @@ -16873,8 +19478,31 @@ E7FCBE401314471B000DE34E /* Frameworks */ = { isa = PBXGroup; children = ( + 5EAFA4CD1EF16059002DC188 /* LocalAuthentication.framework */, + D41D36701EB14D87007FA978 /* libDiagnosticMessagesClient.tbd */, + D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */, + EB59D66B1E95EF2900997EAC /* libcompression.dylib */, + 474B5FBF1E662E21007546F8 /* SecurityFoundation.framework */, + 4738AE241E732D7E006BD53D /* SharedWebCredentials.framework */, + DCCA5E831E539EE7009EE93D /* AppKit.framework */, + 6CE22D6F1E49206600974785 /* UIKit.framework */, + 6CCDF78B1E3C26BC003F2555 /* XCTest.framework */, + 6C5232D41E3C183F00330DB1 /* CloudKit.framework */, + D40B6A871E2B5F9900CD6EE5 /* CoreFoundation.framework */, + D40B6A881E2B5F9900CD6EE5 /* Foundation.framework */, + 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */, + 6C0B0C3D1E2537C6007F95E5 /* WirelessDiagnostics.framework */, + EB10557A1E14DF640003C309 /* Security.framework */, + 0CAD1E221E032D4000537693 /* AggregateDictionary.framework */, + CDA43D251DFCA0790038E038 /* AggregateDictionary.framework */, + CD2F99D91DFC995B00769430 /* libsqlite3.0.dylib */, + DC3502DA1E02121800BC0587 /* CryptoTokenKit.framework */, + DC9EBA311DEE768000D0F733 /* CloudKit.framework */, + DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */, + DC27B57D1DDFC24500599261 /* libsqlite3.0.dylib */, BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */, - EB3EBF0F1DBD413600620B2C /* libobjc.dylib */, + EBF3745E1DBFB32A0065D840 /* libobjc.dylib */, + DC3A81D41D99D567000C7419 /* libcoretls_cfhelpers.dylib */, DC59EA731D91CBD0001BDDF5 /* libcrypto.dylib */, DC5AC0C61D8353C800CF422C /* PCSC.framework */, DC52EC6A1D80D0E300B0A59C /* IDSFoundation.framework */, @@ -16905,6 +19533,7 @@ 4C7913241799A5CB00A9633E /* MobileCoreServices.framework */, D4B858661D370D9A003B2D95 /* MobileCoreServices.framework */, E7FC30AB1332DE9000802946 /* MobileKeyBag.framework */, + DC3502E81E02172C00BC0587 /* OCMock.framework */, 5E1D7E0319A5EBB700D322DA /* Preferences.framework */, 43DB542E1BB1F85B0083C3F1 /* ProtectedCloudStorage.framework */, 52D82BD316A5EADA0078DFE5 /* Security.framework */, @@ -16927,10 +19556,8 @@ DC1789181D77998C00B50D50 /* libbsm.dylib */, E7F482A51C75453900390FDB /* libcoreauthd_test_client.a */, 0CFC029B1D41650700E6283B /* libcoretls.dylib */, - DCE4E6D91D7A421D00AFB96E /* libcoretls.dylib */, E7F482A21C7544E600390FDB /* libctkclient_test.a */, EBE54D771BE33227000C4856 /* libmis.dylib */, - DC17891A1D77999200B50D50 /* libobjc.dylib */, DC17891C1D77999700B50D50 /* libpam.dylib */, DCE4E81B1D7A4E8F00AFB96E /* libsqlite3.0.dylib */, DC17891E1D77999D00B50D50 /* libsqlite3.dylib */, @@ -16950,27 +19577,60 @@ name = secedumodetest; sourceTree = ""; }; + EB1055641E14DB370003C309 /* secfuzzer */ = { + isa = PBXGroup; + children = ( + EBB8399B1E295B8F00853BAC /* secfuzzer.m */, + EB10556A1E14DB7E0003C309 /* certificates */, + EB10556B1E14DC0F0003C309 /* SecCertificateFuzzer.c */, + ); + name = secfuzzer; + path = tests/secfuzzer; + sourceTree = ""; + }; + EB10556A1E14DB7E0003C309 /* certificates */ = { + isa = PBXGroup; + children = ( + ); + path = certificates; + sourceTree = ""; + }; + EB27FF051E402C3C00EC9E3A /* ckksctl */ = { + isa = PBXGroup; + children = ( + EB27FF0B1E402C8000EC9E3A /* ckksctl.h */, + EB27FF0C1E402C8000EC9E3A /* ckksctl.m */, + EB27FF2F1E408CC900EC9E3A /* ckksctl-Entitlements.plist */, + ); + path = ckksctl; + sourceTree = ""; + }; EB2CA5311D2C30CD00AB770F /* xcconfig */ = { isa = PBXGroup; children = ( + DC5225091E402D8B0021640A /* PlatformLibraries.xcconfig */, + DC976C581E3AC5E50012A6DD /* PlatformFeatures.xcconfig */, EB2CA5561D2C30F700AB770F /* Security.xcconfig */, D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */, DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */, DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */, - DCC78EA31D80870D00865A7C /* lib_ios_debug.xcconfig */, - DC71D8DD1D94CF3C0065FB93 /* lib_ios_debug_shim.xcconfig */, - DCC78EA41D80870D00865A7C /* lib_ios_release.xcconfig */, - DC71D8DE1D94CF6A0065FB93 /* lib_ios_release_shim.xcconfig */, + DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */, D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */, - D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */, - D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */, - D47C56AF1DCA841D00E18518 /* lib_ios_x64_debug_shim.xcconfig */, - D47C56B01DCA843800E18518 /* lib_ios_x64_release_shim.xcconfig */, + D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */, DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */, + BE8351D41EC0EEDD00ACD5FD /* framework_requiring_modern_objc_runtime.xcconfig */, ); name = xcconfig; sourceTree = ""; }; + EB2D549F1F02A25700E46890 /* SecAtomicFile */ = { + isa = PBXGroup; + children = ( + EB2D54A01F02A28200E46890 /* SecAtomicFile.cpp */, + ); + path = SecAtomicFile; + sourceTree = ""; + }; EB425CCC1C6584A9000ECE53 /* secbackuptest */ = { isa = PBXGroup; children = ( @@ -17011,12 +19671,17 @@ children = ( EB9C1DAD1BDFD49400F89272 /* Security.plist */, EB3A8DD71BEEC4D6001A89AA /* Security_edumode.plist */, + EB2D549F1F02A25700E46890 /* SecAtomicFile */, EB9C1D7C1BDFD0E100F89272 /* secbackupntest */, EB425CCC1C6584A9000ECE53 /* secbackuptest */, EB0BC9641C3C792E00785842 /* secedumodetest */, EBCF73CC1CE45F3F00BED7CA /* secitemfunctionality */, + BED208E31EDF95BB00753952 /* manifeststresstest */, EBA9AA561CE30C91004E2B68 /* secitemnotifications */, EB4339F61CC323F000A7EACE /* secitemstresstest */, + 470415D01E5E14B6001F3D95 /* seckeychainnetworkextensionstest */, + 47702B1F1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */, + 47702B2F1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */, ); path = RegressionTests; sourceTree = ""; @@ -17049,6 +19714,24 @@ path = "security-sysdiagnose"; sourceTree = ""; }; + F621D0801ED6EA4C000EA569 /* authorizationdump */ = { + isa = PBXGroup; + children = ( + F619D71D1ED70BB0005B5F46 /* main.m */, + ); + name = authorizationdump; + sourceTree = ""; + }; + F667EC541E96E8C800203D5C /* authdtests */ = { + isa = PBXGroup; + children = ( + F667EC551E96E94800203D5C /* main.m */, + F6A0971E1E953A1500B1E7D6 /* authdtestlist.h */, + F6A0971F1E953ABD00B1E7D6 /* authdtests.m */, + ); + name = authdtests; + sourceTree = ""; + }; F93C49391AB8FF530047E01A /* ckcdiagnose */ = { isa = PBXGroup; children = ( @@ -17060,6 +19743,22 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 225394B01E3080A600D3CD9B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 225394D31E3083C600D3CD9B /* SecCodeHost.h in Headers */, + 225394D41E3083D000D3CD9B /* CodeSigning.h in Headers */, + 225394D51E3083DA00D3CD9B /* CSCommon.h in Headers */, + 225394D61E3083E300D3CD9B /* SecCode.h in Headers */, + 225394D71E3083ED00D3CD9B /* SecStaticCode.h in Headers */, + 225394D81E3083F700D3CD9B /* SecRequirement.h in Headers */, + 2296B0E61E32EF08000D1EA7 /* requirement.h in Headers */, + 2296B0EC1E32EF10000D1EA7 /* cs.h in Headers */, + 225394DB1E30864B00D3CD9B /* CSCommonPriv.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4C32C0AA0A4975F6002891BD /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -17082,6 +19781,7 @@ 4C12828D0BB4957D00985BB0 /* SecTrustSettingsPriv.h in Headers */, CDDE9BD11729ABFA0013B0E8 /* SecPasswordGenerate.h in Headers */, 4C7072860AC9EA4F007CC205 /* SecKey.h in Headers */, + 476541651F339F6300413F65 /* SecdWatchdog.h in Headers */, 4C7072D40AC9ED5A007CC205 /* SecKeyPriv.h in Headers */, 4C7073CA0ACB2BAD007CC205 /* SecRSAKey.h in Headers */, EB6928C51D9C9C6E00062A18 /* SecRecoveryKey.h in Headers */, @@ -17090,6 +19790,7 @@ 4C64E01C0B8FBC71009B306C /* SecIdentity.h in Headers */, 4C64E01D0B8FBC7E009B306C /* Security.h in Headers */, E7676DB619411DF300498DD4 /* SecServerEncryptionSupport.h in Headers */, + F964772C1E5832540019E4EB /* SecCodePriv.h in Headers */, 4C4296320BB0A68200491999 /* SecTrustSettings.h in Headers */, 4CBA0E880BB33C0000E72B55 /* SecPolicy.h in Headers */, 4C6416D50BB34F00001C83FD /* SecPolicyPriv.h in Headers */, @@ -17097,23 +19798,31 @@ 4CD3BA621106FF4D00BE8B75 /* SecECKey.h in Headers */, 4C6416F10BB357D5001C83FD /* SecInternal.h in Headers */, 443381ED18A3D83100215606 /* SecAccessControl.h in Headers */, + 4723C9C61F152EC00082882F /* SFSQLite.h in Headers */, 4C1B442D0BB9CAF900461B82 /* SecTrustStore.h in Headers */, DC3C7AB81D838C6F00F6A832 /* oidsalg.h in Headers */, + B61F67561F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h in Headers */, 4CF41D0C0BBB4022005F3248 /* SecCertificatePath.h in Headers */, 4C2F81D50BF121D2003C4F77 /* SecRandom.h in Headers */, + ACBAF6EE1E941AE00007BA2F /* transform_regressions.h in Headers */, 7940D4130C3ACF9000FDB5D8 /* SecDH.h in Headers */, 790850F70CA88AE10083CC4D /* securityd_client.h in Headers */, 795CA9CE0D38435E00BAE6A2 /* p12pbegen.h in Headers */, 79EF5B730D3D6AFE009F5270 /* p12import.h in Headers */, + 4723C9C21F152EB50082882F /* SFObjCType.h in Headers */, 4CE7EA791AEAF39C0067F5BD /* SecItemBackup.h in Headers */, + 222F23A01DAC1603007ACB90 /* SecTaskPriv.h in Headers */, DC3C7AB51D838C1300F6A832 /* SecAsn1Templates.h in Headers */, 79EF5B6E0D3D6A31009F5270 /* SecImportExport.h in Headers */, + 4723C9CA1F152ECE0082882F /* SFSQLiteStatement.h in Headers */, 4CCE0ADA0D41797400DDBB21 /* SecIdentityPriv.h in Headers */, + 4723C9DC1F1540CE0082882F /* SFAnalyticsLogger.h in Headers */, 4CCE0ADE0D4179E500DDBB21 /* SecBasePriv.h in Headers */, 4CFBF6100D5A951100969BBE /* SecPolicyInternal.h in Headers */, DC3C7AB91D838C8D00F6A832 /* oids.h in Headers */, 4C87F3A80D611C26000E7104 /* SecTrustPriv.h in Headers */, 79BDD3C20D60DB84000D84D3 /* SecCMS.h in Headers */, + DC2C5F4B1F0D935200FEBDA7 /* CKKSControlProtocol.h in Headers */, 107226D30D91DB32003CF14F /* SecTask.h in Headers */, 4C7CE5700DC7DC6600AE53FC /* SecEntitlements.h in Headers */, 791766DE0DD0162C00F3B974 /* SecCertificateRequest.h in Headers */, @@ -17137,6 +19846,15 @@ 8E02FA6B1107BE460043545E /* pbkdf2.h in Headers */, 8ED6F6CA110904E300D2B368 /* SecPBKDF.h in Headers */, 7901791812D51F7200CA4D44 /* SecCmsBase.h in Headers */, + D4FBBD631DD661AD004408F7 /* CMSDecoder.h in Headers */, + D4FBBD621DD661A7004408F7 /* CMSEncoder.h in Headers */, + 22A23B3A1E3AAC9800C41830 /* CodeSigning.h in Headers */, + 22A23B3B1E3AAC9800C41830 /* CSCommon.h in Headers */, + 22A23B3C1E3AAC9800C41830 /* SecCode.h in Headers */, + 22A23B3D1E3AAC9800C41830 /* SecStaticCode.h in Headers */, + 724340BA1ED3FEC800F8F566 /* SecSMIME.h in Headers */, + 22A23B3E1E3AAC9800C41830 /* SecRequirement.h in Headers */, + 22A23B3F1E3AAC9800C41830 /* SecCodeHost.h in Headers */, DC3C7AB61D838C2D00F6A832 /* SecAsn1Types.h in Headers */, DC3C73551D837B2C00F6A832 /* SOSPeerInfoPriv.h in Headers */, 7901791912D51F7200CA4D44 /* SecCmsContentInfo.h in Headers */, @@ -17153,6 +19871,46 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + ACBAF69A1E9417F40007BA2F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ACBAF6EF1E941AE00007BA2F /* transform_regressions.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BEF88C251EAFFC3F00357577 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + BEF88C911EB000BE00357577 /* TPVoucher.h in Headers */, + BEF88C8D1EB000BE00357577 /* TPSigningKey.h in Headers */, + BEF88C7D1EB000BE00357577 /* TPHash.h in Headers */, + BEF88C7C1EB000BE00357577 /* TPEncrypter.h in Headers */, + BEF88C8B1EB000BE00357577 /* TPPolicyDocument.h in Headers */, + BEF88C8F1EB000BE00357577 /* TPUtils.h in Headers */, + BEF88C7F1EB000BE00357577 /* TPModel.h in Headers */, + BEF88C791EB000BE00357577 /* TPCircle.h in Headers */, + BE61F5AF1EB0060C00556CCF /* TrustedPeers.h in Headers */, + BEF88C891EB000BE00357577 /* TPPolicy.h in Headers */, + BEF88C871EB000BE00357577 /* TPPeerStableInfo.h in Headers */, + BEF88C7B1EB000BE00357577 /* TPDecrypter.h in Headers */, + BEF88C771EB000BE00357577 /* TPCategoryRule.h in Headers */, + BEF88C8E1EB000BE00357577 /* TPTypes.h in Headers */, + BEF88C811EB000BE00357577 /* TPPeer.h in Headers */, + BEF88C831EB000BE00357577 /* TPPeerDynamicInfo.h in Headers */, + BEF88C851EB000BE00357577 /* TPPeerPermanentInfo.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D4ADA3171E2B41670031CEA3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D43761661EB2996C00954447 /* SecRevocationNetworking.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC0067951D87876F005AF8DB /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -17399,7 +20157,6 @@ DC0BCA011D8B827200070CB0 /* SecureTransportPriv.h in Headers */, DC0BC9FE1D8B827200070CB0 /* CipherSuite.h in Headers */, DC0BC9FF1D8B827200070CB0 /* SecureTransport.h in Headers */, - DC0BCA0F1D8B827200070CB0 /* sslUtils.h in Headers */, DC0BCA0A1D8B827200070CB0 /* sslDebug.h in Headers */, DC0BCA021D8B827200070CB0 /* sslCipherSpecs.h in Headers */, DC0BC9FD1D8B827200070CB0 /* tlsCallbacks.h in Headers */, @@ -17530,27 +20287,28 @@ DC0BCDA21D8C6A1F00070CB0 /* iOSforOSX.h in Headers */, DC0BCD801D8C6A1E00070CB0 /* SecCFCCWrappers.h in Headers */, DC0BCDA91D8C6A1F00070CB0 /* SecFileLocations.h in Headers */, - DC0BCD741D8C6A1E00070CB0 /* SecMeta.h in Headers */, DC0BCD951D8C6A1E00070CB0 /* der_date.h in Headers */, DC0BCD861D8C6A1E00070CB0 /* SecDispatchRelease.h in Headers */, DC0BCD7C1D8C6A1E00070CB0 /* SecCoreCrypto.h in Headers */, DC0BCDA01D8C6A1F00070CB0 /* fileIo.h in Headers */, DC0BCD7A1D8C6A1E00070CB0 /* SecBuffer.h in Headers */, - DC0BCD7E1D8C6A1E00070CB0 /* SecCertificateTrace.h in Headers */, DC0BCD9B1D8C6A1F00070CB0 /* der_plist_internal.h in Headers */, DC0BCDAD1D8C6A1F00070CB0 /* SecSCTUtils.h in Headers */, DC0BCDB21D8C6A1F00070CB0 /* SecInternalReleasePriv.h in Headers */, DC0BCD831D8C6A1E00070CB0 /* SecCFWrappers.h in Headers */, DC0BCDB01D8C6A1F00070CB0 /* SecAppleAnchorPriv.h in Headers */, + B61577EC1F201562004A3930 /* SecPaddingConfigurationsPriv.h in Headers */, DC65E7C11D8CBB1500152EF0 /* readline.h in Headers */, EB4B6E261DC0683600AFC494 /* SecADWrapper.h in Headers */, DC0BCDAA1D8C6A1F00070CB0 /* SecXPCError.h in Headers */, + 72CDF5131EC679A4002D233B /* sec_action.h in Headers */, DC0BCD8F1D8C6A1E00070CB0 /* debugging_test.h in Headers */, DC0BCD781D8C6A1E00070CB0 /* SecAKSWrappers.h in Headers */, DC0BCDA71D8C6A1F00070CB0 /* SecDb.h in Headers */, DC0BCDA11D8C6A1F00070CB0 /* sqlutils.h in Headers */, DC963EC61D95F646008A153E /* der_plist.h in Headers */, DC0BCD8E1D8C6A1E00070CB0 /* debugging.h in Headers */, + EB7AE6F91E86DAD200B80B15 /* SecPLWrappers.h in Headers */, DC0BCD871D8C6A1E00070CB0 /* SecIOFormat.h in Headers */, DC0BCD8A1D8C6A1E00070CB0 /* array_size.h in Headers */, ); @@ -17632,8 +20390,6 @@ DC1785511D778ACD00B50D50 /* SecIdentitySearch.h in Headers */, DC1787381D77903700B50D50 /* SecIdentitySearchPriv.h in Headers */, DC17859B1D778C7400B50D50 /* SecImportExport.h in Headers */, - DC1787531D7790A500B50D50 /* SecIntegrity.h in Headers */, - DC1787541D7790A500B50D50 /* SecIntegrityLib.h in Headers */, DC17859C1D778C7900B50D50 /* SecItem.h in Headers */, DC1787781D77917100B50D50 /* SecItemBackup.h in Headers */, DC17877F1D7791A800B50D50 /* SecItemPriv.h in Headers */, @@ -17652,6 +20408,8 @@ DC1787791D77917700B50D50 /* SecPasswordGenerate.h in Headers */, DC1785941D778BF400B50D50 /* SecPolicy.h in Headers */, DC17877D1D77919B00B50D50 /* SecPolicyPriv.h in Headers */, + B61577EA1F201542004A3930 /* SecPaddingConfigurationsPriv.h in Headers */, + 222F239F1DAC15C5007ACB90 /* SecTaskPriv.h in Headers */, DC1785551D778ACD00B50D50 /* SecPolicySearch.h in Headers */, DC1785951D778BFA00B50D50 /* SecRandom.h in Headers */, DC17873E1D77903700B50D50 /* SecRandomP.h in Headers */, @@ -17665,7 +20423,6 @@ DC17858C1D778B8000B50D50 /* SecStaticCode.h in Headers */, DC1787561D7790A500B50D50 /* SecStaticCodePriv.h in Headers */, DC17859E1D778C8800B50D50 /* SecTask.h in Headers */, - DC1787571D7790A500B50D50 /* SecTaskPriv.h in Headers */, DC1785371D778A0100B50D50 /* SecTransform.h in Headers */, DC1786FA1D778F2500B50D50 /* SecTransformInternal.h in Headers */, DC1785381D778A0100B50D50 /* SecTransformReadTransform.h in Headers */, @@ -17717,10 +20474,12 @@ DC1785431D778A7400B50D50 /* oids.h in Headers */, DC1785161D77895A00B50D50 /* oidsalg.h in Headers */, DC1785171D77895A00B50D50 /* oidsattr.h in Headers */, + DCCBFA391DBAE445001DD54D /* SecInternal.h in Headers */, DC17857C1D778B4A00B50D50 /* oidsbase.h in Headers */, DC17857D1D778B4A00B50D50 /* oidscert.h in Headers */, DC17857E1D778B4A00B50D50 /* oidscrl.h in Headers */, DC1787701D77911D00B50D50 /* osKeyTemplates.h in Headers */, + DC2C5F511F0D935300FEBDA7 /* CKKSControlProtocol.h in Headers */, DC1787711D77911D00B50D50 /* secasn1t.h in Headers */, DC1786FC1D778F3D00B50D50 /* sslTypes.h in Headers */, DC17871F1D778FAA00B50D50 /* tsaSupport.h in Headers */, @@ -17734,8 +20493,60 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 4723C9CB1F152ECF0082882F /* SFSQLiteStatement.h in Headers */, + 4723C9C31F152EB60082882F /* SFObjCType.h in Headers */, DC3C73561D837B9B00F6A832 /* SOSPeerInfoPriv.h in Headers */, EB6928C61D9C9C6F00062A18 /* SecRecoveryKey.h in Headers */, + 4723C9DD1F1540CE0082882F /* SFAnalyticsLogger.h in Headers */, + 4723C9C71F152EC10082882F /* SFSQLite.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DC222C641E034D1F00B09171 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DCFE1C351F17ECE5007640C8 /* CKKSCondition.h in Headers */, + 6C3446461E25346C00F9522B /* CKKSRateLimiter.h in Headers */, + DC2C5F5E1F0EB97E00FEBDA7 /* CKKSNotifier.h in Headers */, + DC5BB4FF1E0C98320010F836 /* CKKSOutgoingQueueOperation.h in Headers */, + DC222C651E034D1F00B09171 /* SOSChangeTracker.h in Headers */, + DCFE1C521F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h in Headers */, + DCBDB3BC1E57CA7A00B61300 /* CKKSViewManager.h in Headers */, + DC762A9F1E57A86A00B03A2C /* CKKSRecordHolder.h in Headers */, + DC1DA65F1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */, + DC222C661E034D1F00B09171 /* SOSEngine.h in Headers */, + DCB5D93C1E4A9A3400BE22AB /* CKKSSynchronizeOperation.h in Headers */, + 479108B81EE879F9008CEFA0 /* CKKSAnalyticsLogger.h in Headers */, + DC222C671E034D1F00B09171 /* SecDbKeychainItem.h in Headers */, + DC222C681E034D1F00B09171 /* SecDbQuery.h in Headers */, + DCEA5D561E2826DB0089CF55 /* CKKSSIV.h in Headers */, + DC222C691E034D1F00B09171 /* CKKSMirrorEntry.h in Headers */, + DC222C6A1E034D1F00B09171 /* CKKSZoneStateEntry.h in Headers */, + DC94BCCB1F10448600E07CEB /* CloudKitCategories.h in Headers */, + DCFE1C281F17E455007640C8 /* CKKSDeviceStateEntry.h in Headers */, + DCFB12C61E95A4C000510F5F /* CKKSCKAccountStateTracker.h in Headers */, + DC222C6B1E034D1F00B09171 /* SecItemDataSource.h in Headers */, + DC18F7701E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h in Headers */, + DC222C6C1E034D1F00B09171 /* CKKSIncomingQueueEntry.h in Headers */, + DC9082C71EA027DC00D0C1C5 /* CKKSZoneChangeFetcher.h in Headers */, + DCA4D2161E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h in Headers */, + DC222C6D1E034D1F00B09171 /* SecItemDb.h in Headers */, + DC222C6E1E034D1F00B09171 /* SecItemSchema.h in Headers */, + DC222C6F1E034D1F00B09171 /* SecKeybagSupport.h in Headers */, + DC222C701E034D1F00B09171 /* iCloudTrace.h in Headers */, + DCEA5D861E2F14810089CF55 /* CKKSAPSReceiver.h in Headers */, + DC222C711E034D1F00B09171 /* CKKSOutgoingQueueEntry.h in Headers */, + DCF7A8A11F04502400CABE89 /* CKKSControlProtocol.h in Headers */, + DCCD88E91E42622200F5AA71 /* CKKSGroupOperation.h in Headers */, + DC15F7671E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.h in Headers */, + DCD6C4B31EC5302500414FEE /* CKKSNearFutureScheduler.h in Headers */, + DCE278E91ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h in Headers */, + DCD662F61E329B6800188186 /* CKKSNewTLKOperation.h in Headers */, + DC4DB1511E24692100CD6769 /* CKKSKey.h in Headers */, + DCE278DE1ED789EF0083B485 /* CKKSCurrentItemPointer.h in Headers */, + DC222C731E034D1F00B09171 /* CKKSItem.h in Headers */, + DC7A17EE1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -17743,25 +20554,47 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + DCFE1C341F17ECE5007640C8 /* CKKSCondition.h in Headers */, + DC1DA65E1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */, + DC2C5F5D1F0EB97E00FEBDA7 /* CKKSNotifier.h in Headers */, + DCCD88E81E42622200F5AA71 /* CKKSGroupOperation.h in Headers */, + 6CC1859E1E24E8EB009657D8 /* CKKSRateLimiter.h in Headers */, + DCFE1C511F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h in Headers */, + DCBDB3BB1E57CA7A00B61300 /* CKKSViewManager.h in Headers */, + DC762A9E1E57A86A00B03A2C /* CKKSRecordHolder.h in Headers */, + DC5BB4FE1E0C98320010F836 /* CKKSOutgoingQueueOperation.h in Headers */, + DCB5D93B1E4A9A3400BE22AB /* CKKSSynchronizeOperation.h in Headers */, DC52E7E81D80BE8700B0A59C /* SOSChangeTracker.h in Headers */, + 479108B71EE879F9008CEFA0 /* CKKSAnalyticsLogger.h in Headers */, DC52E7E51D80BE7400B0A59C /* SOSEngine.h in Headers */, DC52E7E41D80BE6E00B0A59C /* SecDbKeychainItem.h in Headers */, - D46F315B1E00A27D0065B550 /* SecTrustLoggingServer.h in Headers */, + DC7A17ED1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h in Headers */, DC52E7E31D80BDA600B0A59C /* SecDbQuery.h in Headers */, + DC378B2D1DEF9DF000A3DAFA /* CKKSMirrorEntry.h in Headers */, + DC94BCCA1F10448600E07CEB /* CloudKitCategories.h in Headers */, + DCFE1C271F17E455007640C8 /* CKKSDeviceStateEntry.h in Headers */, + DCFB12C51E95A4C000510F5F /* CKKSCKAccountStateTracker.h in Headers */, + DC378B381DEFADB500A3DAFA /* CKKSZoneStateEntry.h in Headers */, DC52E7E71D80BE8100B0A59C /* SecItemDataSource.h in Headers */, + DC18F76F1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h in Headers */, + DC9082C61EA027DB00D0C1C5 /* CKKSZoneChangeFetcher.h in Headers */, + DCA4D2151E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h in Headers */, + DC378B3C1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.h in Headers */, DC52E7E61D80BE7B00B0A59C /* SecItemDb.h in Headers */, DC52E7EA1D80BE9500B0A59C /* SecItemSchema.h in Headers */, DC52E7E91D80BE8D00B0A59C /* SecKeybagSupport.h in Headers */, + DCD662F51E329B6800188186 /* CKKSNewTLKOperation.h in Headers */, DC52E7EB1D80BE9B00B0A59C /* iCloudTrace.h in Headers */, - DC52E7E21D80BDA000B0A59C /* personalization.h in Headers */, - D46F31641E00CCD20065B550 /* SecCertificateSource.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DC52E8AC1D80C1EB00B0A59C /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( + DCF7A8A01F04502400CABE89 /* CKKSControlProtocol.h in Headers */, + DC6D2C931DD2836500BE372D /* CKKSOutgoingQueueEntry.h in Headers */, + DC15F7661E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.h in Headers */, + DCD6C4B21EC5302500414FEE /* CKKSNearFutureScheduler.h in Headers */, + DCE278E81ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h in Headers */, + DCEA5D851E2F14810089CF55 /* CKKSAPSReceiver.h in Headers */, + DC4DB1501E24692100CD6769 /* CKKSKey.h in Headers */, + DCE278DD1ED789EF0083B485 /* CKKSCurrentItemPointer.h in Headers */, + DCEA5D551E2826DB0089CF55 /* CKKSSIV.h in Headers */, + DCDCCB8F1DF7B8D4006E840E /* CKKSItem.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -17770,68 +20603,31 @@ buildActionMask = 2147483647; files = ( DC52E9071D80C3B300B0A59C /* SOSARCDefines.h in Headers */, - DC52E9111D80C3F800B0A59C /* SOSAccount.h in Headers */, - DC52E9181D80C42600B0A59C /* SOSAccountHSAJoin.h in Headers */, + 0C48990B1E0E0FF300C6CF70 /* SOSTransportCircleCK.h in Headers */, DC52E9101D80C3EF00B0A59C /* SOSAccountLog.h in Headers */, - DC52E91F1D80C45100B0A59C /* SOSAccountPriv.h in Headers */, DC52E90A1D80C3CC00B0A59C /* SOSAccountTransaction.h in Headers */, DC52E90C1D80C3D900B0A59C /* SOSBackupEvent.h in Headers */, - DC52E9131D80C40300B0A59C /* SOSBackupSliceKeyBag.h in Headers */, - DC52E9391D80C50E00B0A59C /* SOSCircle.h in Headers */, - DC52E91E1D80C44A00B0A59C /* SOSCircleDer.h in Headers */, - DC52E93E1D80C54300B0A59C /* SOSCirclePriv.h in Headers */, - DC52E90F1D80C3EA00B0A59C /* SOSCircleRings.h in Headers */, - DC52E9271D80C48D00B0A59C /* SOSCircleV2.h in Headers */, - DC3C73571D837BCE00F6A832 /* SOSCloudCircle.h in Headers */, DC3C73581D837BDC00F6A832 /* SOSCloudCircleInternal.h in Headers */, - DC52E9141D80C40B00B0A59C /* SOSCloudKeychainClient.h in Headers */, - DC52E9151D80C41200B0A59C /* SOSCloudKeychainConstants.h in Headers */, - 48776C7F1DA5BB7600CC09B9 /* SOSRingRecovery.h in Headers */, + DCD8A1DC1E09F5E500E4FA0A /* SOSAccount.h in Headers */, + DCD8A1E21E09F78A00E4FA0A /* SOSTransportCircle.h in Headers */, DC52E91D1D80C44400B0A59C /* SOSCoder.h in Headers */, DC52E92B1D80C4A800B0A59C /* SOSConcordanceTrust.h in Headers */, DC52E9331D80C4E500B0A59C /* SOSDataSource.h in Headers */, DC52E9061D80C3AD00B0A59C /* SOSDigestVector.h in Headers */, - DC52E9091D80C3C600B0A59C /* SOSFullPeerInfo.h in Headers */, - DC52E90E1D80C3E400B0A59C /* SOSGenCount.h in Headers */, - DC52E9341D80C4EC00B0A59C /* SOSInternal.h in Headers */, - DC52E9351D80C4F300B0A59C /* SOSKVSKeys.h in Headers */, DC52E9281D80C49300B0A59C /* SOSManifest.h in Headers */, DC52E90B1D80C3D400B0A59C /* SOSMessage.h in Headers */, DC52E9381D80C50800B0A59C /* SOSPeer.h in Headers */, DC52E91C1D80C43F00B0A59C /* SOSPeerCoder.h in Headers */, - DC3C73591D837BEC00F6A832 /* SOSPeerInfo.h in Headers */, - DC52E92D1D80C4BC00B0A59C /* SOSPeerInfoCollections.h in Headers */, - DC52E92E1D80C4C300B0A59C /* SOSPeerInfoDER.h in Headers */, DC52E9161D80C41A00B0A59C /* SOSPeerInfoInternal.h in Headers */, DC3C735A1D837C0000F6A832 /* SOSPeerInfoPriv.h in Headers */, - DC52E9171D80C41F00B0A59C /* SOSPeerInfoRingState.h in Headers */, - DC52E9201D80C45800B0A59C /* SOSPeerInfoSecurityProperties.h in Headers */, - DC52E90D1D80C3DF00B0A59C /* SOSPeerInfoV2.h in Headers */, - DC52E9251D80C48000B0A59C /* SOSPlatform.h in Headers */, DC52E91A1D80C43500B0A59C /* SOSRing.h in Headers */, - DC52E9221D80C46800B0A59C /* SOSRingBackup.h in Headers */, - 485B64121DC16EDA00B771B9 /* SOSKeyedPubKeyIdentifier.h in Headers */, - DC52E9371D80C50300B0A59C /* SOSRingBasic.h in Headers */, 48E617221DBEC6C60098EAAD /* SOSBackupInformation.h in Headers */, - DCFAEDD01D999863005187E4 /* SOSAccountGhost.h in Headers */, - DC52E9361D80C4FD00B0A59C /* SOSRingConcordanceTrust.h in Headers */, - 48776C7B1DA5BB4C00CC09B9 /* SOSRecoveryKeyBag.h in Headers */, - DC52E9401D80C55200B0A59C /* SOSRingDER.h in Headers */, - DC52E9301D80C4D000B0A59C /* SOSRingPeerInfoUtils.h in Headers */, - DC52E9291D80C49A00B0A59C /* SOSRingTypes.h in Headers */, - DC52E9121D80C3FE00B0A59C /* SOSRingUtils.h in Headers */, - DC52E92F1D80C4C900B0A59C /* SOSRingV0.h in Headers */, - DC52E92A1D80C4A200B0A59C /* SOSTransport.h in Headers */, - DC52E93D1D80C53C00B0A59C /* SOSTransportCircle.h in Headers */, + CD198F971DE27B9E00F6FB83 /* SOSAccountPriv.h in Headers */, DC52E9231D80C47100B0A59C /* SOSTransportCircleKVS.h in Headers */, DC52E92C1D80C4AF00B0A59C /* SOSTransportKeyParameter.h in Headers */, - DC52E9431D80C5AA00B0A59C /* SOSTransportKeyParameterKVS.h in Headers */, DC52E9241D80C47900B0A59C /* SOSTransportMessage.h in Headers */, DC52E9191D80C42F00B0A59C /* SOSTransportMessageIDS.h in Headers */, DC52E9321D80C4DF00B0A59C /* SOSTransportMessageKVS.h in Headers */, - DC3C735B1D837C0F00F6A832 /* SOSTypes.h in Headers */, - DC52E9261D80C48700B0A59C /* SOSUserKeygen.h in Headers */, - DC52E91B1D80C43A00B0A59C /* SOSViews.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -17904,10 +20700,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - BE6D96B71DB14B65001B76D4 /* cnnic_certs.h in Headers */, DC0B62281D90974300D43BCB /* si-25-cms-skid.h in Headers */, - BE6D96B81DB14B65001B76D4 /* date_testing_certs.h in Headers */, - BE6D96B91DB14B65001B76D4 /* wosign_certs.h in Headers */, D487FBBA1DB835B500D4BB0B /* si-29-sectrust-sha1-deprecation.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -18094,6 +20887,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + DC3832DA1DB7050900385F63 /* module.modulemap in Headers */, DC71D9E61D95BB0A0065FB93 /* oidsPriv.h in Headers */, DC71D9E71D95BB0A0065FB93 /* libDER.h in Headers */, DC71D9E81D95BB0A0065FB93 /* DER_Decode.h in Headers */, @@ -18277,11 +21071,9 @@ DCB343461D8A32A20054D16E /* ExtendedAttribute.h in Headers */, DCB343601D8A32A20054D16E /* Trust.h in Headers */, DCB3437B1D8A32A20054D16E /* PrimaryKey.h in Headers */, - DCB343421D8A32A20054D16E /* CertificateRequest.h in Headers */, DCB343911D8A32A20054D16E /* TokenLogin.h in Headers */, DCB3434E1D8A32A20054D16E /* Item.h in Headers */, DCB343851D8A32A20054D16E /* UnlockReferralItem.h in Headers */, - DCB343681D8A32A20054D16E /* SecTrustOSXEntryPoints.h in Headers */, DCB343A41D8A32A20054D16E /* SecNetscapeTemplates.h in Headers */, DCB343481D8A32A20054D16E /* Globals.h in Headers */, DCB3438D1D8A32A20054D16E /* SecCertificateInternalP.h in Headers */, @@ -18323,6 +21115,7 @@ DCEDE3931D80B11200C3826E /* SecOTR.h in Headers */, DCEDE3921D80B10E00C3826E /* SecOTRDHKey.h in Headers */, DCEDE3911D80B10800C3826E /* SecCTKKeyPriv.h in Headers */, + BEEB47DB1EA189F5004AA5C6 /* SecTrustStatusCodes.h in Headers */, DCEDE3901D80B10100C3826E /* SecOTRIdentityPriv.h in Headers */, DCEDE3511D80B0FA00C3826E /* secd-71-engine-save-sample1.h in Headers */, DCC093801D80B0B700F984E4 /* SecCFAllocator.h in Headers */, @@ -18330,7 +21123,7 @@ DCC0937E1D80B0A700F984E4 /* SecOTRPacketData.h in Headers */, DCC0937D1D80B09E00F984E4 /* SecOTRPackets.h in Headers */, DCC0937C1D80B09200F984E4 /* SecSignatureVerificationSupport.h in Headers */, - 48BC0F661DFA2B5B00DDDFF9 /* accountCirclesViewsPrint.h in Headers */, + 48C2F93C1E4BD00F0093D70C /* accountCirclesViewsPrint.h in Headers */, DCC0937B1D80B07B00F984E4 /* SecOTRSession.h in Headers */, DCC0937A1D80B07200F984E4 /* SecOTRSessionPriv.h in Headers */, DCC093791D80B02100F984E4 /* SecOnOSX.h in Headers */, @@ -18365,7 +21158,6 @@ DCD069231D8CDFFF007602F1 /* TokenStreamSelector.hpp in Headers */, DCD0682B1D8CDF7E007602F1 /* StaticCode.h in Headers */, DCD0681F1D8CDF7E007602F1 /* SecRequirementPriv.h in Headers */, - DCD068671D8CDF7E007602F1 /* SecIntegrityLib.h in Headers */, DCD069131D8CDFFE007602F1 /* ParserSharedInputState.hpp in Headers */, DCD069041D8CDFFE007602F1 /* CircularQueue.hpp in Headers */, DCD068551D8CDF7E007602F1 /* filediskrep.h in Headers */, @@ -18390,7 +21182,6 @@ DCD068271D8CDF7E007602F1 /* cs.h in Headers */, DCD068611D8CDF7E007602F1 /* singlediskrep.h in Headers */, DCD068291D8CDF7E007602F1 /* Code.h in Headers */, - DCD068251D8CDF7E007602F1 /* SecIntegrity.h in Headers */, DCD0690E1D8CDFFE007602F1 /* MismatchedCharException.hpp in Headers */, DCD0687E1D8CDF7E007602F1 /* antlrplugin.h in Headers */, DCD0690D1D8CDFFE007602F1 /* LLkParser.hpp in Headers */, @@ -18462,7 +21253,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - DCD06A411D8CE251007602F1 /* SecIntegrity.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -18479,7 +21269,6 @@ buildActionMask = 2147483647; files = ( DCD06BA41D8E0D7D007602F1 /* machrunloopserver.h in Headers */, - DCD06B871D8E0D7D007602F1 /* fdsel.h in Headers */, DCD06B501D8E0D7D007602F1 /* debugsupport.h in Headers */, DCD06B4C1D8E0D7D007602F1 /* ccaudit.h in Headers */, DCD06B671D8E0D7D007602F1 /* powerwatch.h in Headers */, @@ -18487,23 +21276,17 @@ DCD06BC41D8E0DC2007602F1 /* utilities_dtrace.h in Headers */, DCD06B711D8E0D7D007602F1 /* streams.h in Headers */, DCD06B7C1D8E0D7D007602F1 /* trackingallocator.h in Headers */, - DCD06B851D8E0D7D007602F1 /* fdmover.h in Headers */, DCD06B691D8E0D7D007602F1 /* refcount.h in Headers */, DCD06BA11D8E0D7D007602F1 /* dyld_cache_format.h in Headers */, - DCD06BB81D8E0D7D007602F1 /* ip++.h in Headers */, - DCD06B601D8E0D7D007602F1 /* ktracecodes.h in Headers */, - DCD06BB01D8E0D7D007602F1 /* buffers.h in Headers */, DCD06B7A1D8E0D7D007602F1 /* tqueue.h in Headers */, DCD06B651D8E0D7D007602F1 /* osxcode.h in Headers */, DCD06B631D8E0D7D007602F1 /* memstreams.h in Headers */, DCD06B6F1D8E0D7D007602F1 /* sqlite++.h in Headers */, DCD06B891D8E0D7D007602F1 /* kq++.h in Headers */, DCD06B971D8E0D7D007602F1 /* mach++.h in Headers */, - DCD06BB61D8E0D7D007602F1 /* inetreply.h in Headers */, DCD06B3F1D8E0D7D007602F1 /* FileLockTransaction.h in Headers */, DCD06B9F1D8E0D7D007602F1 /* dyldcache.h in Headers */, DCD06B821D8E0D7D007602F1 /* utilities.h in Headers */, - DCD06BBA1D8E0D7D007602F1 /* url.h in Headers */, DCD06B521D8E0D7D007602F1 /* devrandom.h in Headers */, DCD06B751D8E0D7D007602F1 /* threading.h in Headers */, DCD06B3D1D8E0D7D007602F1 /* debugging.h in Headers */, @@ -18517,20 +21300,14 @@ DCD06B951D8E0D7D007602F1 /* vproc++.h in Headers */, DCD06BAA1D8E0D7D007602F1 /* cfmunge.h in Headers */, DCD06B6A1D8E0D7D007602F1 /* seccfobject.h in Headers */, - DCD06BBE1D8E0D7D007602F1 /* socks++4.h in Headers */, DCD06B411D8E0D7D007602F1 /* CSPDLTransaction.h in Headers */, - DCD06BB41D8E0D7D007602F1 /* hosts.h in Headers */, DCD06B4D1D8E0D7D007602F1 /* daemon.h in Headers */, DCD06BAC1D8E0D7D007602F1 /* cfutilities.h in Headers */, DCD06B4F1D8E0D7D007602F1 /* debugging_internal.h in Headers */, DCD06B931D8E0D7D007602F1 /* unixchild.h in Headers */, DCD06B581D8E0D7D007602F1 /* errors.h in Headers */, - DCD06BC01D8E0D7D007602F1 /* socks++5.h in Headers */, DCD06B551D8E0D7D007602F1 /* dispatch.h in Headers */, DCD06B761D8E0D7D007602F1 /* threading_internal.h in Headers */, - DCD06B5E1D8E0D7D007602F1 /* iodevices.h in Headers */, - DCD06B8F1D8E0D7D007602F1 /* selector.h in Headers */, - DCD06BB21D8E0D7D007602F1 /* headermap.h in Headers */, DCD06BA81D8E0D7D007602F1 /* cfclass.h in Headers */, DCD06BA21D8E0D7D007602F1 /* machserver.h in Headers */, DCD06B6C1D8E0D7D007602F1 /* security_utilities.h in Headers */, @@ -18540,16 +21317,13 @@ DCD06B641D8E0D7D007602F1 /* memutils.h in Headers */, DCD06BA61D8E0D7D007602F1 /* coderepository.h in Headers */, DCD06B5A1D8E0D7D007602F1 /* globalizer.h in Headers */, - DCD06B811D8E0D7D007602F1 /* typedvalue.h in Headers */, DCD06B421D8E0D7D007602F1 /* casts.h in Headers */, DCD06B841D8E0D7D007602F1 /* utility_config.h in Headers */, DCD06B8D1D8E0D7D007602F1 /* pcsc++.h in Headers */, DCD06B9B1D8E0D7D007602F1 /* cfmach++.h in Headers */, DCD06B441D8E0D7D007602F1 /* crc.h in Headers */, - DCD06BAE1D8E0D7D007602F1 /* bufferfifo.h in Headers */, DCD06B6D1D8E0D7D007602F1 /* simpleprefs.h in Headers */, DCD06B8B1D8E0D7D007602F1 /* muscle++.h in Headers */, - DCD06BBC1D8E0D7D007602F1 /* socks++.h in Headers */, DCD06B5C1D8E0D7D007602F1 /* hashing.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -18558,6 +21332,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + BEEB47DC1EA189F5004AA5C6 /* SecTrustStatusCodes.h in Headers */, DCD66DC11D82055400DB1393 /* SecTrustInternal.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -18569,6 +21344,61 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCD8A1551E09EE0F00E4FA0A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + DCD8A15A1E09EE0F00E4FA0A /* SOSAccountTransaction.h in Headers */, + 0CE760561E1316E900B4381E /* SOSAccountTrustClassic+Retirement.h in Headers */, + 0CE760541E13155100B4381E /* SOSAccountTrustClassic+Circle.h in Headers */, + DCD8A15C1E09EE0F00E4FA0A /* SOSBackupSliceKeyBag.h in Headers */, + DCD8A15D1E09EE0F00E4FA0A /* SOSCircle.h in Headers */, + 0C4899271E0F399B00C6CF70 /* SOSAccountTrustOctagon.h in Headers */, + DCD8A15E1E09EE0F00E4FA0A /* SOSCircleDer.h in Headers */, + DCD8A15F1E09EE0F00E4FA0A /* SOSCirclePriv.h in Headers */, + DCD8A1601E09EE0F00E4FA0A /* SOSCircleRings.h in Headers */, + DCD8A1611E09EE0F00E4FA0A /* SOSCircleV2.h in Headers */, + DCD8A1621E09EE0F00E4FA0A /* SOSCloudCircle.h in Headers */, + 0CE760501E1301DC00B4381E /* SOSAccountTrustClassic+Expansion.h in Headers */, + DCD8A1631E09EE0F00E4FA0A /* SOSCloudCircleInternal.h in Headers */, + DCD8A1641E09EE0F00E4FA0A /* SOSCloudKeychainClient.h in Headers */, + DCD8A1651E09EE0F00E4FA0A /* SOSCloudKeychainConstants.h in Headers */, + DCD8A1661E09EE0F00E4FA0A /* SOSRingRecovery.h in Headers */, + 0C4899231E0F386900C6CF70 /* SOSAccountTrustClassic.h in Headers */, + DCD8A1E11E09F76D00E4FA0A /* SOSPeerInfoSecurityProperties.h in Headers */, + DCD8A16C1E09EE0F00E4FA0A /* SOSFullPeerInfo.h in Headers */, + DCD8A1DD1E09F73F00E4FA0A /* SOSPeerInfoDER.h in Headers */, + DCD8A16D1E09EE0F00E4FA0A /* SOSGenCount.h in Headers */, + DCD8A16E1E09EE0F00E4FA0A /* SOSInternal.h in Headers */, + DCD8A16F1E09EE0F00E4FA0A /* SOSKVSKeys.h in Headers */, + DCD8A1741E09EE0F00E4FA0A /* SOSPeerInfo.h in Headers */, + DCD8A17C1E09EE0F00E4FA0A /* SOSPlatform.h in Headers */, + DCD8A17D1E09EE0F00E4FA0A /* SOSRing.h in Headers */, + DCD8A17E1E09EE0F00E4FA0A /* SOSRingBackup.h in Headers */, + DCD8A17F1E09EE0F00E4FA0A /* SOSKeyedPubKeyIdentifier.h in Headers */, + DCD8A1801E09EE0F00E4FA0A /* SOSRingBasic.h in Headers */, + DCD8A1821E09EE0F00E4FA0A /* SOSAccountGhost.h in Headers */, + DCD8A1E01E09F76800E4FA0A /* SOSPeerInfoRingState.h in Headers */, + DCD8A1831E09EE0F00E4FA0A /* SOSRingConcordanceTrust.h in Headers */, + DCD8A1841E09EE0F00E4FA0A /* SOSRecoveryKeyBag.h in Headers */, + DCD8A1851E09EE0F00E4FA0A /* SOSRingDER.h in Headers */, + DCD8A1861E09EE0F00E4FA0A /* SOSRingPeerInfoUtils.h in Headers */, + 0CE760521E1314F700B4381E /* SOSAccountTrustClassic+Identity.h in Headers */, + DCD8A1871E09EE0F00E4FA0A /* SOSRingTypes.h in Headers */, + DCD8A1881E09EE0F00E4FA0A /* SOSAccountPriv.h in Headers */, + DCD8A1DF1E09F76000E4FA0A /* SOSPeerInfoCollections.h in Headers */, + DCD8A1891E09EE0F00E4FA0A /* SOSRingUtils.h in Headers */, + DCD8A18A1E09EE0F00E4FA0A /* SOSRingV0.h in Headers */, + DCD8A18B1E09EE0F00E4FA0A /* SOSTransport.h in Headers */, + EB75B4951E75A44100E469CC /* SOSPiggyback.h in Headers */, + DCD8A1901E09EE0F00E4FA0A /* SOSAccountTrust.h in Headers */, + DCD8A1DE1E09F74700E4FA0A /* SOSPeerInfoV2.h in Headers */, + DCD8A1931E09EE0F00E4FA0A /* SOSTypes.h in Headers */, + DCD8A1941E09EE0F00E4FA0A /* SOSUserKeygen.h in Headers */, + DCD8A1951E09EE0F00E4FA0A /* SOSViews.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DCF7830D1D88B4DE00E694BB /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -18752,6 +21582,7 @@ E71454F11C741E1500B5B20B /* KCDer.h in Headers */, E772FD701CC15F1F00D63E41 /* NSData+SecRandom.h in Headers */, E7F480321C73FC4C00390FDB /* KCAESGCMDuplexSession.h in Headers */, + EB413B821E663AFA00592085 /* PairingChannel.h in Headers */, E7F480121C729C7B00390FDB /* NSError+KCCreationHelpers.h in Headers */, E7E3EFE31CBC195700E79A5D /* KCAccountKCCircleDelegate.h in Headers */, E794BB011C759B1200339A0F /* KCJoiningMessages.h in Headers */, @@ -18920,6 +21751,19 @@ passBuildSettingsInEnvironment = 1; productName = "--- Daemons ---"; }; + EB10556D1E14DD670003C309 /* === Fuzzer Targets ===== */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION)"; + buildConfigurationList = EB10556E1E14DD670003C309 /* Build configuration list for PBXLegacyTarget "=== Fuzzer Targets =====" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + dependencies = ( + ); + name = "=== Fuzzer Targets ====="; + passBuildSettingsInEnvironment = 1; + productName = "--- Daemons ---"; + }; EBBE20571C21380100B7A639 /* SecurityFeatures */ = { isa = PBXLegacyTarget; buildArgumentsString = "$(PROJECT_DIR)/SecurityFeatures/ExternalProject.sh $(ACTION)"; @@ -18948,9 +21792,10 @@ buildRules = ( ); dependencies = ( - DC00ABCF1D821F1700513D74 /* PBXTargetDependency */, + D40B6A8C1E2B63D100CD6EE5 /* PBXTargetDependency */, DC00ABD11D821F1A00513D74 /* PBXTargetDependency */, DC00ABD31D821F1D00513D74 /* PBXTargetDependency */, + DCD8A1EF1E09F8BC00E4FA0A /* PBXTargetDependency */, DC59EA901D91CDC6001BDDF5 /* PBXTargetDependency */, DC65E75A1D8CB48900152EF0 /* PBXTargetDependency */, DC59E9A91D91C7CC001BDDF5 /* PBXTargetDependency */, @@ -18998,6 +21843,24 @@ productReference = 0C2BCBCE1D0648D100ED7A2F /* dtlsEchoServer */; productType = "com.apple.product-type.tool"; }; + 225394AC1E3080A600D3CD9B /* security_codesigning_ios */ = { + isa = PBXNativeTarget; + buildConfigurationList = 225394B11E3080A600D3CD9B /* Build configuration list for PBXNativeTarget "security_codesigning_ios" */; + buildPhases = ( + 225394B01E3080A600D3CD9B /* Headers */, + 225394AD1E3080A600D3CD9B /* Sources */, + 225394AF1E3080A600D3CD9B /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 225394DA1E30846800D3CD9B /* PBXTargetDependency */, + ); + name = security_codesigning_ios; + productName = libsecurity; + productReference = 225394B41E3080A600D3CD9B /* libsecurity_codesigning_ios.a */; + productType = "com.apple.product-type.library.static"; + }; 4381690B1B4EDCBD00C54D58 /* SOSCCAuthPlugin */ = { isa = PBXNativeTarget; buildConfigurationList = 438169381B4EDCBD00C54D58 /* Build configuration list for PBXNativeTarget "SOSCCAuthPlugin" */; @@ -19015,6 +21878,75 @@ productReference = 4381690C1B4EDCBD00C54D58 /* SOSCCAuthPlugin.bundle */; productType = "com.apple.product-type.bundle"; }; + 470415CE1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 470415DA1E5E14B6001F3D95 /* Build configuration list for PBXNativeTarget "seckeychainnetworkextensionstest" */; + buildPhases = ( + 470415CB1E5E14B5001F3D95 /* Sources */, + 470415CC1E5E14B5001F3D95 /* Frameworks */, + 470415CD1E5E14B5001F3D95 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = seckeychainnetworkextensionstest; + productName = seckeychainnetworkextensionstest; + productReference = 470415CF1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */; + productType = "com.apple.product-type.tool"; + }; + 47702B1D1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 47702B221E5F409700B29577 /* Build configuration list for PBXNativeTarget "seckeychainnetworkextensionsystemdaemontest" */; + buildPhases = ( + 47702B1A1E5F409700B29577 /* Sources */, + 47702B1B1E5F409700B29577 /* Frameworks */, + 47702B1C1E5F409700B29577 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = seckeychainnetworkextensionsystemdaemontest; + productName = seckeychainnetworkextensionsystemdaemontest; + productReference = 47702B1E1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */; + productType = "com.apple.product-type.tool"; + }; + 47702B2D1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 47702B321E5F492C00B29577 /* Build configuration list for PBXNativeTarget "seckeychainnetworkextensionunauthorizedaccesstest" */; + buildPhases = ( + 47702B2A1E5F492C00B29577 /* Sources */, + 47702B2B1E5F492C00B29577 /* Frameworks */, + 47702B2C1E5F492C00B29577 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = seckeychainnetworkextensionunauthorizedaccesstest; + productName = seckeychainnetworkextensionunauthorizedaccesstest; + productReference = 47702B2E1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */; + productType = "com.apple.product-type.tool"; + }; + 47C51B831EEA657D0032D9E5 /* SecurityUnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 47C51B931EEA657D0032D9E5 /* Build configuration list for PBXNativeTarget "SecurityUnitTests" */; + buildPhases = ( + 47C51B801EEA657D0032D9E5 /* Sources */, + 47C51B811EEA657D0032D9E5 /* Frameworks */, + 47C51B821EEA657D0032D9E5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 47C51B8B1EEA657D0032D9E5 /* PBXTargetDependency */, + ); + name = SecurityUnitTests; + productName = SecurityUnitTests; + productReference = 47C51B841EEA657D0032D9E5 /* SecurityUnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 4C32C0AE0A4975F6002891BD /* Security_ios */ = { isa = PBXNativeTarget; buildConfigurationList = 4C32C0B10A4975F7002891BD /* Build configuration list for PBXNativeTarget "Security_ios" */; @@ -19024,7 +21956,6 @@ 4C32C0AB0A4975F6002891BD /* Resources */, 4C32C0AC0A4975F6002891BD /* Sources */, 4C32C0AD0A4975F6002891BD /* Frameworks */, - EB5D72ED1B0CB082009CAA47 /* Old SOS header location */, 5EE098DE1CD21661009FCA27 /* Unifdef RC_HIDE_J79/J80 */, ); buildRules = ( @@ -19035,11 +21966,12 @@ DC59EA761D91CC5E001BDDF5 /* PBXTargetDependency */, DCD22D7D1D8CCA18001C9B81 /* PBXTargetDependency */, DCD22D7B1D8CCA07001C9B81 /* PBXTargetDependency */, - DC52E9A31D80C5EE00B0A59C /* PBXTargetDependency */, - DC52E8BD1D80C23300B0A59C /* PBXTargetDependency */, + DCD8A19C1E09EEA200E4FA0A /* PBXTargetDependency */, DCC093781D80ABC300F984E4 /* PBXTargetDependency */, DC52EC5F1D80D08100B0A59C /* PBXTargetDependency */, DCD22D7F1D8CCA2C001C9B81 /* PBXTargetDependency */, + 226A8B451DEF58EE004C35E3 /* PBXTargetDependency */, + 225394B61E30811400D3CD9B /* PBXTargetDependency */, ); name = Security_ios; productName = Security2; @@ -19082,6 +22014,7 @@ DC59EA841D91CD2C001BDDF5 /* PBXTargetDependency */, DC00ABAA1D821DE600513D74 /* PBXTargetDependency */, DC00ABAC1D821DE700513D74 /* PBXTargetDependency */, + DCD8A1FB1E09F99700E4FA0A /* PBXTargetDependency */, DC65E7441D8CB3E000152EF0 /* PBXTargetDependency */, DC65E7461D8CB3E700152EF0 /* PBXTargetDependency */, DC65E7481D8CB3F000152EF0 /* PBXTargetDependency */, @@ -19126,6 +22059,7 @@ dependencies = ( DCD22D821D8CCB5A001C9B81 /* PBXTargetDependency */, DCD22D841D8CCB72001C9B81 /* PBXTargetDependency */, + DCD8A1EC1E09F88400E4FA0A /* PBXTargetDependency */, DC52EC3D1D80CFF000B0A59C /* PBXTargetDependency */, DC52EC201D80CF7400B0A59C /* PBXTargetDependency */, DC52EAA51D80CCF600B0A59C /* PBXTargetDependency */, @@ -19159,6 +22093,7 @@ 52D82BDA16A621F70078DFE5 /* Sources */, 52D82BDB16A621F70078DFE5 /* Frameworks */, 8E64DB4E1C18A5B80076C9DF /* Install launchd plist */, + EB76B7581DCB0C8B00C43FBC /* Install man8 page */, ); buildRules = ( ); @@ -19215,9 +22150,12 @@ buildRules = ( ); dependencies = ( + D40B6A861E2B5F7600CD6EE5 /* PBXTargetDependency */, + DC89998B1E410DBF00E6E604 /* PBXTargetDependency */, DC59EA8D1D91CDB9001BDDF5 /* PBXTargetDependency */, DC65E7561D8CB47600152EF0 /* PBXTargetDependency */, DC00ABC91D821F0200513D74 /* PBXTargetDependency */, + DCD8A1E61E09F81300E4FA0A /* PBXTargetDependency */, DC00ABCB1D821F0500513D74 /* PBXTargetDependency */, DC65E7581D8CB47D00152EF0 /* PBXTargetDependency */, ); @@ -19226,6 +22164,108 @@ productReference = 5EBE247A1B00CCAE0007DB0E /* secacltests */; productType = "com.apple.product-type.tool"; }; + 6C98082C1E788AEB00E70590 /* CKKSCloudKitTests_mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6C98085E1E788AEB00E70590 /* Build configuration list for PBXNativeTarget "CKKSCloudKitTests_mac" */; + buildPhases = ( + 6C98083D1E788AEB00E70590 /* Sources */, + 6C9808481E788AEB00E70590 /* Frameworks */, + 6C98085D1E788AEB00E70590 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 6C98082D1E788AEB00E70590 /* PBXTargetDependency */, + 6C98082F1E788AEB00E70590 /* PBXTargetDependency */, + 6C9808311E788AEB00E70590 /* PBXTargetDependency */, + 6C9808351E788AEB00E70590 /* PBXTargetDependency */, + 6C9808371E788AEB00E70590 /* PBXTargetDependency */, + 6C9808391E788AEB00E70590 /* PBXTargetDependency */, + 6C98083B1E788AEB00E70590 /* PBXTargetDependency */, + 6C9808A01E788B9400E70590 /* PBXTargetDependency */, + ); + name = CKKSCloudKitTests_mac; + productName = CKKSTests; + productReference = 6C9808611E788AEB00E70590 /* CKKSCloudKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 6C9808681E788AFD00E70590 /* CKKSCloudKitTests_ios */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6C98089A1E788AFD00E70590 /* Build configuration list for PBXNativeTarget "CKKSCloudKitTests_ios" */; + buildPhases = ( + 6C9808791E788AFD00E70590 /* Sources */, + 6C9808841E788AFD00E70590 /* Frameworks */, + 6C9808991E788AFD00E70590 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 6C9808A41E788CB100E70590 /* PBXTargetDependency */, + 6C9808691E788AFD00E70590 /* PBXTargetDependency */, + 6C98086B1E788AFD00E70590 /* PBXTargetDependency */, + 6C98086D1E788AFD00E70590 /* PBXTargetDependency */, + 6C9808711E788AFD00E70590 /* PBXTargetDependency */, + 6C9808731E788AFD00E70590 /* PBXTargetDependency */, + 6C9808751E788AFD00E70590 /* PBXTargetDependency */, + 6C9808771E788AFD00E70590 /* PBXTargetDependency */, + ); + name = CKKSCloudKitTests_ios; + productName = CKKSTests; + productReference = 6C98089D1E788AFD00E70590 /* CKKSCloudKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 6CCDF7831E3C25FA003F2555 /* KeychainEntitledTestRunner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6CCDF7881E3C25FB003F2555 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestRunner" */; + buildPhases = ( + 6CCDF7801E3C25FA003F2555 /* Sources */, + 6CCDF7811E3C25FA003F2555 /* Frameworks */, + 6CCDF7821E3C25FA003F2555 /* Copy BATS Test Discovery plist */, + 6CB5F4761E402D0000DBF3F0 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = KeychainEntitledTestRunner; + productName = KeychainEntitledTestRunner; + productReference = 6CCDF7841E3C25FA003F2555 /* KeychainEntitledTestRunner */; + productType = "com.apple.product-type.tool"; + }; + 6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6CF4A0CC1E45488B00ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp_mac" */; + buildPhases = ( + 6CF4A0B01E45488B00ECD7B5 /* Sources */, + 6CF4A0B11E45488B00ECD7B5 /* Frameworks */, + 6CF4A0B21E45488B00ECD7B5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = KeychainEntitledTestApp_mac; + 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"; + }; 728B56A016D59979008FA3AB /* OTAPKIAssetTool */ = { isa = PBXNativeTarget; buildConfigurationList = 728B56AB16D59979008FA3AB /* Build configuration list for PBXNativeTarget "OTAPKIAssetTool" */; @@ -19257,8 +22297,10 @@ dependencies = ( DC59EA7D1D91CCAA001BDDF5 /* PBXTargetDependency */, DC65E7291D8CB2F400152EF0 /* PBXTargetDependency */, + D40B6A7F1E2B5F3D00CD6EE5 /* PBXTargetDependency */, DC52E84B1D80BF1100B0A59C /* PBXTargetDependency */, DC00AB7E1D821C7F00513D74 /* PBXTargetDependency */, + DCD8A1E91E09F85B00E4FA0A /* PBXTargetDependency */, DC00AB801D821C8300513D74 /* PBXTargetDependency */, ); name = securityd_ios; @@ -19283,6 +22325,23 @@ productReference = 7913B2110D172B3900601FE9 /* sslServer */; productType = "com.apple.product-type.tool"; }; + ACBAF6991E9417F40007BA2F /* security_transform_regressions */ = { + isa = PBXNativeTarget; + buildConfigurationList = ACBAF6DA1E9417F40007BA2F /* Build configuration list for PBXNativeTarget "security_transform_regressions" */; + buildPhases = ( + ACBAF69A1E9417F40007BA2F /* Headers */, + ACBAF6BB1E9417F40007BA2F /* Sources */, + ACBAF6D91E9417F40007BA2F /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = security_transform_regressions; + productName = libsecurityd_client_macos; + productReference = ACBAF6DD1E9417F40007BA2F /* libsecurity_transform_regressions.a */; + productType = "com.apple.product-type.library.static"; + }; BE197F2519116FD100BA91D1 /* SharedWebCredentialViewService */ = { isa = PBXNativeTarget; buildConfigurationList = BE197F5819116FD100BA91D1 /* Build configuration list for PBXNativeTarget "SharedWebCredentialViewService" */; @@ -19318,14 +22377,67 @@ productReference = BE442BC118B7FDB800F24DAE /* swcagent */; productType = "com.apple.product-type.tool"; }; + BED208D41EDF950E00753952 /* manifeststresstest */ = { + isa = PBXNativeTarget; + buildConfigurationList = BED208DA1EDF950E00753952 /* Build configuration list for PBXNativeTarget "manifeststresstest" */; + buildPhases = ( + BED208D51EDF950E00753952 /* Sources */, + BED208D71EDF950E00753952 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = manifeststresstest; + productName = secbackupntest; + productReference = BED208DD1EDF950E00753952 /* manifeststresstest */; + productType = "com.apple.product-type.tool"; + }; + BEF88C271EAFFC3F00357577 /* TrustedPeers */ = { + isa = PBXNativeTarget; + buildConfigurationList = BEF88C421EAFFC4000357577 /* Build configuration list for PBXNativeTarget "TrustedPeers" */; + buildPhases = ( + BEF88C231EAFFC3F00357577 /* Sources */, + BEF88C241EAFFC3F00357577 /* Frameworks */, + BEF88C251EAFFC3F00357577 /* Headers */, + BEF88C261EAFFC3F00357577 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TrustedPeers; + productName = TrustedPeers; + productReference = BEF88C281EAFFC3F00357577 /* TrustedPeers.framework */; + productType = "com.apple.product-type.framework"; + }; + BEF88C2F1EAFFC3F00357577 /* TrustedPeersTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = BEF88C431EAFFC4000357577 /* Build configuration list for PBXNativeTarget "TrustedPeersTests" */; + buildPhases = ( + BEF88C2C1EAFFC3F00357577 /* Sources */, + BEF88C2D1EAFFC3F00357577 /* Frameworks */, + BEF88C2E1EAFFC3F00357577 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BEF88C331EAFFC3F00357577 /* PBXTargetDependency */, + ); + name = TrustedPeersTests; + productName = TrustedPeersTests; + productReference = BEF88C301EAFFC3F00357577 /* TrustedPeersTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; CD276C261A83F60C003226BC /* KeychainSyncingOverIDSProxy */ = { isa = PBXNativeTarget; buildConfigurationList = CD276C2C1A83F60C003226BC /* Build configuration list for PBXNativeTarget "KeychainSyncingOverIDSProxy" */; buildPhases = ( CD276C231A83F60C003226BC /* Sources */, CD276C241A83F60C003226BC /* Frameworks */, - CDF91EA61AAE019800E88CF7 /* CopyFiles */, + CDF91EA61AAE019800E88CF7 /* Install alloy plist */, 8E64DAF81C17BA620076C9DF /* Install launchd plist */, + EB76B7561DCB0C6900C43FBC /* Install man8 page */, ); buildRules = ( ); @@ -19337,6 +22449,60 @@ productReference = CD276C271A83F60C003226BC /* KeychainSyncingOverIDSProxy.bundle */; productType = "com.apple.product-type.bundle"; }; + D41257CE1E9410A300781F23 /* trustd_ios */ = { + isa = PBXNativeTarget; + buildConfigurationList = D41257D61E9410A300781F23 /* Build configuration list for PBXNativeTarget "trustd_ios" */; + buildPhases = ( + D41257CB1E9410A300781F23 /* Sources */, + D41257CC1E9410A300781F23 /* Frameworks */, + D41257CD1E9410A300781F23 /* Copy LaunchDaemon */, + ); + buildRules = ( + ); + dependencies = ( + D41257E81E941AD200781F23 /* PBXTargetDependency */, + D41257E61E941ACC00781F23 /* PBXTargetDependency */, + D41257E41E941A8400781F23 /* PBXTargetDependency */, + ); + name = trustd_ios; + productName = trustd_ios; + productReference = D41257CF1E9410A300781F23 /* trustd */; + productType = "com.apple.product-type.tool"; + }; + D4ADA3181E2B41670031CEA3 /* libtrustd */ = { + isa = PBXNativeTarget; + buildConfigurationList = D4ADA31A1E2B41670031CEA3 /* Build configuration list for PBXNativeTarget "libtrustd" */; + buildPhases = ( + D4ADA3151E2B41670031CEA3 /* Sources */, + D4ADA3161E2B41670031CEA3 /* Frameworks */, + D4ADA3171E2B41670031CEA3 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = libtrustd; + productName = libtrustd; + productReference = D4ADA3191E2B41670031CEA3 /* libtrustd.a */; + productType = "com.apple.product-type.library.static"; + }; + DA30D6751DF8C8FB00EC6B43 /* KeychainSyncAccountUpdater */ = { + isa = PBXNativeTarget; + buildConfigurationList = DA30D6801DF8C8FB00EC6B43 /* Build configuration list for PBXNativeTarget "KeychainSyncAccountUpdater" */; + buildPhases = ( + DA30D6721DF8C8FB00EC6B43 /* Sources */, + DA30D6731DF8C8FB00EC6B43 /* Frameworks */, + DA30D6741DF8C8FB00EC6B43 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = KeychainSyncAccountUpdater; + productName = KeychainSyncAccountUpdater; + productReference = DA30D6761DF8C8FB00EC6B43 /* KeychainSyncAccountUpdater.bundle */; + productType = "com.apple.product-type.bundle"; + }; DC0067921D87876F005AF8DB /* securityd_server_macos */ = { isa = PBXNativeTarget; buildConfigurationList = DC0067BD1D87876F005AF8DB /* Build configuration list for PBXNativeTarget "securityd_server_macos" */; @@ -19780,14 +22946,13 @@ DC1789A71D779E7E00B50D50 /* Run Script Generate Strings */, DC1789021D77980500B50D50 /* Resources */, DC1789E81D77A0E700B50D50 /* CopyFiles */, - DC178B481D77A51600B50D50 /* Run Script Copy XPC Service */, - DC178B8A1D77A54000B50D50 /* Old SOS header location */, - DC0BC5601D8B6D2E00070CB0 /* Embed XPC Services */, + DC178B481D77A51600B50D50 /* Make XPC server symlink */, ); buildRules = ( DC58C36E1D77B4AD003C25A4 /* PBXBuildRule */, ); dependencies = ( + DCD8A1FE1E09FA1800E4FA0A /* PBXTargetDependency */, DC0B62961D90B6DB00D43BCB /* PBXTargetDependency */, DCC5BF381D937329008D1E84 /* PBXTargetDependency */, DC1789791D779C6700B50D50 /* PBXTargetDependency */, @@ -19796,7 +22961,6 @@ DCB340191D8A248C0054D16E /* PBXTargetDependency */, DCD66DC31D82056C00DB1393 /* PBXTargetDependency */, DCD66DE61D82061F00DB1393 /* PBXTargetDependency */, - DC00AB661D821BFD00513D74 /* PBXTargetDependency */, DC52EE7E1D80D8B100B0A59C /* PBXTargetDependency */, DCD06A8A1D8CE356007602F1 /* PBXTargetDependency */, DCB342371D8A2CD70054D16E /* PBXTargetDependency */, @@ -19827,16 +22991,57 @@ DCF789461D88CD7C00E694BB /* PBXTargetDependency */, DCB341791D8A2AF10054D16E /* PBXTargetDependency */, DC0BC7BF1D8B784F00070CB0 /* PBXTargetDependency */, - DC00AB681D821C0500513D74 /* PBXTargetDependency */, DC00AB6A1D821C0700513D74 /* PBXTargetDependency */, - DC0BC55B1D8B6D2E00070CB0 /* PBXTargetDependency */, - DC0BC5791D8B6EE200070CB0 /* PBXTargetDependency */, ); name = Security_osx; productName = Security_osx; productReference = DC1789041D77980500B50D50 /* Security.framework */; productType = "com.apple.product-type.framework"; }; + DC222C371E034D1F00B09171 /* libsecurityd_ios_NO_AKS */ = { + isa = PBXNativeTarget; + buildConfigurationList = DC222C741E034D1F00B09171 /* Build configuration list for PBXNativeTarget "libsecurityd_ios_NO_AKS" */; + buildPhases = ( + DC222C381E034D1F00B09171 /* Sources */, + DC222C631E034D1F00B09171 /* Frameworks */, + DC222C641E034D1F00B09171 /* Headers */, + 6C0B0C481E2537E2007F95E5 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = libsecurityd_ios_NO_AKS; + productName = libsecurity; + productReference = DC222C771E034D1F00B09171 /* libsecurityd_ios_NO_AKS.a */; + productType = "com.apple.product-type.library.static"; + }; + DC3502B41E0208BE00BC0587 /* CKKSTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = DC3502BA1E0208BE00BC0587 /* Build configuration list for PBXNativeTarget "CKKSTests" */; + buildPhases = ( + DC3502B11E0208BE00BC0587 /* Sources */, + DC3502B21E0208BE00BC0587 /* Frameworks */, + DC9A2C791EB40A64008FAC27 /* Embed OCMock */, + DC7162D41EB4154D000D2BB5 /* Copy BATS Test Discovery Plist */, + DC7162D61EB4157D000D2BB5 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + DC3502C71E020D5600BC0587 /* PBXTargetDependency */, + DC3502C41E020D4D00BC0587 /* PBXTargetDependency */, + DC3502CE1E020E2200BC0587 /* PBXTargetDependency */, + DC0984F71E1DB6D400140ADC /* PBXTargetDependency */, + DC0985001E1DB70A00140ADC /* PBXTargetDependency */, + DC3502D51E02117600BC0587 /* PBXTargetDependency */, + DC222C791E034EE700B09171 /* PBXTargetDependency */, + ); + name = CKKSTests; + productName = CKKSTests; + productReference = DC3502B51E0208BE00BC0587 /* CKKSTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; DC3A4B571D91E9FB00E46D4A /* CodeSigningHelper */ = { isa = PBXNativeTarget; buildConfigurationList = DC3A4B5B1D91E9FB00E46D4A /* Build configuration list for PBXNativeTarget "CodeSigningHelper" */; @@ -19862,6 +23067,7 @@ DC52E7741D80BC8000B0A59C /* Sources */, DC52E7AD1D80BC8000B0A59C /* Frameworks */, DC52E7AE1D80BC8000B0A59C /* Headers */, + 6C0B0C4A1E253840007F95E5 /* CopyFiles */, ); buildRules = ( ); @@ -19872,26 +23078,9 @@ productReference = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; productType = "com.apple.product-type.library.static"; }; - DC52E88A1D80C1EB00B0A59C /* secipc_client */ = { + DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */ = { isa = PBXNativeTarget; - buildConfigurationList = DC52E8B71D80C1EB00B0A59C /* Build configuration list for PBXNativeTarget "secipc_client" */; - buildPhases = ( - DC52E88B1D80C1EB00B0A59C /* Sources */, - DC52E8AB1D80C1EB00B0A59C /* Frameworks */, - DC52E8AC1D80C1EB00B0A59C /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = secipc_client; - productName = libsecurity; - productReference = DC52E8BA1D80C1EB00B0A59C /* libsecipc_client.a */; - productType = "com.apple.product-type.library.static"; - }; - DC52E8BE1D80C25800B0A59C /* SecureObjectSync */ = { - isa = PBXNativeTarget; - buildConfigurationList = DC52E8C31D80C25800B0A59C /* Build configuration list for PBXNativeTarget "SecureObjectSync" */; + buildConfigurationList = DC52E8C31D80C25800B0A59C /* Build configuration list for PBXNativeTarget "SecureObjectSyncServer" */; buildPhases = ( DC52E8BF1D80C25800B0A59C /* Sources */, DC52E8C11D80C25800B0A59C /* Frameworks */, @@ -19901,9 +23090,9 @@ ); dependencies = ( ); - name = SecureObjectSync; + name = SecureObjectSyncServer; productName = libsecurity; - productReference = DC52E8C61D80C25800B0A59C /* libSecureObjectSync.a */; + productReference = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; productType = "com.apple.product-type.library.static"; }; DC52EA441D80CB7000B0A59C /* SecurityTool */ = { @@ -20258,14 +23447,14 @@ buildRules = ( ); dependencies = ( + DC0BB4441ED4D74A0035F886 /* PBXTargetDependency */, DC65E7601D8CB4A300152EF0 /* PBXTargetDependency */, DC59EA931D91CDD6001BDDF5 /* PBXTargetDependency */, DC65E7621D8CB4AA00152EF0 /* PBXTargetDependency */, DC00ABE21D821F6000513D74 /* PBXTargetDependency */, - DC00ABDC1D821F5300513D74 /* PBXTargetDependency */, - DC71DA0F1D95E1210065FB93 /* PBXTargetDependency */, DC00ABE01D821F5C00513D74 /* PBXTargetDependency */, - DC00ABDE1D821F5600513D74 /* PBXTargetDependency */, + DCD8A1F21E09F8DB00E4FA0A /* PBXTargetDependency */, + D40B6A921E2B678D00CD6EE5 /* PBXTargetDependency */, DC00ABE41D821F6200513D74 /* PBXTargetDependency */, DCD22D671D8CC387001C9B81 /* PBXTargetDependency */, DC65E7641D8CB4B100152EF0 /* PBXTargetDependency */, @@ -20650,6 +23839,23 @@ productReference = DCD66DDB1D8205C400DB1393 /* libSecOtrOSX.a */; productType = "com.apple.product-type.library.static"; }; + DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */ = { + isa = PBXNativeTarget; + buildConfigurationList = DCD8A1961E09EE0F00E4FA0A /* Build configuration list for PBXNativeTarget "SecureObjectSyncFramework" */; + buildPhases = ( + DCD8A1071E09EE0F00E4FA0A /* Sources */, + DCD8A1541E09EE0F00E4FA0A /* Frameworks */, + DCD8A1551E09EE0F00E4FA0A /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SecureObjectSyncFramework; + productName = libsecurity; + productReference = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; + productType = "com.apple.product-type.library.static"; + }; DCE4E68A1D7A37FA00AFB96E /* security2tool_macos */ = { isa = PBXNativeTarget; buildConfigurationList = DCE4E6A11D7A37FA00AFB96E /* Build configuration list for PBXNativeTarget "security2tool_macos" */; @@ -20665,6 +23871,7 @@ DC71D8E41D959C000065FB93 /* PBXTargetDependency */, DC00AB921D821D6000513D74 /* PBXTargetDependency */, DC71DA0D1D95DD670065FB93 /* PBXTargetDependency */, + DCD8A2031E09FAE500E4FA0A /* PBXTargetDependency */, DC00AB941D821D6500513D74 /* PBXTargetDependency */, DC00AB961D821D6800513D74 /* PBXTargetDependency */, ); @@ -20694,6 +23901,7 @@ DCB345B31D8A361F0054D16E /* PBXTargetDependency */, DC63CAFA1D91A16700C03317 /* PBXTargetDependency */, DCE4E7BC1D7A45ED00AFB96E /* PBXTargetDependency */, + ACBAF6FE1E941E090007BA2F /* PBXTargetDependency */, DC0BCA781D8B830900070CB0 /* PBXTargetDependency */, DC65E7521D8CB45300152EF0 /* PBXTargetDependency */, ); @@ -20729,45 +23937,48 @@ buildPhases = ( DCE4E7F21D7A4DA800AFB96E /* Sources */, DCE4E7F31D7A4DA800AFB96E /* Frameworks */, - DCE4E7F41D7A4DA800AFB96E /* CopyFiles */, - DCE4E80B1D7A4E2900AFB96E /* CopyFiles */, + DCE4E7F41D7A4DA800AFB96E /* Copy LaunchAgents files */, + DCE4E80B1D7A4E2900AFB96E /* Copy Logging Files */, + EBC15B1C1DB432E600126882 /* Copy Sandbox profile */, + 6C1520D31DCCF6F000C85C6D /* Install man8 page */, ); buildRules = ( ); dependencies = ( + DCD8A2071E09FB1F00E4FA0A /* PBXTargetDependency */, DC71DA091D95BEE00065FB93 /* PBXTargetDependency */, DC71DA031D95BDEA0065FB93 /* PBXTargetDependency */, DC00AB721D821C4600513D74 /* PBXTargetDependency */, DC00AB741D821C4800513D74 /* PBXTargetDependency */, + D40B6A951E2B67FF00CD6EE5 /* PBXTargetDependency */, DC65E7261D8CB2E100152EF0 /* PBXTargetDependency */, DC00AB761D821C4C00513D74 /* PBXTargetDependency */, - DC00AB781D821C5000513D74 /* PBXTargetDependency */, ); name = secd; productName = secd; productReference = DCE4E7F61D7A4DA800AFB96E /* secd */; productType = "com.apple.product-type.tool"; }; - DCE4E82D1D7A57AE00AFB96E /* trustd */ = { + DCE4E82D1D7A57AE00AFB96E /* trustd_macos */ = { isa = PBXNativeTarget; - buildConfigurationList = DCE4E8561D7A57AE00AFB96E /* Build configuration list for PBXNativeTarget "trustd" */; + buildConfigurationList = DCE4E8561D7A57AE00AFB96E /* Build configuration list for PBXNativeTarget "trustd_macos" */; buildPhases = ( DCE4E8381D7A57AE00AFB96E /* Sources */, DCE4E83A1D7A57AE00AFB96E /* Frameworks */, - DCE4E8521D7A57AE00AFB96E /* CopyFiles */, - DCE4E8541D7A57AE00AFB96E /* CopyFiles */, + DCE4E8521D7A57AE00AFB96E /* Copy LaunchAgent */, + DCE4E8541D7A57AE00AFB96E /* Copy LaunchDaemon Files */, + BEB463AD1E64F3C1008EB77E /* Copy Sandbox */, + D4ADA3111E2B209C0031CEA3 /* Install man8 page */, ); buildRules = ( ); dependencies = ( + D40B6A811E2B5F4700CD6EE5 /* PBXTargetDependency */, DC71DA0B1D95BEF60065FB93 /* PBXTargetDependency */, DC71DA051D95BDF90065FB93 /* PBXTargetDependency */, - DC00AB851D821CA300513D74 /* PBXTargetDependency */, - DC00AB871D821CA900513D74 /* PBXTargetDependency */, - DC00AB891D821CAD00513D74 /* PBXTargetDependency */, DC65E72C1D8CB31200152EF0 /* PBXTargetDependency */, ); - name = trustd; + name = trustd_macos; productName = secd; productReference = DCE4E8591D7A57AE00AFB96E /* trustd */; productType = "com.apple.product-type.tool"; @@ -20818,7 +24029,8 @@ DCE4E90D1D7F3D5300AFB96E /* Sources */, DCE4E90E1D7F3D5300AFB96E /* Frameworks */, DCE4E90F1D7F3D5300AFB96E /* Resources */, - DCE4E9701D7F3EA700AFB96E /* CopyFiles */, + DCE4E9701D7F3EA700AFB96E /* Install launchd plist */, + EB76B75B1DCB0DD500C43FBC /* Install man8 page */, ); buildRules = ( ); @@ -20969,6 +24181,7 @@ DC59EA871D91CD76001BDDF5 /* PBXTargetDependency */, DC00ABBB1D821E9B00513D74 /* PBXTargetDependency */, DC00ABBD1D821E9F00513D74 /* PBXTargetDependency */, + DCD8A1F51E09F91F00E4FA0A /* PBXTargetDependency */, DC65E74E1D8CB41E00152EF0 /* PBXTargetDependency */, DC0BCDB91D8C6AE000070CB0 /* PBXTargetDependency */, DC65E7501D8CB42700152EF0 /* PBXTargetDependency */, @@ -21037,10 +24250,8 @@ dependencies = ( E7D847D11C6BE9720025BB44 /* PBXTargetDependency */, DC00AB9E1D821DBB00513D74 /* PBXTargetDependency */, - DC00ABA01D821DBC00513D74 /* PBXTargetDependency */, - DC00ABA21D821DBF00513D74 /* PBXTargetDependency */, + DCD8A1F81E09F97300E4FA0A /* PBXTargetDependency */, DC65E7401D8CB3CD00152EF0 /* PBXTargetDependency */, - DC00ABA41D821DC400513D74 /* PBXTargetDependency */, DC59EA811D91CD16001BDDF5 /* PBXTargetDependency */, DC65E7421D8CB3D400152EF0 /* PBXTargetDependency */, ); @@ -21065,6 +24276,81 @@ productReference = EB0BC93E1C3C791500785842 /* secedumodetest */; productType = "com.apple.product-type.tool"; }; + EB1055741E14DF430003C309 /* SecCertificateFuzzer */ = { + isa = PBXNativeTarget; + buildConfigurationList = EB1055761E14DF430003C309 /* Build configuration list for PBXNativeTarget "SecCertificateFuzzer" */; + buildPhases = ( + EB1055711E14DF430003C309 /* Sources */, + EB1055721E14DF430003C309 /* Frameworks */, + EB1055801E14DFE40003C309 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SecCertificateFuzzer; + productName = SecCertificateFuzzer; + productReference = EB1055751E14DF430003C309 /* libSecCertificateFuzzer.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; + EB108F181E6CE4D2003B0456 /* KCPairingTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = EB108F3E1E6CE4D2003B0456 /* Build configuration list for PBXNativeTarget "KCPairingTests" */; + buildPhases = ( + EB108F251E6CE4D2003B0456 /* Sources */, + EB108F2B1E6CE4D2003B0456 /* Frameworks */, + EB108F3A1E6CE4D2003B0456 /* Resources */, + EB108F3D1E6CE4D2003B0456 /* chmod BATS Tests */, + ); + buildRules = ( + ); + dependencies = ( + EBFBC2B21E76585500A34469 /* PBXTargetDependency */, + EBFBC2B41E76586700A34469 /* PBXTargetDependency */, + EBFBC2B61E76587800A34469 /* PBXTargetDependency */, + EB108F1F1E6CE4D2003B0456 /* PBXTargetDependency */, + EBFBC2B81E76588200A34469 /* PBXTargetDependency */, + EBFBC2BA1E76588A00A34469 /* PBXTargetDependency */, + ); + name = KCPairingTests; + productName = KeychainCircleTests; + productReference = EB108F411E6CE4D2003B0456 /* KCPairingTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + EB27FF101E402CD300EC9E3A /* ckksctl */ = { + isa = PBXNativeTarget; + buildConfigurationList = EB27FF151E402CD400EC9E3A /* Build configuration list for PBXNativeTarget "ckksctl" */; + buildPhases = ( + EB27FF0D1E402CD300EC9E3A /* Sources */, + EB27FF0E1E402CD300EC9E3A /* Frameworks */, + EB27FF0F1E402CD300EC9E3A /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ckksctl; + productName = ckksctl; + productReference = EB27FF111E402CD300EC9E3A /* ckksctl */; + productType = "com.apple.product-type.tool"; + }; + EB2D54A11F02A45E00E46890 /* secatomicfile */ = { + isa = PBXNativeTarget; + buildConfigurationList = EB2D54A71F02A45E00E46890 /* Build configuration list for PBXNativeTarget "secatomicfile" */; + buildPhases = ( + EB2D54A21F02A45E00E46890 /* Sources */, + EB2D54A41F02A45E00E46890 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + EBFF18D01F02C2FE004E58FC /* PBXTargetDependency */, + ); + name = secatomicfile; + productName = secbackupntest; + productReference = EB2D54AA1F02A45E00E46890 /* secatomicfile */; + productType = "com.apple.product-type.tool"; + }; EB425C9E1C65846D000ECE53 /* secbackuptest */ = { isa = PBXNativeTarget; buildConfigurationList = EB425CA31C65846D000ECE53 /* Build configuration list for PBXNativeTarget "secbackuptest" */; @@ -21129,6 +24415,23 @@ productReference = EBA9AA861CE30E58004E2B68 /* secitemnotifications */; productType = "com.apple.product-type.tool"; }; + EBB839A41E29665D00853BAC /* secfuzzer */ = { + isa = PBXNativeTarget; + buildConfigurationList = EBB839A91E29665E00853BAC /* Build configuration list for PBXNativeTarget "secfuzzer" */; + buildPhases = ( + EBB839A11E29665D00853BAC /* Sources */, + EBB839A21E29665D00853BAC /* Frameworks */, + EBB839A31E29665D00853BAC /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = secfuzzer; + productName = secfuzzer; + productReference = EBB839A51E29665D00853BAC /* secfuzzer */; + productType = "com.apple.product-type.tool"; + }; EBCF73F31CE45F9C00BED7CA /* secitemfunctionality */ = { isa = PBXNativeTarget; buildConfigurationList = EBCF73F91CE45F9C00BED7CA /* Build configuration list for PBXNativeTarget "secitemfunctionality" */; @@ -21164,29 +24467,116 @@ productReference = EBF374721DC055580065D840 /* security-sysdiagnose */; productType = "com.apple.product-type.tool"; }; + F621D0271ED6DCE7000EA569 /* authorizationdump */ = { + isa = PBXNativeTarget; + buildConfigurationList = F621D07C1ED6DCE7000EA569 /* Build configuration list for PBXNativeTarget "authorizationdump" */; + buildPhases = ( + F621D02A1ED6DCE7000EA569 /* Sources */, + F621D04E1ED6DCE7000EA569 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = authorizationdump; + productName = securitytool_macos; + productReference = F621D07F1ED6DCE7000EA569 /* authorizationdump */; + productType = "com.apple.product-type.tool"; + }; + F667EC561E96E9B100203D5C /* authdtest */ = { + isa = PBXNativeTarget; + buildConfigurationList = F667EC5D1E96E9B100203D5C /* Build configuration list for PBXNativeTarget "authdtest" */; + buildPhases = ( + F667EC571E96E9B100203D5C /* Sources */, + F667EC591E96E9B100203D5C /* Frameworks */, + F667EC5C1E96E9B100203D5C /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + F667EC651E96EDCF00203D5C /* PBXTargetDependency */, + ); + name = authdtest; + productName = seckeychainnetworkextensionstest; + productReference = F667EC601E96E9B100203D5C /* authdtest */; + productType = "com.apple.product-type.tool"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 4C35DB69094F906D002917C4 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0900; TargetAttributes = { 4381690B1B4EDCBD00C54D58 = { CreatedOnToolsVersion = 7.0; }; + 470415CE1E5E14B5001F3D95 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; + 47702B1D1E5F409700B29577 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; + 47702B2D1E5F492C00B29577 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; + 47C51B831EEA657D0032D9E5 = { + CreatedOnToolsVersion = 9.0; + }; 5EBE24791B00CCAE0007DB0E = { CreatedOnToolsVersion = 7.0; }; + 6C98082C1E788AEB00E70590 = { + TestTargetID = 6CF4A0B31E45488B00ECD7B5; + }; + 6C9808681E788AFD00E70590 = { + TestTargetID = 6CF4A0DF1E4549F200ECD7B5; + }; + 6CCDF7831E3C25FA003F2555 = { + CreatedOnToolsVersion = 8.3; + ProvisioningStyle = Automatic; + }; + 6CF4A0B31E45488B00ECD7B5 = { + CreatedOnToolsVersion = 8.3; + ProvisioningStyle = Automatic; + }; + 6CF4A0DF1E4549F200ECD7B5 = { + CreatedOnToolsVersion = 8.3; + ProvisioningStyle = Automatic; + }; + BEF88C271EAFFC3F00357577 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; + BEF88C2F1EAFFC3F00357577 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; CD276C261A83F60C003226BC = { CreatedOnToolsVersion = 7.0; }; + D41257CE1E9410A300781F23 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; D41AD42D1B967169008C7270 = { CreatedOnToolsVersion = 7.0; }; D41AD4311B967179008C7270 = { CreatedOnToolsVersion = 7.0; }; + D4ADA3181E2B41670031CEA3 = { + CreatedOnToolsVersion = 8.3; + ProvisioningStyle = Automatic; + }; + DA30D6751DF8C8FB00EC6B43 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Automatic; + }; DC008B451D90CE53004002A3 = { CreatedOnToolsVersion = 8.0; ProvisioningStyle = Automatic; @@ -21207,6 +24597,10 @@ CreatedOnToolsVersion = 8.0; ProvisioningStyle = Automatic; }; + DC3502B41E0208BE00BC0587 = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; DC3A4B571D91E9FB00E46D4A = { CreatedOnToolsVersion = 8.0; ProvisioningStyle = Automatic; @@ -21313,6 +24707,14 @@ E7D847CD1C6BE9720025BB44 = { CreatedOnToolsVersion = 7.3; }; + EB1055741E14DF430003C309 = { + CreatedOnToolsVersion = 8.2.1; + ProvisioningStyle = Automatic; + }; + EB27FF101E402CD300EC9E3A = { + CreatedOnToolsVersion = 8.3; + ProvisioningStyle = Automatic; + }; EB6A6FA81B90F83A0045DC68 = { CreatedOnToolsVersion = 7.0; }; @@ -21328,6 +24730,10 @@ EB9C1DAE1BDFD4DE00F89272 = { CreatedOnToolsVersion = 7.1; }; + EBB839A41E29665D00853BAC = { + CreatedOnToolsVersion = 8.3; + ProvisioningStyle = Automatic; + }; EBBE20571C21380100B7A639 = { CreatedOnToolsVersion = 7.2; }; @@ -21395,12 +24801,14 @@ DC1789031D77980500B50D50 /* Security_osx */, DC1785041D77873100B50D50 /* copyHeadersToSystem */, E7D847C41C6BE9710025BB44 /* KeychainCircle */, + BEF88C271EAFFC3F00357577 /* TrustedPeers */, DC8E04911D7F6CED006D80EB /* ======= Daemons ========= */, DCE4E8931D7F34F600AFB96E /* authd */, DCE4E7F51D7A4DA800AFB96E /* secd */, 790851B50CA9859F0083CC4D /* securityd_ios */, DC5AC04F1D8352D900CF422C /* securityd_macos */, - DCE4E82D1D7A57AE00AFB96E /* trustd */, + D41257CE1E9410A300781F23 /* trustd_ios */, + DCE4E82D1D7A57AE00AFB96E /* trustd_macos */, 52D82BDD16A621F70078DFE5 /* CloudKeychainProxy */, CD276C261A83F60C003226BC /* KeychainSyncingOverIDSProxy */, DC0BC5501D8B6D2D00070CB0 /* XPCKeychainSandboxCheck */, @@ -21408,8 +24816,10 @@ DC8E04B11D7F6EC9006D80EB /* ======= Libraries ========= */, DCC78EA81D8088E200865A7C /* security */, DC52E7731D80BC8000B0A59C /* libsecurityd_ios */, - DC52E88A1D80C1EB00B0A59C /* secipc_client */, - DC52E8BE1D80C25800B0A59C /* SecureObjectSync */, + DC222C371E034D1F00B09171 /* libsecurityd_ios_NO_AKS */, + D4ADA3181E2B41670031CEA3 /* libtrustd */, + DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */, + DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */, DC52EA441D80CB7000B0A59C /* SecurityTool */, DC52EBC61D80CEF100B0A59C /* SecurityCommands */, DC52EC211D80CFB200B0A59C /* SOSCommands */, @@ -21428,6 +24838,8 @@ DC0BCCF41D8C694700070CB0 /* utilitiesRegressions */, DC0BC9C81D8B824700070CB0 /* security_ssl */, DC0BCA131D8B82B000070CB0 /* security_ssl_regressions */, + DCD06AA91D8E0D53007602F1 /* security_utilities */, + 225394AC1E3080A600D3CD9B /* security_codesigning_ios */, DC8834011D8A218F00CE0ACA /* ASN1_not_installed */, DC71D99F1D95BA6C0065FB93 /* ASN1 */, DC59E9AC1D91C9DC001BDDF5 /* DER_not_installed */, @@ -21458,8 +24870,8 @@ DC0BC9661D8B810A00070CB0 /* security_pkcs12 */, DC0BC99A1D8B81BE00070CB0 /* security_sd_cspdl */, DC0BCA791D8B858600070CB0 /* security_transform */, + ACBAF6991E9417F40007BA2F /* security_transform_regressions */, DC0BCB011D8B894F00070CB0 /* security_translocate */, - DCD06AA91D8E0D53007602F1 /* security_utilities */, DCF787501D88C86900E694BB /* security_apple_empty */, DC6A82911D87749900418608 /* securityd_client_macos */, DC0067921D87876F005AF8DB /* securityd_server_macos */, @@ -21473,28 +24885,38 @@ 4C52D0B316EFC61E0079966E /* CircleJoinRequested */, F93C49021AB8FCE00047E01A /* ckcdiagnose.sh */, EBF374711DC055580065D840 /* security-sysdiagnose */, + EB27FF101E402CD300EC9E3A /* ckksctl */, + F621D0271ED6DCE7000EA569 /* authorizationdump */, DC8E04A11D7F6DFC006D80EB /* ======= Apps ========== */, DCE4E9101D7F3D5300AFB96E /* Keychain Circle Notification */, DCE4E8DC1D7F39DB00AFB96E /* Cloud Keychain Utility */, BE197F2519116FD100BA91D1 /* SharedWebCredentialViewService */, DC8E049D1D7F6DBC006D80EB /* ==== Test Binaries ======= */, + BEF88C2F1EAFFC3F00357577 /* TrustedPeersTests */, E7D847CD1C6BE9720025BB44 /* KeychainCircleTests */, + EB108F181E6CE4D2003B0456 /* KCPairingTests */, 4C711D5813AFCD0900FE865D /* SecurityDevTests */, E710C7411331946400F85568 /* SecurityTests */, DCE4E7311D7A43B500AFB96E /* SecurityTestsOSX */, + DC3502B41E0208BE00BC0587 /* CKKSTests */, DC610AAD1D7910C3002223DE /* gk_reset_check_macos */, DC610A551D78F9D2002223DE /* codesign_tests_macos */, DC610A461D78F48F002223DE /* SecTaskTest_macos */, 5EBE24791B00CCAE0007DB0E /* secacltests */, + EB2D54A11F02A45E00E46890 /* secatomicfile */, 0C0BDB2E175685B000BC1A7E /* secdtests_ios */, DC610A021D78F129002223DE /* secdtests_macos */, EB9C1D791BDFD0E000F89272 /* secbackupntest */, EB425C9E1C65846D000ECE53 /* secbackuptest */, EB0BC9361C3C791500785842 /* secedumodetest */, EBCF73F31CE45F9C00BED7CA /* secitemfunctionality */, + BED208D41EDF950E00753952 /* manifeststresstest */, EB433A201CC3243600A7EACE /* secitemstresstest */, EBA9AA7D1CE30E58004E2B68 /* secitemnotifications */, DCE4E7CB1D7A4AED00AFB96E /* sectests_macos */, + 470415CE1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */, + 47702B1D1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */, + 47702B2D1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */, 0C6799F912F7C37C00712919 /* dtlsTests */, 0C2BCBA81D06401F00ED7A2F /* dtlsEchoClient */, 0C2BCBBD1D0648D100ED7A2F /* dtlsEchoServer */, @@ -21506,6 +24928,11 @@ DC59EA621D91CB9F001BDDF5 /* parseTicket */, DC0BC5C51D8B72E700070CB0 /* test-checkpw */, DC0BC5D51D8B73B000070CB0 /* perf-checkpw */, + 6C98082C1E788AEB00E70590 /* CKKSCloudKitTests_mac */, + 6C9808681E788AFD00E70590 /* CKKSCloudKitTests_ios */, + 6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */, + 6CF4A0DF1E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */, + 6CCDF7831E3C25FA003F2555 /* KeychainEntitledTestRunner */, DC5AC1351D835D9700CF422C /* ===== Source Gen ===== */, DC008B451D90CE53004002A3 /* securityd_macos_mig */, DC6BC26C1D90CFEF00DD57B3 /* securityd_macos_startup */, @@ -21521,6 +24948,7 @@ 728B56A016D59979008FA3AB /* OTAPKIAssetTool */, 5E10992419A5E55800A60E2B /* ISACLProtectedItems */, 5346480017331E1100FE9172 /* KeychainSyncAccountNotification */, + DA30D6751DF8C8FB00EC6B43 /* KeychainSyncAccountUpdater */, 4381690B1B4EDCBD00C54D58 /* SOSCCAuthPlugin */, DCD0696B1D8CE1F9007602F1 /* ==== Code Signing ===== */, DCD06A7B1D8CE32F007602F1 /* All Codesigning */, @@ -21529,6 +24957,9 @@ DCD069661D8CE105007602F1 /* codesigning_RequirementsLanguage */, DCD06A541D8CE2D5007602F1 /* gkunpack */, DC3A4B571D91E9FB00E46D4A /* CodeSigningHelper */, + EB10556D1E14DD670003C309 /* === Fuzzer Targets ===== */, + EBB839A41E29665D00853BAC /* secfuzzer */, + EB1055741E14DF430003C309 /* SecCertificateFuzzer */, DC8E04A91D7F6E63006D80EB /* === Legacy Targets ===== */, DCF7889C1D88CB5200E694BB /* plugin_apple_x509_cl */, EB9C1DAE1BDFD4DE00F89272 /* SecurityBatsTests */, @@ -21538,6 +24969,8 @@ EB6A6FB41B90F8C90045DC68 /* phase2 */, E79EEDE01CD4000C00C2FBFC /* Security_executables */, 05EF68B519491512007958C3 /* Security_frameworks */, + F667EC561E96E9B100203D5C /* authdtest */, + 47C51B831EEA657D0032D9E5 /* SecurityUnitTests */, ); }; /* End PBXProject section */ @@ -21630,6 +25063,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 47C51B821EEA657D0032D9E5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4C32C0AB0A4975F6002891BD /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -21638,6 +25078,7 @@ BE4AC9BA18B8273600B84964 /* SharedWebCredentials.strings in Resources */, DCEE1E861D93427400DC0EB7 /* com.apple.securityd.plist in Resources */, EB433A2E1CC325E900A7EACE /* secitemstresstest.entitlements in Resources */, + 475F37201EE8F23900248FB5 /* SFAnalyticsLogging.plist in Resources */, 4C198F220ACDB4BF00AAB142 /* Certificate.strings in Resources */, 4C198F230ACDB4BF00AAB142 /* OID.strings in Resources */, ); @@ -21650,6 +25091,7 @@ 52A23EDD161DEC3F00E271E0 /* Default-568h@2x.png in Resources */, D4D886E91CEBDD2A00DC7583 /* nist-certs in Resources */, D4D886BF1CEB9F3B00DC7583 /* ssl-policy-certs in Resources */, + D4AA64861E97273D00D317ED /* si-18-certificate-parse in Resources */, D4EC94FB1CEA482D0083E753 /* si-20-sectrust-policies-data in Resources */, 0C0C88781CCEC5C400617D1B /* si-82-sectrust-ct-data in Resources */, ); @@ -21671,6 +25113,39 @@ ); 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; + files = ( + 6CF4A0C01E45488B00ECD7B5 /* Assets.xcassets in Resources */, + 6CF4A0C31E45488B00ECD7B5 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6CF4A0DE1E4549F200ECD7B5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6CF4A0F21E4549F300ECD7B5 /* LaunchScreen.storyboard in Resources */, + 6CF4A0EF1E4549F300ECD7B5 /* Assets.xcassets in Resources */, + 6CF4A0ED1E4549F300ECD7B5 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; BE197F2419116FD100BA91D1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -21680,6 +25155,27 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BEF88C261EAFFC3F00357577 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BEF88C2E1EAFFC3F00357577 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DA30D6741DF8C8FB00EC6B43 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC0BC54F1D8B6D2D00070CB0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -21712,7 +25208,6 @@ DC178A451D77A1F600B50D50 /* framework.sb in Resources */, DC178A2D1D77A1E700B50D50 /* tp_policyOids.mdsinfo in Resources */, DC178A231D77A1E700B50D50 /* csp_primary.mdsinfo in Resources */, - DC178A411D77A1F500B50D50 /* iToolsTrustedApps.plist in Resources */, DC178A251D77A1E700B50D50 /* cspdl_csp_capabilities.mdsinfo in Resources */, DC178A281D77A1E700B50D50 /* dl_common.mdsinfo in Resources */, DC178A441D77A1F600B50D50 /* SecErrorMessages.strings in Resources */, @@ -21726,6 +25221,7 @@ DC178A2F1D77A1E700B50D50 /* sd_cspdl_common.mdsinfo in Resources */, DC178A291D77A1E700B50D50 /* dl_primary.mdsinfo in Resources */, DC178A261D77A1E700B50D50 /* cspdl_csp_primary.mdsinfo in Resources */, + 475F37211EE8F23900248FB5 /* SFAnalyticsLogging.plist in Resources */, DC178A221D77A1E700B50D50 /* csp_common.mdsinfo in Resources */, DC178A431D77A1F600B50D50 /* SecDebugErrorMessages.strings in Resources */, DC178A481D77A1F600B50D50 /* TimeStampingPrefs.plist in Resources */, @@ -21755,6 +25251,7 @@ files = ( DCE4E76D1D7A43B500AFB96E /* nist-certs in Resources */, DCE4E76E1D7A43B500AFB96E /* ssl-policy-certs in Resources */, + D4AA64881E97275200D317ED /* si-18-certificate-parse in Resources */, DCE4E76F1D7A43B500AFB96E /* si-20-sectrust-policies-data in Resources */, DCE4E7701D7A43B500AFB96E /* si-82-sectrust-ct-data in Resources */, DCE4E7B41D7A43DC00AFB96E /* si-82-sectrust-ct-logs.plist in Resources */, @@ -21806,6 +25303,7 @@ 52A23EDC161DEC3800E271E0 /* Default-568h@2x.png in Resources */, D4D886EA1CEBDE0800DC7583 /* nist-certs in Resources */, D4D886C01CEB9F7200DC7583 /* ssl-policy-certs in Resources */, + D4AA64871E97274900D317ED /* si-18-certificate-parse in Resources */, D4EC94FE1CEA48760083E753 /* si-20-sectrust-policies-data in Resources */, 0C0C88791CCEC5C500617D1B /* si-82-sectrust-ct-data in Resources */, ); @@ -21832,6 +25330,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EB108F3A1E6CE4D2003B0456 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -21864,6 +25369,19 @@ shellScript = "if [ -d $DSTROOT ]; then\n RC_HIDE_J79_VAL=0\n RC_HIDE_J80_VAL=0\n SEC_HDRS_PATH=\"System/Library/Frameworks/Security.framework/Headers\"\n\n if [ ! -z $RC_HIDE_J79 ]; then\n RC_HIDE_J79_VAL=1\n fi\n\n if [ ! -z $RC_HIDE_J80 ]; then\n RC_HIDE_J80_VAL=1\n fi\n\n if [ -a $DSTROOT/$SEC_HDRS_PATH/SecAccessControl.h ]; then\n unifdef -B -DRC_HIDE_J79=$RC_HIDE_J79_VAL -DRC_HIDE_J80=$RC_HIDE_J80_VAL -o $DSTROOT/$SEC_HDRS_PATH/SecAccessControl.h $DSTROOT/$SEC_HDRS_PATH/SecAccessControl.h\n if [$? eq 2]; then\n exit 2\n fi\n fi\n\n if [ -a $DSTROOT/$SEC_HDRS_PATH/SecItem.h ]; then\n unifdef -B -DRC_HIDE_J79=$RC_HIDE_J79_VAL -DRC_HIDE_J80=$RC_HIDE_J80_VAL -o $DSTROOT/$SEC_HDRS_PATH/SecItem.h $DSTROOT/$SEC_HDRS_PATH/SecItem.h\n if [$? eq 2]; then\n exit 2\n fi\n fi\n\n exit 0\nfi"; showEnvVarsInLog = 0; }; + 6CB5F4761E402D0000DBF3F0 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "chown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist"; + }; 8E64DAF81C17BA620076C9DF /* Install launchd plist */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; @@ -21973,19 +25491,19 @@ shellPath = /bin/sh; shellScript = "set -x\n\nDERIVED_SRC=${BUILT_PRODUCTS_DIR}/derived_src\nmkdir -p ${DERIVED_SRC}\n\n# make error message string files\n\nGENDEBUGSTRS[0]=YES; ERRORSTRINGS[0]=${DERIVED_SRC}/SecDebugErrorMessages.strings\nGENDEBUGSTRS[1]=NO ; ERRORSTRINGS[1]=${DERIVED_SRC}/en.lproj/SecErrorMessages.strings\n\nmkdir -p ${DERIVED_SRC}/en.lproj\n\nfor ((ix=0;ix<2;ix++)) ; do\nperl OSX/lib/generateErrStrings.pl \\\n${GENDEBUGSTRS[ix]} \\\n${DERIVED_SRC} \\\n${ERRORSTRINGS[ix]} \\\n${BUILT_PRODUCTS_DIR}/Security.framework/Headers/Authorization.h \\\n${BUILT_PRODUCTS_DIR}/Security.framework/Headers/AuthSession.h \\\n${BUILT_PRODUCTS_DIR}/Security.framework/Headers/SecureTransport.h \\\n${BUILT_PRODUCTS_DIR}/Security.framework/Headers/SecBase.h \\\n${BUILT_PRODUCTS_DIR}/Security.framework/Headers/cssmerr.h \\\n${BUILT_PRODUCTS_DIR}/Security.framework/Headers/cssmapple.h \\\n${BUILT_PRODUCTS_DIR}/Security.framework/Headers/CSCommon.h \\\n${BUILT_PRODUCTS_DIR}/Security.framework/PrivateHeaders/AuthorizationPriv.h \\\n${PROJECT_DIR}/OSX/libsecurity_keychain/lib/MacOSErrorStrings.h \\\n${BUILT_PRODUCTS_DIR}/Security.framework/PrivateHeaders/SecureTransportPriv.h\ndone\n"; }; - DC178B481D77A51600B50D50 /* Run Script Copy XPC Service */ = { + DC178B481D77A51600B50D50 /* Make XPC server symlink */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Run Script Copy XPC Service"; + name = "Make XPC server symlink"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ ! -h ${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/XPCServices ]; then\nln -s Versions/Current/XPCServices ${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/XPCServices\nfi\n\nexit 0"; + 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"; }; DC58C4381D77BE5E003C25A4 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -22070,6 +25588,19 @@ shellPath = /bin/sh; shellScript = "TARGET=${BUILT_PRODUCTS_DIR}/derived_src\nCONFIG=${PROJECT_DIR}/OSX/libsecurity_cssm/lib/generator.cfg\n\nmkdir -p ${TARGET}\n/usr/bin/perl ${PROJECT_DIR}/OSX/libsecurity_cssm/lib/generator.pl ${SRCROOT}/OSX/libsecurity_cssm/lib/ ${CONFIG} ${TARGET}"; }; + DC7162D61EB4157D000D2BB5 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "chown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist"; + }; DC71D9FE1D95BB5B0065FB93 /* Why is this here? */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; @@ -22269,6 +25800,22 @@ shellScript = "chown root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist"; showEnvVarsInLog = 0; }; + EB108F3D1E6CE4D2003B0456 /* chmod BATS Tests */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + "", + ); + name = "chmod BATS Tests"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "chown root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist"; + showEnvVarsInLog = 0; + }; EBC15E801BE29A8C001C0C5B /* Chown BATS plist */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; @@ -22291,7 +25838,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 476541A11F33EDA500413F65 /* SecdWatchdog.m in Sources */, + DCCD33D21E3FF0D800AA4AD1 /* spi.c in Sources */, 0C0BDB32175685B000BC1A7E /* main.m in Sources */, + DC5F35AF1EE0F27C00900966 /* server_entitlement_helpers.c in Sources */, + DC4269101E82FD9F002B7110 /* server_security_helpers.c in Sources */, + DCB221591E8B08CA001598BC /* server_xpc.m in Sources */, + DC4269001E82038D002B7110 /* server_endpoint.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -22317,6 +25870,45 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 225394AD1E3080A600D3CD9B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 220179EB1E3BF1F100EFB6F3 /* detachedrep.cpp in Sources */, + 220179EA1E3BF16000EFB6F3 /* slcrep.cpp in Sources */, + 220179E31E3BEB7100EFB6F3 /* dirscanner.cpp in Sources */, + 225394B71E3081F900D3CD9B /* cskernel.cpp in Sources */, + 225394B81E30820900D3CD9B /* Code.cpp in Sources */, + 225394B91E30821400D3CD9B /* bundlediskrep.cpp in Sources */, + 225394BA1E30821E00D3CD9B /* cdbuilder.cpp in Sources */, + 225394BB1E30822700D3CD9B /* codedirectory.cpp in Sources */, + DC5BD5831E8C6FC800C5EC49 /* SecTask.c in Sources */, + 225394BC1E30823E00D3CD9B /* cs.cpp in Sources */, + 225394BD1E30824C00D3CD9B /* SecCode.cpp in Sources */, + 225394BE1E30825500D3CD9B /* SecStaticCode.cpp in Sources */, + 225394BF1E30826100D3CD9B /* SecRequirement.cpp in Sources */, + 225394C01E30826B00D3CD9B /* diskrep.cpp in Sources */, + 225394C11E30827600D3CD9B /* filediskrep.cpp in Sources */, + 225394C21E30827E00D3CD9B /* kerneldiskrep.cpp in Sources */, + 225394C31E30828800D3CD9B /* StaticCode.cpp in Sources */, + 225394C41E30829300D3CD9B /* reqparser.cpp in Sources */, + 225394C51E3082A100D3CD9B /* requirement.cpp in Sources */, + 225394C61E3082AB00D3CD9B /* Requirements.cpp in Sources */, + 225394C71E3082B600D3CD9B /* reqdumper.cpp in Sources */, + 225394C81E3082BE00D3CD9B /* reqinterp.cpp in Sources */, + 225394C91E3082C900D3CD9B /* reqmaker.cpp in Sources */, + 225394CA1E3082D500D3CD9B /* macho++.cpp in Sources */, + 225394CB1E30831D00D3CD9B /* machorep.cpp in Sources */, + 225394CC1E30832A00D3CD9B /* sigblob.cpp in Sources */, + 225394CD1E30833400D3CD9B /* resources.cpp in Sources */, + 225394CE1E30833F00D3CD9B /* cfmunge.cpp in Sources */, + 225394CF1E30835700D3CD9B /* csutilities.cpp in Sources */, + 225394D01E30836200D3CD9B /* singlediskrep.cpp in Sources */, + 225394D11E30836F00D3CD9B /* reqreader.cpp in Sources */, + 225394D21E30837900D3CD9B /* cserror.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 438169081B4EDCBD00C54D58 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -22325,14 +25917,55 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 470415CB1E5E14B5001F3D95 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 470415DC1E5E1534001F3D95 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 47702B1A1E5F409700B29577 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 47702B281E5F412500B29577 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 47702B2A1E5F492C00B29577 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 47702B371E5F495C00B29577 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 47C51B801EEA657D0032D9E5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 47C51B871EEA657D0032D9E5 /* SecurityUnitTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4C32C0AC0A4975F6002891BD /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 220179E91E3BF03200EFB6F3 /* dummy.cpp in Sources */, + 4723C9CC1F152ED30082882F /* SFSQLiteStatement.m in Sources */, + DCA85B931E8D97E400BA7241 /* client.c in Sources */, 18F7F67914D77F4400F88A12 /* NtlmGenerator.c in Sources */, + 0CD8CB051ECA50780076F37F /* SOSPeerOTRTimer.m in Sources */, + DCA85B981E8D980A00BA7241 /* client_endpoint.m in Sources */, 18F7F67A14D77F4400F88A12 /* ntlmBlobPriv.c in Sources */, - 18F7F67C14D77F5000F88A12 /* SecTask.c in Sources */, + 4723C9E01F1540CE0082882F /* SFAnalyticsLogger.m in Sources */, + 4723C9C81F152ECA0082882F /* SFSQLite.m in Sources */, E7B00700170B581D00B27966 /* Security.exp-in in Sources */, + 4723C9C41F152EBB0082882F /* SFObjCType.m in Sources */, + EB48C1A51E573EE400EC5E57 /* whoami.m in Sources */, + B61F67571F1FCFCB00E2FDBB /* SecPaddingConfigurations.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -22352,8 +25985,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 476541A71F33EE3F00413F65 /* SecdWatchdog.m in Sources */, 4CC92B1D15A3BF2F00C6D578 /* testmain.c in Sources */, + DC4268F61E82036F002B7110 /* server_endpoint.m in Sources */, 0C78F1CD16A5E1BF00654E08 /* sectask-10-sectask.c in Sources */, + DCB221531E8B08BC001598BC /* server_xpc.m in Sources */, + DCCD33D01E3FEF2A00AA4AD1 /* spi.c in Sources */, + DC42690C1E82FD9A002B7110 /* server_security_helpers.c in Sources */, + DC5F35AA1EE0F27100900966 /* server_entitlement_helpers.c in Sources */, 0C78F1CF16A5E1BF00654E08 /* sectask_ipc.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -22422,8 +26061,87 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4765419B1F33ED7E00413F65 /* SecdWatchdog.m in Sources */, + DCB221581E8B08C9001598BC /* server_xpc.m in Sources */, + DCA85B971E8D980200BA7241 /* client.c in Sources */, + DCCD33E91E3FFDBF00AA4AD1 /* spi.c in Sources */, + DCA85B9B1E8D981200BA7241 /* client_endpoint.m in Sources */, + DC4269111E82FDA0002B7110 /* server_security_helpers.c in Sources */, + DC5F35AE1EE0F27C00900966 /* server_entitlement_helpers.c in Sources */, 5EBE247D1B00CCAE0007DB0E /* main.c in Sources */, 5E4E05A41B0CA0FD001C4A31 /* sec_acl_stress.c in Sources */, + DC4268FF1E82038C002B7110 /* server_endpoint.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6C98083D1E788AEB00E70590 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 476541A41F33EDED00413F65 /* SecdWatchdog.m in Sources */, + 47B011A71F17D8980030B49F /* SFAnalyticsLogger.m in Sources */, + 47B011981F17D78D0030B49F /* SFSQLite.m in Sources */, + 47B011991F17D78D0030B49F /* SFSQLiteStatement.m in Sources */, + 47B011971F17D7810030B49F /* SFObjCType.m in Sources */, + DC2D438F1F0EEC2A0005D382 /* MockCloudKit.m in Sources */, + DCB515E21ED3D134001F1152 /* SecTask.c in Sources */, + DCB515E11ED3D11A001F1152 /* client.c in Sources */, + 6C9808A61E788CD200E70590 /* CKKSCloudKitTests.m in Sources */, + 6C98083E1E788AEB00E70590 /* spi.c in Sources */, + DC2353301ECA658900D7C1BE /* server_security_helpers.c in Sources */, + DC2353321ECA659000D7C1BE /* server_xpc.m in Sources */, + DC5F35B11EE0F28B00900966 /* server_entitlement_helpers.c in Sources */, + DC2353291ECA658300D7C1BE /* server_endpoint.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6C9808791E788AFD00E70590 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 476541A51F33EE1E00413F65 /* SecdWatchdog.m in Sources */, + 47B011AD1F17D8A00030B49F /* SFAnalyticsLogger.m in Sources */, + 47B0119B1F17D7F10030B49F /* SFSQLite.m in Sources */, + 47B0119C1F17D7F10030B49F /* SFSQLiteStatement.m in Sources */, + 47B0119A1F17D7E80030B49F /* SFObjCType.m in Sources */, + DC2D43951F0EEC300005D382 /* MockCloudKit.m in Sources */, + 6C9808A51E788CD100E70590 /* CKKSCloudKitTests.m in Sources */, + DCB515E31ED3D135001F1152 /* SecTask.c in Sources */, + DCB515E01ED3D111001F1152 /* client.c in Sources */, + DCB515E41ED3D15A001F1152 /* client_endpoint.m in Sources */, + 6C98087A1E788AFD00E70590 /* spi.c in Sources */, + DC5F35B21EE0F28C00900966 /* server_entitlement_helpers.c in Sources */, + DC2353311ECA658B00D7C1BE /* server_security_helpers.c in Sources */, + DC2353331ECA659000D7C1BE /* server_xpc.m in Sources */, + DC23532F1ECA658400D7C1BE /* server_endpoint.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6CCDF7801E3C25FA003F2555 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6CB5F47B1E402E6700DBF3F0 /* KeychainEntitledTestRunner.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6CF4A0B01E45488B00ECD7B5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6CF4A0BE1E45488B00ECD7B5 /* ViewController.m in Sources */, + 6CF4A0BB1E45488B00ECD7B5 /* main.m in Sources */, + 6CF4A0B81E45488B00ECD7B5 /* AppDelegate.m in Sources */, + ); + 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; }; @@ -22440,7 +26158,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DCCD33CF1E3FEF1800AA4AD1 /* spi.c in Sources */, + 476541711F33B59500413F65 /* SecdWatchdog.m in Sources */, 790851D40CA9B19D0083CC4D /* server.c in Sources */, + DC5F35A71EE0F25100900966 /* server_entitlement_helpers.c in Sources */, + DC4269091E82FD8C002B7110 /* server_security_helpers.c in Sources */, + DCB221511E8B08A6001598BC /* server_xpc.m in Sources */, + DC6ACC471E81E08E00125DC5 /* server_endpoint.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -22454,6 +26178,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + ACBAF6BB1E9417F40007BA2F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ACBAF6F91E941B020007BA2F /* transform-01-sigverify.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; BE197F2219116FD100BA91D1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -22472,20 +26204,115 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + BED208D51EDF950E00753952 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BE22FC041EE3584400893431 /* mark.m in Sources */, + BE22FBCE1EE1E26600893431 /* Keychain.m in Sources */, + BE22FBD11EE2084100893431 /* Config.m in Sources */, + BE22FBC61EE0E8AB00893431 /* Monkey.m in Sources */, + BED208E81EDF974500753952 /* manifeststresstest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BEF88C231EAFFC3F00357577 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BEF88C781EB000BE00357577 /* TPCategoryRule.m in Sources */, + BEF88C841EB000BE00357577 /* TPPeerDynamicInfo.m in Sources */, + BEF88C921EB000BE00357577 /* TPVoucher.m in Sources */, + BEF88C901EB000BE00357577 /* TPUtils.m in Sources */, + BEF88C8A1EB000BE00357577 /* TPPolicy.m in Sources */, + BEF88C801EB000BE00357577 /* TPModel.m in Sources */, + BEF88C8C1EB000BE00357577 /* TPPolicyDocument.m in Sources */, + BEF88C7E1EB000BE00357577 /* TPHash.m in Sources */, + BEF88C881EB000BE00357577 /* TPPeerStableInfo.m in Sources */, + BEF88C861EB000BE00357577 /* TPPeerPermanentInfo.m in Sources */, + BEF88C7A1EB000BE00357577 /* TPCircle.m in Sources */, + BEF88C821EB000BE00357577 /* TPPeer.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BEF88C2C1EAFFC3F00357577 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BEF88C941EB000FD00357577 /* TPDummyDecrypter.m in Sources */, + BEF88C9D1EB000FD00357577 /* TPUtilsTests.m in Sources */, + BEF88C951EB000FD00357577 /* TPDummyEncrypter.m in Sources */, + BEF88C981EB000FD00357577 /* TPModelTests.m in Sources */, + BEF88C9B1EB000FD00357577 /* TPPeerTests.m in Sources */, + BEF88C931EB000FD00357577 /* TPCircleTests.m in Sources */, + BEF88C971EB000FD00357577 /* TPDummySigningKeyTests.m in Sources */, + BEF88C9A1EB000FD00357577 /* TPPeerStableInfoTests.m in Sources */, + BEF88C991EB000FD00357577 /* TPPeerPermanentInfoTests.m in Sources */, + BEF88C961EB000FD00357577 /* TPDummySigningKey.m in Sources */, + BEF88C9E1EB000FD00357577 /* TPVoucherTests.m in Sources */, + BEF88C9C1EB000FD00357577 /* TPPolicyDocumentTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD276C231A83F60C003226BC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( CD23B49E1DA06EB40047EDE9 /* IDSPersistentState.m in Sources */, CD23B4A01DA06EB40047EDE9 /* IDSProxy.m in Sources */, + 0C5D62F11E81E74800AA4D02 /* SOSInternal.m in Sources */, CD23B4A11DA06EB40047EDE9 /* keychainsyncingoveridsproxy.m in Sources */, CD23B4A31DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+ReceiveMessage.m in Sources */, CD23B4A51DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+SendMessage.m in Sources */, - CD23B4A71DA06EB40047EDE9 /* KeychainSyncingOverIDSProxy+Throttle.m in Sources */, E7A5F5591C0D052600F3BEBB /* SOSCloudKeychainConstants.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; + D41257CB1E9410A300781F23 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D41257D91E9412B800781F23 /* trustd.c in Sources */, + DC5F35A81EE0F25300900966 /* server_entitlement_helpers.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D4ADA3151E2B41670031CEA3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D43DBEFB1E99D1CA00C04AEA /* asynchttp.c in Sources */, + D43DBEFC1E99D1CA00C04AEA /* nameconstraints.c in Sources */, + D43DBEFD1E99D1CA00C04AEA /* OTATrustUtilities.c in Sources */, + D43DBEFE1E99D1CA00C04AEA /* personalization.c in Sources */, + D43DBEFF1E99D1CA00C04AEA /* policytree.c in Sources */, + D43DBF001E99D1CA00C04AEA /* SecCAIssuerCache.c in Sources */, + D43DBF011E99D1CA00C04AEA /* SecCAIssuerRequest.c in Sources */, + D43DBF021E99D1CA00C04AEA /* SecCertificateServer.c in Sources */, + D43DBF031E99D1CA00C04AEA /* SecCertificateSource.c in Sources */, + D43DBF041E99D1CA00C04AEA /* SecOCSPCache.c in Sources */, + D43DBF051E99D1CA00C04AEA /* SecOCSPRequest.c in Sources */, + D43761671EB2996C00954447 /* SecRevocationNetworking.m in Sources */, + D43DBF061E99D1CA00C04AEA /* SecOCSPResponse.c in Sources */, + D43DBF071E99D1CA00C04AEA /* SecPinningDb.m in Sources */, + D43DBF081E99D1CA00C04AEA /* SecPolicyServer.c in Sources */, + D43DBF091E99D1CA00C04AEA /* SecRevocationDb.c in Sources */, + D43DBF0A1E99D1CA00C04AEA /* SecRevocationServer.c in Sources */, + D43DBF0B1E99D1CA00C04AEA /* SecTrustLoggingServer.c in Sources */, + D43DBF0C1E99D1CA00C04AEA /* SecTrustServer.c in Sources */, + D43DBF0D1E99D1CA00C04AEA /* SecTrustStoreServer.c in Sources */, + D40B6A9B1E2B690E00CD6EE5 /* SecuritydXPC.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DA30D6721DF8C8FB00EC6B43 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DA30D6851DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC0067A81D87876F005AF8DB /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -22837,6 +26664,7 @@ DC0BCD9F1D8C6A1F00070CB0 /* fileIo.c in Sources */, DC0BCDA81D8C6A1F00070CB0 /* SecFileLocations.c in Sources */, DC0BCDA61D8C6A1F00070CB0 /* SecDb.c in Sources */, + EB7AE6F81E86DACC00B80B15 /* SecPLWrappers.m in Sources */, DC0BCD7B1D8C6A1E00070CB0 /* SecCoreCrypto.c in Sources */, DC0BCDAF1D8C6A1F00070CB0 /* SecAppleAnchor.c in Sources */, DC0BCDA41D8C6A1F00070CB0 /* iOSforOSX-SecAttr.c in Sources */, @@ -22847,14 +26675,15 @@ DC0BCDA51D8C6A1F00070CB0 /* iOSforOSX-SecRandom.c in Sources */, DC0BCD841D8C6A1E00070CB0 /* SecCFError.c in Sources */, DC0BCD981D8C6A1F00070CB0 /* der_plist.c in Sources */, - DC0BCD7D1D8C6A1E00070CB0 /* SecCertificateTrace.c in Sources */, DC0BCD771D8C6A1E00070CB0 /* SecAKSWrappers.c in Sources */, + 72CDF5191EC679A8002D233B /* sec_action.c in Sources */, DC0BCD901D8C6A1E00070CB0 /* der_array.c in Sources */, DC0BCD7F1D8C6A1E00070CB0 /* SecCFCCWrappers.c in Sources */, E7C787351DD0FEF90087FC34 /* NSURL+SOSPlistStore.m in Sources */, DC0BCD9E1D8C6A1F00070CB0 /* der_string.c in Sources */, DC0BCD911D8C6A1E00070CB0 /* der_boolean.c in Sources */, DC0BCD931D8C6A1E00070CB0 /* der_data.c in Sources */, + E78CCDC71E737F6700C1CFAA /* SecNSAdditions.m in Sources */, DC0BCD921D8C6A1E00070CB0 /* der_null.c in Sources */, DC0BCD9C1D8C6A1F00070CB0 /* der_set.c in Sources */, DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.c in Sources */, @@ -22889,12 +26718,129 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4723C9C91F152ECA0082882F /* SFSQLite.m in Sources */, + DCA85B991E8D980B00BA7241 /* client_endpoint.m in Sources */, + DCA85B941E8D97E400BA7241 /* client.c in Sources */, DCDF0A4F1D81D76F007AF174 /* Security.exp-in in Sources */, DC1789A51D779E3B00B50D50 /* dummy.cpp in Sources */, + 4723C9C51F152EBC0082882F /* SFObjCType.m in Sources */, + 4723C9CD1F152ED40082882F /* SFSQLiteStatement.m in Sources */, + 4723C9E11F1540CE0082882F /* SFAnalyticsLogger.m in Sources */, + B61577E81F20151C004A3930 /* SecPaddingConfigurations.c in Sources */, DC1789A21D779DF400B50D50 /* SecBreadcrumb.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; + DC222C381E034D1F00B09171 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DC222C3A1E034D1F00B09171 /* CKKSItemEncrypter.m in Sources */, + DC7A17F01E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m in Sources */, + DCEA5D581E2826DB0089CF55 /* CKKSSIV.m in Sources */, + EBB407B41EBA46B300A541A5 /* CKKSPowerCollection.m in Sources */, + DCB5D93E1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m in Sources */, + DC222C3B1E034D1F00B09171 /* SOSChangeTracker.c in Sources */, + DC222C3D1E034D1F00B09171 /* SOSEngine.c in Sources */, + 6C8CC3B31E2F913D009025C5 /* AWDKeychainCKKSRateLimiterAggregatedScores.m in Sources */, + DC222C401E034D1F00B09171 /* SecDbItem.c in Sources */, + DCCD88EB1E42622200F5AA71 /* CKKSGroupOperation.m in Sources */, + DC222C411E034D1F00B09171 /* SecDbKeychainItem.c in Sources */, + DC222C421E034D1F00B09171 /* SecDbQuery.c in Sources */, + 6C3446471E25346C00F9522B /* CKKSRateLimiter.m in Sources */, + DCA4D2001E552DD50056214F /* CKKSCurrentKeyPointer.m in Sources */, + DCFB12C81E95A4C000510F5F /* CKKSCKAccountStateTracker.m in Sources */, + DC222C431E034D1F00B09171 /* SecItemBackupServer.c in Sources */, + DCE278E01ED789EF0083B485 /* CKKSCurrentItemPointer.m in Sources */, + DC222C441E034D1F00B09171 /* SecItemDataSource.c in Sources */, + 526965D31E6E284500627F9D /* AsymKeybagBackup.m in Sources */, + DCFE1C541F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m in Sources */, + DCD6C4B51EC5302500414FEE /* CKKSNearFutureScheduler.m in Sources */, + 6C588D811EAA20AC00D7E322 /* RateLimiter.m in Sources */, + DC94BCCD1F10448600E07CEB /* CloudKitCategories.m in Sources */, + DC5BB4FB1E0C90DF0010F836 /* CKKSIncomingQueueOperation.m in Sources */, + DC222C451E034D1F00B09171 /* CKKSIncomingQueueEntry.m in Sources */, + DC15F7691E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m in Sources */, + DC222C461E034D1F00B09171 /* SecItemDb.c in Sources */, + DC222C471E034D1F00B09171 /* SecItemSchema.c in Sources */, + DCEA5D881E2F14810089CF55 /* CKKSAPSReceiver.m in Sources */, + DC2C5F611F0EB97E00FEBDA7 /* CKKSNotifier.m in Sources */, + DC222C481E034D1F00B09171 /* SecItemServer.c in Sources */, + DC18F7721E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m in Sources */, + DC222C491E034D1F00B09171 /* SecKeybagSupport.c in Sources */, + DC1DA6691E4555D80094CE7F /* CKKSScanLocalItemsOperation.m in Sources */, + 6C8CC3B41E2F913D009025C5 /* AWDKeychainCKKSRateLimiterOverload.m in Sources */, + DC222C4A1E034D1F00B09171 /* SecLogSettingsServer.m in Sources */, + 479DA1781EBBA8D30065C98F /* CKKSManifest.m in Sources */, + DCD662F81E329B6800188186 /* CKKSNewTLKOperation.m in Sources */, + DC222C4D1E034D1F00B09171 /* CKKSOutgoingQueueEntry.m in Sources */, + DC222C4E1E034D1F00B09171 /* CKKS.m in Sources */, + DC762AA11E57A86A00B03A2C /* CKKSRecordHolder.m in Sources */, + DC222C501E034D1F00B09171 /* SecOTRRemote.m in Sources */, + 479108BA1EE879F9008CEFA0 /* CKKSAnalyticsLogger.m in Sources */, + DC222C511E034D1F00B09171 /* CKKSItem.m in Sources */, + DCBDB3BE1E57CA7A00B61300 /* CKKSViewManager.m in Sources */, + DCFE1C2A1F17E455007640C8 /* CKKSDeviceStateEntry.m in Sources */, + DCA4D2181E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m in Sources */, + DCE278EB1ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m in Sources */, + DC222C541E034D1F00B09171 /* CKKSSQLDatabaseObject.m in Sources */, + DCEA5D981E3015840089CF55 /* CKKSZone.m in Sources */, + DCB837381ED5045100015C07 /* CKKSLockStateTracker.m in Sources */, + DCF7A8A41F0450EB00CABE89 /* CKKSControlProtocol.m in Sources */, + DC4DB1531E24692100CD6769 /* CKKSKey.m in Sources */, + DC9082C51EA0277700D0C1C5 /* CKKSZoneChangeFetcher.m in Sources */, + DC222C571E034D1F00B09171 /* SecuritydXPC.c in Sources */, + 6C8CC3B51E2F913D009025C5 /* AWDKeychainCKKSRateLimiterTopWriters.m in Sources */, + DCBDB3B81E57C82300B61300 /* CKKSKeychainView.m in Sources */, + DC222C5A1E034D1F00B09171 /* iCloudTrace.c in Sources */, + DC5BB5011E0C98320010F836 /* CKKSOutgoingQueueOperation.m in Sources */, + 5269658E1E6A154800627F9D /* SecBackupKeybagEntry.m in Sources */, + DC222C5D1E034D1F00B09171 /* CKKSMirrorEntry.m in Sources */, + DC54DD101EA7D9E800108E92 /* CKKSManifestLeafRecord.m in Sources */, + DCFE1C371F17ECE5007640C8 /* CKKSCondition.m in Sources */, + DC222C611E034D1F00B09171 /* swcagent_client.c in Sources */, + DC222C621E034D1F00B09171 /* CKKSZoneStateEntry.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DC3502B11E0208BE00BC0587 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 476541A61F33EE2700413F65 /* SecdWatchdog.m in Sources */, + 4771ECD91F17CE5100840998 /* SFAnalyticsLogger.m in Sources */, + 4771ECCE1F17CD2100840998 /* SFObjCType.m in Sources */, + 4771ECCC1F17CD0E00840998 /* SFSQLite.m in Sources */, + 4771ECCD1F17CD0E00840998 /* SFSQLiteStatement.m in Sources */, + DCD6C4B71EC5319600414FEE /* CKKSNearFutureSchedulerTests.m in Sources */, + DC08D1C41E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m in Sources */, + 47E553741EDF674700749715 /* CKKSManifestTests.m in Sources */, + 6C588D7F1EAA14AA00D7E322 /* RateLimiterTests.m in Sources */, + DC4DB15F1E2590B100CD6769 /* CKKSEncryptionTests.m in Sources */, + DC3502E71E0214C800BC0587 /* MockCloudKit.m in Sources */, + DC6593D11ED8DAB900C19462 /* CKKSTests+CurrentPointerAPI.m in Sources */, + DCA85B9A1E8D981100BA7241 /* client_endpoint.m in Sources */, + DC9A2C5F1EB3F557008FAC27 /* CKKSTests+Coalesce.m in Sources */, + DC222C8A1E089BAE00B09171 /* CKKSSQLTests.m in Sources */, + DC15F79C1E68EAD5003B9A40 /* CKKSTests+API.m in Sources */, + 4723C9D41F1531A30082882F /* CKKSLoggerTests.m in Sources */, + DC3502B81E0208BE00BC0587 /* CKKSTests.m in Sources */, + 6C3446301E24F6BE00F9522B /* CKKSRateLimiterTests.m in Sources */, + DCA85B961E8D980100BA7241 /* client.c in Sources */, + DCE7F2091F21726500DDB0F7 /* CKKSAPSReceiverTests.m in Sources */, + DC96053F1ECA2D6400AF9BDA /* SecTask.c in Sources */, + DC08D1CC1E64FCC5006237DA /* CKKSSOSTests.m in Sources */, + DC222CA81E08A7D900B09171 /* CloudKitMockXCTest.m in Sources */, + DC9C75161E4BCE1800F1CA0D /* CKKSOperationTests.m in Sources */, + DCB221561E8B08BF001598BC /* server_xpc.m in Sources */, + DC42690F1E82FD9C002B7110 /* server_security_helpers.c in Sources */, + DC4268FE1E820371002B7110 /* server_endpoint.m in Sources */, + DCFE1C3D1F17EFB5007640C8 /* CKKSConditionTests.m in Sources */, + DCCD33C91E3FE95900AA4AD1 /* spi.c in Sources */, + DC5F35AC1EE0F27900900966 /* server_entitlement_helpers.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DC3A4B541D91E9FB00E46D4A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -22907,127 +26853,115 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D46F31631E00CCD20065B550 /* SecCertificateSource.c in Sources */, - DC52E7DD1D80BD5500B0A59C /* OTATrustUtilities.c in Sources */, + DC797E1A1DD3F9A400CC9E42 /* CKKSSQLDatabaseObject.m in Sources */, + 6CC1859F1E24E8EB009657D8 /* CKKSRateLimiter.m in Sources */, + DCFB12C71E95A4C000510F5F /* CKKSCKAccountStateTracker.m in Sources */, + EBB407B31EBA46B200A541A5 /* CKKSPowerCollection.m in Sources */, + DCCD88EA1E42622200F5AA71 /* CKKSGroupOperation.m in Sources */, + DC54DD0F1EA7D9E700108E92 /* CKKSManifestLeafRecord.m in Sources */, + DCDCCB901DF7B8D4006E840E /* CKKSItem.m in Sources */, + DC1ED8C11DD5197E002BDCFA /* CKKSItemEncrypter.m in Sources */, + DC6D2C921DD2835A00BE372D /* CKKSOutgoingQueueEntry.m in Sources */, + 6C8CC3AD1E2F913C009025C5 /* AWDKeychainCKKSRateLimiterTopWriters.m in Sources */, + DC378B3D1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m in Sources */, + DC5BB4FA1E0C90DE0010F836 /* CKKSIncomingQueueOperation.m in Sources */, + DC5BB5001E0C98320010F836 /* CKKSOutgoingQueueOperation.m in Sources */, + DC378B391DEFADB500A3DAFA /* CKKSZoneStateEntry.m in Sources */, + 526965D21E6E284400627F9D /* AsymKeybagBackup.m in Sources */, + 6C588D801EAA20AB00D7E322 /* RateLimiter.m in Sources */, + DC15F7681E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m in Sources */, + DCE278DF1ED789EF0083B485 /* CKKSCurrentItemPointer.m in Sources */, + DCA4D1FF1E552DD50056214F /* CKKSCurrentKeyPointer.m in Sources */, + DCFE1C531F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m in Sources */, + DCD6C4B41EC5302500414FEE /* CKKSNearFutureScheduler.m in Sources */, + DC378B2F1DEF9E0E00A3DAFA /* CKKSMirrorEntry.m in Sources */, + DC94BCCC1F10448600E07CEB /* CloudKitCategories.m in Sources */, + DC1ED8C61DD55476002BDCFA /* CKKS.m in Sources */, + DCB5D93D1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m in Sources */, + DC762AA01E57A86A00B03A2C /* CKKSRecordHolder.m in Sources */, DC52E7DF1D80BD8700B0A59C /* SOSChangeTracker.c in Sources */, - D46F315A1E00A27D0065B550 /* SecTrustLoggingServer.c in Sources */, - DC52E7C61D80BCBA00B0A59C /* SOSCloudCircleServer.c in Sources */, + DC1DA6681E4555D80094CE7F /* CKKSScanLocalItemsOperation.m in Sources */, + DC18F7711E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m in Sources */, + DC2C5F601F0EB97E00FEBDA7 /* CKKSNotifier.m in Sources */, DC52E7CF1D80BCFD00B0A59C /* SOSEngine.c in Sources */, - DC52E7D91D80BD3C00B0A59C /* SecCAIssuerCache.c in Sources */, - DC52E7D81D80BD3800B0A59C /* SecCAIssuerRequest.c in Sources */, + DC4DB1521E24692100CD6769 /* CKKSKey.m in Sources */, + DCBDB3BD1E57CA7A00B61300 /* CKKSViewManager.m in Sources */, DC52E7C41D80BCAD00B0A59C /* SecDbItem.c in Sources */, DC52E7D31D80BD1800B0A59C /* SecDbKeychainItem.c in Sources */, DC52E7CC1D80BCDF00B0A59C /* SecDbQuery.c in Sources */, + 479DA1721EBBA8D10065C98F /* CKKSManifest.m in Sources */, DC52E7CB1D80BCD800B0A59C /* SecItemBackupServer.c in Sources */, DC52E7CD1D80BCE700B0A59C /* SecItemDataSource.c in Sources */, DC52E7DE1D80BD7F00B0A59C /* SecItemDb.c in Sources */, DC52E7E01D80BD8D00B0A59C /* SecItemSchema.c in Sources */, DC52E7D71D80BD2D00B0A59C /* SecItemServer.c in Sources */, - DC52E7CE1D80BCF800B0A59C /* SecKeybagSupport.c in Sources */, - DC52E7E11D80BD9300B0A59C /* SecLogSettingsServer.c in Sources */, - DC52E7D51D80BD2300B0A59C /* SecOCSPCache.c in Sources */, - DC52E7D21D80BD1200B0A59C /* SecOCSPRequest.c in Sources */, - DC52E7D11D80BD0C00B0A59C /* SecOCSPResponse.c in Sources */, - DC52E7DC1D80BD4F00B0A59C /* SecOTRRemote.c in Sources */, - DC52E7D01D80BD0200B0A59C /* SecPolicyServer.c in Sources */, - DC52E7CA1D80BCD300B0A59C /* SecTrustServer.c in Sources */, - DC52E7C81D80BCC600B0A59C /* SecTrustStoreServer.c in Sources */, + 479108B91EE879F9008CEFA0 /* CKKSAnalyticsLogger.m in Sources */, + DCD8A0CF1E09EA1800E4FA0A /* SecKeybagSupport.c in Sources */, + DC52E7E11D80BD9300B0A59C /* SecLogSettingsServer.m in Sources */, + DCFE1C291F17E455007640C8 /* CKKSDeviceStateEntry.m in Sources */, + 6C8CC3AC1E2F913C009025C5 /* AWDKeychainCKKSRateLimiterOverload.m in Sources */, + DC52E7DC1D80BD4F00B0A59C /* SecOTRRemote.m in Sources */, + DCE278EA1ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m in Sources */, + DCD662F71E329B6800188186 /* CKKSNewTLKOperation.m in Sources */, + DCB837321ED5045000015C07 /* CKKSLockStateTracker.m in Sources */, + DCF7A8A31F0450EB00CABE89 /* CKKSControlProtocol.m in Sources */, + DCBDB3B71E57C82300B61300 /* CKKSKeychainView.m in Sources */, DC52E7D61D80BD2800B0A59C /* SecuritydXPC.c in Sources */, - DC52E7DB1D80BD4A00B0A59C /* asynchttp.c in Sources */, + DC7A17EF1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m in Sources */, + DCA4D2171E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m in Sources */, + 5269658D1E6A154700627F9D /* SecBackupKeybagEntry.m in Sources */, DC52E7D41D80BD1D00B0A59C /* iCloudTrace.c in Sources */, - DC52E7C91D80BCCB00B0A59C /* nameconstraints.c in Sources */, - DC52E7C31D80BCA600B0A59C /* personalization.c in Sources */, - DC52E7DA1D80BD4400B0A59C /* policytree.c in Sources */, - BEE523D61DA610F500DD0AA3 /* SecRevocationDb.c in Sources */, - DC52E7C71D80BCBE00B0A59C /* spi.c in Sources */, + DCEA5D871E2F14810089CF55 /* CKKSAPSReceiver.m in Sources */, + DCEA5D571E2826DB0089CF55 /* CKKSSIV.m in Sources */, + 6C8CC3AB1E2F913C009025C5 /* AWDKeychainCKKSRateLimiterAggregatedScores.m in Sources */, + DC9082C41EA0277600D0C1C5 /* CKKSZoneChangeFetcher.m in Sources */, + DCFE1C361F17ECE5007640C8 /* CKKSCondition.m in Sources */, + DCEA5D971E3015830089CF55 /* CKKSZone.m in Sources */, DC52E7C51D80BCB300B0A59C /* swcagent_client.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - DC52E88B1D80C1EB00B0A59C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DC52E8BB1D80C21700B0A59C /* client.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; DC52E8BF1D80C25800B0A59C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 48BC0F6A1DFA357000DDDFF9 /* accountCirclesViewsPrint.c in Sources */, - 48E617211DBEC6BA0098EAAD /* SOSBackupInformation.c in Sources */, - DC52E8F11D80C34000B0A59C /* SOSAccount.c in Sources */, - DC52E8F31D80C34000B0A59C /* SOSAccountBackup.c in Sources */, - DC52E8F41D80C34000B0A59C /* SOSAccountCircles.c in Sources */, - DCDCC7E51D9B5526006487E8 /* SOSAccountSync.c in Sources */, - DC52E8F61D80C34000B0A59C /* SOSAccountCloudParameters.c in Sources */, - DC52E8F71D80C34000B0A59C /* SOSAccountCredentials.c in Sources */, - DC52E8F81D80C34000B0A59C /* SOSAccountDer.c in Sources */, - 485B64111DC16ED600B771B9 /* SOSKeyedPubKeyIdentifier.c in Sources */, - DC52E8F91D80C34000B0A59C /* SOSAccountFullPeerInfo.c in Sources */, - DC52E8F51D80C34000B0A59C /* SOSAccountHSAJoin.c in Sources */, - DC52E8FC1D80C34000B0A59C /* SOSAccountLog.c in Sources */, - DC52E8FA1D80C34000B0A59C /* SOSAccountPeers.c in Sources */, - DC52E8FB1D80C34000B0A59C /* SOSAccountPersistence.c in Sources */, - DC52E8FF1D80C34000B0A59C /* SOSAccountRingUpdate.c in Sources */, - DC52E8FE1D80C34000B0A59C /* SOSAccountRings.c in Sources */, - 48776C7E1DA5BB7600CC09B9 /* SOSRingRecovery.c in Sources */, - DC52E8F21D80C34000B0A59C /* SOSAccountTransaction.c in Sources */, - DC52E8FD1D80C34000B0A59C /* SOSAccountUpdate.c in Sources */, - DC52E9001D80C34000B0A59C /* SOSAccountViewSync.c in Sources */, + 48E617211DBEC6BA0098EAAD /* SOSBackupInformation.m in Sources */, + DC52E8F11D80C34000B0A59C /* SOSAccount.m in Sources */, + DC52E8F31D80C34000B0A59C /* SOSAccountBackup.m in Sources */, + DC52E8F41D80C34000B0A59C /* SOSAccountCircles.m in Sources */, + 0CD8CB0B1ECA50920076F37F /* SOSPeerOTRTimer.m in Sources */, + DCDCC7E51D9B5526006487E8 /* SOSAccountSync.m in Sources */, + DC52E8F71D80C34000B0A59C /* SOSAccountCredentials.m in Sources */, + DC52E8F91D80C34000B0A59C /* SOSAccountFullPeerInfo.m in Sources */, + DC52E8FC1D80C34000B0A59C /* SOSAccountLog.m in Sources */, + DC52E8FA1D80C34000B0A59C /* SOSAccountPeers.m in Sources */, + DC52E8FB1D80C34000B0A59C /* SOSAccountPersistence.m in Sources */, + DC52E8FF1D80C34000B0A59C /* SOSAccountRingUpdate.m in Sources */, + DC52E8FE1D80C34000B0A59C /* SOSAccountRings.m in Sources */, + DC52E8F21D80C34000B0A59C /* SOSAccountTransaction.m in Sources */, + DC52E8FD1D80C34000B0A59C /* SOSAccountUpdate.m in Sources */, + DC52E9001D80C34000B0A59C /* SOSAccountViewSync.m in Sources */, DC52E9011D80C34000B0A59C /* SOSBackupEvent.c in Sources */, - DC52E9021D80C34000B0A59C /* SOSBackupSliceKeyBag.c in Sources */, - DC52E8E41D80C33000B0A59C /* SOSCircle.c in Sources */, - DC52E8E61D80C33000B0A59C /* SOSCircleDer.c in Sources */, - DC52E8E51D80C33000B0A59C /* SOSCircleV2.c in Sources */, - DC3C789B1D83854700F6A832 /* SOSCloudKeychainConstants.c in Sources */, - DC52E9E31D80CAFE00B0A59C /* SOSCloudKeychainClient.c in Sources */, + 7281E0871DFD01800021E1B7 /* SOSAccountGetSet.m in Sources */, + 0C4899121E0E105D00C6CF70 /* SOSTransportCircleCK.m in Sources */, DC52E8DD1D80C31F00B0A59C /* SOSCoder.c in Sources */, DC52E8DE1D80C31F00B0A59C /* SOSDigestVector.c in Sources */, - DC52E8D11D80C30500B0A59C /* SOSECWrapUnwrap.c in Sources */, - DC52E8D51D80C31500B0A59C /* SOSFullPeerInfo.c in Sources */, - DC52E8E71D80C33000B0A59C /* SOSGenCount.c in Sources */, - DC52E8D41D80C30500B0A59C /* SOSInternal.c in Sources */, - DC52E8C71D80C2FD00B0A59C /* SOSKVSKeys.c in Sources */, DC52E8E01D80C31F00B0A59C /* SOSManifest.c in Sources */, DC52E8E11D80C31F00B0A59C /* SOSMessage.c in Sources */, - DC52E8E21D80C31F00B0A59C /* SOSPeer.c in Sources */, - DC52E8E31D80C31F00B0A59C /* SOSPeerCoder.c in Sources */, - DC52E8D61D80C31500B0A59C /* SOSPeerInfo.c in Sources */, - DC52E8D91D80C31500B0A59C /* SOSPeerInfoCollections.c in Sources */, - DC52E8D71D80C31500B0A59C /* SOSPeerInfoDER.c in Sources */, - 48776C7A1DA5BB4C00CC09B9 /* SOSRecoveryKeyBag.c in Sources */, - DC52E8DA1D80C31500B0A59C /* SOSPeerInfoRingState.c in Sources */, - DC52E8DB1D80C31500B0A59C /* SOSPeerInfoSecurityProperties.c in Sources */, - DC52E8D81D80C31500B0A59C /* SOSPeerInfoV2.c in Sources */, - DCFAEDCF1D999859005187E4 /* SOSAccountGhost.c in Sources */, - DC52E8E81D80C33000B0A59C /* SOSRingBackup.c in Sources */, - E7E5B55F1DC7ACAE00C03FFB /* SOSAccountGetSet.c in Sources */, - DC52E8E91D80C33000B0A59C /* SOSRingBasic.c in Sources */, - DC52E8EA1D80C33000B0A59C /* SOSRingConcordanceTrust.c in Sources */, + DC52E8E21D80C31F00B0A59C /* SOSPeer.m in Sources */, + DC52E8E31D80C31F00B0A59C /* SOSPeerCoder.m in Sources */, + DCFAEDCF1D999859005187E4 /* SOSAccountGhost.m in Sources */, EB6928F91D9ED5BA00062A18 /* SecRecoveryKey.m in Sources */, - DC52E8EB1D80C33000B0A59C /* SOSRingDER.c in Sources */, - 48776C811DA5BC0E00CC09B9 /* SOSAccountRecovery.c in Sources */, - DC52E8EC1D80C33000B0A59C /* SOSRingPeerInfoUtils.c in Sources */, - DC52E8ED1D80C33000B0A59C /* SOSRingTypes.c in Sources */, - DC52E8EE1D80C33000B0A59C /* SOSRingUtils.c in Sources */, - DC52E8EF1D80C33000B0A59C /* SOSRingV0.c in Sources */, - DC52E8D31D80C30500B0A59C /* SOSSysdiagnose.c in Sources */, - DC52E8C81D80C2FD00B0A59C /* SOSTransport.c in Sources */, - DC52E8C91D80C2FD00B0A59C /* SOSTransportBackupPeer.c in Sources */, - DC52E8CA1D80C2FD00B0A59C /* SOSTransportCircle.c in Sources */, - DC52E8CB1D80C2FD00B0A59C /* SOSTransportCircleKVS.c in Sources */, - DC52E8CC1D80C2FD00B0A59C /* SOSTransportKeyParameter.c in Sources */, - DC52E8CD1D80C2FD00B0A59C /* SOSTransportKeyParameterKVS.c in Sources */, - DC52E8CE1D80C2FD00B0A59C /* SOSTransportMessage.c in Sources */, - DC52E8CF1D80C2FD00B0A59C /* SOSTransportMessageIDS.c in Sources */, - DC52E8D01D80C2FD00B0A59C /* SOSTransportMessageKVS.c in Sources */, - DC52E9031D80C34000B0A59C /* SOSUserKeygen.c in Sources */, - DC52E8F01D80C33000B0A59C /* SOSViews.c in Sources */, - DC52E9E21D80C62D00B0A59C /* secToolFileIO.c in Sources */, - DC52E9051D80C36A00B0A59C /* secViewDisplay.c in Sources */, + 48776C811DA5BC0E00CC09B9 /* SOSAccountRecovery.m in Sources */, + DC52E8C91D80C2FD00B0A59C /* SOSTransportBackupPeer.m in Sources */, + DC52E8CA1D80C2FD00B0A59C /* SOSTransportCircle.m in Sources */, + DC52E8CB1D80C2FD00B0A59C /* SOSTransportCircleKVS.m in Sources */, + DC52E8CC1D80C2FD00B0A59C /* SOSTransportKeyParameter.m in Sources */, + DC52E8CE1D80C2FD00B0A59C /* SOSTransportMessage.m in Sources */, + 0CAD1E1C1E032ADB00537693 /* SOSCloudCircleServer.m in Sources */, + DC52E8CF1D80C2FD00B0A59C /* SOSTransportMessageIDS.m in Sources */, + 0CAC5DBF1EB3DA4C00AD884B /* SOSPeerRateLimiter.m in Sources */, + DC52E8D01D80C2FD00B0A59C /* SOSTransportMessageKVS.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -23039,7 +26973,9 @@ DC52EAA11D80CCAC00B0A59C /* SecurityTool.c in Sources */, DC52EAA01D80CCA700B0A59C /* whoami.m in Sources */, DC52EA9F1D80CCA100B0A59C /* digest_calc.c in Sources */, + EBEEEE3C1EA31D9600E15F5C /* SOSControlHelper.m in Sources */, DC52EA9E1D80CC9B00B0A59C /* leaks.c in Sources */, + EB48C1A61E573EEC00EC5E57 /* sos.m in Sources */, DC52EA9D1D80CC9700B0A59C /* syncbubble.m in Sources */, DC52EBC31D80CEBA00B0A59C /* print_cert.c in Sources */, ); @@ -23049,13 +26985,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 48BC0F6B1DFA357200DDDFF9 /* accountCirclesViewsPrint.c in Sources */, DC52EC1E1D80CF6700B0A59C /* verify_cert.c in Sources */, DC52EC1D1D80CF6200B0A59C /* keychain_util.c in Sources */, DC52EC1C1D80CF5D00B0A59C /* add_internet_password.c in Sources */, DC52EC1B1D80CF5600B0A59C /* codesign.c in Sources */, DC52EC1A1D80CF5100B0A59C /* keychain_add.c in Sources */, - DC52EC191D80CF4C00B0A59C /* keychain_find.c in Sources */, + DC52EC191D80CF4C00B0A59C /* keychain_find.m in Sources */, DC52EC181D80CF4700B0A59C /* log_control.c in Sources */, DC52EC171D80CF4200B0A59C /* pkcs12_util.c in Sources */, DC52EC161D80CF3B00B0A59C /* scep.c in Sources */, @@ -23069,12 +27004,13 @@ buildActionMask = 2147483647; files = ( 0C0CECA41DA45ED700C22FBC /* recovery_key.m in Sources */, - DC52EC3B1D80CFE900B0A59C /* syncbackup.c in Sources */, - DC52EC3A1D80CFE400B0A59C /* keychain_log.c in Sources */, + DC52EC3B1D80CFE900B0A59C /* syncbackup.m in Sources */, + DC52EC3A1D80CFE400B0A59C /* keychain_log.m in Sources */, + 48C2F93B1E4BCFE80093D70C /* accountCirclesViewsPrint.m in Sources */, DC52EC391D80CFDF00B0A59C /* secViewDisplay.c in Sources */, DC52EC381D80CFDB00B0A59C /* secToolFileIO.c in Sources */, DC52EC371D80CFD400B0A59C /* keychain_sync_test.m in Sources */, - DC52EC361D80CFD000B0A59C /* keychain_sync.c in Sources */, + DC52EC361D80CFD000B0A59C /* keychain_sync.m in Sources */, DC3C7C901D83957F00F6A832 /* NSFileHandle+Formatting.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -23103,15 +27039,14 @@ DC52EC7B1D80D15600B0A59C /* sc-30-peerinfo.c in Sources */, DC52EC7A1D80D15200B0A59C /* sc-40-circle.c in Sources */, DC52EC791D80D14D00B0A59C /* sc-45-digestvector.c in Sources */, - DC52EC781D80D14800B0A59C /* SOSRegressionUtilities.c in Sources */, + DC52EC781D80D14800B0A59C /* SOSRegressionUtilities.m in Sources */, DC52EC771D80D14400B0A59C /* sc-130-resignationticket.c in Sources */, - DC52EC761D80D13F00B0A59C /* sc-150-ring.c in Sources */, + DC52EC761D80D13F00B0A59C /* sc-150-ring.m in Sources */, DC52EC751D80D13B00B0A59C /* sc-42-circlegencount.c in Sources */, DC52EC741D80D13500B0A59C /* SOSTestDataSource.c in Sources */, - DC52EC731D80D12E00B0A59C /* sc-20-keynames.c in Sources */, + DC52EC731D80D12E00B0A59C /* sc-20-keynames.m in Sources */, DC52EC721D80D12900B0A59C /* sc-150-backupkeyderivation.c in Sources */, DC52EC711D80D12200B0A59C /* sc-153-backupslicekeybag.c in Sources */, - DC52EC701D80D11C00B0A59C /* sc-140-hsa2.c in Sources */, DC52EC6F1D80D11800B0A59C /* sc-25-soskeygen.c in Sources */, DC52EC6E1D80D0F700B0A59C /* SOSTestDevice.c in Sources */, DC52EC6D1D80D0F100B0A59C /* sc-31-peerinfo-simplefuzz.c in Sources */, @@ -23150,12 +27085,7 @@ DC52ECBD1D80D22600B0A59C /* si-42-identity.c in Sources */, DC52ECBE1D80D22600B0A59C /* si-43-persistent.c in Sources */, DC52ECC31D80D22600B0A59C /* si-50-secrandom.c in Sources */, - DC52ECC41D80D22600B0A59C /* si-60-cms.c in Sources */, - DC52ECC51D80D22600B0A59C /* si-61-pkcs12.c in Sources */, DC52ECC71D80D22600B0A59C /* si-63-scep.c in Sources */, - DC52ECC81D80D22600B0A59C /* si-64-ossl-cms.c in Sources */, - DC52ECC91D80D22600B0A59C /* si-65-cms-cert-policy.c in Sources */, - DC52ECCC1D80D22600B0A59C /* si-68-secmatchissuer.c in Sources */, DC52ECCD1D80D22600B0A59C /* si-69-keydesc.c in Sources */, DC52ECD01D80D22600B0A59C /* si-72-syncableitems.c in Sources */, DC52ECD11D80D22600B0A59C /* si-73-secpasswordgenerate.c in Sources */, @@ -23179,9 +27109,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DC52EDA01D80D4F700B0A59C /* sd-10-policytree.c in Sources */, - DC52ED9F1D80D4F200B0A59C /* SOSTransportTestTransports.c in Sources */, - DC52ED9E1D80D4ED00B0A59C /* secd-95-escrow-persistence.c in Sources */, + DC52EDA01D80D4F700B0A59C /* sd-10-policytree.m in Sources */, + DC52ED9F1D80D4F200B0A59C /* SOSTransportTestTransports.m in Sources */, + DC52ED9E1D80D4ED00B0A59C /* secd-95-escrow-persistence.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -23190,78 +27120,85 @@ buildActionMask = 2147483647; files = ( E7C787211DCA4D430087FC34 /* CKDAKSLockMonitor.m in Sources */, - DC52EDFA1D80D66600B0A59C /* SOSRegressionUtilities.c in Sources */, + DC52EDFA1D80D66600B0A59C /* SOSRegressionUtilities.m in Sources */, DCFAEDD61D99A47A005187E4 /* secd-36-ks-encrypt.m in Sources */, + 7281E08D1DFD0B520021E1B7 /* XPCNotificationDispatcher.m in Sources */, DC52EDF91D80D66000B0A59C /* SOSTestDataSource.c in Sources */, + 7281E0911DFD0E510021E1B7 /* CKDSimulatedStore.m in Sources */, E73A7E911DC81E0300A5B2D1 /* CKDSimulatedAccount.m in Sources */, DC52EDF81D80D65C00B0A59C /* SOSTestDevice.c in Sources */, DC52EDF71D80D65700B0A59C /* si-90-emcs.m in Sources */, - 483E798F1DC87605005C0008 /* secd-67-prefixedKeyIDs.c in Sources */, - 48CC589F1DA5FF2700EBD9DB /* secd-66-account-recovery.c in Sources */, - E73A7E921DC81E0F00A5B2D1 /* CKDKVSProxy.m in Sources */, + 483E798F1DC87605005C0008 /* secd-67-prefixedKeyIDs.m in Sources */, + 48CC589F1DA5FF2700EBD9DB /* secd-66-account-recovery.m in Sources */, DC52EDF51D80D62E00B0A59C /* SecdTestKeychainUtilities.c in Sources */, - DC52EDF61D80D62E00B0A59C /* SOSTransportTestTransports.c in Sources */, - DC52EDB51D80D5C500B0A59C /* secd-03-corrupted-items.c in Sources */, - DC52EDB61D80D5C500B0A59C /* secd-04-corrupted-items.c in Sources */, + DC52EDF61D80D62E00B0A59C /* SOSTransportTestTransports.m in Sources */, + EB9C02481E8A15B40040D3C6 /* secd-37-pairing-initial-sync.m in Sources */, + 0CAD1E5E1E1C5D0600537693 /* secd-95-escrow-persistence.m in Sources */, + DC52EDB51D80D5C500B0A59C /* secd-03-corrupted-items.m in Sources */, + 0CAD1E5D1E1C5CF900537693 /* secd-80-views-alwayson.m in Sources */, + DC52EDB61D80D5C500B0A59C /* secd-04-corrupted-items.m in Sources */, DC52EDB71D80D5C500B0A59C /* secd-05-corrupted-items.m in Sources */, - DC55329C1DDAA28800B6A6A7 /* XPCNotificationDispatcher.m in Sources */, - DC52EDBB1D80D5C500B0A59C /* secd-01-items.c in Sources */, - DC52EDBC1D80D5C500B0A59C /* secd-02-upgrade-while-locked.c in Sources */, + DC52EDBB1D80D5C500B0A59C /* secd-01-items.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.c in Sources */, - DC52EDBF1D80D5C500B0A59C /* secd-30-keychain-upgrade.c in Sources */, - DC52EDC01D80D5C500B0A59C /* secd-31-keychain-bad.c in Sources */, - DC52EDC11D80D5C500B0A59C /* secd-31-keychain-unreadable.c in Sources */, - DC52EDC21D80D5C500B0A59C /* secd-32-restore-bad-backup.c in Sources */, + DCFAEDD21D99991F005187E4 /* secd-668-ghosts.m in Sources */, + DC52EDBF1D80D5C500B0A59C /* secd-30-keychain-upgrade.m in Sources */, + DC52EDC01D80D5C500B0A59C /* secd-31-keychain-bad.m in Sources */, + DC52EDC11D80D5C500B0A59C /* secd-31-keychain-unreadable.m in Sources */, + 0CCDE7171EEB08220021A946 /* secd-156-timers.m in Sources */, + DC52EDC21D80D5C500B0A59C /* secd-32-restore-bad-backup.m in Sources */, DC52EDC31D80D5C500B0A59C /* secd-33-keychain-ctk.m in Sources */, - DC0B622C1D90982C00D43BCB /* secd-201-coders.c in Sources */, - DC52EDC41D80D5C500B0A59C /* secd-34-backup-der-parse.c in Sources */, - DC52EDC51D80D5C500B0A59C /* secd-35-keychain-migrate-inet.c in Sources */, - DC52EDC61D80D5C500B0A59C /* secd-40-cc-gestalt.c in Sources */, - DC52EDC71D80D5C500B0A59C /* secd-50-account.c in Sources */, - E73A7E8B1DC81DF700A5B2D1 /* secd-210-keyinterest.m in Sources */, - DC52EDC81D80D5C500B0A59C /* secd-49-manifests.c in Sources */, - DC52EDC91D80D5C500B0A59C /* secd-50-message.c in Sources */, - DC52EDCA1D80D5C500B0A59C /* secd-51-account-inflate.c in Sources */, - DC52EDCC1D80D5C500B0A59C /* secd-52-account-changed.c in Sources */, - DC52EDCD1D80D5C500B0A59C /* secd-55-account-circle.c in Sources */, - DCFAEDD71D99A4AB005187E4 /* secd-154-engine-backoff.c in Sources */, - DC52EDCE1D80D5C500B0A59C /* secd-55-account-incompatibility.c in Sources */, - DC52EDCF1D80D5C500B0A59C /* secd-56-account-apply.c in Sources */, - DC52EDD01D80D5C500B0A59C /* secd-57-account-leave.c in Sources */, - DC52EDD11D80D5C500B0A59C /* secd-57-1-account-last-standing.c in Sources */, - DC52EDD21D80D5C500B0A59C /* secd-58-password-change.c in Sources */, - DC52EDD31D80D5C500B0A59C /* secd-59-account-cleanup.c in Sources */, - DC52EDD41D80D5C500B0A59C /* secd-60-account-cloud-identity.c in Sources */, - DC52EDD51D80D5C500B0A59C /* secd60-account-cloud-exposure.c in Sources */, - DC52EDD61D80D5C500B0A59C /* secd-61-account-leave-not-in-kansas-anymore.c in Sources */, - DC52EDD71D80D5C500B0A59C /* secd-62-account-backup.c in Sources */, - DC52EDD81D80D5C500B0A59C /* secd-62-account-hsa-join.c in Sources */, - DC52EDD91D80D5C500B0A59C /* secd-63-account-resurrection.c in Sources */, - DC52EDDA1D80D5C500B0A59C /* secd-65-account-retirement-reset.c in Sources */, - E73A7E8F1DC81E0300A5B2D1 /* CKDSimulatedStore.m in Sources */, + 0CAD1E5C1E1C5CEB00537693 /* secd_77_ids_messaging.m in Sources */, + DC0B622C1D90982C00D43BCB /* secd-201-coders.m in Sources */, + 0CAD1E5A1E1C5CD100537693 /* secd-71-engine-save.m in Sources */, + DC52EDC41D80D5C500B0A59C /* secd-34-backup-der-parse.m in Sources */, + DC52EDC51D80D5C500B0A59C /* secd-35-keychain-migrate-inet.m in Sources */, + DC52EDC61D80D5C500B0A59C /* secd-40-cc-gestalt.m in Sources */, + DC52EDC71D80D5C500B0A59C /* secd-50-account.m in Sources */, + DC52EDC81D80D5C500B0A59C /* secd-49-manifests.m in Sources */, + DC52EDC91D80D5C500B0A59C /* secd-50-message.m in Sources */, + DC52EDCA1D80D5C500B0A59C /* secd-51-account-inflate.m in Sources */, + DC52EDCC1D80D5C500B0A59C /* secd-52-account-changed.m in Sources */, + DC52EDCD1D80D5C500B0A59C /* secd-55-account-circle.m in Sources */, + DCFAEDD71D99A4AB005187E4 /* secd-154-engine-backoff.m in Sources */, + DC52EDCE1D80D5C500B0A59C /* secd-55-account-incompatibility.m in Sources */, + DC52EDCF1D80D5C500B0A59C /* secd-56-account-apply.m in Sources */, + DC52EDD01D80D5C500B0A59C /* secd-57-account-leave.m in Sources */, + DC52EDD11D80D5C500B0A59C /* secd-57-1-account-last-standing.m in Sources */, + DC52EDD21D80D5C500B0A59C /* secd-58-password-change.m in Sources */, + DC52EDD31D80D5C500B0A59C /* secd-59-account-cleanup.m in Sources */, + DC52EDD41D80D5C500B0A59C /* secd-60-account-cloud-identity.m in Sources */, + DC52EDD51D80D5C500B0A59C /* secd60-account-cloud-exposure.m in Sources */, + 0CAD1E5B1E1C5CE100537693 /* secd-76-idstransport.m in Sources */, + DC52EDD61D80D5C500B0A59C /* secd-61-account-leave-not-in-kansas-anymore.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 */, DCDCC7E31D9B54EE006487E8 /* secd-202-recoverykey.m in Sources */, - DC52EDDB1D80D5C500B0A59C /* secd-64-circlereset.c in Sources */, - 48AFBA7C1DEF8D4800436D08 /* secd-80-views-alwayson.c in Sources */, - DC52EDDC1D80D5C500B0A59C /* secd-70-engine.c in Sources */, - DC52EDDD1D80D5C500B0A59C /* secd-70-engine-corrupt.c in Sources */, - DC52EDDE1D80D5C500B0A59C /* secd-70-engine-smash.c in Sources */, - DC52EDDF1D80D5C500B0A59C /* secd-70-otr-remote.c in Sources */, - DC52EDE21D80D5C500B0A59C /* secd-74-engine-beer-servers.c in Sources */, - DC52EDE31D80D5C500B0A59C /* secd-75-engine-views.c in Sources */, - DC52EDE61D80D5C500B0A59C /* secd-80-views-basic.c in Sources */, - DC52EDE71D80D5C500B0A59C /* secd-82-secproperties-basic.c in Sources */, - DC52EDE81D80D5C500B0A59C /* secd-81-item-acl-stress.c in Sources */, - DC52EDE91D80D5C500B0A59C /* secd-81-item-acl.c in Sources */, - DC52EDEA1D80D5C500B0A59C /* secd-82-persistent-ref.c in Sources */, + DC52EDDB1D80D5C500B0A59C /* secd-64-circlereset.m in Sources */, + DC52EDDC1D80D5C500B0A59C /* secd-70-engine.m in Sources */, + 0C3C00731EF3636500AB19FE /* secd-155-otr-negotiation-monitor.m in Sources */, + 7281E08F1DFD0DBB0021E1B7 /* secd-210-keyinterest.m in Sources */, + 0CAD1E591E1C5CBD00537693 /* secd-52-offering-gencount-reset.m in Sources */, + DC52EDDD1D80D5C500B0A59C /* secd-70-engine-corrupt.m in Sources */, + DC52EDDE1D80D5C500B0A59C /* secd-70-engine-smash.m in Sources */, + 522B280E1E64B4BF002B5638 /* secd-230-keybagtable.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 */, + DC52EDE31D80D5C500B0A59C /* secd-75-engine-views.m in Sources */, + DC52EDE61D80D5C500B0A59C /* secd-80-views-basic.m in Sources */, + DC52EDE71D80D5C500B0A59C /* secd-82-secproperties-basic.m in Sources */, + DC52EDE81D80D5C500B0A59C /* secd-81-item-acl-stress.m in Sources */, + DC52EDE91D80D5C500B0A59C /* secd-81-item-acl.m in Sources */, + DC52EDEA1D80D5C500B0A59C /* secd-82-persistent-ref.m in Sources */, DC52EDEB1D80D5C500B0A59C /* secd-83-item-match-policy.m in Sources */, DC52EDEC1D80D5C500B0A59C /* secd-83-item-match-valid-on-date.m in Sources */, DC52EDED1D80D5C600B0A59C /* secd-83-item-match-trusted.m in Sources */, - DC52EDEF1D80D5C600B0A59C /* secd-90-hsa2.c in Sources */, - DC52EDF11D80D5C600B0A59C /* secd-100-initialsync.c in Sources */, - DC52EDF21D80D5C600B0A59C /* secd-130-other-peer-views.c in Sources */, - DC52EDF41D80D5C600B0A59C /* secd-200-logstate.c in Sources */, + DC52EDF11D80D5C600B0A59C /* secd-100-initialsync.m in Sources */, + DC52EDF21D80D5C600B0A59C /* secd-130-other-peer-views.m in Sources */, + DC52EDF41D80D5C600B0A59C /* secd-200-logstate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -23271,16 +27208,22 @@ 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 */, DC52EE5F1D80D79400B0A59C /* si-85-sectrust-ssl-policy.c in Sources */, + D4AA64891E9727EB00D317ED /* si-18-certificate-parse.m in Sources */, + B61577F41F20513C004A3930 /* padding-00-mmcs.c in Sources */, DC0B62291D90974600D43BCB /* si-25-cms-skid.m in Sources */, DC52EE5E1D80D78C00B0A59C /* si-82-sectrust-ct.m in Sources */, - DC52EE5D1D80D76B00B0A59C /* si-87-sectrust-name-constraints.c in Sources */, + DC52EE5D1D80D76B00B0A59C /* si-87-sectrust-name-constraints.m in Sources */, + 09CB49701F2F64E300C8E4DE /* si-44-seckey-fv.m in Sources */, DC52EE5C1D80D76300B0A59C /* si-20-sectrust-policies.m in Sources */, DC52EE511D80D73800B0A59C /* si-15-certificate.c in Sources */, + BE6215BE1DB6E69100961E15 /* si-84-sectrust-allowlist.m in Sources */, DC52EE521D80D73800B0A59C /* si-16-ec-certificate.c in Sources */, DC52EE421D80D71900B0A59C /* si-20-sectrust.c in Sources */, + D4096E031ED5F21C000AC459 /* si-65-cms-cert-policy.c in Sources */, DC52EE441D80D71900B0A59C /* si-21-sectrust-asr.c in Sources */, DC52EE451D80D71900B0A59C /* si-22-sectrust-iap.c in Sources */, DC52EE471D80D71900B0A59C /* si-23-sectrust-ocsp.c in Sources */, @@ -23291,19 +27234,23 @@ DC52EE4B1D80D71900B0A59C /* si-24-sectrust-nist.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 */, DC52EE4E1D80D71900B0A59C /* si-27-sectrust-exceptions.c 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 */, D487FBB81DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m in Sources */, DC52EE561D80D73800B0A59C /* si-44-seckey-ies.m in Sources */, - DC52EE571D80D73800B0A59C /* si-67-sectrust-blacklist.c in Sources */, + DC52EE571D80D73800B0A59C /* si-67-sectrust-blocklist.c in Sources */, + D4096E021ED5F207000AC459 /* si-64-ossl-cms.c in Sources */, DC52EE581D80D73800B0A59C /* si-70-sectrust-unified.c in Sources */, - BE6D96BB1DB14B9F001B76D4 /* si-84-sectrust-allowlist.m in Sources */, DC52EE591D80D73800B0A59C /* si-82-seccertificate-ct.c in Sources */, DC52EE5A1D80D73800B0A59C /* si-83-seccertificate-sighashalg.c in Sources */, DC52EE5B1D80D73800B0A59C /* si-97-sectrust-path-scoring.m in Sources */, + D47E69401E92F75D002C8CF6 /* si-61-pkcs12.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -23311,14 +27258,16 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EB78D3F91E600E93009AFE05 /* SOSCloudCircle.m in Sources */, DC52EE7C1D80D89E00B0A59C /* SecItemBackup.c in Sources */, + DC4269051E82EDC4002B7110 /* SecItem.m in Sources */, + EBEEEE3E1EA31DB100E15F5C /* SOSControlHelper.m in Sources */, DC52EE7B1D80D89900B0A59C /* SecKeyAdaptors.c in Sources */, DC52EE7A1D80D89400B0A59C /* SecCFAllocator.c in Sources */, DC52EE791D80D88D00B0A59C /* SecItem.c in Sources */, DC52EE781D80D88800B0A59C /* SecRSAKey.c in Sources */, DC52EE771D80D88300B0A59C /* SecDH.c in Sources */, DC52EE761D80D87F00B0A59C /* SecCTKKey.c in Sources */, - DC52EE751D80D87900B0A59C /* SOSCloudCircle.c in Sources */, DC52EE741D80D86F00B0A59C /* SecAccessControl.c in Sources */, DC52EE731D80D86800B0A59C /* SecKey.c in Sources */, DC52EE721D80D86400B0A59C /* SecuritydXPC.c in Sources */, @@ -23395,13 +27344,13 @@ DC5ABDD01D832E4000CF422C /* db_commands.cpp in Sources */, DC5ABDD11D832E4000CF422C /* display_error_code.c in Sources */, DC5ABDD21D832E4000CF422C /* trusted_cert_dump.c in Sources */, - DC5ABDD31D832E4000CF422C /* identity_find.c in Sources */, + DC5ABDD31D832E4000CF422C /* identity_find.m in Sources */, DC5ABDD41D832E4000CF422C /* identity_prefs.c in Sources */, DC5ABDD51D832E4000CF422C /* key_create.c in Sources */, DC5ABDD61D832E4000CF422C /* keychain_add.c in Sources */, DC5ABDD71D832E4000CF422C /* keychain_create.c in Sources */, DC5ABDD81D832E4000CF422C /* keychain_delete.c in Sources */, - DC5ABDD91D832E4000CF422C /* keychain_export.c in Sources */, + DC5ABDD91D832E4000CF422C /* keychain_export.m in Sources */, DC5ABDDA1D832E4000CF422C /* keychain_find.c in Sources */, DC5ABDDB1D832E4000CF422C /* keychain_import.c in Sources */, DC5ABDDC1D832E4000CF422C /* keychain_list.c in Sources */, @@ -23477,7 +27426,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 476541A21F33EDAD00413F65 /* SecdWatchdog.m in Sources */, + DCCD33D31E3FF0D800AA4AD1 /* spi.c in Sources */, DC610A181D78F129002223DE /* main.m in Sources */, + DC5F35B01EE0F27C00900966 /* server_entitlement_helpers.c in Sources */, + DC4269121E82FDA1002B7110 /* server_security_helpers.c in Sources */, + DCB2215A1E8B08CB001598BC /* server_xpc.m in Sources */, + DC4269011E82038D002B7110 /* server_endpoint.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -23721,7 +27676,6 @@ DCB3433B1D8A32A20054D16E /* Access.cpp in Sources */, DCB3436A1D8A32A20054D16E /* CCallbackMgr.cp in Sources */, DCB3433F1D8A32A20054D16E /* Certificate.cpp in Sources */, - DCB343411D8A32A20054D16E /* CertificateRequest.cpp in Sources */, DCB343431D8A32A20054D16E /* CertificateValues.cpp in Sources */, DCB343701D8A32A20054D16E /* DLDBListCFPref.cpp in Sources */, DCB343721D8A32A20054D16E /* DynamicDLDBList.cpp in Sources */, @@ -23747,7 +27701,6 @@ DCB342FD1D8A32A20054D16E /* SecCertificate.cpp in Sources */, DCB342FE1D8A32A20054D16E /* SecCertificateBundle.cpp in Sources */, DCB3438B1D8A32A20054D16E /* SecCertificateP.c in Sources */, - DCB342FF1D8A32A20054D16E /* SecCertificateRequest.cpp in Sources */, DCB343921D8A32A20054D16E /* SecExport.cpp in Sources */, DCB343931D8A32A20054D16E /* SecExternalRep.cpp in Sources */, DCB343371D8A32A20054D16E /* SecFDERecoveryAsymmetricCrypto.cpp in Sources */, @@ -23853,17 +27806,19 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 48BC0F651DFA2B5B00DDDFF9 /* accountCirclesViewsPrint.c in Sources */, - DCC78EE91D808B4100865A7C /* SOSCloudCircle.c in Sources */, + 0CAD1E581E1C5C6C00537693 /* SOSCloudCircle.m in Sources */, DCC78EE81D808B3500865A7C /* secToolFileIO.c in Sources */, DCC78EE71D808B2F00865A7C /* secViewDisplay.c in Sources */, DCC78EE61D808B2A00865A7C /* SecAccessControl.c in Sources */, DCC78EE51D808B2100865A7C /* SecBase64.c in Sources */, DCC78EE41D808B1B00865A7C /* SecCFAllocator.c in Sources */, DCC78EE31D808B1300865A7C /* SecCMS.c in Sources */, + BEEB47D91EA189F5004AA5C6 /* SecTrustStatusCodes.c in Sources */, DCC78EE21D808B0E00865A7C /* SecCTKKey.c in Sources */, DCC78EE11D808B0900865A7C /* SecCertificate.c in Sources */, DCC78EE01D808B0000865A7C /* SecCertificatePath.c in Sources */, + DC4269041E82EDAC002B7110 /* SecItem.m in Sources */, + EBEEEE3D1EA31DB000E15F5C /* SOSControlHelper.m in Sources */, DCC78EDF1D808AF800865A7C /* SecCertificateRequest.c in Sources */, DCC78EDE1D808AF100865A7C /* SecDH.c in Sources */, DCC78EDD1D808AEC00865A7C /* SecDigest.c in Sources */, @@ -23879,6 +27834,7 @@ DCC78ED31D808AA000865A7C /* SecKeyAdaptors.c in Sources */, DCC78ED21D808A9500865A7C /* SecOTRDHKey.c in Sources */, DCC78ED11D808A8E00865A7C /* SecOTRFullIdentity.c in Sources */, + B61577ED1F202049004A3930 /* SecPaddingConfigurations.c in Sources */, DCC78ED01D808A8800865A7C /* SecOTRMath.c in Sources */, DCC78ECF1D808A8200865A7C /* SecOTRPacketData.c in Sources */, DCC78ECE1D808A7B00865A7C /* SecOTRPackets.c in Sources */, @@ -23893,6 +27849,7 @@ DCC78EC51D808A4100865A7C /* SecRSAKey.c in Sources */, DCC78EC41D808A3B00865A7C /* SecSCEP.c in Sources */, DCC78EC31D808A2E00865A7C /* SecServerEncryptionSupport.c in Sources */, + 48C2F93A1E4BCFDC0093D70C /* accountCirclesViewsPrint.m in Sources */, DCC78EC21D808A2800865A7C /* SecSharedCredential.c in Sources */, DCC78EC11D808A2200865A7C /* SecSignatureVerificationSupport.c in Sources */, DCC78EC01D808A1C00865A7C /* SecTrust.c in Sources */, @@ -23904,11 +27861,6 @@ DCC78EBA1D8089BD00865A7C /* p12pbegen.c in Sources */, DCC78EB91D8089A700865A7C /* pbkdf2.c in Sources */, DCC78EB81D80899C00865A7C /* vmdh.c in Sources */, - DCC78EB61D80898E00865A7C /* secd-52-offering-gencount-reset.c in Sources */, - DCC78EB51D80898500865A7C /* secd-71-engine-save.c in Sources */, - DCC78EB41D80897E00865A7C /* secd-76-idstransport.c in Sources */, - DCC78EB31D80890E00865A7C /* secd-95-escrow-persistence.c in Sources */, - DCC78EB21D80890800865A7C /* secd_77_ids_messaging.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -23947,7 +27899,6 @@ DCD068221D8CDF7E007602F1 /* SecCodeSigner.cpp in Sources */, DCD068201D8CDF7E007602F1 /* SecRequirement.cpp in Sources */, DCD0681D1D8CDF7E007602F1 /* SecStaticCode.cpp in Sources */, - DCD068821D8CDF7E007602F1 /* SecTask.c in Sources */, DCD0682C1D8CDF7E007602F1 /* StaticCode.cpp in Sources */, DCD0693D1D8CDFFF007602F1 /* String.cpp in Sources */, DCD0693E1D8CDFFF007602F1 /* Token.cpp in Sources */, @@ -23979,6 +27930,7 @@ DCD0685A1D8CDF7E007602F1 /* kerneldiskrep.cpp in Sources */, DCD0685C1D8CDF7E007602F1 /* machorep.cpp in Sources */, DCD068881D8CDF7E007602F1 /* opaquewhitelist.cpp in Sources */, + DC5BD5841E8C6FD100C5EC49 /* SecTask.c in Sources */, DCD068661D8CDF7E007602F1 /* piddiskrep.cpp in Sources */, DCD0688A1D8CDF7E007602F1 /* policydb.cpp in Sources */, DCD0688C1D8CDF7E007602F1 /* policyengine.cpp in Sources */, @@ -24004,7 +27956,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DCD06A401D8CE245007602F1 /* SecIntegrityLib.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -24031,15 +27982,12 @@ DCD06B9C1D8E0D7D007602F1 /* cfmach++.cpp in Sources */, DCD06B5D1D8E0D7D007602F1 /* hashing.cpp in Sources */, DCD06B531D8E0D7D007602F1 /* devrandom.cpp in Sources */, - DCD06BB31D8E0D7D007602F1 /* headermap.cpp in Sources */, DCD06B8E1D8E0D7D007602F1 /* pcsc++.cpp in Sources */, DCD06B4B1D8E0D7D007602F1 /* ccaudit.cpp in Sources */, DCD06BAB1D8E0D7D007602F1 /* cfmunge.cpp in Sources */, - DCD06BBB1D8E0D7D007602F1 /* url.cpp in Sources */, DCD06B6B1D8E0D7D007602F1 /* seccfobject.cpp in Sources */, DCD06B741D8E0D7D007602F1 /* superblob.cpp in Sources */, DCD06BA01D8E0D7D007602F1 /* dyldcache.cpp in Sources */, - DCD06BB11D8E0D7D007602F1 /* buffers.cpp in Sources */, DCD06B6E1D8E0D7D007602F1 /* simpleprefs.cpp in Sources */, DCD06B621D8E0D7D007602F1 /* logging.cpp in Sources */, DCD06B771D8E0D7D007602F1 /* threading.cpp in Sources */, @@ -24051,25 +27999,15 @@ DCD06BAD1D8E0D7D007602F1 /* cfutilities.cpp in Sources */, DCD06B9A1D8E0D7D007602F1 /* mach_notify.c in Sources */, DCD06B431D8E0D7D007602F1 /* crc.c in Sources */, - DCD06BB51D8E0D7D007602F1 /* hosts.cpp in Sources */, DCD06B701D8E0D7D007602F1 /* sqlite++.cpp in Sources */, DCD06B541D8E0D7D007602F1 /* dispatch.cpp in Sources */, - DCD06B901D8E0D7D007602F1 /* selector.cpp in Sources */, - DCD06BB71D8E0D7D007602F1 /* inetreply.cpp in Sources */, - DCD06B881D8E0D7D007602F1 /* fdsel.cpp in Sources */, - DCD06B861D8E0D7D007602F1 /* fdmover.cpp in Sources */, - DCD06BBF1D8E0D7D007602F1 /* socks++4.cpp in Sources */, DCD06B3E1D8E0D7D007602F1 /* FileLockTransaction.cpp in Sources */, - DCD06BC11D8E0D7D007602F1 /* socks++5.cpp in Sources */, DCD06B4A1D8E0D7D007602F1 /* blob.cpp in Sources */, - DCD06B801D8E0D7D007602F1 /* typedvalue.cpp in Sources */, - DCD06BB91D8E0D7D007602F1 /* ip++.cpp in Sources */, DCD06B591D8E0D7D007602F1 /* errors.cpp in Sources */, DCD06B571D8E0D7D007602F1 /* endian.cpp in Sources */, DCD06B7E1D8E0D7D007602F1 /* transactions.cpp in Sources */, DCD06B921D8E0D7D007602F1 /* unix++.cpp in Sources */, DCD06BA71D8E0D7D007602F1 /* coderepository.cpp in Sources */, - DCD06B5F1D8E0D7D007602F1 /* iodevices.cpp in Sources */, DCD06B481D8E0D7D007602F1 /* alloc.cpp in Sources */, DCD06B961D8E0D7D007602F1 /* vproc++.cpp in Sources */, DCD06B8C1D8E0D7D007602F1 /* muscle++.cpp in Sources */, @@ -24081,8 +28019,6 @@ DCD06B941D8E0D7D007602F1 /* unixchild.cpp in Sources */, DCD06B401D8E0D7D007602F1 /* CSPDLTransaction.cpp in Sources */, DCD06B9E1D8E0D7D007602F1 /* macho++.cpp in Sources */, - DCD06BAF1D8E0D7D007602F1 /* bufferfifo.cpp in Sources */, - DCD06BBD1D8E0D7D007602F1 /* socks++.cpp in Sources */, DCD06B661D8E0D7D007602F1 /* osxcode.cpp in Sources */, DCD06B5B1D8E0D7D007602F1 /* globalizer.cpp in Sources */, DCD06B681D8E0D7D007602F1 /* powerwatch.cpp in Sources */, @@ -24099,6 +28035,7 @@ D45917E41DC13E6700752D25 /* SecCertificateRequest.c in Sources */, DCD66DC01D82054500DB1393 /* SecCertificate.c in Sources */, DCD66DBF1D82053E00DB1393 /* SecDigest.c in Sources */, + BEEB47DA1EA189F5004AA5C6 /* SecTrustStatusCodes.c in Sources */, DCD66DBE1D82053700DB1393 /* SecBase64.c in Sources */, DCD66DBD1D82053100DB1393 /* SecCertificatePath.c in Sources */, DCD66DB61D82050900DB1393 /* SecKey.c in Sources */, @@ -24131,6 +28068,60 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DCD8A1071E09EE0F00E4FA0A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DCD8A1DA1E09F54700E4FA0A /* SOSAccountDer.m in Sources */, + DCD8A1E31E09F7E700E4FA0A /* SOSAccountCloudParameters.m in Sources */, + DCD8A19D1E09EEC800E4FA0A /* SOSBackupSliceKeyBag.m in Sources */, + EB75B4961E75A44100E469CC /* SOSPiggyback.m in Sources */, + DCD8A1B31E09F12D00E4FA0A /* SOSCircle.c in Sources */, + DCD8A1AC1E09F09200E4FA0A /* SOSCircleDer.c in Sources */, + DCD8A1FF1E09FA6100E4FA0A /* secViewDisplay.c in Sources */, + DCD8A1B41E09F12D00E4FA0A /* SOSCircleV2.c in Sources */, + DCD8A1A01E09EF3500E4FA0A /* SOSCloudKeychainClient.c in Sources */, + DCD8A1DB1E09F5D100E4FA0A /* SOSAccountTrust.m in Sources */, + DCD8A1A11E09EF5C00E4FA0A /* SOSCloudKeychainConstants.c in Sources */, + DCD8A1A91E09F04700E4FA0A /* SOSECWrapUnwrap.c in Sources */, + 0C4899251E0F38FA00C6CF70 /* SOSAccountTrustOctagon.m in Sources */, + DCD8A1BD1E09F1D600E4FA0A /* SOSFullPeerInfo.m in Sources */, + DCD8A2001E09FA7900E4FA0A /* secToolFileIO.c in Sources */, + DCD8A1B51E09F15400E4FA0A /* SOSGenCount.c in Sources */, + DCD8A19F1E09EF0F00E4FA0A /* SOSInternal.m in Sources */, + EBEEEE3F1EA31E6D00E15F5C /* SOSControlHelper.m in Sources */, + DCD8A1A61E09EFD700E4FA0A /* SOSKVSKeys.m in Sources */, + DCD8A1B61E09F16C00E4FA0A /* SOSKeyedPubKeyIdentifier.c in Sources */, + DCD8A1321E09EE0F00E4FA0A /* SOSPeerInfo.m in Sources */, + DCD8A1A41E09EF9000E4FA0A /* SOSPeerInfoCollections.c in Sources */, + DCD8A1B11E09F11900E4FA0A /* SOSPeerInfoDER.m in Sources */, + 0CE7604C1E12F56800B4381E /* SOSAccountTrustClassic+Identity.m in Sources */, + DCD8A1B21E09F11900E4FA0A /* SOSPeerInfoRingState.m in Sources */, + DCD8A1A71E09F01300E4FA0A /* SOSPeerInfoSecurityProperties.m in Sources */, + 0CE7604E1E12F5BA00B4381E /* SOSAccountTrustClassic+Retirement.m in Sources */, + DCD8A1A51E09EFAE00E4FA0A /* SOSPeerInfoV2.m in Sources */, + 0CE760481E12F2F300B4381E /* SOSAccountTrustClassic+Expansion.m in Sources */, + 48C2F9391E4BCFDA0093D70C /* accountCirclesViewsPrint.m in Sources */, + DCD8A1C21E09F23B00E4FA0A /* SOSRecoveryKeyBag.m in Sources */, + DCD8A1B81E09F1BB00E4FA0A /* SOSRingBackup.m in Sources */, + DCD8A1B91E09F1BB00E4FA0A /* SOSRingBasic.m in Sources */, + DCD8A1BB1E09F1BB00E4FA0A /* SOSRingConcordanceTrust.c in Sources */, + DCD8A1AE1E09F0C500E4FA0A /* SOSRingDER.c in Sources */, + DCD8A1BC1E09F1BB00E4FA0A /* SOSRingPeerInfoUtils.c in Sources */, + DCD8A1BA1E09F1BB00E4FA0A /* SOSRingRecovery.m in Sources */, + DCD8A1B01E09F0F400E4FA0A /* SOSRingTypes.m in Sources */, + DCD8A1AF1E09F0DC00E4FA0A /* SOSRingUtils.c in Sources */, + 0C48991C1E0F384700C6CF70 /* SOSAccountTrustClassic.m in Sources */, + DCD8A1B71E09F19100E4FA0A /* SOSRingV0.m in Sources */, + DCD8A1A31E09EF7800E4FA0A /* SOSSysdiagnose.m in Sources */, + DCD8A1C71E09F2B400E4FA0A /* SOSTransport.m in Sources */, + DCD8A1A81E09F03100E4FA0A /* SOSUserKeygen.m in Sources */, + DCD8A1511E09EE0F00E4FA0A /* SOSViews.m in Sources */, + DCD8A19E1E09EEDA00E4FA0A /* SecRecoveryKey.m in Sources */, + 0CE7604A1E12F30200B4381E /* SOSAccountTrustClassic+Circle.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DCE4E6911D7A37FA00AFB96E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -24162,7 +28153,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DCCD33CE1E3FEF1700AA4AD1 /* spi.c in Sources */, + 476541701F33B59300413F65 /* SecdWatchdog.m in Sources */, DCE4E8071D7A4DE200AFB96E /* server.c in Sources */, + DC5F35A61EE0F25000900966 /* server_entitlement_helpers.c in Sources */, + DC4269081E82FD8B002B7110 /* server_security_helpers.c in Sources */, + DCB221501E8B08A5001598BC /* server_xpc.m in Sources */, + DC6ACC461E81E08D00125DC5 /* server_endpoint.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -24170,7 +28167,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DCE4E8391D7A57AE00AFB96E /* server.c in Sources */, + D4BEECE81E93094500F76D1A /* trustd.c in Sources */, + DC5F35A91EE0F25300900966 /* server_entitlement_helpers.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -24190,7 +28188,6 @@ DCE4E8C01D7F353900AFB96E /* process.c in Sources */, DCE4E8B31D7F353900AFB96E /* agent.c in Sources */, DCE4E8BE1D7F353900AFB96E /* mechanism.c in Sources */, - DCE4E8BB1D7F353900AFB96E /* debugging.c in Sources */, DCE4E8B41D7F353900AFB96E /* authdb.c in Sources */, DCE4E8B81D7F353900AFB96E /* ccaudit.c in Sources */, DCE4E8BD1D7F353900AFB96E /* main.c in Sources */, @@ -24457,8 +28454,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 476541A31F33EDCC00413F65 /* SecdWatchdog.m in Sources */, 4CC92B1C15A3BF2F00C6D578 /* testmain.c in Sources */, 0C78F1CC16A5E1BF00654E08 /* sectask-10-sectask.c in Sources */, + DCCD33D11E3FEF2C00AA4AD1 /* spi.c in Sources */, + DCB221541E8B08BE001598BC /* server_xpc.m in Sources */, + DC42690D1E82FD9B002B7110 /* server_security_helpers.c in Sources */, + DC4268FC1E820370002B7110 /* server_endpoint.m in Sources */, + DC5F35AB1EE0F27100900966 /* server_entitlement_helpers.c in Sources */, 0C78F1CE16A5E1BF00654E08 /* sectask_ipc.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -24474,6 +28477,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EB413B801E663AEB00592085 /* PairingChannel.m in Sources */, E7F480151C73980D00390FDB /* KCJoiningRequestSession.m in Sources */, E7F480331C73FC4C00390FDB /* KCAESGCMDuplexSession.m in Sources */, E794BB001C7598F900339A0F /* KCJoiningMessages.m in Sources */, @@ -24506,6 +28510,40 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EB1055711E14DF430003C309 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EB1055791E14DF570003C309 /* SecCertificateFuzzer.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB108F251E6CE4D2003B0456 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EB108F261E6CE4D2003B0456 /* KCPairingTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB27FF0D1E402CD300EC9E3A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DC5BCC481E53820200649140 /* SecArgParse.c in Sources */, + EB27FF2D1E407FF600EC9E3A /* ckksctl.m in Sources */, + DCF7A8A51F0451AC00CABE89 /* CKKSControlProtocol.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB2D54A21F02A45E00E46890 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EB2D54AB1F02A47200E46890 /* SecAtomicFile.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; EB425C9F1C65846D000ECE53 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -24538,6 +28576,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EBB839A11E29665D00853BAC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EBB839B01E2968AB00853BAC /* secfuzzer.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; EBCF73F41CE45F9C00BED7CA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -24554,12 +28600,29 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F621D02A1ED6DCE7000EA569 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F619D71E1ED70BC1005B5F46 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F667EC571E96E9B100203D5C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F667EC621E96EAD200203D5C /* main.m in Sources */, + F667EC611E96E9E700203D5C /* authdtests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 0C10C93A1DD548B6000602A8 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = 0C10C9391DD548B6000602A8 /* PBXContainerItemProxy */; }; 0C10C93C1DD548BD000602A8 /* PBXTargetDependency */ = { @@ -24592,11 +28655,31 @@ target = E710C7411331946400F85568 /* SecurityTests */; targetProxy = 0CC827F1138712B100BD99B7 /* PBXContainerItemProxy */; }; + 225394B61E30811400D3CD9B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 225394AC1E3080A600D3CD9B /* security_codesigning_ios */; + targetProxy = 225394B51E30811400D3CD9B /* PBXContainerItemProxy */; + }; + 225394DA1E30846800D3CD9B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD067561D8CDCF3007602F1 /* codesigning_DTrace */; + targetProxy = 225394D91E30846800D3CD9B /* PBXContainerItemProxy */; + }; + 226A8B451DEF58EE004C35E3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD06AA91D8E0D53007602F1 /* security_utilities */; + targetProxy = 226A8B441DEF58EE004C35E3 /* PBXContainerItemProxy */; + }; 438169E71B4EE4B300C54D58 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4381690B1B4EDCBD00C54D58 /* SOSCCAuthPlugin */; targetProxy = 438169E61B4EE4B300C54D58 /* PBXContainerItemProxy */; }; + 47C51B8B1EEA657D0032D9E5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC1789031D77980500B50D50 /* Security_osx */; + targetProxy = 47C51B8A1EEA657D0032D9E5 /* PBXContainerItemProxy */; + }; 4C52D0EE16EFCD720079966E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4C52D0B316EFC61E0079966E /* CircleJoinRequested */; @@ -24657,6 +28740,121 @@ target = 5EBE24791B00CCAE0007DB0E /* secacltests */; targetProxy = 5EF7C2551B00EEF900E5E99C /* PBXContainerItemProxy */; }; + 6C24EF4A1E415109000DE79F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6CCDF7831E3C25FA003F2555 /* KeychainEntitledTestRunner */; + targetProxy = 6C24EF491E415109000DE79F /* PBXContainerItemProxy */; + }; + 6C24EF531E415132000DE79F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6CCDF7831E3C25FA003F2555 /* KeychainEntitledTestRunner */; + targetProxy = 6C24EF521E415132000DE79F /* PBXContainerItemProxy */; + }; + 6C98082D1E788AEB00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC59E9AC1D91C9DC001BDDF5 /* DER_not_installed */; + targetProxy = 6C98082E1E788AEB00E70590 /* PBXContainerItemProxy */; + }; + 6C98082F1E788AEB00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC8834011D8A218F00CE0ACA /* ASN1_not_installed */; + targetProxy = 6C9808301E788AEB00E70590 /* PBXContainerItemProxy */; + }; + 6C9808311E788AEB00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BCC211D8C684F00070CB0 /* utilities */; + targetProxy = 6C9808321E788AEB00E70590 /* PBXContainerItemProxy */; + }; + 6C9808351E788AEB00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = 6C9808361E788AEB00E70590 /* PBXContainerItemProxy */; + }; + 6C9808371E788AEB00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; + targetProxy = 6C9808381E788AEB00E70590 /* PBXContainerItemProxy */; + }; + 6C9808391E788AEB00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCC78EA81D8088E200865A7C /* security */; + targetProxy = 6C98083A1E788AEB00E70590 /* PBXContainerItemProxy */; + }; + 6C98083B1E788AEB00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC222C371E034D1F00B09171 /* libsecurityd_ios_NO_AKS */; + targetProxy = 6C98083C1E788AEB00E70590 /* PBXContainerItemProxy */; + }; + 6C9808691E788AFD00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC59E9AC1D91C9DC001BDDF5 /* DER_not_installed */; + targetProxy = 6C98086A1E788AFD00E70590 /* PBXContainerItemProxy */; + }; + 6C98086B1E788AFD00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC8834011D8A218F00CE0ACA /* ASN1_not_installed */; + targetProxy = 6C98086C1E788AFD00E70590 /* PBXContainerItemProxy */; + }; + 6C98086D1E788AFD00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BCC211D8C684F00070CB0 /* utilities */; + targetProxy = 6C98086E1E788AFD00E70590 /* PBXContainerItemProxy */; + }; + 6C9808711E788AFD00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = 6C9808721E788AFD00E70590 /* PBXContainerItemProxy */; + }; + 6C9808731E788AFD00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; + targetProxy = 6C9808741E788AFD00E70590 /* PBXContainerItemProxy */; + }; + 6C9808751E788AFD00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCC78EA81D8088E200865A7C /* security */; + targetProxy = 6C9808761E788AFD00E70590 /* PBXContainerItemProxy */; + }; + 6C9808771E788AFD00E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC222C371E034D1F00B09171 /* libsecurityd_ios_NO_AKS */; + targetProxy = 6C9808781E788AFD00E70590 /* PBXContainerItemProxy */; + }; + 6C9808A01E788B9400E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */; + targetProxy = 6C98089F1E788B9400E70590 /* PBXContainerItemProxy */; + }; + 6C9808A41E788CB100E70590 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6CF4A0DF1E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */; + targetProxy = 6C9808A31E788CB100E70590 /* PBXContainerItemProxy */; + }; + ACBAF6FE1E941E090007BA2F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = ACBAF6991E9417F40007BA2F /* security_transform_regressions */; + targetProxy = ACBAF6FD1E941E090007BA2F /* PBXContainerItemProxy */; + }; + BE061EAC1EE5EA5600B22118 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BED208D41EDF950E00753952 /* manifeststresstest */; + targetProxy = BE061EAB1EE5EA5600B22118 /* PBXContainerItemProxy */; + }; + BE061EB31EE5EAC800B22118 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BED208D41EDF950E00753952 /* manifeststresstest */; + targetProxy = BE061EB21EE5EAC800B22118 /* PBXContainerItemProxy */; + }; + BE061EB71EE5EB9000B22118 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BED208D41EDF950E00753952 /* manifeststresstest */; + targetProxy = BE061EB61EE5EB9000B22118 /* PBXContainerItemProxy */; + }; + BE061EB91EE5EBA000B22118 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BED208D41EDF950E00753952 /* manifeststresstest */; + targetProxy = BE061EB81EE5EBA000B22118 /* PBXContainerItemProxy */; + }; BE197F631911742900BA91D1 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = BE197F2519116FD100BA91D1 /* SharedWebCredentialViewService */; @@ -24667,11 +28865,106 @@ target = BE442BA018B7FDB800F24DAE /* swcagent */; targetProxy = BE4AC9B318B8020400B84964 /* PBXContainerItemProxy */; }; + BE9C38C81EB115A7007E2AE1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BEF88C271EAFFC3F00357577 /* TrustedPeers */; + targetProxy = BE9C38C71EB115A7007E2AE1 /* PBXContainerItemProxy */; + }; + BE9C38CF1EB115C9007E2AE1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BEF88C271EAFFC3F00357577 /* TrustedPeers */; + targetProxy = BE9C38CE1EB115C9007E2AE1 /* PBXContainerItemProxy */; + }; + BE9C38D11EB115F4007E2AE1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BEF88C2F1EAFFC3F00357577 /* TrustedPeersTests */; + targetProxy = BE9C38D01EB115F4007E2AE1 /* PBXContainerItemProxy */; + }; + BE9C38D31EB11605007E2AE1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BEF88C2F1EAFFC3F00357577 /* TrustedPeersTests */; + targetProxy = BE9C38D21EB11605007E2AE1 /* PBXContainerItemProxy */; + }; + BEF88C331EAFFC3F00357577 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = BEF88C271EAFFC3F00357577 /* TrustedPeers */; + targetProxy = BEF88C321EAFFC3F00357577 /* PBXContainerItemProxy */; + }; CD0637811A840C6400C81E74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = CD276C261A83F60C003226BC /* KeychainSyncingOverIDSProxy */; targetProxy = CD6130ED1DA1C0CC00E1E42F /* PBXContainerItemProxy */; }; + D40B6A7F1E2B5F3D00CD6EE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D4ADA3181E2B41670031CEA3 /* libtrustd */; + targetProxy = D40B6A7E1E2B5F3D00CD6EE5 /* PBXContainerItemProxy */; + }; + D40B6A811E2B5F4700CD6EE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D4ADA3181E2B41670031CEA3 /* libtrustd */; + targetProxy = D40B6A801E2B5F4700CD6EE5 /* PBXContainerItemProxy */; + }; + D40B6A861E2B5F7600CD6EE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D4ADA3181E2B41670031CEA3 /* libtrustd */; + targetProxy = D40B6A851E2B5F7600CD6EE5 /* PBXContainerItemProxy */; + }; + D40B6A8C1E2B63D100CD6EE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D4ADA3181E2B41670031CEA3 /* libtrustd */; + targetProxy = D40B6A8B1E2B63D100CD6EE5 /* PBXContainerItemProxy */; + }; + D40B6A921E2B678D00CD6EE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D4ADA3181E2B41670031CEA3 /* libtrustd */; + targetProxy = D40B6A911E2B678D00CD6EE5 /* PBXContainerItemProxy */; + }; + D40B6A951E2B67FF00CD6EE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D4ADA3181E2B41670031CEA3 /* libtrustd */; + targetProxy = D40B6A941E2B67FF00CD6EE5 /* PBXContainerItemProxy */; + }; + D41257E41E941A8400781F23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC59E9AC1D91C9DC001BDDF5 /* DER_not_installed */; + targetProxy = D41257E31E941A8400781F23 /* PBXContainerItemProxy */; + }; + D41257E61E941ACC00781F23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BCC211D8C684F00070CB0 /* utilities */; + targetProxy = D41257E51E941ACC00781F23 /* PBXContainerItemProxy */; + }; + D41257E81E941AD200781F23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D4ADA3181E2B41670031CEA3 /* libtrustd */; + targetProxy = D41257E71E941AD200781F23 /* PBXContainerItemProxy */; + }; + D41257F11E941E7D00781F23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D41257CE1E9410A300781F23 /* trustd_ios */; + targetProxy = D41257F01E941E7D00781F23 /* PBXContainerItemProxy */; + }; + D41257F31E941E8600781F23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D41257CE1E9410A300781F23 /* trustd_ios */; + targetProxy = D41257F21E941E8600781F23 /* PBXContainerItemProxy */; + }; + D41257F51E941E8E00781F23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D41257CE1E9410A300781F23 /* trustd_ios */; + targetProxy = D41257F41E941E8E00781F23 /* PBXContainerItemProxy */; + }; + D41257F71E941E9600781F23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D41257CE1E9410A300781F23 /* trustd_ios */; + targetProxy = D41257F61E941E9600781F23 /* PBXContainerItemProxy */; + }; + D419C0261E57EACA008619D1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4CE5A54C09C796E100D27A3F /* sslViewer */; + targetProxy = D419C0251E57EACA008619D1 /* PBXContainerItemProxy */; + }; D41AD43A1B96721E008C7270 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 790851B50CA9859F0083CC4D /* securityd_ios */; @@ -24782,6 +29075,11 @@ target = 728B56A016D59979008FA3AB /* OTAPKIAssetTool */; targetProxy = D41AD4711B978F76008C7270 /* PBXContainerItemProxy */; }; + DA30D6821DF8C93500EC6B43 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DA30D6751DF8C8FB00EC6B43 /* KeychainSyncAccountUpdater */; + targetProxy = DA30D6811DF8C93500EC6B43 /* PBXContainerItemProxy */; + }; DC0067901D878132005AF8DB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC6A82911D87749900418608 /* securityd_client_macos */; @@ -24817,16 +29115,6 @@ target = DC008B451D90CE53004002A3 /* securityd_macos_mig */; targetProxy = DC008B651D90CF40004002A3 /* PBXContainerItemProxy */; }; - DC00AB661D821BFD00513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E88A1D80C1EB00B0A59C /* secipc_client */; - targetProxy = DC00AB651D821BFD00513D74 /* PBXContainerItemProxy */; - }; - DC00AB681D821C0500513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; - targetProxy = DC00AB671D821C0500513D74 /* PBXContainerItemProxy */; - }; DC00AB6A1D821C0700513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC52EC521D80D05200B0A59C /* logging */; @@ -24844,17 +29132,12 @@ }; DC00AB761D821C4C00513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC00AB751D821C4C00513D74 /* PBXContainerItemProxy */; }; - DC00AB781D821C5000513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E88A1D80C1EB00B0A59C /* secipc_client */; - targetProxy = DC00AB771D821C5000513D74 /* PBXContainerItemProxy */; - }; DC00AB7E1D821C7F00513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC00AB7D1D821C7F00513D74 /* PBXContainerItemProxy */; }; DC00AB801D821C8300513D74 /* PBXTargetDependency */ = { @@ -24862,21 +29145,6 @@ target = DC52EC3E1D80D00800B0A59C /* libSWCAgent */; targetProxy = DC00AB7F1D821C8300513D74 /* PBXContainerItemProxy */; }; - DC00AB851D821CA300513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; - targetProxy = DC00AB841D821CA300513D74 /* PBXContainerItemProxy */; - }; - DC00AB871D821CA900513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */; - targetProxy = DC00AB861D821CA900513D74 /* PBXContainerItemProxy */; - }; - DC00AB891D821CAD00513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E88A1D80C1EB00B0A59C /* secipc_client */; - targetProxy = DC00AB881D821CAD00513D74 /* PBXContainerItemProxy */; - }; DC00AB921D821D6000513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC52EC211D80CFB200B0A59C /* SOSCommands */; @@ -24897,21 +29165,6 @@ target = DCC78EA81D8088E200865A7C /* security */; targetProxy = DC00AB9D1D821DBB00513D74 /* PBXContainerItemProxy */; }; - DC00ABA01D821DBC00513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */; - targetProxy = DC00AB9F1D821DBC00513D74 /* PBXContainerItemProxy */; - }; - DC00ABA21D821DBF00513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; - targetProxy = DC00ABA11D821DBF00513D74 /* PBXContainerItemProxy */; - }; - DC00ABA41D821DC400513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E88A1D80C1EB00B0A59C /* secipc_client */; - targetProxy = DC00ABA31D821DC400513D74 /* PBXContainerItemProxy */; - }; DC00ABAA1D821DE600513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */; @@ -24919,7 +29172,7 @@ }; DC00ABAC1D821DE700513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC00ABAB1D821DE700513D74 /* PBXContainerItemProxy */; }; DC00ABAE1D821DEB00513D74 /* PBXTargetDependency */ = { @@ -24944,7 +29197,7 @@ }; DC00ABBD1D821E9F00513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC00ABBC1D821E9F00513D74 /* PBXContainerItemProxy */; }; DC00ABBF1D821EA700513D74 /* PBXTargetDependency */ = { @@ -24959,14 +29212,9 @@ }; DC00ABCB1D821F0500513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC00ABCA1D821F0500513D74 /* PBXContainerItemProxy */; }; - DC00ABCF1D821F1700513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E88A1D80C1EB00B0A59C /* secipc_client */; - targetProxy = DC00ABCE1D821F1700513D74 /* PBXContainerItemProxy */; - }; DC00ABD11D821F1A00513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DCC78EA81D8088E200865A7C /* security */; @@ -24974,7 +29222,7 @@ }; DC00ABD31D821F1D00513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC00ABD21D821F1D00513D74 /* PBXContainerItemProxy */; }; DC00ABD51D821F2700513D74 /* PBXTargetDependency */ = { @@ -24982,19 +29230,9 @@ target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */; targetProxy = DC00ABD41D821F2700513D74 /* PBXContainerItemProxy */; }; - DC00ABDC1D821F5300513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52E88A1D80C1EB00B0A59C /* secipc_client */; - targetProxy = DC00ABDB1D821F5300513D74 /* PBXContainerItemProxy */; - }; - DC00ABDE1D821F5600513D74 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DCC78EA81D8088E200865A7C /* security */; - targetProxy = DC00ABDD1D821F5600513D74 /* PBXContainerItemProxy */; - }; DC00ABE01D821F5C00513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC00ABDF1D821F5C00513D74 /* PBXContainerItemProxy */; }; DC00ABE21D821F6000513D74 /* PBXTargetDependency */ = { @@ -25009,7 +29247,7 @@ }; DC00ABEE1D821FB700513D74 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC00ABED1D821FB700513D74 /* PBXContainerItemProxy */; }; DC00ABF01D821FBA00513D74 /* PBXTargetDependency */ = { @@ -25017,20 +29255,25 @@ target = DC52EC601D80D0C400B0A59C /* SOSRegressions */; targetProxy = DC00ABEF1D821FBA00513D74 /* PBXContainerItemProxy */; }; + DC0984F71E1DB6D400140ADC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DC0984F61E1DB6D400140ADC /* PBXContainerItemProxy */; + }; + DC0985001E1DB70A00140ADC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; + targetProxy = DC0984FF1E1DB70A00140ADC /* PBXContainerItemProxy */; + }; DC0B62961D90B6DB00D43BCB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC1785041D77873100B50D50 /* copyHeadersToSystem */; targetProxy = DC0B62951D90B6DB00D43BCB /* PBXContainerItemProxy */; }; - DC0BC55B1D8B6D2E00070CB0 /* PBXTargetDependency */ = { + DC0BB4441ED4D74A0035F886 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC0BC5501D8B6D2D00070CB0 /* XPCKeychainSandboxCheck */; - targetProxy = DC0BC55A1D8B6D2E00070CB0 /* PBXContainerItemProxy */; - }; - DC0BC5791D8B6EE200070CB0 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC0BC5631D8B6E3D00070CB0 /* XPCTimeStampingService */; - targetProxy = DC0BC5781D8B6EE200070CB0 /* PBXContainerItemProxy */; + target = DCC78EA81D8088E200865A7C /* security */; + targetProxy = DC0BB4431ED4D74A0035F886 /* PBXContainerItemProxy */; }; DC0BC5AF1D8B714000070CB0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; @@ -25147,25 +29390,50 @@ target = DC1789031D77980500B50D50 /* Security_osx */; targetProxy = DC178BF21D77ABE300B50D50 /* PBXContainerItemProxy */; }; + DC222C791E034EE700B09171 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC222C371E034D1F00B09171 /* libsecurityd_ios_NO_AKS */; + targetProxy = DC222C781E034EE700B09171 /* PBXContainerItemProxy */; + }; + DC3502C41E020D4D00BC0587 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC8834011D8A218F00CE0ACA /* ASN1_not_installed */; + targetProxy = DC3502C31E020D4D00BC0587 /* PBXContainerItemProxy */; + }; + DC3502C71E020D5600BC0587 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC59E9AC1D91C9DC001BDDF5 /* DER_not_installed */; + targetProxy = DC3502C61E020D5600BC0587 /* PBXContainerItemProxy */; + }; + DC3502CE1E020E2200BC0587 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BCC211D8C684F00070CB0 /* utilities */; + targetProxy = DC3502CD1E020E2200BC0587 /* PBXContainerItemProxy */; + }; + DC3502D51E02117600BC0587 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCC78EA81D8088E200865A7C /* security */; + targetProxy = DC3502D41E02117600BC0587 /* PBXContainerItemProxy */; + }; DC3A4B6B1D91EBEE00E46D4A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC3A4B571D91E9FB00E46D4A /* CodeSigningHelper */; targetProxy = DC3A4B6A1D91EBEE00E46D4A /* PBXContainerItemProxy */; }; - DC52E84B1D80BF1100B0A59C /* PBXTargetDependency */ = { + DC5224F91E4029520021640A /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */; - targetProxy = DC52E84A1D80BF1100B0A59C /* PBXContainerItemProxy */; + target = DC3502B41E0208BE00BC0587 /* CKKSTests */; + targetProxy = DC5224F81E4029520021640A /* PBXContainerItemProxy */; }; - DC52E8BD1D80C23300B0A59C /* PBXTargetDependency */ = { + DC5225001E40295C0021640A /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E88A1D80C1EB00B0A59C /* secipc_client */; - targetProxy = DC52E8BC1D80C23300B0A59C /* PBXContainerItemProxy */; + target = DC3502B41E0208BE00BC0587 /* CKKSTests */; + targetProxy = DC5224FF1E40295C0021640A /* PBXContainerItemProxy */; }; - DC52E9A31D80C5EE00B0A59C /* PBXTargetDependency */ = { + DC52E84B1D80BF1100B0A59C /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; - targetProxy = DC52E9A21D80C5EE00B0A59C /* PBXContainerItemProxy */; + target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */; + targetProxy = DC52E84A1D80BF1100B0A59C /* PBXContainerItemProxy */; }; DC52EAA51D80CCF600B0A59C /* PBXTargetDependency */ = { isa = PBXTargetDependency; @@ -25659,14 +29927,9 @@ }; DC71DA0D1D95DD670065FB93 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC71DA0C1D95DD670065FB93 /* PBXContainerItemProxy */; }; - DC71DA0F1D95E1210065FB93 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DC52EE661D80D82600B0A59C /* SecItemShimOSX */; - targetProxy = DC71DA0E1D95E1210065FB93 /* PBXContainerItemProxy */; - }; DC82FFEB1D90D4640085674B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC82FFE51D90D3F60085674B /* security_utilities_DTrace */; @@ -25677,6 +29940,11 @@ target = DC82FFEC1D90D4D20085674B /* security_ocspd_macos_mig */; targetProxy = DC82FFF11D90D54F0085674B /* PBXContainerItemProxy */; }; + DC89998B1E410DBF00E6E604 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC8834011D8A218F00CE0ACA /* ASN1_not_installed */; + targetProxy = DC89998A1E410DBF00E6E604 /* PBXContainerItemProxy */; + }; DCB340191D8A248C0054D16E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC8834011D8A218F00CE0ACA /* ASN1_not_installed */; @@ -25712,6 +29980,26 @@ target = DCB343AD1D8A34FD0054D16E /* security_keychain_regressions */; targetProxy = DCB345B21D8A361F0054D16E /* PBXContainerItemProxy */; }; + DCB515D01ED3CC36001F1152 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6C9808681E788AFD00E70590 /* CKKSCloudKitTests_ios */; + targetProxy = DCB515CF1ED3CC36001F1152 /* PBXContainerItemProxy */; + }; + DCB515D71ED3CC52001F1152 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6C98082C1E788AEB00E70590 /* CKKSCloudKitTests_mac */; + targetProxy = DCB515D61ED3CC52001F1152 /* PBXContainerItemProxy */; + }; + DCB515D91ED3CC6B001F1152 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */; + targetProxy = DCB515D81ED3CC6B001F1152 /* PBXContainerItemProxy */; + }; + DCB515DB1ED3CC73001F1152 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6CF4A0DF1E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */; + targetProxy = DCB515DA1ED3CC73001F1152 /* PBXContainerItemProxy */; + }; DCBE6E4A1D91E23D00A3E5E5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DCD06A541D8CE2D5007602F1 /* gkunpack */; @@ -25824,7 +30112,7 @@ }; DCD22D841D8CCB72001C9B81 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DC52E8BE1D80C25800B0A59C /* SecureObjectSync */; + target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DCD22D831D8CCB72001C9B81 /* PBXContainerItemProxy */; }; DCD66DC31D82056C00DB1393 /* PBXTargetDependency */ = { @@ -25837,6 +30125,66 @@ target = DCD66DC41D8205C400DB1393 /* SecOtrOSX */; targetProxy = DCD66DE51D82061F00DB1393 /* PBXContainerItemProxy */; }; + DCD8A19C1E09EEA200E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A19B1E09EEA200E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1E61E09F81300E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1E51E09F81300E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1E91E09F85B00E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1E81E09F85B00E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1EC1E09F88400E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1EB1E09F88400E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1EF1E09F8BC00E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1EE1E09F8BC00E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1F21E09F8DB00E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1F11E09F8DB00E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1F51E09F91F00E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1F41E09F91F00E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1F81E09F97300E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1F71E09F97300E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1FB1E09F99700E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1FA1E09F99700E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A1FE1E09FA1800E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A1FD1E09FA1800E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A2031E09FAE500E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A2021E09FAE500E4FA0A /* PBXContainerItemProxy */; + }; + DCD8A2071E09FB1F00E4FA0A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = DCD8A2061E09FB1F00E4FA0A /* PBXContainerItemProxy */; + }; DCE4E6AA1D7A38E700AFB96E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DCE4E68A1D7A37FA00AFB96E /* security2tool_macos */; @@ -25869,7 +30217,7 @@ }; DCE4E8621D7A58BA00AFB96E /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DCE4E82D1D7A57AE00AFB96E /* trustd */; + target = DCE4E82D1D7A57AE00AFB96E /* trustd_macos */; targetProxy = DCE4E8611D7A58BA00AFB96E /* PBXContainerItemProxy */; }; DCE4E8D81D7F37F200AFB96E /* PBXTargetDependency */ = { @@ -25987,6 +30335,66 @@ target = CD276C261A83F60C003226BC /* KeychainSyncingOverIDSProxy */; targetProxy = CD6130EC1DA1C0CC00E1E42F /* PBXContainerItemProxy */; }; + EB0D30FA1EF12BFB00C3C17D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E79EEDD21CD3F8AB00C2FBFC /* Security_tests_ios */; + targetProxy = EB0D30F91EF12BFB00C3C17D /* PBXContainerItemProxy */; + }; + EB10557D1E14DFB60003C309 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EB1055741E14DF430003C309 /* SecCertificateFuzzer */; + targetProxy = EB10557C1E14DFB60003C309 /* PBXContainerItemProxy */; + }; + EB10557F1E14DFBE0003C309 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EB1055741E14DF430003C309 /* SecCertificateFuzzer */; + targetProxy = EB10557E1E14DFBE0003C309 /* PBXContainerItemProxy */; + }; + EB108F1F1E6CE4D2003B0456 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BCC211D8C684F00070CB0 /* utilities */; + targetProxy = EB108F201E6CE4D2003B0456 /* PBXContainerItemProxy */; + }; + EB1C4CA71E85883900404981 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 470415CE1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */; + targetProxy = EB1C4CA61E85883900404981 /* PBXContainerItemProxy */; + }; + EB1C4CA91E85883900404981 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 47702B1D1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */; + targetProxy = EB1C4CA81E85883900404981 /* PBXContainerItemProxy */; + }; + EB1C4CAB1E85883900404981 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 47702B2D1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */; + targetProxy = EB1C4CAA1E85883900404981 /* PBXContainerItemProxy */; + }; + EB1C4CB21E85884300404981 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 470415CE1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */; + targetProxy = EB1C4CB11E85884300404981 /* PBXContainerItemProxy */; + }; + EB1C4CB41E85884300404981 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 47702B1D1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */; + targetProxy = EB1C4CB31E85884300404981 /* PBXContainerItemProxy */; + }; + EB1C4CB61E85884300404981 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 47702B2D1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */; + targetProxy = EB1C4CB51E85884300404981 /* PBXContainerItemProxy */; + }; + EB27FF261E40716D00EC9E3A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EB27FF101E402CD300EC9E3A /* ckksctl */; + targetProxy = EB27FF251E40716D00EC9E3A /* PBXContainerItemProxy */; + }; + EB27FF281E40717400EC9E3A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EB27FF101E402CD300EC9E3A /* ckksctl */; + targetProxy = EB27FF271E40717400EC9E3A /* PBXContainerItemProxy */; + }; EB31EA831D3EF2FB008F952A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5346480017331E1100FE9172 /* KeychainSyncAccountNotification */; @@ -26007,6 +30415,26 @@ target = EB433A201CC3243600A7EACE /* secitemstresstest */; targetProxy = EB433A2B1CC3252A00A7EACE /* PBXContainerItemProxy */; }; + EB58A05C1E74C517009C10D7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E79EEDA71CD3F87B00C2FBFC /* Security_tests_osx */; + targetProxy = EB58A05B1E74C517009C10D7 /* PBXContainerItemProxy */; + }; + EB58A05E1E74C51F009C10D7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E79EEDD21CD3F8AB00C2FBFC /* Security_tests_ios */; + targetProxy = EB58A05D1E74C51F009C10D7 /* PBXContainerItemProxy */; + }; + EB58A0601E74C8D9009C10D7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EBB839A41E29665D00853BAC /* secfuzzer */; + targetProxy = EB58A05F1E74C8D9009C10D7 /* PBXContainerItemProxy */; + }; + EB58A0621E74C8E4009C10D7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EBB839A41E29665D00853BAC /* secfuzzer */; + targetProxy = EB58A0611E74C8E4009C10D7 /* PBXContainerItemProxy */; + }; EB63ADE11C3E74F900C45A69 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = EB0BC9361C3C791500785842 /* secedumodetest */; @@ -26052,6 +30480,16 @@ target = EB9C1DAE1BDFD4DE00F89272 /* SecurityBatsTests */; targetProxy = EB9FE0B51BFBC499004FEAAF /* PBXContainerItemProxy */; }; + EBA62C151EAD34C60096B33A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6CCDF7831E3C25FA003F2555 /* KeychainEntitledTestRunner */; + targetProxy = EBA62C141EAD34C60096B33A /* PBXContainerItemProxy */; + }; + EBA62C1C1EAD34CD0096B33A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6CCDF7831E3C25FA003F2555 /* KeychainEntitledTestRunner */; + targetProxy = EBA62C1B1EAD34CD0096B33A /* PBXContainerItemProxy */; + }; EBA9AA891CE3E76C004E2B68 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = EBA9AA7D1CE30E58004E2B68 /* secitemnotifications */; @@ -26072,6 +30510,16 @@ target = EBCF73F31CE45F9C00BED7CA /* secitemfunctionality */; targetProxy = EBCF743E1CE593A700BED7CA /* PBXContainerItemProxy */; }; + EBD31B3B1E0A186500FBE9FA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BC5631D8B6E3D00070CB0 /* XPCTimeStampingService */; + targetProxy = EBD31B3A1E0A186500FBE9FA /* PBXContainerItemProxy */; + }; + EBD31B421E0A18A600FBE9FA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BC5501D8B6D2D00070CB0 /* XPCKeychainSandboxCheck */; + targetProxy = EBD31B411E0A18A600FBE9FA /* PBXContainerItemProxy */; + }; EBD849361B242C8900C5FD1E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4CE5A54C09C796E100D27A3F /* sslViewer */; @@ -26097,6 +30545,61 @@ target = EBF374711DC055580065D840 /* security-sysdiagnose */; targetProxy = EBF374871DC058CC0065D840 /* PBXContainerItemProxy */; }; + EBFBC2B01E76582C00A34469 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EB108F181E6CE4D2003B0456 /* KCPairingTests */; + targetProxy = EBFBC2AF1E76582C00A34469 /* PBXContainerItemProxy */; + }; + EBFBC2B21E76585500A34469 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E7D847C41C6BE9710025BB44 /* KeychainCircle */; + targetProxy = EBFBC2B11E76585500A34469 /* PBXContainerItemProxy */; + }; + EBFBC2B41E76586700A34469 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCC78EA81D8088E200865A7C /* security */; + targetProxy = EBFBC2B31E76586700A34469 /* PBXContainerItemProxy */; + }; + EBFBC2B61E76587800A34469 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */; + targetProxy = EBFBC2B51E76587800A34469 /* PBXContainerItemProxy */; + }; + EBFBC2B81E76588200A34469 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC59E9AC1D91C9DC001BDDF5 /* DER_not_installed */; + targetProxy = EBFBC2B71E76588200A34469 /* PBXContainerItemProxy */; + }; + EBFBC2BA1E76588A00A34469 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC8834011D8A218F00CE0ACA /* ASN1_not_installed */; + targetProxy = EBFBC2B91E76588A00A34469 /* PBXContainerItemProxy */; + }; + EBFF18CE1F02BA66004E58FC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EB2D54A11F02A45E00E46890 /* secatomicfile */; + targetProxy = EBFF18CD1F02BA66004E58FC /* PBXContainerItemProxy */; + }; + EBFF18D01F02C2FE004E58FC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BC8981D8B7CBD00070CB0 /* security_filedb */; + targetProxy = EBFF18CF1F02C2FE004E58FC /* PBXContainerItemProxy */; + }; + F621D0831ED6ED5B000EA569 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F621D0271ED6DCE7000EA569 /* authorizationdump */; + targetProxy = F621D0821ED6ED5B000EA569 /* PBXContainerItemProxy */; + }; + F667EC651E96EDCF00203D5C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DC0BCBD91D8C648C00070CB0 /* regressionBase */; + targetProxy = F667EC641E96EDCF00203D5C /* PBXContainerItemProxy */; + }; + F667EC671E96FA4600203D5C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F667EC561E96E9B100203D5C /* authdtest */; + targetProxy = F667EC661E96FA4600203D5C /* PBXContainerItemProxy */; + }; F94E7AE21ACC8E7700F23132 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = F93C49021AB8FCE00047E01A /* ckcdiagnose.sh */; @@ -26137,6 +30640,30 @@ name = CloudKeychain.strings; sourceTree = ""; }; + 6CF4A0C11E45488B00ECD7B5 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 6CF4A0C21E45488B00ECD7B5 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 6CF4A0EB1E4549F300ECD7B5 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 6CF4A0EC1E4549F300ECD7B5 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 6CF4A0F01E4549F300ECD7B5 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 6CF4A0F11E4549F300ECD7B5 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; BE197F2A19116FD100BA91D1 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( @@ -26310,21 +30837,35 @@ "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; INSTALL_PATH = /usr/local/bin; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)/usr/lib/system", ); - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "-ObjC", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_MOBILEASSET)", + ); "OTHER_LDFLAGS[sdk=embedded]" = ( + "$(inherited)", "-framework", MobileKeyBag, "-laks", "-lACM", "-lImg4Decode", "-lz", - "-ObjC", "-lSystem", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-framework", + CrashReporterSupport, ); PRODUCT_NAME = secdtests; STRIP_STYLE = debugging; @@ -26340,21 +30881,35 @@ "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; INSTALL_PATH = /usr/local/bin; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)/usr/lib/system", ); - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "-ObjC", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_MOBILEASSET)", + ); "OTHER_LDFLAGS[sdk=embedded]" = ( + "$(inherited)", "-framework", MobileKeyBag, "-laks", "-lACM", "-lImg4Decode", "-lz", - "-ObjC", "-lSystem", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-framework", + CrashReporterSupport, ); PRODUCT_NAME = secdtests; STRIP_STYLE = debugging; @@ -26365,10 +30920,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "sslViewer/sslViewer-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; @@ -26379,10 +30930,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "sslViewer/sslViewer-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; @@ -26393,10 +30940,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "sslViewer/sslViewer-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; @@ -26407,10 +30950,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "sslViewer/sslViewer-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; @@ -26451,6 +30990,104 @@ }; name = Release; }; + 225394B21E3080A600D3CD9B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = NO; + 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + "$(PROJECT_DIR)/header_symlinks/iOS/**", + "$(PROJECT_DIR)/OSX/sec/ProjectHeaders", + "$(PROJECT_DIR)/OSX/utilities", + "$(PROJECT_DIR)/OSX/sec/ipc", + "$(PROJECT_DIR)/OSX/sectask", + "$(PROJECT_DIR)/OSX/libsecurity_asn1", + "$(PROJECT_DIR)/OSX/libsecurity_ssl", + "$(PROJECT_DIR)/OSX/regressions", + "$(PROJECT_DIR)/OSX/ibsecurity_keychain/libDER", + "$(DSTROOT)/usr/local/include", + "${BUILT_PRODUCTS_DIR}/cstemp/**", + ); + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + WARNING_CFLAGS = ( + "-Wno-deprecated-declarations", + "-Wglobal-constructors", + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + "$(inherited)", + "-Wno-error=c++11-narrowing", + "-Wno-vla-extension", + ); + }; + name = Debug; + }; + 225394B31E3080A600D3CD9B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = NO; + 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + "$(PROJECT_DIR)/header_symlinks/iOS/**", + "$(PROJECT_DIR)/OSX/sec/ProjectHeaders", + "$(PROJECT_DIR)/OSX/utilities", + "$(PROJECT_DIR)/OSX/sec/ipc", + "$(PROJECT_DIR)/OSX/sectask", + "$(PROJECT_DIR)/OSX/libsecurity_asn1", + "$(PROJECT_DIR)/OSX/libsecurity_ssl", + "$(PROJECT_DIR)/OSX/regressions", + "$(PROJECT_DIR)/OSX/ibsecurity_keychain/libDER", + "$(DSTROOT)/usr/local/include", + "${BUILT_PRODUCTS_DIR}/cstemp/**", + ); + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + WARNING_CFLAGS = ( + "-Wno-deprecated-declarations", + "-Wglobal-constructors", + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + "$(inherited)", + "-Wno-error=c++11-narrowing", + "-Wno-vla-extension", + ); + }; + name = Release; + }; 438169101B4EDCBD00C54D58 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -26475,6 +31112,198 @@ }; name = Release; }; + 470415D31E5E14B6001F3D95 /* 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; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Debug; + }; + 470415D41E5E14B6001F3D95 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = 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 = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Release; + }; + 47702B231E5F409700B29577 /* 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/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; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Debug; + }; + 47702B241E5F409700B29577 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = 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; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Release; + }; + 47702B331E5F492C00B29577 /* 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/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; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Debug; + }; + 47702B341E5F492C00B29577 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = 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; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Release; + }; + 47C51B8C1EEA657D0032D9E5 /* 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 = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_STRICT_PROTOTYPES = NO; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_DYNAMIC_NO_PIC = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + INFOPLIST_FILE = SecurityUnitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.SecurityUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 47C51B8D1EEA657D0032D9E5 /* 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 = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_STRICT_PROTOTYPES = NO; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + ENABLE_NS_ASSERTIONS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + INFOPLIST_FILE = SecurityUnitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.SecurityUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; 4C52D0BE16EFC61E0079966E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -26490,10 +31319,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = CircleJoinRequested/entitlements.plist; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -26525,7 +31350,10 @@ "-fno-inline", "-DDEBUG", ); - OTHER_LDFLAGS = "$(APPLE_AKS_LIBRARY)"; + OTHER_LDFLAGS = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -26546,10 +31374,6 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = CircleJoinRequested/entitlements.plist; ENABLE_NS_ASSERTIONS = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_UNDECLARED_SELECTOR = YES; HEADER_SEARCH_PATHS = ( @@ -26568,7 +31392,10 @@ "$(SDKROOT)/System/Library/PrivateFrameworks/CloudServices/Headers", ); INSTALL_PATH = /System/Library/Frameworks/Security.framework/CircleJoinRequested/; - OTHER_LDFLAGS = "$(APPLE_AKS_LIBRARY)"; + OTHER_LDFLAGS = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + ); PRODUCT_NAME = "$(TARGET_NAME)"; VALIDATE_PRODUCT = YES; }; @@ -26612,6 +31439,10 @@ "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); HEADER_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/OSX/regressions", @@ -26621,7 +31452,14 @@ "$(inherited)", "\"$(SDKROOT)/usr/lib/system\"", ); - OTHER_LDFLAGS = "$(inherited)"; + OTHER_LDFLAGS = ( + "$(inherited)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", + ); "OTHER_LDFLAGS[sdk=embedded][arch=*]" = ( "$(inherited)", "-framework", @@ -26630,6 +31468,13 @@ "-lACM", "-lImg4Decode", "-lSystem", + "-lSecureKeyVaultForiapd", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", ); PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.${PRODUCT_NAME:identifier}"; PRODUCT_NAME = SecurityDevTests; @@ -26647,6 +31492,10 @@ "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); HEADER_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/OSX/regressions", @@ -26656,7 +31505,14 @@ "$(inherited)", "\"$(SDKROOT)/usr/lib/system\"", ); - OTHER_LDFLAGS = "$(inherited)"; + OTHER_LDFLAGS = ( + "$(inherited)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", + ); "OTHER_LDFLAGS[sdk=embedded]" = ( "$(inherited)", "-framework", @@ -26665,6 +31521,13 @@ "-lACM", "-lImg4Decode", "-lSystem", + "-lSecureKeyVaultForiapd", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", ); PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.${PRODUCT_NAME:identifier}"; PRODUCT_NAME = SecurityDevTests; @@ -26675,10 +31538,6 @@ 4C9DE9D41181AC4900CF5C27 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; OTHER_LDFLAGS = ( "-lsqlite3", @@ -26710,10 +31569,6 @@ 4C9DE9D51181AC4900CF5C27 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; "OTHER_LDFLAGS[sdk=embedded]" = ( "-lsqlite3", @@ -26755,6 +31610,7 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_UNINITIALIZED_AUTOS = YES; HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES = ""; HEADER_SEARCH_PATHS = ( @@ -26797,6 +31653,7 @@ 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 = ( "$(inherited)", @@ -26971,20 +31828,26 @@ ); INSTALL_PATH = /usr/local/bin; LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/local/lib"; - "OTHER_LDFLAGS[sdk=embedded*]" = ( - "-lMobileGestalt", - "-framework", - AggregateDictionary, - "-lz", + OTHER_LDFLAGS = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_MOBILEGESTALT)", + "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)", + "$(OTHER_LDFLAGS_APPLESYSTEMINFO)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_AGGREGATEDICTIONARY)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", ); "OTHER_LDFLAGS[sdk=embedded]" = ( "$(inherited)", - "-framework", - MobileKeyBag, - "-laks", "-lACM", "-lImg4Decode", "-lSystem", + "-framework", + CrashReporterSupport, ); PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -27002,25 +31865,437 @@ ); INSTALL_PATH = /usr/local/bin; LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/local/lib"; - "OTHER_LDFLAGS[sdk=embedded*]" = ( - "-lMobileGestalt", - "-framework", - AggregateDictionary, - "-lz", + OTHER_LDFLAGS = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_MOBILEGESTALT)", + "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)", + "$(OTHER_LDFLAGS_APPLESYSTEMINFO)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_AGGREGATEDICTIONARY)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", ); "OTHER_LDFLAGS[sdk=embedded]" = ( "$(inherited)", - "-framework", - MobileKeyBag, - "-laks", "-lACM", "-lImg4Decode", "-lSystem", + "-framework", + CrashReporterSupport, ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; + 6C98085F1E788AEB00E70590 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "NO_SERVER=1", + "NO_LIBTRUSTD=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + INFOPLIST_FILE = keychain/ckks/tests/CKKSCloudKitTestsInfo.plist; + INSTALL_PATH = /AppleInternal/XCTests/com.apple.security; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=iphoneos*]" = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-framework", + CrashReporterSupport, + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSCloudKitTests; + PRODUCT_NAME = CKKSCloudKitTests; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeychainEntitledTestApp_mac.app/Contents/MacOS/KeychainEntitledTestApp_mac"; + }; + name = Debug; + }; + 6C9808601E788AEB00E70590 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "NO_SERVER=1", + "NO_LIBTRUSTD=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + INFOPLIST_FILE = keychain/ckks/tests/CKKSCloudKitTestsInfo.plist; + INSTALL_PATH = /AppleInternal/XCTests/com.apple.security; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=iphoneos*]" = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-framework", + CrashReporterSupport, + ); + 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; + }; + name = Release; + }; + 6C98089B1E788AFD00E70590 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "NO_SERVER=1", + "NO_LIBTRUSTD=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + INFOPLIST_FILE = keychain/ckks/tests/CKKSCloudKitTestsInfo.plist; + INSTALL_PATH = /AppleInternal/XCTests/com.apple.security; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=iphoneos*]" = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-framework", + CrashReporterSupport, + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSCloudKitTests; + PRODUCT_NAME = CKKSCloudKitTests; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeychainEntitledTestApp_ios.app/KeychainEntitledTestApp_ios"; + }; + name = Debug; + }; + 6C98089C1E788AFD00E70590 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "NO_SERVER=1", + "NO_LIBTRUSTD=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + INFOPLIST_FILE = keychain/ckks/tests/CKKSCloudKitTestsInfo.plist; + INSTALL_PATH = /AppleInternal/XCTests/com.apple.security; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=iphoneos*]" = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-framework", + CrashReporterSupport, + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSCloudKitTests; + PRODUCT_NAME = CKKSCloudKitTests; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeychainEntitledTestApp_ios.app/KeychainEntitledTestApp_ios"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 6CCDF7891E3C25FB003F2555 /* 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 = "$(SRCROOT)/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist"; + DEBUG_INFORMATION_FORMAT = dwarf; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/../../Library/Frameworks", + "$(SDKROOT)/../../AppleInternal/Library/Frameworks", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + 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"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Debug; + }; + 6CCDF78A1E3C25FB003F2555 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist"; + COPY_PHASE_STRIP = NO; + ENABLE_NS_ASSERTIONS = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/../../Library/Frameworks", + "$(SDKROOT)/../../AppleInternal/Library/Frameworks", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + 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"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Release; + }; + 6CF4A0C51E45488B00ECD7B5 /* 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"; + 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; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_CODE_SIGN_FLAGS = "--deep"; + PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.KeychainEntitledTestApp-mac"; + PRODUCT_NAME = KeychainEntitledTestApp; + }; + name = Debug; + }; + 6CF4A0C61E45488B00ECD7B5 /* 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"; + 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; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CODE_SIGN_FLAGS = "--deep"; + PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.KeychainEntitledTestApp-mac"; + 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"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; + 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"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; + 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; + }; 728B56AC16D59979008FA3AB /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 22C002A31AC9D33100B3469E /* OTAPKIAssetTool.xcconfig */; @@ -27037,10 +32312,6 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "$(PROJECT_DIR)/OTAPKIAssetTool/OTAPKIAssetTool-entitlements.plist"; CODE_SIGN_IDENTITY = "-"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -27080,10 +32351,6 @@ CODE_SIGN_ENTITLEMENTS = "$(PROJECT_DIR)/OTAPKIAssetTool/OTAPKIAssetTool-entitlements.plist"; CODE_SIGN_IDENTITY = "-"; ENABLE_NS_ASSERTIONS = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; INSTALL_PATH = /usr/libexec; @@ -27103,10 +32370,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "sslViewer/sslServer-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; OTHER_LDFLAGS = ( "-lsqlite3", @@ -27121,7 +32384,6 @@ IOKit, "-framework", MobileKeyBag, - "-lcorecrypto$(Sim_Name)", "-laks", "-lACM", ); @@ -27133,10 +32395,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "sslViewer/sslServer-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; OTHER_LDFLAGS = ""; "OTHER_LDFLAGS[sdk=embedded]" = ( @@ -27147,7 +32405,6 @@ IOKit, "-framework", MobileKeyBag, - "-lcorecrypto$(Sim_Name)", "-laks", "-lACM", ); @@ -27176,13 +32433,10 @@ MODULEMAP_FILE = Modules/Security.iOS.modulemap; OTHER_LDFLAGS = ( "-laks", - "-Wl,-upward-lcoretls", - "-Wl,-upward-lcoretls_cfhelpers", - ); - "OTHER_LDFLAGS[sdk=*simulator*]" = ( - "-Wl,-upward-lcoretls", - "-Wl,-upward-lcoretls_cfhelpers", + "-Wl,-upward_framework,Foundation", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", ); + "OTHER_LDFLAGS[sdk=*simulator*]" = "-Wl,-upward_framework,Foundation"; PRODUCT_BUNDLE_IDENTIFIER = "com.apple.${EXECUTABLE_NAME}"; PRODUCT_NAME = Security; STRIP_STYLE = debugging; @@ -27207,13 +32461,10 @@ MODULEMAP_FILE = Modules/Security.iOS.modulemap; OTHER_LDFLAGS = ( "-laks", - "-Wl,-upward-lcoretls", - "-Wl,-upward-lcoretls_cfhelpers", - ); - "OTHER_LDFLAGS[sdk=*simulator*]" = ( - "-Wl,-upward-lcoretls", - "-Wl,-upward-lcoretls_cfhelpers", + "-Wl,-upward_framework,Foundation", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", ); + "OTHER_LDFLAGS[sdk=*simulator*]" = "-Wl,-upward_framework,Foundation"; PRODUCT_BUNDLE_IDENTIFIER = "com.apple.${EXECUTABLE_NAME}"; PRODUCT_NAME = Security; STRIP_STYLE = debugging; @@ -27227,16 +32478,18 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = SecurityTool/entitlements.plist; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; "INSTALL_PATH[sdk=macosx*]" = /usr/bin; OTHER_LDFLAGS = ( "-lsqlite3", "-framework", CFNetwork, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", ); "OTHER_LDFLAGS[sdk=embedded][arch=*]" = ( "-lsqlite3", @@ -27248,6 +32501,12 @@ MobileKeyBag, "-laks", "-lACM", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", ); PRODUCT_NAME = security; STRIP_STYLE = debugging; @@ -27259,13 +32518,8 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = SecurityTool/entitlements.plist; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); INSTALL_PATH = /usr/local/bin; "INSTALL_PATH[sdk=macosx*]" = /usr/bin; - OTHER_LDFLAGS = ""; "OTHER_LDFLAGS[sdk=embedded]" = ( "-lsqlite3", "-framework", @@ -27276,11 +32530,23 @@ MobileKeyBag, "-laks", "-lACM", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", ); "OTHER_LDFLAGS[sdk=embeddedsimulator*][arch=*]" = ( "-lsqlite3", "-framework", CFNetwork, + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", ); PRODUCT_NAME = security; STRIP_STYLE = debugging; @@ -27291,14 +32557,11 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "sslViewer/sslViewer-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "SEC_IOS_ON_OSX=1", ); + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = sslViewer; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; @@ -27309,14 +32572,11 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "sslViewer/sslViewer-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "SEC_IOS_ON_OSX=1", ); + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = sslViewer; SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; @@ -27326,52 +32586,110 @@ 792EFFE20CBBF878007C00A0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "SECD_SERVER=1", + "$(inherited)", + ); GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INSTALL_PATH = /usr/libexec; LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/local/lib"; - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", + ); "OTHER_LDFLAGS[sdk=embedded][arch=*]" = ( "$(OTHER_LDFLAGS)", "-framework", MobileKeyBag, "-laks", "-lACM", - "-lImg4Decode", + "-ObjC", "-lSystem", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "-framework", + CrashReporterSupport, + ); + "OTHER_LDFLAGS[sdk=iphonesimulator*]" = ( + "$(inherited)", + "-ObjC", ); PRODUCT_NAME = securityd; STRIP_STYLE = debugging; + USE_HEADERMAP = NO; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-error=modules-ambiguous-internal-linkage", + ); }; name = Debug; }; 792EFFE30CBBF878007C00A0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "SECD_SERVER=1", + "$(inherited)", + ); GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INSTALL_PATH = /usr/libexec; LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/local/lib"; - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", + ); "OTHER_LDFLAGS[sdk=embedded][arch=*]" = ( "$(OTHER_LDFLAGS)", "-framework", MobileKeyBag, "-laks", "-lACM", - "-lImg4Decode", "-lSystem", + "-ObjC", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "-framework", + CrashReporterSupport, + ); + "OTHER_LDFLAGS[sdk=iphonesimulator*]" = ( + "$(inherited)", + "-ObjC", ); PRODUCT_NAME = securityd; STRIP_STYLE = debugging; + USE_HEADERMAP = NO; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-error=modules-ambiguous-internal-linkage", + ); }; name = Release; }; @@ -27401,13 +32719,17 @@ CLANG_STATIC_ANALYZER_MODE = shallow; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; + CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; @@ -27446,10 +32768,7 @@ INSTALL_DAEMON_AGENT_DIR = "$(SYSTEM_LIBRARY_DIR)/LaunchDaemons"; "INSTALL_DAEMON_AGENT_DIR[sdk=macosx*]" = "$(SYSTEM_LIBRARY_DIR)/LaunchAgents"; ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ( - "-fconstant-cfstrings", - "-fno-inline", - ); + OTHER_LDFLAGS = ""; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = macosx.internal; SECURITY_FRAMEWORK_RESOURCES_DIR = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/"; @@ -27459,15 +32778,6 @@ Sim_Name = ""; "Sim_Name[sdk=embeddedsimulator*][arch=*]" = _sim; TARGETED_DEVICE_FAMILY = "1,2"; - WARNING_CFLAGS = ( - "-Wall", - "-Wextra", - "-Wno-unused-parameter", - "-Wno-missing-field-initializers", - "-Wno-error=deprecated-declarations", - "-Wno-error=implicit-retain-self", - "-Wno-error=#warnings", - ); }; name = Debug; }; @@ -27483,13 +32793,17 @@ CLANG_STATIC_ANALYZER_MODE = shallow; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; + CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = YES; @@ -27504,7 +32818,7 @@ "$(inherited)", ); GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; @@ -27526,7 +32840,7 @@ 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"; - OTHER_CFLAGS = "-fconstant-cfstrings"; + OTHER_LDFLAGS = ""; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = macosx.internal; SECURITY_FRAMEWORK_RESOURCES_DIR = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/"; @@ -27535,15 +32849,44 @@ Sim_Name = ""; "Sim_Name[sdk=embeddedsimulator*][arch=*]" = _sim; TARGETED_DEVICE_FAMILY = "1,2"; - WARNING_CFLAGS = ( - "-Wall", - "-Wextra", - "-Wno-unused-parameter", - "-Wno-missing-field-initializers", - "-Wno-error=deprecated-declarations", - "-Wno-error=implicit-retain-self", - "-Wno-error=#warnings", + }; + name = Release; + }; + ACBAF6DB1E9417F40007BA2F /* Debug */ = { + isa = XCBuildConfiguration; + 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)", ); + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = NO; + }; + name = Debug; + }; + ACBAF6DC1E9417F40007BA2F /* Release */ = { + isa = XCBuildConfiguration; + 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)", + ); + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = NO; }; name = Release; }; @@ -27570,10 +32913,6 @@ CODE_SIGN_ENTITLEMENTS = "$(TARGET_NAME)/entitlements.plist"; "CODE_SIGN_IDENTITY[sdk=embedded*]" = "-"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -27621,10 +32960,6 @@ "CODE_SIGN_IDENTITY[sdk=embedded*]" = "-"; COMBINE_HIDPI_IMAGES = YES; ENABLE_NS_ASSERTIONS = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "$(TARGET_NAME)/$(TARGET_NAME)-Prefix.pch"; @@ -27645,10 +32980,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "OSX/sec/SharedWebCredential/swcagent-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/"; OTHER_LDFLAGS = ""; @@ -27665,10 +32996,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = "OSX/sec/SharedWebCredential/swcagent-entitlements.plist"; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/"; OTHER_LDFLAGS = ""; @@ -27681,6 +33008,149 @@ }; name = Release; }; + BED208DB1EDF950E00753952 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_ENTITLEMENTS = RegressionTests/manifeststresstest/manifeststresstest.entitlements; + INSTALL_PATH = /AppleInternal/CoreOS/tests/Security; + OTHER_LDFLAGS = ( + "-framework", + Security, + ); + "OTHER_LDFLAGS[sdk=embedded]" = ( + "-laks", + "-framework", + Security, + "-framework", + IOKit, + ); + "OTHER_LDFLAGS[sdk=macosx*]" = ( + "-laks", + "-framework", + Security, + "-framework", + IOKit, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + }; + name = Debug; + }; + BED208DC1EDF950E00753952 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_ENTITLEMENTS = RegressionTests/manifeststresstest/manifeststresstest.entitlements; + INSTALL_PATH = /AppleInternal/CoreOS/tests/Security; + OTHER_LDFLAGS = ( + "-framework", + Security, + ); + "OTHER_LDFLAGS[sdk=embedded]" = ( + "-laks", + "-framework", + Security, + "-framework", + IOKit, + ); + "OTHER_LDFLAGS[sdk=macosx*]" = ( + "-laks", + "-framework", + Security, + "-framework", + IOKit, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BEF88C391EAFFC4000357577 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BE8351D41EC0EEDD00ACD5FD /* framework_requiring_modern_objc_runtime.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + INFOPLIST_FILE = keychain/trust/TrustedPeers/Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = ( + "-laks", + "-Wl,-upward_framework,Foundation", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + ); + "OTHER_LDFLAGS[sdk=*simulator*]" = "-Wl,-upward_framework,Foundation"; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustedPeers; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + BEF88C3A1EAFFC4000357577 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BE8351D41EC0EEDD00ACD5FD /* framework_requiring_modern_objc_runtime.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + INFOPLIST_FILE = keychain/trust/TrustedPeers/Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + OTHER_LDFLAGS = ( + "-laks", + "-Wl,-upward_framework,Foundation", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + ); + "OTHER_LDFLAGS[sdk=*simulator*]" = "-Wl,-upward_framework,Foundation"; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustedPeers; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + BEF88C3B1EAFFC4000357577 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = keychain/trust/TrustedPeersTests/Info.plist; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustedPeersTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + VALID_ARCHS = "armv6 armv7 arm64 x86_64 x86_64h"; + }; + name = Debug; + }; + BEF88C3C1EAFFC4000357577 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = keychain/trust/TrustedPeersTests/Info.plist; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustedPeersTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + VALID_ARCHS = "armv6 armv7 arm64 x86_64 x86_64h"; + }; + name = Release; + }; CD276C2D1A83F60C003226BC /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */; @@ -27701,6 +33171,7 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_UNINITIALIZED_AUTOS = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -27742,6 +33213,7 @@ COPY_PHASE_STRIP = NO; "DEBUG_INFORMATION_FORMAT[sdk=macosx*]" = "dwarf-with-dsym"; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; HEADER_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/OSX/sec/SOSCircle/CKBridge", @@ -27763,6 +33235,51 @@ }; name = Release; }; + D41257D71E9410A300781F23 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_ENTITLEMENTS = OSX/trustd/iOS/entitlements.plist; + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); + INSTALL_PATH = /usr/libexec; + LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/local/lib"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = "$(OTHER_LDFLAGS_MOBILEASSET)"; + "OTHER_LDFLAGS[sdk=embedded]" = ( + "$(inherited)", + "-lImg4Decode", + ); + PRODUCT_NAME = trustd; + STRIP_STYLE = debugging; + }; + name = Debug; + }; + D41257D81E9410A300781F23 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CODE_SIGN_ENTITLEMENTS = OSX/trustd/iOS/entitlements.plist; + ENABLE_NS_ASSERTIONS = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); + INSTALL_PATH = /usr/libexec; + LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/local/lib"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = "$(OTHER_LDFLAGS_MOBILEASSET)"; + "OTHER_LDFLAGS[sdk=embedded]" = ( + "$(inherited)", + "-lImg4Decode", + ); + PRODUCT_NAME = trustd; + STRIP_STYLE = debugging; + }; + name = Release; + }; D41AD42F1B967169008C7270 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -27791,6 +33308,70 @@ }; name = Release; }; + D4ADA31B1E2B41670031CEA3 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + EXECUTABLE_PREFIX = ""; + "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*]" = ( + "$(inherited)", + "SECITEM_SHIM_OSX=1", + "SEC_IOS_ON_OSX=1", + "TRUSTD_SERVER=1", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = "-ObjC"; + }; + name = Debug; + }; + D4ADA31C1E2B41670031CEA3 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + EXECUTABLE_PREFIX = ""; + "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*]" = ( + "$(inherited)", + "TRUSTD_SERVER=1", + "SECITEM_SHIM_OSX=1", + "SEC_IOS_ON_OSX=1", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = "-ObjC"; + }; + name = Release; + }; + DA30D6791DF8C8FB00EC6B43 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = KeychainSyncAccountUpdater/Info.plist; + INSTALL_PATH = /System/Library/CoreServices/UAUPlugins; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.KeychainSyncAccountUpdater; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + DA30D67A1DF8C8FB00EC6B43 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = KeychainSyncAccountUpdater/Info.plist; + INSTALL_PATH = /System/Library/CoreServices/UAUPlugins; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.KeychainSyncAccountUpdater; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; DC0067BE1D87876F005AF8DB /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */; @@ -27926,6 +33507,7 @@ DC0BC56A1D8B6E3D00070CB0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = NO; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; @@ -27936,6 +33518,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_SHADOW = NO; @@ -27946,12 +33529,14 @@ MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.XPCTimeStampingService; PRODUCT_NAME = "$(TARGET_NAME)"; + VALID_ARCHS = "x86_64 x86_64h"; }; name = Debug; }; DC0BC56B1D8B6E3D00070CB0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = NO; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; @@ -27961,6 +33546,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_SHADOW = NO; @@ -27971,6 +33557,7 @@ MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.XPCTimeStampingService; PRODUCT_NAME = "$(TARGET_NAME)"; + VALID_ARCHS = "x86_64 x86_64h"; }; name = Release; }; @@ -28368,6 +33955,11 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/OSX/libsecurity_ssl", + "$(PROJECT_DIR)/header_symlinks/", + "$(inherited)", + ); MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -28389,6 +33981,11 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/OSX/libsecurity_ssl", + "$(PROJECT_DIR)/header_symlinks/", + "$(inherited)", + ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -28446,6 +34043,7 @@ 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 = ( @@ -28454,6 +34052,7 @@ ); MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = NO; }; name = Debug; }; @@ -28463,6 +34062,7 @@ 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 = ( @@ -28471,6 +34071,7 @@ ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = NO; }; name = Release; }; @@ -28502,7 +34103,7 @@ }; DC0BCBFB1D8C648C00070CB0 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -28515,10 +34116,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -28531,7 +34128,7 @@ }; DC0BCBFC1D8C648C00070CB0 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -28544,10 +34141,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -28574,20 +34167,13 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_SHADOW = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = NO; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders", - ); MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -28614,20 +34200,13 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_SHADOW = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = NO; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders", - ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -28653,10 +34232,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -28687,10 +34262,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -28747,10 +34318,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = Security; - SDKROOT = macosx; + SDKROOT = macosx.internal; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -28793,10 +34363,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = Security; - SDKROOT = macosx; + SDKROOT = macosx.internal; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -28829,6 +34398,12 @@ GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ( + "-laks", + "-lCrashReporterClient", + "-Wl,-upward_framework,Foundation", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + ); VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -28860,38 +34435,137 @@ GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ( + "-laks", + "-lCrashReporterClient", + "-Wl,-upward_framework,Foundation", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + ); VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; - DC3A4B5C1D91E9FB00E46D4A /* Debug */ = { + DC222C751E034D1F00B09171 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; + 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_DOCUMENTATION_COMMENTS = YES; + 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; + EXECUTABLE_PREFIX = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "USE_KEYSTORE=0", + "$(inherited)", + ); + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + DC222C761E034D1F00B09171 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + 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_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + EXECUTABLE_PREFIX = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "USE_KEYSTORE=0", + "$(inherited)", + ); + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + DC3502BB1E0208BE00BC0587 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/../../AppleInternal/Library/Frameworks", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "NO_SERVER=1", + "$(inherited)", + ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; - GCC_WARN_UNDECLARED_SELECTOR = YES; - INFOPLIST_FILE = "OSX/libsecurity_codesigning/CodeSigningHelper/CodeSigningHelper-Info.plist"; - INSTALL_PATH = /System/Library/Frameworks/Security.framework/Versions/A/XPCServices; - MACH_O_TYPE = mh_execute; + INFOPLIST_FILE = keychain/ckks/tests/Info.plist; + INSTALL_PATH = /AppleInternal/XCTests/com.apple.security/; + 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; - PRODUCT_BUNDLE_IDENTIFIER = com.apple.CodeSigningHelper; - PRODUCT_NAME = "com.apple.$(TARGET_NAME:rfc1034identifier)"; - SKIP_INSTALL = NO; - WRAPPER_EXTENSION = xpc; + OTHER_LDFLAGS = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-ObjC", + ); + "OTHER_LDFLAGS[sdk=iphoneos*]" = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-ObjC", + "-framework", + CrashReporterSupport, + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSTests; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; - DC3A4B5D1D91E9FB00E46D4A /* Release */ = { + DC3502BC1E0208BE00BC0587 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -28899,76 +34573,121 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/../../AppleInternal/Library/Frameworks", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "NO_SERVER=1", + "$(inherited)", + ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; - GCC_WARN_UNDECLARED_SELECTOR = YES; - INFOPLIST_FILE = "OSX/libsecurity_codesigning/CodeSigningHelper/CodeSigningHelper-Info.plist"; - INSTALL_PATH = /System/Library/Frameworks/Security.framework/Versions/A/XPCServices; - MACH_O_TYPE = mh_execute; + INFOPLIST_FILE = keychain/ckks/tests/Info.plist; + INSTALL_PATH = /AppleInternal/XCTests/com.apple.security/; + 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 = NO; - PRODUCT_BUNDLE_IDENTIFIER = com.apple.CodeSigningHelper; - PRODUCT_NAME = "com.apple.$(TARGET_NAME:rfc1034identifier)"; - SKIP_INSTALL = NO; - WRAPPER_EXTENSION = xpc; + OTHER_LDFLAGS = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-ObjC", + ); + "OTHER_LDFLAGS[sdk=iphoneos*]" = ( + "$(APPLE_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_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "-ObjC", + "-framework", + CrashReporterSupport, + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + VALIDATE_PRODUCT = YES; }; name = Release; }; - DC52E7C01D80BC8000B0A59C /* Debug */ = { + DC3A4B5C1D91E9FB00E46D4A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_debug_shim.xcconfig */; buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - EXECUTABLE_PREFIX = ""; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "OSX/libsecurity_codesigning/CodeSigningHelper/CodeSigningHelper-Info.plist"; + INSTALL_PATH = /System/Library/Frameworks/Security.framework/Versions/A/XPCServices; + MACH_O_TYPE = mh_execute; MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.CodeSigningHelper; + PRODUCT_NAME = "com.apple.$(TARGET_NAME:rfc1034identifier)"; + SKIP_INSTALL = NO; + WRAPPER_EXTENSION = xpc; }; name = Debug; }; - DC52E7C11D80BC8000B0A59C /* Release */ = { + DC3A4B5D1D91E9FB00E46D4A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56B01DCA843800E18518 /* lib_ios_x64_release_shim.xcconfig */; buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - EXECUTABLE_PREFIX = ""; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "OSX/libsecurity_codesigning/CodeSigningHelper/CodeSigningHelper-Info.plist"; + INSTALL_PATH = /System/Library/Frameworks/Security.framework/Versions/A/XPCServices; + MACH_O_TYPE = mh_execute; MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.apple.CodeSigningHelper; + PRODUCT_NAME = "com.apple.$(TARGET_NAME:rfc1034identifier)"; + SKIP_INSTALL = NO; + WRAPPER_EXTENSION = xpc; }; name = Release; }; - DC52E8B81D80C1EB00B0A59C /* Debug */ = { + DC52E7C01D80BC8000B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DC71D8DD1D94CF3C0065FB93 /* lib_ios_debug_shim.xcconfig */; + baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; @@ -28979,6 +34698,8 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + EXECUTABLE_PREFIX = ""; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -28986,11 +34707,12 @@ }; name = Debug; }; - DC52E8B91D80C1EB00B0A59C /* Release */ = { + DC52E7C11D80BC8000B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DC71D8DE1D94CF6A0065FB93 /* lib_ios_release_shim.xcconfig */; + baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; @@ -29001,6 +34723,8 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + EXECUTABLE_PREFIX = ""; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29010,7 +34734,7 @@ }; DC52E8C41D80C25800B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DCC78EA31D80870D00865A7C /* lib_ios_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -29024,6 +34748,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29033,7 +34758,7 @@ }; DC52E8C51D80C25800B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DCC78EA41D80870D00865A7C /* lib_ios_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -29056,7 +34781,7 @@ }; DC52EA4A1D80CB7000B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29078,7 +34803,7 @@ }; DC52EA4B1D80CB7000B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29100,7 +34825,7 @@ }; DC52EBD31D80CEF100B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29122,7 +34847,7 @@ }; DC52EBD41D80CEF100B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29144,7 +34869,7 @@ }; DC52EC321D80CFB200B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29166,7 +34891,7 @@ }; DC52EC331D80CFB200B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29188,7 +34913,7 @@ }; DC52EC4B1D80D00800B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_debug_shim.xcconfig */; + baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29211,7 +34936,7 @@ }; DC52EC4C1D80D00800B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56B01DCA843800E18518 /* lib_ios_x64_release_shim.xcconfig */; + baseConfigurationReference = D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29234,7 +34959,7 @@ }; DC52EC5A1D80D05200B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DCC78EA31D80870D00865A7C /* lib_ios_debug.xcconfig */; + baseConfigurationReference = DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -29257,7 +34982,7 @@ }; DC52EC5B1D80D05200B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DCC78EA41D80870D00865A7C /* lib_ios_release.xcconfig */; + baseConfigurationReference = DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -29280,7 +35005,7 @@ }; DC52EC661D80D0C400B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29293,10 +35018,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29306,7 +35027,7 @@ }; DC52EC671D80D0C400B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29319,10 +35040,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29332,7 +35049,7 @@ }; DC52EC951D80D1A800B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29345,10 +35062,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29358,7 +35071,7 @@ }; DC52EC961D80D1A800B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29371,10 +35084,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29384,7 +35093,7 @@ }; DC52ED9B1D80D4CD00B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29397,10 +35106,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29410,7 +35115,7 @@ }; DC52ED9C1D80D4CD00B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29423,10 +35128,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29436,7 +35137,7 @@ }; DC52EDAF1D80D58400B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -29450,10 +35151,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29463,7 +35160,7 @@ }; DC52EDB01D80D58400B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -29477,10 +35174,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29490,7 +35183,7 @@ }; DC52EE3F1D80D6DD00B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AC1DCA835200E18518 /* lib_ios_x64_debug.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -29504,10 +35197,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29517,7 +35206,7 @@ }; DC52EE401D80D6DD00B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D47C56AE1DCA839400E18518 /* lib_ios_x64_release.xcconfig */; + baseConfigurationReference = D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -29531,10 +35220,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; @@ -29544,7 +35229,7 @@ }; DC52EE6C1D80D82600B0A59C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DC71D8DD1D94CF3C0065FB93 /* lib_ios_debug_shim.xcconfig */; + baseConfigurationReference = DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29566,7 +35251,7 @@ }; DC52EE6D1D80D82600B0A59C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DC71D8DE1D94CF6A0065FB93 /* lib_ios_release_shim.xcconfig */; + baseConfigurationReference = DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -29848,10 +35533,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; @@ -29867,6 +35548,7 @@ INSTALL_PATH = /usr/bin; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = security; + RUN_CLANG_STATIC_ANALYZER = NO; SUPPORTED_PLATFORMS = macosx; USE_HEADERMAP = NO; }; @@ -29889,10 +35571,6 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -29907,6 +35585,7 @@ INSTALL_PATH = /usr/bin; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = security; + RUN_CLANG_STATIC_ANALYZER = NO; SUPPORTED_PLATFORMS = macosx; USE_HEADERMAP = NO; }; @@ -29937,8 +35616,8 @@ HEADER_SEARCH_PATHS = ( "$(PROJECT_DIR)/header_symlinks/macOS/", "$(PROJECT_DIR)/securityd/", + "$(PROJECT_DIR)/OSX/include/", "$(inherited)", - "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders", ); INSTALL_PATH = /usr/sbin; MTL_ENABLE_DEBUG_INFO = YES; @@ -29977,8 +35656,8 @@ HEADER_SEARCH_PATHS = ( "$(PROJECT_DIR)/header_symlinks/macOS/", "$(PROJECT_DIR)/securityd/", + "$(PROJECT_DIR)/OSX/include/", "$(inherited)", - "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders", ); INSTALL_PATH = /usr/sbin; MTL_ENABLE_DEBUG_INFO = NO; @@ -30079,6 +35758,11 @@ "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; INSTALL_PATH = /usr/local/bin; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -30087,6 +35771,7 @@ OTHER_LDFLAGS = ( "$(APPLE_AKS_LIBRARY)", "-ObjC", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", ); "OTHER_LDFLAGS[sdk=embedded]" = ( "-lACM", @@ -30107,6 +35792,11 @@ "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; INSTALL_PATH = /usr/local/bin; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -30115,6 +35805,7 @@ OTHER_LDFLAGS = ( "$(APPLE_AKS_LIBRARY)", "-ObjC", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", ); "OTHER_LDFLAGS[sdk=embedded]" = ( "-lACM", @@ -30149,6 +35840,7 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INSTALL_PATH = /AppleInternal/CoreOS/codesign_tests/; @@ -30181,6 +35873,7 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INSTALL_PATH = /AppleInternal/CoreOS/codesign_tests/; @@ -30407,11 +36100,16 @@ baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_SHADOW = NO; + "HEADER_SEARCH_PATHS[sdk=embedded*]" = ( + "$(PROJECT_DIR)/header_symlinks/iOS", + "$(inherited)", + ); MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/security_asn1; @@ -30423,11 +36121,16 @@ baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_SHADOW = NO; + "HEADER_SEARCH_PATHS[sdk=embedded*]" = ( + "$(PROJECT_DIR)/header_symlinks/iOS", + "$(inherited)", + ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/security_asn1; @@ -30441,10 +36144,13 @@ CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; + DEFINES_MODULE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GENERATE_TEXT_BASED_STUBS = NO; INLINE_PRIVATE_FRAMEWORKS = NO; + MODULEMAP_FILE = OSX/libsecurity_keychain/libDER/libDER/module.modulemap; MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_MODULE_NAME = libDER; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/security_libDER/libDER; SKIP_INSTALL = YES; @@ -30460,10 +36166,13 @@ CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; + DEFINES_MODULE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GENERATE_TEXT_BASED_STUBS = NO; INLINE_PRIVATE_FRAMEWORKS = NO; + MODULEMAP_FILE = OSX/libsecurity_keychain/libDER/libDER/module.modulemap; MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_MODULE_NAME = libDER; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/security_libDER/libDER; SKIP_INSTALL = YES; @@ -30509,11 +36218,16 @@ baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_SHADOW = NO; + "HEADER_SEARCH_PATHS[sdk=embedded*]" = ( + "$(PROJECT_DIR)/header_symlinks/iOS", + "$(inherited)", + ); MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/security_asn1; @@ -30526,11 +36240,16 @@ baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_SHADOW = NO; + "HEADER_SEARCH_PATHS[sdk=embedded*]" = ( + "$(PROJECT_DIR)/header_symlinks/iOS", + "$(inherited)", + ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/security_asn1; @@ -31414,7 +37133,7 @@ }; DCC78EB01D8088E200865A7C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DCC78EA31D80870D00865A7C /* lib_ios_debug.xcconfig */; + baseConfigurationReference = DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -31437,7 +37156,7 @@ }; DCC78EB11D8088E200865A7C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DCC78EA41D80870D00865A7C /* lib_ios_release.xcconfig */; + baseConfigurationReference = DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -31505,7 +37224,6 @@ OSX/libsecurity_codesigning/antlr2/, "$(BUILT_PRODUCTS_DIR)/derived_src", "$(BUILT_PRODUCTS_DIR)/cstemp/", - "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders", ); MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -31532,7 +37250,6 @@ OSX/libsecurity_codesigning/antlr2/, "$(BUILT_PRODUCTS_DIR)/derived_src", "$(BUILT_PRODUCTS_DIR)/cstemp/", - "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders", ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -31699,10 +37416,7 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_IDENTITY = ""; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; HEADER_SEARCH_PATHS = ( "$(PROJECT_DIR)/OSX/include/", "$(inherited)", @@ -31734,10 +37448,7 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_IDENTITY = ""; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; HEADER_SEARCH_PATHS = ( "$(PROJECT_DIR)/OSX/include/", "$(inherited)", @@ -31785,14 +37496,32 @@ isa = XCBuildConfiguration; baseConfigurationReference = DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */; buildSettings = { + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_32_64_BIT)"; CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/OSX/libsecurity_cssm/lib/", + "$(PROJECT_DIR)/header_symlinks/**", + "$(PROJECT_DIR)/OSX/include/", + "$(inherited)", + "$(PROJECT_DIR)", + "$(PROJECT_DIR)/OSX/libsecurity_apple_csp/open_ssl", + "${BUILT_PRODUCTS_DIR}/derived_src/**", + "$(PROJECT_DIR)/OSX/lib$(PRODUCT_NAME)/lib/", + ); MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = NO; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos watchos macosx appletvos appletvsimulator watchsimulator"; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-sign-compare", + "-Wno-deprecated-register", + "-Wno-vla-extension", + ); }; name = Debug; }; @@ -31800,20 +37529,38 @@ isa = XCBuildConfiguration; baseConfigurationReference = DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */; buildSettings = { + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_32_64_BIT)"; CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/OSX/libsecurity_cssm/lib/", + "$(PROJECT_DIR)/header_symlinks/**", + "$(PROJECT_DIR)/OSX/include/", + "$(inherited)", + "$(PROJECT_DIR)", + "$(PROJECT_DIR)/OSX/libsecurity_apple_csp/open_ssl", + "$(PROJECT_DIR)/OSX/lib$(PRODUCT_NAME)/lib/", + "${BUILT_PRODUCTS_DIR}/derived_src/**", + ); MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = NO; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos watchos macosx appletvos appletvsimulator watchsimulator"; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-sign-compare", + "-Wno-deprecated-register", + "-Wno-vla-extension", + ); }; name = Release; }; DCD66D711D8204A700DB1393 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DC71D8DD1D94CF3C0065FB93 /* lib_ios_debug_shim.xcconfig */; + baseConfigurationReference = DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -31835,7 +37582,7 @@ }; DCD66D721D8204A700DB1393 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DC71D8DE1D94CF6A0065FB93 /* lib_ios_release_shim.xcconfig */; + baseConfigurationReference = DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -31857,7 +37604,7 @@ }; DCD66DD91D8205C400DB1393 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DCC78EA31D80870D00865A7C /* lib_ios_debug.xcconfig */; + baseConfigurationReference = DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -31879,7 +37626,7 @@ }; DCD66DDA1D8205C400DB1393 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DCC78EA41D80870D00865A7C /* lib_ios_release.xcconfig */; + baseConfigurationReference = DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -31899,14 +37646,65 @@ }; name = Release; }; + DCD8A1971E09EE0F00E4FA0A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + 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_DOCUMENTATION_COMMENTS = YES; + 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; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + DCD8A1981E09EE0F00E4FA0A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + 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_DOCUMENTATION_COMMENTS = YES; + 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; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; DCE4E6A21D7A37FA00AFB96E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = OSX/sec/SecurityTool/entitlements.plist; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", ); PRODUCT_NAME = security2; SUPPORTED_PLATFORMS = macosx; @@ -31918,9 +37716,11 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = OSX/sec/SecurityTool/entitlements.plist; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", ); PRODUCT_NAME = security2; SUPPORTED_PLATFORMS = macosx; @@ -31934,10 +37734,6 @@ CODE_SIGN_ENTITLEMENTS = "OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = OSX/SecurityTestsOSX/Info.plist; INSTALL_PATH = /AppleInternal/CoreOS/tests/Security/; @@ -31969,10 +37765,6 @@ CODE_SIGN_ENTITLEMENTS = "OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist"; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = OSX/SecurityTestsOSX/Info.plist; INSTALL_PATH = /AppleInternal/CoreOS/tests/Security/; @@ -32017,12 +37809,6 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = "OSX/sectests/SecurityTests-Entitlements.plist"; ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - "$(DEVELOPER_LIBRARY_DIR)", - /usr/lib/system, - ); GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -32056,12 +37842,6 @@ COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - "$(DEVELOPER_LIBRARY_DIR)", - /usr/lib/system, - ); GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -32092,6 +37872,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CREATE_INFOPLIST_SECTION_IN_BINARY = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -32099,14 +37880,28 @@ ); GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "SECD_SERVER=1", + "$(inherited)", + ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "OSX/sec/securityd/Info-macOS.plist"; INSTALL_PATH = /usr/libexec; - MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; - OTHER_LDFLAGS = "$(APPLE_AKS_LIBRARY)"; + OTHER_LDFLAGS = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; + USE_HEADERMAP = NO; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-error=modules-ambiguous-internal-linkage", + ); }; name = Debug; }; @@ -32131,6 +37926,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; COPY_PHASE_STRIP = NO; + CREATE_INFOPLIST_SECTION_IN_BINARY = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -32138,14 +37934,28 @@ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "SECD_SERVER=1", + "$(inherited)", + ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "OSX/sec/securityd/Info-macOS.plist"; INSTALL_PATH = /usr/libexec; - MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; - OTHER_LDFLAGS = "$(APPLE_AKS_LIBRARY)"; + OTHER_LDFLAGS = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; + USE_HEADERMAP = NO; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-error=modules-ambiguous-internal-linkage", + ); }; name = Release; }; @@ -32168,26 +37978,22 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = OSX/trustd/macOS/entitlements.plist; ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( - "TRUSTD_SERVER=1", + "LIBTRUSTD=1", "$(inherited)", ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = NO; INSTALL_PATH = /usr/libexec; - MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = trustd; WARNING_CFLAGS = ( "-Wextra", "-Wno-unused-parameter", @@ -32216,27 +38022,23 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = OSX/trustd/macOS/entitlements.plist; COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( - "TRUSTD_SERVER=1", + "LIBTRUSTD=1", "$(inherited)", ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = NO; INSTALL_PATH = /usr/libexec; - MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = trustd; WARNING_CFLAGS = ( "-Wextra", "-Wno-unused-parameter", @@ -32261,11 +38063,13 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = "OSX/authd/authd-Entitlements.plist"; COMBINE_HIDPI_IMAGES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "OSX/authd/security.auth-Prefix.pch"; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNINITIALIZED_AUTOS = NO; @@ -32292,12 +38096,14 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = "OSX/authd/authd-Entitlements.plist"; COMBINE_HIDPI_IMAGES = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "OSX/authd/security.auth-Prefix.pch"; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNINITIALIZED_AUTOS = NO; @@ -32331,10 +38137,6 @@ CODE_SIGN_ENTITLEMENTS = OSX/sec/SecurityTool/entitlements.plist; COMBINE_HIDPI_IMAGES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_PREFIX_HEADER = "OSX/Keychain/Keychain-Prefix.pch"; @@ -32381,10 +38183,6 @@ COMBINE_HIDPI_IMAGES = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_NO_COMMON_BLOCKS = YES; GCC_PREFIX_HEADER = "OSX/Keychain/Keychain-Prefix.pch"; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -32425,10 +38223,6 @@ CODE_SIGN_ENTITLEMENTS = "OSX/Keychain Circle Notification/entitlments.plist"; COMBINE_HIDPI_IMAGES = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_PREFIX_HEADER = "OSX/Keychain Circle Notification/Keychain Circle Notification-Prefix.pch"; @@ -32471,10 +38265,6 @@ COMBINE_HIDPI_IMAGES = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_NO_COMMON_BLOCKS = YES; GCC_PREFIX_HEADER = "OSX/Keychain Circle Notification/Keychain Circle Notification-Prefix.pch"; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -32770,7 +38560,6 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; INFOPLIST_FILE = "OSX/libsecurity_apple_x509_cl/Info-plugin_apple_x509_cl.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_NAME = apple_x509_cl; SKIP_INSTALL = YES; @@ -32802,7 +38591,6 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; INFOPLIST_FILE = "OSX/libsecurity_apple_x509_cl/Info-plugin_apple_x509_cl.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = apple_x509_cl; SKIP_INSTALL = YES; @@ -32846,6 +38634,10 @@ "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "SecurityTests/SecurityTests-Info.plist"; INSTALL_PATH = /AppleInternal/Applications; @@ -32854,7 +38646,13 @@ "$(inherited)", "\"$(SDKROOT)/usr/lib/system\"", ); - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", + ); "OTHER_LDFLAGS[sdk=embedded]" = ( "$(inherited)", "-framework", @@ -32863,6 +38661,15 @@ "-lACM", "-lImg4Decode", "-lSystem", + "-lSecureKeyVaultForiapd", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "-framework", + CrashReporterSupport, ); PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.${PRODUCT_NAME:identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -32880,6 +38687,10 @@ "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "LIBTRUSTD=1", + "$(inherited)", + ); HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "SecurityTests/SecurityTests-Info.plist"; INSTALL_PATH = /AppleInternal/Applications; @@ -32888,7 +38699,13 @@ "$(inherited)", "\"$(SDKROOT)/usr/lib/system\"", ); - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "$(OTHER_LDFLAGS_SECURITYFOUNDATION)", + ); "OTHER_LDFLAGS[sdk=embedded]" = ( "$(inherited)", "-framework", @@ -32897,6 +38714,15 @@ "-lACM", "-lImg4Decode", "-lSystem", + "-lSecureKeyVaultForiapd", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "$(OTHER_LDFLAGS_APS)", + "$(OTHER_LDFLAGS_CLOUDKIT)", + "$(OTHER_LDFLAGS_PROTOBUF)", + "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)", + "-framework", + CrashReporterSupport, ); PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.${PRODUCT_NAME:identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -32983,12 +38809,7 @@ CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = "Keychain/Keychain-Entitlements.plist"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_PRECOMPILE_PREFIX_HEADER = NO; @@ -33044,12 +38865,7 @@ CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = "Keychain/Keychain-Entitlements.plist"; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", - ); GCC_C_LANGUAGE_STANDARD = gnu99; GCC_PRECOMPILE_PREFIX_HEADER = NO; HEADER_SEARCH_PATHS = ( @@ -33138,8 +38954,10 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = KeychainCircle/Info.plist; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + MODULEMAP_FILE = Modules/KeychainCircle.modulemap; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = "$(OTHER_LDFLAGS_MOBILEGESTALT)"; PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainCircle.KeychainCircle; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_TEXT_BASED_API = YES; @@ -33179,7 +38997,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = KeychainCircle/Info.plist; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + MODULEMAP_FILE = Modules/KeychainCircle.modulemap; MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = "$(OTHER_LDFLAGS_MOBILEGESTALT)"; PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainCircle.KeychainCircle; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_TEXT_BASED_API = YES; @@ -33223,30 +39043,41 @@ "-lACM", "-framework", SystemConfiguration, - "-F$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", "-framework", AppleSystemInfo, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", ); "OTHER_LDFLAGS[sdk=embedded]" = ( "-laks", "-lACM", "-framework", SystemConfiguration, - "-F$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", "-lMobileGestalt", "-framework", AggregateDictionary, "-framework", MobileKeyBag, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", ); "OTHER_LDFLAGS[sdk=embeddedsimulator*]" = ( "-lACM", "-framework", SystemConfiguration, - "-F$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", "-lMobileGestalt", "-framework", AggregateDictionary, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=macosx*]" = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "-lACM", + "-framework", + SystemConfiguration, + "-framework", + AppleSystemInfo, + "-lDiagnosticMessagesClient", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", ); PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainCircle.KeychainCircleTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -33286,33 +39117,43 @@ MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", "-lACM", "-framework", SystemConfiguration, - "-F$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", "-framework", AppleSystemInfo, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", ); "OTHER_LDFLAGS[sdk=embedded]" = ( "-laks", "-lACM", "-framework", SystemConfiguration, - "-F$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", "-lMobileGestalt", "-framework", AggregateDictionary, "-framework", MobileKeyBag, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", ); "OTHER_LDFLAGS[sdk=embeddedsimulator*]" = ( "-lACM", "-framework", SystemConfiguration, - "-F$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", "-lMobileGestalt", "-framework", AggregateDictionary, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=macosx*]" = ( + "$(APPLE_AKS_LIBRARY)", + "-lACM", + "-framework", + SystemConfiguration, + "-framework", + AppleSystemInfo, + "-lDiagnosticMessagesClient", ); PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainCircle.KeychainCircleTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -33430,6 +39271,437 @@ }; name = Release; }; + EB10556F1E14DD670003C309 /* Debug */ = { + isa = XCBuildConfiguration; + 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; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = 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; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + EB1055701E14DD670003C309 /* Release */ = { + isa = XCBuildConfiguration; + 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; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + 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_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + EB1055771E14DF430003C309 /* Debug */ = { + isa = XCBuildConfiguration; + 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_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + 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; + INSTALL_PATH = "$(SECURITY_FUZZER_BASE_DIR)/lib"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Debug; + }; + EB1055781E14DF430003C309 /* Release */ = { + isa = XCBuildConfiguration; + 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_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + 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"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Release; + }; + EB108F3F1E6CE4D2003B0456 /* Debug */ = { + isa = XCBuildConfiguration; + 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; + 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; + 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; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "KeychainCircle/Tests/KCPairingTest-Info.plist"; + INSTALL_PATH = /AppleInternal/XCTests/com.apple.security; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ( + "$(APPLE_AKS_LIBRARY)", + "-lACM", + "-framework", + SystemConfiguration, + "-framework", + AppleSystemInfo, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=embedded]" = ( + "-laks", + "-lACM", + "-framework", + SystemConfiguration, + "-lMobileGestalt", + "-framework", + AggregateDictionary, + "-framework", + MobileKeyBag, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=embeddedsimulator*]" = ( + "-lACM", + "-framework", + SystemConfiguration, + "-lMobileGestalt", + "-framework", + AggregateDictionary, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=macosx*]" = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "-lACM", + "-framework", + SystemConfiguration, + "-framework", + AppleSystemInfo, + "-lDiagnosticMessagesClient", + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainCircle.KeychainCircleTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTS_TEXT_BASED_API = YES; + }; + name = Debug; + }; + EB108F401E6CE4D2003B0456 /* Release */ = { + isa = XCBuildConfiguration; + 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; + 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; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + 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; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "KeychainCircle/Tests/KCPairingTest-Info.plist"; + INSTALL_PATH = /AppleInternal/XCTests/com.apple.security; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ( + "$(APPLE_AKS_LIBRARY)", + "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)", + "-lACM", + "-framework", + SystemConfiguration, + "-framework", + AppleSystemInfo, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=embedded]" = ( + "-laks", + "-lACM", + "-framework", + SystemConfiguration, + "-lMobileGestalt", + "-framework", + AggregateDictionary, + "-framework", + MobileKeyBag, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=embeddedsimulator*]" = ( + "-lACM", + "-framework", + SystemConfiguration, + "-lMobileGestalt", + "-framework", + AggregateDictionary, + "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)", + ); + "OTHER_LDFLAGS[sdk=macosx*]" = ( + "$(APPLE_AKS_LIBRARY)", + "-lACM", + "-framework", + SystemConfiguration, + "-framework", + AppleSystemInfo, + "-lDiagnosticMessagesClient", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainCircle.KeychainCircleTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTS_TEXT_BASED_API = YES; + }; + name = Release; + }; + EB27FF161E402CD400EC9E3A /* 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 = "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; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + EB27FF171E402CD400EC9E3A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = "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; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + EB2D54A81F02A45E00E46890 /* Debug */ = { + 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_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; + 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 = ( + "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; + OTHER_LDFLAGS = ( + "-framework", + Security, + ); + "OTHER_LDFLAGS[sdk=embedded]" = ( + "-laks", + "-framework", + Security, + "-framework", + IOKit, + ); + "OTHER_LDFLAGS[sdk=macosx*]" = ( + "-laks", + "-framework", + Security, + "-framework", + IOKit, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + }; + name = Debug; + }; + EB2D54A91F02A45E00E46890 /* 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; + 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; + COPY_PHASE_STRIP = NO; + 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_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INSTALL_PATH = /AppleInternal/CoreOS/tests/Security; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ( + "-framework", + Security, + ); + "OTHER_LDFLAGS[sdk=embedded]" = ( + "-laks", + "-framework", + Security, + "-framework", + IOKit, + ); + "OTHER_LDFLAGS[sdk=macosx*]" = ( + "-laks", + "-framework", + Security, + "-framework", + IOKit, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; EB425CA41C65846D000ECE53 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */; @@ -33975,6 +40247,44 @@ }; name = Debug; }; + EBB839AA1E29665E00853BAC /* Debug */ = { + isa = XCBuildConfiguration; + 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)"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + EBB839AB1E29665E00853BAC /* Release */ = { + isa = XCBuildConfiguration; + 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; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; EBBE20591C21380200B7A639 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -34203,6 +40513,123 @@ }; name = Release; }; + F621D07D1ED6DCE7000EA569 /* Debug */ = { + isa = XCBuildConfiguration; + 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; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_SHADOW = NO; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/header_symlinks/macOS/", + "$(inherited)", + ); + INSTALL_PATH = /usr/local/bin; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = NO; + SUPPORTED_PLATFORMS = macosx; + USE_HEADERMAP = NO; + }; + name = Debug; + }; + F621D07E1ED6DCE7000EA569 /* Release */ = { + isa = XCBuildConfiguration; + 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; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_SHADOW = NO; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/header_symlinks/macOS/", + "$(inherited)", + ); + INSTALL_PATH = /usr/local/bin; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + RUN_CLANG_STATIC_ANALYZER = NO; + SUPPORTED_PLATFORMS = macosx; + USE_HEADERMAP = NO; + }; + name = Release; + }; + F667EC5E1E96E9B100203D5C /* 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; + 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; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Debug; + }; + F667EC5F1E96E9B100203D5C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + 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 = "$(TARGET_NAME)"; + SDKROOT = macosx.internal; + }; + name = Release; + }; F93C49041AB8FCE00047E01A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -34301,6 +40728,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 225394B11E3080A600D3CD9B /* Build configuration list for PBXNativeTarget "security_codesigning_ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 225394B21E3080A600D3CD9B /* Debug */, + 225394B31E3080A600D3CD9B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 438169381B4EDCBD00C54D58 /* Build configuration list for PBXNativeTarget "SOSCCAuthPlugin" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -34310,6 +40746,42 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 470415DA1E5E14B6001F3D95 /* Build configuration list for PBXNativeTarget "seckeychainnetworkextensionstest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 470415D31E5E14B6001F3D95 /* Debug */, + 470415D41E5E14B6001F3D95 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 47702B221E5F409700B29577 /* Build configuration list for PBXNativeTarget "seckeychainnetworkextensionsystemdaemontest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 47702B231E5F409700B29577 /* Debug */, + 47702B241E5F409700B29577 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 47702B321E5F492C00B29577 /* Build configuration list for PBXNativeTarget "seckeychainnetworkextensionunauthorizedaccesstest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 47702B331E5F492C00B29577 /* Debug */, + 47702B341E5F492C00B29577 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 47C51B931EEA657D0032D9E5 /* Build configuration list for PBXNativeTarget "SecurityUnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 47C51B8C1EEA657D0032D9E5 /* Debug */, + 47C51B8D1EEA657D0032D9E5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 4C32C0B10A4975F7002891BD /* Build configuration list for PBXNativeTarget "Security_ios" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -34436,6 +40908,51 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 6C98085E1E788AEB00E70590 /* Build configuration list for PBXNativeTarget "CKKSCloudKitTests_mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6C98085F1E788AEB00E70590 /* Debug */, + 6C9808601E788AEB00E70590 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6C98089A1E788AFD00E70590 /* Build configuration list for PBXNativeTarget "CKKSCloudKitTests_ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6C98089B1E788AFD00E70590 /* Debug */, + 6C98089C1E788AFD00E70590 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6CCDF7881E3C25FB003F2555 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestRunner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6CCDF7891E3C25FB003F2555 /* Debug */, + 6CCDF78A1E3C25FB003F2555 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6CF4A0CC1E45488B00ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp_mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6CF4A0C51E45488B00ECD7B5 /* Debug */, + 6CF4A0C61E45488B00ECD7B5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6CF4A0F41E4549F300ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp_ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6CF4A0F51E4549F300ECD7B5 /* Debug */, + 6CF4A0F61E4549F300ECD7B5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 728B56AB16D59979008FA3AB /* Build configuration list for PBXNativeTarget "OTAPKIAssetTool" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -34463,6 +40980,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + ACBAF6DA1E9417F40007BA2F /* Build configuration list for PBXNativeTarget "security_transform_regressions" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + ACBAF6DB1E9417F40007BA2F /* Debug */, + ACBAF6DC1E9417F40007BA2F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; BE197F5819116FD100BA91D1 /* Build configuration list for PBXNativeTarget "SharedWebCredentialViewService" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -34481,6 +41007,33 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + BED208DA1EDF950E00753952 /* Build configuration list for PBXNativeTarget "manifeststresstest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BED208DB1EDF950E00753952 /* Debug */, + BED208DC1EDF950E00753952 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BEF88C421EAFFC4000357577 /* Build configuration list for PBXNativeTarget "TrustedPeers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BEF88C391EAFFC4000357577 /* Debug */, + BEF88C3A1EAFFC4000357577 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BEF88C431EAFFC4000357577 /* Build configuration list for PBXNativeTarget "TrustedPeersTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BEF88C3B1EAFFC4000357577 /* Debug */, + BEF88C3C1EAFFC4000357577 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; CD276C2C1A83F60C003226BC /* Build configuration list for PBXNativeTarget "KeychainSyncingOverIDSProxy" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -34490,6 +41043,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D41257D61E9410A300781F23 /* Build configuration list for PBXNativeTarget "trustd_ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D41257D71E9410A300781F23 /* Debug */, + D41257D81E9410A300781F23 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; D41AD42E1B967169008C7270 /* Build configuration list for PBXAggregateTarget "Security_executables_watchos" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -34508,6 +41070,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D4ADA31A1E2B41670031CEA3 /* Build configuration list for PBXNativeTarget "libtrustd" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D4ADA31B1E2B41670031CEA3 /* Debug */, + D4ADA31C1E2B41670031CEA3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DA30D6801DF8C8FB00EC6B43 /* Build configuration list for PBXNativeTarget "KeychainSyncAccountUpdater" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DA30D6791DF8C8FB00EC6B43 /* Debug */, + DA30D67A1DF8C8FB00EC6B43 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DC0067BD1D87876F005AF8DB /* Build configuration list for PBXNativeTarget "securityd_server_macos" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -34751,34 +41331,43 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - DC3A4B5B1D91E9FB00E46D4A /* Build configuration list for PBXNativeTarget "CodeSigningHelper" */ = { + DC222C741E034D1F00B09171 /* Build configuration list for PBXNativeTarget "libsecurityd_ios_NO_AKS" */ = { isa = XCConfigurationList; buildConfigurations = ( - DC3A4B5C1D91E9FB00E46D4A /* Debug */, - DC3A4B5D1D91E9FB00E46D4A /* Release */, + DC222C751E034D1F00B09171 /* Debug */, + DC222C761E034D1F00B09171 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - DC52E7BF1D80BC8000B0A59C /* Build configuration list for PBXNativeTarget "libsecurityd_ios" */ = { + DC3502BA1E0208BE00BC0587 /* Build configuration list for PBXNativeTarget "CKKSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - DC52E7C01D80BC8000B0A59C /* Debug */, - DC52E7C11D80BC8000B0A59C /* Release */, + DC3502BB1E0208BE00BC0587 /* Debug */, + DC3502BC1E0208BE00BC0587 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DC3A4B5B1D91E9FB00E46D4A /* Build configuration list for PBXNativeTarget "CodeSigningHelper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DC3A4B5C1D91E9FB00E46D4A /* Debug */, + DC3A4B5D1D91E9FB00E46D4A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - DC52E8B71D80C1EB00B0A59C /* Build configuration list for PBXNativeTarget "secipc_client" */ = { + DC52E7BF1D80BC8000B0A59C /* Build configuration list for PBXNativeTarget "libsecurityd_ios" */ = { isa = XCConfigurationList; buildConfigurations = ( - DC52E8B81D80C1EB00B0A59C /* Debug */, - DC52E8B91D80C1EB00B0A59C /* Release */, + DC52E7C01D80BC8000B0A59C /* Debug */, + DC52E7C11D80BC8000B0A59C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - DC52E8C31D80C25800B0A59C /* Build configuration list for PBXNativeTarget "SecureObjectSync" */ = { + DC52E8C31D80C25800B0A59C /* Build configuration list for PBXNativeTarget "SecureObjectSyncServer" */ = { isa = XCConfigurationList; buildConfigurations = ( DC52E8C41D80C25800B0A59C /* Debug */, @@ -35345,6 +41934,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + DCD8A1961E09EE0F00E4FA0A /* Build configuration list for PBXNativeTarget "SecureObjectSyncFramework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DCD8A1971E09EE0F00E4FA0A /* Debug */, + DCD8A1981E09EE0F00E4FA0A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DCE4E6A11D7A37FA00AFB96E /* Build configuration list for PBXNativeTarget "security2tool_macos" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -35381,7 +41979,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - DCE4E8561D7A57AE00AFB96E /* Build configuration list for PBXNativeTarget "trustd" */ = { + DCE4E8561D7A57AE00AFB96E /* Build configuration list for PBXNativeTarget "trustd_macos" */ = { isa = XCConfigurationList; buildConfigurations = ( DCE4E8571D7A57AE00AFB96E /* Debug */, @@ -35588,6 +42186,51 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + EB10556E1E14DD670003C309 /* Build configuration list for PBXLegacyTarget "=== Fuzzer Targets =====" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB10556F1E14DD670003C309 /* Debug */, + EB1055701E14DD670003C309 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EB1055761E14DF430003C309 /* Build configuration list for PBXNativeTarget "SecCertificateFuzzer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB1055771E14DF430003C309 /* Debug */, + EB1055781E14DF430003C309 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EB108F3E1E6CE4D2003B0456 /* Build configuration list for PBXNativeTarget "KCPairingTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB108F3F1E6CE4D2003B0456 /* Debug */, + EB108F401E6CE4D2003B0456 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EB27FF151E402CD400EC9E3A /* Build configuration list for PBXNativeTarget "ckksctl" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB27FF161E402CD400EC9E3A /* Debug */, + EB27FF171E402CD400EC9E3A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EB2D54A71F02A45E00E46890 /* Build configuration list for PBXNativeTarget "secatomicfile" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB2D54A81F02A45E00E46890 /* Debug */, + EB2D54A91F02A45E00E46890 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; EB425CA31C65846D000ECE53 /* Build configuration list for PBXNativeTarget "secbackuptest" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -35662,6 +42305,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + EBB839A91E29665E00853BAC /* Build configuration list for PBXNativeTarget "secfuzzer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EBB839AA1E29665E00853BAC /* Debug */, + EBB839AB1E29665E00853BAC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; EBBE20581C21380200B7A639 /* Build configuration list for PBXLegacyTarget "SecurityFeatures" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -35689,6 +42341,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + F621D07C1ED6DCE7000EA569 /* Build configuration list for PBXNativeTarget "authorizationdump" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F621D07D1ED6DCE7000EA569 /* Debug */, + F621D07E1ED6DCE7000EA569 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F667EC5D1E96E9B100203D5C /* Build configuration list for PBXNativeTarget "authdtest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F667EC5E1E96E9B100203D5C /* Debug */, + F667EC5F1E96E9B100203D5C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; F93C49031AB8FCE00047E01A /* Build configuration list for PBXAggregateTarget "ckcdiagnose.sh" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Security.xcodeproj/xcshareddata/xcschemes/CKKSTests.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/CKKSTests.xcscheme new file mode 100644 index 00000000..7ed8e0dd --- /dev/null +++ b/Security.xcodeproj/xcshareddata/xcschemes/CKKSTests.xcscheme @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Security.xcodeproj/xcshareddata/xcschemes/TrustedPeers.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/TrustedPeers.xcscheme new file mode 100644 index 00000000..8fbfa021 --- /dev/null +++ b/Security.xcodeproj/xcshareddata/xcschemes/TrustedPeers.xcscheme @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Security.xcodeproj/xcshareddata/xcschemes/ios - Debug.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/ios - Debug.xcscheme index 2ff5f627..f6881673 100644 --- a/Security.xcodeproj/xcshareddata/xcschemes/ios - Debug.xcscheme +++ b/Security.xcodeproj/xcshareddata/xcschemes/ios - Debug.xcscheme @@ -1,6 +1,6 @@ + + + + + + @@ -236,10 +252,6 @@ argument = "si_23_sectrust_ocsp" isEnabled = "NO"> - - @@ -293,7 +305,7 @@ isEnabled = "NO"> + + + + @@ -365,7 +385,7 @@ isEnabled = "NO"> + + diff --git a/Security.xcodeproj/xcshareddata/xcschemes/ios - Release.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/ios - Release.xcscheme index 7b8fddc5..470baeb2 100644 --- a/Security.xcodeproj/xcshareddata/xcschemes/ios - Release.xcscheme +++ b/Security.xcodeproj/xcshareddata/xcschemes/ios - Release.xcscheme @@ -1,6 +1,6 @@ + + @@ -275,7 +279,7 @@ isEnabled = "NO"> @@ -45,6 +46,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -147,6 +149,10 @@ argument = "secd_50_message" isEnabled = "NO"> + + @@ -185,7 +191,7 @@ + isEnabled = "YES"> + + + + + + @@ -223,6 +241,14 @@ argument = "secd_75_engine_views" isEnabled = "NO"> + + + + @@ -252,17 +278,29 @@ isEnabled = "NO"> + + + + + + @@ -271,6 +309,10 @@ argument = "secd_202_recoverykey" isEnabled = "NO"> + + @@ -294,6 +336,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -93,6 +135,14 @@ argument = "kc-30-xara" isEnabled = "NO"> + + + + @@ -189,6 +239,10 @@ argument = "si_16_ec_certificate" isEnabled = "NO"> + + @@ -245,6 +299,10 @@ argument = "si_29_sectrust_sha1_deprecation" isEnabled = "NO"> + + @@ -261,16 +319,40 @@ argument = "si_44_seckey_ies" isEnabled = "NO"> + + + + + + + + + + + + + + + + diff --git a/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme index 40687c0c..1996fb98 100644 --- a/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme +++ b/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme @@ -1,6 +1,6 @@ + + + + + + @@ -260,6 +274,10 @@ argument = "secd_90_hsa2" isEnabled = "NO"> + + diff --git a/Security.xcodeproj/xcshareddata/xcschemes/osx - sectests.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/osx - sectests.xcscheme index 0384941f..fc4ced8e 100644 --- a/Security.xcodeproj/xcshareddata/xcschemes/osx - sectests.xcscheme +++ b/Security.xcodeproj/xcshareddata/xcschemes/osx - sectests.xcscheme @@ -1,6 +1,6 @@ + com.apple.private.keychain.sysbound + + com.apple.security.attestation.access + keychain-cloud-circle com.apple.keystore.access-keychain-keys @@ -32,6 +36,7 @@ com.apple.security.sos 123456.test.group 123456.test.group2 + com.apple.bluetooth com.apple.private.ubiquity-kvstore-access diff --git a/SecurityTests/nist-certs/Expectations.plist b/SecurityTests/nist-certs/Expectations.plist index 984e46e2..34179ce6 100644 --- a/SecurityTests/nist-certs/Expectations.plist +++ b/SecurityTests/nist-certs/Expectations.plist @@ -2,57 +2,53 @@ - Validpre2000UTCnotBeforeDateTest3EE.crt - Can't parse 1950 UTCTime InvalidBasicSelfIssuedNewWithOldTest5EE.crt - Check PDF + CRLs not supported. InvalidBasicSelfIssuedOldWithNewTest2EE.crt - Check PDF + CRLs not supported. InvalidLongSerialNumberTest18EE.crt - Check PDF + CRLs not supported. InvalidNegativeSerialNumberTest15EE.crt - Check PDF + CRLs not supported. InvalidcRLIssuerTest27EE.crt - Check PDF + CRLs not supported. InvalidcRLIssuerTest31EE.crt - Check PDF + CRLs not supported. InvalidcRLIssuerTest32EE.crt - Check PDF + CRLs not supported. InvalidcRLIssuerTest34EE.crt - Check PDF + CRLs not supported. InvalidcRLIssuerTest35EE.crt - Check PDF + CRLs not supported. InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt - Check PDF + CRLs not supported. InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt - Check PDF + CRLs not supported. InvalidonlyContainsAttributeCertsTest14EE.crt - Check PDF + CRLs not supported. InvalidonlyContainsCACertsTest12EE.crt - Check PDF + CRLs not supported. InvalidonlyContainsUserCertsTest11EE.crt - Check PDF + CRLs not supported. InvalidonlySomeReasonsTest15EE.crt - Check PDF + CRLs not supported. InvalidonlySomeReasonsTest16EE.crt - Check PDF + CRLs not supported. InvalidonlySomeReasonsTest17EE.crt - Check PDF + CRLs not supported. InvalidonlySomeReasonsTest20EE.crt - Check PDF + CRLs not supported. InvalidonlySomeReasonsTest21EE.crt - Check PDF + CRLs not supported. ValidDSAParameterInheritanceTest5EE.crt - Check PDF + DSA not supported. ValidDSASignaturesTest4EE.crt - Check PDF + DSA not supported. ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt - Check PDF + <rdar://problem/30270922> ValidUTF8StringCaseInsensitiveMatchTest11EE.crt - Check PDF + <rdar://problem/30270922> InvalidDNnameConstraintsTest13EE.crt - Check PDF - ValidDNnameConstraintsTest14EE.crt - Can't evaluate empty subject name. + <rdar://problem/22749979> -- non-intersecting subtrees are appended diff --git a/SecurityTests/testlist.h b/SecurityTests/testlist.h index 79b71efc..3d647278 100644 --- a/SecurityTests/testlist.h +++ b/SecurityTests/testlist.h @@ -1,5 +1,5 @@ /* Don't prevent multiple inclusion of this file. */ -#include +#include #include #include #include diff --git a/SecurityTests/testmain.c b/SecurityTests/testmain.c index 282dbaa9..42f10fd8 100644 --- a/SecurityTests/testmain.c +++ b/SecurityTests/testmain.c @@ -10,12 +10,12 @@ #include -#include +#include #include "testlist.h" -#include +#include #include "testlist.h" -#include +#include #include #include diff --git a/SecurityTool/authz.c b/SecurityTool/authz.c index 44974aed..48e73a14 100644 --- a/SecurityTool/authz.c +++ b/SecurityTool/authz.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "authz.h" #include "security_tool.h" @@ -91,7 +92,7 @@ write_dict_to_stdout(CFDictionaryRef dict) CFRelease(right_definition_xml); } -static CFDictionaryRef +static CFDictionaryRef CF_RETURNS_RETAINED read_dict_from_stdin() { ssize_t bytes_read = 0; @@ -127,7 +128,7 @@ read_dict_from_stdin() return right_dict; } -static CFPropertyListRef +static CFPropertyListRef CF_RETURNS_RETAINED read_plist_from_file(CFStringRef filePath) { CFTypeRef property = NULL; @@ -225,6 +226,7 @@ write_plist_to_file(CFPropertyListRef propertyList, CFStringRef filePath) status = TRUE; bail: + CFReleaseNull(property); if (NULL != xmlData) CFRelease(xmlData); if (NULL != fileURL) diff --git a/SecurityTool/cmsutil.c b/SecurityTool/cmsutil.c index 1c98d51b..bfcecedf 100644 --- a/SecurityTool/cmsutil.c +++ b/SecurityTool/cmsutil.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include @@ -148,7 +149,9 @@ static SecPolicyRef CERT_PolicyForCertUsage(SECCertUsage certUsage, const char * emailAddress }; CSSM_DATA value = { sizeof(options), (uint8 *)&options }; - SEC_CHECK(SecPolicySetValue(policy, &value), "SecPolicySetValue"); + if (SecPolicySetValue(policy, &value)) { + goto loser; + } } // @@@ Need to set values for SSL and other policies. @@ -642,10 +645,10 @@ static SecCmsMessageRef signed_data(struct signOptionsStr *signOptions) false)) == NULL) { // look for identity by common name rather than email address - if ((identity = find_identity(signOptions->options->certDBHandle, - signOptions->nickname, - NULL, - signOptions->options->certUsage)) == NULL) + if ((identity = CopyMatchingIdentity(signOptions->options->certDBHandle, + signOptions->nickname, + NULL, + signOptions->options->certUsage)) == NULL) { sec_error("could not find signing identity for name: \"%s\"", signOptions->nickname); return NULL; @@ -1028,12 +1031,12 @@ static SecCmsMessageRef signed_data_certsonly(struct certsonlyOptionsStr *certso // build chain of objects: message->signedData->data SEC_CHECK0(sigd = SecCmsSignedDataCreateCertsOnly(cmsg, certs[0], true), "cannot create certs only CMS signedData object"); - CFRelease(certs[0]); + CFReleaseNull(certs[0]); for (i = 1; i < cnt; ++i) { SEC_CHECK2(SecCmsSignedDataAddCertChain(sigd, certs[i]), "cannot add cert chain for \"%s\"", certsonlyOptions->recipients[i]); - CFRelease(certs[i]); + CFReleaseNull(certs[i]); } SEC_CHECK0(cinfo = SecCmsMessageGetContentInfo(cmsg), @@ -1053,7 +1056,7 @@ loser: if (certs) { for (; i < cnt; ++i) - CFRelease(certs[i]); + CFReleaseNull(certs[i]); free(certs); } @@ -1143,6 +1146,10 @@ int cms_util(int argc, char * const *argv) result = 2; /* Trigger usage message. */ goto loser; } + if(!optarg) { + result = 2; + goto loser; + } decodeOptions.suppressContent = true; if (!strcmp(optarg, "MD2")) signOptions.hashAlgTag = SEC_OID_MD2; @@ -1319,7 +1326,7 @@ int cms_util(int argc, char * const *argv) case 'u': { - int usageType = atoi (strdup(optarg)); + int usageType = atoi (optarg); if (usageType < certUsageSSLClient || usageType > certUsageAnyCA) { result = 1; @@ -1546,6 +1553,21 @@ int cms_util(int argc, char * const *argv) } loser: + if(signOptions.encryptionKeyPreferenceNick) { + free(signOptions.encryptionKeyPreferenceNick); + } + if(signOptions.nickname) { + free(signOptions.nickname); + } + if(signOptions.subjectKeyID) { + free(signOptions.subjectKeyID); + } + if(signOptions.timestampingURL) { + free(signOptions.timestampingURL); + } + if(envFileName) { + free(envFileName); + } if (cmsg) SecCmsMessageDestroy(cmsg); if (outFile != stdout) diff --git a/SecurityTool/createFVMaster.c b/SecurityTool/createFVMaster.c index 4cbeb9d3..dd623b7d 100644 --- a/SecurityTool/createFVMaster.c +++ b/SecurityTool/createFVMaster.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "srCdsaUtils.h" @@ -73,7 +74,6 @@ OSStatus generateKeyPair(CSSM_CSP_HANDLE cspHand, CSSM_DL_DB_HANDLE dlDbHand, CS OSStatus createRootCert(CSSM_TP_HANDLE tpHand, CSSM_CL_HANDLE clHand, CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR subjPubKey, CSSM_KEY_PTR signerPrivKey, const char *hostName, const char *userName, CSSM_ALGORITHMS sigAlg, const CSSM_OID *sigOid, CSSM_DATA_PTR certData); -void randUint32(uint32 *u); static char *secCopyCString(CFStringRef theString); @@ -117,6 +117,7 @@ OSStatus makeMasterPassword(const char *fvmkcName, const char *masterPasswordPas CFDataRef certData = NULL; printf("Generating a %d bit key pair; this may take several minutes\n", keySizeInBits); status = createPair(hostName,userName,*keychainRef,keySizeInBits, &certData); + CFReleaseNull(userName); if (status) sec_error("Error in createPair: %s", sec_errstr(status)); if (certData) @@ -311,7 +312,7 @@ OSStatus createRootCert( /* certReq */ certReq.cspHand = cspHand; certReq.clHand = clHand; - randUint32(&certReq.serialNumber); // random serial number + certReq.serialNumber = arc4random(); certReq.numSubjectNames = 2; certReq.subjectNames = subjectNames; @@ -648,18 +649,6 @@ OSStatus generateKeyPair( return noErr; } -// Fill a uint32 with random data -void randUint32(uint32 *u) -{ - int dev = open("/dev/random", O_RDONLY); - if(dev < 0) { - return; - } - read(dev, u, sizeof(*u)); - close(dev); -} - - //========================================================================== int diff --git a/SecurityTool/identity_find.h b/SecurityTool/identity_find.h index 96dca380..56c17051 100644 --- a/SecurityTool/identity_find.h +++ b/SecurityTool/identity_find.h @@ -33,7 +33,7 @@ extern "C" { #endif -extern SecIdentityRef find_identity(CFTypeRef keychainOrArray, +extern SecIdentityRef CopyMatchingIdentity(CFTypeRef keychainOrArray, const char *identity, const char *hash, CSSM_KEYUSE keyUsage); diff --git a/SecurityTool/identity_find.c b/SecurityTool/identity_find.m similarity index 76% rename from SecurityTool/identity_find.c rename to SecurityTool/identity_find.m index 25634895..1fe81888 100644 --- a/SecurityTool/identity_find.c +++ b/SecurityTool/identity_find.m @@ -23,6 +23,8 @@ * identity_find.c */ +#import + #include "identity_find.h" #include "keychain_utilities.h" #include "trusted_cert_utils.h" @@ -39,6 +41,9 @@ #include #include #include +#include +#include +#include // cssmErrorString #include @@ -47,134 +52,126 @@ // SecIdentitySearchCreateWithPolicy #include +static bool checkKeyUsageOperation(CSSM_KEYUSE keyUse, CSSM_KEYUSE keyOp, NSDictionary *keyAttrs, id secKeyOp) { + if (keyUse & keyOp) { + return [keyAttrs[secKeyOp] isEqual:@YES]; + } + return true; +} + +static bool checkKeyUsage(CSSM_KEYUSE keyUse, NSDictionary *keyAttrs) { + CSSM_KEYUSE keyOps[] = { CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_DECRYPT, CSSM_KEYUSE_SIGN, CSSM_KEYUSE_VERIFY, CSSM_KEYUSE_SIGN_RECOVER, CSSM_KEYUSE_VERIFY_RECOVER, CSSM_KEYUSE_WRAP, CSSM_KEYUSE_UNWRAP, CSSM_KEYUSE_DERIVE }; + id secKeyOps[] = { (id)kSecAttrCanEncrypt, (id)kSecAttrCanDecrypt, (id)kSecAttrCanSign, (id)kSecAttrCanVerify, (id)kSecAttrCanSignRecover, (id)kSecAttrCanVerifyRecover, (id)kSecAttrCanWrap, (id)kSecAttrCanUnwrap, (id)kSecAttrCanDerive }; + + if (keyUse & CSSM_KEYUSE_ANY) { + for (size_t i = 0; i < sizeof(keyOps) / sizeof(CSSM_KEYUSE); ++i) { + keyUse |= keyOps[i]; + } + } + for (size_t i = 0; i < sizeof(keyOps) / sizeof(CSSM_KEYUSE); ++i) { + if (!checkKeyUsageOperation(keyUse, keyOps[i], keyAttrs, secKeyOps[i])) + return false; + } + return true; +} SecIdentityRef -find_identity(CFTypeRef keychainOrArray, - const char *identity, - const char *hash, - CSSM_KEYUSE keyUsage) +CopyMatchingIdentity(CFTypeRef keychainOrArray, + const char *identity, + const char *hash, + CSSM_KEYUSE keyUsage) { - SecIdentityRef identityRef = NULL; - SecIdentitySearchRef searchRef = NULL; - OSStatus status = SecIdentitySearchCreate(keychainOrArray, keyUsage, &searchRef); - if (status) { - return identityRef; - } - + id identityRef; // check input hash string and convert to data - CSSM_DATA hashData = { 0, NULL }; + NSData *hashData; if (hash) { - CSSM_SIZE len = strlen(hash)/2; - hashData.Length = len; - hashData.Data = (uint8 *)malloc(hashData.Length); - fromHex(hash, &hashData); + hashData = (__bridge_transfer NSData *)CFDataCreateFromHexString(kCFAllocatorDefault, (__bridge CFStringRef)[NSString stringWithUTF8String:hash]); } // filter candidates against the hash (or the name, if no hash provided) - CFStringRef matchRef = (identity) ? CFStringCreateWithCString(NULL, identity, kCFStringEncodingUTF8) : NULL; + NSString *matchName = (identity) ? [NSString stringWithUTF8String:identity] : nil; Boolean exactMatch = FALSE; - CSSM_DATA certData = { 0, NULL }; - SecIdentityRef candidate = NULL; - - while (SecIdentitySearchCopyNext(searchRef, &candidate) == noErr) { - SecCertificateRef cert = NULL; - if (SecIdentityCopyCertificate(candidate, &cert) != noErr) { - safe_CFRelease(&candidate); - continue; - } - if (SecCertificateGetData(cert, &certData) != noErr) { - safe_CFRelease(&cert); - safe_CFRelease(&candidate); + NSDictionary *query; + if (keychainOrArray) { + id keychainArray; + if (![(__bridge id)keychainOrArray isKindOfClass:[NSArray class]]) { + keychainArray = @[(__bridge id)keychainOrArray]; + } else { + keychainArray = (__bridge id)keychainOrArray; + } + query = @{ (id)kSecClass : (id)kSecClassIdentity, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecMatchSearchList : keychainArray, + (id)kSecReturnRef : @YES }; + } else { + query = @{ (id)kSecClass : (id)kSecClassIdentity, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecReturnRef : @YES }; + } + NSArray *identities; + if (SecItemCopyMatching((CFDictionaryRef)query, (void *)&identities) != errSecSuccess) { + return NULL; + } + + for (id candidate in identities) { + id cert; + if (SecIdentityCopyCertificate((__bridge SecIdentityRef)candidate, (void *)&cert) != errSecSuccess) continue; - } - if (hash) { - uint8 candidate_sha1_hash[20]; - CSSM_DATA digest; - digest.Length = sizeof(candidate_sha1_hash); - digest.Data = candidate_sha1_hash; - if ((SecDigestGetData(CSSM_ALGID_SHA1, &digest, &certData) == CSSM_OK) && - (hashData.Length == digest.Length) && - (!memcmp(hashData.Data, digest.Data, digest.Length))) { - identityRef = candidate; // currently retained - safe_CFRelease(&cert); - break; // we're done - can't get more exact than this - } + if (keyUsage) { + NSData *pubKeyHash = (__bridge_transfer NSData*)SecCertificateCopyPublicKeySHA1Digest((__bridge SecCertificateRef)cert); + NSDictionary *keyAttrs; + if (SecItemCopyMatching((__bridge CFDictionaryRef)@{ (id)kSecClass : (id)kSecClassKey, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnAttributes : @YES }, (void *)&keyAttrs) != errSecSuccess) + continue; + if (!(checkKeyUsage(keyUsage, keyAttrs))) { + continue; + } + } + if (hashData) { + NSData *certDataHash = (__bridge NSData *)SecCertificateGetSHA1Digest((__bridge SecCertificateRef)cert); + if ([hashData isEqual:certDataHash]) { + identityRef = candidate; + break; + } } else { // copy certificate name - CFStringRef nameRef = NULL; - if ((SecCertificateCopyCommonName(cert, &nameRef) != noErr) || nameRef == NULL) { - safe_CFRelease(&cert); - safe_CFRelease(&candidate); + NSString *commonName; + if ((SecCertificateCopyCommonName((__bridge SecCertificateRef)cert, (void *)&commonName) != errSecSuccess) || commonName == nil) { continue; // no name, so no match is possible } - CFIndex nameLen = CFStringGetLength(nameRef); - CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(nameLen, kCFStringEncodingUTF8); - char *nameBuf = (char *)malloc(bufLen); - if (!CFStringGetCString(nameRef, nameBuf, bufLen-1, kCFStringEncodingUTF8)) - nameBuf[0]=0; - - if (!strcmp(identity, "*")) { // special case: means "just take the first one" - sec_error("Using identity \"%s\"", nameBuf); - identityRef = candidate; // currently retained - free(nameBuf); - safe_CFRelease(&nameRef); - safe_CFRelease(&cert); + + if (identity && !strcmp(identity, "*")) { // special case: means "just take the first one" + sec_error("Using identity \"%s\"", [commonName UTF8String]); + identityRef = candidate; break; } CFRange find = { kCFNotFound, 0 }; - if (nameRef && matchRef) - find = CFStringFind(nameRef, matchRef, kCFCompareCaseInsensitive | kCFCompareNonliteral); - Boolean isExact = (find.location == 0 && find.length == nameLen); + if (commonName && matchName) + find = CFStringFind((__bridge CFStringRef)commonName, (__bridge CFStringRef)matchName, kCFCompareCaseInsensitive | kCFCompareNonliteral); + Boolean isExact = (find.location == 0 && find.length == (CFIndex)commonName.length); if (find.location == kCFNotFound) { - free(nameBuf); - safe_CFRelease(&nameRef); - safe_CFRelease(&cert); - safe_CFRelease(&candidate); continue; // no match } if (identityRef) { // got two matches if (exactMatch && !isExact) { // prior is better; ignore this one - free(nameBuf); - safe_CFRelease(&nameRef); - safe_CFRelease(&cert); - safe_CFRelease(&candidate); continue; } if (exactMatch == isExact) { // same class of match - if (CFEqual(identityRef, candidate)) { // identities have same cert - free(nameBuf); - safe_CFRelease(&nameRef); - safe_CFRelease(&cert); - safe_CFRelease(&candidate); + if ([identityRef isEqual:candidate]) { // identities have same cert continue; } // ambiguity - must fail sec_error("\"%s\" is ambiguous, matches more than one certificate", identity); - free(nameBuf); - safe_CFRelease(&nameRef); - safe_CFRelease(&cert); - safe_CFRelease(&candidate); - safe_CFRelease(&identityRef); + identityRef = nil; break; } - safe_CFRelease(&identityRef); // about to replace with this one } - identityRef = candidate; // currently retained + identityRef = candidate; exactMatch = isExact; - free(nameBuf); - safe_CFRelease(&nameRef); } - safe_CFRelease(&cert); - } - - safe_CFRelease(&searchRef); - safe_CFRelease(&matchRef); - if (hashData.Data) { - free(hashData.Data); } - return identityRef; + return identityRef?(__bridge_retained SecIdentityRef)identityRef:NULL; } static void printIdentity(SecIdentityRef identity, SecPolicyRef policy, int ordinalValue) diff --git a/SecurityTool/identity_prefs.c b/SecurityTool/identity_prefs.c index ead7797d..2d67ab26 100644 --- a/SecurityTool/identity_prefs.c +++ b/SecurityTool/identity_prefs.c @@ -36,6 +36,7 @@ #include #include #include +#include // SecCertificateInferLabel, SecDigestGetData #include @@ -59,7 +60,7 @@ do_set_identity_preference(CFTypeRef keychainOrArray, // find identity (if specified by name or hash) if (identity || hash) { - identityRef = find_identity(keychainOrArray, identity, hash, keyUsage); + identityRef = CopyMatchingIdentity(keychainOrArray, identity, hash, keyUsage); if (!identityRef) { sec_error("No matching identity found for \"%s\"", (hash) ? hash : identity); result = 1; @@ -80,6 +81,13 @@ cleanup: return result; } +typedef struct { + int i; + const char *name; +} ctk_print_context; + +OSStatus ctk_dump_item(CFTypeRef item, ctk_print_context *ctx); + static int do_get_identity_preference(const char *service, CSSM_KEYUSE keyUsage, @@ -159,7 +167,19 @@ do_get_identity_preference(const char *service, } else { - print_keychain_item_attributes(stdout, (SecKeychainItemRef)certRef, FALSE, FALSE, FALSE, FALSE); + CFTypeRef keys[] = { kSecValueRef, kSecReturnAttributes }; + CFTypeRef values[] = { certRef, kCFBooleanTrue }; + CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(CFTypeRef), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryRef attributes = NULL; + if (SecItemCopyMatching(query, (void *)&attributes) == errSecSuccess && CFDictionaryContainsKey(attributes, kSecAttrTokenID)) { + ctk_print_context ctx = { 1, "certificate" }; + ctk_dump_item(attributes, &ctx); + } else + print_keychain_item_attributes(stdout, (SecKeychainItemRef)certRef, FALSE, FALSE, FALSE, FALSE); + + CFRelease(query); + if(attributes) + CFRelease(attributes); } cleanup: diff --git a/SecurityTool/keychain_add.c b/SecurityTool/keychain_add.c index 0e70bf39..bfc65544 100644 --- a/SecurityTool/keychain_add.c +++ b/SecurityTool/keychain_add.c @@ -532,7 +532,7 @@ cleanup: static bool promptForPasswordData(char **returnedPasswordData) { // Caller must zero memory and free returned value. - // Returns true if we have data; false means the user cancelled + // Returns true if we have data; false means the user canceled if (!returnedPasswordData) return false; diff --git a/SecurityTool/keychain_export.c b/SecurityTool/keychain_export.m similarity index 90% rename from SecurityTool/keychain_export.c rename to SecurityTool/keychain_export.m index 23559a88..4164f2cb 100644 --- a/SecurityTool/keychain_export.c +++ b/SecurityTool/keychain_export.m @@ -23,6 +23,8 @@ * keychain_export.c */ +#import + #include "keychain_export.h" #include "keychain_utilities.h" #include "security_tool.h" @@ -36,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -559,6 +562,8 @@ typedef struct { const char *name; } ctk_print_context; +OSStatus +ctk_dump_item(CFTypeRef item, ctk_print_context *ctx); static void ctk_print_dict(const void *key, const void *value, void *context) @@ -585,7 +590,7 @@ ctk_dump_item_footer(ctk_print_context *ctx) printf("====\n"); } -static OSStatus +OSStatus ctk_dump_item(CFTypeRef item, ctk_print_context *ctx) { OSStatus stat = errSecSuccess; @@ -627,68 +632,62 @@ ctk_dump_items(CFArrayRef items, CFTypeRef secClass, const char *name) static OSStatus ctk_dump(CFTypeRef secClass, const char *name, const char *tid) { - OSStatus stat = errSecSuccess; - CFDictionaryRef query = NULL; - CFTypeRef result = NULL; - - const void *keys[] = { - kSecClass, - kSecMatchLimit, - kSecAttrAccessGroup, - kSecReturnAttributes, - }; - - const void *values[] = { - secClass, - kSecMatchLimitAll, - kSecAttrAccessGroupToken, - kCFBooleanTrue + NSArray *result; + BOOL returnRef = NO; + + if ([(__bridge id)secClass isEqual:(id)kSecClassIdentity] || [(__bridge id)secClass isEqual:(id)kSecClassCertificate]) + returnRef = YES; + + NSDictionary *query = @{ + (id)kSecClass : (__bridge id)secClass, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecAttrAccessGroup : (id)kSecAttrAccessGroupToken, + (id)kSecReturnAttributes : @YES, + (id)kSecReturnRef : @(returnRef) }; - // Query attributes of items of the requested secClass. - query = CFDictionaryCreate(kCFAllocatorDefault, - keys, - values, - sizeof(values) / sizeof(values[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if(tid) { - CFMutableDictionaryRef updatedQuery = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(query) + 1, query); - CFStringRef tidStr = CFStringCreateWithCString(kCFAllocatorDefault, tid, kCFStringEncodingUTF8); - CFDictionaryAddValue(updatedQuery, kSecAttrTokenID, tidStr); - CFRelease(tidStr); - - CFRelease(query); + NSMutableDictionary *updatedQuery = [NSMutableDictionary dictionaryWithDictionary:query]; + updatedQuery[(id)kSecAttrTokenID] = [NSString stringWithUTF8String:tid]; query = updatedQuery; } - stat = SecItemCopyMatching(query, (CFTypeRef *)&result); + OSStatus stat = SecItemCopyMatching((__bridge CFTypeRef)query, (void *)&result); if(stat) { if (stat == errSecItemNotFound) { fprintf(stderr, "No items found.\n"); } else { sec_error("SecItemCopyMatching: %x (%d) - %s", stat, stat, sec_errstr(stat)); } - goto cleanup; + return stat; } // We expect an array of dictionaries containing item attributes as result. - if(CFGetTypeID(result) == CFArrayGetTypeID()) { - stat = ctk_dump_items((CFArrayRef)result, secClass, name); - } else { - stat = errSecInternalComponent; - } + if([result isKindOfClass:[NSArray class]]) { + if (returnRef) { + NSMutableArray *updatedResult = [NSMutableArray array]; + for (NSDictionary *dict in result) { + NSMutableDictionary *updatedItem = [NSMutableDictionary dictionaryWithDictionary:dict]; + id itemRef = updatedItem[(id)kSecValueRef]; + if ([(__bridge id)secClass isEqual:(id)kSecClassIdentity]) { + id certificateRef; + if (SecIdentityCopyCertificate((__bridge SecIdentityRef)itemRef, (void *)&certificateRef) != errSecSuccess) + continue; + itemRef = certificateRef; + } -cleanup: - if(query) { - CFRelease(query); - } + NSData *certDigest = (__bridge NSData*)SecCertificateGetSHA1Digest((__bridge SecCertificateRef)itemRef); + updatedItem[@"sha1"] = certDigest; + [updatedItem removeObjectForKey:(id)kSecValueRef]; + [updatedResult addObject:updatedItem]; + } + result = updatedResult; + } - if(result) { - CFRelease(result); + stat = ctk_dump_items((__bridge CFArrayRef)result, secClass, name); + } else { + stat = errSecInternalComponent; } - return stat; } diff --git a/SecurityTool/keychain_find.c b/SecurityTool/keychain_find.c index 51776602..a6e781a2 100644 --- a/SecurityTool/keychain_find.c +++ b/SecurityTool/keychain_find.c @@ -43,6 +43,7 @@ #include #include #include +#include // SecDigestGetData, SecKeychainSearchCreateForCertificateByEmail, SecCertificateFindByEmail @@ -1189,6 +1190,13 @@ cleanup: return result; } +#define SetKeyToString(dict, key, arg) \ +{ \ + CFStringRef str = CFStringCreateWithCStringNoCopy(NULL, arg, kCFStringEncodingUTF8, kCFAllocatorNull); \ + CFDictionarySetValue(dict, key, str); \ + CFReleaseNull(str); \ +} + int keychain_find_key(int argc, char * const *argv) { /* @@ -1219,25 +1227,25 @@ keychain_find_key(int argc, char * const *argv) { switch (ch) { case 'a': - CFDictionarySetValue(query, kSecAttrApplicationLabel, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrApplicationLabel, optarg); break; case 'c': - CFDictionarySetValue(query, kSecAttrCreator, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrCreator, optarg); break; case 'd': CFDictionarySetValue(query, kSecAttrCanDecrypt, kCFBooleanTrue); break; case 'D': - CFDictionarySetValue(query, kSecAttrDescription, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrDescription, optarg); break; case 'e': CFDictionarySetValue(query, kSecAttrCanEncrypt, kCFBooleanTrue); break; case 'j': - CFDictionarySetValue(query, kSecAttrComment, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrComment, optarg); break; case 'l': - CFDictionarySetValue(query, kSecAttrLabel, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrLabel, optarg); break; case 'r': CFDictionarySetValue(query, kSecAttrCanDerive, kCFBooleanTrue); @@ -1287,6 +1295,7 @@ keychain_find_key(int argc, char * const *argv) { CFDictionarySetValue(query, kSecMatchSearchList, searchList); CFRelease(searchList); } + CFReleaseNull(keychainOrArray); OSStatus status = SecItemCopyMatching(query, &results); if(status) { @@ -1344,45 +1353,47 @@ int keychain_set_internet_password_partition_list(int argc, char * const *argv) switch (ch) { case 'a': - CFDictionarySetValue(query, kSecAttrAccount, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrAccount, optarg); break; case 'c': - CFDictionarySetValue(query, kSecAttrCreator, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrCreator, optarg); break; case 'C': - CFDictionarySetValue(query, kSecAttrType, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrType, optarg); break; case 'd': - CFDictionarySetValue(query, kSecAttrSecurityDomain, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrSecurityDomain, optarg); break; case 'D': - CFDictionarySetValue(query, kSecAttrDescription, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrDescription, optarg); break; case 'j': - CFDictionarySetValue(query, kSecAttrComment, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrComment, optarg); break; case 'l': - CFDictionarySetValue(query, kSecAttrLabel, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrLabel, optarg); break; case 'p': - CFDictionarySetValue(query, kSecAttrPath, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrPath, optarg); break; case 'P': - CFDictionarySetValue(query, kSecAttrPort, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrPort, optarg); break; case 'r': - CFDictionarySetValue(query, kSecAttrProtocol, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrProtocol, optarg); break; case 's': - CFDictionarySetValue(query, kSecAttrService, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrService, optarg); break; case 't': - CFDictionarySetValue(query, kSecAttrAuthenticationType, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrAuthenticationType, optarg); break; case 'S': + CFReleaseNull(partitionidsinput); partitionidsinput = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull); break; case 'k': + CFReleaseNull(password); password = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull); break; case '?': @@ -1431,33 +1442,35 @@ keychain_set_generic_password_partition_list(int argc, char * const *argv) { switch (ch) { case 'a': - CFDictionarySetValue(query, kSecAttrAccount, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrAccount, optarg); break; case 'c': - CFDictionarySetValue(query, kSecAttrCreator, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrCreator, optarg); break; case 'C': - CFDictionarySetValue(query, kSecAttrType, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrType, optarg); break; case 'D': - CFDictionarySetValue(query, kSecAttrDescription, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrDescription, optarg); break; case 'G': - CFDictionarySetValue(query, kSecAttrGeneric, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrGeneric, optarg); break; case 'j': - CFDictionarySetValue(query, kSecAttrComment, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrComment, optarg); break; case 'l': - CFDictionarySetValue(query, kSecAttrLabel, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrLabel, optarg); break; case 's': - CFDictionarySetValue(query, kSecAttrService, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrService, optarg); break; case 'S': + CFReleaseNull(partitionidsinput); partitionidsinput = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull); break; case 'k': + CFReleaseNull(password); password = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull); break; case '?': @@ -1520,25 +1533,26 @@ keychain_set_key_partition_list(int argc, char * const *argv) { switch (ch) { case 'a': - CFDictionarySetValue(query, kSecAttrApplicationLabel, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrApplicationLabel, optarg); break; case 'c': - CFDictionarySetValue(query, kSecAttrCreator, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrCreator, optarg); break; case 'd': + SetKeyToString(query, kSecAttrCanDecrypt, optarg); CFDictionarySetValue(query, kSecAttrCanDecrypt, kCFBooleanTrue); break; case 'D': - CFDictionarySetValue(query, kSecAttrDescription, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrDescription, optarg); break; case 'e': CFDictionarySetValue(query, kSecAttrCanEncrypt, kCFBooleanTrue); break; case 'j': - CFDictionarySetValue(query, kSecAttrComment, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrComment, optarg); break; case 'l': - CFDictionarySetValue(query, kSecAttrLabel, CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull)); + SetKeyToString(query, kSecAttrLabel, optarg); break; case 'r': CFDictionarySetValue(query, kSecAttrCanDerive, kCFBooleanTrue); @@ -1567,9 +1581,11 @@ keychain_set_key_partition_list(int argc, char * const *argv) { CFDictionarySetValue(query, kSecAttrCanWrap, kCFBooleanTrue); break; case 'S': + CFReleaseNull(partitionidsinput); partitionidsinput = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull); break; case 'k': + CFReleaseNull(password); password = CFStringCreateWithCStringNoCopy(NULL, optarg, kCFStringEncodingUTF8, kCFAllocatorNull); break; case '?': @@ -1593,6 +1609,8 @@ keychain_set_key_partition_list(int argc, char * const *argv) { result = keychain_parse_args_and_set_partition_list(argc, argv, query, partitionidsinput, password); cleanup: + CFReleaseNull(partitionidsinput); + CFReleaseNull(password); safe_CFRelease(&query); return result; } @@ -1602,6 +1620,7 @@ int keychain_parse_args_and_set_partition_list(int argc, char * const *argv, CFM int result = 0; const char *keychainName = NULL; SecKeychainRef kc = NULL; + CFStringRef localPassword = NULL; // if we were given a keychain, use it if (argc == 1) @@ -1639,13 +1658,15 @@ int keychain_parse_args_and_set_partition_list(int argc, char * const *argv, CFM result = -1; goto cleanup; } - password = CFStringCreateWithCString(NULL, cpassword, kCFStringEncodingUTF8); + localPassword = CFStringCreateWithCString(NULL, cpassword, kCFStringEncodingUTF8); + password = localPassword; free(cpassword); } result = keychain_set_partition_list(kc, query, password, partitionidsinput); cleanup: + CFReleaseNull(localPassword); return result; } @@ -1658,6 +1679,7 @@ int keychain_set_partition_list(SecKeychainRef kc, CFDictionaryRef query, CFStri GetCStringFromCFString(password, &passwordBuf, &passwordLen); OSStatus status; + CFTypeRef results = NULL; // Unlock the keychain with the given password, since we'll be fetching ACLs status = SecKeychainUnlock(kc, (UInt32) passwordLen, passwordBuf, true); @@ -1667,7 +1689,6 @@ int keychain_set_partition_list(SecKeychainRef kc, CFDictionaryRef query, CFStri goto cleanup; } - CFTypeRef results = NULL; status = SecItemCopyMatching(query, &results); if(status) { sec_perror("SecItemCopyMatching", status); diff --git a/SecurityTool/keychain_utilities.c b/SecurityTool/keychain_utilities.c index 669f9bed..5cc2ebc3 100644 --- a/SecurityTool/keychain_utilities.c +++ b/SecurityTool/keychain_utilities.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "readline_cssm.h" @@ -72,7 +73,7 @@ void check_obsolete_keychain(const char *kcName) } } -SecKeychainRef +SecKeychainRef CF_RETURNS_RETAINED keychain_open(const char *name) { SecKeychainRef keychain = NULL; @@ -115,11 +116,15 @@ keychain_open(const char *name) return keychain; } } - CFRelease(dynamic); + CFReleaseNull(dynamic); } } - result = SecKeychainOpen(name, &keychain); + if(name) { + result = SecKeychainOpen(name, &keychain); + } else { + result = errSecParam; + } if (result) { sec_error("SecKeychainOpen %s: %s", name, sec_errstr(result)); @@ -788,34 +793,34 @@ print_buffer_ascii(FILE *stream, size_t length, const void *data) void print_buffer(FILE *stream, size_t length, const void *data) { - uint8 *p = (uint8 *) data; - Boolean hex = FALSE; - Boolean ascii = FALSE; - UInt32 ix; - for (ix = 0; ix < length; ++ix) - { - int ch = *p++; - if (ch >= ' ' && ch <= '~' && ch != '\\') - ascii = TRUE; - else - hex = TRUE; - } + uint8 *p = (uint8 *) data; + Boolean hex = FALSE; + Boolean ascii = FALSE; + UInt32 ix; + for (ix = 0; ix < length; ++ix) + { + int ch = *p++; + if (ch >= ' ' && ch <= '~' && ch != '\\') + ascii = TRUE; + else + hex = TRUE; + } - if (hex) - { - fputc('0', stream); - fputc('x', stream); - print_buffer_hex(stream, length, data); - if (ascii) - fputc(' ', stream); - fputc(' ', stream); - } - if (ascii) - { - fputc('"', stream); - print_buffer_ascii(stream, length, data); - fputc('"', stream); - } + if (hex) + { + fputc('0', stream); + fputc('x', stream); + print_buffer_hex(stream, length, data); + if (ascii) + fputc(' ', stream); + fputc(' ', stream); + } + if (ascii) + { + fputc('"', stream); + print_buffer_ascii(stream, length, data); + fputc('"', stream); + } } void @@ -849,7 +854,7 @@ fromHex(const char *hexDigits, CSSM_DATA *data) } } -CFDataRef +CFDataRef CF_RETURNS_RETAINED cfFromHex(CFStringRef hex) { // behavior is undefined if you pass in a non-hex string. Don't do that. char* chex; @@ -865,7 +870,7 @@ cfFromHex(CFStringRef hex) { CFDataIncreaseLength(bin, bytes); if(!bin || (size_t) CFDataGetLength(bin) != bytes) { - safe_CFRelease(bin); + CFReleaseNull(bin); return NULL; } @@ -877,7 +882,7 @@ cfFromHex(CFStringRef hex) { return bin; } -CFStringRef cfToHex(CFDataRef bin) { +CFStringRef CF_RETURNS_RETAINED cfToHex(CFDataRef bin) { size_t len = CFDataGetLength(bin) * 2; CFMutableStringRef str = CFStringCreateMutable(NULL, len); @@ -914,7 +919,7 @@ GetCStringFromCFString(CFStringRef cfstring, char** cstr, size_t* len) { *len = strnlen(*cstr, strLen); } -CFDictionaryRef makeCFDictionaryFromData(CFDataRef data) +CFDictionaryRef CF_RETURNS_RETAINED makeCFDictionaryFromData(CFDataRef data) { if (data) { CFPropertyListRef plist = CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL); diff --git a/SecurityTool/keychain_utilities.h b/SecurityTool/keychain_utilities.h index 6c1ca6bf..e58ceaf5 100644 --- a/SecurityTool/keychain_utilities.h +++ b/SecurityTool/keychain_utilities.h @@ -70,7 +70,7 @@ extern void GetCStringFromCFString(CFStringRef cfstring, char** cstr, size_t* le extern void print_partition_id_list(FILE *stream, CFStringRef description); -extern void safe_CFRelease(void *cfTypeRefPtr); +extern void safe_CFRelease(void CF_CONSUMED *cfTypeRefPtr); extern void check_obsolete_keychain(const char *kcName); diff --git a/SecurityTool/security.1 b/SecurityTool/security.1 index a19ef924..a949890f 100644 --- a/SecurityTool/security.1 +++ b/SecurityTool/security.1 @@ -2,7 +2,7 @@ .\"See Also: .\"man mdoc.samples for a complete listing of options .\"man mdoc for the short list of editing options -.Dd March 1, 2012 \" DATE +.Dd March 15, 2017 \" DATE .Dt security 1 \" Program name and manual section number .Os Darwin .Sh NAME \" Section Header - required - don't modify @@ -1420,14 +1420,17 @@ Import admin Trust Settings; default is user. .Op Fl c Ar certFile .Op Fl r Ar rootCertFile .Op Fl p Ar policy -.Op Fl k Ar keychain +.Op Fl C .Op Fl d Ar date -.Op Fl n +.Op Fl k Ar keychain +.Op Fl n Ar name +.Op Fl N .Op Fl L .Op Fl l .Op Fl e Ar emailAddress .Op Fl s Ar sslHost .Op Fl q +.Op Fl R Ar revCheckOption .Bl -item -offset -indent Verify one or more certificates. .It @@ -1439,27 +1442,33 @@ Certificate to verify, in DER or PEM format. Can be specified more than once; le Root certificate, in DER or PEM format. Can be specified more than once. If not specified, the system anchor certificates are used. If one root certificate is specified, and zero (non-root) certificates are specified, the root certificate is verified against itself. .It Fl p Ar policy Specify verification policy (ssl, smime, codeSign, IPSec, basic, swUpdate, pkgSign, eap, appleID, macappstore, timestamping). Default is basic. -.It Fl k Ar keychain -Keychain to search for intermediate certs. Can be specified multiple times. Default is the current user's keychain search list. +.It Fl C +Specify this evaluation is for client usage, if the verification policy (e.g. ssl) distinguishes between client and server usage. Default is server usage. .It Fl d Ar date Date to set for verification. Specified in the format of YYYY-MM-DD-hh:mm:ss (time optional). e.g: 2016-04-25-15:59:59 for April 25, 2016 at 3:59:59 pm in GMT -.It Fl n +.It Fl k Ar keychain +Keychain to search for intermediate CA certificates. Can be specified multiple times. Default is the current user's keychain search list. +.It Fl n Ar name +Specify a name to be verified, e.g. the SSL host name for the ssl policy, or RFC822 email address for the smime policy. For backward compatibility, if the -n option is provided without an argument, it will be interpreted as equivalent to -N. +.It Fl N Avoid searching any keychains. .It Fl L Use local certificates only. If an issuing CA certificate is missing, this option will avoid accessing the network to fetch it. .It Fl l Specifies that the leaf certificate is a CA cert. By default, a leaf certificate with a Basic Constraints extension with the CA bit set fails verification. .It Fl e Ar emailAddress -Specify email address for the smime policy. +Specify email address for the smime policy. (This option is deprecated; use -n instead.) .It Fl s Ar sslHost -Specify SSL host name for the ssl policy. +Specify SSL host name for the ssl policy. (This option is deprecated; use -n instead.) .It Fl q Quiet, no stdout or stderr. +.It Fl R Ar revCheckOption +Specify a revocation checking option for this evaluation (ocsp, crl, require, offline). Can be specified multiple times; e.g. to enable revocation checking via either OCSP or CRL methods and require a positive response, use "-R ocsp -R crl -R require". The offline option will consult previously cached responses, but will not make a request to a revocation server. .El .It .Sy Examples .Bl -tag -width -indent -.It security> verify-cert -c applestore0.cer -c applestore1.cer -p ssl -s store.apple.com +.It security> verify-cert -c applestore0.cer -c applestore1.cer -p ssl -n store.apple.com .It security> verify-cert -r serverbasic.crt .El .\"marker. diff --git a/SecurityTool/security.c b/SecurityTool/security.c index e0df1c8d..67abc3d3 100644 --- a/SecurityTool/security.c +++ b/SecurityTool/security.c @@ -87,10 +87,6 @@ typedef struct command /* The default prompt. */ const char *prompt_string = "security> "; -/* The name of this program. */ -const char *prog_name; - - /* Forward declarations of static functions. */ static int help(int argc, char * const *argv); @@ -622,17 +618,28 @@ const command commands[] = " -c certFile Certificate to verify. Can be specified multiple times, leaf first.\n" " -r rootCertFile Root Certificate. Can be specified multiple times.\n" " -p policy Verify Policy (basic, ssl, smime, codeSign, IPSec, swUpdate, pkgSign,\n" - " eap, appleID, macappstore, timestamping); default is basic.\n" - " -d date Set date and time to use when verifying certificate,\n" - " provided in the form of YYYY-MM-DD-hh:mm:ss (time optional) in GMT.\n" - " e.g: 2016-04-25-15:59:59 for April 25, 2016 at 3:59:59 pm in GMT\n" - " -k keychain Keychain. Can be called multiple times. Default is default search list.\n" - " -n No keychain search list.\n" + " eap, appleID, macappstore, timestamping); default is basic.\n" + " -C Set client policy to true. Default is server policy. (ssl, IPSec, eap)\n" + " -d date Set date and time to use when verifying certificate,\n" + " provided in the form of YYYY-MM-DD-hh:mm:ss (time optional) in GMT.\n" + " e.g: 2016-04-25-15:59:59 for April 25, 2016 at 3:59:59 pm in GMT\n" + " -k keychain Keychain. Can be specified multiple times. Default is default search list.\n" + " -n name Name to be verified. (ssl, IPSec, smime)\n" + " -N No keychain search list. (For backward compatibility, -n without a\n" + " subsequent name argument is interpreted as equivalent to -N.)\n" " -L Local certificates only (do not try to fetch missing CA certs from net).\n" " -l Leaf cert is a CA (normally an error, unless this option is given).\n" - " -e emailAddress Email address for smime policy.\n" - " -s sslHost SSL host name for ssl policy.\n" - " -q Quiet.\n", + " -e emailAddress Email address for smime policy. (Deprecated; use -n instead.)\n" + " -s sslHost SSL host name for ssl policy. (Deprecated; use -n instead.)\n" + " -q Quiet.\n" + " -R revCheckOption Perform revocation checking with one of the following options:\n" + " ocsp Check revocation status using OCSP method.\n" + " crl Check revocation status using CRL method.\n" + " require Require a positive response for successful verification.\n" + " offline Consult cached responses only (no network requests).\n" + " Can be specified multiple times; e.g. to enable revocation checking\n" + " via either OCSP or CRL methods and require a positive response, use\n" + " \"-R ocsp -R crl -R require\".\n", "Verify certificate(s)." }, { "authorize" , authorize, @@ -898,7 +905,7 @@ usage(void) " -p Set the prompt to \"prompt\" (implies -i).\n" " -q Be less verbose.\n" " -v Be more verbose about what's going on.\n" - "%s commands are:\n", prog_name, prog_name); + "%s commands are:\n", getprogname(), getprogname()); help(0, NULL); return 2; } @@ -978,7 +985,7 @@ sec_error(const char *msg, ...) { va_list args; - fprintf(stderr, "%s: ", prog_name); + fprintf(stderr, "%s: ", getprogname()); va_start(args, msg); vfprintf(stderr, msg, args); @@ -1003,10 +1010,6 @@ main(int argc, char * const *argv) int ch; - /* Remember my name. */ - prog_name = strrchr(argv[0], '/'); - prog_name = prog_name ? prog_name + 1 : argv[0]; - /* Do getopt stuff for global options. */ optind = 1; optreset = 1; diff --git a/SecurityTool/security_tool.h b/SecurityTool/security_tool.h index 2244bf76..0bc40f9e 100644 --- a/SecurityTool/security_tool.h +++ b/SecurityTool/security_tool.h @@ -23,8 +23,8 @@ * security.h */ -#ifndef _SECURITY_H_ -#define _SECURITY_H_ 1 +#ifndef _SECURITY_TOOL_H_ +#define _SECURITY_TOOL_H_ 1 #ifdef __cplusplus extern "C" { @@ -46,4 +46,4 @@ void sec_perror(const char *msg, int err); } #endif -#endif /* _SECURITY_H_ */ +#endif /* _SECURITY_TOOL_H_ */ diff --git a/SecurityTool/smartcards.m b/SecurityTool/smartcards.m index 2bbd4444..fb934a18 100644 --- a/SecurityTool/smartcards.m +++ b/SecurityTool/smartcards.m @@ -11,9 +11,8 @@ const CFStringRef kTKDisabledTokensPreferencesKey = CFSTR("DisabledTokens"); static void listDisabledTokens() { id value = (__bridge_transfer id)CFPreferencesCopyValue(kTKDisabledTokensPreferencesKey, kTKSmartCardPreferencesDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (![value isKindOfClass:NSArray.class]) + if (value && ![value isKindOfClass:NSArray.class]) return; - NSArray *disabledTokens = (NSArray*)value; for (id tokenName in disabledTokens) { if ([tokenName isKindOfClass:NSString.class]) { @@ -24,7 +23,7 @@ static void listDisabledTokens() { static void disable(const char *tokenToDisable) { id value = (__bridge_transfer id)CFPreferencesCopyValue(kTKDisabledTokensPreferencesKey, kTKSmartCardPreferencesDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (![value isKindOfClass:NSArray.class]) + if (value && ![value isKindOfClass:NSArray.class]) return; NSMutableArray *disabledTokens = [NSMutableArray arrayWithArray:value]; NSString *tokenName = [NSString stringWithUTF8String:tokenToDisable]; @@ -40,9 +39,8 @@ static void disable(const char *tokenToDisable) { static void enable(const char *tokenToEnable) { id value = (__bridge_transfer id)CFPreferencesCopyValue(kTKDisabledTokensPreferencesKey, kTKSmartCardPreferencesDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (![value isKindOfClass:NSArray.class]) + if (value && ![value isKindOfClass:NSArray.class]) return; - NSString *tokenName = [NSString stringWithUTF8String:tokenToEnable]; NSMutableArray *disabledTokens = [NSMutableArray arrayWithArray:value]; if ([disabledTokens containsObject:tokenName]) { diff --git a/SecurityTool/trusted_cert_add.c b/SecurityTool/trusted_cert_add.c index a4cc36ef..d2edf884 100644 --- a/SecurityTool/trusted_cert_add.c +++ b/SecurityTool/trusted_cert_add.c @@ -82,9 +82,10 @@ #include #include #include +#include /* r/w files as CFData */ -static CFDataRef readFileData( +static CFDataRef CF_RETURNS_RETAINED readFileData( const char *fileName) { unsigned char *d; diff --git a/SecurityTool/trusted_cert_utils.c b/SecurityTool/trusted_cert_utils.c index 459903b2..4a6f532e 100644 --- a/SecurityTool/trusted_cert_utils.c +++ b/SecurityTool/trusted_cert_utils.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2003-2004,2006,2009-2010,2012,2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2003-2004,2006,2009-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, @@ -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@ * * trusted_cert_utils.c @@ -435,3 +435,28 @@ const CSSM_OID *policyStringToOid( return NULL; } } + +CFOptionFlags revCheckOptionStringToFlags( + const char *revCheckOption) +{ + CFOptionFlags result = 0; + if(revCheckOption == NULL) { + return result; + } + else if(!strcmp(revCheckOption, "ocsp")) { + result |= kSecRevocationOCSPMethod; + } + else if(!strcmp(revCheckOption, "crl")) { + result |= kSecRevocationCRLMethod; + } + else if(!strcmp(revCheckOption, "require")) { + result |= kSecRevocationRequirePositiveResponse; + } + else if(!strcmp(revCheckOption, "offline")) { + result |= kSecRevocationNetworkAccessDisabled; + } + else if(!strcmp(revCheckOption, "online")) { + result |= kSecRevocationOnlineCheck; + } + return result; +} diff --git a/SecurityTool/trusted_cert_utils.h b/SecurityTool/trusted_cert_utils.h index fb2e10fb..f4d8403a 100644 --- a/SecurityTool/trusted_cert_utils.h +++ b/SecurityTool/trusted_cert_utils.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2003-2004,2006,2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2003-2004,2006,2014-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, @@ -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@ * * trusted_cert_utils.h @@ -62,11 +62,14 @@ extern int compareOids(const CSSM_OID *oid1, const CSSM_OID *oid2); extern SecTrustedApplicationRef appPathToAppRef(const char *appPath); /* read a file --> SecCertificateRef */ -int readCertFile(const char *fileName, SecCertificateRef *certRef); +int readCertFile(const char *fileName, SecCertificateRef *certRef); /* policy string --> CSSM_OID */ const CSSM_OID *policyStringToOid(const char *policy); +/* revocation option string --> revocation option flag */ +CFOptionFlags revCheckOptionStringToFlags(const char *revCheckOption); + #ifdef __cplusplus } #endif diff --git a/SecurityTool/verify_cert.c b/SecurityTool/verify_cert.c index 544e62cd..ae3c72e5 100644 --- a/SecurityTool/verify_cert.c +++ b/SecurityTool/verify_cert.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2006,2010,2012,2014 Apple Inc. All Rights Reserved. + * Copyright (c) 2006,2010,2012,2014-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, @@ -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@ * * verify_cert.c @@ -35,6 +35,7 @@ #include #include "trusted_cert_utils.h" #include "verify_cert.h" +#include /* * Read file as a cert, add to a CFArray, creating the array if necessary @@ -66,15 +67,19 @@ verify_cert(int argc, char * const *argv) CFMutableArrayRef certs = NULL; CFMutableArrayRef roots = NULL; CFMutableArrayRef keychains = NULL; + CFMutableArrayRef policies = NULL; const CSSM_OID *policy = &CSSMOID_APPLE_X509_BASIC; SecKeychainRef kcRef = NULL; int ourRtn = 0; bool quiet = false; + bool client = false; SecPolicyRef policyRef = NULL; + SecPolicyRef revPolicyRef = NULL; SecTrustRef trustRef = NULL; SecPolicySearchRef searchRef = NULL; const char *emailAddrs = NULL; const char *sslHost = NULL; + const char *name = NULL; CSSM_APPLE_TP_SSL_OPTIONS sslOpts; CSSM_APPLE_TP_SMIME_OPTIONS smimeOpts; CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0; @@ -84,9 +89,10 @@ verify_cert(int argc, char * const *argv) CFDataRef cfActionData = NULL; SecTrustResultType resultType; OSStatus ocrtn; - struct tm time; - CFGregorianDate gregorianDate; - CFDateRef dateRef = NULL; + struct tm time; + CFGregorianDate gregorianDate; + CFDateRef dateRef = NULL; + CFOptionFlags revOptions = 0; if(argc < 2) { return 2; /* @@@ Return 2 triggers usage message. */ @@ -94,8 +100,11 @@ verify_cert(int argc, char * const *argv) /* permit network cert fetch unless explicitly turned off with '-L' */ actionFlags |= CSSM_TP_ACTION_FETCH_CERT_FROM_NET; optind = 1; - while ((arg = getopt(argc, argv, "c:r:p:k:e:s:d:Llnq")) != -1) { + while ((arg = getopt(argc, argv, "Cc:r:p:k:e:s:d:LlNnqR:")) != -1) { switch (arg) { + case 'C': + client = true; + break; case 'c': /* this can be specified multiple times */ if(addCertFile(optarg, &certs)) { @@ -138,10 +147,21 @@ verify_cert(int argc, char * const *argv) case 'l': actionFlags |= CSSM_TP_ACTION_LEAF_IS_CA; break; - case 'n': + case 'n': { + /* Legacy macOS used 'n' as the "no keychain search list" flag. + iOS interprets it as the name option, with one argument. + */ + char *o = argv[optind]; + if (o && o[0] != '-') { + name = optarg; + ++optind; + break; + } + } /* intentional fall-through to "no keychains" case, if no arg */ + case 'N': /* No keychains, signalled by empty keychain array */ if(keychains != NULL) { - fprintf(stderr, "-k and -n are mutually exclusive\n"); + fprintf(stderr, "-k and -%c are mutually exclusive\n", arg); ourRtn = 2; goto errOut; } @@ -156,27 +176,29 @@ verify_cert(int argc, char * const *argv) case 'q': quiet = true; break; - case 'd': - memset(&time, 0, sizeof(struct tm)); - if (strptime(optarg, "%Y-%m-%d-%H:%M:%S", &time) == NULL) { - if (strptime(optarg, "%Y-%m-%d", &time) == NULL) { - fprintf(stderr, "Date processing error\n"); - ourRtn = 2; - goto errOut; - } - } - - gregorianDate.second = time.tm_sec; - gregorianDate.minute = time.tm_min; - gregorianDate.hour = time.tm_hour; - gregorianDate.day = time.tm_mday; - gregorianDate.month = time.tm_mon + 1; - gregorianDate.year = time.tm_year + 1900; - - if (dateRef == NULL) { - dateRef = CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(gregorianDate, NULL)); - } - break; + case 'd': + memset(&time, 0, sizeof(struct tm)); + if (strptime(optarg, "%Y-%m-%d-%H:%M:%S", &time) == NULL) { + if (strptime(optarg, "%Y-%m-%d", &time) == NULL) { + fprintf(stderr, "Date processing error\n"); + ourRtn = 2; + goto errOut; + } + } + gregorianDate.second = time.tm_sec; + gregorianDate.minute = time.tm_min; + gregorianDate.hour = time.tm_hour; + gregorianDate.day = time.tm_mday; + gregorianDate.month = time.tm_mon + 1; + gregorianDate.year = time.tm_year + 1900; + + if (dateRef == NULL) { + dateRef = CFDateCreate(NULL, CFGregorianDateGetAbsoluteTime(gregorianDate, NULL)); + } + break; + case 'R': + revOptions |= revCheckOptionStringToFlags(optarg); + break; default: ourRtn = 2; goto errOut; @@ -224,11 +246,13 @@ verify_cert(int argc, char * const *argv) /* per-policy options */ if(compareOids(policy, &CSSMOID_APPLE_TP_SSL) || compareOids(policy, &CSSMOID_APPLE_TP_APPLEID_SHARING)) { - if(sslHost != NULL) { + const char *nameStr = (name) ? name : ((sslHost) ? sslHost : NULL); + if(nameStr) { memset(&sslOpts, 0, sizeof(sslOpts)); sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION; - sslOpts.ServerName = sslHost; - sslOpts.ServerNameLen = (uint32) strlen(sslHost); + sslOpts.ServerName = nameStr; + sslOpts.ServerNameLen = (uint32) strlen(nameStr); + sslOpts.Flags = (client) ? CSSM_APPLE_TP_SSL_CLIENT : 0; optionData.Data = (uint8 *)&sslOpts; optionData.Length = sizeof(sslOpts); ortn = SecPolicySetValue(policyRef, &optionData); @@ -240,11 +264,12 @@ verify_cert(int argc, char * const *argv) } } if(compareOids(policy, &CSSMOID_APPLE_TP_SMIME)) { - if(emailAddrs != NULL) { + const char *nameStr = (name) ? name : ((emailAddrs) ? emailAddrs : NULL); + if(nameStr) { memset(&smimeOpts, 0, sizeof(smimeOpts)); smimeOpts.Version = CSSM_APPLE_TP_SMIME_OPTS_VERSION; - smimeOpts.SenderEmail = emailAddrs; - smimeOpts.SenderEmailLen = (uint32) strlen(emailAddrs); + smimeOpts.SenderEmail = nameStr; + smimeOpts.SenderEmailLen = (uint32) strlen(nameStr); optionData.Data = (uint8 *)&smimeOpts; optionData.Length = sizeof(smimeOpts); ortn = SecPolicySetValue(policyRef, &optionData); @@ -256,8 +281,17 @@ verify_cert(int argc, char * const *argv) } } - /* Now create a SecTrustRef and set its options */ - ortn = SecTrustCreateWithCertificates(certs, policyRef, &trustRef); + /* create policies array */ + policies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(policies, policyRef); + /* add optional SecPolicyRef for revocation, if specified */ + if(revOptions != 0) { + revPolicyRef = SecPolicyCreateRevocation(revOptions); + CFArrayAppendValue(policies, revPolicyRef); + } + + /* create trust reference from certs and policies */ + ortn = SecTrustCreateWithCertificates(certs, policies, &trustRef); if(ortn) { cssmPerror("SecTrustCreateWithCertificates", ortn); ourRtn = 1; @@ -293,14 +327,14 @@ verify_cert(int argc, char * const *argv) goto errOut; } } - if(dateRef != NULL) { - ortn = SecTrustSetVerifyDate(trustRef, dateRef); - if(ortn) { - cssmPerror("SecTrustSetVerifyDate", ortn); - ourRtn = 1; - goto errOut; - } - } + if(dateRef != NULL) { + ortn = SecTrustSetVerifyDate(trustRef, dateRef); + if(ortn) { + cssmPerror("SecTrustSetVerifyDate", ortn); + ourRtn = 1; + goto errOut; + } + } /* GO */ ortn = SecTrustEvaluate(trustRef, &resultType); @@ -322,16 +356,6 @@ verify_cert(int argc, char * const *argv) } ourRtn = 1; break; - case kSecTrustResultConfirm: - /* - * Cert chain may well have verified OK, but user has flagged - * one of these certs as untrustable. - */ - if(!quiet) { - fprintf(stderr, "SecTrustEvaluate result: kSecTrustResultConfirm\n"); - } - ourRtn = 1; - break; default: ourRtn = 1; if(!quiet) { @@ -351,10 +375,13 @@ verify_cert(int argc, char * const *argv) printf("...certificate verification successful.\n"); } errOut: + CFReleaseNull(dateRef); /* cleanup */ CFRELEASE(certs); CFRELEASE(roots); CFRELEASE(keychains); + CFRELEASE(policies); + CFRELEASE(revPolicyRef); CFRELEASE(policyRef); CFRELEASE(trustRef); CFRELEASE(searchRef); diff --git a/SecurityUnitTests/Info.plist b/SecurityUnitTests/Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/SecurityUnitTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/SecurityUnitTests/SecurityUnitTests.m b/SecurityUnitTests/SecurityUnitTests.m new file mode 100644 index 00000000..0f5fe403 --- /dev/null +++ b/SecurityUnitTests/SecurityUnitTests.m @@ -0,0 +1,43 @@ +/* + * 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 + +@interface SecurityUnitTests : XCTestCase +@end + +@implementation SecurityUnitTests + +- (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"); + XCTAssertNotNil(attributes[@"bsiz"], @"the SecKey attributes dictionary value for 'bsiz' is nil"); +} + +@end diff --git a/SharedWebCredentialViewService/SWCViewController.m b/SharedWebCredentialViewService/SWCViewController.m index 336232b0..f48c2a73 100755 --- a/SharedWebCredentialViewService/SWCViewController.m +++ b/SharedWebCredentialViewService/SWCViewController.m @@ -296,13 +296,18 @@ const NSString* SWC_SERVER_KEY = @"srvr"; CFRelease(credentialList); } + table.frame = CGRectMake(0.0, 0.0, 300.0, 45.0); + [table layoutIfNeeded]; // so autolayout can do its thing and then we can measure a cell + UITableViewCell* cell = table.visibleCells.firstObject; + CGFloat heightForOneRow = cell ? CGRectGetHeight(cell.frame) : 45.0; NSDictionary* views = NSDictionaryOfVariableBindings(table); if ([_credentials count] > 2) { - NSDictionary *metrics = @{@"height":@120.0}; + CGFloat manyCredentialsHeight = CGFloatMax((heightForOneRow * 2) + 30.0, 120.0); + NSDictionary *metrics = @{@"height":@(manyCredentialsHeight)}; [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[table]-|" options:0 metrics:metrics views:views]]; [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]-|" options:0 metrics:metrics views:views]]; @@ -310,24 +315,24 @@ const NSString* SWC_SERVER_KEY = @"srvr"; table.layer.borderWidth = 1.0 / scale; table.layer.borderColor = [UIColor colorWithWhite:.5 alpha:.5].CGColor; - [self setPreferredContentSize:CGSizeMake(0,140)]; + [self setPreferredContentSize:CGSizeMake(0, manyCredentialsHeight + 20.0)]; } else if ([_credentials count] == 2) { - NSDictionary *metrics = @{@"height":@90.0}; + NSDictionary *metrics = @{@"height":@(heightForOneRow * 2)}; [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[table]|" options:0 metrics:metrics views:views]]; [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]-|" options:0 metrics:metrics views:views]]; - [self setPreferredContentSize:CGSizeMake(0,90)]; + [self setPreferredContentSize:CGSizeMake(0, heightForOneRow * 2)]; [table setScrollEnabled: NO]; } else { // [_credentials count] == 1 - NSDictionary *metrics = @{@"height":@45.0}; + NSDictionary *metrics = @{@"height":@(heightForOneRow)}; [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[table]|" options:0 metrics:metrics views:views]]; [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[table(height)]|" options:0 metrics:metrics views:views]]; - [self setPreferredContentSize:CGSizeMake(0,45)]; + [self setPreferredContentSize:CGSizeMake(0, heightForOneRow)]; [table setScrollEnabled: NO]; } @@ -345,6 +350,7 @@ const NSString* SWC_SERVER_KEY = @"srvr"; _selectedCell = [NSIndexPath indexPathForItem:0 inSection: 0]; SWCItemCell *cell = (SWCItemCell *)[_table cellForRowAtIndexPath: _selectedCell]; [cell setTicked: YES]; + [cell layoutSubviews]; [_table selectRowAtIndexPath: _selectedCell animated: NO scrollPosition: UITableViewScrollPositionTop]; CFErrorRef error = NULL; diff --git a/base/SecBase.h b/base/SecBase.h index b42b3486..4154dab2 100644 --- a/base/SecBase.h +++ b/base/SecBase.h @@ -28,6 +28,16 @@ #include #include +// Truth table for following declarations: +// +// TARGET_OS_OSX TARGET_OS_OSX TARGET_OS_IPHONE TARGET_OS_IPHONE +// SEC_IOS_ON_OSX SEC_IOS_ON_OSX +// =================================================================================================== +// SEC_OS_IPHONE 0 1 1 1 +// SEC_OS_IPHONE_INCLUDES 0 0 1 1 +// SEC_OS_OSX 1 0 0 0 +// SEC_OS_OSX_INCLUDES 1 1 0 0 + #if TARGET_OS_OSX #ifdef SEC_IOS_ON_OSX #define SEC_OS_IPHONE 1 @@ -142,7 +152,7 @@ struct SecKeychainAttribute { SecKeychainAttrType tag; UInt32 length; - void *data; + void * __nullable data; }; typedef struct SecKeychainAttribute SecKeychainAttribute; @@ -161,7 +171,7 @@ typedef SecKeychainAttribute *SecKeychainAttributePtr; struct SecKeychainAttributeList { UInt32 count; - SecKeychainAttribute *attr; + SecKeychainAttribute * __nullable attr; }; typedef struct SecKeychainAttributeList SecKeychainAttributeList; @@ -207,7 +217,7 @@ struct SecKeychainAttributeInfo { UInt32 count; UInt32 *tag; - UInt32 *format; + UInt32 * __nullable format; }; typedef struct SecKeychainAttributeInfo SecKeychainAttributeInfo; @@ -302,7 +312,7 @@ CF_ENUM(OSStatus) errSecUnimplemented = -4, /* Function or operation not implemented. */ errSecDskFull = -34, errSecIO = -36, /*I/O error (bummers)*/ - errSecOpWr = -49, /*file already open with with write permission*/ + errSecOpWr = -49, /*file already open with write permission*/ errSecParam = -50, /* One or more parameters passed to a function were not valid. */ errSecWrPerm = -61, /* write permissions error*/ errSecAllocate = -108, /* Failed to allocate memory. */ @@ -312,6 +322,8 @@ CF_ENUM(OSStatus) errSecInternalComponent = -2070, errSecCoreFoundationUnknown = -4960, + errSecMissingEntitlement = -34018, /* A required entitlement isn't present. */ + errSecNotAvailable = -25291, /* No keychain is available. You may need to restart your computer. */ errSecReadOnly = -25292, /* This keychain cannot be modified. */ errSecAuthFailed = -25293, /* The user name or passphrase you entered is not correct. */ diff --git a/base/SecBasePriv.h b/base/SecBasePriv.h index 10e245b0..7c07fe28 100644 --- a/base/SecBasePriv.h +++ b/base/SecBasePriv.h @@ -85,7 +85,6 @@ enum errSecMatchLimitUnsupported = errSecParam, // -34015, /* The caller passed in a kSecMatchLimit key to a call which does not support limits. */ errSecItemIllegalQuery = errSecParam, // -34016, /* The caller passed in a query which contained too many keys. */ errSecWaitForCallback = -34017, /* This operation is incomplete, until the callback is invoked (not an error). */ - errSecMissingEntitlement = -34018, /* Internal error when a required entitlement isn't present. */ errSecUpgradePending = -34019, /* Error returned if keychain database needs a schema migration but the device is locked, clients should wait for a device unlock notification and retry the command. */ errSecMPSignatureInvalid = -25327, /* Signature invalid on MP message */ diff --git a/base/SecRandom.h b/base/SecRandom.h index 5aff4248..862d6103 100644 --- a/base/SecRandom.h +++ b/base/SecRandom.h @@ -41,7 +41,7 @@ CF_IMPLICIT_BRIDGING_ENABLED /*! @typedef SecRandomRef - @abstract Reference to a (psuedo) random number generator. + @abstract Reference to a (pseudo) random number generator. */ typedef const struct __SecRandom * SecRandomRef; @@ -54,10 +54,9 @@ extern const SecRandomRef kSecRandomDefault @function SecRandomCopyBytes @abstract Return count random bytes in *bytes, allocated by the caller. It is critical to check the return value for error - @result Return 0 on success or -1 if something went wrong, check errno - to find out the real error. + @result Return 0 on success, any other value on failure. */ -int SecRandomCopyBytes(SecRandomRef __nullable rnd, size_t count, uint8_t *bytes) +int SecRandomCopyBytes(SecRandomRef __nullable rnd, size_t count, void *bytes) __attribute__ ((warn_unused_result)) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0); diff --git a/base/Security.h b/base/Security.h index 592fc2ba..3fd993d4 100644 --- a/base/Security.h +++ b/base/Security.h @@ -35,7 +35,7 @@ #include #include -#if SEC_OS_IPHONE +#if SEC_OS_IPHONE_INCLUDES #include #endif @@ -43,7 +43,7 @@ #include #endif -#if SEC_OS_OSX +#if SEC_OS_OSX_INCLUDES /* CDSA */ #include #include diff --git a/cssm/certextensions.h b/cssm/certextensions.h index d38a30a5..cf0c799f 100644 --- a/cssm/certextensions.h +++ b/cssm/certextensions.h @@ -31,6 +31,7 @@ #if SEC_OS_OSX #include +#include /* CSSM_X509_RDN_PTR */ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" diff --git a/cssm/cssmapple.h b/cssm/cssmapple.h index 3870a86d..9823cd3f 100644 --- a/cssm/cssmapple.h +++ b/cssm/cssmapple.h @@ -94,6 +94,7 @@ enum CSSM_WORDID_PREAUTH_SOURCE, CSSM_WORDID_ASYMMETRIC_KEY, CSSM_WORDID_PARTITION, + CSSM_WORDID_KEYBAG_KEY, CSSM_WORDID__FIRST_UNUSED }; @@ -121,7 +122,8 @@ enum CSSM_SAMPLE_TYPE_RETRY_ID = CSSM_WORDID_PROPAGATE, CSSM_SAMPLE_TYPE_SYMMETRIC_KEY = CSSM_WORDID_SYMMETRIC_KEY, CSSM_SAMPLE_TYPE_PREAUTH = CSSM_WORDID_PREAUTH, - CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY = CSSM_WORDID_ASYMMETRIC_KEY + CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY = CSSM_WORDID_ASYMMETRIC_KEY, + CSSM_SAMPLE_TYPE_KEYBAG_KEY = CSSM_WORDID_KEYBAG_KEY, // there is no CSSM_SAMPLE_TYPE_PREAUTH_SOURCE }; @@ -408,7 +410,8 @@ enum { /* UNLOCK_REFERRAL "type" attribute values */ enum { CSSM_APPLE_UNLOCK_TYPE_KEY_DIRECT = 1, // master secret key stored directly - CSSM_APPLE_UNLOCK_TYPE_WRAPPED_PRIVATE = 2 // master key wrapped by public key + CSSM_APPLE_UNLOCK_TYPE_WRAPPED_PRIVATE = 2, // master key wrapped by public key + CSSM_APPLE_UNLOCK_TYPE_KEYBAG = 3 // master key wrapped via keybag }; /* Apple DL private error codes. */ diff --git a/header_symlinks/iOS/Security/CSCommon.h b/header_symlinks/iOS/Security/CSCommon.h new file mode 120000 index 00000000..a2c01617 --- /dev/null +++ b/header_symlinks/iOS/Security/CSCommon.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/CSCommon.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/CSCommonPriv.h b/header_symlinks/iOS/Security/CSCommonPriv.h new file mode 120000 index 00000000..fc11d821 --- /dev/null +++ b/header_symlinks/iOS/Security/CSCommonPriv.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/CSCommonPriv.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/CodeSigning.h b/header_symlinks/iOS/Security/CodeSigning.h new file mode 120000 index 00000000..3f02ac7b --- /dev/null +++ b/header_symlinks/iOS/Security/CodeSigning.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/CodeSigning.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/SecCode.h b/header_symlinks/iOS/Security/SecCode.h new file mode 120000 index 00000000..ed9f8f59 --- /dev/null +++ b/header_symlinks/iOS/Security/SecCode.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/SecCode.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/SecCodeHost.h b/header_symlinks/iOS/Security/SecCodeHost.h new file mode 120000 index 00000000..484bbaeb --- /dev/null +++ b/header_symlinks/iOS/Security/SecCodeHost.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/SecCodeHost.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/SecCodePriv.h b/header_symlinks/iOS/Security/SecCodePriv.h new file mode 120000 index 00000000..fedda6e6 --- /dev/null +++ b/header_symlinks/iOS/Security/SecCodePriv.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/SecCodePriv.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/SecCodeSigner.h b/header_symlinks/iOS/Security/SecCodeSigner.h new file mode 120000 index 00000000..3f2e50d6 --- /dev/null +++ b/header_symlinks/iOS/Security/SecCodeSigner.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/SecCodeSigner.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/SecRequirement.h b/header_symlinks/iOS/Security/SecRequirement.h new file mode 120000 index 00000000..d1a9c5be --- /dev/null +++ b/header_symlinks/iOS/Security/SecRequirement.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/SecRequirement.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/SecRequirementPriv.h b/header_symlinks/iOS/Security/SecRequirementPriv.h new file mode 120000 index 00000000..dcfaa942 --- /dev/null +++ b/header_symlinks/iOS/Security/SecRequirementPriv.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/SecRequirementPriv.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/SecStaticCode.h b/header_symlinks/iOS/Security/SecStaticCode.h new file mode 120000 index 00000000..a3d61d95 --- /dev/null +++ b/header_symlinks/iOS/Security/SecStaticCode.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/SecStaticCode.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/SecStaticCodePriv.h b/header_symlinks/iOS/Security/SecStaticCodePriv.h new file mode 120000 index 00000000..82e25d4a --- /dev/null +++ b/header_symlinks/iOS/Security/SecStaticCodePriv.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_codesigning/lib/SecStaticCodePriv.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/X509Templates.h b/header_symlinks/iOS/Security/X509Templates.h new file mode 120000 index 00000000..4e02f5b8 --- /dev/null +++ b/header_symlinks/iOS/Security/X509Templates.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_asn1/lib/X509Templates.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/keyTemplates.h b/header_symlinks/iOS/Security/keyTemplates.h new file mode 120000 index 00000000..86bd66db --- /dev/null +++ b/header_symlinks/iOS/Security/keyTemplates.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_asn1/lib/keyTemplates.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/nameTemplates.h b/header_symlinks/iOS/Security/nameTemplates.h new file mode 120000 index 00000000..1af658bf --- /dev/null +++ b/header_symlinks/iOS/Security/nameTemplates.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_asn1/lib/nameTemplates.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/oidsattr.h b/header_symlinks/iOS/Security/oidsattr.h new file mode 120000 index 00000000..2c68f9a5 --- /dev/null +++ b/header_symlinks/iOS/Security/oidsattr.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_asn1/lib/oidsattr.h \ No newline at end of file diff --git a/header_symlinks/iOS/Security/osxcode.h b/header_symlinks/iOS/Security/osxcode.h new file mode 120000 index 00000000..16f8536a --- /dev/null +++ b/header_symlinks/iOS/Security/osxcode.h @@ -0,0 +1 @@ +./../../OSX/libsecurity_utilities/lib/osxcode.h \ No newline at end of file diff --git a/header_symlinks/macOS/Security/SecSharedCredential.h b/header_symlinks/macOS/Security/SecSharedCredential.h new file mode 120000 index 00000000..645d048c --- /dev/null +++ b/header_symlinks/macOS/Security/SecSharedCredential.h @@ -0,0 +1 @@ +./../../keychain/SecSharedCredential.h \ No newline at end of file diff --git a/OSX/sec/Security/SecAccessControl.h b/keychain/SecAccessControl.h similarity index 100% rename from OSX/sec/Security/SecAccessControl.h rename to keychain/SecAccessControl.h diff --git a/keychain/SecImportExport.h b/keychain/SecImportExport.h index 019d8357..225ad9af 100644 --- a/keychain/SecImportExport.h +++ b/keychain/SecImportExport.h @@ -154,7 +154,7 @@ typedef struct /* for import and export */ uint32_t version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */ SecKeyImportExportFlags flags; /* SecKeyImportExportFlags bits */ - CFTypeRef passphrase; /* kSecFormatPKCS12, kSecFormatWrapped* + CFTypeRef __nullable passphrase; /* kSecFormatPKCS12, kSecFormatWrapped* * formats only. Legal types are * CFStringRef and CFDataRef. */ CFStringRef alertTitle; /* title of secure passphrase alert panel */ @@ -174,11 +174,11 @@ typedef struct /* for import and export */ uint32_t version; /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */ SecKeyImportExportFlags flags; /* SecKeyImportExportFlags bits */ - CFTypeRef passphrase; /* kSecFormatPKCS12, kSecFormatWrapped* + CFTypeRef __nullable passphrase; /* kSecFormatPKCS12, kSecFormatWrapped* * formats only. Legal types are * CFStringRef and CFDataRef. */ - CFStringRef alertTitle; /* title of secure passphrase alert panel */ - CFStringRef alertPrompt; /* prompt in secure passphrase alert panel */ + CFStringRef __nullable alertTitle; /* title of secure passphrase alert panel */ + CFStringRef __nullable alertPrompt; /* prompt in secure passphrase alert panel */ /* for import only */ SecAccessRef __nullable accessRef; /* specifies the initial ACL of imported diff --git a/keychain/SecItem.h b/keychain/SecItem.h index 680bf7ec..f34d6957 100644 --- a/keychain/SecItem.h +++ b/keychain/SecItem.h @@ -149,9 +149,9 @@ extern const CFStringRef kSecClassIdentity kSecAttrIsPermanent kSecAttrApplicationTag kSecAttrKeyType - kSecAttrPRF (iOS only) - kSecAttrSalt (iOS only) - kSecAttrRounds (iOS only) + kSecAttrPRF (OS X only) + kSecAttrSalt (OS X only) + kSecAttrRounds (OS X only) kSecAttrKeySizeInBits kSecAttrEffectiveKeySize kSecAttrCanEncrypt @@ -399,12 +399,12 @@ extern const CFStringRef kSecClassIdentity @constant kSecAttrPRF Specifies a dictionary key whose value is the PRF (pseudo-random function) for this key (see "kSecAttrPRF Value Constants".) - iOS only. + OS X only. @constant kSecAttrSalt Specifies a dictionary key whose value is a - CFData containing the salt to use for this key. iOS only. + CFData containing the salt to use for this key. OS X only. @constant kSecAttrRounds Specifies a dictionary key whose value is the number of rounds for the pseudo-random function specified by kSecAttrPRF. - iOS only. + OS X only. @constant kSecAttrKeySizeInBits Specifies a dictionary key whose value is a CFNumberRef indicating the number of bits in this key. @constant kSecAttrEffectiveKeySize Specifies a dictionary key whose value @@ -550,6 +550,10 @@ extern const CFStringRef kSecAttrSyncViewHint __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); extern const CFStringRef kSecAttrTokenID __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); +extern const CFStringRef kSecAttrPersistantReference + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrPersistentReference +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); /*! @enum kSecAttrAccessible Value Constants diff --git a/keychain/SecItemPriv.h b/keychain/SecItemPriv.h index 5ed03647..80028dc0 100644 --- a/keychain/SecItemPriv.h +++ b/keychain/SecItemPriv.h @@ -35,6 +35,7 @@ #include #include #include +#include #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) #include @@ -283,10 +284,46 @@ extern const CFStringRef kSecAttrSyncViewHint __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); extern const CFStringRef kSecAttrMultiUser __OSX_AVAILABLE(10.11.5) __IOS_AVAILABLE(9.3) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); + +/* This will force the syncing system to derive an item's plaintext synchronization id from its primary key. + * This might leak primary key information, but will cause syncing devices to discover sync conflicts sooner. + * Protected by the kSecEntitlementPrivateCKKSPlaintextFields entitlement. + * + * Will only be respected during a SecItemAdd. + */ +extern const CFStringRef kSecAttrDeriveSyncIDFromItemAttributes +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrPCSPlaintextServiceIdentifier + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrPCSPlaintextPublicKey + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrPCSPlaintextPublicIdentity + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.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 __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const CFStringRef kSecAttrUUID + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrSysBound + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrSHA1 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +#define kSecSecAttrSysBoundNot 0 +#define kSecSecAttrSysBoundPreserveDuringRestore 1 +extern const CFStringRef kSecAttrKeyTypeECSECPrimeRandomPKA + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecAttrKeyTypeSecureEnclaveAttestation + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +// Should not be used, use kSecAttrTokenOID instead. +extern const CFStringRef kSecAttrSecureEnclaveKeyBlob + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + /*! @enum kSecAttrAccessible Value Constants (Private) @constant kSecAttrAccessibleAlwaysPrivate Private alias for kSecAttrAccessibleAlways, @@ -312,7 +349,7 @@ extern const CFStringRef kSecAttrViewHintPCSiCloudBackup; extern const CFStringRef kSecAttrViewHintPCSNotes; extern const CFStringRef kSecAttrViewHintPCSiMessage; #if SEC_OS_IPHONE -extern const CFStringRef kSecAttrViewHintFeldspar; +extern const CFStringRef kSecAttrViewHintPCSFeldspar; #endif /* SEC_OS_IPHONE */ extern const CFStringRef kSecAttrViewHintPCSSharing; @@ -321,6 +358,13 @@ extern const CFStringRef kSecAttrViewHintHomeKit; extern const CFStringRef kSecAttrViewHintThumper; extern const CFStringRef kSecAttrViewHintContinuityUnlock; extern const CFStringRef kSecAttrViewHintAccessoryPairing; +extern const CFStringRef kSecAttrViewHintNanoRegistry; +extern const CFStringRef kSecAttrViewHintWatchMigration; +extern const CFStringRef kSecAttrViewHintEngram; +extern const CFStringRef kSecAttrViewHintManatee; +extern const CFStringRef kSecAttrViewHintAutoUnlock; +extern const CFStringRef kSecAttrViewHintHealth; + #if SEC_OS_IPHONE extern const CFStringRef kSecUseSystemKeychain @@ -365,6 +409,10 @@ extern const CFStringRef kSecUseSyncBubbleKeychain the caller name for which the application is attempting to authenticate. The caller must have 'com.apple.private.LocalAuthentication.CallerName' entitlement set to YES to use this feature, otherwise it is ignored. + @constant kSecUseTokenRawItems If set to true, token-based items (i.e. those + which have non-empty kSecAttrTokenID are not going through client-side + postprocessing, only raw form stored in the database is listed. This + flag is ignored in other operations than SecItemCopyMatching(). */ extern const CFStringRef kSecUseTombstones __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); @@ -372,6 +420,28 @@ extern const CFStringRef kSecUseCredentialReference __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); extern const CFStringRef kSecUseCallerName __OSX_AVAILABLE(10.11.4) __IOS_AVAILABLE(9.3) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); +extern const CFStringRef kSecUseTokenRawItems + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +extern const CFStringRef kSOSInternalAccessGroup + __OSX_AVAILABLE(10.9) __IOS_AVAILABLE(7.0) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3); + +/*! + @enum kSecAttrTokenID Value Constants + @discussion Predefined item attribute constant used to get or set values + in a dictionary. The kSecAttrTokenID constant is the key and its value + can be kSecAttrTokenIDSecureEnclave. + @constant kSecAttrTokenIDKeyAppleStore Specifies well-known identifier of + the token implemented using libaks (AppleKeyStore). This token is identical to + kSecAttrTokenIDSecureEnclave for devices which support Secure Enclave and + silently falls back to in-kernel emulation for those devices which do not + have Secure Enclave support. + */ +extern const CFStringRef kSecAttrTokenIDAppleKeyStore + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(3.0); + + +extern const CFStringRef kSecNetworkExtensionAccessGroupSuffix; /*! @function SecItemCopyDisplayNames @@ -393,12 +463,57 @@ OSStatus SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames); /*! @function SecItemDeleteAll - @abstract Removes all items from the keychain and added root certificates - from the trust store. + @abstract Removes all items from the keychain. @result A result code. See "Security Error Codes" (SecBase.h). */ OSStatus SecItemDeleteAll(void); +/*! + @function _SecItemAddAndNotifyOnSync + @abstract Adds an item to the keychain, and calls syncCallback when the item has synced + @param attributes Attributes dictionary to be passed to SecItemAdd + @param result Result reference to be passed to SecItemAdd + @param syncCallback Block to be executed after the item has synced or failed to sync + @result The result code returned from SecItemAdd + */ +OSStatus _SecItemAddAndNotifyOnSync(CFDictionaryRef attributes, CFTypeRef * CF_RETURNS_RETAINED result, void (^syncCallback)(bool didSync, CFErrorRef error)); + +/*! + @function SecItemSetCurrentItemAcrossAllDevices + @abstract Sets 'new current item' to be the 'current' item in CloudKit for the given identifier. + */ +void SecItemSetCurrentItemAcrossAllDevices(CFStringRef accessGroup, + CFStringRef identifier, + CFStringRef viewHint, + CFDataRef newCurrentItemReference, + CFDataRef newCurrentItemHash, + CFDataRef oldCurrentItemReference, + CFDataRef oldCurrentItemHash, + void (^complete)(CFErrorRef error)); + +/*! + @function SecItemFetchCurrentItemAcrossAllDevices + @abstract Fetches the locally cached idea of which keychain item is 'current' across this iCloud account + for the given access group and identifier. + @param accessGroup The accessGroup of your process and the expected current item + @param identifier Which 'current' item you're interested in. Freeform, but should match the ID given to + SecItemSetCurrentItemAcrossAllDevices. + @param viewHint The keychain view hint for your items. + @param fetchCloudValue If false, will return the local machine's cached idea of which item is current. If true, + performs a CloudKit operation to determine the most up-to-date version. + @param complete Called to return values: a persistent ref to the current item, if such an item exists. Otherwise, error. + */ +void SecItemFetchCurrentItemAcrossAllDevices(CFStringRef accessGroup, + CFStringRef identifier, + CFStringRef viewHint, + bool fetchCloudValue, + void (^complete)(CFDataRef persistentRef, CFErrorRef error)); + + +#if __OBJC__ +void _SecItemFetchDigests(NSString *itemClass, NSString *accessGroup, void (^complete)(NSArray *, NSError *)); +#endif + #if SEC_OS_IPHONE /*! @function SecItemDeleteAllWithAccessGroups @@ -452,6 +567,8 @@ OSStatus SecErrorGetOSStatus(CFErrorRef error); bool _SecKeychainRollKeys(bool force, CFErrorRef *error); CFDictionaryRef _SecSecuritydCopyWhoAmI(CFErrorRef *error); +XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopyCKKSEndpoint(CFErrorRef *error); +XPC_RETURNS_RETAINED xpc_endpoint_t _SecSecuritydCopySOSStatusEndpoint(CFErrorRef *error); #if SEC_OS_IPHONE bool _SecSyncBubbleTransfer(CFArrayRef services, uid_t uid, CFErrorRef *error); @@ -464,6 +581,8 @@ bool _SecSystemKeychainTransfer(CFErrorRef *error); bool _SecSyncDeleteUserViews(uid_t uid, CFErrorRef *error); #endif /* SEC_OS_IPHONE */ + + OSStatus SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes); #if SEC_OS_OSX @@ -506,7 +625,7 @@ SecItemUpdateWithError(CFDictionaryRef inQuery, #if SEC_OS_OSX /*! @function SecItemParentCachePurge - @abstract Clear the cache of parent certificates used in SecItemCopyParentCertificates. + @abstract Clear the cache of parent certificates used in SecItemCopyParentCertificates_osx. */ void SecItemParentCachePurge(); #endif @@ -514,7 +633,7 @@ void SecItemParentCachePurge(); #if SEC_OS_OSX_INCLUDES /*! - @function SecItemCopyParentCertificates + @function SecItemCopyParentCertificates_osx @abstract Retrieve an array of possible issuing certificates for a given certificate. @param certificate A reference to a certificate whose issuers are being sought. @param context Pass NULL in this parameter to indicate that the default certificate @@ -525,7 +644,7 @@ void SecItemParentCachePurge(); of the signature is performed by this function; its purpose is only to provide a list of candidate certificates. */ -CFArrayRef SecItemCopyParentCertificates(SecCertificateRef certificate, void *context) +CFArrayRef SecItemCopyParentCertificates_osx(SecCertificateRef certificate, void *context) __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA); /*! diff --git a/keychain/SecKey.h b/keychain/SecKey.h index 3abf8086..b18737ba 100644 --- a/keychain/SecKey.h +++ b/keychain/SecKey.h @@ -619,6 +619,11 @@ SecKeyRef SecKeyUnwrapSymmetric(CFDataRef _Nullable * __nonnull keyToUnwrap, * kSecAttrCanWrap default false for private keys, true for public keys * kSecAttrCanUnwrap default true for private keys, false for public keys + NOTE: The function always saves keys in the keychain on macOS and as such attribute + kSecAttrIsPermanent is ignored. The function respects attribute kSecAttrIsPermanent + on iOS, tvOS and watchOS. + It is recommended to use SecKeyCreateRandomKey() which respects kSecAttrIsPermanent + on all platforms. */ OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef * _Nullable CF_RETURNS_RETAINED publicKey, SecKeyRef * _Nullable CF_RETURNS_RETAINED privateKey) @@ -924,6 +929,46 @@ __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AV @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512 RSA signature with PKCS#1 padding, SHA-512 digest is generated 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. + PSS padding is calculated using MGF1 with SHA1 and saltLength parameter is set to 20 (SHA-1 output size). + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA224 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-224 generated digest. + PSS padding is calculated using MGF1 with SHA224 and saltLength parameter is set to 28 (SHA-224 output size). + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA256 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-256 generated digest. + PSS padding is calculated using MGF1 with SHA256 and saltLength parameter is set to 32 (SHA-256 output size). + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA384 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-384 generated digest. + PSS padding is calculated using MGF1 with SHA384 and saltLength parameter is set to 48 (SHA-384 output size). + + @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA512 + RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-512 generated digest. + 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. + 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. + 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. + 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. + 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. + 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. @@ -1029,75 +1074,131 @@ __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AV as authentication data for AES-GCM encryption. @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM in new code. Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1. AES Key size + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1. AES Key size + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1. AES Key size + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1. AES Key size + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA1AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM in new code. Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA224AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1. AES Key size + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1. AES Key size + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA384AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1. AES Key size + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). @constant kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM - ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. - Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1. AES Key size + Legacy ECIES encryption or decryption, use kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM in new code. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512. AES Key size is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG and all-zero 16 byte long IV (initialization vector). + @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA224. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, + and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG, AES key + is first half of KDF output and 16 byte long IV (initialization vector) is second half of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA256. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, + and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG, AES key + is first half of KDF output and 16 byte long IV (initialization vector) is second half of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA384. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, + and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG, AES key + is first half of KDF output and 16 byte long IV (initialization vector) is second half of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA512. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, + and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG, AES key + is first half of KDF output and 16 byte long IV (initialization vector) is second half of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA224. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, + and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG, AES key + is first half of KDF output and 16 byte long IV (initialization vector) is second half of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA256. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, + and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG, AES key + is first half of KDF output and 16 byte long IV (initialization vector) is second half of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA384. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, + and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG, AES key + is first half of KDF output and 16 byte long IV (initialization vector) is second half of KDF output. + + @constant kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM + ECIES encryption or decryption. This algorithm does not limit the size of the message to be encrypted or decrypted. + Encryption is done using AES-GCM with key negotiated by kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA512. AES Key size + is 128bit for EC keys <=256bit and 256bit for bigger EC keys. Ephemeral public key data is used as sharedInfo for KDF, + and static public key data is used as authenticationData for AES-GCM processing. AES-GCM uses 16 bytes long TAG, AES key + is first half of KDF output and 16 byte long IV (initialization vector) is second half of KDF output. + @constant kSecKeyAlgorithmECDHKeyExchangeCofactor Compute shared secret using ECDH cofactor algorithm, suitable only for kSecAttrKeyTypeECSECPrimeRandom keys. This algorithm does not accept any parameters, length of output raw shared secret is given by the length of the key. @@ -1188,6 +1289,28 @@ __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AV extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512 __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA1 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA224 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA256 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA384 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPSSSHA512 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA1 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA224 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA256 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA384 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmRSASignatureMessagePSSSHA512 +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureRFC4754 __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); @@ -1263,6 +1386,24 @@ __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AV extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorX963SHA512AESGCM __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA224AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA256AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA384AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionStandardVariableIVX963SHA512AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA224AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA256AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA384AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const SecKeyAlgorithm kSecKeyAlgorithmECIESEncryptionCofactorVariableIVX963SHA512AESGCM +__OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandard __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); extern const SecKeyAlgorithm kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1 diff --git a/keychain/SecKeyPriv.h b/keychain/SecKeyPriv.h index 6ec03618..b5af4ce9 100644 --- a/keychain/SecKeyPriv.h +++ b/keychain/SecKeyPriv.h @@ -240,6 +240,14 @@ struct __SecKey { }; #endif +/* Create a public key from a CFData containing a SubjectPublicKeyInfo in DER format. */ +SecKeyRef SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator, + CFDataRef subjectPublicKeyInfoData); + +/* Crete a SubjectPublicKeyInfo in DER format from a SecKey */ +CFDataRef SecKeyCopySubjectPublicKeyInfo(SecKeyRef key); + + #if SEC_OS_IPHONE /*! @function SecKeyCreate @@ -260,10 +268,6 @@ SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator, const SecAsn1Oid *oid1, const SecAsn1Item *params, const SecAsn1Item *keyData); -/* Create a public key from a CFData containing a SubjectPublicKeyInfo in DER format. */ -SecKeyRef SecKeyCreateFromSubjectPublicKeyInfoData(CFAllocatorRef allocator, - CFDataRef subjectPublicKeyInfoData); - /* Create public key from private key */ SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey); @@ -770,6 +774,9 @@ __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AV Boolean SecKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); +extern const CFStringRef kSecKeyParameterSETokenAttestationNonce +API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); + /*! @function SecKeyCreateDuplicate @abstract Creates duplicate fo the key. diff --git a/OSX/sec/Security/SecSharedCredential.h b/keychain/SecSharedCredential.h similarity index 100% rename from OSX/sec/Security/SecSharedCredential.h rename to keychain/SecSharedCredential.h diff --git a/keychain/analytics/CKKSPowerCollection.h b/keychain/analytics/CKKSPowerCollection.h new file mode 100644 index 00000000..7e7deb2e --- /dev/null +++ b/keychain/analytics/CKKSPowerCollection.h @@ -0,0 +1,40 @@ +/* + * 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 + +#if OCTAGON + + +@class CKKSOutgoingQueueEntry; + +@interface CKKSPowerCollection : NSOperation + +- (void)storedOQE:(CKKSOutgoingQueueEntry *)oqe; +- (void)deletedOQE:(CKKSOutgoingQueueEntry *)oqe; + +- (void)commit; + +@end + +#endif diff --git a/keychain/analytics/CKKSPowerCollection.m b/keychain/analytics/CKKSPowerCollection.m new file mode 100644 index 00000000..c3bbde44 --- /dev/null +++ b/keychain/analytics/CKKSPowerCollection.m @@ -0,0 +1,83 @@ +/* + * 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 "CKKSPowerCollection.h" +#import "CKKSOutgoingQueueEntry.h" +#import "SecPLWrappers.h" + +#if OCTAGON + +@interface CKKSPowerCollection () +@property (strong) NSMutableDictionary *store; +@property (strong) NSMutableDictionary *delete; +@end + +@implementation CKKSPowerCollection + +- (instancetype)init +{ + if ((self = [super init]) != nil) { + _store = [NSMutableDictionary dictionary]; + _delete = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)addToStatsDictionary:(NSMutableDictionary *)stats key:(NSString *)key +{ + if(!key) { + key = @"access-group-missing"; + } + NSNumber *number = stats[key]; + stats[key] = @([number longValue] + 1); +} + +- (void)storedOQE:(CKKSOutgoingQueueEntry *)oqe +{ + [self addToStatsDictionary:_store key:oqe.accessgroup]; +} +- (void)deletedOQE:(CKKSOutgoingQueueEntry *)oqe +{ + [self addToStatsDictionary:_delete key:oqe.accessgroup]; +} + +-(void)summary:(NSString *)operation stats:(NSDictionary *)stats +{ + for (NSString *accessGroup in stats) { + SecPLLogRegisteredEvent(@"CKKSSyncing", @{ + @"operation" : operation, + @"accessgroup" : accessGroup, + @"items" : stats[accessGroup] + }); + } +} + +- (void)commit +{ + [self summary:@"store" stats:_store]; + [self summary:@"delete" stats:_delete]; +} + +@end + +#endif diff --git a/keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.h b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.h new file mode 100644 index 00000000..88cd982d --- /dev/null +++ b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.h @@ -0,0 +1,50 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from stdin + +#import +#import + +#ifdef __cplusplus +#define AWDKEYCHAINCKKSRATELIMITERAGGREGATEDSCORES_FUNCTION extern "C" +#else +#define AWDKEYCHAINCKKSRATELIMITERAGGREGATEDSCORES_FUNCTION extern +#endif + +@interface AWDKeychainCKKSRateLimiterAggregatedScores : PBCodable +{ + PBRepeatedUInt32 _datas; + uint64_t _timestamp; + NSString *_ratelimitertype; + struct { + int timestamp:1; + } _has; +} + + +@property (nonatomic) BOOL hasTimestamp; +@property (nonatomic) uint64_t timestamp; + +@property (nonatomic, readonly) NSUInteger datasCount; +@property (nonatomic, readonly) uint32_t *datas; +- (void)clearDatas; +- (void)addData:(uint32_t)i; +- (uint32_t)dataAtIndex:(NSUInteger)idx; +- (void)setDatas:(uint32_t *)list count:(NSUInteger)count; + +@property (nonatomic, readonly) BOOL hasRatelimitertype; +@property (nonatomic, retain) NSString *ratelimitertype; + +// Performs a shallow copy into other +- (void)copyTo:(AWDKeychainCKKSRateLimiterAggregatedScores *)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:(AWDKeychainCKKSRateLimiterAggregatedScores *)other; + +AWDKEYCHAINCKKSRATELIMITERAGGREGATEDSCORES_FUNCTION BOOL AWDKeychainCKKSRateLimiterAggregatedScoresReadFrom(__unsafe_unretained AWDKeychainCKKSRateLimiterAggregatedScores *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.m b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.m new file mode 100644 index 00000000..d6a61068 --- /dev/null +++ b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.m @@ -0,0 +1,264 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from stdin + +#import +#if !TARGET_OS_BRIDGE + +#import "AWDKeychainCKKSRateLimiterAggregatedScores.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation AWDKeychainCKKSRateLimiterAggregatedScores + +- (void)dealloc +{ + PBRepeatedUInt32Clear(&(self->_datas)); +} + +@synthesize timestamp = _timestamp; +- (void)setTimestamp:(uint64_t)v +{ + _has.timestamp = YES; + _timestamp = v; +} +- (void)setHasTimestamp:(BOOL)f +{ + _has.timestamp = f; +} +- (BOOL)hasTimestamp +{ + return _has.timestamp; +} +- (NSUInteger)datasCount +{ + return _datas.count; +} +- (uint32_t *)datas +{ + return _datas.list; +} +- (void)clearDatas +{ + PBRepeatedUInt32Clear(&_datas); +} +- (void)addData:(uint32_t)i +{ + PBRepeatedUInt32Add(&_datas, i); +} +- (uint32_t)dataAtIndex:(NSUInteger)idx +{ + if (_datas.count <= idx) + { + [[NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"idx (%tu) is out of range (%tu)", idx, _datas.count] userInfo:nil] raise]; + } + return _datas.list[idx]; +} +- (void)setDatas:(uint32_t *)list count:(NSUInteger)count +{ + PBRepeatedUInt32Set(&_datas, list, count); +} +- (BOOL)hasRatelimitertype +{ + return _ratelimitertype != nil; +} +@synthesize ratelimitertype = _ratelimitertype; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_has.timestamp) + { + [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_timestamp] forKey:@"timestamp"]; + } + [dict setObject:PBRepeatedUInt32NSArray(&(self->_datas)) forKey:@"data"]; + if (self->_ratelimitertype) + { + [dict setObject:self->_ratelimitertype forKey:@"ratelimitertype"]; + } + return dict; +} + +BOOL AWDKeychainCKKSRateLimiterAggregatedScoresReadFrom(__unsafe_unretained AWDKeychainCKKSRateLimiterAggregatedScores *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 /* timestamp */: + { + self->_has.timestamp = YES; + self->_timestamp = PBReaderReadUint64(reader); + } + break; + case 2 /* datas */: + { + if (TYPE_LENGTH_DELIMITED == aType) + { + PBDataReaderMark mark_data; + BOOL markError = !PBReaderPlaceMark(reader, &mark_data); + if (markError) + { + return NO; + } + while (PBReaderHasMoreData(reader)) + { + uint32_t new_data = PBReaderReadUint32(reader); + PBRepeatedUInt32Add(&(self->_datas), new_data); + } + PBReaderRecallMark(reader, &mark_data); + } + else + { + PBRepeatedUInt32Add(&(self->_datas), PBReaderReadUint32(reader)); + } + } + break; + case 3 /* ratelimitertype */: + { + NSString *new_ratelimitertype = PBReaderReadString(reader); + self->_ratelimitertype = new_ratelimitertype; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return AWDKeychainCKKSRateLimiterAggregatedScoresReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* timestamp */ + { + if (self->_has.timestamp) + { + PBDataWriterWriteUint64Field(writer, self->_timestamp, 1); + } + } + /* datas */ + { + if (self->_datas.count) + { + NSUInteger i_datas; + for (i_datas = 0; i_datas < self->_datas.count; i_datas++) + { + PBDataWriterWriteUint32Field(writer, self->_datas.list[i_datas], 2); + } + } + } + /* ratelimitertype */ + { + if (self->_ratelimitertype) + { + PBDataWriterWriteStringField(writer, self->_ratelimitertype, 3); + } + } +} + +- (void)copyTo:(AWDKeychainCKKSRateLimiterAggregatedScores *)other +{ + if (self->_has.timestamp) + { + other->_timestamp = _timestamp; + other->_has.timestamp = YES; + } + if ([self datasCount]) + { + [other clearDatas]; + NSUInteger datasCnt = [self datasCount]; + for (NSUInteger i = 0; i < datasCnt; i++) + { + [other addData:[self dataAtIndex:i]]; + } + } + if (_ratelimitertype) + { + other.ratelimitertype = _ratelimitertype; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + AWDKeychainCKKSRateLimiterAggregatedScores *copy = [[[self class] allocWithZone:zone] init]; + if (self->_has.timestamp) + { + copy->_timestamp = _timestamp; + copy->_has.timestamp = YES; + } + PBRepeatedUInt32Copy(&(copy->_datas), &_datas); + copy->_ratelimitertype = [_ratelimitertype copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + AWDKeychainCKKSRateLimiterAggregatedScores *other = (AWDKeychainCKKSRateLimiterAggregatedScores *)object; + return [other isMemberOfClass:[self class]] + && + ((self->_has.timestamp && other->_has.timestamp && self->_timestamp == other->_timestamp) || (!self->_has.timestamp && !other->_has.timestamp)) + && + PBRepeatedUInt32IsEqual(&(self->_datas), &(other->_datas)) + && + ((!self->_ratelimitertype && !other->_ratelimitertype) || [self->_ratelimitertype isEqual:other->_ratelimitertype]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + (self->_has.timestamp ? PBHashInt((NSUInteger)self->_timestamp) : 0) + ^ + PBRepeatedUInt32Hash(&(self->_datas)) + ^ + [self->_ratelimitertype hash] + ; +} + +- (void)mergeFrom:(AWDKeychainCKKSRateLimiterAggregatedScores *)other +{ + if (other->_has.timestamp) + { + self->_timestamp = other->_timestamp; + self->_has.timestamp = YES; + } + NSUInteger datasCnt = [other datasCount]; + for (NSUInteger i = 0; i < datasCnt; i++) + { + [self addData:[other dataAtIndex:i]]; + } + if (other->_ratelimitertype) + { + [self setRatelimitertype:other->_ratelimitertype]; + } +} + +@end +#endif diff --git a/keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.h b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.h new file mode 100644 index 00000000..6b4f97ce --- /dev/null +++ b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.h @@ -0,0 +1,47 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from stdin + +#import +#import + +#ifdef __cplusplus +#define AWDKEYCHAINCKKSRATELIMITEROVERLOAD_FUNCTION extern "C" +#else +#define AWDKEYCHAINCKKSRATELIMITEROVERLOAD_FUNCTION extern +#endif + +@interface AWDKeychainCKKSRateLimiterOverload : PBCodable +{ + int64_t _durationMsec; + uint64_t _timestamp; + NSString *_ratelimitertype; + struct { + int durationMsec:1; + int timestamp:1; + } _has; +} + + +@property (nonatomic) BOOL hasTimestamp; +@property (nonatomic) uint64_t timestamp; + +@property (nonatomic) BOOL hasDurationMsec; +@property (nonatomic) int64_t durationMsec; + +@property (nonatomic, readonly) BOOL hasRatelimitertype; +@property (nonatomic, retain) NSString *ratelimitertype; + +// Performs a shallow copy into other +- (void)copyTo:(AWDKeychainCKKSRateLimiterOverload *)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:(AWDKeychainCKKSRateLimiterOverload *)other; + +AWDKEYCHAINCKKSRATELIMITEROVERLOAD_FUNCTION BOOL AWDKeychainCKKSRateLimiterOverloadReadFrom(__unsafe_unretained AWDKeychainCKKSRateLimiterOverload *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.m b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.m new file mode 100644 index 00000000..9642e21c --- /dev/null +++ b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.m @@ -0,0 +1,227 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from stdin + +#import +#if !TARGET_OS_BRIDGE + +#import "AWDKeychainCKKSRateLimiterOverload.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation AWDKeychainCKKSRateLimiterOverload + +@synthesize timestamp = _timestamp; +- (void)setTimestamp:(uint64_t)v +{ + _has.timestamp = YES; + _timestamp = v; +} +- (void)setHasTimestamp:(BOOL)f +{ + _has.timestamp = f; +} +- (BOOL)hasTimestamp +{ + return _has.timestamp; +} +@synthesize durationMsec = _durationMsec; +- (void)setDurationMsec:(int64_t)v +{ + _has.durationMsec = YES; + _durationMsec = v; +} +- (void)setHasDurationMsec:(BOOL)f +{ + _has.durationMsec = f; +} +- (BOOL)hasDurationMsec +{ + return _has.durationMsec; +} +- (BOOL)hasRatelimitertype +{ + return _ratelimitertype != nil; +} +@synthesize ratelimitertype = _ratelimitertype; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_has.timestamp) + { + [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_timestamp] forKey:@"timestamp"]; + } + if (self->_has.durationMsec) + { + [dict setObject:[NSNumber numberWithLongLong:self->_durationMsec] forKey:@"durationMsec"]; + } + if (self->_ratelimitertype) + { + [dict setObject:self->_ratelimitertype forKey:@"ratelimitertype"]; + } + return dict; +} + +BOOL AWDKeychainCKKSRateLimiterOverloadReadFrom(__unsafe_unretained AWDKeychainCKKSRateLimiterOverload *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 /* timestamp */: + { + self->_has.timestamp = YES; + self->_timestamp = PBReaderReadUint64(reader); + } + break; + case 2 /* durationMsec */: + { + self->_has.durationMsec = YES; + self->_durationMsec = PBReaderReadInt64(reader); + } + break; + case 3 /* ratelimitertype */: + { + NSString *new_ratelimitertype = PBReaderReadString(reader); + self->_ratelimitertype = new_ratelimitertype; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return AWDKeychainCKKSRateLimiterOverloadReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* timestamp */ + { + if (self->_has.timestamp) + { + PBDataWriterWriteUint64Field(writer, self->_timestamp, 1); + } + } + /* durationMsec */ + { + if (self->_has.durationMsec) + { + PBDataWriterWriteInt64Field(writer, self->_durationMsec, 2); + } + } + /* ratelimitertype */ + { + if (self->_ratelimitertype) + { + PBDataWriterWriteStringField(writer, self->_ratelimitertype, 3); + } + } +} + +- (void)copyTo:(AWDKeychainCKKSRateLimiterOverload *)other +{ + if (self->_has.timestamp) + { + other->_timestamp = _timestamp; + other->_has.timestamp = YES; + } + if (self->_has.durationMsec) + { + other->_durationMsec = _durationMsec; + other->_has.durationMsec = YES; + } + if (_ratelimitertype) + { + other.ratelimitertype = _ratelimitertype; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + AWDKeychainCKKSRateLimiterOverload *copy = [[[self class] allocWithZone:zone] init]; + if (self->_has.timestamp) + { + copy->_timestamp = _timestamp; + copy->_has.timestamp = YES; + } + if (self->_has.durationMsec) + { + copy->_durationMsec = _durationMsec; + copy->_has.durationMsec = YES; + } + copy->_ratelimitertype = [_ratelimitertype copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + AWDKeychainCKKSRateLimiterOverload *other = (AWDKeychainCKKSRateLimiterOverload *)object; + return [other isMemberOfClass:[self class]] + && + ((self->_has.timestamp && other->_has.timestamp && self->_timestamp == other->_timestamp) || (!self->_has.timestamp && !other->_has.timestamp)) + && + ((self->_has.durationMsec && other->_has.durationMsec && self->_durationMsec == other->_durationMsec) || (!self->_has.durationMsec && !other->_has.durationMsec)) + && + ((!self->_ratelimitertype && !other->_ratelimitertype) || [self->_ratelimitertype isEqual:other->_ratelimitertype]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + (self->_has.timestamp ? PBHashInt((NSUInteger)self->_timestamp) : 0) + ^ + (self->_has.durationMsec ? PBHashInt((NSUInteger)self->_durationMsec) : 0) + ^ + [self->_ratelimitertype hash] + ; +} + +- (void)mergeFrom:(AWDKeychainCKKSRateLimiterOverload *)other +{ + if (other->_has.timestamp) + { + self->_timestamp = other->_timestamp; + self->_has.timestamp = YES; + } + if (other->_has.durationMsec) + { + self->_durationMsec = other->_durationMsec; + self->_has.durationMsec = YES; + } + if (other->_ratelimitertype) + { + [self setRatelimitertype:other->_ratelimitertype]; + } +} + +@end +#endif diff --git a/keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.h b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.h new file mode 100644 index 00000000..1d649b76 --- /dev/null +++ b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.h @@ -0,0 +1,50 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from stdin + +#import +#import + +#ifdef __cplusplus +#define AWDKEYCHAINCKKSRATELIMITERTOPWRITERS_FUNCTION extern "C" +#else +#define AWDKEYCHAINCKKSRATELIMITERTOPWRITERS_FUNCTION extern +#endif + +@interface AWDKeychainCKKSRateLimiterTopWriters : PBCodable +{ + uint64_t _timestamp; + NSString *_ratelimitertype; + NSMutableArray *_writers; + struct { + int timestamp:1; + } _has; +} + + +@property (nonatomic) BOOL hasTimestamp; +@property (nonatomic) uint64_t timestamp; + +@property (nonatomic, retain) NSMutableArray *writers; +- (void)clearWriters; +- (void)addWriter:(NSString *)i; +- (NSUInteger)writersCount; +- (NSString *)writerAtIndex:(NSUInteger)idx; ++ (Class)writerType; + +@property (nonatomic, readonly) BOOL hasRatelimitertype; +@property (nonatomic, retain) NSString *ratelimitertype; + +// Performs a shallow copy into other +- (void)copyTo:(AWDKeychainCKKSRateLimiterTopWriters *)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:(AWDKeychainCKKSRateLimiterTopWriters *)other; + +AWDKEYCHAINCKKSRATELIMITERTOPWRITERS_FUNCTION BOOL AWDKeychainCKKSRateLimiterTopWritersReadFrom(__unsafe_unretained AWDKeychainCKKSRateLimiterTopWriters *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.m b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.m new file mode 100644 index 00000000..6cfaaa5b --- /dev/null +++ b/keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.m @@ -0,0 +1,244 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from stdin + +#import +#if !TARGET_OS_BRIDGE + +#import "AWDKeychainCKKSRateLimiterTopWriters.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation AWDKeychainCKKSRateLimiterTopWriters + +@synthesize timestamp = _timestamp; +- (void)setTimestamp:(uint64_t)v +{ + _has.timestamp = YES; + _timestamp = v; +} +- (void)setHasTimestamp:(BOOL)f +{ + _has.timestamp = f; +} +- (BOOL)hasTimestamp +{ + return _has.timestamp; +} +@synthesize writers = _writers; +- (void)clearWriters +{ + [_writers removeAllObjects]; +} +- (void)addWriter:(NSString *)i +{ + if (!_writers) + { + _writers = [[NSMutableArray alloc] init]; + } + [_writers addObject:i]; +} +- (NSUInteger)writersCount +{ + return [_writers count]; +} +- (NSString *)writerAtIndex:(NSUInteger)idx +{ + return [_writers objectAtIndex:idx]; +} ++ (Class)writerType +{ + return [NSString class]; +} +- (BOOL)hasRatelimitertype +{ + return _ratelimitertype != nil; +} +@synthesize ratelimitertype = _ratelimitertype; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_has.timestamp) + { + [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_timestamp] forKey:@"timestamp"]; + } + if (self->_writers) + { + [dict setObject:self->_writers forKey:@"writer"]; + } + if (self->_ratelimitertype) + { + [dict setObject:self->_ratelimitertype forKey:@"ratelimitertype"]; + } + return dict; +} + +BOOL AWDKeychainCKKSRateLimiterTopWritersReadFrom(__unsafe_unretained AWDKeychainCKKSRateLimiterTopWriters *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 /* timestamp */: + { + self->_has.timestamp = YES; + self->_timestamp = PBReaderReadUint64(reader); + } + break; + case 2 /* writers */: + { + NSString *new_writers = PBReaderReadString(reader); + if (new_writers) + { + [self addWriter:new_writers]; + } + } + break; + case 3 /* ratelimitertype */: + { + NSString *new_ratelimitertype = PBReaderReadString(reader); + self->_ratelimitertype = new_ratelimitertype; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return AWDKeychainCKKSRateLimiterTopWritersReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* timestamp */ + { + if (self->_has.timestamp) + { + PBDataWriterWriteUint64Field(writer, self->_timestamp, 1); + } + } + /* writers */ + { + for (NSString *s_writers in self->_writers) + { + PBDataWriterWriteStringField(writer, s_writers, 2); + } + } + /* ratelimitertype */ + { + if (self->_ratelimitertype) + { + PBDataWriterWriteStringField(writer, self->_ratelimitertype, 3); + } + } +} + +- (void)copyTo:(AWDKeychainCKKSRateLimiterTopWriters *)other +{ + if (self->_has.timestamp) + { + other->_timestamp = _timestamp; + other->_has.timestamp = YES; + } + if ([self writersCount]) + { + [other clearWriters]; + NSUInteger writersCnt = [self writersCount]; + for (NSUInteger i = 0; i < writersCnt; i++) + { + [other addWriter:[self writerAtIndex:i]]; + } + } + if (_ratelimitertype) + { + other.ratelimitertype = _ratelimitertype; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + AWDKeychainCKKSRateLimiterTopWriters *copy = [[[self class] allocWithZone:zone] init]; + if (self->_has.timestamp) + { + copy->_timestamp = _timestamp; + copy->_has.timestamp = YES; + } + for (NSString *v in _writers) + { + NSString *vCopy = [v copyWithZone:zone]; + [copy addWriter:vCopy]; + } + copy->_ratelimitertype = [_ratelimitertype copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + AWDKeychainCKKSRateLimiterTopWriters *other = (AWDKeychainCKKSRateLimiterTopWriters *)object; + return [other isMemberOfClass:[self class]] + && + ((self->_has.timestamp && other->_has.timestamp && self->_timestamp == other->_timestamp) || (!self->_has.timestamp && !other->_has.timestamp)) + && + ((!self->_writers && !other->_writers) || [self->_writers isEqual:other->_writers]) + && + ((!self->_ratelimitertype && !other->_ratelimitertype) || [self->_ratelimitertype isEqual:other->_ratelimitertype]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + (self->_has.timestamp ? PBHashInt((NSUInteger)self->_timestamp) : 0) + ^ + [self->_writers hash] + ^ + [self->_ratelimitertype hash] + ; +} + +- (void)mergeFrom:(AWDKeychainCKKSRateLimiterTopWriters *)other +{ + if (other->_has.timestamp) + { + self->_timestamp = other->_timestamp; + self->_has.timestamp = YES; + } + for (NSString *iter_writers in other->_writers) + { + [self addWriter:iter_writers]; + } + if (other->_ratelimitertype) + { + [self setRatelimitertype:other->_ratelimitertype]; + } +} + +@end +#endif diff --git a/keychain/analytics/awd/AWDKeychainSecDbMarkedCorrupt.h b/keychain/analytics/awd/AWDKeychainSecDbMarkedCorrupt.h new file mode 100644 index 00000000..4c2743b1 --- /dev/null +++ b/keychain/analytics/awd/AWDKeychainSecDbMarkedCorrupt.h @@ -0,0 +1,48 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from stdin + +#import +#import + +#ifdef __cplusplus +#define AWDKEYCHAINSECDBMARKEDCORRUPT_FUNCTION extern "C" +#else +#define AWDKEYCHAINSECDBMARKEDCORRUPT_FUNCTION extern +#endif + +@interface AWDKeychainSecDbMarkedCorrupt : PBCodable +{ + uint64_t _timestamp; + uint32_t _reason; + uint32_t _sqlitecode; + struct { + int timestamp:1; + int reason:1; + int sqlitecode:1; + } _has; +} + + +@property (nonatomic) BOOL hasTimestamp; +@property (nonatomic) uint64_t timestamp; + +@property (nonatomic) BOOL hasReason; +@property (nonatomic) uint32_t reason; + +@property (nonatomic) BOOL hasSqlitecode; +@property (nonatomic) uint32_t sqlitecode; + +// Performs a shallow copy into other +- (void)copyTo:(AWDKeychainSecDbMarkedCorrupt *)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:(AWDKeychainSecDbMarkedCorrupt *)other; + +AWDKEYCHAINSECDBMARKEDCORRUPT_FUNCTION BOOL AWDKeychainSecDbMarkedCorruptReadFrom(__unsafe_unretained AWDKeychainSecDbMarkedCorrupt *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/analytics/awd/AWDKeychainSecDbMarkedCorrupt.m b/keychain/analytics/awd/AWDKeychainSecDbMarkedCorrupt.m new file mode 100644 index 00000000..d597b31a --- /dev/null +++ b/keychain/analytics/awd/AWDKeychainSecDbMarkedCorrupt.m @@ -0,0 +1,242 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from stdin + +#import +#if !TARGET_OS_BRIDGE + +#import "AWDKeychainSecDbMarkedCorrupt.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation AWDKeychainSecDbMarkedCorrupt + +@synthesize timestamp = _timestamp; +- (void)setTimestamp:(uint64_t)v +{ + _has.timestamp = YES; + _timestamp = v; +} +- (void)setHasTimestamp:(BOOL)f +{ + _has.timestamp = f; +} +- (BOOL)hasTimestamp +{ + return _has.timestamp; +} +@synthesize reason = _reason; +- (void)setReason:(uint32_t)v +{ + _has.reason = YES; + _reason = v; +} +- (void)setHasReason:(BOOL)f +{ + _has.reason = f; +} +- (BOOL)hasReason +{ + return _has.reason; +} +@synthesize sqlitecode = _sqlitecode; +- (void)setSqlitecode:(uint32_t)v +{ + _has.sqlitecode = YES; + _sqlitecode = v; +} +- (void)setHasSqlitecode:(BOOL)f +{ + _has.sqlitecode = f; +} +- (BOOL)hasSqlitecode +{ + return _has.sqlitecode; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_has.timestamp) + { + [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_timestamp] forKey:@"timestamp"]; + } + if (self->_has.reason) + { + [dict setObject:[NSNumber numberWithUnsignedInt:self->_reason] forKey:@"reason"]; + } + if (self->_has.sqlitecode) + { + [dict setObject:[NSNumber numberWithUnsignedInt:self->_sqlitecode] forKey:@"sqlitecode"]; + } + return dict; +} + +BOOL AWDKeychainSecDbMarkedCorruptReadFrom(__unsafe_unretained AWDKeychainSecDbMarkedCorrupt *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 /* timestamp */: + { + self->_has.timestamp = YES; + self->_timestamp = PBReaderReadUint64(reader); + } + break; + case 2 /* reason */: + { + self->_has.reason = YES; + self->_reason = PBReaderReadUint32(reader); + } + break; + case 3 /* sqlitecode */: + { + self->_has.sqlitecode = YES; + self->_sqlitecode = PBReaderReadUint32(reader); + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return AWDKeychainSecDbMarkedCorruptReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* timestamp */ + { + if (self->_has.timestamp) + { + PBDataWriterWriteUint64Field(writer, self->_timestamp, 1); + } + } + /* reason */ + { + if (self->_has.reason) + { + PBDataWriterWriteUint32Field(writer, self->_reason, 2); + } + } + /* sqlitecode */ + { + if (self->_has.sqlitecode) + { + PBDataWriterWriteUint32Field(writer, self->_sqlitecode, 3); + } + } +} + +- (void)copyTo:(AWDKeychainSecDbMarkedCorrupt *)other +{ + if (self->_has.timestamp) + { + other->_timestamp = _timestamp; + other->_has.timestamp = YES; + } + if (self->_has.reason) + { + other->_reason = _reason; + other->_has.reason = YES; + } + if (self->_has.sqlitecode) + { + other->_sqlitecode = _sqlitecode; + other->_has.sqlitecode = YES; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + AWDKeychainSecDbMarkedCorrupt *copy = [[[self class] allocWithZone:zone] init]; + if (self->_has.timestamp) + { + copy->_timestamp = _timestamp; + copy->_has.timestamp = YES; + } + if (self->_has.reason) + { + copy->_reason = _reason; + copy->_has.reason = YES; + } + if (self->_has.sqlitecode) + { + copy->_sqlitecode = _sqlitecode; + copy->_has.sqlitecode = YES; + } + return copy; +} + +- (BOOL)isEqual:(id)object +{ + AWDKeychainSecDbMarkedCorrupt *other = (AWDKeychainSecDbMarkedCorrupt *)object; + return [other isMemberOfClass:[self class]] + && + ((self->_has.timestamp && other->_has.timestamp && self->_timestamp == other->_timestamp) || (!self->_has.timestamp && !other->_has.timestamp)) + && + ((self->_has.reason && other->_has.reason && self->_reason == other->_reason) || (!self->_has.reason && !other->_has.reason)) + && + ((self->_has.sqlitecode && other->_has.sqlitecode && self->_sqlitecode == other->_sqlitecode) || (!self->_has.sqlitecode && !other->_has.sqlitecode)) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + (self->_has.timestamp ? PBHashInt((NSUInteger)self->_timestamp) : 0) + ^ + (self->_has.reason ? PBHashInt((NSUInteger)self->_reason) : 0) + ^ + (self->_has.sqlitecode ? PBHashInt((NSUInteger)self->_sqlitecode) : 0) + ; +} + +- (void)mergeFrom:(AWDKeychainSecDbMarkedCorrupt *)other +{ + if (other->_has.timestamp) + { + self->_timestamp = other->_timestamp; + self->_has.timestamp = YES; + } + if (other->_has.reason) + { + self->_reason = other->_reason; + self->_has.reason = YES; + } + if (other->_has.sqlitecode) + { + self->_sqlitecode = other->_sqlitecode; + self->_has.sqlitecode = YES; + } +} + +@end +#endif diff --git a/keychain/analytics/awd/AWDMetricIds_Keychain.h b/keychain/analytics/awd/AWDMetricIds_Keychain.h new file mode 100644 index 00000000..1c49d40e --- /dev/null +++ b/keychain/analytics/awd/AWDMetricIds_Keychain.h @@ -0,0 +1,35 @@ +// +// AWDMetricIds_Keychain.h +// AppleWirelessDiagnostics +// +// WARNING :: DO NOT MODIFY THIS FILE! +// +// This file is auto-generated! Do not modify it or your changes will get overwritten! +// + +#ifndef AWD_MetricId_HeaderGuard_Keychain +#define AWD_MetricId_HeaderGuard_Keychain + +// Component Id: +// --------------- +// Use this value for any API requesting the "component id" for your component. +enum { + AWDComponentId_Keychain = 0x60 +}; + + +// Simple Metrics: +// --------------- +// This component currently has no metrics compatible with the 'simple metric' API. + + +// General Metrics: +// ---------------- +enum { + AWDMetricId_Keychain_CKKSRateLimiterOverload = 0x600000, + AWDMetricId_Keychain_CKKSRateLimiterTopWriters = 0x600001, + AWDMetricId_Keychain_CKKSRateLimiterAggregatedScores = 0x600002, + AWDMetricId_Keychain_SecDbMarkedCorrupt = 0x600003 +}; + +#endif // AWD_MetricId_HeaderGuard_Keychain diff --git a/keychain/analytics/awd/AwdMetadata-0x60-Keychain.bin b/keychain/analytics/awd/AwdMetadata-0x60-Keychain.bin new file mode 100644 index 0000000000000000000000000000000000000000..d47965cdf6e4c83e44c59526fa2e177382195d72 GIT binary patch literal 924 zcmaKqPfy!07{=`+Dw)NfDo8BqCLw$Q34uyNn5&%-)ikM8o7MpmCtTZvh_)$CVB%J` z&#_Oi^Q4I*_nr4Srd@a74QaY*Ye*Eue%?HO^8W1Iqh=eU>_*5y7CM1<6P|DIT-<%V zF~{0(m>(Mmy*&I(E%@@#MCcW0*+rVpf;}3I%<3~2GyE2xU=VH!!2rPk;bS3~W8qUF zSeb=9cWfJ1Ef>AUFfytpjFy~=ZC2-8L~4IkD^Q(tacOPl(HeU2&A^)9u~VP?I9)zh z*W!#vgS}R(^Ny!#Kk7%R(r>Pm?!{b=JM$);(UlU%`*?VyGi$=~=Gmlqx?1Ad4MVL$ zNR=HCYn8B^(z;zxqP4==QKH#xbA7JlUaa-yFl9NxkSw26OiU;jP31I&;XHOSERlS@>dOcKxla-R7Kdn!Xn$Ne6Rz5rcDvwZPwIt$S zQqzNGAqdU^wIok@dCUQ+6*2!~oxXC`0-PRN(TXSWz;S?5HYdqN4>n!IQjs;*@Wsyd zX_qzRsaI!mhlv+~@I)YjIu9DM>j%Ey^|`Zn +#include +#include +#include +#include + +#ifdef __OBJC__ +#import + +typedef NS_ENUM(NSUInteger, SecCKKSItemEncryptionVersion) { + CKKSItemEncryptionVersionNone = 0, // No encryption present + CKKSItemEncryptionVersion1 = 1, // Current version, AES-SIV 512, not all fields authenticated + CKKSItemEncryptionVersion2 = 2, // Seed3 version, AES-SIV 512, all fields (including unknown fields) authenticated +}; + +extern const SecCKKSItemEncryptionVersion currentCKKSItemEncryptionVersion; + +/* Queue Actions */ +extern NSString* const SecCKKSActionAdd; +extern NSString* const SecCKKSActionDelete; +extern NSString* const SecCKKSActionModify; + +/* Queue States */ +@protocol SecCKKSItemState +@end +typedef NSString CKKSItemState; +extern CKKSItemState* const SecCKKSStateNew; +extern CKKSItemState* const SecCKKSStateUnauthenticated; +extern CKKSItemState* const SecCKKSStateInFlight; +extern CKKSItemState* const SecCKKSStateReencrypt; +extern CKKSItemState* const SecCKKSStateError; +extern CKKSItemState* const SecCKKSStateDeleted; // meta-state: please delete this item! + +/* Processed States */ +@protocol SecCKKSProcessedState +@end +typedef NSString CKKSProcessedState; +extern CKKSProcessedState* const SecCKKSProcessedStateLocal; +extern CKKSProcessedState* const SecCKKSProcessedStateRemote; + +/* Key Classes */ +@protocol SecCKKSKeyClass +@end +typedef NSString CKKSKeyClass; +extern CKKSKeyClass* const SecCKKSKeyClassTLK; +extern CKKSKeyClass* const SecCKKSKeyClassA; +extern CKKSKeyClass* const SecCKKSKeyClassC; + +/* Useful CloudKit configuration */ +extern NSString* const SecCKKSContainerName; +extern bool SecCKKSContainerUsePCS; +extern NSString* const SecCKKSSubscriptionID; +extern NSString* const SecCKKSAPSNamedPort; + +/* Item CKRecords */ +extern NSString* const SecCKRecordItemType; +extern NSString* const SecCKRecordVersionKey; +extern NSString* const SecCKRecordEncryptionVersionKey; +extern NSString* const SecCKRecordParentKeyRefKey; +extern NSString* const SecCKRecordDataKey; +extern NSString* const SecCKRecordWrappedKeyKey; +extern NSString* const SecCKRecordGenerationCountKey; +extern NSString* const SecCKRecordPCSServiceIdentifier; +extern NSString* const SecCKRecordPCSPublicKey; +extern NSString* const SecCKRecordPCSPublicIdentity; +extern NSString* const SecCKRecordServerWasCurrent; + +/* Intermediate Key CKRecord Keys */ +extern NSString* const SecCKRecordIntermediateKeyType; +extern NSString* const SecCKRecordKeyClassKey; +//extern NSString* const SecCKRecordWrappedKeyKey; +//extern NSString* const SecCKRecordParentKeyRefKey; + +/* Current Key CKRecord Keys */ +extern NSString* const SecCKRecordCurrentKeyType; +// The key class will be the record name. +//extern NSString* const SecCKRecordParentKeyRefKey; <-- represent the current key for this key class + +/* Current Item CKRecord Keys */ +extern NSString* const SecCKRecordCurrentItemType; +extern NSString* const SecCKRecordItemRefKey; +//extern NSString* const SecCKRecordVersionKey; <-- the OS version which last updated the record + +/* Device State CKRexord Keys */ +extern NSString* const SecCKRecordDeviceStateType; +extern NSString* const SecCKRecordCirclePeerID; +extern NSString* const SecCKRecordCircleStatus; +extern NSString* const SecCKRecordKeyState; +extern NSString* const SecCKRecordCurrentTLK; +extern NSString* const SecCKRecordCurrentClassA; +extern NSString* const SecCKRecordCurrentClassC; + +/* Manifest master CKRecord Keys */ +extern NSString* const SecCKRecordManifestType; +extern NSString* const SecCKRecordManifestDigestValueKey; +extern NSString* const SecCKRecordManifestGenerationCountKey; +extern NSString* const SecCKRecordManifestLeafRecordIDsKey; +extern NSString* const SecCKRecordManifestPeerManifestRecordIDsKey; +extern NSString* const SecCKRecordManifestCurrentItemsKey; +extern NSString* const SecCKRecordManifestSignaturesKey; +extern NSString* const SecCKRecordManifestSignerIDKey; +extern NSString* const SecCKRecordManifestSchemaKey; + +/* Manifest leaf CKRecord Keys */ +extern NSString* const SecCKRecordManifestLeafType; +extern NSString* const SecCKRecordManifestLeafDERKey; +extern NSString* const SecCKRecordManifestLeafDigestKey; + +/* Zone Key Hierarchy States */ +@protocol SecCKKSZoneKeyState +@end +typedef NSString CKKSZoneKeyState; + +// Class has just been created. +extern CKKSZoneKeyState* const SecCKKSZoneKeyStateInitializing; +// CKKSZone has just informed us that its setup is done (and completed successfully). +extern CKKSZoneKeyState* const SecCKKSZoneKeyStateInitialized; +// Everything is ready and waiting for input. +extern CKKSZoneKeyState* const SecCKKSZoneKeyStateReady; +// 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; +// We've received a wrapped TLK, but we don't have its contents yet. Wait until they arrive. +extern CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLK; +// We've received a wrapped TLK, but we can't process it until the keybag unlocks. Wait until then. +extern CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForUnlock; +// Things are unhealthy, but we're not sure entirely why. +extern CKKSZoneKeyState* const SecCKKSZoneKeyStateUnhealthy; +// Something has gone horribly wrong with the current key pointers. +extern CKKSZoneKeyState* const SecCKKSZoneKeyStateBadCurrentPointers; +// Something has gone wrong creating new TLKs. +extern CKKSZoneKeyState* const SecCKKSZoneKeyStateNewTLKsFailed; +// 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* CKKSZoneKeyStateMap(void); +NSDictionary* CKKSZoneKeyStateInverseMap(void); +NSNumber* CKKSZoneKeyToNumber(CKKSZoneKeyState* state); +CKKSZoneKeyState* CKKSZoneKeyRecover(NSNumber* stateNumber); + +/* Hide Item Length */ +extern const NSUInteger SecCKKSItemPaddingBlockSize; + +/* Aggd Keys */ +extern NSString* const SecCKKSAggdPropagationDelay; +extern NSString* const SecCKKSAggdPrimaryKeyConflict; +extern NSString* const SecCKKSAggdViewKeyCount; +extern NSString* const SecCKKSAggdItemReencryption; + +extern NSString* const SecCKKSUserDefaultsSuite; + +/* Queue limits: these should likely be configurable via plist */ +#define SecCKKSOutgoingQueueItemsAtOnce 100 +#define SecCKKSIncomingQueueItemsAtOnce 10 + +#endif // OBJ-C + +/* C functions to interact with CKKS */ +void SecCKKSInitialize(SecDbRef db); +void SecCKKSNotifyBlock(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes); + +// Called by XPC approximately every 3 days +void SecCKKS24hrNotification(void); + +// Register this callback to receive a call when the item with this UUID next successfully (or unsuccessfully) exits the outgoing queue. +void CKKSRegisterSyncStatusCallback(CFStringRef cfuuid, SecBoolCFErrorCallback callback); + +// Returns true if CloudKit keychain syncing should occur +bool SecCKKSIsEnabled(void); + +bool SecCKKSEnable(void); +bool SecCKKSDisable(void); + +bool SecCKKSResetSyncing(void); + +bool SecCKKSSyncManifests(void); +bool SecCKKSEnableSyncManifests(void); +bool SecCKKSSetSyncManifests(bool value); + +bool SecCKKSEnforceManifests(void); +bool SecCKKSEnableEnforceManifests(void); +bool SecCKKSSetEnforceManifests(bool value); + +// Testing support +bool SecCKKSTestsEnabled(void); +bool SecCKKSTestsEnable(void); +bool SecCKKSTestsDisable(void); + +void SecCKKSTestResetFlags(void); +bool SecCKKSTestDisableAutomaticUUID(void); +void SecCKKSTestSetDisableAutomaticUUID(bool set); + +bool SecCKKSTestDisableSOS(void); +void SecCKKSTestSetDisableSOS(bool set); + +bool SecCKKSTestDisableKeyNotifications(void); +void SecCKKSTestSetDisableKeyNotifications(bool set); + + +XPC_RETURNS_RETAINED xpc_endpoint_t +SecServerCreateCKKSEndpoint(void); + +// TODO: handle errors better +typedef CF_ENUM(CFIndex, CKKSErrorCode) { + CKKSNoUUIDOnItem = 15, +}; + +#define SecTranslateError(nserrorptr, cferror) \ + if(nserrorptr) { \ + *nserrorptr = (__bridge_transfer NSError*) cferror; \ + } else { \ + CFReleaseNull(cferror); \ + } + +// 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 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__) \ +} + +#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 + +#endif /* CKKS_h */ diff --git a/keychain/ckks/CKKS.m b/keychain/ckks/CKKS.m new file mode 100644 index 00000000..324de08c --- /dev/null +++ b/keychain/ckks/CKKS.m @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#import +#if OCTAGON +#import +#endif + +#include +#include +#include + +#import +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSViewManager.h" +#import "keychain/ckks/CKKSKey.h" + +const SecCKKSItemEncryptionVersion currentCKKSItemEncryptionVersion = CKKSItemEncryptionVersion2; + +NSString* const SecCKKSActionAdd = @"add"; +NSString* const SecCKKSActionDelete = @"delete"; +NSString* const SecCKKSActionModify = @"modify"; + +CKKSItemState* const SecCKKSStateNew = (CKKSItemState*) @"new"; +CKKSItemState* const SecCKKSStateUnauthenticated = (CKKSItemState*) @"unauthenticated"; +CKKSItemState* const SecCKKSStateInFlight = (CKKSItemState*) @"inflight"; +CKKSItemState* const SecCKKSStateReencrypt = (CKKSItemState*) @"reencrypt"; +CKKSItemState* const SecCKKSStateError = (CKKSItemState*) @"error"; +CKKSItemState* const SecCKKSStateDeleted = (CKKSItemState*) @"deleted"; + +CKKSProcessedState* const SecCKKSProcessedStateLocal = (CKKSProcessedState*) @"local"; +CKKSProcessedState* const SecCKKSProcessedStateRemote = (CKKSProcessedState*) @"remote"; + +CKKSKeyClass* const SecCKKSKeyClassTLK = (CKKSKeyClass*) @"tlk"; +CKKSKeyClass* const SecCKKSKeyClassA = (CKKSKeyClass*) @"classA"; +CKKSKeyClass* const SecCKKSKeyClassC = (CKKSKeyClass*) @"classC"; + +NSString* const SecCKKSContainerName = @"com.apple.security.keychain"; +bool SecCKKSContainerUsePCS = false; + +NSString* const SecCKKSSubscriptionID = @"keychain-changes"; +NSString* const SecCKKSAPSNamedPort = @"com.apple.securityd.aps"; + +NSString* const SecCKRecordItemType = @"item"; +NSString* const SecCKRecordVersionKey = @"uploadver"; +NSString* const SecCKRecordEncryptionVersionKey = @"encver"; +NSString* const SecCKRecordDataKey = @"data"; +NSString* const SecCKRecordParentKeyRefKey = @"parentkeyref"; +NSString* const SecCKRecordWrappedKeyKey = @"wrappedkey"; +NSString* const SecCKRecordGenerationCountKey = @"gen"; + +NSString* const SecCKRecordPCSServiceIdentifier = @"pcsservice"; +NSString* const SecCKRecordPCSPublicKey = @"pcspublickey"; +NSString* const SecCKRecordPCSPublicIdentity = @"pcspublicidentity"; +NSString* const SecCKRecordServerWasCurrent = @"server_wascurrent"; + +NSString* const SecCKRecordIntermediateKeyType = @"synckey"; +NSString* const SecCKRecordKeyClassKey = @"class"; + +NSString* const SecCKRecordCurrentKeyType = @"currentkey"; + +NSString* const SecCKRecordCurrentItemType = @"currentitem"; +NSString* const SecCKRecordItemRefKey = @"item"; + +NSString* const SecCKRecordDeviceStateType = @"devicestate"; +NSString* const SecCKRecordCirclePeerID = @"peerid"; +NSString* const SecCKRecordCircleStatus = @"circle"; +NSString* const SecCKRecordKeyState = @"keystate"; +NSString* const SecCKRecordCurrentTLK = @"currentTLK"; +NSString* const SecCKRecordCurrentClassA = @"currentClassA"; +NSString* const SecCKRecordCurrentClassC = @"currentClassC"; + +NSString* const SecCKRecordManifestType = @"manifest"; +NSString* const SecCKRecordManifestDigestValueKey = @"digest_value"; +NSString* const SecCKRecordManifestGenerationCountKey = @"generation_count"; +NSString* const SecCKRecordManifestLeafRecordIDsKey = @"leaf_records"; +NSString* const SecCKRecordManifestPeerManifestRecordIDsKey = @"peer_manifests"; +NSString* const SecCKRecordManifestCurrentItemsKey = @"current_items"; +NSString* const SecCKRecordManifestSignaturesKey = @"signatures"; +NSString* const SecCKRecordManifestSignerIDKey = @"signer_id"; +NSString* const SecCKRecordManifestSchemaKey = @"schema"; + +NSString* const SecCKRecordManifestLeafType = @"manifest_leaf"; +NSString* const SecCKRecordManifestLeafDERKey = @"der"; +NSString* const SecCKRecordManifestLeafDigestKey = @"digest"; + +CKKSZoneKeyState* const SecCKKSZoneKeyStateReady = (CKKSZoneKeyState*) @"ready"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateError = (CKKSZoneKeyState*) @"error"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateCancelled = (CKKSZoneKeyState*) @"cancelled"; + +CKKSZoneKeyState* const SecCKKSZoneKeyStateInitializing = (CKKSZoneKeyState*) @"initializing"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateInitialized = (CKKSZoneKeyState*) @"initialized"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateFetchComplete = (CKKSZoneKeyState*) @"fetchcomplete"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateNeedFullRefetch = (CKKSZoneKeyState*) @"needrefetch"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLK = (CKKSZoneKeyState*) @"waitfortlk"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForUnlock = (CKKSZoneKeyState*) @"waitforunlock"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateUnhealthy = (CKKSZoneKeyState*) @"unhealthy"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateBadCurrentPointers = (CKKSZoneKeyState*) @"badcurrentpointers"; +CKKSZoneKeyState* const SecCKKSZoneKeyStateNewTLKsFailed = (CKKSZoneKeyState*) @"newtlksfailed"; + +NSDictionary* CKKSZoneKeyStateMap(void) { + static NSDictionary* map = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + map = @{ + SecCKKSZoneKeyStateReady: [NSNumber numberWithUnsignedInt: 0], + SecCKKSZoneKeyStateError: [NSNumber numberWithUnsignedInt: 1], + SecCKKSZoneKeyStateCancelled: [NSNumber numberWithUnsignedInt: 2], + + SecCKKSZoneKeyStateInitializing: [NSNumber numberWithUnsignedInt: 3], + SecCKKSZoneKeyStateInitialized: [NSNumber numberWithUnsignedInt: 4], + SecCKKSZoneKeyStateFetchComplete: [NSNumber numberWithUnsignedInt: 5], + SecCKKSZoneKeyStateWaitForTLK: [NSNumber numberWithUnsignedInt: 6], + SecCKKSZoneKeyStateWaitForUnlock: [NSNumber numberWithUnsignedInt: 7], + SecCKKSZoneKeyStateUnhealthy: [NSNumber numberWithUnsignedInt: 8], + SecCKKSZoneKeyStateBadCurrentPointers: [NSNumber numberWithUnsignedInt: 9], + SecCKKSZoneKeyStateNewTLKsFailed: [NSNumber numberWithUnsignedInt:10], + }; + }); + return map; +} + +NSDictionary* CKKSZoneKeyStateInverseMap(void) { + static NSDictionary* backwardMap = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSDictionary* forwardMap = CKKSZoneKeyStateMap(); + backwardMap = [NSDictionary dictionaryWithObjects:[forwardMap allKeys] forKeys:[forwardMap allValues]]; + }); + return backwardMap; +} + +NSNumber* CKKSZoneKeyToNumber(CKKSZoneKeyState* state) { + if(!state) { + return CKKSZoneKeyStateMap()[SecCKKSZoneKeyStateError]; + } + NSNumber* result = CKKSZoneKeyStateMap()[state]; + if(result) { + return result; + } + return CKKSZoneKeyStateMap()[SecCKKSZoneKeyStateError]; +} +CKKSZoneKeyState* CKKSZoneKeyRecover(NSNumber* stateNumber) { + if(!stateNumber) { + return SecCKKSZoneKeyStateError; + } + CKKSZoneKeyState* result = CKKSZoneKeyStateInverseMap()[stateNumber]; + if(result) { + return result; + } + return SecCKKSZoneKeyStateError; +} + +const NSUInteger SecCKKSItemPaddingBlockSize = 20; + +NSString* const SecCKKSAggdPropagationDelay = @"com.apple.security.ckks.propagationdelay"; +NSString* const SecCKKSAggdPrimaryKeyConflict = @"com.apple.security.ckks.pkconflict"; +NSString* const SecCKKSAggdViewKeyCount = @"com.apple.security.ckks.keycount"; +NSString* const SecCKKSAggdItemReencryption = @"com.apple.security.ckks.reencrypt"; + +NSString* const SecCKKSUserDefaultsSuite = @"com.apple.security.ckks"; + +#if OCTAGON +static bool enableCKKS = true; +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)."); + return false; + } + + return enableCKKS; +} + +bool SecCKKSEnable() { + enableCKKS = true; + return enableCKKS; +} + +bool SecCKKSDisable() { + enableCKKS = false; + return enableCKKS; +} + +bool SecCKKSResetSyncing(void) { + [CKKSViewManager resetManager: true setTo: nil]; + return SecCKKSIsEnabled(); +} + +bool SecCKKSTestsEnabled(void) { + return testCKKS; +} + +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."); + testCKKS = false; + return false; + } + + testCKKS = true; + return testCKKS; +} + +bool SecCKKSTestsDisable(void) { + testCKKS = false; + return testCKKS; +} + +// Feature flags to twiddle behavior +static bool CKKSSyncManifests = false; +bool SecCKKSSyncManifests(void) { + return CKKSSyncManifests; +} +bool SecCKKSEnableSyncManifests() { + CKKSSyncManifests = true; + return CKKSSyncManifests; +} +bool SecCKKSSetSyncManifests(bool value) { + CKKSSyncManifests = value; + return CKKSSyncManifests; +} + +static bool CKKSEnforceManifests = false; +bool SecCKKSEnforceManifests(void) { + return CKKSEnforceManifests; +} +bool SecCKKSEnableEnforceManifests() { + CKKSEnforceManifests = true; + return CKKSEnforceManifests; +} +bool SecCKKSSetEnforceManifests(bool value) { + CKKSEnforceManifests = value; + return CKKSEnforceManifests; +} + +// Feature flags to twiddle behavior for tests +static bool CKKSDisableAutomaticUUID = false; +bool SecCKKSTestDisableAutomaticUUID(void) { +#if DEBUG + return CKKSDisableAutomaticUUID; +#else + return false; +#endif +} +void SecCKKSTestSetDisableAutomaticUUID(bool set) { + CKKSDisableAutomaticUUID = set; +} + +static bool CKKSDisableSOS = false; +bool SecCKKSTestDisableSOS(void) { +#if DEBUG + return CKKSDisableSOS; +#else + return false; +#endif +} +void SecCKKSTestSetDisableSOS(bool set) { + CKKSDisableSOS = set; +} + + +static bool CKKSDisableKeyNotifications = false; +bool SecCKKSTestDisableKeyNotifications(void) { +#if DEBUG + return CKKSDisableKeyNotifications; +#else + return false; +#endif +} +void SecCKKSTestSetDisableKeyNotifications(bool set) { + CKKSDisableKeyNotifications = set; +} + +void SecCKKSTestResetFlags(void) { + SecCKKSTestSetDisableAutomaticUUID(false); + SecCKKSTestSetDisableSOS(false); + SecCKKSTestSetDisableKeyNotifications(false); +} + +XPC_RETURNS_RETAINED xpc_endpoint_t +SecServerCreateCKKSEndpoint(void) +{ + if (SecCKKSIsEnabled()) { + return [[CKKSViewManager manager] xpcControlEndpoint]; + } else { + return NULL; + } +} + +#else /* NO OCTAGON */ + +bool SecCKKSIsEnabled(void) { + secerror("CKKS was disabled at compile time."); + return false; +} + +bool SecCKKSEnable() { + return false; +} + +bool SecCKKSDisable() { + return false; +} + +bool SecCKKSResetSyncing(void) { + return SecCKKSIsEnabled(); +} + +XPC_RETURNS_RETAINED xpc_endpoint_t +SecServerCreateCKKSEndpoint(void) +{ + return NULL; +} +#endif /* OCTAGON */ + + + +void SecCKKSInitialize(SecDbRef db) { +#if OCTAGON + CKKSViewManager* manager = [CKKSViewManager manager]; + [manager initializeZones]; + + SecDbAddNotifyPhaseBlock(db, ^(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes) { + SecCKKSNotifyBlock(dbconn, phase, source, changes); + }); + + [manager.completedSecCKKSInitialize fulfill]; +#endif +} + +void SecCKKSNotifyBlock(SecDbConnectionRef dbconn, SecDbTransactionPhase phase, SecDbTransactionSource source, CFArrayRef changes) { +#if OCTAGON + if(phase == kSecDbTransactionDidRollback) { + return; + } + + // Ignore our own changes, otherwise we'd infinite-loop. + if(source == kSecDbCKKSTransaction) { + secinfo("ckks", "Ignoring kSecDbCKKSTransaction notification"); + return; + } + + CFArrayForEach(changes, ^(CFTypeRef r) { + SecDbItemRef deleted = NULL; + SecDbItemRef added = NULL; + + SecDbEventTranslateComponents(r, (CFTypeRef*) &deleted, (CFTypeRef*) &added); + + if(!added && !deleted) { + secerror("CKKS: SecDbEvent gave us garbage: %@", r); + return; + } + + [[CKKSViewManager manager] handleKeychainEventDbConnection: dbconn source:source added: added deleted: deleted]; + }); +#endif +} + +void SecCKKS24hrNotification() { +#if OCTAGON + @autoreleasepool { + [[CKKSViewManager manager] xpc24HrNotification]; + } +#endif +} + +void CKKSRegisterSyncStatusCallback(CFStringRef cfuuid, SecBoolCFErrorCallback cfcallback) { +#if OCTAGON + // Keep plumbing, but transition to NS. + SecBoolNSErrorCallback nscallback = ^(bool result, NSError* err) { + cfcallback(result, (__bridge CFErrorRef) err); + }; + + [[CKKSViewManager manager] registerSyncStatusCallback: (__bridge NSString*) cfuuid callback:nscallback]; +#endif +} diff --git a/keychain/ckks/CKKSAPSReceiver.h b/keychain/ckks/CKKSAPSReceiver.h new file mode 100644 index 00000000..9a876a91 --- /dev/null +++ b/keychain/ckks/CKKSAPSReceiver.h @@ -0,0 +1,59 @@ +/* + * 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 + +#if OCTAGON +#import +#import +#import "keychain/ckks/CloudKitDependencies.h" +#import "keychain/ckks/CKKSCondition.h" + +@protocol CKKSZoneUpdateReceiver +- (void)notifyZoneChange: (CKRecordZoneNotification*) notification; +@end + +@interface CKKSAPSReceiver : NSObject + +@property NSMapTable>* zoneMap; + +// class dependencies (for injection) +@property (readonly) Class apsConnectionClass; + +@property id apsConnection; + ++ (instancetype)receiverForEnvironment:(NSString*)environmentName + namedDelegatePort:(NSString*)namedDelegatePort + apsConnectionClass:(Class)apsConnectionClass; +- (CKKSCondition*)register:(id)receiver forZoneID:(CKRecordZoneID *)zoneID; + +// Test support: +- (instancetype)initWithEnvironmentName:(NSString*)environmentName + namedDelegatePort:(NSString*)namedDelegatePort + apsConnectionClass:(Class)apsConnectionClass; +// This is the queue that APNS will use send the notifications to us ++ (dispatch_queue_t)apsDeliveryQueue; + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSAPSReceiver.m b/keychain/ckks/CKKSAPSReceiver.m new file mode 100644 index 00000000..31bd8625 --- /dev/null +++ b/keychain/ckks/CKKSAPSReceiver.m @@ -0,0 +1,164 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "keychain/ckks/CKKSAPSReceiver.h" +#import "keychain/ckks/CKKSCondition.h" +#import +#include + +@interface CKKSAPSReceiver() +// If we receive >0 notifications for a CKRecordZoneID that hasn't been registered yet, give them a fake update when they register +@property NSMutableSet* undeliveredUpdates; +@end + +@implementation CKKSAPSReceiver + ++ (instancetype)receiverForEnvironment:(NSString *)environmentName + namedDelegatePort:(NSString*)namedDelegatePort + apsConnectionClass:(Class)apsConnectionClass { + static NSMutableDictionary* environmentMap = nil; + + if(environmentName == nil) { + secnotice("ckkspush", "No push environment; not bringing up APS."); + return nil; + } + + @synchronized([self class]) { + if(environmentMap == nil) { + environmentMap = [[NSMutableDictionary alloc] init]; + } + + CKKSAPSReceiver* recv = [environmentMap valueForKey: environmentName]; + + if(recv == nil) { + recv = [[CKKSAPSReceiver alloc] initWithEnvironmentName: environmentName namedDelegatePort:namedDelegatePort apsConnectionClass: apsConnectionClass]; + [environmentMap setValue: recv forKey: environmentName]; + } + + return recv; + } +} + ++ (dispatch_queue_t)apsDeliveryQueue { + static dispatch_queue_t aps_dispatch_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + aps_dispatch_queue = dispatch_queue_create("aps-callback-queue", DISPATCH_QUEUE_SERIAL); + }); + return aps_dispatch_queue; +} + +- (instancetype)initWithEnvironmentName:(NSString*)environmentName + namedDelegatePort:(NSString*)namedDelegatePort + apsConnectionClass:(Class)apsConnectionClass { + if(self = [super init]) { + _apsConnectionClass = apsConnectionClass; + _apsConnection = NULL; + + _undeliveredUpdates = [[NSMutableSet alloc] init]; + + // APS might be slow. This doesn't need to happen immediately, so let it happen later. + __weak __typeof(self) weakSelf = self; + dispatch_async([CKKSAPSReceiver apsDeliveryQueue], ^{ + __strong __typeof(self) strongSelf = weakSelf; + if(!strongSelf) { + return; + } + strongSelf.apsConnection = [[strongSelf.apsConnectionClass alloc] initWithEnvironmentName:environmentName namedDelegatePort:namedDelegatePort queue:[CKKSAPSReceiver apsDeliveryQueue]]; + strongSelf.apsConnection.delegate = strongSelf; + + // The following string should match: [[NSBundle mainBundle] bundleIdentifier] + NSString* topic = [kCKPushTopicPrefix stringByAppendingString:@"com.apple.securityd"]; + [strongSelf.apsConnection setEnabledTopics:@[topic]]; + }); + + _zoneMap = [NSMapTable strongToWeakObjectsMapTable]; + } + return self; +} + +- (CKKSCondition*)register:(id)receiver forZoneID:(CKRecordZoneID *)zoneID { + CKKSCondition* finished = [[CKKSCondition alloc] init]; + + __weak __typeof(self) weakSelf = self; + dispatch_async([CKKSAPSReceiver apsDeliveryQueue], ^{ + __strong __typeof(self) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckks: received registration for released CKKSAPSReceiver"); + return; + } + + [self.zoneMap setObject:receiver forKey: zoneID]; + if([strongSelf.undeliveredUpdates containsObject:zoneID]) { + [strongSelf.undeliveredUpdates removeObject:zoneID]; + + // Now, send the receiver its fake notification! + secerror("ckks: sending fake push to newly-registered zone(%@): %@", zoneID, receiver); + [receiver notifyZoneChange:nil]; + } + + [finished fulfill]; + }); + + return finished; +} + +#pragma mark - APS Delegate callbacks + +- (void)connection:(APSConnection *)connection didReceivePublicToken:(NSData *)publicToken { + // no-op. + secnotice("ckkspush", "CKKSAPSDelegate initiated: %@", connection); +} + +- (void)connection:(APSConnection *)connection didReceiveToken:(NSData *)token forTopic:(NSString *)topic identifier:(NSString *)identifier { + secnotice("ckkspush", "Received per-topic push token \"%@\" for topic \"%@\" identifier \"%@\" on connection %@", token, topic, identifier, connection); +} + +- (void)connection:(APSConnection *)connection didReceiveIncomingMessage:(APSIncomingMessage *)message { + secnotice("ckkspush", "CKKSAPSDelegate received a message: %@ on connection %@", message, connection); + + CKNotification* notification = [CKNotification notificationFromRemoteNotificationDictionary:message.userInfo]; + + if(notification.notificationType == CKNotificationTypeRecordZone) { + CKRecordZoneNotification* rznotification = (CKRecordZoneNotification*) notification; + + // Find receiever in map + id recv = [self.zoneMap objectForKey:rznotification.recordZoneID]; + if(recv) { + [recv notifyZoneChange:rznotification]; + } else { + secerror("ckks: received push for unregistered zone: %@", rznotification); + if(rznotification.recordZoneID) { + [self.undeliveredUpdates addObject: rznotification.recordZoneID]; + } + } + } else { + secerror("ckks: unexpected notification: %@", notification); + } +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSAnalyticsLogger.h b/keychain/ckks/CKKSAnalyticsLogger.h new file mode 100644 index 00000000..bacbba6c --- /dev/null +++ b/keychain/ckks/CKKSAnalyticsLogger.h @@ -0,0 +1,62 @@ +/* + * 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 + +#if OCTAGON +#import "Analytics/SFAnalyticsLogger.h" + +@class CKKSKeychainView; + +@protocol CKKSAnalyticsFailableEvent +@end +typedef NSString CKKSAnalyticsFailableEvent; +extern CKKSAnalyticsFailableEvent* const CKKSEventProcessIncomingQueueClassA; +extern CKKSAnalyticsFailableEvent* const CKKSEventProcessIncomingQueueClassC; +extern CKKSAnalyticsFailableEvent* const CKKSEventUploadChanges; + +@protocol CKKSAnalyticsSignpostEvent +@end +typedef NSString CKKSAnalyticsSignpostEvent; +extern CKKSAnalyticsSignpostEvent* const CKKSEventPushNotificationReceived; +extern CKKSAnalyticsSignpostEvent* const CKKSEventItemAddedToOutgoingQueue; + +@interface CKKSAnalyticsLogger : SFAnalyticsLogger + ++ (instancetype)logger; + +- (void)logSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view; +- (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view; +- (void)logUnrecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view; + +- (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event inView:(CKKSKeychainView*)view; + +@end + +@interface CKKSAnalyticsLogger (UniteTesting) + +- (NSDate*)dateOfLastSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view; + +@end + +#endif diff --git a/keychain/ckks/CKKSAnalyticsLogger.m b/keychain/ckks/CKKSAnalyticsLogger.m new file mode 100644 index 00000000..a87a5d08 --- /dev/null +++ b/keychain/ckks/CKKSAnalyticsLogger.m @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import "CKKSAnalyticsLogger.h" +#import "debugging.h" +#import "CKKS.h" +#import "CKKSViewManager.h" +#import "CKKSKeychainView.h" +#include +#import "Analytics/SFAnalyticsLogger.h" +#import + +NSString* const CKKSAnalyticsAttributeRecoverableError = @"recoverableError"; +NSString* const CKKSAnalyticsAttributeZoneName = @"zone"; +NSString* const CKKSAnalyticsAttributeErrorDomain = @"errorDomain"; +NSString* const CKKSAnalyticsAttributeErrorCode = @"errorCode"; + +NSString* const CKKSAnalyticsHasTLKs = @"TLKs"; +NSString* const CKKSAnalyticsSyncedClassARecently = @"inSyncA"; +NSString* const CKKSAnalyticsSyncedClassCRecently = @"inSyncC"; +NSString* const CKKSAnalyticsIncomingQueueIsErrorFree = @"IQNOE"; +NSString* const CKKSAnalyticsOutgoingQueueIsErrorFree = @"OQNOE"; +NSString* const CKKSAnalyticsInSync = @"inSync"; + +CKKSAnalyticsFailableEvent* const CKKSEventProcessIncomingQueueClassA = (CKKSAnalyticsFailableEvent*)@"CKKSEventProcessIncomingQueueClassA"; +CKKSAnalyticsFailableEvent* const CKKSEventProcessIncomingQueueClassC = (CKKSAnalyticsFailableEvent*)@"CKKSEventProcessIncomingQueueClassC"; +CKKSAnalyticsFailableEvent* const CKKSEventUploadChanges = (CKKSAnalyticsFailableEvent*)@"CKKSEventUploadChanges"; + +CKKSAnalyticsSignpostEvent* const CKKSEventPushNotificationReceived = (CKKSAnalyticsSignpostEvent*)@"CKKSEventPushNotificationReceived"; +CKKSAnalyticsSignpostEvent* const CKKSEventItemAddedToOutgoingQueue = (CKKSAnalyticsSignpostEvent*)@"CKKSEventItemAddedToOutgoingQueue"; + +@implementation CKKSAnalyticsLogger + ++ (NSString*)databasePath +{ + return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)@"ckks_analytics_v2.db") path]; +} + ++ (instancetype)logger +{ + // just here because I want it in the header for discoverability + return [super logger]; +} + +- (void)logSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view +{ + [self logSuccessForEventNamed:[NSString stringWithFormat:@"%@-%@", view.zoneName, event]]; + [self setDateProperty:[NSDate date] forKey:[NSString stringWithFormat:@"last_success_%@-%@", view.zoneName, event]]; +} + +- (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view +{ + NSDictionary* attributes = @{ CKKSAnalyticsAttributeRecoverableError : @(YES), + CKKSAnalyticsAttributeZoneName : view.zoneName, + CKKSAnalyticsAttributeErrorDomain : error.domain, + CKKSAnalyticsAttributeErrorCode : @(error.code) }; + + [super logSoftFailureForEventNamed:event withAttributes:attributes]; +} + +- (void)logUnrecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view +{ + NSDictionary* attributes = @{ CKKSAnalyticsAttributeRecoverableError : @(NO), + CKKSAnalyticsAttributeZoneName : view.zoneName, + CKKSAnalyticsAttributeErrorDomain : error.domain, + CKKSAnalyticsAttributeErrorCode : @(error.code) }; + + [self logHardFailureForEventNamed:event withAttributes:attributes]; +} + +- (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event inView:(CKKSKeychainView*)view +{ + [self noteEventNamed:[NSString stringWithFormat:@"%@-%@", view.zoneName, event]]; +} + +- (NSDate*)dateOfLastSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view +{ + return [self datePropertyForKey:[NSString stringWithFormat:@"last_success_%@-%@", view.zoneName, event]]; +} + +- (NSDictionary*)extraValuesToUploadToServer +{ + NSMutableDictionary* values = [NSMutableDictionary dictionary]; + for (NSString* viewName in [CKKSViewManager viewList]) { + CKKSKeychainView* view = [CKKSViewManager findOrCreateView:viewName]; + NSDate* dateOfLastSyncClassA = [self dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassA inView:view]; + NSDate* dateOfLastSyncClassC = [self dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassC inView:view]; + + NSInteger fuzzyDaysSinceClassASync = [CKKSAnalyticsLogger fuzzyDaysSinceDate:dateOfLastSyncClassA]; + NSInteger fuzzyDaysSinceClassCSync = [CKKSAnalyticsLogger fuzzyDaysSinceDate:dateOfLastSyncClassC]; + [values setValue:@(fuzzyDaysSinceClassASync) forKey:[NSString stringWithFormat:@"%@-daysSinceClassASync", viewName]]; + [values setValue:@(fuzzyDaysSinceClassCSync) forKey:[NSString stringWithFormat:@"%@-daysSinceClassCSync", viewName]]; + + BOOL hasTLKs = [view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateReady]; + BOOL syncedClassARecently = fuzzyDaysSinceClassASync < 7; + BOOL syncedClassCRecently = fuzzyDaysSinceClassCSync < 7; + BOOL incomingQueueIsErrorFree = view.lastIncomingQueueOperation.error == nil; + BOOL outgoingQueueIsErrorFree = view.lastOutgoingQueueOperation.error == nil; + + NSString* hasTLKsKey = [NSString stringWithFormat:@"%@-%@", viewName, CKKSAnalyticsHasTLKs]; + NSString* syncedClassARecentlyKey = [NSString stringWithFormat:@"%@-%@", viewName, CKKSAnalyticsSyncedClassARecently]; + NSString* syncedClassCRecentlyKey = [NSString stringWithFormat:@"%@-%@", viewName, CKKSAnalyticsSyncedClassCRecently]; + NSString* incomingQueueIsErrorFreeKey = [NSString stringWithFormat:@"%@-%@", viewName, CKKSAnalyticsIncomingQueueIsErrorFree]; + NSString* outgoingQueueIsErrorFreeKey = [NSString stringWithFormat:@"%@-%@", viewName, CKKSAnalyticsOutgoingQueueIsErrorFree]; + + values[hasTLKsKey] = @(hasTLKs); + values[syncedClassARecentlyKey] = @(syncedClassARecently); + values[syncedClassCRecentlyKey] = @(syncedClassCRecently); + values[incomingQueueIsErrorFreeKey] = @(incomingQueueIsErrorFree); + values[outgoingQueueIsErrorFreeKey] = @(outgoingQueueIsErrorFree); + + BOOL weThinkWeAreInSync = hasTLKs && syncedClassARecently && syncedClassCRecently && incomingQueueIsErrorFree && outgoingQueueIsErrorFree; + NSString* inSyncKey = [NSString stringWithFormat:@"%@-%@", viewName, CKKSAnalyticsInSync]; + values[inSyncKey] = @(weThinkWeAreInSync); + } + + return values; +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSCKAccountStateTracker.h b/keychain/ckks/CKKSCKAccountStateTracker.h new file mode 100644 index 00000000..b676664d --- /dev/null +++ b/keychain/ckks/CKKSCKAccountStateTracker.h @@ -0,0 +1,89 @@ +/* + * 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 + +#if OCTAGON +#import +#import +#import "keychain/ckks/CloudKitDependencies.h" +#import "keychain/ckks/CKKSCondition.h" +#include + +/* + * Implements a 'debouncer' to store the current CK account and circle state, and receive updates to it. + * + * Will only be considered "logged in" if we both have a CK account and are 'in circle'. + * + * It will notify listeners on account state changes, so multiple repeated account state notifications with the same state are filtered by this class. + * Listeners can also get the 'current' state, no matter what it is. They will also then be atomically added to the notification queue, and so will + * always receive the next update, preventing them from getting a stale state and missing an immediate update. + */ + +typedef NS_ENUM(NSInteger, CKKSAccountStatus) { + /* Set at initialization. This means we haven't figured out what the account state is. */ + CKKSAccountStatusUnknown = 0, + /* We have an iCloud account and are in-circle */ + CKKSAccountStatusAvailable = 1, + /* No iCloud account is logged in on this device, or we're out of circle */ + CKKSAccountStatusNoAccount = 3, +}; + +@protocol CKKSAccountStateListener +-(void)ckAccountStatusChange: (CKKSAccountStatus)oldStatus to:(CKKSAccountStatus)currentStatus; +@end + +@interface CKKSCKAccountStateTracker : NSObject +@property CKKSCondition* finishedInitialCalls; + +// If you use these, please be aware they could change out from under you at any time +@property CKAccountInfo* currentCKAccountInfo; +@property SOSCCStatus currentCircleStatus; + +// Fetched and memoized from CloudKit; we can't afford deadlocks with their callbacks +@property NSString* ckdeviceID; +@property NSError* ckdeviceIDError; +@property CKKSCondition* ckdeviceIDInitialized; + +// Fetched and memoized from the Account when we're in-circle; our threading model is strange +@property NSString* accountCirclePeerID; +@property NSError* accountCirclePeerIDError; +@property CKKSCondition* accountCirclePeerIDInitialized; + +-(instancetype)init: (CKContainer*) container nsnotificationCenterClass: (Class) nsnotificationCenterClass; + +-(CKKSAccountStatus)currentCKAccountStatusAndNotifyOnChange: (id) listener; + +// Methods useful for testing: + +// Call this to simulate a notification (and pause the calling thread until all notifications are delivered) +-(void)notifyCKAccountStatusChangeAndWaitForSignal; +-(void)notifyCircleStatusChangeAndWaitForSignal; + ++(SOSCCStatus)getCircleStatus; ++(void)fetchCirclePeerID:(void (^)(NSString* peerID, NSError* error))callback; ++(NSString*)stringFromAccountStatus: (CKKSAccountStatus) status; + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSCKAccountStateTracker.m b/keychain/ckks/CKKSCKAccountStateTracker.m new file mode 100644 index 00000000..4d2e2d92 --- /dev/null +++ b/keychain/ckks/CKKSCKAccountStateTracker.m @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#include +#include +#include +#include +#include + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSCKAccountStateTracker.h" + + +@interface CKKSCKAccountStateTracker () +@property (readonly) Class nsnotificationCenterClass; + +@property CKKSAccountStatus currentComputedAccountStatus; + +@property dispatch_queue_t queue; + +@property NSMapTable>* changeListeners; +@property CKContainer* container; // used only for fetching the CKAccountStatus + +/* We have initialization races. We should report CKKSAccountStatusUnknown until both of + * these are true, otherwise on a race, it looks like we logged out. */ +@property bool firstCKAccountFetch; +@property bool firstSOSCircleFetch; +@end + +@implementation CKKSCKAccountStateTracker + +-(instancetype)init: (CKContainer*) container nsnotificationCenterClass: (Class) nsnotificationCenterClass { + if((self = [super init])) { + _nsnotificationCenterClass = nsnotificationCenterClass; + _changeListeners = [NSMapTable strongToWeakObjectsMapTable]; // Backwards from how we'd like, but it's the best way to have weak pointers to CKKSAccountStateListener. + _currentCKAccountInfo = nil; + _currentCircleStatus = kSOSCCError; + + _currentComputedAccountStatus = CKKSAccountStatusUnknown; + + _container = container; + + _queue = dispatch_queue_create("ck-account-state", DISPATCH_QUEUE_SERIAL); + + _firstCKAccountFetch = false; + _firstSOSCircleFetch = false; + + _finishedInitialCalls = [[CKKSCondition alloc] init]; + _ckdeviceIDInitialized = [[CKKSCondition alloc] init]; + + id notificationCenter = [self.nsnotificationCenterClass defaultCenter]; + secinfo("ckksaccount", "Registering with notification center %@", notificationCenter); + [notificationCenter addObserver:self selector:@selector(notifyCKAccountStatusChange:) name:CKAccountChangedNotification object:NULL]; + + __weak __typeof(self) weakSelf = self; + + // If this is a live server, register with notify + if(!SecCKKSTestsEnabled()) { + int token = 0; + notify_register_dispatch(kSOSCCCircleChangedNotification, &token, dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^(int t) { + [weakSelf notifyCircleChange:nil]; + }); + } + + // Fire off a fetch of the account status. Do not go on our local queue, because notifyCKAccountStatusChange will attempt to go back on it for thread-safety. + dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ + __strong __typeof(self) strongSelf = weakSelf; + if(!strongSelf) { + return; + } + [strongSelf notifyCKAccountStatusChange:nil]; + [strongSelf notifyCircleChange:nil]; + [strongSelf.finishedInitialCalls fulfill]; + }); + } + return self; +} + +-(void)dealloc { + id notificationCenter = [self.nsnotificationCenterClass defaultCenter]; + [notificationCenter removeObserver:self]; +} + +-(NSString*)descriptionInternal: (NSString*) selfString { + return [NSString stringWithFormat:@"<%@: %@ (%@ %@)", + selfString, + [self currentStatus], + self.currentCKAccountInfo, + SOSCCGetStatusDescription(self.currentCircleStatus)]; +} + +-(NSString*)description { + return [self descriptionInternal: [[self class] description]]; +} + +-(NSString*)debugDescription { + return [self descriptionInternal: [super description]]; +} + +-(CKKSAccountStatus)currentCKAccountStatusAndNotifyOnChange: (id) listener { + + __block CKKSAccountStatus status = CKKSAccountStatusUnknown; + + dispatch_sync(self.queue, ^{ + status = self.currentComputedAccountStatus; + + bool alreadyRegisteredListener = false; + NSEnumerator *enumerator = [self.changeListeners objectEnumerator]; + id value; + + while ((value = [enumerator nextObject])) { + // do pointer comparison + alreadyRegisteredListener |= (value == listener); + } + + if(listener && !alreadyRegisteredListener) { + NSString* queueName = [NSString stringWithFormat: @"ck-account-state-%@", listener]; + + dispatch_queue_t objQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL); + [self.changeListeners setObject: listener forKey: objQueue]; + } + }); + return status; +} + +- (dispatch_semaphore_t)notifyCKAccountStatusChange:(__unused id)object { + // signals when this notify is Complete, including all downcalls. + dispatch_semaphore_t finishedSema = dispatch_semaphore_create(0); + + [self.container accountInfoWithCompletionHandler:^(CKAccountInfo* ckAccountInfo, NSError * _Nullable error) { + if(error) { + secerror("ckksaccount: error getting account info: %@", error); + dispatch_semaphore_signal(finishedSema); + return; + } + + dispatch_sync(self.queue, ^{ + self.firstCKAccountFetch = true; + [self _onqueueUpdateAccountState:ckAccountInfo circle:self.currentCircleStatus deliveredSemaphore:finishedSema]; + }); + }]; + + return finishedSema; +} + +-(dispatch_semaphore_t)notifyCircleChange:(__unused id)object { + dispatch_semaphore_t finishedSema = dispatch_semaphore_create(0); + + SOSCCStatus circleStatus = [CKKSCKAccountStateTracker getCircleStatus]; + if(circleStatus == kSOSCCError) { + dispatch_semaphore_signal(finishedSema); + return finishedSema; + } + + dispatch_sync(self.queue, ^{ + self.firstSOSCircleFetch = true; + + [self _onqueueUpdateAccountState:self.currentCKAccountInfo circle:circleStatus deliveredSemaphore:finishedSema]; + }); + return finishedSema; +} + +// Takes the new ckAccountInfo we're moving to +-(void)_onqueueUpdateCKDeviceID: (CKAccountInfo*)ckAccountInfo { + dispatch_assert_queue(self.queue); + __weak __typeof(self) weakSelf = self; + + // If we're in an account, opportunistically fill in the device id + if(ckAccountInfo.accountStatus == CKAccountStatusAvailable) { + [self.container fetchCurrentDeviceIDWithCompletionHandler:^(NSString* deviceID, NSError* ckerror) { + __strong __typeof(self) strongSelf = weakSelf; + + // Make sure you synchronize here; if we've logged out before the callback returns, don't record the result + dispatch_async(strongSelf.queue, ^{ + __strong __typeof(self) innerStrongSelf = weakSelf; + if(innerStrongSelf.currentCKAccountInfo.accountStatus == CKAccountStatusAvailable) { + secnotice("ckksaccount", "CloudKit deviceID is: %@ %@", deviceID, ckerror); + + innerStrongSelf.ckdeviceID = deviceID; + innerStrongSelf.ckdeviceIDError = ckerror; + [innerStrongSelf.ckdeviceIDInitialized fulfill]; + } else { + // Logged out! No ckdeviceid. + secerror("ckksaccount: Logged back out but still received a fetchCurrentDeviceIDWithCompletionHandler callback"); + + innerStrongSelf.ckdeviceID = nil; + innerStrongSelf.ckdeviceIDError = nil; + // Don't touch the ckdeviceIDInitialized object; it should have been reset when the logout happened. + } + }); + }]; + } else { + // Logging out? no more device ID. + self.ckdeviceID = nil; + self.ckdeviceIDError = nil; + self.ckdeviceIDInitialized = [[CKKSCondition alloc] init]; + } +} + +// Pulled out for mocking purposes ++(void)fetchCirclePeerID:(void (^)(NSString* _Nullable peerID, NSError* _Nullable error))callback { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + CFErrorRef cferror = nil; + SOSPeerInfoRef egoPeerInfo = SOSCCCopyMyPeerInfo(&cferror); + NSString* egoPeerID = egoPeerInfo ? (NSString*)CFBridgingRelease(CFRetainSafe(SOSPeerInfoGetPeerID(egoPeerInfo))) : nil; + CFReleaseNull(egoPeerInfo); + + callback(egoPeerID, CFBridgingRelease(cferror)); + }); +} + +// Takes the new ckAccountInfo we're moving to +-(void)_onqueueUpdateCirclePeerID: (SOSCCStatus)sosccstatus { + dispatch_assert_queue(self.queue); + __weak __typeof(self) weakSelf = self; + + // If we're in a circle, fetch the peer id + if(sosccstatus == kSOSCCInCircle) { + [CKKSCKAccountStateTracker fetchCirclePeerID:^(NSString* peerID, NSError* error) { + __strong __typeof(self) strongSelf = weakSelf; + dispatch_async(strongSelf.queue, ^{ + __strong __typeof(self) innerstrongSelf = weakSelf; + + if(innerstrongSelf.currentCircleStatus == kSOSCCInCircle) { + secnotice("ckksaccount", "Circle peerID is: %@ %@", peerID, error); + // Still in circle. Proceed. + innerstrongSelf.accountCirclePeerID = peerID; + innerstrongSelf.accountCirclePeerIDError = error; + [innerstrongSelf.accountCirclePeerIDInitialized fulfill]; + } else { + secerror("ckksaccount: Out of circle but still received a fetchCirclePeerID callback"); + // Not in-circle. Throw away circle id. + strongSelf.accountCirclePeerID = nil; + strongSelf.accountCirclePeerIDError = nil; + // Don't touch the accountCirclePeerIDInitialized object; it should have been reset when the logout happened. + } + }); + }]; + } else { + // Not in-circle, reset circle ID + self.accountCirclePeerID = nil; + self.accountCirclePeerIDError = nil; + self.accountCirclePeerIDInitialized = [[CKKSCondition alloc] init]; + } +} + +-(void)_onqueueUpdateAccountState: (CKAccountInfo*) ckAccountInfo circle: (SOSCCStatus) sosccstatus deliveredSemaphore: (dispatch_semaphore_t) finishedSema { + dispatch_assert_queue(self.queue); + + if([self.currentCKAccountInfo isEqual: ckAccountInfo] && self.currentCircleStatus == sosccstatus) { + // no-op. + secinfo("ckksaccount", "received another notification of CK Account State %@ and Circle status %d", ckAccountInfo, (int)sosccstatus); + dispatch_semaphore_signal(finishedSema); + return; + } + + if(![self.currentCKAccountInfo isEqual: ckAccountInfo]) { + secnotice("ckksaccount", "moving to CK Account info: %@", ckAccountInfo); + self.currentCKAccountInfo = ckAccountInfo; + + [self _onqueueUpdateCKDeviceID: ckAccountInfo]; + } + if(self.currentCircleStatus != sosccstatus) { + secnotice("ckksaccount", "moving to circle status: %@", SOSCCGetStatusDescription(sosccstatus)); + self.currentCircleStatus = sosccstatus; + + [self _onqueueUpdateCirclePeerID: sosccstatus]; + } + + if(!self.firstSOSCircleFetch || !self.firstCKAccountFetch) { + secnotice("ckksaccount", "Haven't received updates from all sources; not passing update along: %@", self); + dispatch_semaphore_signal(finishedSema); + return; + } + + // We are CKKSAccountStatusAvailable if we are: + // in CKAccountStatusAvailable + // and in circle + // and supportsDeviceToDeviceEncryption == true + CKKSAccountStatus oldComputedStatus = self.currentComputedAccountStatus; + + if(self.currentCKAccountInfo) { + if(self.currentCKAccountInfo.accountStatus == CKAccountStatusAvailable) { + // CloudKit thinks we're logged in. Double check! + if(self.currentCKAccountInfo.supportsDeviceToDeviceEncryption && self.currentCircleStatus == kSOSCCInCircle) { + self.currentComputedAccountStatus = CKKSAccountStatusAvailable; + } else { + self.currentComputedAccountStatus = CKKSAccountStatusNoAccount; + } + + } else { + // Account status is not CKAccountStatusAvailable; no more checking required. + self.currentComputedAccountStatus = CKKSAccountStatusNoAccount; + } + } else { + // No CKAccountInfo? We haven't received an update from cloudd yet; Change nothing. + } + + if(oldComputedStatus == self.currentComputedAccountStatus) { + secnotice("ckksaccount", "No change in computed account status: %@ (%@ %@)", + [self currentStatus], + self.currentCKAccountInfo, + SOSCCGetStatusDescription(self.currentCircleStatus)); + dispatch_semaphore_signal(finishedSema); + return; + } + + secnotice("ckksaccount", "New computed account status: %@ (%@ %@)", + [self currentStatus], + self.currentCKAccountInfo, + SOSCCGetStatusDescription(self.currentCircleStatus)); + + dispatch_group_t g = dispatch_group_create(); + if(!g) { + secnotice("ckksaccount", "Unable to get dispatch group."); + return; + } + + NSEnumerator *enumerator = [self.changeListeners keyEnumerator]; + dispatch_queue_t dq; + + // Queue up the changes for each listener. + while ((dq = [enumerator nextObject])) { + id listener = [self.changeListeners objectForKey: dq]; + __weak __typeof(listener) weakListener = listener; + + if(listener) { + dispatch_group_async(g, dq, ^{ + [weakListener ckAccountStatusChange: oldComputedStatus to: self.currentComputedAccountStatus]; + }); + } + } + + dispatch_group_notify(g, self.queue, ^{ + dispatch_semaphore_signal(finishedSema); + }); +} + +-(void)notifyCKAccountStatusChangeAndWaitForSignal { + dispatch_semaphore_wait([self notifyCKAccountStatusChange: nil], DISPATCH_TIME_FOREVER); +} + +-(void)notifyCircleStatusChangeAndWaitForSignal { + dispatch_semaphore_wait([self notifyCircleChange: nil], DISPATCH_TIME_FOREVER); +} + +// This is its own function to allow OCMock to swoop in and replace the result during testing. ++(SOSCCStatus)getCircleStatus { + CFErrorRef cferror = NULL; + + SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror); + if(cferror) { + secerror("ckksaccount: error getting circle status: %@", cferror); + CFReleaseNull(cferror); + return kSOSCCError; + } + return status; +} + +-(NSString*)currentStatus { + return [CKKSCKAccountStateTracker stringFromAccountStatus:self.currentComputedAccountStatus]; +} + ++(NSString*)stringFromAccountStatus: (CKKSAccountStatus) status { + switch(status) { + case CKKSAccountStatusUnknown: return @"account state unknown"; + case CKKSAccountStatusAvailable: return @"logged in"; + case CKKSAccountStatusNoAccount: return @"no account"; + } +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSCondition.h b/keychain/ckks/CKKSCondition.h new file mode 100644 index 00000000..ff6cf694 --- /dev/null +++ b/keychain/ckks/CKKSCondition.h @@ -0,0 +1,44 @@ +/* + * 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 +#import + +/* + * CKKSCondition is for implementing one-shot condition variables, + * based on libdispatch semaphores (which might use condition variables underneath). + */ + +@interface CKKSCondition : NSObject + +-(instancetype)init; + +/* Fulfills the condition. Can only be called once per CKKSCondition. */ +-(void)fulfill; + +/* Wait for the the condition to be fulfilled. The returned result behaves exactly like + libdispatch's dispatch_semaphore_wait. */ +-(long)wait:(uint64_t)timeout; + +@end + diff --git a/keychain/ckks/CKKSCondition.m b/keychain/ckks/CKKSCondition.m new file mode 100644 index 00000000..998c3485 --- /dev/null +++ b/keychain/ckks/CKKSCondition.m @@ -0,0 +1,56 @@ +/* + * 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 "keychain/ckks/CKKSCondition.h" + +@interface CKKSCondition () +@property dispatch_semaphore_t semaphore; +@end + +@implementation CKKSCondition + +-(instancetype)init +{ + if((self = [super init])) { + _semaphore = dispatch_semaphore_create(0); + } + return self; +} + +-(void)fulfill { + dispatch_semaphore_signal(self.semaphore); +} + +-(long)wait:(uint64_t)timeout { + long result = dispatch_semaphore_wait(self.semaphore, dispatch_time(DISPATCH_TIME_NOW, timeout)); + + // If we received a go-ahead from the semaphore, replace the signal + if(0 == result) { + dispatch_semaphore_signal(self.semaphore); + } + + return result; +} + +@end + diff --git a/keychain/ckks/CKKSControlProtocol.h b/keychain/ckks/CKKSControlProtocol.h new file mode 100644 index 00000000..ce241101 --- /dev/null +++ b/keychain/ckks/CKKSControlProtocol.h @@ -0,0 +1,40 @@ +/* + * 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 + +@protocol CKKSControlProtocol +- (void)performanceCounters:(void(^)(NSDictionary *))reply; +- (void)rpcResetLocal: (NSString*)viewName reply: (void(^)(NSError* result)) reply; +- (void)rpcResetCloudKit: (NSString*)viewName reply: (void(^)(NSError* result)) reply; +- (void)rpcResync:(NSString*)viewName reply: (void(^)(NSError* result)) reply; +- (void)rpcStatus:(NSString*)viewName reply: (void(^)(NSArray* result, NSError* error)) reply; +- (void)rpcFetchAndProcessChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply; +- (void)rpcFetchAndProcessClassAChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply; +- (void)rpcPushOutgoingChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply; +- (void)rpcGetAnalyticsSysdiagnoseWithReply:(void (^)(NSString* sysdiagnose, NSError* error))reply; +- (void)rpcGetAnalyticsJSONWithReply:(void (^)(NSData* json, NSError* error))reply; +- (void)rpcForceUploadAnalyticsWithReply:(void (^)(BOOL success, NSError* error))reply; +@end + +NSXPCInterface* CKKSSetupControlProtocol(NSXPCInterface* interface); diff --git a/keychain/ckks/CKKSControlProtocol.m b/keychain/ckks/CKKSControlProtocol.m new file mode 100644 index 00000000..0cb2bd69 --- /dev/null +++ b/keychain/ckks/CKKSControlProtocol.m @@ -0,0 +1,108 @@ +/* + * 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 + +#import "keychain/ckks/CKKSControlProtocol.h" + +#if OCTAGON +#import +#import +#import +#include + +// Weak-link CloudKit, until we can get ckksctl out of base system +static void *cloudKit = NULL; + +static void +initCloudKit(void) +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + cloudKit = dlopen("/System/Library/Frameworks/CloudKit.framework/CloudKit", RTLD_LAZY); + }); +} + +static void +getCloudKitSymbol(void **sym, const char *name) +{ + initCloudKit(); + if (!sym || *sym) { + return; + } + *sym = dlsym(cloudKit, name); + if (*sym == NULL) { + fprintf(stderr, "symbol %s is missing", name); + abort(); + } +} +#endif // OCTAGON + +NSXPCInterface* CKKSSetupControlProtocol(NSXPCInterface* interface) { +#if OCTAGON + static NSMutableSet *errClasses; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + __typeof(CKAcceptableValueClasses) *soft_CKAcceptableValueClasses = NULL; + getCloudKitSymbol((void **)&soft_CKAcceptableValueClasses, "CKAcceptableValueClasses"); + errClasses = [NSMutableSet setWithSet:soft_CKAcceptableValueClasses()]; + + char *classes[] = { + "CKPrettyError", + "CKRecordID", + "NSURL", + "NSError" + }; + + for (unsigned n = 0; n < sizeof(classes)/sizeof(classes[0]); n++) { + Class cls = objc_getClass(classes[n]); + if (cls) { + [errClasses addObject:cls]; + } + } + }); + + @try { + [interface setClasses:errClasses forSelector:@selector(rpcResetLocal:reply:) argumentIndex:0 ofReply:YES]; + [interface setClasses:errClasses forSelector:@selector(rpcResetCloudKit:reply:) argumentIndex:0 ofReply:YES]; + [interface setClasses:errClasses forSelector:@selector(rpcResync:reply:) argumentIndex:0 ofReply:YES]; + [interface setClasses:errClasses forSelector:@selector(rpcStatus: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(rpcGetAnalyticsJSONWithReply:) argumentIndex:1 ofReply:YES]; + [interface setClasses:errClasses forSelector:@selector(rpcForceUploadAnalyticsWithReply:) argumentIndex:1 ofReply:YES]; + [interface setClasses:errClasses forSelector:@selector(rpcGetAnalyticsSysdiagnoseWithReply:) argumentIndex:1 ofReply:YES]; + } + @catch(NSException* e) { + secerror("CKKSSetupControlProtocol failed, continuing, but you might crash later: %@", e); +#if DEBUG + @throw e; +#endif + } +#endif + + return interface; +} + diff --git a/keychain/ckks/CKKSCurrentItemPointer.h b/keychain/ckks/CKKSCurrentItemPointer.h new file mode 100644 index 00000000..694118fc --- /dev/null +++ b/keychain/ckks/CKKSCurrentItemPointer.h @@ -0,0 +1,52 @@ +/* + * 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 + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSItem.h" +#import "keychain/ckks/CKKSKey.h" + +#if OCTAGON + +@interface CKKSCurrentItemPointer : CKKSCKRecordHolder + +@property CKKSProcessedState* state; +@property NSString* identifier; +@property NSString* currentItemUUID; + +- (instancetype)initForIdentifier:(NSString*)identifier + currentItemUUID:(NSString*)currentItemUUID + state:(CKKSProcessedState*)state + zoneID:(CKRecordZoneID*)zoneID + encodedCKRecord:(NSData*) encodedrecord; + ++ (instancetype) fromDatabase:(NSString*)identifier state:(CKKSProcessedState*)state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase:(NSString*)identifier state:(CKKSProcessedState*)state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (NSArray*)remoteItemPointers: (CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error; ++ (bool) deleteAll:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *) error; + +@end + +#endif diff --git a/keychain/ckks/CKKSCurrentItemPointer.m b/keychain/ckks/CKKSCurrentItemPointer.m new file mode 100644 index 00000000..1d4203fb --- /dev/null +++ b/keychain/ckks/CKKSCurrentItemPointer.m @@ -0,0 +1,158 @@ +/* + * 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 "keychain/ckks/CKKSCurrentItemPointer.h" + +#if OCTAGON + +@implementation CKKSCurrentItemPointer + +- (instancetype)initForIdentifier:(NSString*)identifier + currentItemUUID:(NSString*)currentItemUUID + state:(CKKSProcessedState*)state + zoneID:(CKRecordZoneID*)zoneID + encodedCKRecord: (NSData*) encodedrecord +{ + if(self = [super initWithCKRecordType: SecCKRecordCurrentItemType encodedCKRecord:encodedrecord zoneID:zoneID]) { + _state = state; + _identifier = identifier; + _currentItemUUID = currentItemUUID; + } + return self; +} + +- (NSString*)description { + return [NSString stringWithFormat:@"", self.zoneID.zoneName, self.identifier, self.currentItemUUID]; +} + +#pragma mark - CKKSCKRecordHolder methods + +- (NSString*) CKRecordName { + return self.identifier; +} + +- (CKRecord*)updateCKRecord: (CKRecord*) record zoneID: (CKRecordZoneID*) zoneID { + // The record name should already match identifier... + if(![record.recordID.recordName isEqualToString: self.identifier]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordNameException" + reason:[NSString stringWithFormat: @"CKRecord name (%@) was not %@", record.recordID.recordName, self.identifier] + userInfo:nil]; + } + + // Set the parent reference + record[SecCKRecordItemRefKey] = [[CKReference alloc] initWithRecordID: [[CKRecordID alloc] initWithRecordName: self.currentItemUUID zoneID: zoneID] + action: CKReferenceActionNone]; + return record; +} + +- (bool)matchesCKRecord: (CKRecord*) record { + if(![record.recordType isEqualToString: SecCKRecordCurrentItemType]) { + return false; + } + + if(![record.recordID.recordName isEqualToString: self.identifier]) { + return false; + } + + if(![[record[SecCKRecordItemRefKey] recordID].recordName isEqualToString: self.currentItemUUID]) { + return false; + } + + return true; +} + +- (void)setFromCKRecord: (CKRecord*) record { + if(![record.recordType isEqualToString: SecCKRecordCurrentItemType]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordTypeException" + reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordCurrentItemType] + userInfo:nil]; + } + + [self setStoredCKRecord:record]; + + self.identifier = (CKKSKeyClass*) record.recordID.recordName; + self.currentItemUUID = [record[SecCKRecordItemRefKey] recordID].recordName; +} + +#pragma mark - Load from database + ++ (instancetype)fromDatabase:(NSString*)identifier state:(CKKSProcessedState*)state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"identifier":identifier, @"state":state, @"ckzone":zoneID.zoneName} error: error]; +} + ++ (instancetype)tryFromDatabase:(NSString*)identifier state:(CKKSProcessedState*)state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"identifier":identifier, @"state":state, @"ckzone":zoneID.zoneName} error: error]; +} + ++ (NSArray*)remoteItemPointers: (CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere: @{@"state": SecCKKSProcessedStateRemote, @"ckzone":zoneID.zoneName} error:error]; +} + ++ (bool)deleteAll:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error { + bool ok = [CKKSSQLDatabaseObject deleteFromTable:[self sqlTable] where: @{@"ckzone":zoneID.zoneName} connection:nil error: error]; + + if(ok) { + secdebug("ckksitem", "Deleted all %@", self); + } else { + secdebug("ckksitem", "Couldn't delete all %@: %@", self, error ? *error : @"unknown"); + } + return ok; +} + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*)sqlTable { + return @"currentitems"; +} + ++ (NSArray*)sqlColumns { + return @[@"identifier", @"currentItemUUID", @"state", @"ckzone", @"ckrecord"]; +} + +- (NSDictionary*) whereClauseToFindSelf { + return @{@"identifier": self.identifier, @"ckzone":self.zoneID.zoneName, @"currentItemUUID": CKKSNilToNSNull(self.currentItemUUID), @"state":self.state}; +} + +- (NSDictionary*)sqlValues { + return @{@"identifier": self.identifier, + @"currentItemUUID": CKKSNilToNSNull(self.currentItemUUID), + @"state": CKKSNilToNSNull(self.state), + @"ckzone": CKKSNilToNSNull(self.zoneID.zoneName), + @"ckrecord": CKKSNilToNSNull([self.encodedCKRecord base64EncodedStringWithOptions:0]), + }; +} + ++ (instancetype)fromDatabaseRow: (NSDictionary*) row { + return [[CKKSCurrentItemPointer alloc] initForIdentifier:row[@"identifier"] + currentItemUUID:CKKSNSNullToNil(row[@"currentItemUUID"]) + state:CKKSNSNullToNil(row[@"state"]) + zoneID:[[CKRecordZoneID alloc] initWithZoneName: row[@"ckzone"] ownerName:CKCurrentUserDefaultName] + encodedCKRecord:[[NSData alloc] initWithBase64EncodedString: row[@"ckrecord"] options:0]]; +} + +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/CKKSCurrentKeyPointer.h b/keychain/ckks/CKKSCurrentKeyPointer.h new file mode 100644 index 00000000..a26b2b42 --- /dev/null +++ b/keychain/ckks/CKKSCurrentKeyPointer.h @@ -0,0 +1,65 @@ +/* + * 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 + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSItem.h" +#import "keychain/ckks/CKKSKey.h" + +#if OCTAGON + +@interface CKKSCurrentKeyPointer : CKKSCKRecordHolder + +@property CKKSKeyClass* keyclass; +@property NSString* currentKeyUUID; + +- (instancetype)initForClass:(CKKSKeyClass*)keyclass + currentKeyUUID:(NSString*)currentKeyUUID + zoneID:(CKRecordZoneID*)zoneID + encodedCKRecord: (NSData*) encodedrecord; + ++ (instancetype) fromDatabase: (CKKSKeyClass*) keyclass zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase: (CKKSKeyClass*) keyclass zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (instancetype) forKeyClass: (CKKSKeyClass*) keyclass withKeyUUID: (NSString*) keyUUID zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (NSArray*)all:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (bool) deleteAll:(CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error; + +@end + +@interface CKKSCurrentKeySet : NSObject +@property NSError* error; +@property CKKSKey* tlk; +@property CKKSKey* classA; +@property CKKSKey* classC; +@property CKKSCurrentKeyPointer* currentTLKPointer; +@property CKKSCurrentKeyPointer* currentClassAPointer; +@property CKKSCurrentKeyPointer* currentClassCPointer; + +-(instancetype)init; +-(instancetype)initForZone:(CKRecordZoneID*)zoneID; +@end + +#endif diff --git a/keychain/ckks/CKKSCurrentKeyPointer.m b/keychain/ckks/CKKSCurrentKeyPointer.m new file mode 100644 index 00000000..c80520c5 --- /dev/null +++ b/keychain/ckks/CKKSCurrentKeyPointer.m @@ -0,0 +1,219 @@ +/* + * 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 "CKKSCurrentKeyPointer.h" + +#if OCTAGON + +@implementation CKKSCurrentKeyPointer + +- (instancetype)initForClass:(CKKSKeyClass*)keyclass + currentKeyUUID:(NSString*)currentKeyUUID + zoneID:(CKRecordZoneID*)zoneID + encodedCKRecord: (NSData*) encodedrecord +{ + if(self = [super initWithCKRecordType: SecCKRecordCurrentKeyType encodedCKRecord:encodedrecord zoneID:zoneID]) { + _keyclass = keyclass; + _currentKeyUUID = currentKeyUUID; + + if(self.currentKeyUUID == nil) { + secerror("ckkscurrentkey: created a CKKSCurrentKey with a nil currentKeyUUID. Why?"); + } + } + return self; +} + +- (NSString*)description { + return [NSString stringWithFormat:@"", self.zoneID.zoneName, self.keyclass, self.currentKeyUUID]; +} + +#pragma mark - CKKSCKRecordHolder methods + +- (NSString*) CKRecordName { + return self.keyclass; +} + +- (CKRecord*) updateCKRecord: (CKRecord*) record zoneID: (CKRecordZoneID*) zoneID { + // The record name should already match keyclass... + if(![record.recordID.recordName isEqualToString: self.keyclass]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordNameException" + reason:[NSString stringWithFormat: @"CKRecord name (%@) was not %@", record.recordID.recordName, self.keyclass] + userInfo:nil]; + } + + // Set the parent reference + record[SecCKRecordParentKeyRefKey] = [[CKReference alloc] initWithRecordID: [[CKRecordID alloc] initWithRecordName: self.currentKeyUUID zoneID: zoneID] action: CKReferenceActionNone]; + return record; +} + +- (bool) matchesCKRecord: (CKRecord*) record { + if(![record.recordType isEqualToString: SecCKRecordCurrentKeyType]) { + return false; + } + + if(![record.recordID.recordName isEqualToString: self.keyclass]) { + return false; + } + + if(![[record[SecCKRecordParentKeyRefKey] recordID].recordName isEqualToString: self.currentKeyUUID]) { + return false; + } + + return true; +} + +- (void) setFromCKRecord: (CKRecord*) record { + if(![record.recordType isEqualToString: SecCKRecordCurrentKeyType]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordTypeException" + reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordCurrentKeyType] + userInfo:nil]; + } + + [self setStoredCKRecord:record]; + + // TODO: verify this is a real keyclass + self.keyclass = (CKKSKeyClass*) record.recordID.recordName; + self.currentKeyUUID = [record[SecCKRecordParentKeyRefKey] recordID].recordName; + + if(self.currentKeyUUID == nil) { + secerror("ckkscurrentkey: No current key UUID in record! How/why? %@", record); + } +} + +#pragma mark - Load from database + ++ (instancetype) fromDatabase: (CKKSKeyClass*) keyclass zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"keyclass": keyclass, @"ckzone":zoneID.zoneName} error: error]; +} + ++ (instancetype) tryFromDatabase: (CKKSKeyClass*) keyclass zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"keyclass": keyclass, @"ckzone":zoneID.zoneName} error: error]; +} + ++ (instancetype) forKeyClass: (CKKSKeyClass*) keyclass withKeyUUID: (NSString*) keyUUID zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + NSError* localerror = nil; + CKKSCurrentKeyPointer* current = [self tryFromDatabase: keyclass zoneID:zoneID error: &localerror]; + if(localerror) { + if(error) { + *error = localerror; + } + return nil; + } + + if(current) { + current.currentKeyUUID = keyUUID; + return current; + } + + return [[CKKSCurrentKeyPointer alloc] initForClass: keyclass currentKeyUUID: keyUUID zoneID:zoneID encodedCKRecord:nil]; +} + ++ (NSArray*)all:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere:@{@"ckzone":zoneID.zoneName} error:error]; +} + ++ (bool) deleteAll:(CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error { + bool ok = [CKKSSQLDatabaseObject deleteFromTable:[self sqlTable] where: @{@"ckzone":zoneID.zoneName} connection:nil error: error]; + + if(ok) { + secdebug("ckksitem", "Deleted all %@", self); + } else { + secdebug("ckksitem", "Couldn't delete all %@: %@", self, error ? *error : @"unknown"); + } + return ok; +} + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*) sqlTable { + return @"currentkeys"; +} + ++ (NSArray*) sqlColumns { + return @[@"keyclass", @"currentKeyUUID", @"ckzone", @"ckrecord"]; +} + +- (NSDictionary*) whereClauseToFindSelf { + return @{@"keyclass": self.keyclass, @"ckzone":self.zoneID.zoneName}; +} + +- (NSDictionary*) sqlValues { + return @{@"keyclass": self.keyclass, + @"currentKeyUUID": CKKSNilToNSNull(self.currentKeyUUID), + @"ckzone": CKKSNilToNSNull(self.zoneID.zoneName), + @"ckrecord": CKKSNilToNSNull([self.encodedCKRecord base64EncodedStringWithOptions:0]), + }; +} + ++ (instancetype) fromDatabaseRow: (NSDictionary*) row { + return [[CKKSCurrentKeyPointer alloc] initForClass: row[@"keyclass"] + currentKeyUUID: [row[@"currentKeyUUID"] isEqual: [NSNull null]] ? nil : row[@"currentKeyUUID"] + zoneID: [[CKRecordZoneID alloc] initWithZoneName: row[@"ckzone"] ownerName:CKCurrentUserDefaultName] + encodedCKRecord: [[NSData alloc] initWithBase64EncodedString: row[@"ckrecord"] options:0]]; +} + +@end + +@implementation CKKSCurrentKeySet +-(instancetype)init { + if((self = [super init])) { + } + + return self; +} +-(instancetype)initForZone:(CKRecordZoneID*)zoneID { + if((self = [super init])) { + NSError* error = nil; + _currentTLKPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassTLK zoneID:zoneID error:&error]; + _currentClassAPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassA zoneID:zoneID error:&error]; + _currentClassCPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassC zoneID:zoneID error:&error]; + + _tlk = _currentTLKPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:_currentTLKPointer.currentKeyUUID zoneID:zoneID error:&error] : nil; + _classA = _currentClassAPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:_currentClassAPointer.currentKeyUUID zoneID:zoneID error:&error] : nil; + _classC = _currentClassCPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:_currentClassCPointer.currentKeyUUID zoneID:zoneID error:&error] : nil; + + _error = error; + } + + return self; +} +-(NSString*)description { + if(self.error) { + return [NSString stringWithFormat:@"", + self.currentTLKPointer.currentKeyUUID, self.tlk, + self.currentClassAPointer.currentKeyUUID, self.classA, + self.currentClassCPointer.currentKeyUUID, self.classC, + self.error]; + + } else { + return [NSString stringWithFormat:@"", + self.currentTLKPointer.currentKeyUUID, self.tlk, + self.currentClassAPointer.currentKeyUUID, self.classA, + self.currentClassCPointer.currentKeyUUID, self.classC]; + } +} +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSDeviceStateEntry.h b/keychain/ckks/CKKSDeviceStateEntry.h new file mode 100644 index 00000000..8634310f --- /dev/null +++ b/keychain/ckks/CKKSDeviceStateEntry.h @@ -0,0 +1,76 @@ +/* + * 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 CKKSDeviceStateEntry_h +#define CKKSDeviceStateEntry_h + +#if OCTAGON + +#include +#include + +#import +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSSQLDatabaseObject.h" +#import "keychain/ckks/CKKSRecordHolder.h" + +/* + * This is the backing class for "device state" records: each device in an iCloud account copies + * some state about itself into each keychain view it wants to participate in. + * + * This shares some overlap with the CKKSZoneStateEntry, but differs in that: + * - This will be uploaded to CloudKit + * - We will have receive such records from other devices + */ + +@interface CKKSDeviceStateEntry : CKKSCKRecordHolder +@property NSString* device; + +@property NSString* circlePeerID; +@property SOSCCStatus circleStatus; +@property CKKSZoneKeyState* keyState; + +@property NSString* currentTLKUUID; +@property NSString* currentClassAUUID; +@property NSString* currentClassCUUID; + ++ (instancetype)fromDatabase:(NSString*)device zoneID:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error; ++ (instancetype)tryFromDatabase:(NSString*)device zoneID:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error; ++ (instancetype)tryFromDatabaseFromCKRecordID:(CKRecordID*)recordID error:(NSError * __autoreleasing *)error; ++ (NSArray*)allInZone:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initForDevice:(NSString*)device + circlePeerID:(NSString*)circlePeerID + circleStatus:(SOSCCStatus)circleStatus + keyState:(CKKSZoneKeyState*)keyState + currentTLKUUID:(NSString*)currentTLKUUID + currentClassAUUID:(NSString*)currentClassAUUID + currentClassCUUID:(NSString*)currentClassCUUID + zoneID:(CKRecordZoneID*)zoneID + encodedCKRecord:(NSData*)encodedrecord; +@end + +#endif // OCTAGON +#endif /* CKKSDeviceStateEntry_h */ + diff --git a/keychain/ckks/CKKSDeviceStateEntry.m b/keychain/ckks/CKKSDeviceStateEntry.m new file mode 100644 index 00000000..38af3b74 --- /dev/null +++ b/keychain/ckks/CKKSDeviceStateEntry.m @@ -0,0 +1,301 @@ +/* + * 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@ + */ + +#if OCTAGON + +#include + +#import + +#import +#import +#import "keychain/ckks/CKKSDeviceStateEntry.h" +#import "keychain/ckks/CKKSKeychainView.h" +#include + +@implementation CKKSDeviceStateEntry + +- (instancetype)initForDevice:(NSString*)device + circlePeerID:(NSString*)circlePeerID + circleStatus:(SOSCCStatus)circleStatus + keyState:(CKKSZoneKeyState*)keyState + currentTLKUUID:(NSString*)currentTLKUUID + currentClassAUUID:(NSString*)currentClassAUUID + currentClassCUUID:(NSString*)currentClassCUUID + zoneID:(CKRecordZoneID*)zoneID + encodedCKRecord:(NSData*)encodedrecord +{ + if((self = [super initWithCKRecordType:SecCKRecordDeviceStateType + encodedCKRecord:encodedrecord + zoneID:zoneID])) { + _device = device; + _circleStatus = circleStatus; + _keyState = keyState; + + _circlePeerID = circlePeerID; + + _currentTLKUUID = currentTLKUUID; + _currentClassAUUID = currentClassAUUID; + _currentClassCUUID = currentClassCUUID; + } + return self; +} + +#define kSOSCCErrorPositive 111 + +-(id)sosCCStatusToCKType:(SOSCCStatus)status { + // kSOSCCError is -1, but without a size. + // make it a special number + if(status == kSOSCCError) { + [NSNumber numberWithInt:kSOSCCErrorPositive]; + } + return [NSNumber numberWithInt:status]; +} + +-(SOSCCStatus)cktypeToSOSCCStatus:(id)object { + if(![object isKindOfClass:[NSNumber class]]) { + return kSOSCCError; + } + NSNumber* number = (NSNumber*)object; + + uint32_t n = [number unsignedIntValue]; + + switch(n) { + case (uint32_t)kSOSCCInCircle: + return kSOSCCInCircle; + case (uint32_t)kSOSCCNotInCircle: + return kSOSCCNotInCircle; + case (uint32_t)kSOSCCRequestPending: + return kSOSCCRequestPending; + case (uint32_t)kSOSCCCircleAbsent: + return kSOSCCCircleAbsent; + case (uint32_t)kSOSCCErrorPositive: // Use the magic number + return kSOSCCError; + 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); + return kSOSCCError; + } +} + ++(NSString*)nameFromCKRecordID:(CKRecordID*)recordID { + // Strip off the prefix from the recordName + NSString* prefix = @"ckid-"; + NSString* name = recordID.recordName; + + if ([name hasPrefix:prefix]) { + name = [name substringFromIndex:[prefix length]]; + } + return name; +} + +-(NSString*)description { + NSDate* updated = self.storedCKRecord.modificationDate; + + return [NSString stringWithFormat:@"", + self.device, + self.circlePeerID, + self.zoneID.zoneName, + SOSAccountGetSOSCCStatusString(self.circleStatus), + self.keyState, + self.currentTLKUUID, + self.currentClassAUUID, + self.currentClassCUUID, + updated ? updated : @"unknown" + ]; +} + +- (BOOL)isEqual: (id) object { + if(![object isKindOfClass:[CKKSDeviceStateEntry class]]) { + return NO; + } + + CKKSDeviceStateEntry* obj = (CKKSDeviceStateEntry*) object; + + return ([self.zoneID isEqual: obj.zoneID] && + ((self.device == nil && obj.device == nil) || [self.device isEqual: obj.device]) && + ((self.circlePeerID == nil && obj.circlePeerID == nil) || [self.circlePeerID isEqual: obj.circlePeerID]) && + (self.circleStatus == obj.circleStatus) && + ((self.keyState == nil && obj.keyState == nil) || [self.keyState isEqual: obj.keyState]) && + ((self.currentTLKUUID == nil && obj.currentTLKUUID == nil) || [self.currentTLKUUID isEqual: obj.currentTLKUUID]) && + ((self.currentClassAUUID == nil && obj.currentClassAUUID == nil) || [self.currentClassAUUID isEqual: obj.currentClassAUUID]) && + ((self.currentClassCUUID == nil && obj.currentClassCUUID == nil) || [self.currentClassCUUID isEqual: obj.currentClassCUUID]) && + YES) ? YES : NO; +} + +#pragma mark - Database Operations + ++ (instancetype)fromDatabase:(NSString*)device zoneID:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error { + return [self fromDatabaseWhere: @{@"device":CKKSNilToNSNull(device), @"ckzone": CKKSNilToNSNull(zoneID.zoneName)} error:error]; +} + ++ (instancetype)tryFromDatabase:(NSString*)device zoneID:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error { + return [self tryFromDatabaseWhere: @{@"device":CKKSNilToNSNull(device), @"ckzone": CKKSNilToNSNull(zoneID.zoneName)} error:error]; +} + ++ (instancetype)tryFromDatabaseFromCKRecordID:(CKRecordID*)recordID error:(NSError * __autoreleasing *)error { + return [self tryFromDatabaseWhere: @{@"device":CKKSNilToNSNull([self nameFromCKRecordID:recordID]), @"ckzone": CKKSNilToNSNull(recordID.zoneID.zoneName)} error:error]; +} + ++ (NSArray*)allInZone:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error { + return [self allWhere:@{@"ckzone": CKKSNilToNSNull(zoneID.zoneName)} error:error]; +} + +#pragma mark - CKKSCKRecordHolder methods + +- (NSString*)CKRecordName { + return [NSString stringWithFormat:@"ckid-%@", self.device]; +} + +- (CKRecord*)updateCKRecord: (CKRecord*) record zoneID: (CKRecordZoneID*) zoneID { + if(![record.recordID.recordName isEqualToString: [self CKRecordName]]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordNameException" + reason:[NSString stringWithFormat: @"CKRecord name (%@) was not %@", record.recordID.recordName, [self CKRecordName]] + userInfo:nil]; + } + if(![record.recordType isEqualToString: SecCKRecordDeviceStateType]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordTypeException" + reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordDeviceStateType] + userInfo:nil]; + } + + record[SecCKRecordCircleStatus] = [self sosCCStatusToCKType: self.circleStatus]; + record[SecCKRecordKeyState] = CKKSZoneKeyToNumber(self.keyState); + + record[SecCKRecordCirclePeerID] = self.circlePeerID; + +#define CKKeyRef(uuid) (!uuid ? nil : [[CKReference alloc] initWithRecordID:[[CKRecordID alloc] initWithRecordName:uuid \ + zoneID:self.zoneID] \ + action: CKReferenceActionNone]) + + record[SecCKRecordCurrentTLK] = CKKeyRef(self.currentTLKUUID); + record[SecCKRecordCurrentClassA] = CKKeyRef(self.currentClassAUUID); + record[SecCKRecordCurrentClassC] = CKKeyRef(self.currentClassCUUID); + + return record; +} + +- (bool)matchesCKRecord: (CKRecord*) record { + if(![record.recordType isEqualToString: SecCKRecordDeviceStateType]) { + return false; + } + + + if(![record.recordID.recordName isEqualToString: [self CKRecordName]]) { + return false; + } + + if((!(self.circlePeerID == nil && record[SecCKRecordCirclePeerID] == nil)) && + ![record[SecCKRecordCirclePeerID] isEqualToString: self.circlePeerID]) { + return false; + } + + if([self cktypeToSOSCCStatus: record[SecCKRecordCircleStatus]] != self.circleStatus) { + return false; + } + + if(![CKKSZoneKeyRecover(record[SecCKRecordKeyState]) isEqualToString: self.keyState]) { + return false; + } + + if(![[[record[SecCKRecordCurrentTLK] recordID] recordName] isEqualToString: self.currentTLKUUID]) { + return false; + } + if(![[[record[SecCKRecordCurrentClassA] recordID] recordName] isEqualToString: self.currentTLKUUID]) { + return false; + } + if(![[[record[SecCKRecordCurrentClassC] recordID] recordName] isEqualToString: self.currentTLKUUID]) { + return false; + } + + return true; +} + +- (void)setFromCKRecord: (CKRecord*) record { + if(![record.recordType isEqualToString: SecCKRecordDeviceStateType]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordTypeException" + reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordDeviceStateType] + userInfo:nil]; + } + + [self setStoredCKRecord:record]; + + self.device = [CKKSDeviceStateEntry nameFromCKRecordID: record.recordID];; + + self.circlePeerID = record[SecCKRecordCirclePeerID]; + + self.circleStatus = [self cktypeToSOSCCStatus:record[SecCKRecordCircleStatus]]; + self.keyState = CKKSZoneKeyRecover(record[SecCKRecordKeyState]); + + self.currentTLKUUID = [[record[SecCKRecordCurrentTLK] recordID] recordName]; + self.currentClassAUUID = [[record[SecCKRecordCurrentClassA] recordID] recordName]; + self.currentClassCUUID = [[record[SecCKRecordCurrentClassC] recordID] recordName]; +} + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*)sqlTable { + return @"ckdevicestate"; +} + ++ (NSArray*)sqlColumns { + return @[@"device", @"ckzone", @"peerid", @"circlestatus", @"keystate", @"currentTLK", @"currentClassA", @"currentClassC", @"ckrecord"]; +} + +- (NSDictionary*)whereClauseToFindSelf { + return @{@"device":self.device, @"ckzone":self.zoneID.zoneName}; +} + +- (NSDictionary*)sqlValues { + return @{@"device": self.device, + @"ckzone": CKKSNilToNSNull(self.zoneID.zoneName), + @"peerid": CKKSNilToNSNull(self.circlePeerID), + @"circlestatus": (__bridge NSString*)SOSAccountGetSOSCCStatusString(self.circleStatus), + @"keystate": CKKSNilToNSNull(self.keyState), + @"currentTLK": CKKSNilToNSNull(self.currentTLKUUID), + @"currentClassA": CKKSNilToNSNull(self.currentClassAUUID), + @"currentClassC": CKKSNilToNSNull(self.currentClassCUUID), + @"ckrecord": CKKSNilToNSNull([self.encodedCKRecord base64EncodedStringWithOptions:0]), + }; +} + ++ (instancetype)fromDatabaseRow:(NSDictionary*)row { + return [[CKKSDeviceStateEntry alloc] initForDevice:row[@"device"] + circlePeerID:CKKSNSNullToNil(row[@"peerid"]) circleStatus:SOSAccountGetSOSCCStatusFromString((__bridge CFStringRef) CKKSNSNullToNil(row[@"circlestatus"])) + keyState:CKKSNSNullToNil(row[@"keystate"]) + currentTLKUUID:CKKSNSNullToNil(row[@"currentTLK"]) + currentClassAUUID:CKKSNSNullToNil(row[@"currentClassA"]) + currentClassCUUID:CKKSNSNullToNil(row[@"currentClassC"]) + zoneID:[[CKRecordZoneID alloc] initWithZoneName: row[@"ckzone"] ownerName:CKCurrentUserDefaultName] + encodedCKRecord:CKKSUnbase64NullableString(row[@"ckrecord"]) + ]; +} + +@end + +#endif + diff --git a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h new file mode 100644 index 00000000..1e8a356f --- /dev/null +++ b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h @@ -0,0 +1,51 @@ +/* + * 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 + +#if OCTAGON + +@class CKKSKeychainView; +#import "keychain/ckks/CKKSGroupOperation.h" + +@interface CKKSFetchAllRecordZoneChangesOperation : CKKSGroupOperation + +// Set this to true before starting this operation if you'd like resync behavior: +// Fetching everything currently in CloudKit and comparing to local copy +@property bool resync; + +@property (weak) CKKSKeychainView* ckks; +@property CKRecordZoneID* zoneID; + +@property NSMutableDictionary* modifications; +@property NSMutableDictionary* deletions; + +@property CKServerChangeToken* serverChangeToken; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup; + +@end + + +#endif diff --git a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m new file mode 100644 index 00000000..bdf3f14c --- /dev/null +++ b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m @@ -0,0 +1,363 @@ +/* + * 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 + +#if OCTAGON + +#import "keychain/ckks/CloudKitDependencies.h" +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" +#import "keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h" +#import "keychain/ckks/CKKSMirrorEntry.h" +#import "keychain/ckks/CKKSManifest.h" +#import "keychain/ckks/CKKSManifestLeafRecord.h" +#include + + +@interface CKKSFetchAllRecordZoneChangesOperation() +@property CKDatabaseOperation* fetchRecordZoneChangesOperation; +@property CKOperationGroup* ckoperationGroup; +@end + +@implementation CKKSFetchAllRecordZoneChangesOperation + +// Sets up an operation to fetch all changes from the server, and collect them until we know if the fetch completes. +// As a bonus, you can depend on this operation without worry about NSOperation completion block dependency issues. + +- (instancetype)init { + return nil; +} + +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup { + + if(self = [super init]) { + _ckks = ckks; + _ckoperationGroup = ckoperationGroup; + self.zoneID = ckks.zoneID; + + self.resync = false; + + self.modifications = [[NSMutableDictionary alloc] init]; + self.deletions = [[NSMutableDictionary alloc] init]; + + // Can't fetch unless the zone is created. + [self addNullableDependency:ckks.viewSetupOperation]; + } + return self; +} + +- (void)_onqueueRecordsChanged:(NSArray*)records +{ + for (CKRecord* record in records) { + [self.ckks _onqueueCKRecordChanged:record resync:self.resync]; + } +} + +- (void)_updateLatestTrustedManifest +{ + CKKSKeychainView* ckks = self.ckks; + NSError* error = nil; + NSArray* pendingManifests = [CKKSPendingManifest all:&error]; + NSUInteger greatestKnownManifestGeneration = [CKKSManifest greatestKnownGenerationCount]; + for (CKKSPendingManifest* manifest in pendingManifests) { + if (manifest.generationCount >= greatestKnownManifestGeneration) { + [manifest commitToDatabaseWithError:&error]; + } + else { + // if this is an older generation, just get rid of it + [manifest deleteFromDatabase:&error]; + } + } + + if (![ckks _onQueueUpdateLatestManifestWithError:&error]) { + self.error = error; + ckkserror("ckksfetch", ckks, "failed to get latest manifest"); + } +} + +- (void)_onqueueProcessRecordDeletions +{ + CKKSKeychainView* ckks = self.ckks; + [self.deletions enumerateKeysAndObjectsUsingBlock:^(CKRecordID * _Nonnull recordID, NSString * _Nonnull recordType, BOOL * _Nonnull stop) { + ckksinfo("ckksfetch", ckks, "Processing record deletion(%@): %@", recordType, recordID); + + // CKKS: Check Current Item pointers in the Manifest + // TODO: check that these deletions match a manifest upload + // Delegate these back up into the CKKS object for processing + [ckks _onqueueCKRecordDeleted:recordID recordType:recordType resync:self.resync]; + }]; +} + +- (void)_onqueueScanForExtraneousLocalItems +{ + // TODO: must scan through all CKMirrorEntries and determine if any exist that CloudKit didn't tell us about + CKKSKeychainView* ckks = self.ckks; + NSError* error = nil; + if(self.resync) { + ckksnotice("ckksresync", ckks, "Comparing local UUIDs against the CloudKit list"); + NSMutableArray* uuids = [[CKKSMirrorEntry allUUIDs: &error] mutableCopy]; + + for(NSString* uuid in uuids) { + if([self.modifications objectForKey: [[CKRecordID alloc] initWithRecordName: uuid zoneID: ckks.zoneID]]) { + ckksdebug("ckksresync", ckks, "UUID %@ is still in CloudKit; carry on.", uuid); + } else { + CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase: uuid zoneID:ckks.zoneID error: &error]; + if(error != nil) { + ckkserror("ckksresync", ckks, "Couldn't read an item from the database, but it used to be there: %@ %@", uuid, error); + self.error = error; + continue; + } + + ckkserror("ckksresync", ckks, "BUG: Local item %@ not found in CloudKit, deleting", uuid); + [ckks _onqueueCKRecordDeleted:ckme.item.storedCKRecord.recordID recordType:ckme.item.storedCKRecord.recordType resync:self.resync]; + } + } + } +} + +- (void)groupStart { + __weak __typeof(self) weakSelf = self; + + + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksresync", ckks, "no CKKS object"); + return; + } + + [ckks dispatchSync: ^bool{ + ckks.lastRecordZoneChangesOperation = self; + + NSError* error = nil; + NSQualityOfService qos = NSQualityOfServiceUtility; + + CKFetchRecordZoneChangesOptions* options = [[CKFetchRecordZoneChangesOptions alloc] init]; + if(self.resync) { + ckksnotice("ckksresync", ckks, "Beginning resync fetch!"); + + options.previousServerChangeToken = nil; + + // currently, resyncs are user initiated (or the key hierarchy is upset, which is implicitly user initiated) + qos = NSQualityOfServiceUserInitiated; + } else { + // This is the normal case: fetch only the delta since the last fetch + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: ckks.zoneName]; + if(error || !ckse) { + ckkserror("ckksfetch", ckks, "couldn't fetch zone status for %@: %@", ckks.zoneName, error); + self.error = error; + return false; + } + + ckksnotice("ckksfetch", ckks, "Beginning fetch(%@) starting at change token %@", ckks.zoneName, ckse.changeToken); + + options.previousServerChangeToken = ckse.changeToken; + + if(ckse.changeToken == nil) { + // First sync is special. + qos = NSQualityOfServiceUserInitiated; + } + } + + self.fetchRecordZoneChangesOperation = [[ckks.fetchRecordZoneChangesOperationClass alloc] initWithRecordZoneIDs: @[ckks.zoneID] optionsByRecordZoneID:@{ckks.zoneID: options}]; + + self.fetchRecordZoneChangesOperation.fetchAllChanges = YES; + self.fetchRecordZoneChangesOperation.qualityOfService = qos; + self.fetchRecordZoneChangesOperation.group = self.ckoperationGroup; + ckksnotice("ckksfetch", ckks, "Operation group is %@", self.ckoperationGroup); + + self.fetchRecordZoneChangesOperation.recordChangedBlock = ^(CKRecord *record) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf) { + ckkserror("ckksfetch", strongCKKS, "received callback for released object"); + return; + } + + ckksinfo("ckksfetch", strongCKKS, "CloudKit notification: record changed(%@): %@", [record recordType], record); + + // Add this to the modifications, and remove it from the deletions + [strongSelf.modifications setObject: record forKey: record.recordID]; + [strongSelf.deletions removeObjectForKey: record.recordID]; + }; + + self.fetchRecordZoneChangesOperation.recordWithIDWasDeletedBlock = ^(CKRecordID *recordID, NSString *recordType) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf) { + ckkserror("ckksfetch", strongCKKS, "received callback for released object"); + return; + } + + ckksinfo("ckksfetch", strongCKKS, "CloudKit notification: deleted record(%@): %@", recordType, recordID); + + // Add to the deletions, and remove any pending modifications + [strongSelf.modifications removeObjectForKey: recordID]; + [strongSelf.deletions setObject: recordType forKey: recordID]; + }; + + // This class only supports fetching from a single zone, so we can ignore recordZoneID + self.fetchRecordZoneChangesOperation.recordZoneChangeTokensUpdatedBlock = ^(CKRecordZoneID *recordZoneID, CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf) { + ckkserror("ckksfetch", strongCKKS, "received callback for released object"); + return; + } + + ckksinfo("ckksfetch", strongCKKS, "Received a new server change token: %@ %@", serverChangeToken, clientChangeTokenData); + strongSelf.serverChangeToken = serverChangeToken; + }; + + // Completion blocks don't count for dependencies. Use this intermediate operation hack instead. + NSBlockOperation* recordZoneChangesCompletedOperation = [[NSBlockOperation alloc] init]; + recordZoneChangesCompletedOperation.name = @"record-zone-changes-completed"; + + self.fetchRecordZoneChangesOperation.recordZoneFetchCompletionBlock = ^(CKRecordZoneID *recordZoneID, CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData, BOOL moreComing, NSError * recordZoneError) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) blockCKKS = strongSelf.ckks; + + if(!strongSelf) { + ckkserror("ckksfetch", blockCKKS, "received callback for released object"); + return; + } + + if(!blockCKKS) { + ckkserror("ckksfetch", blockCKKS, "no CKKS object"); + return; + } + + ckksnotice("ckksfetch", blockCKKS, "Record zone fetch complete: changeToken=%@ clientChangeTokenData=%@ changed=%lu deleted=%lu error=%@", serverChangeToken, clientChangeTokenData, + (unsigned long)strongSelf.deletions.count, + (unsigned long)strongSelf.deletions.count, + recordZoneError); + + // Completion! Mark these down. + if(recordZoneError) { + strongSelf.error = recordZoneError; + } + strongSelf.serverChangeToken = serverChangeToken; + + if(recordZoneError != nil) { + // An error occurred. All our fetches are useless. Skip to the end. + } else { + // Commit these changes! + __block NSError* error = nil; + + NSMutableDictionary* changedRecordsDict = [[NSMutableDictionary alloc] init]; + + [blockCKKS dispatchSyncWithAccountQueue:^bool{ + // let's process records in a specific order by type + // 1. Manifest leaf records, without which the manifest master records are meaningless + // 2. Manifest master records, which will be used to validate incoming items + // 3. Intermediate key records + // 4. Current key records + // 5. Item records + + [strongSelf.modifications enumerateKeysAndObjectsUsingBlock:^(CKRecordID* _Nonnull recordID, CKRecord* _Nonnull record, BOOL* stop) { + ckksinfo("ckksfetch", blockCKKS, "Sorting record modification %@: %@", recordID, record); + NSMutableArray* changedRecordsByType = changedRecordsDict[record.recordType]; + if(!changedRecordsByType) { + changedRecordsByType = [[NSMutableArray alloc] init]; + changedRecordsDict[record.recordType] = changedRecordsByType; + }; + + [changedRecordsByType addObject:record]; + }]; + + if ([CKKSManifest shouldSyncManifests]) { + if (!strongSelf.resync) { + [strongSelf _onqueueRecordsChanged:changedRecordsDict[SecCKRecordManifestLeafType]]; + [strongSelf _onqueueRecordsChanged:changedRecordsDict[SecCKRecordManifestType]]; + } + + [strongSelf _updateLatestTrustedManifest]; + } + + [strongSelf _onqueueRecordsChanged:changedRecordsDict[SecCKRecordIntermediateKeyType]]; + [strongSelf _onqueueRecordsChanged:changedRecordsDict[SecCKRecordCurrentKeyType]]; + [strongSelf _onqueueRecordsChanged:changedRecordsDict[SecCKRecordItemType]]; + [strongSelf _onqueueRecordsChanged:changedRecordsDict[SecCKRecordCurrentItemType]]; + [strongSelf _onqueueRecordsChanged:changedRecordsDict[SecCKRecordDeviceStateType]]; + + [strongSelf _onqueueProcessRecordDeletions]; + [strongSelf _onqueueScanForExtraneousLocalItems]; + + CKKSZoneStateEntry* state = [CKKSZoneStateEntry state: blockCKKS.zoneName]; + state.lastFetchTime = [NSDate date]; // The last fetch happened right now! + if(strongSelf.serverChangeToken) { + ckksdebug("ckksfetch", blockCKKS, "Zone change fetch complete: saving new server change token: %@", strongSelf.serverChangeToken); + state.changeToken = strongSelf.serverChangeToken; + } + [state saveToDatabase:&error]; + if(error) { + ckkserror("ckksfetch", blockCKKS, "Couldn't save new server change token: %@", error); + strongSelf.error = error; + } + + if(error) { + ckkserror("ckksfetch", blockCKKS, "horrible error occurred: %@", error); + strongSelf.error = error; + return false; + } + + return true; + }]; + } + }; + + // Called with overall operation success. As I understand it, this block will be called for every operation. + // In the case of, e.g., network failure, the recordZoneFetchCompletionBlock will not be called, but this one will. + self.fetchRecordZoneChangesOperation.fetchRecordZoneChangesCompletionBlock = ^(NSError * _Nullable operationError) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf) { + ckkserror("ckksfetch", strongCKKS, "received callback for released object"); + return; + } + + ckksnotice("ckksfetch", strongCKKS, "Record zone changes fetch complete: error=%@", operationError); + if(operationError) { + strongSelf.error = operationError; + } + + // Trigger the fake 'we're done' operation. + [strongSelf runBeforeGroupFinished: recordZoneChangesCompletedOperation]; + }; + + [self dependOnBeforeGroupFinished: recordZoneChangesCompletedOperation]; + [self dependOnBeforeGroupFinished: self.fetchRecordZoneChangesOperation]; + [ckks.database addOperation: self.fetchRecordZoneChangesOperation]; + return true; + }]; +} + +- (void)cancel { + [self.fetchRecordZoneChangesOperation cancel]; + [super cancel]; +} + +@end + +#endif diff --git a/keychain/ckks/CKKSGroupOperation.h b/keychain/ckks/CKKSGroupOperation.h new file mode 100644 index 00000000..452cd271 --- /dev/null +++ b/keychain/ckks/CKKSGroupOperation.h @@ -0,0 +1,95 @@ +/* + * 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 CKKSGroupOperation_h +#define CKKSGroupOperation_h + +#import +#include + +@class CKKSCondition; + +@interface NSOperation (CKKSUsefulPrintingOperation) +- (NSString*)description; +- (BOOL)isPending; + +// If op is nonnull, op becomes a dependency of this operation +- (void)addNullableDependency: (NSOperation*) op; + +// Add all operations in this collection as dependencies, then add yourself to the collection +-(void)linearDependencies:(NSHashTable*)collection; +@end + +@interface NSBlockOperation (CKKSUsefulConstructorOperation) ++(instancetype)named: (NSString*)name withBlock: (void(^)(void)) block; +@end + + +#define CKKSResultErrorDomain @"CKKSResultOperationError" +enum { + CKKSResultSubresultError = 1, + CKKSResultSubresultCancelled = 2, + CKKSResultTimedOut = 3, +}; + +@interface CKKSResultOperation : NSBlockOperation +@property NSError* error; +@property NSDate* finishDate; +@property CKKSCondition* completionHandlerDidRunCondition; + +// Very similar to addDependency, but: +// if the dependent operation has an error or is canceled, cancel this operation +- (void)addSuccessDependency: (CKKSResultOperation*) operation; + +// Call to check if you should run. +// Note: all subclasses must call this if they'd like to comply with addSuccessDependency +// Also sets your .error property to encapsulate the upstream error +- (bool)allDependentsSuccessful; + +// Allows you to time out CKKSResultOperations: if they haven't started by now, they'll cancel themselves +// and set their error to indicate the timeout +- (instancetype)timeout:(dispatch_time_t)timeout; + +// Convenience constructor. ++(instancetype)operationWithBlock:(void (^)(void))block; ++(instancetype)named: (NSString*)name withBlock: (void(^)(void)) block; +@end + +@interface CKKSGroupOperation : CKKSResultOperation { + BOOL executing; + BOOL finished; +} + +@property NSOperationQueue* operationQueue; + +- (instancetype)init; + +// For subclasses: override this to execute at Group operation start time +- (void)groupStart; + +- (void)runBeforeGroupFinished: (NSOperation*) suboperation; +- (void)dependOnBeforeGroupFinished: (NSOperation*) suboperation; +@end + +#endif // CKKSGroupOperation_h diff --git a/keychain/ckks/CKKSGroupOperation.m b/keychain/ckks/CKKSGroupOperation.m new file mode 100644 index 00000000..79c58513 --- /dev/null +++ b/keychain/ckks/CKKSGroupOperation.m @@ -0,0 +1,469 @@ +/* + * 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 "CKKSGroupOperation.h" +#import "CKKSCondition.h" +#include + +@implementation NSOperation (CKKSUsefulPrintingOperation) +- (NSString*)selfname { + if(self.name) { + return [NSString stringWithFormat: @"%@(%@)", NSStringFromClass([self class]), self.name]; + } else { + return NSStringFromClass([self class]); + } +} + +-(void)linearDependencies: (NSHashTable*) collection { + @synchronized(collection) { + for(NSOperation* existingop in collection) { + if(existingop == self) { + // don't depend on yourself + continue; + } + [self addDependency: existingop]; + } + [collection addObject:self]; + } +} + +-(NSString*)pendingDependenciesString:(NSString*)prefix { + NSArray* dependencies = [self.dependencies copy]; + dependencies = [dependencies objectsAtIndexes: [dependencies indexesOfObjectsPassingTest: ^BOOL (id obj, + NSUInteger idx, + BOOL* stop) { + return [obj isPending] ? YES : NO; + }]]; + + if(dependencies.count == 0u) { + return @""; + } + + return [NSString stringWithFormat: @"%@%@", prefix, [dependencies componentsJoinedByString: @", "]]; +} + +- (NSString*)description { + NSString* state = ([self isFinished] ? @"finished" : + [self isCancelled] ? @"cancelled" : + [self isExecuting] ? @"executing" : + [self isReady] ? @"ready" : + @"pending"); + + return [NSString stringWithFormat: @"<%@: %@%@>", [self selfname], state, [self pendingDependenciesString: @" dep:"]]; +} +- (NSString*)debugDescription { + NSString* state = ([self isFinished] ? @"finished" : + [self isCancelled] ? @"cancelled" : + [self isExecuting] ? @"executing" : + [self isReady] ? @"ready" : + @"pending"); + + return [NSString stringWithFormat: @"<%@ (%p): %@%@>", [self selfname], self, state, [self pendingDependenciesString: @" dep:"]]; +} + +- (BOOL)isPending { + return (!([self isExecuting] || [self isFinished])) ? YES : NO; +} + +- (void)addNullableDependency: (NSOperation*) op { + if(op) { + [self addDependency:op]; + } +} +@end + +@implementation NSBlockOperation (CKKSUsefulConstructorOperation) ++(instancetype)named: (NSString*)name withBlock: (void(^)(void)) block { + // How many blocks could a block block if a block could block blocks? + NSBlockOperation* blockOp = [NSBlockOperation blockOperationWithBlock: block]; + blockOp.name = name; + return blockOp; +} +@end + + +@interface CKKSResultOperation() +@property NSMutableArray* successDependencies; +@property bool timeoutCanOccur; +@property dispatch_queue_t timeoutQueue; +@property void (^finishingBlock)(void); +@end + +@implementation CKKSResultOperation +- (instancetype)init { + if(self = [super init]) { + _error = nil; + _successDependencies = [[NSMutableArray alloc] init]; + _timeoutCanOccur = true; + _timeoutQueue = dispatch_queue_create("result-operation-timeout", DISPATCH_QUEUE_SERIAL); + _completionHandlerDidRunCondition = [[CKKSCondition alloc] init]; + + __weak __typeof(self) weakSelf = self; + _finishingBlock = ^(void) { + weakSelf.finishDate = [NSDate dateWithTimeIntervalSinceNow:0]; + }; + self.completionBlock = ^{}; // our _finishing block gets added in the method override + } + return self; +} + +- (NSString*)description { + NSString* state = ([self isFinished] ? [NSString stringWithFormat:@"finished %@", self.finishDate] : + [self isCancelled] ? @"cancelled" : + [self isExecuting] ? @"executing" : + [self isReady] ? @"ready" : + @"pending"); + + if(self.error) { + return [NSString stringWithFormat: @"<%@: %@ error:%@>", [self selfname], state, self.error]; + } else { + return [NSString stringWithFormat: @"<%@: %@%@>", [self selfname], state, [self pendingDependenciesString:@" dep:"]]; + } +} + +- (NSString*)debugDescription { + return [self description]; +} + +- (void)setCompletionBlock:(void (^)(void))completionBlock +{ + __weak __typeof(self) weakSelf = self; + [super setCompletionBlock:^(void) { + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + secerror("ckksresultoperation: completion handler called on deallocated operation instance"); + completionBlock(); // go ahead and still behave as things would if this method override were not here + return; + } + + strongSelf.finishingBlock(); + completionBlock(); + [strongSelf.completionHandlerDidRunCondition fulfill]; + }]; +} + +- (void)start { + if(![self allDependentsSuccessful]) { + secdebug("ckksresultoperation", "Not running due to some failed dependent: %@", self.error); + [self cancel]; + } else { + dispatch_sync(self.timeoutQueue, ^{ + if(![self isCancelled]) { + self.timeoutCanOccur = false; + }; + }); + } + + [super start]; +} + +- (instancetype)timeout:(dispatch_time_t)timeout { + __weak __typeof(self) weakSelf = self; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout), self.timeoutQueue, ^{ + __strong __typeof(self) strongSelf = weakSelf; + if(strongSelf.timeoutCanOccur) { + strongSelf.error = [NSError errorWithDomain:CKKSResultErrorDomain code: CKKSResultTimedOut userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Operation timed out waiting to start for [%@]", [self pendingDependenciesString:@""]]}]; + strongSelf.timeoutCanOccur = false; + [strongSelf cancel]; + } + }); + + return self; +} + +- (void)addSuccessDependency: (CKKSResultOperation*) operation { + if(!operation) { + return; + } + @synchronized(self) { + [self.successDependencies addObject: operation]; + [self addDependency: operation]; + } +} + +- (bool)allDependentsSuccessful { + return [self allSuccessful: self.successDependencies]; +} + +- (bool)allSuccessful: (NSArray*) operations { + @synchronized(self) { + bool result = false; + + bool finished = true; // all dependents must be finished + bool cancelled = false; // no dependents can be cancelled + bool failed = false; // no dependents can have failed + + for(CKKSResultOperation* op in operations) { + finished &= !!([op isFinished]); + cancelled |= !!([op isCancelled]); + failed |= (op.error != nil); + + // TODO: combine suberrors + if(op.error != nil) { + if([op.error.domain isEqual: CKKSResultErrorDomain] && op.error.code == CKKSResultSubresultError) { + // Already a subresult, just copy it on in + self.error = op.error; + } else { + self.error = [NSError errorWithDomain:CKKSResultErrorDomain code: CKKSResultSubresultError userInfo:@{ NSUnderlyingErrorKey: op.error}]; + } + } + } + + result = finished && !( cancelled || failed ); + + if(!result && self.error == nil) { + self.error = [NSError errorWithDomain:CKKSResultErrorDomain code: CKKSResultSubresultCancelled userInfo:nil]; + } + return result; + } +} + ++ (CKKSResultOperation*)operationWithBlock:(void (^)(void))block { + CKKSResultOperation* op = [[CKKSResultOperation alloc] init]; + [op addExecutionBlock: block]; + return op; +} + ++(instancetype)named:(NSString*)name withBlock:(void(^)(void)) block { + CKKSResultOperation* blockOp = [CKKSResultOperation operationWithBlock: block]; + blockOp.name = name; + return blockOp; +} +@end + + +@interface CKKSGroupOperation() +@property NSBlockOperation* startOperation; +@property NSBlockOperation* finishOperation; + +@property NSMutableArray* internalSuccesses; +@end + + +@implementation CKKSGroupOperation + +- (instancetype)init { + if(self = [super init]) { + __weak __typeof(self) weakSelf = self; + + _operationQueue = [[NSOperationQueue alloc] init]; + _internalSuccesses = [[NSMutableArray alloc] init]; + + // At start, we'll call this method (for subclasses) + _startOperation = [NSBlockOperation blockOperationWithBlock:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckks: received callback for released object"); + return; + } + + if(![strongSelf allDependentsSuccessful]) { + secdebug("ckksgroup", "Not running due to some failed dependent: %@", strongSelf.error); + [strongSelf cancel]; + return; + } + + [strongSelf groupStart]; + }]; + + // The finish operation will 'finish' us + _finishOperation = [NSBlockOperation blockOperationWithBlock:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckks: received callback for released object"); + return; + } + + [strongSelf completeOperation]; + }]; + + [self.finishOperation addDependency: self.startOperation]; + [self.operationQueue addOperation: self.finishOperation]; + + self.startOperation.name = @"group-start"; + self.finishOperation.name = @"group-finish"; + + executing = NO; + finished = NO; + } + return self; +} + +- (void)dealloc { + // If the GroupOperation is dealloced before starting, all of its downstream operations form a retain loop. + + if([self isPending]) { + [self.operationQueue cancelAllOperations]; + [self.startOperation cancel]; + [super cancel]; + } +} + +- (BOOL)isPending { + return [self.startOperation isPending]; +} + +- (void)setName:(NSString*) name { + self.operationQueue.name = [NSString stringWithFormat: @"group-queue:%@", name]; + self.startOperation.name = [NSString stringWithFormat: @"group-start:%@", name]; + self.finishOperation.name = [NSString stringWithFormat: @"group-finish:%@", name]; + [super setName: name]; +} + +- (NSString*)description { + if(self.isFinished) { + if(self.error) { + return [NSString stringWithFormat: @"<%@: finished %@ - %@>", [self selfname], self.finishDate, self.error]; + } else { + return [NSString stringWithFormat: @"<%@: finished %@>", [self selfname], self.finishDate]; + } + } + + 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(finishDep != self.startOperation && (NSNotFound == [ops indexOfObject: finishDep])) { + [ops addObject: finishDep]; + } + } + + NSString* opsString = [ops componentsJoinedByString:@", "]; + + if(self.error) { + return [NSString stringWithFormat: @"<%@: [%@] error:%@>", [self selfname], opsString, self.error]; + } else { + return [NSString stringWithFormat: @"<%@: [%@]%@>", [self selfname], opsString, [self pendingDependenciesString:@" dep:"]]; + } +} + +- (NSString*)debugDescription { + return [self description]; +} + +- (BOOL)isConcurrent { + return YES; +} + +- (BOOL)isExecuting { + return self->executing; +} + +- (BOOL)isFinished { + return self->finished; +} + +- (void)start { + if([self isCancelled]) { + [self willChangeValueForKey:@"isFinished"]; + finished = YES; + [self didChangeValueForKey:@"isFinished"]; + return; + } + + [self.operationQueue addOperation: self.startOperation]; + + [self willChangeValueForKey:@"isExecuting"]; + executing = YES; + [self didChangeValueForKey:@"isExecuting"]; +} + +- (void)cancel { + [self.operationQueue cancelAllOperations]; + [self.startOperation cancel]; + + [super cancel]; + + // Our finishoperation might not fire (as we cancelled it above), so let's help it out + [self completeOperation]; +} + +- (void)completeOperation { + [self willChangeValueForKey:@"isFinished"]; + [self willChangeValueForKey:@"isExecuting"]; + + // Run through all the failable operations in this group, and determine if we should be considered successful ourselves + [self allSuccessful: self.internalSuccesses]; + + executing = NO; + finished = YES; + + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; +} + +- (void)addDependency:(NSOperation *)op { + [super addDependency:op]; + [self.startOperation addDependency: op]; +} + +- (void)groupStart { + // Do nothing. Subclasses can do things here. +} + +- (void)runBeforeGroupFinished: (NSOperation*) suboperation { + if([self isCancelled]) { + // Cancelled operations can't add anything. + secnotice("ckksgroup", "Not adding operation to cancelled group"); + return; + } + + // op must wait for this operation to start + [suboperation addDependency: self.startOperation]; + + [self dependOnBeforeGroupFinished: suboperation]; + [self.operationQueue addOperation: suboperation]; +} + +- (void)dependOnBeforeGroupFinished: (NSOperation*) suboperation { + if(suboperation == nil) { + return; + } + + if([self isCancelled]) { + // Cancelled operations can't add anything. + secnotice("ckksgroup", "Can't add operation dependency to cancelled group"); + return; + } + + if([self.finishOperation isExecuting] || [self.finishOperation isFinished]) { + @throw @"Attempt to add operation to completed group"; + } + + // If this is a CKKSResultOperation, then its result impacts our result. + if([suboperation isKindOfClass: [CKKSResultOperation class]]) { + // don't use addSuccessDependency, because it's not a dependency for The Group Operation, but rather a suboperation + @synchronized(self) { + [self.internalSuccesses addObject: (CKKSResultOperation*) suboperation]; + } + } + + // Make sure it waits for us... + [suboperation addDependency: self.startOperation]; + // and we wait for it. + [self.finishOperation addDependency: suboperation]; +} + +@end diff --git a/keychain/ckks/CKKSHealKeyHierarchyOperation.h b/keychain/ckks/CKKSHealKeyHierarchyOperation.h new file mode 100644 index 00000000..4f74072d --- /dev/null +++ b/keychain/ckks/CKKSHealKeyHierarchyOperation.h @@ -0,0 +1,40 @@ +/* + * 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 +#import "keychain/ckks/CKKSGroupOperation.h" + +#if OCTAGON + +@class CKKSKeychainView; + +@interface CKKSHealKeyHierarchyOperation : CKKSGroupOperation +@property (weak) CKKSKeychainView* ckks; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup; + +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/CKKSHealKeyHierarchyOperation.m b/keychain/ckks/CKKSHealKeyHierarchyOperation.m new file mode 100644 index 00000000..8bdd550e --- /dev/null +++ b/keychain/ckks/CKKSHealKeyHierarchyOperation.m @@ -0,0 +1,406 @@ +/* + * 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 "CKKSKeychainView.h" +#import "CKKSCurrentKeyPointer.h" +#import "CKKSKey.h" +#import "CKKSHealKeyHierarchyOperation.h" +#import "CKKSGroupOperation.h" + +#if OCTAGON + +@interface CKKSHealKeyHierarchyOperation () +@property NSBlockOperation* cloudkitModifyOperationFinished; +@property CKOperationGroup* ckoperationGroup; +@end + +@implementation CKKSHealKeyHierarchyOperation + +- (instancetype)init { + return nil; +} +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup { + if(self = [super init]) { + _ckks = ckks; + _ckoperationGroup = ckoperationGroup; + } + return self; +} + +- (void)groupStart { + /* + * We've been invoked because something is wonky with the key hierarchy. + * + * Attempt to figure out what it is, and what we can do about it. + * + * The answer "nothing, everything is terrible" is acceptable. + */ + + __weak __typeof(self) weakSelf = self; + + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksheal", ckks, "no CKKS object"); + return; + } + + if(self.cancelled) { + ckksnotice("ckksheal", ckks, "CKKSHealKeyHierarchyOperation cancelled, quitting"); + return; + } + + // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety. + [ckks dispatchSync: ^bool{ + if(self.cancelled) { + ckksnotice("ckksheal", ckks, "CKKSHealKeyHierarchyOperation cancelled, quitting"); + return false; + } + + NSError* error = nil; + + CKKSCurrentKeySet* keyset = [[CKKSCurrentKeySet alloc] initForZone:ckks.zoneID]; + + bool changedCurrentTLK = false; + bool changedCurrentClassA = false; + bool changedCurrentClassC = false; + + if(keyset.error) { + self.error = keyset.error; + ckkserror("ckksheal", ckks, "couldn't load current key set, attempting to proceed: %@", keyset.error); + } else { + ckksnotice("ckksheal", ckks, "Key set is %@", keyset); + } + + // There's all sorts of brokenness that could exist. For now, we check for: + // + // 1. Current key pointers are nil. + // 2. Keys do not exist in local keychain (but TLK does) + // 3. Keys do not exist in local keychain (including TLK) + // + + if(keyset.currentTLKPointer && keyset.currentClassAPointer && keyset.currentClassCPointer && + (!keyset.tlk || !keyset.classA || !keyset.classC)) { + // Huh. No keys, but some current key pointers? Weird. + // 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; + } + } + + // No current key records. That's... odd. + if(!keyset.currentTLKPointer) { + ckksnotice("ckksheal", ckks, "No current TLK pointer?"); + keyset.currentTLKPointer = [[CKKSCurrentKeyPointer alloc] initForClass: SecCKKSKeyClassTLK currentKeyUUID:nil zoneID:ckks.zoneID encodedCKRecord:nil]; + } + if(!keyset.currentClassAPointer) { + ckksnotice("ckksheal", ckks, "No current ClassA pointer?"); + keyset.currentClassAPointer = [[CKKSCurrentKeyPointer alloc] initForClass: SecCKKSKeyClassA currentKeyUUID:nil zoneID:ckks.zoneID encodedCKRecord:nil]; + } + if(!keyset.currentClassCPointer) { + ckksnotice("ckksheal", ckks, "No current ClassC pointer?"); + keyset.currentClassCPointer = [[CKKSCurrentKeyPointer alloc] initForClass: SecCKKSKeyClassC currentKeyUUID:nil zoneID:ckks.zoneID encodedCKRecord:nil]; + } + + + if(keyset.currentTLKPointer.currentKeyUUID == nil || keyset.currentClassAPointer.currentKeyUUID == nil || keyset.currentClassCPointer.currentKeyUUID == nil || + keyset.tlk == nil || keyset.classA == nil || keyset.classC == nil) { + + // The records exist, but are broken. Point them at something reasonable. + NSArray* keys = [CKKSKey allKeys:ckks.zoneID error:&error]; + + CKKSKey* newTLK = nil; + CKKSKey* newClassAKey = nil; + CKKSKey* newClassCKey = nil; + + NSMutableArray* recordsToSave = [[NSMutableArray alloc] init]; + NSMutableArray* recordIDsToDelete = [[NSMutableArray alloc] init]; + + // Find the current top local key. That's our new TLK. + for(CKKSKey* key in keys) { + CKKSKey* topKey = [key topKeyInAnyState: &error]; + if(newTLK == nil) { + 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:@"securityd" + code:0 + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"Key hierarchy has split: %@ and %@ are roots", newTLK, topKey]}]]; + return true; + } + } + + if(![ckks checkTLK: 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; + + } else { + // Otherwise, something has gone horribly wrong. enter error state. + ckkserror("ckksheal", ckks, "CKKS claims %@ is not a valid TLK: %@", newTLK, error); + NSError* newError = nil; + if(error) { + newError = [NSError errorWithDomain:@"securityd" + code:0 + userInfo:@{NSLocalizedDescriptionKey: @"invalid TLK from CloudKit", NSUnderlyingErrorKey: error}]; + } else { + newError = [NSError errorWithDomain:@"securityd" + code:0 + userInfo:@{NSLocalizedDescriptionKey: @"invalid TLK from CloudKit"}]; + } + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:newError]; + return true; + } + } + + // We have our new TLK. + keyset.currentTLKPointer.currentKeyUUID = newTLK.uuid; + changedCurrentTLK = true; + + // Find some class A and class C keys directly under this one. + for(CKKSKey* key in keys) { + if([key.parentKeyUUID isEqualToString: newTLK.uuid]) { + if((keyset.currentClassAPointer.currentKeyUUID == nil || keyset.classA == nil) && + [key.keyclass isEqualToString: SecCKKSKeyClassA]) { + keyset.currentClassAPointer.currentKeyUUID = key.uuid; + changedCurrentClassA = true; + } + + if((keyset.currentClassCPointer.currentKeyUUID == nil || keyset.classC == nil) && + [key.keyclass isEqualToString: SecCKKSKeyClassC]) { + keyset.currentClassCPointer.currentKeyUUID = key.uuid; + changedCurrentClassC = true; + } + } + } + + if(!keyset.currentClassAPointer.currentKeyUUID) { + newClassAKey = [CKKSKey randomKeyWrappedByParent:newTLK error:&error]; + [newClassAKey saveKeyMaterialToKeychain:&error]; + + if(error) { + ckkserror("ckksheal", ckks, "couldn't create new classA key: %@", error); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:[NSError errorWithDomain: @"securityd" code:0 userInfo:@{NSLocalizedDescriptionKey: @"couldn't create new classA key", NSUnderlyingErrorKey: error}]]; + } + + keyset.currentClassAPointer.currentKeyUUID = newClassAKey.uuid; + changedCurrentClassA = true; + } + if(!keyset.currentClassCPointer.currentKeyUUID) { + newClassCKey = [CKKSKey randomKeyWrappedByParent:newTLK error:&error]; + [newClassCKey saveKeyMaterialToKeychain:&error]; + + if(error) { + ckkserror("ckksheal", ckks, "couldn't create new classC key: %@", error); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:[NSError errorWithDomain: @"securityd" code:0 userInfo:@{NSLocalizedDescriptionKey: @"couldn't create new classC key", NSUnderlyingErrorKey: error}]]; + } + + keyset.currentClassCPointer.currentKeyUUID = newClassCKey.uuid; + changedCurrentClassC = true; + } + + // Note: we never make a new TLK here. So, don't save it back to CloudKit. + //if(newTLK) { + // [recordsToSave addObject: [newTLK CKRecordWithZoneID: ckks.zoneID]]; + //} + if(newClassAKey) { + [recordsToSave addObject: [newClassAKey CKRecordWithZoneID: ckks.zoneID]]; + } + if(newClassCKey) { + [recordsToSave addObject: [newClassCKey CKRecordWithZoneID: ckks.zoneID]]; + } + + if(changedCurrentTLK) { + [recordsToSave addObject: [keyset.currentTLKPointer CKRecordWithZoneID: ckks.zoneID]]; + } + if(changedCurrentClassA) { + [recordsToSave addObject: [keyset.currentClassAPointer CKRecordWithZoneID: ckks.zoneID]]; + } + if(changedCurrentClassC) { + [recordsToSave addObject: [keyset.currentClassCPointer CKRecordWithZoneID: ckks.zoneID]]; + } + + ckksinfo("ckksheal", ckks, "Saving new keys %@ to cloudkit %@", recordsToSave, ckks.database); + + // Use the spare operation trick to wait for the CKModifyRecordsOperation to complete + self.cloudkitModifyOperationFinished = [NSBlockOperation named:@"heal-cloudkit-modify-operation-finished" withBlock:^{}]; + [self dependOnBeforeGroupFinished: self.cloudkitModifyOperationFinished]; + + CKModifyRecordsOperation* modifyRecordsOp = nil; + + // Get the CloudKit operation ready... + modifyRecordsOp = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave recordIDsToDelete:recordIDsToDelete]; + modifyRecordsOp.atomic = YES; + modifyRecordsOp.longLived = NO; // The keys are only in memory; mark this explicitly not long-lived + modifyRecordsOp.timeoutIntervalForRequest = 2; + modifyRecordsOp.qualityOfService = NSQualityOfServiceUtility; // relatively important. Use Utility. + modifyRecordsOp.group = self.ckoperationGroup; + ckksnotice("ckksheal", ckks, "Operation group is %@", self.ckoperationGroup); + + modifyRecordsOp.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) blockCKKS = strongSelf.ckks; + + // These should all fail or succeed as one. Do the hard work in the records completion block. + if(!error) { + ckksnotice("ckksheal", blockCKKS, "Successfully completed upload for %@", record.recordID.recordName); + } else { + ckkserror("ckksheal", blockCKKS, "error on row: %@ %@", error, record); + } + }; + + modifyRecordsOp.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *error) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf) { + secerror("ckks: received callback for released object"); + return; + } + + ckksnotice("ckksheal", strongCKKS, "Completed Key Heal CloudKit operation with error: %@", error); + + [strongCKKS dispatchSync: ^bool{ + if(error == nil) { + // Success. Persist the keys to the CKKS database. + + // Save the new CKRecords to the before persisting to database + for(CKRecord* record in savedRecords) { + if([newTLK matchesCKRecord: record]) { + newTLK.storedCKRecord = record; + } else if([newClassAKey matchesCKRecord: record]) { + newClassAKey.storedCKRecord = record; + } else if([newClassCKey matchesCKRecord: record]) { + newClassCKey.storedCKRecord = record; + + } else if([keyset.currentTLKPointer matchesCKRecord: record]) { + keyset.currentTLKPointer.storedCKRecord = record; + } else if([keyset.currentClassAPointer matchesCKRecord: record]) { + keyset.currentClassAPointer.storedCKRecord = record; + } else if([keyset.currentClassCPointer matchesCKRecord: record]) { + keyset.currentClassCPointer.storedCKRecord = record; + } + } + + NSError* localerror = nil; + + [newTLK saveToDatabaseAsOnlyCurrentKeyForClassAndState: &localerror]; + [newClassAKey saveToDatabaseAsOnlyCurrentKeyForClassAndState: &localerror]; + [newClassCKey saveToDatabaseAsOnlyCurrentKeyForClassAndState: &localerror]; + + [keyset.currentTLKPointer saveToDatabase: &localerror]; + [keyset.currentClassAPointer saveToDatabase: &localerror]; + [keyset.currentClassCPointer saveToDatabase: &localerror]; + + 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; + } else { + // Everything is groovy. HOWEVER, we might still not have processed the keys. Ask for that! + [strongCKKS _onqueueKeyStateMachineRequestProcess]; + [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateReady withError: nil]; + } + } else { + // ERROR. This isn't a total-failure error state, but one that should kick off a healing process. + ckkserror("ckksheal", strongCKKS, "couldn't save new key hierarchy to CloudKit: %@", error); + [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateNewTLKsFailed withError: nil]; + } + return true; + }]; + + // Notify that we're done + [strongSelf.operationQueue addOperation: strongSelf.cloudkitModifyOperationFinished]; + }; + + [ckks.database addOperation: modifyRecordsOp]; + return true; + } + + [keyset.tlk loadKeyMaterialFromKeychain:&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) { + ckkserror("ckksheal", ckks, "No TLK in keychain, triggering move to bad state: %@", error); + [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateWaitForTLK withError: nil]; + return false; + } + + if(![self ensureKeyPresent:keyset.classA]) { + return false; + } + + if(![self ensureKeyPresent:keyset.classC]) { + return false; + } + + // Seems good to us. Check if we're ready? + [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateReady withError: nil]; + + return true; + }]; +} + +- (bool)ensureKeyPresent:(CKKSKey*)key { + NSError* error = nil; + CKKSKeychainView* ckks = self.ckks; + + [key loadKeyMaterialFromKeychain:&error]; + if(error) { + ckkserror("ckksheal", ckks, "Couldn't load classC key from keychain. Attempting recovery: %@", error); + error = nil; + [key unwrapViaKeyHierarchy: &error]; + if(error) { + ckkserror("ckksheal", ckks, "Couldn't unwrap class C key using key hierarchy. Keys are broken, quitting: %@", error); + [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error]; + self.error = error; + return false; + } + [key saveKeyMaterialToKeychain:&error]; + if(error) { + ckkserror("ckksheal", ckks, "Couldn't save class C key to keychain: %@", error); + [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error]; + self.error = error; + return false; + } + } + return true; +} + +- (void)cancel { + [self.cloudkitModifyOperationFinished cancel]; + [super cancel]; +} + +@end; + +#endif diff --git a/keychain/ckks/CKKSIncomingQueueEntry.h b/keychain/ckks/CKKSIncomingQueueEntry.h new file mode 100644 index 00000000..80a7235d --- /dev/null +++ b/keychain/ckks/CKKSIncomingQueueEntry.h @@ -0,0 +1,62 @@ +/* + * 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 "CKKSSQLDatabaseObject.h" +#import "CKKSItem.h" +#import "CKKSMirrorEntry.h" +#include +#include + +#ifndef CKKSIncomingQueueEntry_h +#define CKKSIncomingQueueEntry_h +#if OCTAGON + +#import + +@interface CKKSIncomingQueueEntry : CKKSSQLDatabaseObject + +@property CKKSItem* item; +@property NSString* uuid; // through-access to underlying item + +@property NSString* action; +@property NSString* state; + +- (instancetype) initWithCKKSItem:(CKKSItem*) ckme + action:(NSString*) action + state:(NSString*) state; + ++ (instancetype) fromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (NSArray*)fetch:(ssize_t)n + startingAtUUID:(NSString*)uuid + state:(NSString*)state + zoneID:(CKRecordZoneID*)zoneID + error: (NSError * __autoreleasing *) error; + ++ (NSDictionary*)countsByState:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + +@end + +#endif +#endif /* CKKSIncomingQueueEntry_h */ diff --git a/keychain/ckks/CKKSIncomingQueueEntry.m b/keychain/ckks/CKKSIncomingQueueEntry.m new file mode 100644 index 00000000..39a711a5 --- /dev/null +++ b/keychain/ckks/CKKSIncomingQueueEntry.m @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#import + +#import "CKKSKeychainView.h" + +#include +#include +#include + +#if OCTAGON + +#import +#import "CKKSIncomingQueueEntry.h" +#import "CKKSItemEncrypter.h" +#import "CKKSSIV.h" + +@implementation CKKSIncomingQueueEntry + +- (NSString*)description { + return [NSString stringWithFormat: @"<%@(%@): %@ %@ (%@)>", + NSStringFromClass([self class]), + self.item.zoneID.zoneName, + self.action, + self.item.uuid, + self.state]; +} + +- (instancetype) initWithCKKSItem:(CKKSItem*) item + action:(NSString*) action + state:(NSString*) state { + if(self = [super init]) { + _item = item; + _action = action; + _state = state; + } + + return self; +} + +#pragma mark - Property access to underlying CKKSItem + +-(NSString*)uuid { + return self.item.uuid; +} + +-(void)setUuid:(NSString *)uuid { + self.item.uuid = uuid; +} + +#pragma mark - Database Operations + ++ (instancetype) fromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error]; +} + ++ (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error]; +} + ++ (NSArray*)fetch:(ssize_t)n + startingAtUUID:(NSString*)uuid + state:(NSString*)state + zoneID:(CKRecordZoneID*)zoneID + error: (NSError * __autoreleasing *) error { + NSMutableDictionary* whereDict = [@{@"state": CKKSNilToNSNull(state), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} mutableCopy]; + if(uuid) { + whereDict[@"UUID"] = [CKKSSQLWhereObject op:@">" stringValue:uuid]; + } + return [self fetch:n + where:whereDict + orderBy:@[@"UUID"] + error:error]; +} + + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*)sqlTable { + return @"incomingqueue"; +} + ++ (NSArray*)sqlColumns { + return [[CKKSItem sqlColumns] arrayByAddingObjectsFromArray: @[@"action", @"state"]]; +} + +- (NSDictionary*)whereClauseToFindSelf { + return [self.item whereClauseToFindSelf]; +} + +- (NSDictionary*)sqlValues { + NSMutableDictionary* values = [[self.item sqlValues] mutableCopy]; + values[@"action"] = self.action; + values[@"state"] = self.state; + return values; +} + + ++ (instancetype)fromDatabaseRow: (NSDictionary*) row { + return [[CKKSIncomingQueueEntry alloc] initWithCKKSItem: [CKKSItem fromDatabaseRow: row] + action: row[@"action"] + state: row[@"state"]]; +} + ++ (NSDictionary*)countsByState:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + NSMutableDictionary* results = [[NSMutableDictionary alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [[self class] sqlTable] + where: @{@"ckzone": CKKSNilToNSNull(zoneID.zoneName)} + columns: @[@"state", @"count(rowid)"] + groupBy: @[@"state"] + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + results[row[@"state"]] = [NSNumber numberWithInteger: [row[@"count(rowid)"] integerValue]]; + } + error: error]; + return results; +} + +@end + +#endif diff --git a/keychain/ckks/CKKSIncomingQueueOperation.h b/keychain/ckks/CKKSIncomingQueueOperation.h new file mode 100644 index 00000000..dd2a8a12 --- /dev/null +++ b/keychain/ckks/CKKSIncomingQueueOperation.h @@ -0,0 +1,43 @@ +/* + * 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 +#import "keychain/ckks/CKKSGroupOperation.h" +#if OCTAGON + +@class CKKSKeychainView; + +@interface CKKSIncomingQueueOperation : CKKSResultOperation +@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; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks errorOnClassAFailure:(bool)errorOnClassAFailure; + +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/CKKSIncomingQueueOperation.m b/keychain/ckks/CKKSIncomingQueueOperation.m new file mode 100644 index 00000000..e840c536 --- /dev/null +++ b/keychain/ckks/CKKSIncomingQueueOperation.m @@ -0,0 +1,669 @@ +/* + * 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 "CKKSKeychainView.h" +#import "CKKSIncomingQueueOperation.h" +#import "CKKSIncomingQueueEntry.h" +#import "CKKSItemEncrypter.h" +#import "CKKSOutgoingQueueEntry.h" +#import "CKKSKey.h" +#import "CKKSManifest.h" +#import "CKKSAnalyticsLogger.h" +#import "keychain/ckks/CKKSCurrentItemPointer.h" + +#include +#include +#include + +#include + +#if OCTAGON + +@interface CKKSIncomingQueueOperation () +@property bool newOutgoingEntries; +@property bool pendingClassAEntries; +@end + +@implementation CKKSIncomingQueueOperation + +- (instancetype)init { + return nil; +} +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks errorOnClassAFailure:(bool)errorOnClassAFailure { + if(self = [super init]) { + _ckks = ckks; + + // 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]) { + __weak __typeof(self) weakSelf = self; + __weak CKKSKeychainView* weakCKKS = ckks; + CKKSResultOperation* updateManifestOperation = [CKKSResultOperation operationWithBlock:^{ + __strong __typeof(self) strongSelf = weakSelf; + __strong CKKSKeychainView* strongCKKS = weakCKKS; + __block NSError* error = nil; + if (!strongCKKS || !strongSelf) { + ckkserror("ckksincoming", strongCKKS, "update manifest operation fired for released object"); + return; + } + + [strongCKKS dispatchSyncWithAccountQueue:^bool{ + strongCKKS.latestManifest = [CKKSManifest latestTrustedManifestForZone:strongCKKS.zoneName error:&error]; + if (error) { + strongSelf.error = error; + ckkserror("ckksincoming", strongCKKS, "failed to get latest manifest: %@", error); + return false; + } + else { + return true; + } + }]; + }]; + updateManifestOperation.name = @"update-manifest-operation"; + + [ckks scheduleOperation:updateManifestOperation]; + [self addSuccessDependency:updateManifestOperation]; + } + } + return self; +} + +- (bool)processNewCurrentItemPointers:(NSArray*)queueEntries withManifest:(CKKSManifest*)manifest egoManifest:(CKKSEgoManifest*)egoManifest +{ + CKKSKeychainView* ckks = self.ckks; + + NSError* error = nil; + for(CKKSCurrentItemPointer* p in queueEntries) { + if ([CKKSManifest shouldSyncManifests]) { + if (![manifest validateCurrentItem:p withError:&error]) { + ckkserror("ckksincoming", ckks, "Unable to validate current item pointer (%@) against manifest (%@)", p, manifest); + [[CKKSAnalyticsLogger logger] logSoftFailureForEventNamed:@"CKKSManifestCurrentItemPointerValidation" withAttributes:@{CKKSManifestZoneKey : ckks.zoneID.zoneName, CKKSManifestSignerIDKey : manifest.signerID ?: @"no signer", CKKSManifestGenCountKey : @(manifest.generationCount)}]; + if ([CKKSManifest shouldEnforceManifests]) { + return false; + } + } + else { + [[CKKSAnalyticsLogger logger] logSuccessForEventNamed:@"CKKSManifestCurrentItemPointerValidation"]; + } + } + + p.state = SecCKKSProcessedStateLocal; + + [p saveToDatabase:&error]; + ckksnotice("ckkspointer", ckks, "Saving new current item pointer: %@", p); + if(error) { + ckkserror("ckksincoming", ckks, "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]; + } + + return (error == nil); +} + +- (bool)processQueueEntries:(NSArray*)queueEntries withManifest:(CKKSManifest*)manifest egoManifest:(CKKSEgoManifest*)egoManifest +{ + CKKSKeychainView* ckks = self.ckks; + + NSMutableArray* newOrChangedRecords = [[NSMutableArray alloc] init]; + NSMutableArray* deletedRecordIDs = [[NSMutableArray alloc] init]; + NSInteger manifestGenerationCount = manifest.generationCount; + NSString* manifestSignerID = manifest.signerID ?: @"no signer"; + + for(id entry in queueEntries) { + 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); + + // 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 + // across all classes, though... + NSMutableDictionary* attributes = [[CKKSItemEncrypter decryptItemToDictionary: iqe.item error:&error] mutableCopy]; + if(!attributes || error) { + if([ckks.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]; + if(localerror || ([key.keyclass isEqualToString:SecCKKSKeyClassA] && self.errorOnClassAFailure)) { + self.error = error; + } + + // If this isn't an error, make sure it gets processed later. + if([key.keyclass isEqualToString:SecCKKSKeyClassA] && !self.errorOnClassAFailure) { + self.pendingClassAEntries = true; + } + + } else if ([error.domain isEqualToString:@"securityd"] && error.code == errSecItemNotFound) { + ckkserror("ckksincoming", ckks, "Coudn't find key in keychain; attempting to poke key hierarchy: %@", error) + [ckks _onqueueAdvanceKeyStateMachineToState: nil withError: nil]; + + } else { + ckkserror("ckksincoming", ckks, "Couldn't decrypt IQE %@ for some reason: %@", iqe, error); + self.error = error; + } + continue; + } + + // Add the UUID (which isn't stored encrypted) + [attributes setValue: iqe.item.uuid forKey: (__bridge NSString*) kSecAttrUUID]; + + // Add the PCS plaintext fields, if they exist + if(iqe.item.plaintextPCSServiceIdentifier) { + [attributes setValue: iqe.item.plaintextPCSServiceIdentifier forKey: (__bridge NSString*) kSecAttrPCSPlaintextServiceIdentifier]; + } + if(iqe.item.plaintextPCSPublicKey) { + [attributes setValue: iqe.item.plaintextPCSPublicKey forKey: (__bridge NSString*) kSecAttrPCSPlaintextPublicKey]; + } + if(iqe.item.plaintextPCSPublicIdentity) { + [attributes setValue: iqe.item.plaintextPCSPublicIdentity forKey: (__bridge NSString*) kSecAttrPCSPlaintextPublicIdentity]; + } + + // This item is also synchronizable (by definition) + [attributes setValue: @(YES) forKey: (__bridge NSString*) kSecAttrSynchronizable]; + + NSString* classStr = [attributes objectForKey: (__bridge NSString*) kSecClass]; + if(![classStr isKindOfClass: [NSString class]]) { + 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); + continue; + } + + const SecDbClass * classP = !classStr ? NULL : kc_class_with_name((__bridge CFStringRef) classStr); + + if(!classP) { + ckkserror("ckksincoming", ckks, "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); + self.error = error; + } + continue; + } + + if([iqe.action isEqualToString: SecCKKSActionAdd] || [iqe.action isEqualToString: SecCKKSActionModify]) { + BOOL requireManifestValidation = [CKKSManifest shouldEnforceManifests]; + BOOL manifestValidatesItem = [manifest validateItem:iqe.item withError:&error]; + if (manifestValidatesItem) { + [[CKKSAnalyticsLogger logger] logSuccessForEventNamed:@"CKKSManifestValidateItemAdd"]; + } + else { + [[CKKSAnalyticsLogger logger] logSoftFailureForEventNamed:@"CKKSManifestValidateItemAdd" withAttributes:@{CKKSManifestZoneKey : ckks.zoneID.zoneName, CKKSManifestSignerIDKey : manifestSignerID, CKKSManifestGenCountKey : @(manifestGenerationCount)}]; + } + + 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; + } + + continue; + } + } else if ([iqe.action isEqualToString: SecCKKSActionDelete]) { + BOOL requireManifestValidation = [CKKSManifest shouldEnforceManifests]; + BOOL manifestValidatesDelete = ![manifest itemUUIDExistsInManifest:iqe.uuid]; + if (manifestValidatesDelete) { + [[CKKSAnalyticsLogger logger] logSuccessForEventNamed:@"CKKSManifestValidateItemDelete"]; + } + else { + [[CKKSAnalyticsLogger logger] logSoftFailureForEventNamed:@"CKKSManifestValidateItemDelete" withAttributes:@{CKKSManifestZoneKey : ckks.zoneID.zoneName, CKKSManifestSignerIDKey : manifestSignerID, CKKSManifestGenCountKey : @(manifestGenerationCount)}]; + } + + 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); + return false; + } + } + } + } + + if(newOrChangedRecords.count > 0 || deletedRecordIDs > 0) { + // Schedule a view change notification + [ckks.notifyViewChangedScheduler trigger]; + } + + if ([CKKSManifest shouldSyncManifests]) { + [egoManifest updateWithNewOrChangedRecords:newOrChangedRecords deletedRecordIDs:deletedRecordIDs]; + } + return true; +} + +- (bool)_onqueueUpdateIQE:(CKKSIncomingQueueEntry*)iqe withState:(NSString*)newState error:(NSError**)error +{ + if (![iqe.state isEqualToString:newState]) { + NSMutableDictionary* oldWhereClause = iqe.whereClauseToFindSelf.mutableCopy; + oldWhereClause[@"state"] = iqe.state; + iqe.state = newState; + if ([iqe saveToDatabase:error]) { + if (![CKKSSQLDatabaseObject deleteFromTable:[iqe.class sqlTable] where:oldWhereClause connection:NULL error:error]) { + return false; + } + } + else { + return false; + } + } + + return true; +} + +- (void) main { + // Synchronous, on some thread. Get back on the CKKS queue for thread-safety. + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksincoming", ckks, "no CKKS object"); + return; + } + + [ckks dispatchSyncWithAccountQueue: ^bool{ + if(self.cancelled) { + ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting"); + return false; + } + ckks.lastIncomingQueueOperation = self; + + ckksnotice("ckksincoming", ckks, "Processing incoming queue"); + + 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; + + if ([CKKSManifest shouldSyncManifests]) { + NSDictionary* stateCounts = [CKKSIncomingQueueEntry countsByState:ckks.zoneID error:&error]; + if (error) { + ckkserror("ckksincoming", ckks, "Error fetching incoming queue state counts: %@", error); + self.error = error; + return false; + } + NSUInteger unauthenticatedItemCount = stateCounts[SecCKKSStateUnauthenticated].unsignedIntegerValue; + + // take any existing unauthenticated entries and put them back in the new state + NSArray* unauthenticatedEntries = nil; + NSString* lastMaxUUID = nil; + NSUInteger numEntriesProcessed = 0; + while (numEntriesProcessed < unauthenticatedItemCount && (unauthenticatedEntries == nil || unauthenticatedEntries.count == SecCKKSIncomingQueueItemsAtOnce)) { + if(self.cancelled) { + ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting"); + return false; + } + + 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; + } + + 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; + } + + lastMaxUUID = ([lastMaxUUID compare:unauthenticatedEntry.uuid] == NSOrderedDescending) ? lastMaxUUID : unauthenticatedEntry.uuid; + } + } + } + + // Iterate through all incoming queue entries a chunk at a time (for peak memory concerns) + NSArray * queueEntries = nil; + NSString* lastMaxUUID = nil; + NSUInteger processedItems = 0; + while(queueEntries == nil || queueEntries.count == SecCKKSIncomingQueueItemsAtOnce) { + if(self.cancelled) { + ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting"); + return false; + } + + queueEntries = [CKKSIncomingQueueEntry fetch: SecCKKSIncomingQueueItemsAtOnce + startingAtUUID:lastMaxUUID + state:SecCKKSStateNew + zoneID:ckks.zoneID + error: &error]; + + if(error != nil) { + ckkserror("ckksincoming", ckks, "Error fetching incoming queue records: %@", error); + self.error = error; + return false; + } + + if([queueEntries count] == 0) { + // Nothing to do! exit. + ckksnotice("ckksincoming", ckks, "Nothing in incoming queue to process"); + break; + } + + if (![self processQueueEntries:queueEntries withManifest:ckks.latestManifest egoManifest:ckks.egoManifest]) { + ckksnotice("ckksincoming", ckks, "processQueueEntries didn't complete successfully"); + return false; + } + processedItems += [queueEntries count]; + + // Find the highest UUID for the next fetch. + for(CKKSIncomingQueueEntry* iqe in queueEntries) { + lastMaxUUID = ([lastMaxUUID compare:iqe.uuid] == NSOrderedDescending) ? lastMaxUUID : iqe.uuid; + }; + } + + // Process other queues: CKKSCurrentItemPointers + ckksnotice("ckksincoming", ckks, "Processed %lu items in incoming queue", processedItems); + + NSArray* 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; + } + ckksnotice("ckksincoming", ckks, "Processed %lu items in CIP queue", newCIPs.count); + } + + if(self.newOutgoingEntries) { + // No operation group + [ckks processOutgoingQueue:nil]; + } + + if(self.pendingClassAEntries) { + [self.ckks processIncomingQueueAfterNextUnlock]; + } + + __weak __typeof(self) weakSelf = self; + self.completionBlock = ^(void) { + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + ckkserror("ckksincoming", ckks, "received callback for released object"); + return; + } + + if (!strongSelf.error) { + CKKSAnalyticsLogger* logger = [CKKSAnalyticsLogger logger]; + [logger logSuccessForEvent:CKKSEventProcessIncomingQueueClassC inView:ckks]; + if (!strongSelf.pendingClassAEntries) { + [logger logSuccessForEvent:CKKSEventProcessIncomingQueueClassA inView:ckks]; + } + } + }; + + return ok; + }]; +} + +- (void)_onqueueHandleIQEChange: (CKKSIncomingQueueEntry*) iqe attributes:(NSDictionary*)attributes 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; + __block NSError* error = NULL; + + SecDbItemRef item = SecDbItemCreateWithAttributes(NULL, classP, (__bridge CFDictionaryRef) attributes, KEYBAG_DEVICE, &cferror); + + __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 + // delete the item with the 'higher' UUID. + // Otherwise, the cloud wins. + + SecADAddValueForScalarKey((__bridge CFStringRef) SecCKKSAggdPrimaryKeyConflict,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); + if(replace) { + *replace = CFRetainSafe(item); + } + return; + } + + CFStringRef itemUUID = CFDictionaryGetValue(item->attributes, kSecAttrUUID); + CFStringRef olditemUUID = CFDictionaryGetValue(olditem->attributes, kSecAttrUUID); + + CFComparisonResult compare = CFStringCompare(itemUUID, olditemUUID, 0); + CKKSOutgoingQueueEntry* oqe = nil; + switch(compare) { + case kCFCompareLessThan: + // item wins; delete olditem + ckksnotice("ckksincoming", ckks, "Primary key conflict; replacing %@ with CK item %@", olditem, item); + if(replace) { + *replace = CFRetainSafe(item); + moddate = (__bridge NSDate*) CFDictionaryGetValue(item->attributes, kSecAttrModificationDate); + } + + oqe = [CKKSOutgoingQueueEntry withItem:olditem action:SecCKKSActionDelete ckks:ckks error:&error]; + [oqe saveToDatabase: &error]; + self.newOutgoingEntries = true; + break; + case kCFCompareGreaterThan: + // 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]; + [oqe saveToDatabase: &error]; + self.newOutgoingEntries = true; + moddate = nil; + break; + + case kCFCompareEqualTo: + // remote item wins; this is the normal update case + ckksnotice("ckksincoming", ckks, "Primary key conflict; replacing %@ with CK item %@", olditem, item); + if(replace) { + *replace = CFRetainSafe(item); + moddate = (__bridge NSDate*) CFDictionaryGetValue(item->attributes, kSecAttrModificationDate); + } + break; + } + }); + + // SecDbItemInsertOrReplace returns an error even when it succeeds. + if(!replaceok && SecErrorIsSqliteDuplicateItemError(cferror)) { + CFReleaseNull(cferror); + replaceok = true; + } + return replaceok; + }); + + CFReleaseNull(item); + + if(cferror) { + ckkserror("ckksincoming", ckks, "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); + self.error = error; + } + return; + } + + if(error) { + ckkserror("ckksincoming", ckks, "Couldn't handle IQE, but why?: %@", error); + self.error = error; + return; + } + + if(ok) { + ckksinfo("ckksincoming", ckks, "Correctly processed an IQE; deleting"); + [iqe deleteFromDatabase: &error]; + + if(error) { + ckkserror("ckksincoming", ckks, "couldn't delete CKKSIncomingQueueEntry: %@", error); + self.error = error; + } + + if(moddate) { + // Log the number of seconds it took to propagate this change + uint64_t secondsDelay = (uint64_t) ([[NSDate date] timeIntervalSinceDate:moddate]); + SecADClientPushValueForDistributionKey((__bridge CFStringRef) SecCKKSAggdPropagationDelay, secondsDelay); + } + + } else { + ckksnotice("ckksincoming", ckks, "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); + 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*) kSecAttrSyncViewHint: ckks.zoneID.zoneName, + (__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); + + + if(cferror) { + ckkserror("ckksincoming", ckks, "couldn't create query: %@", cferror); + SecTranslateError(&error, cferror); + self.error = error; + return; + } + + ok = kc_with_dbt(true, &cferror, ^(SecDbConnectionRef dbt) { + return s3dl_query_delete(dbt, q, NULL, &cferror); + }); + + if(cferror) { + if(CFErrorGetCode(cferror) == errSecItemNotFound) { + ckkserror("ckksincoming", ckks, "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); + SecTranslateError(&error, cferror); + self.error = error; + query_destroy(q, NULL); + return; + } + } + + + ok = query_notify_and_destroy(q, ok, &cferror); + + if(cferror) { + ckkserror("ckksincoming", ckks, "couldn't delete query: %@", cferror); + SecTranslateError(&error, cferror); + self.error = error; + return; + } + + if(ok) { + ckksnotice("ckksincoming", ckks, "Correctly processed an IQE; deleting"); + [iqe deleteFromDatabase: &error]; + + if(error) { + ckkserror("ckksincoming", ckks, "couldn't delete CKKSIncomingQueueEntry: %@", error); + self.error = error; + } + } else { + ckkserror("ckksincoming", ckks, "IQE not correctly processed, but why? %@ %@", error, cferror); + self.error = error; + } +} + +@end; + +#endif diff --git a/keychain/ckks/CKKSItem.h b/keychain/ckks/CKKSItem.h new file mode 100644 index 00000000..8f6e39a1 --- /dev/null +++ b/keychain/ckks/CKKSItem.h @@ -0,0 +1,119 @@ +/* + * 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 "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSSQLDatabaseObject.h" +#import "keychain/ckks/CKKSRecordHolder.h" +#include +#include + +#ifndef CKKSItem_h +#define CKKSItem_h + +#if OCTAGON + +#import + +@class CKKSWrappedAESSIVKey; + + +// Helper base class that includes UUIDs and key information +@interface CKKSItem : CKKSCKRecordHolder { + +} + +@property (copy) NSString* uuid; +@property (copy) NSString* parentKeyUUID; +@property (copy) NSData* encitem; + +@property (getter=base64Item, setter=setBase64Item:) NSString* base64encitem; + +@property (copy) CKKSWrappedAESSIVKey* wrappedkey; +@property NSUInteger generationCount; +@property enum SecCKKSItemEncryptionVersion encver; + +@property NSNumber* plaintextPCSServiceIdentifier; +@property NSData* plaintextPCSPublicKey; +@property NSData* plaintextPCSPublicIdentity; + +// Used for item encryption and decryption. Attempts to be future-compatible for new CloudKit record fields with an optional olditem field, which may contain a CK record. Any fields in that record that we don't understand will be added to the authenticated data dictionary. +- (NSDictionary*)makeAuthenticatedDataDictionaryUpdatingCKKSItem:(CKKSItem*) olditem encryptionVersion:(SecCKKSItemEncryptionVersion)encversion; + + +- (instancetype) initWithCKRecord: (CKRecord*) record; +- (instancetype) initCopyingCKKSItem: (CKKSItem*) item; + +// Use this one if you really don't have any more information +- (instancetype) initWithUUID: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + zoneID: (CKRecordZoneID*) zoneID; + +// Use this one if you don't have a CKRecord yet +- (instancetype) initWithUUID: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + zoneID: (CKRecordZoneID*) zoneID + encItem: (NSData*) encitem + wrappedkey: (CKKSWrappedAESSIVKey*) wrappedkey + generationCount: (NSUInteger) genCount + encver: (NSUInteger) encver; + +- (instancetype) initWithUUID: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + zoneID: (CKRecordZoneID*)zoneID + encodedCKRecord: (NSData*) encodedrecord + encItem: (NSData*) encitem + wrappedkey: (CKKSWrappedAESSIVKey*) wrappedkey + generationCount: (NSUInteger) genCount + encver: (NSUInteger) encver; + +- (instancetype) initWithUUID: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + zoneID: (CKRecordZoneID*)zoneID + encodedCKRecord: (NSData*) encodedrecord + encItem: (NSData*) encitem + wrappedkey: (CKKSWrappedAESSIVKey*) wrappedkey + generationCount: (NSUInteger) genCount + encver: (NSUInteger) encver +plaintextPCSServiceIdentifier: (NSNumber*) pcsServiceIdentifier + plaintextPCSPublicKey: (NSData*) pcsPublicKey + plaintextPCSPublicIdentity: (NSData*) pcsPublicIdentity; + +// Convenience function: set the upload version for this record to be the current OS version ++ (void)setOSVersionInRecord: (CKRecord*) record; + + +@end + +@interface CKKSSQLDatabaseObject (CKKSZoneExtras) +// Convenience function: get all UUIDs of this type ++ (NSArray*) allUUIDs: (NSError * __autoreleasing *) error; + +// Convenience function: get all objects in this particular zone ++ (NSArray*) all:(CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error; + +// Convenience function: delete all records of this type with this zoneID ++ (bool) deleteAll:(CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error; +@end + +#endif +#endif /* CKKSItem_H */ diff --git a/keychain/ckks/CKKSItem.m b/keychain/ckks/CKKSItem.m new file mode 100644 index 00000000..00f87879 --- /dev/null +++ b/keychain/ckks/CKKSItem.m @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#import +#import "CKKSItem.h" +#import "CKKSSIV.h" + +#include +#include +#include + +#if OCTAGON + +#import +#import + +@implementation CKKSItem + +- (instancetype) initWithCKRecord: (CKRecord*) record { + if(self = [super initWithCKRecord: record]) { + } + return self; +} + +- (instancetype) initCopyingCKKSItem: (CKKSItem*) item { + if(self = [super initWithCKRecordType: item.ckRecordType encodedCKRecord:item.encodedCKRecord zoneID:item.zoneID]) { + _uuid = item.uuid; + _parentKeyUUID = item.parentKeyUUID; + _generationCount = item.generationCount; + _encitem = item.encitem; + _wrappedkey = item.wrappedkey; + _encver = item.encver; + + _plaintextPCSServiceIdentifier = item.plaintextPCSServiceIdentifier; + _plaintextPCSPublicKey = item.plaintextPCSPublicKey; + _plaintextPCSPublicIdentity = item.plaintextPCSPublicIdentity; + } + return self; +} + +- (instancetype) initWithUUID: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + zoneID: (CKRecordZoneID*) zoneID +{ + return [self initWithUUID:uuid + parentKeyUUID:parentKeyUUID + zoneID:zoneID + encodedCKRecord:nil + encItem:nil + wrappedkey:nil + generationCount:0 + encver:CKKSItemEncryptionVersionNone]; +} + +- (instancetype) initWithUUID: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + zoneID: (CKRecordZoneID*) zoneID + encItem: (NSData*) encitem + wrappedkey: (CKKSWrappedAESSIVKey*) wrappedkey + generationCount: (NSUInteger) genCount + encver: (NSUInteger) encver +{ + return [self initWithUUID:uuid + parentKeyUUID:parentKeyUUID + zoneID:zoneID + encodedCKRecord:nil + encItem:encitem + wrappedkey:wrappedkey + generationCount:genCount + encver:encver]; +} + +- (instancetype) initWithUUID: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + zoneID: (CKRecordZoneID*)zoneID + encodedCKRecord: (NSData*) encodedrecord + encItem: (NSData*) encitem + wrappedkey: (CKKSWrappedAESSIVKey*) wrappedkey + generationCount: (NSUInteger) genCount + encver: (NSUInteger) encver +{ + return [self initWithUUID:uuid + parentKeyUUID:parentKeyUUID + zoneID:zoneID + encodedCKRecord:encodedrecord + encItem:encitem + wrappedkey:wrappedkey + generationCount:genCount + encver:encver +plaintextPCSServiceIdentifier:nil + plaintextPCSPublicKey:nil + plaintextPCSPublicIdentity:nil]; +} + +- (instancetype) initWithUUID: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + zoneID: (CKRecordZoneID*)zoneID + encodedCKRecord: (NSData*) encodedrecord + encItem: (NSData*) encitem + wrappedkey: (CKKSWrappedAESSIVKey*) wrappedkey + generationCount: (NSUInteger) genCount + encver: (NSUInteger) encver +plaintextPCSServiceIdentifier: (NSNumber*) pcsServiceIdentifier + plaintextPCSPublicKey: (NSData*) pcsPublicKey + plaintextPCSPublicIdentity: (NSData*) pcsPublicIdentity +{ + if(self = [super initWithCKRecordType: SecCKRecordItemType encodedCKRecord:encodedrecord zoneID:zoneID]) { + _uuid = uuid; + _parentKeyUUID = parentKeyUUID; + _generationCount = genCount; + self.encitem = encitem; + _wrappedkey = wrappedkey; + _encver = encver; + + _plaintextPCSServiceIdentifier = pcsServiceIdentifier; + _plaintextPCSPublicKey = pcsPublicKey; + _plaintextPCSPublicIdentity = pcsPublicIdentity; + } + + return self; +} + +- (BOOL)isEqual: (id) object { + if(![object isKindOfClass:[CKKSItem class]]) { + return NO; + } + + CKKSItem* obj = (CKKSItem*) object; + + return ([self.uuid isEqual: obj.uuid] && + [self.parentKeyUUID isEqual: obj.parentKeyUUID] && + [self.zoneID isEqual: obj.zoneID] && + ((self.encitem == nil && obj.encitem == nil) || ([self.encitem isEqual: obj.encitem])) && + [self.wrappedkey isEqual: obj.wrappedkey] && + self.generationCount == obj.generationCount && + self.encver == obj.encver && + true) ? YES : NO; +} + +#pragma mark - CKRecord handling + +- (NSString*) CKRecordName { + return self.uuid; +} + +- (void) setFromCKRecord: (CKRecord*) record { + if(![record.recordType isEqual: SecCKRecordItemType]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordTypeException" + reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordItemType] + userInfo:nil]; + } + + [self setStoredCKRecord:record]; + + _uuid = [[record recordID] recordName]; + self.parentKeyUUID = [record[SecCKRecordParentKeyRefKey] recordID].recordName; + self.encitem = record[SecCKRecordDataKey]; + self.wrappedkey = [[CKKSWrappedAESSIVKey alloc] initWithBase64: record[SecCKRecordWrappedKeyKey]]; + self.generationCount = [record[SecCKRecordGenerationCountKey] unsignedIntegerValue]; + self.encver = [record[SecCKRecordEncryptionVersionKey] unsignedIntegerValue]; + + self.plaintextPCSServiceIdentifier = record[SecCKRecordPCSServiceIdentifier]; + self.plaintextPCSPublicKey = record[SecCKRecordPCSPublicKey]; + self.plaintextPCSPublicIdentity = record[SecCKRecordPCSPublicIdentity]; +} + ++ (void)setOSVersionInRecord: (CKRecord*) record { +#ifdef PLATFORM + // Use complicated macro magic to get the string value passed in as preprocessor define PLATFORM. +#define PLATFORM_VALUE(f) #f +#define PLATFORM_OBJCSTR(f) @PLATFORM_VALUE(f) + NSString* platform = (PLATFORM_OBJCSTR(PLATFORM)); +#undef PLATFORM_OBJCSTR +#undef PLATFORM_VALUE +#else + NSString* platform = "unknown"; +#warning No PLATFORM defined; why? +#endif + NSString* osversion = [[NSProcessInfo processInfo]operatingSystemVersionString]; + + // subtly improve osversion (but it's okay if that does nothing) + NSString* finalversion = [platform stringByAppendingString: [osversion stringByReplacingOccurrencesOfString:@"Version" withString:@""]]; + record[SecCKRecordVersionKey] = finalversion; +} + +- (CKRecord*) updateCKRecord: (CKRecord*) record zoneID: (CKRecordZoneID*) zoneID { + if(![record.recordType isEqual: SecCKRecordItemType]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordTypeException" + reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordItemType] + userInfo:nil]; + } + + // Items must have a wrapping key. + record[SecCKRecordParentKeyRefKey] = [[CKReference alloc] initWithRecordID: [[CKRecordID alloc] initWithRecordName: self.parentKeyUUID zoneID: zoneID] action: CKReferenceActionValidate]; + + [CKKSItem setOSVersionInRecord: record]; + + record[SecCKRecordDataKey] = self.encitem; + record[SecCKRecordWrappedKeyKey] = [self.wrappedkey base64WrappedKey]; + record[SecCKRecordGenerationCountKey] = [NSNumber numberWithInteger:self.generationCount]; + // TODO: if the record's generation count is already higher than ours, that's a problem. + record[SecCKRecordEncryptionVersionKey] = [NSNumber numberWithInteger:self.encver]; + + // Add unencrypted fields + record[SecCKRecordPCSServiceIdentifier] = self.plaintextPCSServiceIdentifier; + record[SecCKRecordPCSPublicKey] = self.plaintextPCSPublicKey; + record[SecCKRecordPCSPublicIdentity] = self.plaintextPCSPublicIdentity; + + return record; +} + + +- (bool) matchesCKRecord: (CKRecord*) record { + if(![record.recordType isEqual: SecCKRecordItemType]) { + return false; + } + + // We only really care about the data, the wrapped key, the generation count, and the parent key. + // 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"); + return false; + } + + if(![[record[SecCKRecordParentKeyRefKey] recordID].recordName isEqualToString: self.parentKeyUUID]) { + secinfo("ckksitem", "wrapping key reference does not match"); + return false; + } + + if(![record[SecCKRecordGenerationCountKey] isEqual: [NSNumber numberWithInteger:self.generationCount]]) { + secinfo("ckksitem", "SecCKRecordGenerationCountKey does not match"); + return false; + } + + if(![record[SecCKRecordWrappedKeyKey] isEqual: [self.wrappedkey base64WrappedKey]]) { + secinfo("ckksitem", "SecCKRecordWrappedKeyKey does not match"); + return false; + } + + if(![record[SecCKRecordDataKey] isEqual: self.encitem]) { + secinfo("ckksitem", "SecCKRecordDataKey does not match"); + return false; + } + + // Compare plaintext records, too + // 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"); + return false; + } + + if(!((record[SecCKRecordPCSPublicKey] == nil && self.plaintextPCSPublicKey == nil) || + [record[SecCKRecordPCSPublicKey] isEqual: self.plaintextPCSPublicKey])) { + secinfo("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"); + return false; + } + + return true; +} + +// Generates the list of 'authenticated data' to go along with this item, and optionally adds in unknown, future fields received from CloudKit +- (NSDictionary*)makeAuthenticatedDataDictionaryUpdatingCKKSItem:(CKKSItem*) olditem encryptionVersion:(SecCKKSItemEncryptionVersion)encversion { + switch(encversion) { + case CKKSItemEncryptionVersion1: + return [self makeAuthenticatedDataDictionaryUpdatingCKKSItemEncVer1]; + case CKKSItemEncryptionVersion2: + return [self makeAuthenticatedDataDictionaryUpdatingCKKSItemEncVer2:olditem]; + default: + @throw [NSException + exceptionWithName:@"WrongEncryptionVersionException" + reason:[NSString stringWithFormat: @"%d is not a known encryption version", (int)encversion] + userInfo:nil]; + } +} + +- (NSDictionary*)makeAuthenticatedDataDictionaryUpdatingCKKSItemEncVer1 { + NSMutableDictionary* authenticatedData = [[NSMutableDictionary alloc] init]; + + authenticatedData[@"UUID"] = [self.uuid dataUsingEncoding: NSUTF8StringEncoding]; + authenticatedData[SecCKRecordWrappedKeyKey] = [self.parentKeyUUID dataUsingEncoding: NSUTF8StringEncoding]; + + uint64_t genCount64 = OSSwapHostToLittleConstInt64(self.generationCount); + authenticatedData[SecCKRecordGenerationCountKey] = [NSData dataWithBytes:&genCount64 length:sizeof(genCount64)]; + + uint64_t encver = OSSwapHostToLittleConstInt64((uint64_t)self.encver); + authenticatedData[SecCKRecordEncryptionVersionKey] = [NSData dataWithBytes:&encver length:sizeof(encver)]; + + // In v1, don't authenticate the plaintext PCS fields + authenticatedData[SecCKRecordPCSServiceIdentifier] = nil; + authenticatedData[SecCKRecordPCSPublicKey] = nil; + authenticatedData[SecCKRecordPCSPublicIdentity] = nil; + + return authenticatedData; +} + +- (NSDictionary*)makeAuthenticatedDataDictionaryUpdatingCKKSItemEncVer2:(CKKSItem*) olditem { + NSMutableDictionary* authenticatedData = [[NSMutableDictionary alloc] init]; + + authenticatedData[@"UUID"] = [self.uuid dataUsingEncoding: NSUTF8StringEncoding]; + authenticatedData[SecCKRecordWrappedKeyKey] = [self.parentKeyUUID dataUsingEncoding: NSUTF8StringEncoding]; + + uint64_t genCount64 = OSSwapHostToLittleConstInt64(self.generationCount); + authenticatedData[SecCKRecordGenerationCountKey] = [NSData dataWithBytes:&genCount64 length:sizeof(genCount64)]; + + uint64_t encver = OSSwapHostToLittleConstInt64((uint64_t)self.encver); + authenticatedData[SecCKRecordEncryptionVersionKey] = [NSData dataWithBytes:&encver length:sizeof(encver)]; + + // v2 authenticates the PCS fields too + if(self.plaintextPCSServiceIdentifier) { + uint64_t pcsServiceIdentifier = OSSwapHostToLittleConstInt64([self.plaintextPCSServiceIdentifier unsignedLongValue]); + authenticatedData[SecCKRecordPCSServiceIdentifier] = [NSData dataWithBytes:&pcsServiceIdentifier length:sizeof(pcsServiceIdentifier)]; + } + authenticatedData[SecCKRecordPCSPublicKey] = self.plaintextPCSPublicKey; + authenticatedData[SecCKRecordPCSPublicIdentity] = self.plaintextPCSPublicIdentity; + + // Iterate through the fields in the old CKKSItem. If we don't recognize any of them, add them to the authenticated data. + if(olditem) { + CKRecord* record = olditem.storedCKRecord; + if(record) { + for(NSString* key in record.allKeys) { + if([key isEqualToString:@"UUID"] || + [key isEqualToString:SecCKRecordVersionKey] || + [key isEqualToString:SecCKRecordDataKey] || + [key isEqualToString:SecCKRecordWrappedKeyKey] || + [key isEqualToString:SecCKRecordGenerationCountKey] || + [key isEqualToString:SecCKRecordEncryptionVersionKey] || + [key isEqualToString:SecCKRecordPCSServiceIdentifier] || + [key isEqualToString:SecCKRecordPCSPublicKey] || + [key isEqualToString:SecCKRecordPCSPublicIdentity]) { + // This version of CKKS knows about this data field. Ignore them with prejudice. + continue; + } + + if([key hasPrefix:@"server_"]) { + // Ignore all fields prefixed by "server_" + continue; + } + + id obj = record[key]; + + // Skip CKReferences, NSArray, CLLocation, and CKAsset. + if([obj isKindOfClass: [NSString class]]) { + // Add an NSString. + authenticatedData[key] = [obj dataUsingEncoding: NSUTF8StringEncoding]; + } else if([obj isKindOfClass: [NSData class]]) { + // Add an NSData + authenticatedData[key] = [obj copy]; + } else if([obj isKindOfClass:[NSDate class]]) { + // Add an NSDate + NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init]; + NSString* str = [formatter stringForObjectValue: obj]; + + authenticatedData[key] = [str dataUsingEncoding: NSUTF8StringEncoding]; + } else if([obj isKindOfClass: [NSNumber class]]) { + // Add an NSNumber + uint64_t n64 = OSSwapHostToLittleConstInt64([obj unsignedLongLongValue]); + authenticatedData[key] = [NSData dataWithBytes:&n64 length:sizeof(n64)]; + } + } + + } + } + + // TODO: add unauth'ed field name here + + return authenticatedData; +} + +#pragma mark - Utility + +- (NSString*)description { + return [NSString stringWithFormat: @"<%@: %@>", NSStringFromClass([self class]), self.uuid]; +} + +- (NSString*)debugDescription { + return [NSString stringWithFormat: @"<%@: %@ %p>", NSStringFromClass([self class]), self.uuid, self]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + CKKSItem *itemCopy = [super copyWithZone:zone]; + itemCopy->_uuid = _uuid; + itemCopy->_parentKeyUUID = _parentKeyUUID; + itemCopy->_encitem = _encitem; + itemCopy->_wrappedkey = _wrappedkey; + itemCopy->_generationCount = _generationCount; + itemCopy->_encver = _encver; + return itemCopy; +} + +#pragma mark - Getters/Setters + +- (NSString*) base64Item { + return [self.encitem base64EncodedStringWithOptions:0]; +} + +- (void) setBase64Item: (NSString*) base64Item { + _encitem = [[NSData alloc] initWithBase64EncodedString: base64Item options:0]; +} + +#pragma mark - CKKSSQLDatabaseObject helpers + +// Note that CKKSItems are not intended to be saved directly, and so CKKSItem does not implement sqlTable. +// You must subclass CKKSItem to have this work correctly, although you can call back up into this class to use these if you like. + ++ (NSArray*)sqlColumns { + return @[@"UUID", @"parentKeyUUID", @"ckzone", @"encitem", @"wrappedkey", @"gencount", @"encver", @"ckrecord", + @"pcss", @"pcsk", @"pcsi"]; +} + +- (NSDictionary*)whereClauseToFindSelf { + return @{@"UUID": self.uuid, @"ckzone":self.zoneID.zoneName}; +} + +- (NSDictionary*)sqlValues { + return @{@"UUID": self.uuid, + @"parentKeyUUID": self.parentKeyUUID, + @"ckzone": CKKSNilToNSNull(self.zoneID.zoneName), + @"encitem": self.base64encitem, + @"wrappedkey": [self.wrappedkey base64WrappedKey], + @"gencount": [NSNumber numberWithInteger:self.generationCount], + @"encver": [NSNumber numberWithInteger:self.encver], + @"ckrecord": CKKSNilToNSNull([self.encodedCKRecord base64EncodedStringWithOptions:0]), + @"pcss": CKKSNilToNSNull(self.plaintextPCSServiceIdentifier), + @"pcsk": CKKSNilToNSNull([self.plaintextPCSPublicKey base64EncodedStringWithOptions:0]), + @"pcsi": CKKSNilToNSNull([self.plaintextPCSPublicIdentity base64EncodedStringWithOptions:0])}; +} + ++ (instancetype)fromDatabaseRow: (NSDictionary*) row { + return [[CKKSItem alloc] initWithUUID:row[@"UUID"] + parentKeyUUID:row[@"parentKeyUUID"] + zoneID:[[CKRecordZoneID alloc] initWithZoneName: row[@"ckzone"] ownerName:CKCurrentUserDefaultName] + encodedCKRecord:CKKSUnbase64NullableString(row[@"ckrecord"]) + encItem:CKKSUnbase64NullableString(row[@"encitem"]) + wrappedkey:CKKSIsNull(row[@"wrappedkey"]) ? nil : [[CKKSWrappedAESSIVKey alloc] initWithBase64: row[@"wrappedkey"]] + generationCount:[row[@"gencount"] integerValue] + encver:[row[@"encver"] integerValue] + plaintextPCSServiceIdentifier:CKKSIsNull(row[@"pcss"]) ? nil : [NSNumber numberWithInteger: [row[@"pcss"] integerValue]] + plaintextPCSPublicKey:CKKSUnbase64NullableString(row[@"pcsk"]) + plaintextPCSPublicIdentity:CKKSUnbase64NullableString(row[@"pcsi"]) + ]; +} + +@end + +#pragma mark - CK-Aware Database Helpers + +@implementation CKKSSQLDatabaseObject (CKKSZoneExtras) + ++ (NSArray*) allUUIDs: (NSError * __autoreleasing *) error { + __block NSMutableArray* uuids = [[NSMutableArray alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [self sqlTable] + where: nil + columns: @[@"UUID"] + groupBy: nil + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + [uuids addObject: row[@"UUID"]]; + } + error: error]; + return uuids; +} + ++ (NSArray*) all:(CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere: @{@"ckzone": CKKSNilToNSNull(zoneID.zoneName)} error:error]; +} + ++ (bool) deleteAll:(CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error { + bool ok = [CKKSSQLDatabaseObject deleteFromTable:[self sqlTable] where: @{@"ckzone":CKKSNilToNSNull(zoneID.zoneName)} connection:nil error: error]; + + if(ok) { + secdebug("ckksitem", "Deleted all %@", self); + } else { + secdebug("ckksitem", "Couldn't delete all %@: %@", self, error ? *error : @"unknown"); + } + return ok; +} + +@end + +#endif diff --git a/keychain/ckks/CKKSItemEncrypter.h b/keychain/ckks/CKKSItemEncrypter.h new file mode 100644 index 00000000..dc103ef5 --- /dev/null +++ b/keychain/ckks/CKKSItemEncrypter.h @@ -0,0 +1,62 @@ +/* + * 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 CKKSItemEncrypter_h +#define CKKSItemEncrypter_h + +#include + +#if OCTAGON + +@class CKKSItem; +@class CKKSMirrorEntry; +@class CKKSKey; +@class CKKSOutgoingQueueEntry; +@class CKKSAESSIVKey; +@class CKRecordZoneID; + +#define CKKS_PADDING_MARK_BYTE 0x80 + +@interface CKKSItemEncrypter : NSObject { + +} + ++(CKKSItem*)encryptCKKSItem:(CKKSItem*)baseitem + dataDictionary:(NSDictionary *)dict + updatingCKKSItem:(CKKSItem*)olditem + parentkey:(CKKSKey *)parentkey + error:(NSError * __autoreleasing *) error; + ++ (NSDictionary*) decryptItemToDictionary: (CKKSItem*) item error: (NSError * __autoreleasing *) error; + ++ (NSData*) encryptDictionary: (NSDictionary*) dict key: (CKKSAESSIVKey*) key authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error; ++ (NSDictionary*) decryptDictionary: (NSData*) encitem key: (CKKSAESSIVKey*) key authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error; + ++ (NSData *)padData:(NSData *)input blockSize:(NSUInteger)blockSize additionalBlock:(BOOL)extra; ++ (NSData *)removePaddingFromData:(NSData *)input; +@end + +#endif // OCTAGON + +#endif /* CKKSItemEncrypter_h */ + diff --git a/keychain/ckks/CKKSItemEncrypter.m b/keychain/ckks/CKKSItemEncrypter.m new file mode 100644 index 00000000..6327aa9f --- /dev/null +++ b/keychain/ckks/CKKSItemEncrypter.m @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#import +#import +#import + +#include + +#import "CKKSItemEncrypter.h" +#import "CKKSKeychainView.h" + +#import "CKKSOutgoingQueueEntry.h" +#import "CKKSKey.h" +#import "CKKSItem.h" + +#if OCTAGON + +@implementation CKKSItemEncrypter + +// Make it harder to distinguish password lengths especially when password is short. ++ (NSData *)padData:(NSData * _Nonnull)input blockSize:(NSUInteger)blockSize additionalBlock:(BOOL)extra { + // Must apply padding otherwise unpadding will choke + if (blockSize == 0) { + blockSize = 1; + secwarning("CKKS padding function received invalid blocksize 0, using 1 instead"); + } + NSMutableData *data = [NSMutableData dataWithData:input]; + NSUInteger paddingLength = blockSize - (data.length % blockSize); + // Short password as determined by caller: make sure there's at least one block of padding + if (extra) { + paddingLength += blockSize; + } + [data appendData:[NSMutableData dataWithLength:paddingLength]]; + uint8_t *bytes = [data mutableBytes]; + bytes[data.length - paddingLength] = CKKS_PADDING_MARK_BYTE; + return data; +} + ++ (NSData *)removePaddingFromData:(NSData * _Nonnull)input { + size_t len = input.length; + uint8_t const *bytes = [input bytes]; + size_t idx = len; + while (idx > 0) { + idx -= 1; + switch(bytes[idx]) { + case 0: + continue; + case CKKS_PADDING_MARK_BYTE: + return [input subdataWithRange:NSMakeRange(0, idx)]; + default: + return nil; + } + } + return nil; +} + ++(CKKSItem*)encryptCKKSItem:(CKKSItem*)baseitem + dataDictionary:(NSDictionary *)dict + updatingCKKSItem:(CKKSItem*)olditem + parentkey:(CKKSKey *)parentkey + error:(NSError * __autoreleasing *) error +{ + CKKSKey *itemkey = nil; + + // If we're updating a CKKSItem, extract its dictionary and overlay our new one on top + 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")); + return nil; + } + + // Use oldDictionary as a base, and copy in the objects from dict + [oldDictionary addEntriesFromDictionary: dict]; + // and replace the dictionary with the new one + dict = oldDictionary; + } + + // generate a new key and wrap it + itemkey = [CKKSKey randomKeyWrappedByParent: parentkey error:error]; + if(!itemkey) { + return nil; + } + + // Prepare the authenticated data dictionary. It includes the wrapped key, so prepare that first + CKKSItem* encryptedItem = [[CKKSItem alloc] initCopyingCKKSItem: baseitem]; + encryptedItem.parentKeyUUID = parentkey.uuid; + encryptedItem.wrappedkey = itemkey.wrappedkey; + + // if we're updating a v2 item, use v2 + if(olditem && olditem.encver == CKKSItemEncryptionVersion2 && (int)CKKSItemEncryptionVersion2 >= (int)currentCKKSItemEncryptionVersion) { + encryptedItem.encver = CKKSItemEncryptionVersion2; + } else { + encryptedItem.encver = currentCKKSItemEncryptionVersion; + } + + // Copy over the old item's CKRecord, updated for the new item data + if(olditem.storedCKRecord) { + encryptedItem.storedCKRecord = [encryptedItem updateCKRecord:olditem.storedCKRecord zoneID:olditem.storedCKRecord.recordID.zoneID]; + } + + NSDictionary* authenticatedData = [encryptedItem makeAuthenticatedDataDictionaryUpdatingCKKSItem: olditem encryptionVersion:encryptedItem.encver]; + + encryptedItem.encitem = [self encryptDictionary: dict key:itemkey.aessivkey authenticatedData:authenticatedData error:error]; + if(!encryptedItem.encitem) { + return nil; + } + + return encryptedItem; +} + ++ (NSDictionary*) decryptItemToDictionaryVersionNone: (CKKSItem*) item error: (NSError * __autoreleasing *) error { + return [NSPropertyListSerialization propertyListWithData:item.encitem + options:(NSPropertyListReadOptions)kCFPropertyListSupportedFormatBinary_v1_0 + format:nil + error:error]; +} + +// Note that the only difference between v1 and v2 is the authenticated data selection, so we can happily pass encver along ++ (NSDictionary*) decryptItemToDictionaryVersion1or2: (CKKSItem*) item error: (NSError * __autoreleasing *) error { + NSDictionary* authenticatedData = nil; + + CKKSAESSIVKey* itemkey = nil; + + CKKSKey* key = [CKKSKey loadKeyWithUUID: item.parentKeyUUID zoneID:item.zoneID error:error]; + if(!key) { + return nil; + } + + itemkey = [key unwrapAESKey:item.wrappedkey error:error]; + if(!itemkey) { + return nil; + } + + // Prepare the authenticated data dictionary (pass the item as the futureproofed object, so we'll authenticate any new fields in this particular item). + authenticatedData = [item makeAuthenticatedDataDictionaryUpdatingCKKSItem:item encryptionVersion:item.encver]; + + NSDictionary* result = [self decryptDictionary: item.encitem key:itemkey authenticatedData:authenticatedData error:error]; + if(!result) { + secwarning("ckks: couldn't decrypt item %@", *error); + } + return result; +} + ++ (NSDictionary*) decryptItemToDictionary: (CKKSItem*) item error: (NSError * __autoreleasing *) error { + switch (item.encver) { + case CKKSItemEncryptionVersion1: + return [CKKSItemEncrypter decryptItemToDictionaryVersion1or2:item error:error]; + case CKKSItemEncryptionVersion2: + return [CKKSItemEncrypter decryptItemToDictionaryVersion1or2:item error:error]; + case CKKSItemEncryptionVersionNone: /* version 0 was no encrypted, no longer supported */ + default: + { + NSError *localError = [NSError errorWithDomain:@"securityd" + code:1 + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"Unrecognized encryption version: %lu", (unsigned long)item.encver]}]; + secerror("decryptItemToDictionary %@", localError); + if (error) { + *error = localError; + } + return nil; + } + } +} + ++ (NSData*)encryptDictionary: (NSDictionary*) dict key: (CKKSAESSIVKey*) key authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error { + NSData* data = [NSPropertyListSerialization dataWithPropertyList:dict + format:NSPropertyListBinaryFormat_v1_0 + options:0 + error:error]; + if(!data) { + return nil; + } + // Hide password length. Apply extra padding to short passwords. + data = [CKKSItemEncrypter padData:data + blockSize:SecCKKSItemPaddingBlockSize + additionalBlock:[(NSData *)dict[@"v_Data"] length] < SecCKKSItemPaddingBlockSize]; + + return [key encryptData: data authenticatedData: ad error: error]; +} + ++ (NSDictionary*)decryptDictionary: (NSData*) encitem key: (CKKSAESSIVKey*) aeskey authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error { + NSData* plaintext = [aeskey decryptData: encitem authenticatedData: ad error: error]; + if(!plaintext) { + return nil; + } + plaintext = [CKKSItemEncrypter removePaddingFromData:plaintext]; + if(!plaintext) { + if (error) *error = [NSError errorWithDomain:@"securityd" + code:errSecInvalidData + userInfo:@{NSLocalizedDescriptionKey: @"Could not remove padding from decrypted item: malformed data"}]; + return nil; + } + return [NSPropertyListSerialization propertyListWithData:plaintext + options:(NSPropertyListReadOptions)kCFPropertyListSupportedFormatBinary_v1_0 + format:nil + error:error]; +} + +@end + +#endif diff --git a/keychain/ckks/CKKSKey.h b/keychain/ckks/CKKSKey.h new file mode 100644 index 00000000..ce0dedf6 --- /dev/null +++ b/keychain/ckks/CKKSKey.h @@ -0,0 +1,140 @@ +/* + * 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 + +#import "keychain/ckks/CKKSItem.h" +#import "keychain/ckks/CKKSSIV.h" + +#if OCTAGON + +@interface CKKSKey : CKKSItem + +@property (readonly) CKKSAESSIVKey* aessivkey; + +@property (copy) CKKSProcessedState* state; +@property (copy) CKKSKeyClass* keyclass; +@property bool currentkey; + +// Fetches and attempts to unwrap this key for use ++ (instancetype) loadKeyWithUUID: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + +// Creates new random keys, in the parent's zone ++ (instancetype) randomKeyWrappedByParent: (CKKSKey*) parentKey error: (NSError * __autoreleasing *) error; ++ (instancetype) randomKeyWrappedByParent: (CKKSKey*) parentKey keyclass:(CKKSKeyClass*)keyclass error: (NSError * __autoreleasing *) error; + +// Creates a new random key that wraps itself ++ (instancetype)randomKeyWrappedBySelf: (CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error; + +/* Helper functions for persisting key material in the keychain */ +- (bool)saveKeyMaterialToKeychain: (NSError * __autoreleasing *) error; +- (bool)saveKeyMaterialToKeychain: (bool)stashTLK error:(NSError * __autoreleasing *) error; // call this to not stash a non-syncable TLK, if that's what you want + +- (bool)loadKeyMaterialFromKeychain: (NSError * __autoreleasing *) error; +- (bool)deleteKeyMaterialFromKeychain: (NSError * __autoreleasing *) error; ++ (NSString*)isItemKeyForKeychainView: (SecDbItemRef) item; + +// Class methods to help tests ++ (bool)saveKeyMaterialToKeychain:(CKKSKey*)key stashTLK:(bool)stashTLK error:(NSError * __autoreleasing *) error; ++ (NSData*)loadKeyMaterialFromKeychain:(CKKSKey*)key resave:(bool*)resavePtr error:(NSError* __autoreleasing *) error; + ++ (instancetype)keyFromKeychain: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + keyclass: (CKKSKeyClass*)keyclass + state: (CKKSProcessedState*) state + zoneID: (CKRecordZoneID*) zoneID + encodedCKRecord: (NSData*) encodedrecord + currentkey: (NSInteger) currentkey + error: (NSError * __autoreleasing *) error; + + ++ (instancetype) fromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabaseAnyState: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (NSArray*) selfWrappedKeys: (CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (instancetype)currentKeyForClass: (CKKSKeyClass*) keyclass zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (NSArray*)currentKeysForClass: (CKKSKeyClass*) keyclass state:(CKKSProcessedState*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (NSArray*)allKeys: (CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (NSArray*)remoteKeys: (CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (NSArray*)localKeys: (CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + +- (bool)saveToDatabaseAsOnlyCurrentKeyForClassAndState: (NSError * __autoreleasing *) error; + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype) initSelfWrappedWithAESKey: (CKKSAESSIVKey*) aeskey + uuid: (NSString*) uuid + keyclass: (CKKSKeyClass*)keyclass + state: (CKKSProcessedState*) state + zoneID: (CKRecordZoneID*) zoneID + encodedCKRecord: (NSData*) encodedrecord + currentkey: (NSInteger) currentkey; + +- (instancetype) initWrappedBy: (CKKSKey*) wrappingKey + AESKey: (CKKSAESSIVKey*) aeskey + uuid: (NSString*) uuid + keyclass: (CKKSKeyClass*)keyclass + state: (CKKSProcessedState*) state + zoneID: (CKRecordZoneID*) zoneID + encodedCKRecord: (NSData*) encodedrecord + currentkey: (NSInteger) currentkey; + +- (instancetype) initWithWrappedAESKey: (CKKSWrappedAESSIVKey*) wrappedaeskey + uuid: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + keyclass: (CKKSKeyClass*)keyclass + state: (CKKSProcessedState*) state + zoneID: (CKRecordZoneID*) zoneID + encodedCKRecord: (NSData*) encodedrecord + currentkey: (NSInteger) currentkey; + +/* Returns true if we believe this key wraps itself. */ +- (bool)wrapsSelf; + +- (void)zeroKeys; + +- (CKKSKey*)topKeyInAnyState: (NSError * __autoreleasing *) error; + +// Attempts checks if the AES key is already loaded, or attempts to load it from the keychain. Returns false if it fails. +- (CKKSAESSIVKey*)ensureKeyLoaded: (NSError * __autoreleasing *) error; + +// Attempts to unwrap this key via unwrapping its wrapping keys via the key hierarchy. +- (CKKSAESSIVKey*)unwrapViaKeyHierarchy: (NSError * __autoreleasing *) error; + +- (CKKSWrappedAESSIVKey*)wrapAESKey: (CKKSAESSIVKey*) keyToWrap error: (NSError * __autoreleasing *) error; +- (CKKSAESSIVKey*)unwrapAESKey: (CKKSWrappedAESSIVKey*) keyToUnwrap error: (NSError * __autoreleasing *) error; + +- (bool)wrapUnder: (CKKSKey*) wrappingKey error: (NSError * __autoreleasing *) error; +- (bool)unwrapSelfWithAESKey: (CKKSAESSIVKey*) unwrappingKey error: (NSError * __autoreleasing *) error; + +- (NSData*)encryptData: (NSData*) plaintext authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error; +- (NSData*)decryptData: (NSData*) ciphertext authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error; + + ++ (NSDictionary*)countsByClass:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; +@end + +#endif diff --git a/keychain/ckks/CKKSKey.m b/keychain/ckks/CKKSKey.m new file mode 100644 index 00000000..a967f10e --- /dev/null +++ b/keychain/ckks/CKKSKey.m @@ -0,0 +1,833 @@ +/* + * 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 "CKKSViewManager.h" +#import "CKKSKeychainView.h" +#import "CKKSCurrentKeyPointer.h" +#import "CKKSKey.h" +#include +#include +#include + +#if OCTAGON + +#include +#include + +@implementation CKKSKey + +- (instancetype)init { + self = [super init]; + return self; +} + +- (instancetype) initSelfWrappedWithAESKey: (CKKSAESSIVKey*) aeskey + uuid: (NSString*) uuid + keyclass: (CKKSKeyClass*)keyclass + state: (CKKSProcessedState*) state + zoneID: (CKRecordZoneID*) zoneID + encodedCKRecord: (NSData*) encodedrecord + currentkey: (NSInteger) currentkey +{ + if(self = [super initWithUUID: uuid + parentKeyUUID: uuid + zoneID: zoneID + encodedCKRecord: encodedrecord + encItem: nil + wrappedkey: nil + generationCount: 0 + encver: currentCKKSItemEncryptionVersion]) { + _keyclass = keyclass; + _currentkey = !!currentkey; + _aessivkey = aeskey; + _state = state; + + self.ckRecordType = SecCKRecordIntermediateKeyType; + + // Wrap the key with the key. Not particularly useful, but there you go. + NSError* error = nil; + [self wrapUnder: self error:&error]; + if(error != nil) { + secerror("CKKSKey: Couldn't self-wrap key: %@", error); + return nil; + } + } + return self; +} + +- (instancetype) initWrappedBy: (CKKSKey*) wrappingKey + AESKey: (CKKSAESSIVKey*) aeskey + uuid: (NSString*) uuid + keyclass: (CKKSKeyClass*)keyclass + state: (CKKSProcessedState*) state + zoneID: (CKRecordZoneID*) zoneID + encodedCKRecord: (NSData*) encodedrecord + currentkey: (NSInteger) currentkey +{ + if(self = [super initWithUUID: uuid + parentKeyUUID: wrappingKey.uuid + zoneID: zoneID + encodedCKRecord: encodedrecord + encItem:nil + wrappedkey:nil + generationCount:0 + encver: + currentCKKSItemEncryptionVersion]) { + _keyclass = keyclass; + _currentkey = !!currentkey; + _aessivkey = aeskey; + _state = state; + + self.ckRecordType = SecCKRecordIntermediateKeyType; + + NSError* error = nil; + [self wrapUnder: wrappingKey error:&error]; + if(error != nil) { + secerror("CKKSKey: Couldn't wrap key with key: %@", error); + return nil; + } + } + return self; +} + +- (instancetype) initWithWrappedAESKey: (CKKSWrappedAESSIVKey*) wrappedaeskey + uuid: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + keyclass: (CKKSKeyClass*)keyclass + state: (CKKSProcessedState*) state + zoneID: (CKRecordZoneID*) zoneID + encodedCKRecord: (NSData*) encodedrecord + currentkey: (NSInteger) currentkey +{ + if(self = [super initWithUUID:uuid + parentKeyUUID:parentKeyUUID + zoneID:zoneID + encodedCKRecord:encodedrecord + encItem:nil + wrappedkey:wrappedaeskey + generationCount:0 + encver:currentCKKSItemEncryptionVersion]) { + _keyclass = keyclass; + _currentkey = !!currentkey; + _aessivkey = nil; + _state = state; + + self.ckRecordType = SecCKRecordIntermediateKeyType; + } + return self; +} + +- (void)dealloc { + [self zeroKeys]; +} + +- (void)zeroKeys { + [self.aessivkey zeroKey]; +} + +- (bool)wrapsSelf { + return [self.uuid isEqual: self.parentKeyUUID]; +} + +- (bool)wrapUnder: (CKKSKey*) wrappingKey error: (NSError * __autoreleasing *) error { + self.wrappedkey = [wrappingKey wrapAESKey: self.aessivkey error:error]; + if(self.wrappedkey == nil) { + secerror("CKKSKey: couldn't wrap key: %@", error ? *error : @"unknown error"); + } else { + self.parentKeyUUID = wrappingKey.uuid; + } + return (self.wrappedkey != nil); +} + +- (bool)unwrapSelfWithAESKey: (CKKSAESSIVKey*) unwrappingKey error: (NSError * __autoreleasing *) error { + _aessivkey = [unwrappingKey unwrapAESKey:self.wrappedkey error:error]; + return (_aessivkey != nil); +} + ++ (instancetype) loadKeyWithUUID: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + CKKSKey* key = [CKKSKey fromDatabase: uuid zoneID:zoneID error:error]; + + // failed unwrapping means we can't return a key. + if(![key ensureKeyLoaded:error]) { + return nil; + } + return key; +} + ++ (CKKSKey*) randomKeyWrappedByParent: (CKKSKey*) parentKey error: (NSError * __autoreleasing *) error { + return [self randomKeyWrappedByParent: parentKey keyclass:parentKey.keyclass error:error]; +} + ++ (CKKSKey*) randomKeyWrappedByParent: (CKKSKey*) parentKey keyclass:(CKKSKeyClass*)keyclass error: (NSError * __autoreleasing *) error { + CKKSAESSIVKey* aessivkey = [CKKSAESSIVKey randomKey]; + + CKKSKey* key = [[CKKSKey alloc] initWrappedBy: parentKey + AESKey: aessivkey + uuid:[[NSUUID UUID] UUIDString] + keyclass:keyclass + state:SecCKKSProcessedStateLocal + zoneID: parentKey.zoneID + encodedCKRecord: nil + currentkey: false]; + return key; +} + ++ (instancetype)randomKeyWrappedBySelf: (CKRecordZoneID*) zoneID error: (NSError * __autoreleasing *) error { + CKKSAESSIVKey* aessivkey = [CKKSAESSIVKey randomKey]; + NSString* uuid = [[NSUUID UUID] UUIDString]; + + CKKSKey* key = [[CKKSKey alloc] initSelfWrappedWithAESKey: aessivkey + uuid:uuid + keyclass:SecCKKSKeyClassTLK + state:SecCKKSProcessedStateLocal + zoneID: zoneID + encodedCKRecord: nil + currentkey: false]; + return key; + +} + +- (CKKSKey*)topKeyInAnyState: (NSError * __autoreleasing *) error { + // Recursively find the top-level key in the hierarchy, preferring 'remote' keys. + if([self wrapsSelf]) { + return self; + } + + CKKSKey* remoteParent = [CKKSKey tryFromDatabaseWhere: @{@"UUID": self.parentKeyUUID, @"state": SecCKKSProcessedStateRemote} error: error]; + if(remoteParent) { + return [remoteParent topKeyInAnyState: error]; + } + + // No remote parent. Fall back to anything. + CKKSKey* parent = [CKKSKey fromDatabaseWhere: @{@"UUID": self.parentKeyUUID} error: error]; + if(parent) { + return [parent topKeyInAnyState: error]; + } + + // No good. Error is already filled. + return nil; +} + +- (CKKSAESSIVKey*)ensureKeyLoaded: (NSError * __autoreleasing *) error { + if(self.aessivkey) { + return self.aessivkey; + } + + // Attempt to load this key from the keychain + if([self loadKeyMaterialFromKeychain:error]) { + return self.aessivkey; + } + + return nil; +} + + +- (CKKSAESSIVKey*)unwrapViaKeyHierarchy: (NSError * __autoreleasing *) error { + if(self.aessivkey) { + return self.aessivkey; + } + + NSError* localerror = nil; + + // Attempt to load this key from the keychain + if([self loadKeyMaterialFromKeychain:&localerror]) { + // Rad. Success! + return self.aessivkey; + } + + // First, check if we're a TLK. + if([self.keyclass isEqual: SecCKKSKeyClassTLK]) { + // Okay, not loading the key from the keychain above is an issue. If we have a parent key, then fall through to the recursion below. + if(!self.parentKeyUUID || [self.parentKeyUUID isEqualToString: self.uuid]) { + if(error) { + *error = localerror; + } + return nil; + } + } + + // Recursively unwrap our parent. + CKKSKey* parent = [CKKSKey fromDatabaseAnyState:self.parentKeyUUID zoneID:self.zoneID error:error]; + + // TODO: do we need loop detection here? + if(![parent unwrapViaKeyHierarchy: error]) { + return nil; + } + + _aessivkey = [parent unwrapAESKey:self.wrappedkey error:error]; + return self.aessivkey; +} + +- (CKKSWrappedAESSIVKey*)wrapAESKey: (CKKSAESSIVKey*) keyToWrap error: (NSError * __autoreleasing *) error { + CKKSAESSIVKey* key = [self ensureKeyLoaded: error]; + CKKSWrappedAESSIVKey* wrappedkey = [key wrapAESKey: keyToWrap error:error]; + return wrappedkey; +} + +- (CKKSAESSIVKey*)unwrapAESKey: (CKKSWrappedAESSIVKey*) keyToUnwrap error: (NSError * __autoreleasing *) error { + CKKSAESSIVKey* key = [self ensureKeyLoaded: error]; + CKKSAESSIVKey* unwrappedkey = [key unwrapAESKey: keyToUnwrap error:error]; + return unwrappedkey; +} + +- (NSData*)encryptData: (NSData*) plaintext authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error { + CKKSAESSIVKey* key = [self ensureKeyLoaded: error]; + NSData* data = [key encryptData: plaintext authenticatedData:ad error:error]; + return data; +} + +- (NSData*)decryptData: (NSData*) ciphertext authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error { + CKKSAESSIVKey* key = [self ensureKeyLoaded: error]; + NSData* data = [key decryptData: ciphertext authenticatedData:ad error:error]; + return data; +} + +/* Functions to load and save keys from the keychain (where we get to store actual key material!) */ +- (bool)saveKeyMaterialToKeychain: (NSError * __autoreleasing *) error { + return [self saveKeyMaterialToKeychain: true error: error]; +} + +- (bool)saveKeyMaterialToKeychain: (bool)stashTLK error:(NSError * __autoreleasing *) error { + return [CKKSKey saveKeyMaterialToKeychain:self stashTLK:stashTLK error:error]; +} + ++(bool)saveKeyMaterialToKeychain:(CKKSKey*)key stashTLK:(bool)stashTLK error:(NSError * __autoreleasing *) error { + + // Note that we only store the key class, view, UUID, parentKeyUUID, and key material in the keychain + // Any other metadata must be stored elsewhere and filled in at load time. + + if(![key ensureKeyLoaded:error]) { + // No key material, nothing to save to keychain. + return false; + } + + // iOS keychains can't store symmetric keys, so we're reduced to storing this key as a password + NSData* keydata = [[[NSData alloc] initWithBytes:key.aessivkey->key length:key.aessivkey->size] base64EncodedDataWithOptions:0]; + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup: @"com.apple.security.ckks", + (id)kSecAttrDescription: key.keyclass, + (id)kSecAttrServer: key.zoneID.zoneName, + (id)kSecAttrAccount: key.uuid, + (id)kSecAttrPath: key.parentKeyUUID, + (id)kSecAttrIsInvisible: @YES, + (id)kSecValueData : keydata, + } mutableCopy]; + + // Only TLKs are synchronizable. Other keyclasses must synchronize via key hierarchy. + if([key.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + // Use PCS-MasterKey view so they'll be initial-synced under SOS. + query[(id)kSecAttrSyncViewHint] = (id)kSecAttrViewHintPCSMasterKey; + query[(id)kSecAttrSynchronizable] = (id)kCFBooleanTrue; + } + + // Class C keys are accessible after first unlock; TLKs and Class A keys are accessible only when unlocked + if([key.keyclass isEqualToString: SecCKKSKeyClassC]) { + query[(id)kSecAttrAccessible] = (id)kSecAttrAccessibleAfterFirstUnlock; + } else { + query[(id)kSecAttrAccessible] = (id)kSecAttrAccessibleWhenUnlocked; + } + + OSStatus status = SecItemAdd((__bridge CFDictionaryRef) query, NULL); + + if(status == errSecDuplicateItem) { + // Sure, okay, fine, we'll update. + error = nil; + NSMutableDictionary* update = [@{ + (id)kSecValueData: keydata, + (id)kSecAttrPath: key.parentKeyUUID, + } mutableCopy]; + query[(id)kSecValueData] = nil; + query[(id)kSecAttrPath] = nil; + + // Udpate the view-hint, too + if([key.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + update[(id)kSecAttrSyncViewHint] = (id)kSecAttrViewHintPCSMasterKey; + query[(id)kSecAttrSyncViewHint] = nil; + } + + status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef)update); + } + + if(status && error) { + *error = [NSError errorWithDomain:@"securityd" + code:status + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"Couldn't save %@ to keychain: %d", self, (int)status]}]; + } + + // TLKs are synchronizable. Stash them nonsyncably nearby. + // Don't report errors here. + if(stashTLK && [key.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + query = [@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup: @"com.apple.security.ckks", + (id)kSecAttrDescription: [key.keyclass stringByAppendingString: @"-nonsync"], + (id)kSecAttrServer: key.zoneID.zoneName, + (id)kSecAttrAccount: key.uuid, + (id)kSecAttrPath: key.parentKeyUUID, + (id)kSecAttrIsInvisible: @YES, + (id)kSecValueData : keydata, + } mutableCopy]; + query[(id)kSecAttrSynchronizable] = (id)kCFBooleanFalse; + + OSStatus stashstatus = SecItemAdd((__bridge CFDictionaryRef) query, NULL); + if(stashstatus != errSecSuccess) { + if(stashstatus == errSecDuplicateItem) { + // Sure, okay, fine, we'll update. + error = nil; + NSDictionary* update = @{ + (id)kSecValueData: keydata, + (id)kSecAttrPath: key.parentKeyUUID, + }; + query[(id)kSecValueData] = nil; + query[(id)kSecAttrPath] = nil; + + stashstatus = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef)update); + } + + if(stashstatus != errSecSuccess) { + secerror("ckkskey: Couldn't stash %@ to keychain: %d", self, (int)stashstatus); + } + } + } + + return status == 0; +} + ++ (NSData*)loadKeyMaterialFromKeychain:(CKKSKey*)key resave:(bool*)resavePtr error:(NSError* __autoreleasing *)error { + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrDescription: key.keyclass, + (id)kSecAttrAccount: key.uuid, + (id)kSecAttrServer: key.zoneID.zoneName, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @YES, + } mutableCopy]; + + // Synchronizable items are only found if you request synchronizable items. Only TLKs are synchronizable. + if([key.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + query[(id)kSecAttrSynchronizable] = (id)kCFBooleanTrue; + } + + CFTypeRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result); + + if(status == errSecItemNotFound) { + CFReleaseNull(result); + //didn't find a regular tlk? how about a piggy? + if([key.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + query = [@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrDescription: @"tlk-piggy", + (id)kSecAttrSynchronizable : (id)kSecAttrSynchronizableAny, + (id)kSecAttrAccount: [NSString stringWithFormat: @"%@-piggy", key.uuid], + (id)kSecAttrServer: key.zoneID.zoneName, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @YES, + (id)kSecMatchLimit: (id)kSecMatchLimitOne, + } mutableCopy]; + status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result); + if(status == errSecSuccess){ + secnotice("ckkskey", "loaded a piggy TLK (%@)", key.uuid); + + if(resavePtr) { + *resavePtr = true; + } + } + } + } + if(status == errSecItemNotFound && [key.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + CFReleaseNull(result); + + // Try to look for the non-syncable stashed tlk and resurrect it. + query = [@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrDescription: [key.keyclass stringByAppendingString: @"-nonsync"], + (id)kSecAttrServer: key.zoneID.zoneName, + (id)kSecAttrAccount: key.uuid, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @YES, + (id)kSecAttrSynchronizable: @NO, + } mutableCopy]; + + status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result); + if(status == errSecSuccess) { + secnotice("ckkskey", "loaded a stashed TLK (%@)", key.uuid); + + if(resavePtr) { + *resavePtr = true; + } + } + } + + if(status){ //still can't find it! + if(error) { + *error = [NSError errorWithDomain:@"securityd" + code:status + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"Couldn't load %@ from keychain: %d", self, (int)status]}]; + } + return false; + } + + // Determine if we should fix up any attributes on this item... + NSDictionary* resultDict = CFBridgingRelease(result); + + // We created some TLKs with no ViewHint. Fix it. + if([key.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + NSString* viewHint = resultDict[(id)kSecAttrSyncViewHint]; + if(!viewHint) { + ckksnotice("ckkskey", key.zoneID, "Fixing up non-viewhinted TLK %@", self); + query[(id)kSecReturnAttributes] = nil; + query[(id)kSecReturnData] = nil; + + NSDictionary* update = @{(id)kSecAttrSyncViewHint: (id)kSecAttrViewHintPCSMasterKey}; + + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update); + if(status) { + // Don't report error upwards; this is an optimization fixup. + secerror("ckkskey: Couldn't update viewhint on existing TLK %@", self); + } + } + } + + // Okay, back to the real purpose of this function: extract the CFData currently in the results dictionary + NSData* b64keymaterial = resultDict[(id)kSecValueData]; + NSData* keymaterial = [[NSData alloc] initWithBase64EncodedData:b64keymaterial options:0]; + return keymaterial; +} + +- (bool)loadKeyMaterialFromKeychain: (NSError * __autoreleasing *) error { + bool resave = false; + NSData* keymaterial = [CKKSKey loadKeyMaterialFromKeychain:self resave:&resave error:error]; + if(!keymaterial) { + return false; + } + + CKKSAESSIVKey* key = [[CKKSAESSIVKey alloc] initWithBytes: (uint8_t*) keymaterial.bytes len:keymaterial.length]; + _aessivkey = key; + + if(resave) { + secnotice("ckkskey", "Resaving %@ as per request", self); + NSError* resaveError = nil; + [self saveKeyMaterialToKeychain:&resaveError]; + if(resaveError) { + secnotice("ckkskey", "Resaving %@ failed: %@", self, resaveError); + } + } + + return !!(self.aessivkey); +} + +- (bool)deleteKeyMaterialFromKeychain: (NSError * __autoreleasing *) error { + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrDescription: self.keyclass, + (id)kSecAttrAccount: self.uuid, + (id)kSecAttrServer: self.zoneID.zoneName, + (id)kSecReturnData: @YES, + } mutableCopy]; + + // Synchronizable items are only found if you request synchronizable items. Only TLKs are synchronizable. + if([self.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + query[(id)kSecAttrSynchronizable] = (id)kCFBooleanTrue; + } + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef) query); + + if(status) { + if(error) { + *error = [NSError errorWithDomain:@"securityd" + code:status + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"Couldn't delete %@ from keychain: %d", self, (int)status]}]; + } + return false; + } + return true; +} + ++ (instancetype)keyFromKeychain: (NSString*) uuid + parentKeyUUID: (NSString*) parentKeyUUID + keyclass: (CKKSKeyClass*)keyclass + state: (CKKSProcessedState*) state + zoneID: (CKRecordZoneID*) zoneID + encodedCKRecord: (NSData*) encodedrecord + currentkey: (NSInteger) currentkey + error: (NSError * __autoreleasing *) error { + CKKSKey* key = [[CKKSKey alloc] initWithWrappedAESKey:nil + uuid:uuid + parentKeyUUID:parentKeyUUID + keyclass:keyclass + state:state + zoneID:zoneID + encodedCKRecord:encodedrecord + currentkey:currentkey]; + + if(![key loadKeyMaterialFromKeychain:error]) { + return nil; + } + + return key; +} + ++ (NSString*)isItemKeyForKeychainView: (SecDbItemRef) item { + + NSString* accessgroup = (__bridge NSString*) SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup); + NSString* description = (__bridge NSString*) SecDbItemGetCachedValueWithName(item, kSecAttrDescription); + NSString* server = (__bridge NSString*) SecDbItemGetCachedValueWithName(item, kSecAttrServer); + + if(accessgroup && description && server && + ![accessgroup isEqual:[NSNull null]] && + ![description isEqual:[NSNull null]] && + ![server isEqual:[NSNull null]] && + + [accessgroup isEqualToString:@"com.apple.security.ckks"] && + ([description isEqualToString: SecCKKSKeyClassTLK] || + [description isEqualToString: [NSString stringWithFormat:@"%@-nonsync", SecCKKSKeyClassTLK]] || + [description isEqualToString: [NSString stringWithFormat:@"%@-piggy", SecCKKSKeyClassTLK]] || + [description isEqualToString: SecCKKSKeyClassA] || + [description isEqualToString: SecCKKSKeyClassC])) { + + // Certainly looks like us! Return the view name. + return server; + } + + // Never heard of this item. + return nil; +} + + +/* Database functions only return keys marked 'local', unless otherwise specified. */ + ++ (instancetype) fromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"UUID": uuid, @"state": SecCKKSProcessedStateLocal, @"ckzone":zoneID.zoneName} error: error]; +} + ++ (instancetype) fromDatabaseAnyState: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"UUID": uuid, @"ckzone":zoneID.zoneName} error: error]; +} + ++ (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"UUID": uuid, @"state": SecCKKSProcessedStateLocal, @"ckzone":zoneID.zoneName} error: error]; +} + ++ (instancetype) tryFromDatabaseAnyState: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"UUID": uuid, @"ckzone":zoneID.zoneName} error: error]; +} + ++ (NSArray*)selfWrappedKeys:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere: @{@"UUID": [CKKSSQLWhereObject op:@"=" string:@"parentKeyUUID"], @"state": SecCKKSProcessedStateLocal, @"ckzone":zoneID.zoneName} error:error]; +} + ++ (instancetype) currentKeyForClass: (CKKSKeyClass*) keyclass zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + // Load the CurrentKey record, and find the key for it + CKKSCurrentKeyPointer* ckp = [CKKSCurrentKeyPointer fromDatabase:keyclass zoneID:zoneID error:error]; + if(!ckp) { + return nil; + } + return [self fromDatabase:ckp.currentKeyUUID zoneID:zoneID error:error]; +} + ++ (NSArray*) currentKeysForClass: (CKKSKeyClass*) keyclass state:(NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere: @{@"keyclass": keyclass, @"currentkey": @"1", @"state": state ? state : SecCKKSProcessedStateLocal, @"ckzone":zoneID.zoneName} error:error]; +} + +/* Returns all keys for a zone */ ++ (NSArray*)allKeys: (CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere: @{@"ckzone":zoneID.zoneName} error:error]; +} + +/* Returns all keys marked 'remote', i.e., downloaded from CloudKit */ ++ (NSArray*)remoteKeys: (CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere: @{@"state": SecCKKSProcessedStateRemote, @"ckzone":zoneID.zoneName} error:error]; +} + +/* Returns all keys marked 'local', i.e., processed in the past */ ++ (NSArray*)localKeys: (CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere: @{@"state": SecCKKSProcessedStateLocal, @"ckzone":zoneID.zoneName} error:error]; +} + +- (bool)saveToDatabaseAsOnlyCurrentKeyForClassAndState: (NSError * __autoreleasing *) error { + self.currentkey = true; + + // Find other keys for our key class + NSArray* keys = [CKKSKey currentKeysForClass: self.keyclass state: self.state zoneID:self.zoneID error:error]; + if(!keys) { + return false; + } + + for(CKKSKey* key in keys) { + key.currentkey = false; + if(![key saveToDatabase: error]) { + return false; + } + } + if(![self saveToDatabase: error]) { + return false; + } + + return true; +} + +#pragma mark - CKRecord handling + +- (void) setFromCKRecord: (CKRecord*) record { + if(![record.recordType isEqual: SecCKRecordIntermediateKeyType]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordTypeException" + reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordIntermediateKeyType] + userInfo:nil]; + } + + [self setStoredCKRecord: record]; + + self.uuid = [[record recordID] recordName]; + if(record[SecCKRecordParentKeyRefKey] != nil) { + self.parentKeyUUID = [record[SecCKRecordParentKeyRefKey] recordID].recordName; + } else { + // We wrap ourself. + self.parentKeyUUID = self.uuid; + } + + self.keyclass = record[SecCKRecordKeyClassKey]; + self.wrappedkey = [[CKKSWrappedAESSIVKey alloc] initWithBase64: record[SecCKRecordWrappedKeyKey]]; +} + +- (CKRecord*) updateCKRecord: (CKRecord*) record zoneID: (CKRecordZoneID*) zoneID { + if(![record.recordType isEqual: SecCKRecordIntermediateKeyType]) { + @throw [NSException + exceptionWithName:@"WrongCKRecordTypeException" + reason:[NSString stringWithFormat: @"CKRecordType (%@) was not %@", record.recordType, SecCKRecordIntermediateKeyType] + userInfo:nil]; + } + + // The parent key must exist in CloudKit, or this record save will fail. + if([self.parentKeyUUID isEqual: self.uuid]) { + // We wrap ourself. No parent. + record[SecCKRecordParentKeyRefKey] = nil; + } else { + record[SecCKRecordParentKeyRefKey] = [[CKReference alloc] initWithRecordID: [[CKRecordID alloc] initWithRecordName: self.parentKeyUUID zoneID: zoneID] action: CKReferenceActionValidate]; + } + + [CKKSItem setOSVersionInRecord: record]; + + record[SecCKRecordKeyClassKey] = self.keyclass; + record[SecCKRecordWrappedKeyKey] = [self.wrappedkey base64WrappedKey]; + + return record; +} + +#pragma mark - Utility + +- (NSString*)description { + return [NSString stringWithFormat: @"<%@(%@): %@ (%@,%@:%d) %p>", + NSStringFromClass([self class]), + self.zoneID.zoneName, + self.uuid, + self.keyclass, + self.state, + self.currentkey, + &self]; +} + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*) sqlTable { + return @"synckeys"; +} + ++ (NSArray*) sqlColumns { + return @[@"UUID", @"parentKeyUUID", @"ckzone", @"ckrecord", @"keyclass", @"state", @"currentkey", @"wrappedkey"]; +} + +- (NSDictionary*) whereClauseToFindSelf { + return @{@"UUID": self.uuid, @"state": self.state, @"ckzone":self.zoneID.zoneName}; +} + +- (NSDictionary*) sqlValues { + return @{@"UUID": self.uuid, + @"parentKeyUUID": self.parentKeyUUID ? self.parentKeyUUID : self.uuid, // if we don't have a parent, we wrap ourself. + @"ckzone": CKKSNilToNSNull(self.zoneID.zoneName), + @"ckrecord": CKKSNilToNSNull([self.encodedCKRecord base64EncodedStringWithOptions:0]), + @"keyclass": CKKSNilToNSNull(self.keyclass), + @"state": CKKSNilToNSNull(self.state), + @"wrappedkey": CKKSNilToNSNull([self.wrappedkey base64WrappedKey]), + @"currentkey": self.currentkey ? @"1" : @"0"}; +} + ++ (instancetype) fromDatabaseRow: (NSDictionary*) row { + return [[CKKSKey alloc] initWithWrappedAESKey: row[@"wrappedkey"] ? [[CKKSWrappedAESSIVKey alloc] initWithBase64: row[@"wrappedkey"]] : nil + uuid: row[@"UUID"] + parentKeyUUID: row[@"parentKeyUUID"] + keyclass: row[@"keyclass"] + state: row[@"state"] + zoneID: [[CKRecordZoneID alloc] initWithZoneName: row[@"ckzone"] ownerName:CKCurrentUserDefaultName] + encodedCKRecord: [[NSData alloc] initWithBase64EncodedString: row[@"ckrecord"] options:0] + currentkey: [row[@"currentkey"] integerValue]]; + +} + ++ (NSDictionary*)countsByClass:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + NSMutableDictionary* results = [[NSMutableDictionary alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [[self class] sqlTable] + where: @{@"ckzone": CKKSNilToNSNull(zoneID.zoneName)} + columns: @[@"keyclass", @"state", @"count(rowid)"] + groupBy: @[@"keyclass", @"state"] + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + results[[NSString stringWithFormat: @"%@-%@", row[@"state"], row[@"keyclass"]]] = + [NSNumber numberWithInteger: [row[@"count(rowid)"] integerValue]]; + } + error: error]; + return results; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + CKKSKey *keyCopy = [super copyWithZone:zone]; + keyCopy->_aessivkey = _aessivkey; + keyCopy->_state = _state; + keyCopy->_keyclass = _keyclass; + keyCopy->_currentkey = _currentkey; + return keyCopy; +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSKeychainView.h b/keychain/ckks/CKKSKeychainView.h new file mode 100644 index 00000000..f9d7de00 --- /dev/null +++ b/keychain/ckks/CKKSKeychainView.h @@ -0,0 +1,251 @@ +/* + * 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 CKKSKeychainView_h +#define CKKSKeychainView_h + +#import +#include + +#if OCTAGON +#import "keychain/ckks/CloudKitDependencies.h" +#import "keychain/ckks/CKKSAPSReceiver.h" +#import "keychain/ckks/CKKSLockStateTracker.h" +#endif + +#include +#include + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSIncomingQueueOperation.h" +#import "keychain/ckks/CKKSOutgoingQueueOperation.h" +#import "keychain/ckks/CKKSNearFutureScheduler.h" +#import "keychain/ckks/CKKSNewTLKOperation.h" +#import "keychain/ckks/CKKSProcessReceivedKeysOperation.h" +#import "keychain/ckks/CKKSReencryptOutgoingItemsOperation.h" +#import "keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h" +#import "keychain/ckks/CKKSScanLocalItemsOperation.h" +#import "keychain/ckks/CKKSUpdateDeviceStateOperation.h" +#import "keychain/ckks/CKKSGroupOperation.h" +#import "keychain/ckks/CKKSZone.h" +#import "keychain/ckks/CKKSZoneChangeFetcher.h" +#import "keychain/ckks/CKKSNotifier.h" + +#include "CKKS.h" + +# if !OCTAGON +@interface CKKSKeychainView : NSObject { + NSString* _containerName; +} +@end +#else // OCTAGON + +@class CKKSKey; +@class CKKSAESSIVKey; +@class CKKSSynchronizeOperation; +@class CKKSRateLimiter; +@class CKKSManifest; +@class CKKSEgoManifest; +@class CKKSOutgoingQueueEntry; +@class CKKSZoneChangeFetcher; + +@interface CKKSKeychainView : CKKSZone { + CKKSZoneKeyState* _keyHierarchyState; +} + +@property CKKSLockStateTracker* lockStateTracker; + +@property CKKSZoneKeyState* keyHierarchyState; +@property NSError* keyHierarchyError; +@property CKOperationGroup* keyHierarchyOperationGroup; +@property NSOperation* keyStateMachineOperation; + +// If the key hierarchy isn't coming together, it might be because we're out of sync with cloudkit. +// Use this to track if we've completed a full refetch, so fix-up operations can be done. +@property bool keyStateMachineRefetched; +@property CKKSEgoManifest* egoManifest; +@property CKKSManifest* latestManifest; +@property CKKSResultOperation* keyStateReadyDependency; + +@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* keyHierarchyConditions; + +@property CKKSZoneChangeFetcher* zoneChangeFetcher; + +@property (weak) CKKSNearFutureScheduler* savedTLKNotifier; + +// Differs from the zonesetupoperation: zoneSetup is only for CK modifications, viewSetup handles local db changes too +@property CKKSGroupOperation* viewSetupOperation; + +/* Used for debugging: just what happened last time we ran this? */ +@property CKKSIncomingQueueOperation* lastIncomingQueueOperation; +@property CKKSNewTLKOperation* lastNewTLKOperation; +@property CKKSOutgoingQueueOperation* lastOutgoingQueueOperation; +@property CKKSProcessReceivedKeysOperation* lastProcessReceivedKeysOperation; +@property CKKSFetchAllRecordZoneChangesOperation* lastRecordZoneChangesOperation; +@property CKKSReencryptOutgoingItemsOperation* lastReencryptOutgoingItemsOperation; +@property CKKSScanLocalItemsOperation* lastScanLocalItemsOperation; +@property CKKSSynchronizeOperation* lastSynchronizeOperation; + +/* Used for testing: pause operation types by adding operations here */ +@property NSOperation* holdReencryptOutgoingItemsOperation; +@property NSOperation* holdOutgoingQueueOperation; + +/* Trigger this to tell the whole machine that this view has changed */ +@property CKKSNearFutureScheduler* notifyViewChangedScheduler; + +- (instancetype)initWithContainer: (CKContainer*) container + zoneName: (NSString*) zoneName + accountTracker:(CKKSCKAccountStateTracker*) accountTracker + lockStateTracker:(CKKSLockStateTracker*) lockStateTracker + savedTLKNotifier:(CKKSNearFutureScheduler*) savedTLKNotifier + fetchRecordZoneChangesOperationClass: (Class) fetchRecordZoneChangesOperationClass + modifySubscriptionsOperationClass: (Class) modifySubscriptionsOperationClass + modifyRecordZonesOperationClass: (Class) modifyRecordZonesOperationClass + apsConnectionClass: (Class) apsConnectionClass + notifierClass: (Class) notifierClass; + +/* Synchronous operations */ + +- (void) handleKeychainEventDbConnection:(SecDbConnectionRef) dbconn + added:(SecDbItemRef) added + deleted:(SecDbItemRef) deleted + rateLimiter:(CKKSRateLimiter*) rateLimiter + syncCallback:(SecBoolNSErrorCallback) syncCallback; + +-(void)setCurrentItemForAccessGroup:(SecDbItemRef)newItem + hash:(NSData*)newItemSHA1 + accessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + replacing:(SecDbItemRef)oldItem + hash:(NSData*)oldItemSHA1 + complete:(void (^) (NSError* operror)) complete; + +-(void)getCurrentItemForAccessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + fetchCloudValue:(bool)fetchCloudValue + complete:(void (^) (NSString* uuid, NSError* operror)) complete; + +- (bool) outgoingQueueEmpty: (NSError * __autoreleasing *) error; + +- (CKKSResultOperation*)waitForFetchAndIncomingQueueProcessing; +- (void) waitForKeyHierarchyReadiness; +- (void) cancelAllOperations; + +- (CKKSKey*) keyForItem: (SecDbItemRef) item error: (NSError * __autoreleasing *) error; + +- (bool)checkTLK: (CKKSKey*) proposedTLK error: (NSError * __autoreleasing *) error; + +/* Asynchronous kickoffs */ + +- (void) initializeZone; + +- (CKKSOutgoingQueueOperation*)processOutgoingQueue:(CKOperationGroup*)ckoperationGroup; +- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation*)after ckoperationGroup:(CKOperationGroup*)ckoperationGroup; + +- (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA; +- (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA after: (CKKSResultOperation*) after; + +// Schedules a process queueoperation to happen after the next device unlock. This may be Immediately, if the device is unlocked. +- (void)processIncomingQueueAfterNextUnlock; + +// Schedules an operation to update this device's state record in CloudKit +// If rateLimit is true, the operation will abort if it's updated the record in the past 3 days +- (CKKSUpdateDeviceStateOperation*)updateDeviceState:(bool)rateLimit ckoperationGroup:(CKOperationGroup*)ckoperationGroup; + +- (CKKSSynchronizeOperation*) resyncWithCloud; + +- (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because; + +- (CKKSResultOperation*)resetLocalData; +- (CKKSResultOperation*)resetCloudKitZone; + +// Call this to pick and start the next key hierarchy operation for the zone +- (void)advanceKeyStateMachine; + +// Call this to tell the key state machine that you think some new data has arrived that it is interested in +- (void)keyStateMachineRequestProcess; + +// 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) dispatchAsync: (bool (^)(void)) block; +- (void) dispatchSync: (bool (^)(void)) block; +- (void)dispatchSyncWithAccountQueue:(bool (^)(void))block; + +/* Synchronous operations which must be called from inside a dispatchAsync 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 refetch everything in Cloudkit +- (void)_onqueueKeyStateMachineRequestFullRefetch; + +// 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*) state withError: (NSError*) 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 error: (NSError* __autoreleasing*) error; +- (bool)_onqueueErrorOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe itemError: (NSError*) itemError error: (NSError* __autoreleasing*) error; + +// Call this if you've done a write and received an error. It'll pull out any new records returned as CKErrorServerRecordChanged and pretend we received them in a fetch +// +// Note that you need to tell this function the records you wanted to save, so it can determine which record failed from its CKRecordID. +// I don't know why CKRecordIDs don't have record types, either. +- (bool)_onqueueCKWriteFailed:(NSError*)ckerror attemptedRecordsChanged:(NSDictionary*)savedRecords; + +- (bool) _onqueueCKRecordChanged:(CKRecord*)record resync:(bool)resync; +- (bool) _onqueueCKRecordDeleted:(CKRecordID*)recordID recordType:(NSString*)recordType resync:(bool)resync; + +- (bool)_onQueueUpdateLatestManifestWithError:(NSError**)error; + +- (CKKSDeviceStateEntry*)_onqueueCurrentDeviceStateEntry: (NSError* __autoreleasing*)error; + +// Called by the CKKSZoneChangeFetcher +- (bool) isFatalCKFetchError: (NSError*) error; + +// Please don't use these unless you're an Operation in this package +@property NSHashTable* incomingQueueOperations; +@property NSHashTable* outgoingQueueOperations; +@property CKKSScanLocalItemsOperation* initialScanOperation; + +// Returns the current state of this view +-(NSDictionary*)status; +@end +#endif // OCTAGON + + +#define SecTranslateError(nserrorptr, cferror) \ + if(nserrorptr) { \ + *nserrorptr = (__bridge_transfer NSError*) cferror; \ + } else { \ + CFReleaseNull(cferror); \ + } + +#endif /* CKKSKeychainView_h */ diff --git a/keychain/ckks/CKKSKeychainView.m b/keychain/ckks/CKKSKeychainView.m new file mode 100644 index 00000000..f176f2ed --- /dev/null +++ b/keychain/ckks/CKKSKeychainView.m @@ -0,0 +1,2436 @@ +/* + * 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 "CKKSKeychainView.h" + + + +#if OCTAGON +#import "CloudKitDependencies.h" +#import +#import +#endif + +#import "CKKS.h" +#import "CKKSAPSReceiver.h" +#import "CKKSIncomingQueueEntry.h" +#import "CKKSOutgoingQueueEntry.h" +#import "CKKSCurrentKeyPointer.h" +#import "CKKSKey.h" +#import "CKKSMirrorEntry.h" +#import "CKKSZoneStateEntry.h" +#import "CKKSItemEncrypter.h" +#import "CKKSIncomingQueueOperation.h" +#import "CKKSNewTLKOperation.h" +#import "CKKSProcessReceivedKeysOperation.h" +#import "CKKSZone.h" +#import "CKKSFetchAllRecordZoneChangesOperation.h" +#import "CKKSHealKeyHierarchyOperation.h" +#import "CKKSReencryptOutgoingItemsOperation.h" +#import "CKKSScanLocalItemsOperation.h" +#import "CKKSSynchronizeOperation.h" +#import "CKKSRateLimiter.h" +#import "CKKSManifest.h" +#import "CKKSManifestLeafRecord.h" +#import "CKKSZoneChangeFetcher.h" +#import "keychain/ckks/CKKSDeviceStateEntry.h" +#import "keychain/ckks/CKKSNearFutureScheduler.h" +#import "keychain/ckks/CKKSCurrentItemPointer.h" +#import "keychain/ckks/CKKSUpdateCurrentItemPointerOperation.h" +#import "keychain/ckks/CKKSUpdateDeviceStateOperation.h" +#import "keychain/ckks/CKKSLockStateTracker.h" +#import "keychain/ckks/CKKSNotifier.h" +#import "keychain/ckks/CloudKitCategories.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if OCTAGON +@interface CKKSKeychainView() +@property bool setupSuccessful; +@property bool keyStateFetchRequested; +@property bool keyStateFullRefetchRequested; +@property bool keyStateProcessRequested; +@property (atomic) NSString *activeTLK; + +@property (readonly) Class notifierClass; + +@property CKKSNearFutureScheduler* initializeScheduler; + +@property CKKSResultOperation* processIncomingQueueAfterNextUnlockOperation; + +@property NSMutableDictionary* pendingSyncCallbacks; +@end +#endif + +@implementation CKKSKeychainView +#if OCTAGON + +- (instancetype)initWithContainer: (CKContainer*) container + zoneName: (NSString*) zoneName + accountTracker:(CKKSCKAccountStateTracker*) accountTracker + lockStateTracker:(CKKSLockStateTracker*) lockStateTracker + savedTLKNotifier:(CKKSNearFutureScheduler*) savedTLKNotifier + fetchRecordZoneChangesOperationClass: (Class) fetchRecordZoneChangesOperationClass + modifySubscriptionsOperationClass: (Class) modifySubscriptionsOperationClass + modifyRecordZonesOperationClass: (Class) modifyRecordZonesOperationClass + apsConnectionClass: (Class) apsConnectionClass + notifierClass: (Class) notifierClass +{ + + if(self = [super initWithContainer:container + zoneName:zoneName + accountTracker:accountTracker + fetchRecordZoneChangesOperationClass:fetchRecordZoneChangesOperationClass + modifySubscriptionsOperationClass:modifySubscriptionsOperationClass + modifyRecordZonesOperationClass:modifyRecordZonesOperationClass + apsConnectionClass:apsConnectionClass]) { + __weak __typeof(self) weakSelf = self; + + _incomingQueueOperations = [NSHashTable weakObjectsHashTable]; + _outgoingQueueOperations = [NSHashTable weakObjectsHashTable]; + _zoneChangeFetcher = [[CKKSZoneChangeFetcher alloc] initWithCKKSKeychainView: self]; + + _notifierClass = notifierClass; + _notifyViewChangedScheduler = [[CKKSNearFutureScheduler alloc] initWithName:[NSString stringWithFormat: @"%@-notify-scheduler", self.zoneName] + initialDelay:250*NSEC_PER_MSEC + continuingDelay:1*NSEC_PER_SEC + keepProcessAlive:true + block:^{ + __strong __typeof(self) strongSelf = weakSelf; + ckksnotice("ckks", strongSelf, ""); + [strongSelf.notifierClass post:[NSString stringWithFormat:@"com.apple.security.view-change.%@", strongSelf.zoneName]]; + + // Ugly, but: the Manatee and Engram views need to send a fake 'PCS' view change. + // TODO: make this data-driven somehow + if([strongSelf.zoneName isEqualToString:@"Manatee"] || [strongSelf.zoneName isEqualToString:@"Engram"]) { + [strongSelf.notifierClass post:@"com.apple.security.view-change.PCS"]; + } + }]; + + _pendingSyncCallbacks = [[NSMutableDictionary alloc] init]; + + _lockStateTracker = lockStateTracker; + _savedTLKNotifier = savedTLKNotifier; + + _setupSuccessful = false; + + _keyHierarchyConditions = [[NSMutableDictionary alloc] init]; + [CKKSZoneKeyStateMap() enumerateKeysAndObjectsUsingBlock:^(CKKSZoneKeyState * _Nonnull key, NSNumber * _Nonnull obj, BOOL * _Nonnull stop) { + [self.keyHierarchyConditions setObject: [[CKKSCondition alloc] init] forKey:key]; + }]; + + self.keyHierarchyState = SecCKKSZoneKeyStateInitializing; + _keyHierarchyError = nil; + _keyHierarchyOperationGroup = nil; + _keyStateMachineOperation = nil; + _keyStateFetchRequested = false; + _keyStateProcessRequested = false; + + _keyStateReadyDependency = [CKKSResultOperation operationWithBlock:^{ + ckksnotice("ckkskey", weakSelf, "Key state has become ready for the first time."); + }]; + self.keyStateReadyDependency.name = [NSString stringWithFormat: @"%@-key-state-ready", self.zoneName]; + + dispatch_time_t initializeDelay = SecCKKSTestsEnabled() ? NSEC_PER_MSEC * 500 : NSEC_PER_SEC * 30; + _initializeScheduler = [[CKKSNearFutureScheduler alloc] initWithName:[NSString stringWithFormat: @"%@-zone-initializer", self.zoneName] + initialDelay:0 + continuingDelay:initializeDelay + keepProcessAlive:false + block:^{ + __strong __typeof(self) strongSelf = weakSelf; + ckksnotice("ckks", strongSelf, "initialize-scheduler restarting setup"); + [strongSelf maybeRestartSetup]; + }]; + + } + return self; +} + +- (NSString*)description { + return [NSString stringWithFormat:@"<%@: %@>", NSStringFromClass([self class]), self.zoneName]; +} + +- (NSString*)debugDescription { + return [NSString stringWithFormat:@"<%@: %@ %p>", NSStringFromClass([self class]), self.zoneName, 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 + if(_keyHierarchyState) { + self.keyHierarchyConditions[_keyHierarchyState] = [[CKKSCondition alloc] init]; + } + if(keyHierarchyState) { + [self.keyHierarchyConditions[keyHierarchyState] fulfill]; + } + } + + _keyHierarchyState = keyHierarchyState; +} + +- (NSString *)lastActiveTLKUUID +{ + return self.activeTLK; +} + +- (void) initializeZone { + // Unfortunate, but makes retriggering easy. + [self.initializeScheduler trigger]; +} + +- (void)maybeRestartSetup { + [self dispatchSync: ^bool{ + if(self.setupStarted && !self.setupComplete) { + ckksdebug("ckks", self, "setup has restarted. Ignoring timer fire"); + return false; + } + + if(self.setupSuccessful) { + ckksdebug("ckks", self, "setup has completed successfully. Ignoring timer fire"); + return false; + } + + [self resetSetup]; + [self _onqueueInitializeZone]; + return true; + }]; +} + +- (void)resetSetup { + [super resetSetup]; + self.setupSuccessful = false; + + // Key hierarchy state machine resets, too + self.keyHierarchyState = SecCKKSZoneKeyStateInitializing; + _keyHierarchyError = nil; +} + + - (void)_onqueueInitializeZone { + if(!SecCKKSIsEnabled()) { + ckksnotice("ckks", self, "Skipping CloudKit initialization due to disabled CKKS"); + return; + } + + dispatch_assert_queue(self.queue); + + __weak __typeof(self) weakSelf = self; + + NSBlockOperation* afterZoneSetup = [NSBlockOperation blockOperationWithBlock: ^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + return; + } + + __block bool quit = false; + + [strongSelf dispatchSync: ^bool { + ckksnotice("ckks", strongSelf, "Zone setup progress: %@ %d %@ %d %@", + [CKKSCKAccountStateTracker stringFromAccountStatus:strongSelf.accountStatus], + strongSelf.zoneCreated, strongSelf.zoneCreatedError, strongSelf.zoneSubscribed, strongSelf.zoneSubscribedError); + + NSError* error = nil; + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: strongSelf.zoneName]; + ckse.ckzonecreated = strongSelf.zoneCreated; + ckse.ckzonesubscribed = strongSelf.zoneSubscribed; + + // Although, if the zone subscribed error says there's no zone, mark down that there's no zone + if(strongSelf.zoneSubscribedError && + [strongSelf.zoneSubscribedError.domain isEqualToString:CKErrorDomain] && strongSelf.zoneSubscribedError.code == CKErrorPartialFailure) { + NSError* subscriptionError = strongSelf.zoneSubscribedError.userInfo[CKPartialErrorsByItemIDKey][strongSelf.zoneID]; + if(subscriptionError && [subscriptionError.domain isEqualToString:CKErrorDomain] && subscriptionError.code == CKErrorZoneNotFound) { + + ckkserror("ckks", strongSelf, "zone subscription error appears to say the zone doesn't exist, fixing status: %@", strongSelf.zoneSubscribedError); + ckse.ckzonecreated = false; + } + } + + [ckse saveToDatabase: &error]; + if(error) { + ckkserror("ckks", strongSelf, "couldn't save zone creation status for %@: %@", strongSelf.zoneName, error); + } + + if(!strongSelf.zoneCreated || !strongSelf.zoneSubscribed || strongSelf.accountStatus != CKAccountStatusAvailable) { + // Something has gone very wrong. Error out and maybe retry. + quit = true; + + // Note that CKKSZone has probably called [handleLogout]; which means we have a key hierarchy reset queued up. Error here anyway. + NSError* realReason = strongSelf.zoneCreatedError ? strongSelf.zoneCreatedError : strongSelf.zoneSubscribedError; + [strongSelf _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: realReason]; + + // We're supposed to be up, but something has gone wrong. Blindly retry until it works. + if(strongSelf.accountStatus == CKKSAccountStatusAvailable) { + [strongSelf.initializeScheduler trigger]; + ckksnotice("ckks", strongSelf, "We're logged in, but setup didn't work. Scheduling retry for %@", strongSelf.initializeScheduler.nextFireTime); + } + return true; + } else { + strongSelf.setupSuccessful = true; + } + + return true; + }]; + + if(quit) { + ckkserror("ckks", strongSelf, "Quitting setup."); + return; + } + + // We can't enter the account queue until an account exists. Before this point, we don't know if one does. + [strongSelf dispatchSyncWithAccountQueue: ^bool{ + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: strongSelf.zoneName]; + + // Check if we believe we've synced this zone before. + if(ckse.changeToken == nil) { + strongSelf.keyHierarchyOperationGroup = [CKOperationGroup CKKSGroupWithName:@"initial-setup"]; + + ckksnotice("ckks", strongSelf, "No existing change token; going to try to match local items with CloudKit ones."); + + // 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 = [strongSelf.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseInitialStart]; + fetch.name = @"initial-fetch"; + + // Next, try to process them (replacing local entries) + CKKSIncomingQueueOperation* initialProcess = [strongSelf processIncomingQueue: true after: fetch ]; + initialProcess.name = @"initial-process-incoming-queue"; + + // If all that succeeds, iterate through all keychain items and find the ones which need to be uploaded + strongSelf.initialScanOperation = [[CKKSScanLocalItemsOperation alloc] initWithCKKSKeychainView:strongSelf ckoperationGroup:strongSelf.keyHierarchyOperationGroup]; + strongSelf.initialScanOperation.name = @"initial-scan-operation"; + [strongSelf.initialScanOperation addNullableDependency:strongSelf.lockStateTracker.unlockDependency]; + [strongSelf.initialScanOperation addDependency: initialProcess]; + [strongSelf scheduleOperation: strongSelf.initialScanOperation]; + + } else { + // Likely a restart of securityd! + + strongSelf.keyHierarchyOperationGroup = [CKOperationGroup CKKSGroupWithName:@"restart-setup"]; + + if ([CKKSManifest shouldSyncManifests]) { + strongSelf.egoManifest = [CKKSEgoManifest tryCurrentEgoManifestForZone:strongSelf.zoneName]; + } + + // If it's been more than 24 hours since the last fetch, fetch and process everything. + // Otherwise, just kick off the local queue processing. + + NSDate* now = [NSDate date]; + NSDateComponents* offset = [[NSDateComponents alloc] init]; + [offset setHour:-24]; + NSDate* deadline = [[NSCalendar currentCalendar] dateByAddingComponents:offset toDate:now options:0]; + + NSOperation* initialProcess = nil; + if(ckse.lastFetchTime == nil || [ckse.lastFetchTime compare: deadline] == NSOrderedAscending) { + initialProcess = [strongSelf fetchAndProcessCKChanges:CKKSFetchBecauseSecuritydRestart]; + } else { + initialProcess = [strongSelf processIncomingQueue:false]; + } + + if(!strongSelf.egoManifest) { + ckksnotice("ckksmanifest", strongSelf, "No ego manifest on restart; rescanning"); + strongSelf.initialScanOperation = [[CKKSScanLocalItemsOperation alloc] initWithCKKSKeychainView:strongSelf ckoperationGroup:strongSelf.keyHierarchyOperationGroup]; + strongSelf.initialScanOperation.name = @"initial-scan-operation"; + [strongSelf.initialScanOperation addNullableDependency:strongSelf.lockStateTracker.unlockDependency]; + [strongSelf.initialScanOperation addDependency: initialProcess]; + [strongSelf scheduleOperation: strongSelf.initialScanOperation]; + } + + [strongSelf processOutgoingQueue:strongSelf.keyHierarchyOperationGroup]; + } + + // Tell the key state machine to fire off. + [strongSelf _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateInitialized withError: nil]; + return true; + }]; + }]; + afterZoneSetup.name = @"view-setup"; + + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName]; + NSOperation* zoneSetupOperation = [self createSetupOperation: ckse.ckzonecreated zoneSubscribed: ckse.ckzonesubscribed]; + + self.viewSetupOperation = [[CKKSGroupOperation alloc] init]; + self.viewSetupOperation.name = @"view-setup-group"; + if(!zoneSetupOperation.isFinished) { + [self.viewSetupOperation runBeforeGroupFinished: zoneSetupOperation]; + } + + [afterZoneSetup addDependency: zoneSetupOperation]; + [self.viewSetupOperation runBeforeGroupFinished: afterZoneSetup]; + + [self scheduleAccountStatusOperation: self.viewSetupOperation]; +} + +- (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; + } + } + + [CKKSCurrentKeyPointer deleteAll:self.zoneID error: &localerror]; + if(localerror) { + ckkserror("ckks", self, "couldn't delete all CKKSCurrentKeyPointer: %@", 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; + } + } + + [self _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateInitializing withError:nil]; + + return (localerror == nil && !setError); +} + +- (CKKSResultOperation*)resetLocalData { + __weak __typeof(self) weakSelf = self; + + CKKSGroupOperation* resetFollowUp = [[CKKSGroupOperation alloc] init]; + resetFollowUp.name = @"local-reset-follow-up-group"; + __weak __typeof(resetFollowUp) weakResetFollowUp = resetFollowUp; + + CKKSResultOperation* op = [[CKKSResultOperation alloc] init]; + op.name = @"local-reset"; + + __weak __typeof(op) weakOp = op; + [op addExecutionBlock:^{ + __strong __typeof(self) strongSelf = weakSelf; + __strong __typeof(op) strongOp = weakOp; + __strong __typeof(resetFollowUp) strongResetFollowUp = weakResetFollowUp; + if(!strongSelf || !strongOp || !strongResetFollowUp) { + return; + } + + __block NSError* error = nil; + + [strongSelf dispatchSync: ^bool{ + [self _onqueueResetLocalData: &error]; + return true; + }]; + + [strongSelf resetSetup]; + + if(error) { + ckksnotice("ckksreset", strongSelf, "Local reset finished with error %@", error); + strongOp.error = error; + } else { + if(strongSelf.accountStatus == CKKSAccountStatusAvailable) { + // Since we're logged in, we expect a reset to fix up the key hierarchy + ckksnotice("ckksreset", strongSelf, "logged in; re-initializing zone"); + [strongSelf initializeZone]; + + ckksnotice("ckksreset", strongSelf, "waiting for key hierarchy to become ready"); + CKKSResultOperation* waitOp = [CKKSResultOperation named:@"waiting-for-key-hierarchy" withBlock:^{}]; + [waitOp timeout: 60*NSEC_PER_SEC]; + [waitOp addNullableDependency:strongSelf.keyStateReadyDependency]; + + [strongResetFollowUp runBeforeGroupFinished:waitOp]; + } else { + ckksnotice("ckksreset", strongSelf, "logged out; not initializing zone"); + } + } + }]; + + [resetFollowUp runBeforeGroupFinished:op]; + [self scheduleOperationWithoutDependencies:resetFollowUp]; + return resetFollowUp; +} + +- (CKKSResultOperation*)resetCloudKitZone { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckks", self, "Skipping CloudKit reset due to disabled CKKS"); + return nil; + } + + CKKSResultOperation* reset = [super beginResetCloudKitZoneOperation]; + + __weak __typeof(self) weakSelf = self; + CKKSGroupOperation* resetFollowUp = [[CKKSGroupOperation alloc] init]; + resetFollowUp.name = @"cloudkit-reset-follow-up-group"; + + __weak __typeof(resetFollowUp) weakResetFollowUp = resetFollowUp; + [resetFollowUp runBeforeGroupFinished: [CKKSResultOperation named:@"cloudkit-reset-follow-up" withBlock: ^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + return; + } + __strong __typeof(resetFollowUp) strongResetFollowUp = weakResetFollowUp; + + if(!reset.error) { + ckksnotice("ckks", strongSelf, "Successfully deleted zone %@", strongSelf.zoneName); + __block NSError* error = nil; + + [strongSelf dispatchSync: ^bool{ + [strongSelf _onqueueResetLocalData: &error]; + strongSelf.setupSuccessful = false; + return true; + }]; + + if(strongSelf.accountStatus == CKKSAccountStatusAvailable) { + // Since we're logged in, we expect a reset to fix up the key hierarchy + ckksnotice("ckksreset", strongSelf, "re-initializing zone"); + [strongSelf initializeZone]; + + ckksnotice("ckksreset", strongSelf, "waiting for key hierarchy to become ready"); + CKKSResultOperation* waitOp = [CKKSResultOperation named:@"waiting-for-reset" withBlock:^{}]; + [waitOp timeout: 60*NSEC_PER_SEC]; + [waitOp addNullableDependency:strongSelf.keyStateReadyDependency]; + + [strongResetFollowUp runBeforeGroupFinished:waitOp]; + } else { + ckksnotice("ckksreset", strongSelf, "logged out; not initializing zone"); + } + } else { + // Shouldn't ever happen, since reset is a successDependency + ckkserror("ckks", strongSelf, "Couldn't reset zone %@: %@", strongSelf.zoneName, reset.error); + } + }]]; + + [resetFollowUp addSuccessDependency:reset]; + [self scheduleOperationWithoutDependencies:resetFollowUp]; + return resetFollowUp; +} + +- (void)advanceKeyStateMachine { + __weak __typeof(self) weakSelf = self; + + [self dispatchAsync: ^bool{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + false; + } + + [strongSelf _onqueueAdvanceKeyStateMachineToState: nil withError: nil]; + return true; + }]; +}; + +- (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]; +} + +- (void)_onqueueKeyStateMachineRequestFullRefetch { + dispatch_assert_queue(self.queue); + + self.keyStateFullRefetchRequested = true; + [self _onqueueAdvanceKeyStateMachineToState: nil withError: nil]; +} + +- (void)keyStateMachineRequestProcess { + __weak __typeof(self) weakSelf = self; + [self dispatchAsync: ^bool{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + return false; + } + + [strongSelf _onqueueKeyStateMachineRequestProcess]; + return true; + }]; +} + +- (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 fetch. If there was an active process, this flag will stay high + // and the fetch will be launched later. + + self.keyStateProcessRequested = true; + [self _onqueueAdvanceKeyStateMachineToState: nil withError: nil]; +} + +// 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 { + dispatch_assert_queue(self.queue); + __weak __typeof(self) weakSelf = self; + + // Resetting back to 'initializing' takes all precedence. + if([state isEqual: SecCKKSZoneKeyStateInitializing]) { + ckksnotice("ckkskey", self, "Resetting the key hierarchy state machine back to 'initializing'"); + + [self.keyStateMachineOperation cancel]; + self.keyStateMachineOperation = nil; + + self.keyHierarchyState = SecCKKSZoneKeyStateInitializing; + self.keyHierarchyError = nil; + self.keyStateFetchRequested = false; + self.keyStateProcessRequested = false; + + self.keyHierarchyOperationGroup = [CKOperationGroup CKKSGroupWithName:@"key-state-reset"]; + self.keyStateReadyDependency = [CKKSResultOperation operationWithBlock:^{ + ckksnotice("ckkskey", weakSelf, "Key state has become ready for the first time (after reset)."); + }]; + self.keyStateReadyDependency.name = [NSString stringWithFormat: @"%@-key-state-ready", self.zoneName]; + return; + } + + // 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 %@: %@", self.keyHierarchyState, self.keyHierarchyError); + return; + } + + if(error != nil || [state isEqual: SecCKKSZoneKeyStateError]) { + // But wait! Is this a "we're locked" error? + if([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:^{ + __strong __typeof(self) strongSelf = weakSelf; + if(!strongSelf) { + return; + } + [strongSelf dispatchSync:^bool{ + [strongSelf _onqueueAdvanceKeyStateMachineToState:lastState withError:nil]; + return true; + }]; + }]; + state = nil; + [self.keyStateMachineOperation addNullableDependency:self.lockStateTracker.unlockDependency]; + [self scheduleOperation:self.keyStateMachineOperation]; + + } else { + // Error state: record the error and exit early + ckkserror("ckkskey", self, "advised of error: coming from state (%@): %@", self.keyHierarchyState, error); + self.keyHierarchyState = SecCKKSZoneKeyStateError; + self.keyHierarchyError = error; + return; + } + } + + if([state isEqual: SecCKKSZoneKeyStateCancelled]) { + ckkserror("ckkskey", self, "advised of cancel: coming from state (%@): %@", self.keyHierarchyState, error); + self.keyHierarchyState = SecCKKSZoneKeyStateCancelled; + self.keyHierarchyError = error; + + // 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; + return; + } + + // 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(state) { + self.keyStateMachineOperation = nil; + + ckksnotice("ckkskey", self, "Advancing key hierarchy state machine from %@ to %@", self.keyHierarchyState, state); + self.keyHierarchyState = state; + } + + // Many of our decisions below will be based on what keys exist. Help them out. + CKKSCurrentKeySet* keyset = [[CKKSCurrentKeySet alloc] initForZone:self.zoneID]; + NSError* localerror = nil; + NSArray* localKeys = [CKKSKey localKeys:self.zoneID error:&localerror]; + NSArray* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror]; + + // We also are checking for OutgoingQueueEntries in the reencrypt state; this is a sign that our key hierarchy is out of date. + NSArray* outdatedOQEs = [CKKSOutgoingQueueEntry allInState: SecCKKSStateReencrypt zoneID:self.zoneID error: &localerror]; + + SecADSetValueForScalarKey((__bridge CFStringRef) SecCKKSAggdViewKeyCount, [localKeys count]); + + if(localerror) { + ckkserror("ckkskey", self, "couldn't fetch keys and OQEs from local database, entering error state: %@", localerror); + self.keyHierarchyState = SecCKKSZoneKeyStateError; + self.keyHierarchyError = localerror; + return; + } + +#if !defined(NDEBUG) + NSArray* allKeys = [CKKSKey allKeys:self.zoneID error:&localerror]; + ckksdebug("ckkskey", self, "All keys: %@", allKeys); +#endif + + NSError* hierarchyError = nil; + + if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateInitializing]) { + if(state != nil) { + // Wait for CKKSZone to finish initialization. + ckkserror("ckkskey", self, "Asked to advance state machine (to %@) while CK zone still initializing.", state); + } + return; + + } else if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateReady]) { + 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]); + [self _onqueueKeyHierarchyProcess]; + + } else if(self.keyStateFullRefetchRequested) { + // In ready, but someone has requested a full fetch. Kick it off. + ckksnotice("ckkskey", self, "Kicking off a key refetch based on request:%d", self.keyStateFetchRequested); + [self _onqueueKeyHierarchyRefetch]; + + } 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); + [self _onqueueKeyHierarchyFetch]; + } + // TODO: kick off a key roll if one has been requested + + if(!self.keyStateMachineOperation) { + // We think we're ready. Double check. + bool ready = [self _onqueueEnsureKeyHierarchyHealth:&hierarchyError]; + if(!ready || hierarchyError) { + // Things is bad. Kick off a heal to fix things up. + ckksnotice("ckkskey", self, "Thought we were ready, but the key hierarchy is unhealthy: %@", hierarchyError); + self.keyHierarchyState = SecCKKSZoneKeyStateUnhealthy; + + } else { + // In ready, nothing to do. Notify waiters and quit. + self.keyHierarchyOperationGroup = nil; + 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 + if([outdatedOQEs count] > 0u) { + ckksnotice("ckksreencrypt", self, "Reencrypting outgoing items as the key hierarchy is ready"); + CKKSReencryptOutgoingItemsOperation* op = [[CKKSReencryptOutgoingItemsOperation alloc] initWithCKKSKeychainView:self ckoperationGroup:self.keyHierarchyOperationGroup]; + [self scheduleOperation:op]; + } + + return; + } + } + + } else if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateInitialized]) { + // We're initialized and CloudKit is ready. See what needs done... + + // Check if we have an existing key hierarchy + CKKSKey* tlk = [CKKSKey currentKeyForClass:SecCKKSKeyClassTLK zoneID:self.zoneID error:&error]; + CKKSKey* classA = [CKKSKey currentKeyForClass:SecCKKSKeyClassA zoneID:self.zoneID error:&error]; + CKKSKey* classC = [CKKSKey currentKeyForClass:SecCKKSKeyClassC zoneID:self.zoneID error:&error]; + + if(error && !([error.domain isEqual: @"securityd"] && error.code == errSecItemNotFound)) { + ckkserror("ckkskey", self, "Error examining existing key hierarchy: %@", error); + } + + if(tlk && classA && classC && !error) { + // This is likely a restart of securityd, and we think we're ready. Double check. + bool ready = [self _onqueueEnsureKeyHierarchyHealth:&hierarchyError]; + if(ready && !hierarchyError) { + ckksnotice("ckkskey", self, "Already have existing key hierarchy for %@; using it.", self.zoneID.zoneName); + } else if(hierarchyError && [self.lockStateTracker isLockedError:hierarchyError]) { + ckksnotice("ckkskey", self, "Initial scan shows key hierarchy is unavailable since keychain is locked: %@", hierarchyError); + self.keyHierarchyState = SecCKKSZoneKeyStateWaitForUnlock; + } else { + ckksnotice("ckkskey", self, "Initial scan shows key hierarchy is unhealthy: %@", hierarchyError); + self.keyHierarchyState = SecCKKSZoneKeyStateUnhealthy; + } + + } 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); + + [self _onqueueKeyHierarchyFetch]; + } + + } else if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateFetchComplete]) { + // We're initializing this zone, and just completed a fetch of everything. Are there any remote keys? + if(remoteKeys.count > 0u) { + // Process the keys we received. + self.keyStateMachineOperation = [[CKKSProcessReceivedKeysOperation 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'"); + self.keyHierarchyState = SecCKKSZoneKeyStateUnhealthy; + + } else if([remoteKeys count] == 0) { + // No keys, no pointers? make some new ones! + self.keyStateMachineOperation = [[CKKSNewTLKOperation alloc] initWithCKKSKeychainView: self ckoperationGroup:self.keyHierarchyOperationGroup]; + } + + } else if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateWaitForTLK]) { + // We're in a hold state: waiting for the TLK bytes to arrive. + + if(self.keyStateProcessRequested) { + // Someone has requsted a reprocess! Run a ProcessReceivedKeysOperation. + ckksnotice("ckkskey", self, "Received a nudge that our TLK might be here! Starting operation to check."); + [self _onqueueKeyHierarchyProcess]; + } + + } else if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateWaitForUnlock]) { + // We're in a hold state: waiting for the keybag to unlock so we can process the keys again. + + [self _onqueueKeyHierarchyProcess]; + [self.keyStateMachineOperation addNullableDependency: self.lockStateTracker.unlockDependency]; + + } else if([self.keyHierarchyState 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]; + + } else if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateNewTLKsFailed]) { + ckksnotice("ckkskey", self, "Creating new TLKs didn't work. Attempting to refetch!"); + [self _onqueueKeyHierarchyFetch]; + + } else if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateNeedFullRefetch]) { + ckksnotice("ckkskey", self, "Informed of request for full refetch"); + [self _onqueueKeyHierarchyRefetch]; + + } else { + ckkserror("ckks", self, "asked to advance state machine to unknown state: %@", self.keyHierarchyState); + return; + } + + if(self.keyStateMachineOperation) { + + if(self.keyStateReadyDependency == nil || [self.keyStateReadyDependency isFinished]) { + ckksnotice("ckkskey", self, "reloading keyStateReadyDependency due to operation %@", self.keyStateMachineOperation); + + __weak __typeof(self) weakSelf = self; + self.keyHierarchyOperationGroup = [CKOperationGroup CKKSGroupWithName:@"key-state-broken"]; + self.keyStateReadyDependency = [CKKSResultOperation operationWithBlock:^{ + ckksnotice("ckkskey", weakSelf, "Key state has become ready again."); + }]; + self.keyStateReadyDependency.name = [NSString stringWithFormat: @"%@-key-state-ready", self.zoneName]; + } + + [self scheduleOperation: self.keyStateMachineOperation]; + } else if([self.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLK]) { + ckksnotice("ckkskey", self, "Entering %@", self.keyHierarchyState); + + } else if([self.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateUnhealthy]) { + ckksnotice("ckkskey", self, "Looks like the key hierarchy is unhealthy. Launching fix."); + self.keyStateMachineOperation = [[CKKSHealKeyHierarchyOperation alloc] initWithCKKSKeychainView:self ckoperationGroup:self.keyHierarchyOperationGroup]; + [self scheduleOperation: self.keyStateMachineOperation]; + + } else { + // Nothing to do and not in a waiting state? Awesome; we must be in the ready state. + if(![self.keyHierarchyState isEqual: SecCKKSZoneKeyStateReady]) { + ckksnotice("ckkskey", self, "No action to take in state %@; we must be ready.", self.keyHierarchyState); + self.keyHierarchyState = SecCKKSZoneKeyStateReady; + + self.keyHierarchyOperationGroup = nil; + if(self.keyStateReadyDependency) { + [self scheduleOperation: self.keyStateReadyDependency]; + self.keyStateReadyDependency = nil; + } + } + } +} + +- (bool)_onqueueEnsureKeyHierarchyHealth:(NSError* __autoreleasing *)error { + dispatch_assert_queue(self.queue); + + NSError* localerror = nil; + + // Check if we have an existing key hierarchy + CKKSKey* tlk = [CKKSKey currentKeyForClass:SecCKKSKeyClassTLK zoneID:self.zoneID error:&localerror]; + CKKSKey* classA = [CKKSKey currentKeyForClass:SecCKKSKeyClassA zoneID:self.zoneID error:&localerror]; + CKKSKey* classC = [CKKSKey currentKeyForClass:SecCKKSKeyClassC zoneID:self.zoneID error:&localerror]; + + if(localerror || !tlk || !classA || !classC) { + ckkserror("ckkskey", self, "Error examining existing key hierarchy: %@", localerror); + ckkserror("ckkskey", self, "Keys are: %@ %@ %@", tlk, classA, classC); + if(error) { + *error = localerror; + } + return false; + } + + // keychain being locked is not a fatal error here + [tlk loadKeyMaterialFromKeychain:&localerror]; + if(localerror && !([localerror.domain isEqual: @"securityd"] && localerror.code == errSecInteractionNotAllowed)) { + ckksinfo("ckkskey", self, "Error loading TLK(%@): %@", tlk, localerror); + if(error) { + *error = localerror; + } + return false; + } else if(localerror) { + ckksinfo("ckkskey", self, "Error loading TLK(%@), maybe locked: %@", tlk, localerror); + } + localerror = nil; + + // keychain being locked is not a fatal error here + [classA loadKeyMaterialFromKeychain:&localerror]; + if(localerror && !([localerror.domain isEqual: @"securityd"] && localerror.code == errSecInteractionNotAllowed)) { + ckksinfo("ckkskey", self, "Error loading classA key(%@): %@", classA, localerror); + if(error) { + *error = localerror; + } + return false; + } else if(localerror) { + ckksinfo("ckkskey", self, "Error loading classA key(%@), maybe locked: %@", classA, localerror); + } + localerror = nil; + + // keychain being locked is a fatal error here, since this is class C + [classA loadKeyMaterialFromKeychain:&localerror]; + if(localerror) { + ckksinfo("ckkskey", self, "Error loading classC(%@): %@", classC, localerror); + if(error) { + *error = localerror; + } + return false; + } + + self.activeTLK = [tlk uuid]; + + // Got to the bottom? Cool! All keys are present and accounted for. + return true; +} + +- (void)_onqueueKeyHierarchyFetch { + dispatch_assert_queue(self.queue); + + __weak __typeof(self) weakSelf = self; + self.keyStateMachineOperation = [NSBlockOperation blockOperationWithBlock: ^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + return; + } + + [strongSelf dispatchSync: ^bool{ + [strongSelf _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateFetchComplete withError: nil]; + return true; + }]; + }]; + self.keyStateMachineOperation.name = @"waiting-for-fetch"; + + NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetch: CKKSFetchBecauseKeyHierarchy]; + [self.keyStateMachineOperation addDependency: fetchOp]; + + self.keyStateFetchRequested = false; +} + +- (void)_onqueueKeyHierarchyRefetch { + dispatch_assert_queue(self.queue); + + __weak __typeof(self) weakSelf = self; + self.keyStateMachineOperation = [NSBlockOperation blockOperationWithBlock: ^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + return; + } + + [strongSelf dispatchSync: ^bool{ + [strongSelf _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateFetchComplete withError: nil]; + return true; + }]; + }]; + self.keyStateMachineOperation.name = @"waiting-for-refetch"; + + NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulResyncFetch: CKKSFetchBecauseKeyHierarchy]; + [self.keyStateMachineOperation addDependency: fetchOp]; + + self.keyStateMachineRefetched = true; + self.keyStateFullRefetchRequested = false; + self.keyStateFetchRequested = false; +} + + +- (void)_onqueueKeyHierarchyProcess { + dispatch_assert_queue(self.queue); + + self.keyStateMachineOperation = [[CKKSProcessReceivedKeysOperation alloc] initWithCKKSKeychainView: self]; + + // Since we're starting a reprocess, this is answering all previous requests. + self.keyStateProcessRequested = false; +} + +- (void) handleKeychainEventDbConnection: (SecDbConnectionRef) dbconn + added: (SecDbItemRef) added + deleted: (SecDbItemRef) deleted + rateLimiter: (CKKSRateLimiter*) rateLimiter + syncCallback: (SecBoolNSErrorCallback) syncCallback { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckks", self, "Skipping handleKeychainEventDbConnection due to disabled CKKS"); + return; + } + + __block NSError* error = nil; + + if(self.accountStatus != CKKSAccountStatusAvailable && syncCallback) { + // We're not logged into CloudKit, and therefore don't expect this item to be synced anytime particularly soon. + CKKSAccountStatus accountStatus = self.accountStatus; + dispatch_async(self.queue, ^{ + syncCallback(false, [NSError errorWithDomain:@"securityd" + code:errSecNotLoggedIn + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat: @"No iCloud account available(%d); item is not expected to sync", (int)accountStatus]}]); + }); + + syncCallback = nil; + } + + // Tombstones come in as item modifications or item adds. Handle modifications here. + bool addedTombstone = added && SecDbItemIsTombstone(added); + bool deletedTombstone = deleted && SecDbItemIsTombstone(deleted); + + bool addedSync = added && SecDbItemIsSyncable(added); + bool deletedSync = deleted && SecDbItemIsSyncable(deleted); + + 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); + + // On an update that changes an item's primary key, SecDb modifies the existing item, then adds a new tombstone to replace the old primary key. + // Therefore, we might receive an added tombstone here with no deleted item to accompany it. This should be considered a deletion. + if(addedTombstone && !deleted) { + isAdd = false; + isDelete = true; + isModify = false; + + // Passed to withItem: below + deleted = added; + } + + // If neither item is syncable, don't proceed further in the syncing system + bool proceed = addedSync || deletedSync; + + if(!proceed) { + ckksinfo("ckks", self, "skipping sync of non-sync item"); + return; + } + + // Only synchronize items which can transfer between devices + NSString* protection = (__bridge NSString*)SecDbItemGetCachedValueWithName(added ? added : deleted, kSecAttrAccessible); + if(! ([protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleWhenUnlocked] || + [protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleAfterFirstUnlock] || + [protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleAlways])) { + ckksinfo("ckks", self, "skipping sync of device-bound item"); + return; + } + + // 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 { + if(![self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateReady]) { + ckksnotice("ckks", self, "Key state not ready for new items; skipping"); + return true; + } + + CKKSOutgoingQueueEntry* oqe = nil; + if (isAdd) { + oqe = [CKKSOutgoingQueueEntry withItem: added action: SecCKKSActionAdd ckks:self error: &error]; + } else if(isDelete) { + oqe = [CKKSOutgoingQueueEntry withItem: deleted action: SecCKKSActionDelete ckks:self error: &error]; + } else if(isModify) { + oqe = [CKKSOutgoingQueueEntry withItem: added action: SecCKKSActionModify ckks:self error: &error]; + } else { + ckkserror("ckks", self, "processKeychainEventItemAdded given garbage: %@ %@", added, deleted); + return true; + } + + CKOperationGroup* operationGroup = [CKOperationGroup CKKSGroupWithName:@"keychain-api-use"]; + + if(error) { + ckkserror("ckks", self, "Couldn't create outgoing queue entry: %@", error); + + // 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:@"securityd"] && error.code == CKKSNoUUIDOnItem) { + ckksnotice("ckks", self, "Launching scan operation"); + CKKSScanLocalItemsOperation* scanOperation = [[CKKSScanLocalItemsOperation alloc] initWithCKKSKeychainView: self ckoperationGroup:operationGroup]; + [self scheduleOperation: scanOperation]; + } + + // If the problem is 'couldn't load key', tell the key hierarchy state machine to fix it + // Then, launch a scan operation to find this item and upload it + if([error.domain isEqualToString:@"securityd"] && error.code == errSecItemNotFound) { + [self _onqueueAdvanceKeyStateMachineToState: nil withError: nil]; + + ckksnotice("ckks", self, "Launching scan operation to refind %@", added); + CKKSScanLocalItemsOperation* scanOperation = [[CKKSScanLocalItemsOperation alloc] initWithCKKSKeychainView: self ckoperationGroup:operationGroup]; + [scanOperation addNullableDependency:self.keyStateReadyDependency]; + [self scheduleOperation: scanOperation]; + } + + return true; + } + + if(rateLimiter) { + NSDate* limit = nil; + NSInteger value = [rateLimiter judge:oqe at:[NSDate date] limitTime:&limit]; + if(limit) { + oqe.waitUntil = limit; + SecPLLogRegisteredEvent(@"CKKSSyncing", @{ @"ratelimit" : @(value), @"accessgroup" : oqe.accessgroup}); + } + } + + [oqe saveToDatabaseWithConnection: dbconn error: &error]; + if(error) { + ckkserror("ckks", self, "Couldn't save outgoing queue entry to database: %@", error); + return true; + } + + // 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]; + if(error) { + ckkserror("ckks", self, "Couldn't load reencrypt OQE sibling for %@: %@", oqe, error); + } + if(reencryptOQE) { + [reencryptOQE deleteFromDatabase:&error]; + if(error) { + ckkserror("ckks", self, "Couldn't delete reencrypt OQE sibling(%@) for %@: %@", reencryptOQE, oqe, error); + } + 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); + } + } + + if(syncCallback) { + self.pendingSyncCallbacks[oqe.uuid] = syncCallback; + } + + // Schedule a "view changed" notification + [self.notifyViewChangedScheduler trigger]; + + [self processOutgoingQueue:operationGroup]; + + return true; + }]; +} + +-(void)setCurrentItemForAccessGroup:(SecDbItemRef)newItem + hash:(NSData*)newItemSHA1 + accessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + replacing:(SecDbItemRef)oldItem + hash:(NSData*)oldItemSHA1 + complete:(void (^) (NSError* operror)) complete +{ + if(accessGroup == nil || identifier == nil) { + NSError* error = [NSError errorWithDomain:@"securityd" code:errSecParam userInfo:@{NSLocalizedDescriptionKey: @"No access group or identifier given"}]; + ckkserror("ckkscurrent", self, "Cancelling request: %@", error); + complete(error); + return; + } + + __weak __typeof(self) weakSelf = self; + + [self dispatchSync:^bool { + NSError* error = nil; + CFErrorRef cferror = NULL; + + NSString* newItemUUID = nil; + NSString* oldItemUUID = nil; + + // Now that we're on the db queue, ensure that the given hashes for the items match the hashes as they are now. + // That is, the items haven't changed since the caller knew about the item. + NSData* newItemComputedSHA1 = (NSData*) CFBridgingRelease(CFRetainSafe(SecDbItemGetSHA1(newItem, &cferror))); + if(!newItemComputedSHA1 || cferror || + ![newItemComputedSHA1 isEqual:newItemSHA1]) { + ckksnotice("ckkscurrent", self, "Hash mismatch for new item: %@ vs %@", newItemComputedSHA1, newItemSHA1); + error = [NSError errorWithDomain:@"securityd" code:errSecItemInvalidValue userInfo:@{NSLocalizedDescriptionKey: @"New item has changed; hashes mismatch. Refetch and try again."}]; + complete(error); + CFReleaseNull(cferror); + return false; + } + + newItemUUID = (NSString*) CFBridgingRelease(CFRetainSafe(SecDbItemGetValue(newItem, &v10itemuuid, &cferror))); + if(!newItemUUID || cferror) { + ckkserror("ckkscurrent", self, "Error fetching UUID for new item: %@", cferror); + complete((__bridge NSError*) cferror); + CFReleaseNull(cferror); + return false; + } + + if(oldItem) { + NSData* oldItemComputedSHA1 = (NSData*) CFBridgingRelease(CFRetainSafe(SecDbItemGetSHA1(oldItem, &cferror))); + if(!oldItemComputedSHA1 || cferror || + ![oldItemComputedSHA1 isEqual:oldItemSHA1]) { + ckksnotice("ckkscurrent", self, "Hash mismatch for old item: %@ vs %@", oldItemComputedSHA1, oldItemSHA1); + error = [NSError errorWithDomain:@"securityd" code:errSecItemInvalidValue userInfo:@{NSLocalizedDescriptionKey: @"Old item has changed; hashes mismatch. Refetch and try again."}]; + complete(error); + CFReleaseNull(cferror); + return false; + } + + oldItemUUID = (NSString*) CFBridgingRelease(CFRetainSafe(SecDbItemGetValue(oldItem, &v10itemuuid, &cferror))); + if(!oldItemUUID || cferror) { + ckkserror("ckkscurrent", self, "Error fetching UUID for old item: %@", cferror); + complete((__bridge NSError*) cferror); + CFReleaseNull(cferror); + return false; + } + } + + // Not being in a CloudKit account is an automatic failure. + if(self.accountStatus != CKKSAccountStatusAvailable) { + ckksnotice("ckkscurrent", self, "Rejecting current item pointer set since we don't have an iCloud account."); + error = [NSError errorWithDomain:@"securityd" code:errSecNotLoggedIn userInfo:@{NSLocalizedDescriptionKey: @"User is not signed into iCloud."}]; + complete(error); + return false; + } + + // At this point, we've completed all the checks we need for the SecDbItems. Try to launch this boat! + NSString* currentIdentifier = [NSString stringWithFormat:@"%@-%@", accessGroup, identifier]; + ckksnotice("ckkscurrent", self, "Setting current pointer for %@ to %@ (from %@)", currentIdentifier, newItemUUID, oldItemUUID); + CKKSUpdateCurrentItemPointerOperation* ucipo = [[CKKSUpdateCurrentItemPointerOperation alloc] initWithCKKSKeychainView:self + currentPointer:(NSString*)currentIdentifier + oldItemUUID:(NSString*)oldItemUUID + newItemUUID:(NSString*)newItemUUID + ckoperationGroup:[CKOperationGroup CKKSGroupWithName:@"currentitem-api"]]; + CKKSResultOperation* returnCallback = [CKKSResultOperation operationWithBlock:^{ + __strong __typeof(self) strongSelf = weakSelf; + + if(ucipo.error) { + ckkserror("ckkscurrent", strongSelf, "Failed setting a current item pointer with %@", ucipo.error); + } else { + ckksnotice("ckkscurrent", strongSelf, "Finished setting a current item pointer"); + } + complete(ucipo.error); + }]; + returnCallback.name = @"setCurrentItem-return-callback"; + [returnCallback addDependency: ucipo]; + [self scheduleOperation: returnCallback]; + + // Now, schedule ucipo. It modifies the CloudKit zone, so it should insert itself into the list of OutgoingQueueOperations. + // Then, we won't have simultaneous zone-modifying operations. + [ucipo linearDependencies:self.outgoingQueueOperations]; + + // If this operation hasn't started within 60 seconds, cancel it and return a "timed out" error. + [ucipo timeout:60*NSEC_PER_SEC]; + + [self scheduleOperation:ucipo]; + return true; + }]; + return; +} + +-(void)getCurrentItemForAccessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + fetchCloudValue:(bool)fetchCloudValue + complete:(void (^) (NSString* uuid, NSError* operror)) complete +{ + if(accessGroup == nil || identifier == nil) { + complete(NULL, [NSError errorWithDomain:@"securityd" code:errSecParam userInfo:@{NSLocalizedDescriptionKey: @"No access group or identifier given"}]); + return; + } + + // Not being in a CloudKit account is an automatic failure. + if(self.accountStatus != CKKSAccountStatusAvailable) { + ckksnotice("ckkscurrent", self, "Rejecting current item pointer get since we don't have an iCloud account."); + complete(NULL, [NSError errorWithDomain:@"securityd" code:errSecNotLoggedIn userInfo:@{NSLocalizedDescriptionKey: @"User is not signed into iCloud."}]); + return; + } + + CKKSResultOperation* fetchAndProcess = nil; + if(fetchCloudValue) { + fetchAndProcess = [self fetchAndProcessCKChanges:CKKSFetchBecauseCurrentItemFetchRequest]; + } + + __weak __typeof(self) weakSelf = self; + CKKSResultOperation* getCurrentItem = [CKKSResultOperation operationWithBlock:^{ + if(fetchAndProcess.error) { + complete(NULL, fetchAndProcess.error); + return; + } + + __strong __typeof(self) strongSelf = weakSelf; + + [strongSelf dispatchSync: ^bool { + NSError* error = nil; + NSString* currentIdentifier = [NSString stringWithFormat:@"%@-%@", accessGroup, identifier]; + + CKKSCurrentItemPointer* cip = [CKKSCurrentItemPointer fromDatabase:currentIdentifier + state:SecCKKSProcessedStateLocal + zoneID:strongSelf.zoneID + error:&error]; + if(!cip || error) { + ckkserror("ckkscurrent", strongSelf, "No current item pointer for %@", currentIdentifier); + complete(nil, error); + return false; + } + + if(!cip.currentItemUUID) { + ckkserror("ckkscurrent", strongSelf, "Current item pointer is empty %@", cip); + complete(nil, [NSError errorWithDomain:@"securityd" + code:errSecInternalError + userInfo:@{NSLocalizedDescriptionKey: @"Current item pointer is empty"}]); + return false; + } + + complete(cip.currentItemUUID, NULL); + + return true; + }]; + }]; + getCurrentItem.name = @"get-current-item-pointer"; + + [getCurrentItem addNullableDependency:fetchAndProcess]; + [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*)kSecAttrAccessibleAlways] || + [protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleAfterFirstUnlock]) { + class = SecCKKSKeyClassC; + } else { + ckkserror("ckks", self, "can't pick key class for protection %@: %@", protection, item); + if(error) { + *error =[NSError errorWithDomain:@"securityd" + code:5 + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"can't pick key class for protection %@: %@", protection, item]}]; + } + + return nil; + } + + CKKSKey* key = [CKKSKey currentKeyForClass: class zoneID:self.zoneID error:error]; + + // and make sure it's unwrapped. + if(![key ensureKeyLoaded:error]) { + return nil; + } + + return key; +} + +// 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 find the first pending operation in a weak collection +- (NSOperation*)findFirstPendingOperation: (NSHashTable*) table ofClass:(Class)class { + @synchronized(table) { + for(NSOperation* op in table) { + if(op != nil && [op isPending] && (class == nil || [op isKindOfClass: class])) { + return op; + } + } + return 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 { + return [self processOutgoingQueueAfter:nil ckoperationGroup:ckoperationGroup]; +} + +- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation*)after ckoperationGroup:(CKOperationGroup*)ckoperationGroup { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckks", self, "Skipping processOutgoingQueue due to disabled CKKS"); + return nil; + } + + CKKSOutgoingQueueOperation* outgoingop = + (CKKSOutgoingQueueOperation*) [self findFirstPendingOperation:self.outgoingQueueOperations + ofClass:[CKKSOutgoingQueueOperation class]]; + if(outgoingop) { + ckksinfo("ckks", self, "Skipping processOutgoingQueue due to at least one pending instance"); + if(after) { + [outgoingop addDependency: after]; + } + if([outgoingop isPending]) { + if(!outgoingop.ckoperationGroup && ckoperationGroup) { + outgoingop.ckoperationGroup = ckoperationGroup; + } else if(ckoperationGroup) { + ckkserror("ckks", self, "Throwing away CKOperationGroup(%@) in favor of %@", ckoperationGroup, outgoingop.ckoperationGroup); + } + + return outgoingop; + } + } + + CKKSOutgoingQueueOperation* op = [[CKKSOutgoingQueueOperation alloc] initWithCKKSKeychainView:self ckoperationGroup:ckoperationGroup]; + op.name = @"outgoing-queue-operation"; + [op addNullableDependency:after]; + + [op addNullableDependency: self.initialScanOperation]; + + [self scheduleOperation: op]; + return op; +} + +- (void)processIncomingQueueAfterNextUnlock { + // Thread races aren't so important here; we might end up with two or three copies of this operation, but that's okay. + if(![self.processIncomingQueueAfterNextUnlockOperation isPending]) { + __weak __typeof(self) weakSelf = self; + + CKKSResultOperation* restartIncomingQueueOperation = [CKKSResultOperation operationWithBlock:^{ + __strong __typeof(self) strongSelf = weakSelf; + // This IQO shouldn't error if the keybag has locked again. It will simply try again later. + [strongSelf processIncomingQueue:false]; + }]; + + restartIncomingQueueOperation.name = @"reprocess-incoming-queue-after-unlock"; + self.processIncomingQueueAfterNextUnlockOperation = restartIncomingQueueOperation; + + [restartIncomingQueueOperation addNullableDependency:self.lockStateTracker.unlockDependency]; + [self scheduleOperation: restartIncomingQueueOperation]; + } +} + +- (CKKSIncomingQueueOperation*)processIncomingQueue:(bool)failOnClassA { + return [self processIncomingQueue:failOnClassA after: nil]; +} + +- (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA after: (CKKSResultOperation*) after { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckks", self, "Skipping processIncomingQueue due to disabled CKKS"); + return nil; + } + + CKKSIncomingQueueOperation* incomingop = (CKKSIncomingQueueOperation*) [self findFirstPendingOperation:self.incomingQueueOperations]; + if(incomingop) { + ckksinfo("ckks", self, "Skipping processIncomingQueue due to at least one pending instance"); + if(after) { + [incomingop addDependency: after]; + } + // check (again) for race condition; if the op has started we need to add another (for the dependency) + if([incomingop isPending]) { + incomingop.errorOnClassAFailure |= failOnClassA; + return incomingop; + } + } + + CKKSIncomingQueueOperation* op = [[CKKSIncomingQueueOperation alloc] initWithCKKSKeychainView:self errorOnClassAFailure:failOnClassA]; + op.name = @"incoming-queue-operation"; + if(after != nil) { + [op addSuccessDependency: after]; + } + + [self scheduleOperation: op]; + return op; +} + +- (CKKSUpdateDeviceStateOperation*)updateDeviceState:(bool)rateLimit ckoperationGroup:(CKOperationGroup*)ckoperationGroup { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckks", self, "Skipping updateDeviceState due to disabled CKKS"); + return nil; + } + + CKKSUpdateDeviceStateOperation* op = [[CKKSUpdateDeviceStateOperation alloc] initWithCKKSKeychainView:self rateLimit:rateLimit ckoperationGroup:ckoperationGroup]; + op.name = @"device-state-operation"; + + // 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. + [op linearDependencies:self.outgoingQueueOperations]; + + // CKKSUpdateDeviceStateOperations are special: they should fire even if we don't believe we're in an iCloud account. + [self scheduleAccountStatusOperation:op]; + return op; +} + +// 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 { + NSError* localerror = nil; + + CKKSCKAccountStateTracker* accountTracker = self.accountTracker; + + // We must have an iCloud account (with d2de on) to even create one of these + if(accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable || accountTracker.currentCKAccountInfo.supportsDeviceToDeviceEncryption != YES) { + ckkserror("ckksdevice", self, "No iCloud account active: %@", accountTracker.currentCKAccountInfo); + localerror = [NSError errorWithDomain:@"securityd" + code:errSecInternalError + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No active HSA2 iCloud account: %@", accountTracker.currentCKAccountInfo]}]; + if(error) { + *error = localerror; + } + return nil; + } + + CKKSDeviceStateEntry* oldcdse = [CKKSDeviceStateEntry tryFromDatabase:accountTracker.ckdeviceID zoneID:self.zoneID error:&localerror]; + if(localerror) { + ckkserror("ckksdevice", self, "Couldn't read old CKKSDeviceStateEntry from database: %@", localerror); + if(error) { + *error = localerror; + } + return nil; + } + + // Find out what we think the current keys are + CKKSCurrentKeyPointer* currentTLKPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassTLK zoneID:self.zoneID error:&localerror]; + CKKSCurrentKeyPointer* currentClassAPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassA zoneID:self.zoneID error:&localerror]; + CKKSCurrentKeyPointer* currentClassCPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassC zoneID:self.zoneID error:&localerror]; + if(localerror) { + // Things is broken, but the whole point of this record is to share the brokenness. Continue. + ckkserror("ckksdevice", self, "Couldn't read current key pointers from database: %@; proceeding", localerror); + localerror = nil; + } + + CKKSKey* suggestedTLK = currentTLKPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:currentTLKPointer.currentKeyUUID zoneID:self.zoneID error:&localerror] : nil; + CKKSKey* suggestedClassAKey = currentClassAPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:currentClassAPointer.currentKeyUUID zoneID:self.zoneID error:&localerror] : nil; + CKKSKey* suggestedClassCKey = currentClassCPointer.currentKeyUUID ? [CKKSKey tryFromDatabase:currentClassCPointer.currentKeyUUID zoneID:self.zoneID error:&localerror] : nil; + + if(localerror) { + // Things is broken, but the whole point of this record is to share the brokenness. Continue. + ckkserror("ckksdevice", self, "Couldn't read keys from database: %@; proceeding", localerror); + localerror = nil; + } + + // Check if we posess the keys in the keychain + [suggestedTLK ensureKeyLoaded:&localerror]; + if(localerror && [self.lockStateTracker isLockedError:localerror]) { + ckkserror("ckksdevice", self, "Device is locked; couldn't read TLK from keychain. Assuming it is present and continuing; error was %@", localerror); + localerror = nil; + } else if(localerror) { + ckkserror("ckksdevice", self, "Couldn't read TLK from keychain. We do not have a current TLK. Error was %@", localerror); + suggestedTLK = nil; + } + + [suggestedClassAKey ensureKeyLoaded:&localerror]; + if(localerror && [self.lockStateTracker isLockedError:localerror]) { + ckkserror("ckksdevice", self, "Device is locked; couldn't read ClassA key from keychain. Assuming it is present and continuing; error was %@", localerror); + localerror = nil; + } else if(localerror) { + ckkserror("ckksdevice", self, "Couldn't read ClassA key from keychain. We do not have a current ClassA key. Error was %@", localerror); + suggestedClassAKey = nil; + } + + [suggestedClassCKey ensureKeyLoaded:&localerror]; + // class C keys are stored class C, so uh, don't check lock state. + if(localerror) { + ckkserror("ckksdevice", self, "Couldn't read ClassC key from keychain. We do not have a current ClassC key. Error was %@", localerror); + suggestedClassCKey = nil; + } + + // We'd like to have the circle peer ID. Give the account state tracker a fighting chance, but not having it is not an error + if([accountTracker.accountCirclePeerIDInitialized wait:500*NSEC_PER_MSEC] != 0 && !accountTracker.accountCirclePeerID) { + ckkserror("ckksdevice", self, "No peer ID available"); + } + + // We only really want the oldcdse for its encodedCKRecord, so make a new cdse here + CKKSDeviceStateEntry* newcdse = [[CKKSDeviceStateEntry alloc] initForDevice:accountTracker.ckdeviceID + circlePeerID:accountTracker.accountCirclePeerID + circleStatus:accountTracker.currentCircleStatus + keyState:self.keyHierarchyState + currentTLKUUID:suggestedTLK.uuid + currentClassAUUID:suggestedClassAKey.uuid + currentClassCUUID:suggestedClassCKey.uuid + zoneID:self.zoneID + encodedCKRecord:oldcdse.encodedCKRecord]; + return newcdse; +} + +- (CKKSSynchronizeOperation*) resyncWithCloud { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckks", self, "Skipping resyncWithCloud due to disabled CKKS"); + return nil; + } + + CKKSSynchronizeOperation* op = [[CKKSSynchronizeOperation alloc] initWithCKKSKeychainView: self]; + [self scheduleOperation: op]; + return op; +} + +- (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckks", self, "Skipping fetchAndProcessCKChanges due to disabled CKKS"); + return nil; + } + + // We fetched some changes; try to process them! + return [self processIncomingQueue:false after:[self.zoneChangeFetcher requestSuccessfulFetch:because]]; +} + +// 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 +// +// Note that you need to tell this function the records you wanted to save, so it can determine what needs deletion +- (bool)_onqueueCKWriteFailed:(NSError*)ckerror attemptedRecordsChanged:(NSDictionary*)savedRecords { + dispatch_assert_queue(self.queue); + + NSDictionary* partialErrors = ckerror.userInfo[CKPartialErrorsByItemIDKey]; + if([ckerror.domain isEqual:CKErrorDomain] && ckerror.code == CKErrorPartialFailure && partialErrors) { + // Check if this error was "you're out of date" + bool recordChanged = true; + + for(NSError* error in partialErrors.allValues) { + if((![error.domain isEqual:CKErrorDomain]) || (error.code != CKErrorBatchRequestFailed && error.code != CKErrorServerRecordChanged && error.code != CKErrorUnknownItem)) { + // There's an error in there that isn't CKErrorServerRecordChanged, CKErrorBatchRequestFailed, or CKErrorUnknownItem. Don't handle nicely... + recordChanged = false; + } + } + + if(recordChanged) { + ckksnotice("ckks", self, "Received a ServerRecordChanged error, attempting to update new records and delete unknown ones"); + + bool updatedRecord = false; + + for(CKRecordID* recordID in partialErrors.allKeys) { + NSError* error = partialErrors[recordID]; + if([error.domain isEqual:CKErrorDomain] && error.code == CKErrorServerRecordChanged) { + CKRecord* newRecord = error.userInfo[CKRecordChangedErrorServerRecordKey]; + ckksnotice("ckks", self, "On error: updating our idea of: %@", newRecord); + + updatedRecord |= [self _onqueueCKRecordChanged:newRecord resync:true]; + } else if([error.domain isEqual:CKErrorDomain] && error.code == CKErrorUnknownItem) { + CKRecord* record = savedRecords[recordID]; + ckksnotice("ckks", self, "On error: handling an unexpected delete of: %@ %@", recordID, record); + + updatedRecord |= [self _onqueueCKRecordDeleted:recordID recordType:record.recordType resync:true]; + } + } + + if(updatedRecord) { + [self processIncomingQueue:false]; + return true; + } + } + } + + return false; +} + +- (bool)_onqueueCKRecordDeleted:(CKRecordID*)recordID recordType:(NSString*)recordType resync:(bool)resync { + dispatch_assert_queue(self.queue); + + // 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); + NSError* error = nil; + NSError* iqeerror = nil; + CKKSMirrorEntry* ckme = [CKKSMirrorEntry fromDatabase: [recordID recordName] zoneID:self.zoneID error: &error]; + + // Deletes always succeed, not matter the generation count + if(ckme) { + [ckme deleteFromDatabase:&error]; + + CKKSIncomingQueueEntry* iqe = [[CKKSIncomingQueueEntry alloc] initWithCKKSItem:ckme.item action:SecCKKSActionDelete state:SecCKKSStateNew]; + [iqe saveToDatabase:&iqeerror]; + if(iqeerror) { + ckkserror("ckks", self, "Couldn't save incoming queue entry: %@", iqeerror); + } + } + ckksinfo("ckks", self, "CKKSMirrorEntry was deleted: %@ %@ error: %@", recordID, ckme, error); + // TODO: actually pass error back up + return (error == nil); + + } else if([recordType isEqual: SecCKRecordCurrentItemType]) { + ckksinfo("ckks", self, "CloudKit notification: deleted current item pointer(%@): %@", recordType, recordID); + NSError* error = nil; + + [[CKKSCurrentItemPointer tryFromDatabase:[recordID recordName] state:SecCKKSProcessedStateRemote zoneID:self.zoneID error:&error] deleteFromDatabase:&error]; + [[CKKSCurrentItemPointer fromDatabase:[recordID recordName] state:SecCKKSProcessedStateLocal zoneID:self.zoneID error:&error] deleteFromDatabase:&error]; + + ckksinfo("ckks", self, "CKKSCurrentItemPointer was deleted: %@ error: %@", recordID, error); + return (error == nil); + + } else if([recordType isEqual: SecCKRecordIntermediateKeyType]) { + // TODO: handle in some interesting way + return true; + } else if([recordType isEqual: SecCKRecordDeviceStateType]) { + NSError* error = nil; + ckksinfo("ckks", self, "CloudKit notification: deleted device state record(%@): %@", recordType, recordID); + + CKKSDeviceStateEntry* cdse = [CKKSDeviceStateEntry tryFromDatabaseFromCKRecordID:recordID error:&error]; + [cdse deleteFromDatabase: &error]; + ckksinfo("ckks", self, "CKKSCurrentItemPointer(%@) was deleted: %@ error: %@", cdse, recordID, error); + + return (error == nil); + + } else if ([recordType isEqualToString:SecCKRecordManifestType]) { + ckksinfo("ckks", self, "CloudKit notification: deleted manifest record (%@): %@", recordType, recordID); + + NSError* error = nil; + CKKSManifest* manifest = [CKKSManifest manifestForRecordName:recordID.recordName error:&error]; + if (manifest) { + [manifest deleteFromDatabase:&error]; + } + + ckksinfo("ckks", self, "CKKSManifest was deleted: %@ %@ error: %@", recordID, manifest, error); + // TODO: actually pass error back up + return error == nil; + } + else { + ckkserror("ckksfetch", self, "unknown record type: %@ %@", recordType, recordID); + return false; + } +} + +- (bool)_onqueueCKRecordChanged:(CKRecord*)record resync:(bool)resync { + dispatch_assert_queue(self.queue); + + ckksinfo("ckksfetch", self, "Processing record modification(%@): %@", record.recordType, record); + + if([[record recordType] isEqual: SecCKRecordItemType]) { + [self _onqueueCKRecordItemChanged:record resync:resync]; + return true; + } else if([[record recordType] isEqual: SecCKRecordCurrentItemType]) { + [self _onqueueCKRecordCurrentItemPointerChanged:record resync:resync]; + return true; + } else if([[record recordType] isEqual: SecCKRecordIntermediateKeyType]) { + [self _onqueueCKRecordKeyChanged:record resync:resync]; + return true; + } else if([[record recordType] isEqualToString: SecCKRecordCurrentKeyType]) { + [self _onqueueCKRecordCurrentKeyPointerChanged:record resync:resync]; + return true; + } else if ([[record recordType] isEqualToString:SecCKRecordManifestType]) { + [self _onqueueCKRecordManifestChanged:record resync:resync]; + return true; + } else if ([[record recordType] isEqualToString:SecCKRecordManifestLeafType]) { + [self _onqueueCKRecordManifestLeafChanged:record resync:resync]; + return true; + } else if ([[record recordType] isEqualToString:SecCKRecordDeviceStateType]) { + [self _onqueueCKRecordDeviceStateChanged:record resync:resync]; + return true; + } else { + ckkserror("ckksfetch", self, "unknown record type: %@ %@", [record recordType], record); + return false; + } +} + +- (void)_onqueueCKRecordItemChanged:(CKRecord*)record resync:(bool)resync { + dispatch_assert_queue(self.queue); + + NSError* error = nil; + // Find if we knew about this record in the past + bool update = false; + CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase: [[record recordID] recordName] zoneID:self.zoneID error:&error]; + + if(error) { + ckkserror("ckks", self, "error loading a CKKSMirrorEntry from database: %@", error); + // TODO: quit? + } + + if(resync) { + if(!ckme) { + ckkserror("ckksresync", self, "BUG: No local item matching resynced CloudKit record: %@", record); + } else if(![ckme matchesCKRecord:record]) { + ckkserror("ckksresync", self, "BUG: Local item doesn't match resynced CloudKit record: %@ %@", ckme, record); + } else { + ckksnotice("ckksresync", self, "Already know about this item record, skipping update: %@", record); + return; + } + } + + if(ckme && ckme.item && ckme.item.generationCount > [record[SecCKRecordGenerationCountKey] unsignedLongLongValue]) { + ckkserror("ckks", self, "received a record from CloudKit with a bad generation count: %@ (%ld > %@)", ckme.uuid, + (long) ckme.item.generationCount, + record[SecCKRecordGenerationCountKey]); + // Abort processing this record. + return; + } + + // If we found an old version in the database; this might be an update + if(ckme) { + if([ckme matchesCKRecord:record]) { + // 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"); + return; + } + + update = true; + // Set the CKKSMirrorEntry's fields to be whatever this record holds + [ckme setFromCKRecord: record]; + } else { + // Have to make a new CKKSMirrorEntry + ckme = [[CKKSMirrorEntry alloc] initWithCKRecord: record]; + } + + [ckme saveToDatabase: &error]; + + if(error) { + ckkserror("ckks", self, "couldn't save new CKRecord to database: %@ %@", record, error); + } else { + ckksdebug("ckks", self, "CKKSMirrorEntry was created: %@", ckme); + } + + NSError* iqeerror = nil; + CKKSIncomingQueueEntry* iqe = [[CKKSIncomingQueueEntry alloc] initWithCKKSItem:ckme.item + action:(update ? SecCKKSActionModify : SecCKKSActionAdd) + state:SecCKKSStateNew]; + [iqe saveToDatabase:&iqeerror]; + if(iqeerror) { + ckkserror("ckks", self, "Couldn't save modified incoming queue entry: %@", iqeerror); + } else { + ckksdebug("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]; + if(error) { + ckkserror("ckks", self, "Couldn't load OutgoingQueueEntry: %@", error); + } + if(oqe) { + [self _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateDeleted error:&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); + } + } +} + +- (void)_onqueueCKRecordKeyChanged:(CKRecord*)record resync:(bool)resync { + dispatch_assert_queue(self.queue); + + NSError* error = nil; + + if(resync) { + NSError* resyncerror = nil; + + CKKSKey* key = [CKKSKey tryFromDatabaseAnyState:record.recordID.recordName zoneID:self.zoneID error:&resyncerror]; + if(resyncerror) { + ckkserror("ckksresync", self, "error loading key: %@", resyncerror); + } + if(!key) { + ckkserror("ckksresync", self, "BUG: No sync key matching resynced CloudKit record: %@", record); + } else if(![key matchesCKRecord:record]) { + ckkserror("ckksresync", self, "BUG: Local sync key doesn't match resynced CloudKit record(s): %@ %@", key, record); + } else { + ckksnotice("ckksresync", self, "Already know about this sync key, skipping update: %@", record); + return; + } + } + + // For now, drop into the synckeys table as a 'remote' key, then ask for a rekey operation. + CKKSKey* remotekey = [[CKKSKey alloc] initWithCKRecord: record]; + + // We received this from an update. Don't use, yet. + remotekey.state = SecCKKSProcessedStateRemote; + remotekey.currentkey = false; + + [remotekey saveToDatabase:&error]; + if(error) { + ckkserror("ckkskey", self, "Couldn't save key record to database: %@: %@", remotekey, error); + ckksinfo("ckkskey", self, "CKRecord was %@", record); + } + + // We've saved a new key in the database; trigger a rekey operation. + [self _onqueueKeyStateMachineRequestProcess]; +} + +- (void)_onqueueCKRecordCurrentKeyPointerChanged:(CKRecord*)record resync:(bool)resync { + dispatch_assert_queue(self.queue); + + if(resync) { + NSError* ckperror = nil; + CKKSCurrentKeyPointer* ckp = [CKKSCurrentKeyPointer tryFromDatabase:((CKKSKeyClass*) record.recordID.recordName) zoneID:self.zoneID error:&ckperror]; + if(ckperror) { + ckkserror("ckksresync", self, "error loading ckp: %@", ckperror); + } + if(!ckp) { + ckkserror("ckksresync", self, "BUG: No current key pointer matching resynced CloudKit record: %@", record); + } else if(![ckp matchesCKRecord:record]) { + ckkserror("ckksresync", self, "BUG: Local current key pointer doesn't match resynced CloudKit record: %@ %@", ckp, record); + } else { + ckksnotice("ckksresync", self, "Already know about this current key pointer, skipping update: %@", record); + return; + } + } + + NSError* error = nil; + CKKSCurrentKeyPointer* currentkey = [[CKKSCurrentKeyPointer alloc] initWithCKRecord: record]; + + [currentkey saveToDatabase: &error]; + if(error) { + ckkserror("ckkskey", self, "Couldn't save current key pointer to database: %@: %@", currentkey, error); + ckksinfo("ckkskey", self, "CKRecord was %@", record); + } + + // We've saved a new key in the database; trigger a rekey operation. + [self _onqueueKeyStateMachineRequestProcess]; +} + +- (void)_onqueueCKRecordCurrentItemPointerChanged:(CKRecord*)record resync:(bool)resync { + dispatch_assert_queue(self.queue); + + if(resync) { + NSError* ciperror = nil; + CKKSCurrentItemPointer* localcip = [CKKSCurrentItemPointer tryFromDatabase:record.recordID.recordName state:SecCKKSProcessedStateLocal zoneID:self.zoneID error:&ciperror]; + CKKSCurrentItemPointer* remotecip = [CKKSCurrentItemPointer tryFromDatabase:record.recordID.recordName state:SecCKKSProcessedStateRemote zoneID:self.zoneID error:&ciperror]; + if(ciperror) { + ckkserror("ckksresync", self, "error loading cip: %@", ciperror); + } + if(!(localcip || remotecip)) { + ckkserror("ckksresync", self, "BUG: No current item pointer matching resynced CloudKit record: %@", record); + } else if(! ([localcip matchesCKRecord:record] || [remotecip matchesCKRecord:record]) ) { + ckkserror("ckksresync", self, "BUG: Local current item pointer doesn't match resynced CloudKit record(s): %@ %@ %@", localcip, remotecip, record); + } else { + ckksnotice("ckksresync", self, "Already know about this current item pointer, skipping update: %@", record); + return; + } + } + + NSError* error = nil; + CKKSCurrentItemPointer* cip = [[CKKSCurrentItemPointer alloc] initWithCKRecord: record]; + cip.state = SecCKKSProcessedStateRemote; + + [cip saveToDatabase: &error]; + if(error) { + ckkserror("currentitem", self, "Couldn't save current item pointer to database: %@: %@ %@", cip, error, record); + } +} + +- (void)_onqueueCKRecordManifestChanged:(CKRecord*)record resync:(bool)resync +{ + NSError* error = nil; + CKKSPendingManifest* manifest = [[CKKSPendingManifest alloc] initWithCKRecord:record]; + [manifest saveToDatabase:&error]; + if (error) { + ckkserror("CKKS", self, "Failed to save fetched manifest record to database: %@: %@", manifest, error); + ckksinfo("CKKS", self, "manifest CKRecord was %@", record); + } +} + +- (void)_onqueueCKRecordManifestLeafChanged:(CKRecord*)record resync:(bool)resync +{ + NSError* error = nil; + CKKSManifestLeafRecord* manifestLeaf = [[CKKSManifestPendingLeafRecord alloc] initWithCKRecord:record]; + [manifestLeaf saveToDatabase:&error]; + if (error) { + ckkserror("CKKS", self, "Failed to save fetched manifest leaf record to database: %@: %@", manifestLeaf, error); + ckksinfo("CKKS", self, "manifest leaf CKRecord was %@", record); + } +} + +- (void)_onqueueCKRecordDeviceStateChanged:(CKRecord*)record resync:(bool)resync { + if(resync) { + NSError* dserror = nil; + CKKSDeviceStateEntry* cdse = [CKKSDeviceStateEntry tryFromDatabase:record.recordID.recordName zoneID:self.zoneID error:&dserror]; + if(dserror) { + ckkserror("ckksresync", self, "error loading cdse: %@", dserror); + } + if(!cdse) { + ckkserror("ckksresync", self, "BUG: No current device state entry matching resynced CloudKit record: %@", record); + } else if(![cdse matchesCKRecord:record]) { + ckkserror("ckksresync", self, "BUG: Local current device state entry doesn't match resynced CloudKit record(s): %@ %@", cdse, record); + } else { + ckksnotice("ckksresync", self, "Already know about this current item pointer, skipping update: %@", record); + return; + } + } + + NSError* error = nil; + CKKSDeviceStateEntry* cdse = [[CKKSDeviceStateEntry alloc] initWithCKRecord:record]; + [cdse saveToDatabase:&error]; + if (error) { + ckkserror("ckksdevice", self, "Failed to save device record to database: %@: %@ %@", cdse, error, record); + } +} + +- (bool)_onqueueChangeOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe toState: (NSString*) state error: (NSError* __autoreleasing*) error { + dispatch_assert_queue(self.queue); + + NSError* localerror = nil; + + if([state isEqualToString: SecCKKSStateDeleted]) { + // Hurray, this must be a success + SecBoolNSErrorCallback callback = self.pendingSyncCallbacks[oqe.uuid]; + if(callback) { + callback(true, nil); + } + + [oqe deleteFromDatabase: &localerror]; + if(localerror) { + ckkserror("ckks", self, "Couldn't delete %@: %@", oqe, 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 = self.pendingSyncCallbacks[oqe.uuid]; + if(callback) { + callback(false, itemError); + } + NSError* localerror = nil; + + oqe.state = SecCKKSStateError; + [oqe saveToDatabase: &localerror]; + if(localerror) { + ckkserror("ckks", self, "Couldn't set %@ as error: %@", oqe, 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)checkTLK: (CKKSKey*) proposedTLK error: (NSError * __autoreleasing *) error { + // Until we have Octagon Trust, accept this TLK iff we have its actual AES key in the keychain + + if([proposedTLK loadKeyMaterialFromKeychain:error]) { + // Hurray! + return true; + } else { + return false; + } +} + +- (void) dispatchAsync: (bool (^)(void)) block { + // We need to call kc_with_dbt, which blocks. Route up through a global queue... + __weak __typeof(self) weakSelf = self; + + dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ + [weakSelf dispatchSync:block]; + }); +} + +// Use this if you have a potential database connection already +- (void) dispatchSyncWithConnection: (SecDbConnectionRef) dbconn block: (bool (^)(void)) block { + if(dbconn) { + dispatch_sync(self.queue, ^{ + CFErrorRef cferror = NULL; + kc_transaction_type(dbconn, kSecDbExclusiveRemoteCKKSTransactionType, &cferror, block); + + if(cferror) { + ckkserror("ckks", self, "error doing database transaction (sync), major problems ahead: %@", cferror); + } + }); + } else { + [self dispatchSync: block]; + } +} + +- (void) dispatchSync: (bool (^)(void)) block { + // important enough to block this thread. Must get a connection first, though! + __weak __typeof(self) weakSelf = self; + + CFErrorRef cferror = NULL; + kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + return false; + } + + __block bool ok = false; + __block CFErrorRef cferror = NULL; + + dispatch_sync(strongSelf.queue, ^{ + ok = kc_transaction_type(dbt, kSecDbExclusiveRemoteCKKSTransactionType, &cferror, block); + }); + return ok; + }); + if(cferror) { + ckkserror("ckks", self, "error getting database connection (sync), major problems ahead: %@", cferror); + } +} + +- (void)dispatchSyncWithAccountQueue:(bool (^)(void))block +{ + [SOSAccount performOnAccountQueue:^{ + [CKKSManifest performWithAccountInfo:^{ + [self dispatchSync:^bool{ + __block bool result = false; + [SOSAccount performWhileHoldingAccountQueue:^{ // so any calls through SOS account will know they can perform their work without dispatching to the account queue, which we already hold + result = block(); + }]; + return result; + }]; + }]; + }]; +} + +#pragma mark - CKKSZoneUpdateReceiver + +- (void)notifyZoneChange: (CKRecordZoneNotification*) notification { + ckksinfo("ckks", self, "hurray, got a zone change for %@ %@", self, notification); + + [self fetchAndProcessCKChanges:CKKSFetchBecauseAPNS]; +} + +// Must be on the queue when this is called +- (void)handleCKLogin { + dispatch_assert_queue(self.queue); + + if(!self.setupStarted) { + [self _onqueueInitializeZone]; + } else { + ckksinfo("ckks", self, "ignoring login as setup has already started"); + } +} + +- (void)handleCKLogout { + NSBlockOperation* logout = [NSBlockOperation blockOperationWithBlock: ^{ + [self dispatchSync:^bool { + ckksnotice("ckks", self, "received a notification of CK logout for %@", self.zoneName); + NSError* error = nil; + + [self _onqueueResetLocalData: &error]; + + if(error) { + ckkserror("ckks", self, "error while resetting local data: %@", error); + } + return true; + }]; + }]; + + logout.name = @"cloudkit-logout"; + [self scheduleAccountStatusOperation: logout]; +} + +#pragma mark - CKKSChangeFetcherErrorOracle + +- (bool) isFatalCKFetchError: (NSError*) error { + __weak __typeof(self) weakSelf = self; + + // Again, note that this handles exactly one zone. Mutli-zone errors are not supported. + bool isChangeTokenExpiredError = false; + if([error.domain isEqualToString:CKErrorDomain] && (error.code == CKErrorChangeTokenExpired)) { + isChangeTokenExpiredError = true; + } else if([error.domain isEqualToString:CKErrorDomain] && (error.code == CKErrorPartialFailure)) { + NSDictionary* partialErrors = error.userInfo[CKPartialErrorsByItemIDKey]; + for(NSError* partialError in partialErrors.allValues) { + if([partialError.domain isEqualToString:CKErrorDomain] && (partialError.code == CKErrorChangeTokenExpired)) { + isChangeTokenExpiredError = true; + } + } + } + + if(isChangeTokenExpiredError) { + ckkserror("ckks", self, "Received notice that our change token is out of date. Resetting local data..."); + [self cancelAllOperations]; + CKKSResultOperation* resetOp = [self resetLocalData]; + CKKSResultOperation* resetHandler = [CKKSResultOperation named:@"local-reset-handler" withBlock:^{ + __strong __typeof(self) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + return; + } + + if(resetOp.error) { + ckksnotice("ckks", strongSelf, "CloudKit-inspired local reset of %@ ended with error: %@", strongSelf.zoneID, error); + } else { + ckksnotice("ckksreset", strongSelf, "re-initializing zone %@", strongSelf.zoneID); + [strongSelf initializeZone]; + } + }]; + + [resetHandler addDependency:resetOp]; + [self scheduleOperation:resetHandler]; + return true; + } + + bool isDeletedZoneError = false; + if([error.domain isEqualToString:CKErrorDomain] && ((error.code == CKErrorUserDeletedZone) || (error.code == CKErrorZoneNotFound))) { + isDeletedZoneError = true; + } else if([error.domain isEqualToString:CKErrorDomain] && (error.code == CKErrorPartialFailure)) { + NSDictionary* partialErrors = error.userInfo[CKPartialErrorsByItemIDKey]; + for(NSError* partialError in partialErrors.allValues) { + if([partialError.domain isEqualToString:CKErrorDomain] && ((partialError.code == CKErrorUserDeletedZone) || (partialError.code == CKErrorZoneNotFound))) { + isDeletedZoneError = true; + } + } + } + + if(isDeletedZoneError) { + ckkserror("ckks", self, "Received notice that our zone does not exist. Resetting all data."); + [self cancelAllOperations]; + CKKSResultOperation* resetOp = [self resetCloudKitZone]; + CKKSResultOperation* resetHandler = [CKKSResultOperation named:@"reset-handler" withBlock:^{ + __strong __typeof(self) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckks", strongSelf, "received callback for released object"); + return; + } + + if(resetOp.error) { + ckksnotice("ckks", strongSelf, "CloudKit-inspired zone reset of %@ ended with error: %@", strongSelf.zoneID, resetOp.error); + } else { + ckksnotice("ckksreset", strongSelf, "re-initializing zone %@", strongSelf.zoneID); + [strongSelf initializeZone]; + } + }]; + + [resetHandler addDependency:resetOp]; + [self scheduleOperation:resetHandler]; + return true; + } + + if([error.domain isEqualToString:CKErrorDomain] && (error.code == CKErrorBadContainer)) { + ckkserror("ckks", self, "Received notice that our container does not exist. Nothing to do."); + return true; + } + + return false; +} + +#pragma mark - Test Support + +- (bool) outgoingQueueEmpty: (NSError * __autoreleasing *) error { + __block bool ret = false; + [self dispatchSync: ^bool{ + NSArray* queueEntries = [CKKSOutgoingQueueEntry all: error]; + ret = queueEntries && ([queueEntries count] == 0); + return true; + }]; + + return ret; +} + +- (CKKSResultOperation*)waitForFetchAndIncomingQueueProcessing { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckks", self, "Due to disabled CKKS, returning fast from waitForFetchAndIncomingQueueProcessing"); + return nil; + } + + CKKSResultOperation* op = [self fetchAndProcessCKChanges:CKKSFetchBecauseTesting]; + [op waitUntilFinished]; + return op; +} + +- (void)waitForKeyHierarchyReadiness { + if(self.keyStateReadyDependency) { + [self.keyStateReadyDependency waitUntilFinished]; + } +} + +- (void)cancelAllOperations { + [self.zoneSetupOperation cancel]; + [self.keyStateMachineOperation cancel]; + [self.keyStateReadyDependency cancel]; + [self.zoneChangeFetcher cancel]; + + [super cancelAllOperations]; + + [self dispatchSync:^bool{ + [self _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateCancelled withError: nil]; + return true; + }]; +} + +- (NSDictionary*)status { +#define stringify(obj) CKKSNilToNSNull([obj description]) +#define boolstr(obj) (!!(obj) ? @"yes" : @"no") + __block NSDictionary* ret = nil; + __block NSError* error = nil; + CKKSManifest* manifest = [CKKSManifest latestTrustedManifestForZone:self.zoneName error:&error]; + [self dispatchSync: ^bool { + + NSString* uuidTLK = [CKKSKey currentKeyForClass:SecCKKSKeyClassTLK zoneID:self.zoneID error:&error].uuid; + NSString* uuidClassA = [CKKSKey currentKeyForClass:SecCKKSKeyClassA zoneID:self.zoneID error:&error].uuid; + NSString* uuidClassC = [CKKSKey currentKeyForClass:SecCKKSKeyClassC zoneID:self.zoneID error:&error].uuid; + + NSString* manifestGeneration = manifest ? [NSString stringWithFormat:@"%lu", (unsigned long)manifest.generationCount] : nil; + + if(error) { + ckkserror("ckks", self, "error during status: %@", error); + } + // We actually don't care about this error, especially if it's "no current key pointers"... + error = nil; + + // Map deviceStates to strings to avoid NSXPC issues. Obj-c, why is this so hard? + NSArray* deviceStates = [CKKSDeviceStateEntry allInZone:self.zoneID error:&error]; + NSMutableArray* mutDeviceStates = [[NSMutableArray alloc] init]; + [deviceStates enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + [mutDeviceStates addObject: [obj description]]; + }]; + + ret = @{ + @"view": CKKSNilToNSNull(self.zoneName), + @"ckaccountstatus": self.accountStatus == CKAccountStatusCouldNotDetermine ? @"could not determine" : + self.accountStatus == CKAccountStatusAvailable ? @"logged in" : + self.accountStatus == CKAccountStatusRestricted ? @"restricted" : + self.accountStatus == CKAccountStatusNoAccount ? @"logged out" : @"unknown", + @"lockstatetracker": stringify(self.lockStateTracker), + @"accounttracker": stringify(self.accountTracker), + @"fetcher": stringify(self.zoneChangeFetcher), + @"setup": boolstr(self.setupComplete), + @"zoneCreated": boolstr(self.zoneCreated), + @"zoneCreatedError": stringify(self.zoneCreatedError), + @"zoneSubscribed": boolstr(self.zoneSubscribed), + @"zoneSubscribedError": stringify(self.zoneSubscribedError), + @"zoneInitializeScheduler": stringify(self.initializeScheduler), + @"keystate": CKKSNilToNSNull(self.keyHierarchyState), + @"keyStateError": stringify(self.keyHierarchyError), + @"statusError": stringify(error), + @"oqe": CKKSNilToNSNull([CKKSOutgoingQueueEntry countsByState:self.zoneID error:&error]), + @"iqe": CKKSNilToNSNull([CKKSIncomingQueueEntry countsByState:self.zoneID error:&error]), + @"ckmirror": CKKSNilToNSNull([CKKSMirrorEntry countsByParentKey:self.zoneID error:&error]), + @"devicestates": CKKSNilToNSNull(mutDeviceStates), + @"keys": CKKSNilToNSNull([CKKSKey countsByClass:self.zoneID error:&error]), + @"currentTLK": CKKSNilToNSNull(uuidTLK), + @"currentClassA": CKKSNilToNSNull(uuidClassA), + @"currentClassC": CKKSNilToNSNull(uuidClassC), + @"currentManifestGen": CKKSNilToNSNull(manifestGeneration), + + @"zoneSetupOperation": stringify(self.zoneSetupOperation), + @"viewSetupOperation": stringify(self.viewSetupOperation), + @"keyStateOperation": stringify(self.keyStateMachineOperation), + @"lastIncomingQueueOperation": stringify(self.lastIncomingQueueOperation), + @"lastNewTLKOperation": stringify(self.lastNewTLKOperation), + @"lastOutgoingQueueOperation": stringify(self.lastOutgoingQueueOperation), + @"lastRecordZoneChangesOperation": stringify(self.lastRecordZoneChangesOperation), + @"lastProcessReceivedKeysOperation": stringify(self.lastProcessReceivedKeysOperation), + @"lastReencryptOutgoingItemsOperation":stringify(self.lastReencryptOutgoingItemsOperation), + @"lastScanLocalItemsOperation": stringify(self.lastScanLocalItemsOperation), + }; + return false; + }]; + return ret; +} + + + +#endif /* OCTAGON */ +@end diff --git a/keychain/ckks/CKKSLockStateTracker.h b/keychain/ckks/CKKSLockStateTracker.h new file mode 100644 index 00000000..f2d62dde --- /dev/null +++ b/keychain/ckks/CKKSLockStateTracker.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import + +@interface CKKSLockStateTracker : NSObject +@property NSOperation* unlockDependency; + +-(instancetype)init; + +// Force a recheck of the keybag lock state +-(void)recheck; + +// Check if this error code is related to keybag is locked and we should retry later +-(bool)isLockedError:(NSError *)error; + +// Ask AKS if the user's keybag is locked ++(bool)queryAKSLocked; +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSLockStateTracker.m b/keychain/ckks/CKKSLockStateTracker.m new file mode 100644 index 00000000..83236142 --- /dev/null +++ b/keychain/ckks/CKKSLockStateTracker.m @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#include +#include +#include + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSGroupOperation.h" +#import "keychain/ckks/CKKSLockStateTracker.h" + +@interface CKKSLockStateTracker () +@property bool isLocked; +@property dispatch_queue_t queue; +@property NSOperationQueue* operationQueue; +@end + +@implementation CKKSLockStateTracker + +- (instancetype)init { + if((self = [super init])) { + _queue = dispatch_queue_create("lock-state-tracker", DISPATCH_QUEUE_SERIAL); + _operationQueue = [[NSOperationQueue alloc] init]; + + _isLocked = true; + [self resetUnlockDependency]; + + __weak __typeof(self) weakSelf = self; + + // If this is a live server, register with notify + if(!SecCKKSTestsEnabled()) { + int token = 0; + notify_register_dispatch(kUserKeybagStateChangeNotification, &token, _queue, ^(int t) { + [weakSelf _onqueueRecheck]; + }); + } + + dispatch_async(_queue, ^{ + [weakSelf _onqueueRecheck]; + }); + } + return self; +} + +-(NSString*)description { + return [NSString stringWithFormat: @"", self.isLocked ? @"locked" : @"unlocked"]; +} + +-(void)resetUnlockDependency { + if(self.unlockDependency == nil || ![self.unlockDependency isPending]) { + self.unlockDependency = [NSBlockOperation blockOperationWithBlock: ^{ + secinfo("ckks", "Keybag unlocked"); + }]; + self.unlockDependency.name = @"keybag-unlocked-dependency"; + } +} + ++(bool)queryAKSLocked { + CFErrorRef aksError = NULL; + bool locked = true; + + if(!SecAKSGetIsLocked(&locked, &aksError)) { + secerror("ckks: error querying lock state: %@", aksError); + CFReleaseNull(aksError); + } + + return locked; +} + +-(void)_onqueueRecheck { + dispatch_assert_queue(self.queue); + + bool wasLocked = self.isLocked; + self.isLocked = [CKKSLockStateTracker queryAKSLocked]; + + if(wasLocked != self.isLocked) { + if(self.isLocked) { + // We're locked now. + [self resetUnlockDependency]; + } else { + [self.operationQueue addOperation: self.unlockDependency]; + self.unlockDependency = nil; + } + } +} + +-(void)recheck { + dispatch_sync(self.queue, ^{ + [self _onqueueRecheck]; + }); +} + +-(bool)isLockedError:(NSError *)error { + return [error.domain isEqualToString:@"securityd"] && error.code == errSecInteractionNotAllowed; +} + + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSLogger.h b/keychain/ckks/CKKSLogger.h new file mode 100644 index 00000000..a3b8b673 --- /dev/null +++ b/keychain/ckks/CKKSLogger.h @@ -0,0 +1,64 @@ +/* + * 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 + +#if __OBJC2__ + +@interface SFAnalyticsLogger : NSObject + ++ (instancetype)logger; + +- (void)logSuccessForEventNamed:(NSString*)eventName; +- (void)logHardFailureForEventNamed:(NSString*)eventName withAttributes:(NSDictionary*)attributes; +- (void)logSoftFailureForEventNamed:(NSString*)eventName withAttributes:(NSDictionary*)attributes; + +- (void)noteEventNamed:(NSString*)eventName; + +// -------------------------------- +// Things below are for subclasses + +// Override to create a concrete logger instance +@property (readonly, class) NSString* databasePath; + +// Storing dates +- (void)setDateProperty:(NSDate*)date forKey:(NSString*)key; +- (NSDate*)datePropertyForKey:(NSString*)key; +- (NSArray*)datePropertyKeysToUploadToServer; + +- (NSData*)getLoggingJSONWithError:(NSError**)error; +- (BOOL)forceUploadWithError:(NSError**)error; + +// -------------------------------- +// Things below are for unit testing + +@property (readonly) dispatch_queue_t splunkLoggingQueue; +@property (readonly) NSURL* splunkUploadURL; +@property (readonly) NSString* splunkTopicName; +@property (readonly) NSURL* splunkBagURL; +@property (readonly) BOOL allowsInsecureSplunkCert; +@property BOOL ignoreServerDisablingMessages; + +@end + +#endif diff --git a/keychain/ckks/CKKSLogger.m b/keychain/ckks/CKKSLogger.m new file mode 100644 index 00000000..5cc74413 --- /dev/null +++ b/keychain/ckks/CKKSLogger.m @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import "CKKSLogger.h" +#import "debugging.h" +#import "CKKS.h" +#import "CKKSViewManager.h" +#import "keychain/ckks/CKKSKeychainView.h" +#include +#import +#import + +NSString* const CKKSLoggerTableSuccessCount = @"success_count"; +NSString* const CKKSLoggerColumnEventType = @"event_type"; +NSString* const CKKSLoggerColumnSuccessCount = @"success_count"; +NSString* const CKKSLoggerColumnFailureCount = @"failure_count"; + +NSString* const CKKSLoggerTableFailures = @"failures"; +NSString* const CKKSLoggerColumnData = @"data"; + +NSString* const CKKSLoggerUploadDate = @"upload_date"; +NSString* const CKKSLoggerLastClassASync = @"last_class_a_sync"; +NSString* const CKKSLoggerLastClassCSync = @"last_class_c_sync"; + +NSString* const CKKSLoggerDaysSinceLastSyncClassA = @"lastSyncClassA"; +NSString* const CKKSLoggerDaysSinceLastSyncClassC = @"lastSyncClassC"; + +NSString* const CKKSLoggerSplunkTopic = @"topic"; +NSString* const CKKSLoggerSplunkEventTime = @"eventTime"; +NSString* const CKKSLoggerSplunkPostTime = @"postTime"; +NSString* const CKKSLoggerSplunkEvents = @"events"; +NSString* const CKKSLoggerSplunkEventType = @"eventType"; +NSString* const CKKSLoggerMetricsBase = @"metricsBase"; + +NSString* const CKKSLoggerValueSuccess = @"success"; + +#define CKKS_SPLUNK_DEV 0 + +#if CKKS_SPLUNK_DEV +#define SECONDS_BETWEEN_UPLOADS 10 +#else +// three days = 60 seconds times 60 minutes * 72 hours +#define SECONDS_BETWEEN_UPLOADS (60 * 60 * 72) +#endif + +NSString* const CKKSLoggingTableSchema = @"CREATE TABLE IF NOT EXISTS failures (\n" + @"id INTEGER PRIMARY KEY AUTOINCREMENT,\n" + @"data BLOB\n" + @");\n" + @"CREATE TRIGGER IF NOT EXISTS maintain_ring_buffer AFTER INSERT ON failures\n" + @"BEGIN\n" + @"DELETE FROM failures WHERE id != NEW.id AND id % 999 = NEW.id % 999;\n" + @"END;\n" + @"CREATE TABLE IF NOT EXISTS success_count (\n" + @"event_type STRING PRIMARY KEY,\n" + @"success_count INTEGER,\n" + @"failure_count INTEGER\n" + @");\n"; + +static NSString* CKKSLoggingTablePath() +{ + return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)@"ckks_analytics_v1.db") path]; +} + +@interface CKKSLoggerSQLiteStore : SFSQLite + ++ (instancetype)sharedStore; + +@property (readonly, strong) NSArray* failureRecords; +@property (readwrite, strong) NSDate* uploadDate; + +- (void)incrementSuccessCountForEventType:(NSString*)eventType; +- (void)incrementFailureCountForEventType:(NSString*)eventType; +- (NSInteger)successCountForEventType:(NSString*)eventType; +- (NSInteger)failureCountForEventType:(NSString*)eventType; +- (void)addFailureRecord:(NSDictionary*)valueDict; +- (void)clearAllData; + +- (NSDictionary*)summaryCounts; + +@end + +@implementation CKKSLogger { + NSURL* _splunkUploadURL; + NSString* _splunkTopicName; + NSURL* _splunkBagURL; + dispatch_queue_t _queue; + NSInteger _secondsBetweenUploads; + NSDictionary* _metricsBase; // data the server provides and wants us to send back + NSArray* _blacklistedFields; + NSArray* _blacklistedEvents; + + unsigned int _allowInsecureSplunkCert:1; + unsigned int _disableLogging:1; + unsigned int _disableUploads:1; + unsigned int _ignoreServersMessagesTellingUsToGoAway:1; +} + +@synthesize splunkUploadURL = _splunkUploadURL; +@synthesize splunkBagURL = _splunkBagURL; +@synthesize splunkTopicName = _splunkTopicName; +@synthesize splunkLoggingQueue = _queue; + ++ (instancetype)logger +{ +#if TARGET_OS_SIMULATOR + return nil; +#endif + static CKKSLogger* __sharedLogger; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + __sharedLogger = [[CKKSLogger alloc] init]; + }); + + return __sharedLogger; +} + +- (instancetype)init +{ + if (self = [super init]) { + _queue = dispatch_queue_create("com.apple.security.ckks.logging", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + _secondsBetweenUploads = SECONDS_BETWEEN_UPLOADS; + + NSDictionary* systemDefaultValues = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle bundleWithPath:@"/System/Library/Frameworks/Security.framework"] pathForResource:@"CKKSLogging" ofType:@"plist"]]; + _splunkTopicName = systemDefaultValues[@"splunk_topic"]; + _splunkUploadURL = [NSURL URLWithString:systemDefaultValues[@"splunk_uploadURL"]]; + _splunkBagURL = [NSURL URLWithString:systemDefaultValues[@"splunk_bagURL"]]; + _allowInsecureSplunkCert = [[systemDefaultValues valueForKey:@"splunk_allowInsecureCertificate"] boolValue]; + NSString* splunkEndpoint = systemDefaultValues[@"splunk_endpointDomain"]; + + NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:SecCKKSUserDefaultsSuite]; + NSString* userDefaultsSplunkTopic = [defaults stringForKey:@"splunk_topic"]; + if (userDefaultsSplunkTopic) { + _splunkTopicName = userDefaultsSplunkTopic; + } + + NSURL* userDefaultsSplunkUploadURL = [NSURL URLWithString:[defaults stringForKey:@"splunk_uploadURL"]]; + if (userDefaultsSplunkUploadURL) { + _splunkUploadURL = userDefaultsSplunkUploadURL; + } + + NSURL* userDefaultsSplunkBagURL = [NSURL URLWithString:[defaults stringForKey:@"splunk_bagURL"]]; + if (userDefaultsSplunkUploadURL) { + _splunkBagURL = userDefaultsSplunkBagURL; + } + + BOOL userDefaultsAllowInsecureSplunkCert = [defaults boolForKey:@"splunk_allowInsecureCertificate"]; + _allowInsecureSplunkCert |= userDefaultsAllowInsecureSplunkCert; + + NSString* userDefaultsSplunkEndpoint = [defaults stringForKey:@"splunk_endpointDomain"]; + if (userDefaultsSplunkEndpoint) { + splunkEndpoint = userDefaultsSplunkEndpoint; + } + +#if CKKS_SPLUNK_DEV + _ignoreServersMessagesTellingUsToGoAway = YES; + + if (!_splunkUploadURL && splunkEndpoint) { + NSString* urlString = [NSString stringWithFormat:@"https://%@/report/2/%@", splunkEndpoint, _splunkTopicName]; + _splunkUploadURL = [NSURL URLWithString:urlString]; + } +#else + (void)splunkEndpoint; +#endif + } + + return self; +} + +- (void)setLastSuccessfulClassASyncDate:(NSDate*)lastSuccessfulClassASyncDate +{ + dispatch_sync(_queue, ^{ + [[CKKSLoggerSQLiteStore sharedStore] setDateProperty:lastSuccessfulClassASyncDate forKey:CKKSLoggerLastClassASync]; + }); +} + +- (NSDate*)lastSuccessfulClassASyncDate +{ + __block NSDate* result = nil; + dispatch_sync(_queue, ^{ + result = [self _onQueueLastSuccessfulClassASyncDate]; + }); + + return result; +} + +- (NSDate*)_onQueueLastSuccessfulClassASyncDate +{ + dispatch_assert_queue(_queue); + return [[CKKSLoggerSQLiteStore sharedStore] datePropertyForKey:CKKSLoggerLastClassASync] ?: [NSDate distantPast]; +} + +- (void)setLastSuccessfulClassCSyncDate:(NSDate*)lastSuccessfulClassCSyncDate +{ + dispatch_sync(_queue, ^{ + [[CKKSLoggerSQLiteStore sharedStore] setDateProperty:lastSuccessfulClassCSyncDate forKey:CKKSLoggerLastClassCSync]; + }); +} + +- (NSDate*)lastSuccessfulClassCSyncDate +{ + __block NSDate* result = nil; + dispatch_sync(_queue, ^{ + result = [self _onQueueLastSuccessfulClassCSyncDate]; + }); + + return result; +} + +- (NSDate*)_onQueueLastSuccessfulClassCSyncDate +{ + dispatch_assert_queue(_queue); + return [[CKKSLoggerSQLiteStore sharedStore] datePropertyForKey:CKKSLoggerLastClassCSync] ?: [NSDate distantPast]; +} + +- (void)logSuccessForEventNamed:(NSString*)eventName +{ + [self logEventNamed:eventName value:nil isSuccess:YES]; +} + +- (void)logFailureForEventNamed:(NSString*)eventName withAttributes:(NSDictionary*)attributes +{ + [self logEventNamed:eventName value:attributes isSuccess:NO]; +} + +- (void)logEventNamed:(NSString*)eventName value:(NSDictionary*)valueDict isSuccess:(BOOL)isSuccess +{ + __weak __typeof(self) weakSelf = self; + dispatch_async(_queue, ^{ + + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + if (strongSelf->_disableLogging || [strongSelf->_blacklistedEvents containsObject:eventName]) { + return; + } + + CKKSLoggerSQLiteStore* store = [CKKSLoggerSQLiteStore sharedStore]; + if (isSuccess) { + [store incrementSuccessCountForEventType:eventName]; + } + else { + [store incrementFailureCountForEventType:eventName]; + NSMutableDictionary* eventDict = valueDict.mutableCopy; + eventDict[CKKSLoggerSplunkTopic] = strongSelf->_splunkTopicName; + eventDict[CKKSLoggerSplunkEventType] = eventName; + eventDict[CKKSLoggerSplunkEventTime] = @([[NSDate date] timeIntervalSince1970] * 1000); + eventDict[CKKSLoggerMetricsBase] = strongSelf->_metricsBase ?: [NSDictionary dictionary]; + + for (NSString* blacklistedField in strongSelf->_blacklistedFields) { + [eventDict removeObjectForKey:blacklistedField]; + } + + [store addFailureRecord:eventDict]; + } + + NSDate* uploadDate = store.uploadDate; + NSDate* nowDate = [NSDate date]; + if (uploadDate) { + if ([nowDate compare:uploadDate] == NSOrderedDescending) { + [self _onQueueUploadDataWithError:nil]; + } + } + else { + store.uploadDate = [nowDate dateByAddingTimeInterval:strongSelf->_secondsBetweenUploads]; + } + }); +} + +// this method is kind of evil for the fact that it has side-effects in pulling other things besides the metricsURL from the server, and as such should NOT be memoized. +// TODO redo this, probably to return a dictionary. +- (NSURL*)splunkUploadURL +{ + dispatch_assert_queue(_queue); + + if (_splunkUploadURL) { + return _splunkUploadURL; + } + + __weak __typeof(self) weakSelf = self; + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + + __block NSError* error = nil; + NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + NSURLSession* storeBagSession = [NSURLSession sessionWithConfiguration:defaultConfiguration + delegate:self + delegateQueue:nil]; + + NSURL* requestEndpoint = _splunkBagURL; + __block NSURL* result = nil; + NSURLSessionDataTask* storeBagTask = [storeBagSession dataTaskWithURL:requestEndpoint completionHandler:^(NSData * _Nullable data, + NSURLResponse * _Nullable __unused response, + NSError * _Nullable responseError) { + + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + if (data && !responseError) { + NSData *responseData = data; // shut up compiler + NSDictionary* responseDict = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error]; + if([responseDict isKindOfClass:NSDictionary.class] && !error) { + if (!self->_ignoreServersMessagesTellingUsToGoAway) { + strongSelf->_disableLogging = [[responseDict valueForKey:@"disabled"] boolValue]; + if (strongSelf->_disableLogging || [[responseDict valueForKey:@"sendDisabled"] boolValue]) { + // then don't upload anything right now + secerror("not returning a splunk URL because uploads are disabled"); + dispatch_semaphore_signal(sem); + return; + } + + NSUInteger millisecondsBetweenUploads = [[responseDict valueForKey:@"postFrequency"] unsignedIntegerValue] / 1000; + if (millisecondsBetweenUploads > 0) { + strongSelf->_secondsBetweenUploads = millisecondsBetweenUploads; + } + + strongSelf->_blacklistedEvents = responseDict[@"blacklistedEvents"]; + strongSelf->_blacklistedFields = responseDict[@"blacklistedFields"]; + } + + strongSelf->_metricsBase = responseDict[@"metricsBase"]; + + NSString* metricsEndpoint = responseDict[@"metricsUrl"]; + if([metricsEndpoint isKindOfClass:NSString.class]) { + /* Lives our URL */ + NSString* endpoint = [metricsEndpoint stringByAppendingFormat:@"/2/%@", strongSelf->_splunkTopicName]; + secnotice("ckks", "got metrics endpoint: %@", endpoint); + NSURL* endpointURL = [NSURL URLWithString:endpoint]; + if([endpointURL.scheme isEqualToString:@"https"]) { + result = endpointURL; + } + } + } + } + else { + error = responseError; + } + if(error) { + secnotice("ckks", "Unable to fetch splunk endpoint at URL: %@ -- error: %@", requestEndpoint, error.description); + } + else if(!result) { + secnotice("ckks", "Malformed iTunes config payload!"); + } + + dispatch_semaphore_signal(sem); + }]; + + [storeBagTask resume]; + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + + return result; +} + +- (BOOL)forceUploadWithError:(NSError**)error +{ + __block BOOL result = NO; + dispatch_sync(_queue, ^{ + result = [self _onQueueUploadDataWithError:error]; + }); + return result; +} + +- (BOOL)_onQueueUploadDataWithError:(NSError**)error +{ + dispatch_assert_queue(_queue); + + NSData* json = [self _onQueueGetLoggingJSONWithError:error]; + if (json && [self _onQueuePostJSON:json error:error]) { + secinfo("ckks", "uploading sync health data: %@", json); + + CKKSLoggerSQLiteStore* store = [CKKSLoggerSQLiteStore sharedStore]; + [store clearAllData]; + store.uploadDate = [NSDate dateWithTimeIntervalSinceNow:_secondsBetweenUploads]; + return YES; + } + else { + return NO; + } +} + +- (BOOL)_onQueuePostJSON:(NSData*)json error:(NSError**)error +{ + dispatch_assert_queue(_queue); + + /* + * Create the NSURLSession + * We use the ephemeral session config because we don't need cookies or cache + */ + NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + NSURLSession* postSession = [NSURLSession sessionWithConfiguration:defaultConfiguration + delegate:self + delegateQueue:nil]; + + /* + * Create the request + */ + NSURL* postEndpoint = self.splunkUploadURL; + if (!postEndpoint) { + secerror("failed to get a splunk upload endpoint - not uploading"); + return NO; + } + + NSMutableURLRequest* postRequest = [[NSMutableURLRequest alloc] init]; + postRequest.URL = postEndpoint; + postRequest.HTTPMethod = @"POST"; + postRequest.HTTPBody = json; + + /* + * Create the upload task. + */ + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + __block BOOL uploadSuccess = NO; + NSURLSessionDataTask* uploadTask = [postSession dataTaskWithRequest:postRequest + completionHandler:^(NSData * _Nullable __unused data, NSURLResponse * _Nullable response, NSError * _Nullable requestError) { + if(requestError) { + secerror("Error in uploading the events to splunk: %@", requestError); + } + else if (![response isKindOfClass:NSHTTPURLResponse.class]){ + Class class = response.class; + secerror("Received the wrong kind of response: %@", NSStringFromClass(class)); + } + else { + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; + if(httpResponse.statusCode >= 200 && httpResponse.statusCode < 300) { + /* Success */ + uploadSuccess = YES; + secnotice("ckks", "Splunk upload success"); + } + else { + secnotice("ckks", "Splunk upload unexpected status to URL: %@ -- status: %d", postEndpoint, (int)(httpResponse.statusCode)); + } + } + dispatch_semaphore_signal(sem); + }]; + + secnotice("ckks", "Splunk upload start"); + [uploadTask resume]; + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + return uploadSuccess; +} + +#define SECOND_PER_DAY (60 * 60 * 24) + +- (NSInteger)fuzzyDaysSinceDate:(NSDate*)date +{ + NSTimeInterval timeIntervalSinceDate = [[NSDate date] timeIntervalSinceDate:date]; + if (timeIntervalSinceDate < SECOND_PER_DAY) { + return 0; + } + else if (timeIntervalSinceDate < (SECOND_PER_DAY * 7)) { + return 1; + } + else if (timeIntervalSinceDate < (SECOND_PER_DAY * 30)) { + return 7; + } + else if (timeIntervalSinceDate < (SECOND_PER_DAY * 365)) { + return 30; + } + else { + return 365; + } +} + +- (NSData*)getLoggingJSONWithError:(NSError**)error +{ + __block NSData* json = nil; + dispatch_sync(_queue, ^{ + json = [self _onQueueGetLoggingJSONWithError:error]; + }); + + return json; +} + +- (NSData*)_onQueueGetLoggingJSONWithError:(NSError**)error +{ + dispatch_assert_queue(_queue); + + CKKSLoggerSQLiteStore* store = [CKKSLoggerSQLiteStore sharedStore]; + NSArray* failureRecords = [store failureRecords]; + + NSDictionary* successCounts = [store summaryCounts]; + NSInteger totalSuccessCount = 0; + NSInteger totalFailureCount = 0; + for (NSDictionary* perEventTypeSuccessCounts in successCounts.objectEnumerator) { + totalSuccessCount += [perEventTypeSuccessCounts[CKKSLoggerColumnSuccessCount] integerValue]; + totalFailureCount += [perEventTypeSuccessCounts[CKKSLoggerColumnFailureCount] integerValue]; + } + + NSDate* now = [NSDate date]; + + NSMutableDictionary* healthSummaryEvent = [[NSMutableDictionary alloc] init]; + healthSummaryEvent[CKKSLoggerSplunkTopic] = _splunkTopicName ?: [NSNull null]; + healthSummaryEvent[CKKSLoggerSplunkEventTime] = @([now timeIntervalSince1970] * 1000); + healthSummaryEvent[CKKSLoggerSplunkEventType] = @"manifestHealthSummary"; + healthSummaryEvent[CKKSLoggerColumnSuccessCount] = @(totalSuccessCount); + healthSummaryEvent[CKKSLoggerColumnFailureCount] = @(totalFailureCount); + healthSummaryEvent[CKKSLoggerMetricsBase] = _metricsBase ?: [NSDictionary dictionary]; + + for (NSString* viewName in [CKKSViewManager viewList]) { + CKKSKeychainView* view = [CKKSViewManager findOrCreateView:viewName]; + [healthSummaryEvent setValue:@([self fuzzyDaysSinceDate:[self _onQueueLastSuccessfulClassASyncDate]]) forKey:[NSString stringWithFormat:@"%@-%@", view.zoneName, CKKSLoggerDaysSinceLastSyncClassA]]; + [healthSummaryEvent setValue:@([self fuzzyDaysSinceDate:[self _onQueueLastSuccessfulClassCSyncDate]]) forKey:[NSString stringWithFormat:@"%@-%@", view.zoneName, CKKSLoggerDaysSinceLastSyncClassC]]; + } + + NSMutableArray* splunkRecords = failureRecords.mutableCopy; + [splunkRecords addObject:healthSummaryEvent]; + + NSDictionary* jsonDict = @{CKKSLoggerSplunkPostTime : @([now timeIntervalSince1970] * 1000), @"events" : splunkRecords}; + + return [NSJSONSerialization dataWithJSONObject:jsonDict options:NSJSONWritingPrettyPrinted error:error]; +} + +- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler { + assert(completionHandler); + (void)session; + secnotice("ckks", "Splunk upload challenge"); + NSURLCredential *cred = nil; + SecTrustResultType result = kSecTrustResultInvalid; + + if ([challenge previousFailureCount] > 0) { + // Previous failures occurred, bail + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + + } else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + /* + * Evaluate trust for the certificate + */ + + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + + OSStatus status = SecTrustEvaluate(serverTrust, &result); + if (status == errSecSuccess && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)) { + /* + * All is well, accept the credentials + */ + + cred = [NSURLCredential credentialForTrust:serverTrust]; + completionHandler(NSURLSessionAuthChallengeUseCredential, cred); + } else if (_allowInsecureSplunkCert) { + secnotice("ckks", "Force Accepting Splunk Credential"); + + cred = [NSURLCredential credentialForTrust:serverTrust]; + completionHandler(NSURLSessionAuthChallengeUseCredential, cred); + } else { + /* + * An error occurred in evaluating trust, bail + */ + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + } else { + /* + * Just perform the default handling + */ + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } + +} + +- (BOOL)ignoreServerDisablingMessages +{ + return _ignoreServersMessagesTellingUsToGoAway; +} + +- (void)setIgnoreServerDisablingMessages:(BOOL)ignoreServer +{ + _ignoreServersMessagesTellingUsToGoAway = ignoreServer ? YES : NO; +} + +@end + +@implementation CKKSLoggerSQLiteStore + ++ (instancetype)sharedStore +{ + static CKKSLoggerSQLiteStore* store = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + store = [[self alloc] initWithPath:CKKSLoggingTablePath() schema:CKKSLoggingTableSchema]; + [store open]; + }); + + return store; +} + +- (void)dealloc +{ + [self close]; +} + +- (NSInteger)successCountForEventType:(NSString*)eventType +{ + return [[[[self select:@[CKKSLoggerColumnSuccessCount] from:CKKSLoggerTableSuccessCount where:@"event_type = ?" bindings:@[eventType]] firstObject] valueForKey:CKKSLoggerColumnSuccessCount] integerValue]; +} + +- (void)incrementSuccessCountForEventType:(NSString*)eventType +{ + @try { + NSInteger successCount = [self successCountForEventType:eventType]; + NSInteger failureCount = [self failureCountForEventType:eventType]; + [self insertOrReplaceInto:CKKSLoggerTableSuccessCount values:@{CKKSLoggerColumnEventType : eventType, CKKSLoggerColumnSuccessCount : @(successCount + 1), CKKSLoggerColumnFailureCount : @(failureCount)}]; + } @catch (id ue) { + secerror("incrementSuccessCountForEventType exception: %@", ue); + } +} + +- (NSInteger)failureCountForEventType:(NSString*)eventType +{ + return [[[[self select:@[CKKSLoggerColumnFailureCount] from:CKKSLoggerTableSuccessCount where:@"event_type = ?" bindings:@[eventType]] firstObject] valueForKey:CKKSLoggerColumnFailureCount] integerValue]; +} + +- (void)incrementFailureCountForEventType:(NSString*)eventType +{ + @try { + NSInteger successCount = [self successCountForEventType:eventType]; + NSInteger failureCount = [self failureCountForEventType:eventType]; + [self insertOrReplaceInto:CKKSLoggerTableSuccessCount values:@{CKKSLoggerColumnEventType : eventType, CKKSLoggerColumnSuccessCount : @(successCount), CKKSLoggerColumnFailureCount : @(failureCount + 1)}]; + } @catch (id ue) { + secerror("incrementFailureCountForEventType exception: %@", ue); + } +} + +- (NSDictionary*)summaryCounts +{ + NSMutableDictionary* successCountsDict = [NSMutableDictionary dictionary]; + NSArray* rows = [self selectAllFrom:CKKSLoggerTableSuccessCount where:nil bindings:nil]; + for (NSDictionary* rowDict in rows) { + successCountsDict[rowDict[CKKSLoggerColumnEventType]] = @{CKKSLoggerColumnSuccessCount : rowDict[CKKSLoggerColumnSuccessCount], CKKSLoggerColumnFailureCount : rowDict[CKKSLoggerColumnFailureCount]}; + } + + return successCountsDict; +} + +- (NSArray*)failureRecords +{ + NSArray* recordBlobs = [self select:@[CKKSLoggerColumnData] from:CKKSLoggerTableFailures]; + + NSMutableArray* failureRecords = [[NSMutableArray alloc] init]; + for (NSDictionary* row in recordBlobs) { + NSDictionary* deserializedRecord = [NSPropertyListSerialization propertyListWithData:row[CKKSLoggerColumnData] options:0 format:nil error:nil]; + [failureRecords addObject:deserializedRecord]; + } + + return failureRecords; +} + +- (void)addFailureRecord:(NSDictionary*)valueDict +{ + @try { + NSError* error = nil; + NSData* serializedRecord = [NSPropertyListSerialization dataWithPropertyList:valueDict format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error]; + if(!error && serializedRecord) { + [self insertOrReplaceInto:CKKSLoggerTableFailures values:@{CKKSLoggerColumnData : serializedRecord}]; + } + if(error && !serializedRecord) { + secerror("Couldn't serialize failure record: %@", error); + } + } @catch (id ue) { + secerror("addFailureRecord exception: %@", ue); + } +} + +- (NSDate*)uploadDate +{ + return [self datePropertyForKey:CKKSLoggerUploadDate]; +} + +- (void)setUploadDate:(NSDate*)uploadDate +{ + [self setDateProperty:uploadDate forKey:CKKSLoggerUploadDate]; +} + +- (void)clearAllData +{ + [self deleteFrom:CKKSLoggerTableSuccessCount where:@"event_type like ?" bindings:@[@"%"]]; + [self deleteFrom:CKKSLoggerTableFailures where:@"id >= 0" bindings:nil]; +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSLogging.plist b/keychain/ckks/CKKSLogging.plist new file mode 100644 index 00000000..060222c3 --- /dev/null +++ b/keychain/ckks/CKKSLogging.plist @@ -0,0 +1,16 @@ + + + + + splunk_topic + xp_sear_keysync + splunk_allowInsecureCertificate + + splunk_bagURL + https://xp.apple.com/config/1/report/xp_sear_keysync + SyncManifests + + EnforceManifests + + + diff --git a/keychain/ckks/CKKSManifest.h b/keychain/ckks/CKKSManifest.h new file mode 100644 index 00000000..249f722f --- /dev/null +++ b/keychain/ckks/CKKSManifest.h @@ -0,0 +1,115 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "CKKSRecordHolder.h" +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +extern NSString* const CKKSManifestZoneKey; +extern NSString* const CKKSManifestSignerIDKey; +extern NSString* const CKKSManifestGenCountKey; + +@class CKKSManifestMasterRecord; +@class CKRecord; +@class CKKSItem; +@class CKKSCurrentItemPointer; + +@interface CKKSManifest : CKKSCKRecordHolder + +@property (readonly, class) NSUInteger greatestKnownGenerationCount; + +@property (nonatomic, readonly) NSData* digestValue; +@property (nonatomic, readonly) NSUInteger generationCount; +@property (nonatomic, readonly) NSString* signerID; + ++ (void)performWithAccountInfo:(void (^)(void))action; + ++ (bool)shouldSyncManifests; ++ (bool)shouldEnforceManifests; + ++ (nullable instancetype)manifestForZone:(NSString*)zone peerID:(NSString*)peerID error:(NSError**)error; ++ (nullable instancetype)manifestForRecordName:(NSString*)recordName error:(NSError**)error; ++ (nullable instancetype)latestTrustedManifestForZone:(NSString*)zone error:(NSError**)error; + +- (BOOL)updateWithRecord:(CKRecord*)record error:(NSError**)error; + +- (BOOL)validateWithError:(NSError**)error; +- (BOOL)validateItem:(CKKSItem*)item withError:(NSError**)error; +- (BOOL)validateCurrentItem:(CKKSCurrentItemPointer*)currentItem withError:(NSError**)error; +- (BOOL)itemUUIDExistsInManifest:(NSString*)uuid; +- (BOOL)contentsAreEqualToManifest:(CKKSManifest*)otherManifest; + +@end + +@interface CKKSPendingManifest : CKKSManifest + +@property (readonly, getter=isReadyToCommmit) BOOL readyToCommit; + +- (nullable CKKSManifest*)commitToDatabaseWithError:(NSError**)error; + +@end + +@interface CKKSEgoManifest : CKKSManifest + ++ (nullable CKKSEgoManifest*)tryCurrentEgoManifestForZone:(NSString*)zone; ++ (nullable instancetype)newManifestForZone:(NSString*)zone withItems:(NSArray*)items peerManifestIDs:(NSArray*)peerManifestIDs currentItems:(NSDictionary*)currentItems error:(NSError**)error; + +- (void)updateWithNewOrChangedRecords:(NSArray*)newOrChangedRecords deletedRecordIDs:(NSArray*)deletedRecordIDs; +- (void)setCurrentItemUUID:(NSString*)newCurrentItemUUID forIdentifier:(NSString*)currentPointerIdentifier; + +- (NSArray*)allCKRecordsWithZoneID:(CKRecordZoneID*)zoneID; + +@end + +// ---------------------------------------------------- +// Declarations for unit tests + +@class CKKSManifestInjectionPointHelper; + +@interface CKKSManifest (UnitTesting) + +- (void)nilAllIvars; + +@end + +@interface CKKSEgoManifest (UnitTesting) + ++ (nullable instancetype)newFakeManifestForZone:(NSString*)zone withItemRecords:(NSArray*)itemRecords currentItems:(NSDictionary*)currentItems signerID:(NSString*)signerID keyPair:(SFECKeyPair*)keyPair error:(NSError**)error; + +@end + +@interface CKKSManifestInjectionPointHelper : NSObject + +@property (class) BOOL ignoreChanges; // turn to YES to have changes to the database get ignored by CKKSManifest to support negative testing + ++ (void)registerEgoPeerID:(NSString*)egoPeerID keyPair:(SFECKeyPair*)keyPair; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/keychain/ckks/CKKSManifest.m b/keychain/ckks/CKKSManifest.m new file mode 100644 index 00000000..ff05f89d --- /dev/null +++ b/keychain/ckks/CKKSManifest.m @@ -0,0 +1,1450 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "CKKSManifest.h" +#import "CKKSManifestLeafRecord.h" +#import "CKKS.h" +#import "CKKSItem.h" +#import "CKKSCurrentItemPointer.h" +#import "CKKSAnalyticsLogger.h" +#import "utilities/der_plist.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import + +NSString* const CKKSManifestZoneKey = @"zone"; +NSString* const CKKSManifestSignerIDKey = @"signerID"; +NSString* const CKKSManifestGenCountKey = @"gencount"; + +static NSString* const CKKSManifestDigestKey = @"CKKSManifestDigestKey"; +static NSString* const CKKSManifestPeerManifestsKey = @"CKKSManifestPeerManifestsKey"; +static NSString* const CKKSManifestCurrentItemsKey = @"CKKSManifestCurrentItemsKey"; +static NSString* const CKKSManifestGenerationCountKey = @"CKKSManifestGenerationCountKey"; +static NSString* const CKKSManifestSchemaVersionKey = @"CKKSManifestSchemaVersionKey"; + +static NSString* const CKKSManifestEC384SignatureKey = @"CKKSManifestEC384SignatureKey"; + +static NSString* const CKKSManifestErrorDomain = @"CKKSManifestErrorDomain"; + +#define NUM_MANIFEST_LEAF_RECORDS 72 +#define BITS_PER_UUID_CHAR 36 + +static CKKSManifestInjectionPointHelper* __egoHelper = nil; +static NSMutableDictionary* __helpersDict = nil; +static BOOL __ignoreChanges = NO; + +enum { + CKKSManifestErrorInvalidDigest = 1, + CKKSManifestErrorVerifyingKeyNotFound = 2, + CKKSManifestErrorManifestGenerationFailed = 3, + CKKSManifestErrorCurrentItemUUIDNotFound = 4 +}; + +typedef NS_ENUM(NSInteger, CKKSManifestFieldType) { + CKKSManifestFieldTypeStringRaw = 0, + CKKSManifestFieldTypeStringBase64Encoded = 1, + CKKSManifestFieldTypeDataAsBase64String = 2, + CKKSManifestFieldTypeNumber = 3, + CKKSManifestFieldTypeArrayRaw = 4, + CKKSManifestFieldTypeArrayAsDERBase64String = 5, + CKKSManifestFieldTypeDictionaryAsDERBase64String = 6 +}; + +@interface CKKSAccountInfo : NSObject { + SFECKeyPair* _signingKey; + NSDictionary* _peerVerifyingKeys; + NSString* _egoPeerID; + NSError* _setupError; +} + +@property SFECKeyPair* signingKey; +@property NSDictionary* peerVerifyingKeys; +@property NSString* egoPeerID; +@property NSError* setupError; +@end + +static NSDictionary* __thisBuildsSchema = nil; +static CKKSAccountInfo* s_accountInfo = nil; + +@interface CKKSManifest () { +@package + NSData* _derData; + NSData* _digestValue; + NSUInteger _generationCount; + NSString* _signerID; + NSString* _zoneName; + NSArray* _leafRecordIDs; + NSArray* _peerManifestIDs; + NSMutableDictionary* _currentItemsDict; + NSDictionary* _futureData; + NSDictionary* _signaturesDict; + NSDictionary* _schema; + CKKSManifestInjectionPointHelper* _helper; +} + +@property (nonatomic, readonly) NSString* zoneName; +@property (nonatomic, readonly) NSArray* leafRecordIDs; +@property (nonatomic, readonly) NSArray* peerManifestIDs; +@property (nonatomic, readonly) NSDictionary* currentItems; +@property (nonatomic, readonly) NSDictionary* futureData; +@property (nonatomic, readonly) NSDictionary* signatures; +@property (nonatomic, readonly) NSDictionary* schema; + +@property (nonatomic, readwrite) NSString* signerID; +@property (nonatomic) CKKSManifestInjectionPointHelper* helper; + ++ (NSData*)digestValueForLeafRecords:(NSArray*)leafRecords; + +- (void)clearDigest; + +@end + +@interface CKKSPendingManifest () { + NSMutableArray* _committedLeafRecordIDs; +} + +@property (nonatomic, readonly) NSArray* committedLeafRecordIDs; + +@end + +@interface CKKSEgoManifest () { + NSArray* _leafRecords; +} + +@property (class, readonly) CKKSManifestInjectionPointHelper* egoHelper; + +@property (nonatomic, readwrite) NSDictionary* signatures; + +@end + +@interface CKKSManifestInjectionPointHelper () + +- (instancetype)initWithPeerID:(NSString*)peerID keyPair:(SFECKeyPair*)keyPair isEgoPeer:(BOOL)isEgoPeer; + +- (void)performWithSigningKey:(void (^)(SFECKeyPair* _Nullable signingKey, NSError* _Nullable error))handler; +- (void)performWithEgoPeerID:(void (^)(NSString* _Nullable egoPeerID, NSError* _Nullable error))handler; +- (void)performWithPeerVerifyingKeys:(void (^)(NSDictionary* _Nullable peerKeys, NSError* _Nullable error))handler; + +@end + +static NSData* ManifestDERData(NSString* zone, NSData* digestValue, NSArray* peerManifestIDs, NSDictionary* currentItems, NSUInteger generationCount, NSDictionary* futureFields, NSDictionary* schema, NSError** error) +{ + NSArray* sortedPeerManifestIDs = [peerManifestIDs sortedArrayUsingSelector:@selector(compare:)]; + + NSMutableDictionary* manifestDict = [NSMutableDictionary dictionary]; + manifestDict[CKKSManifestDigestKey] = digestValue; + manifestDict[CKKSManifestPeerManifestsKey] = sortedPeerManifestIDs; + manifestDict[CKKSManifestCurrentItemsKey] = currentItems; + manifestDict[CKKSManifestGenerationCountKey] = [NSNumber numberWithUnsignedInteger:generationCount]; + + [futureFields enumerateKeysAndObjectsUsingBlock:^(NSString* futureKey, id futureValue, BOOL* stop) { + CKKSManifestFieldType fieldType = [schema[futureKey] integerValue]; + if (fieldType == CKKSManifestFieldTypeStringRaw) { + manifestDict[futureKey] = futureValue; + } + else if (fieldType == CKKSManifestFieldTypeStringBase64Encoded) { + manifestDict[futureKey] = [[NSString alloc] initWithData:[[NSData alloc] initWithBase64EncodedString:futureValue options:0] encoding:NSUTF8StringEncoding]; + } + else if (fieldType == CKKSManifestFieldTypeDataAsBase64String) { + manifestDict[futureKey] = [[NSData alloc] initWithBase64EncodedString:futureValue options:0]; + } + else if (fieldType == CKKSManifestFieldTypeNumber) { + manifestDict[futureKey] = futureValue; + } + else if (fieldType == CKKSManifestFieldTypeArrayRaw) { + manifestDict[futureKey] = futureValue; + } + else if (fieldType == CKKSManifestFieldTypeArrayAsDERBase64String) { + manifestDict[futureKey] = (__bridge_transfer NSArray*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)[[NSData alloc] initWithBase64EncodedData:futureValue options:0], 0, NULL, NULL); + } + else if (fieldType == CKKSManifestFieldTypeDictionaryAsDERBase64String) { + manifestDict[futureKey] = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)[[NSData alloc] initWithBase64EncodedData:futureValue options:0], 0, NULL, NULL); + } + else { + ckkserrorwithzonename("ckksmanifest", zone, "unrecognized field type in future schema: %ld", (long)fieldType); + } + }]; + + CFErrorRef cfError = NULL; + NSData* derData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)manifestDict, &cfError); + if (cfError) { + ckkserrorwithzonename("ckksmanifest", zone, "error creating manifest der data: %@", cfError); + if (error) { + *error = (__bridge_transfer NSError*)cfError; + } + return nil; + } + + return derData; +} + +static NSUInteger LeafBucketIndexForUUID(NSString* uuid) +{ + NSInteger prefixIntegerValue = 0; + for (NSInteger characterIndex = 0; characterIndex * BITS_PER_UUID_CHAR < NUM_MANIFEST_LEAF_RECORDS; characterIndex++) { + prefixIntegerValue += [uuid characterAtIndex:characterIndex]; + } + + return prefixIntegerValue % NUM_MANIFEST_LEAF_RECORDS; +} + +@implementation CKKSManifest + +@synthesize zoneName = _zoneName; +@synthesize leafRecordIDs = _leafRecordIDs; +@synthesize peerManifestIDs = _peerManifestIDs; +@synthesize currentItems = _currentItemsDict; +@synthesize futureData = _futureData; +@synthesize signatures = _signaturesDict; +@synthesize signerID = _signerID; +@synthesize schema = _schema; +@synthesize helper = _helper; + ++ (void)initialize +{ + if (self == [CKKSManifest class]) { + __thisBuildsSchema = @{ CKKSManifestSchemaVersionKey : @(1), + SecCKRecordManifestDigestValueKey : @(CKKSManifestFieldTypeDataAsBase64String), + SecCKRecordManifestGenerationCountKey : @(CKKSManifestFieldTypeNumber), + SecCKRecordManifestLeafRecordIDsKey : @(CKKSManifestFieldTypeArrayRaw), + SecCKRecordManifestPeerManifestRecordIDsKey : @(CKKSManifestFieldTypeArrayRaw), + SecCKRecordManifestCurrentItemsKey : @(CKKSManifestFieldTypeDictionaryAsDERBase64String), + SecCKRecordManifestSignaturesKey : @(CKKSManifestFieldTypeDictionaryAsDERBase64String), + SecCKRecordManifestSignerIDKey : @(CKKSManifestFieldTypeStringRaw), + SecCKRecordManifestSchemaKey : @(CKKSManifestFieldTypeDictionaryAsDERBase64String) }; + } +} + ++ (void)loadDefaults +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSDictionary* systemDefaults = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle bundleWithPath:@"/System/Library/Frameworks/Security.framework"] pathForResource:@"CKKSLogging" ofType:@"plist"]]; + bool shouldSync = !![[systemDefaults valueForKey:@"SyncManifests"] boolValue]; + bool shouldEnforce = !![[systemDefaults valueForKey:@"EnforceManifests"] boolValue]; + + NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:SecCKKSUserDefaultsSuite]; + bool userDefaultsShouldSync = !![defaults boolForKey:@"SyncManifests"]; + bool userDefaultsShouldEnforce = !![defaults boolForKey:@"EnforceManifests"]; + shouldSync |= userDefaultsShouldSync; + shouldEnforce |= userDefaultsShouldEnforce; + + if(shouldSync) { + SecCKKSEnableSyncManifests(); + } + if(shouldEnforce) { + SecCKKSEnableEnforceManifests(); + } + }); +} + ++ (bool)shouldSyncManifests +{ + [self loadDefaults]; + return SecCKKSSyncManifests(); +} + ++ (bool)shouldEnforceManifests +{ + [self loadDefaults]; + return SecCKKSEnforceManifests(); +} + ++ (void)performWithAccountInfo:(void (^)(void))action +{ + CKKSAccountInfo* accountInfo = [[CKKSAccountInfo alloc] init]; + + [[CKKSEgoManifest egoHelper] performWithSigningKey:^(_SFECKeyPair* signingKey, NSError* error) { + accountInfo.signingKey = signingKey; + if(error) { + secerror("ckksmanifest: cannot get signing key from account: %@", error); + if(accountInfo.setupError == nil) { + accountInfo.setupError = error; + } + } + }]; + + [[CKKSEgoManifest egoHelper] performWithEgoPeerID:^(NSString* egoPeerID, NSError* error) { + accountInfo.egoPeerID = egoPeerID; + + if(error) { + secerror("ckksmanifest: cannot get ego peer ID from account: %@", error); + if(accountInfo.setupError == nil) { + accountInfo.setupError = error; + } + } + }]; + + [[CKKSEgoManifest egoHelper] performWithPeerVerifyingKeys:^(NSDictionary* peerKeys, NSError* error) { + accountInfo.peerVerifyingKeys = peerKeys; + if(error) { + secerror("ckksmanifest: cannot get peer keys from account: %@", error); + if(accountInfo.setupError == nil) { + accountInfo.setupError = error; + } + } + }]; + + s_accountInfo = accountInfo; + + action(); + + s_accountInfo = nil; +} + ++ (nullable instancetype)tryFromDatabaseWhere:(NSDictionary*)whereDict error:(NSError* __autoreleasing *)error +{ + CKKSManifest* manifest = [super tryFromDatabaseWhere:whereDict error:error]; + manifest.helper = __helpersDict[manifest.signerID]; + return manifest; +} + ++ (nullable instancetype)manifestForZone:(NSString*)zone peerID:(NSString*)peerID error:(NSError**)error +{ + NSDictionary* databaseWhereClause = @{ @"ckzone" : zone, @"signerID" : peerID }; + return [self tryFromDatabaseWhere:databaseWhereClause error:error]; +} + ++ (nullable instancetype)manifestForRecordName:(NSString*)recordName error:(NSError**)error +{ + return [self tryFromDatabaseWhere:[self whereClauseForRecordName:recordName] error:error]; +} + ++ (nullable instancetype)latestTrustedManifestForZone:(NSString*)zone error:(NSError**)error +{ + NSDictionary* databaseWhereClause = @{ @"ckzone" : zone }; + NSArray* manifests = [[self allWhere:databaseWhereClause error:error] sortedArrayUsingComparator:^NSComparisonResult(CKKSManifest* _Nonnull firstManifest, CKKSManifest* _Nonnull secondManifest) { + NSInteger firstGenerationCount = firstManifest.generationCount; + NSInteger secondGenerationCount = secondManifest.generationCount; + + if (firstGenerationCount > secondGenerationCount) { + return NSOrderedDescending; + } + else if (firstGenerationCount < secondGenerationCount) { + return NSOrderedAscending; + } + else { + return NSOrderedSame; + } + }]; + + __block CKKSManifest* result = nil; + [manifests enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(CKKSManifest* _Nonnull manifest, NSUInteger index, BOOL* _Nonnull stop) { + if ([manifest validateWithError:nil]) { + result = manifest; + *stop = YES; + } + }]; + + // TODO: add error for when we didn't find anything + return result; +} + ++ (SFEC_X962SigningOperation*)signatureOperation +{ + SFECKeySpecifier* keySpecifier = [[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]; + return [[SFEC_X962SigningOperation alloc] initWithKeySpecifier:keySpecifier digestOperation:[[SFSHA384DigestOperation alloc] init]]; +} + ++ (NSData*)digestForData:(NSData*)data +{ + return [SFSHA384DigestOperation digest:data]; +} + ++ (NSData*)digestValueForLeafRecords:(NSArray*)leafRecords +{ + NSMutableData* concatenatedLeafNodeDigestData = [[NSMutableData alloc] init]; + for (CKKSManifestLeafRecord* leafRecord in leafRecords) { + [concatenatedLeafNodeDigestData appendData:leafRecord.digestValue]; + } + + return [self digestForData:concatenatedLeafNodeDigestData]; +} + ++ (instancetype)manifestForPendingManifest:(CKKSPendingManifest*)pendingManifest +{ + return [[self alloc] initWithDigestValue:pendingManifest.digestValue zone:pendingManifest.zoneName generationCount:pendingManifest.generationCount leafRecordIDs:pendingManifest.committedLeafRecordIDs peerManifestIDs:pendingManifest.peerManifestIDs currentItems:pendingManifest.currentItems futureData:pendingManifest.futureData signatures:pendingManifest.signatures signerID:pendingManifest.signerID schema:pendingManifest.schema encodedRecord:pendingManifest.encodedCKRecord]; +} + ++ (instancetype)fromDatabaseRow:(NSDictionary*)row +{ + NSString* digestBase64String = row[@"digest"]; + NSData* digest = [digestBase64String isKindOfClass:[NSString class]] ? [[NSData alloc] initWithBase64EncodedString:digestBase64String options:0] : nil; + + NSString* zone = row[@"ckzone"]; + NSUInteger generationCount = [row[@"gencount"] integerValue]; + NSString* signerID = row[@"signerID"]; + + NSString* encodedRecordBase64String = row[@"ckrecord"]; + NSData* encodedRecord = [encodedRecordBase64String isKindOfClass:[NSString class]] ? [[NSData alloc] initWithBase64EncodedString:encodedRecordBase64String options:0] : nil; + + NSData* leafRecordIDData = [[NSData alloc] initWithBase64EncodedString:row[@"leafIDs"] options:0]; + NSArray* leafRecordIDs = (__bridge_transfer NSArray*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)leafRecordIDData, 0, NULL, NULL); + if (![leafRecordIDs isKindOfClass:[NSArray class]]) { + leafRecordIDs = [NSArray array]; + } + + NSData* peerManifestIDData = [[NSData alloc] initWithBase64EncodedString:row[@"peerManifests"] options:0]; + NSArray* peerManifestIDs = (__bridge_transfer NSArray*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)peerManifestIDData, 0, NULL, NULL); + if (![peerManifestIDs isKindOfClass:[NSArray class]]) { + peerManifestIDs = [NSArray array]; + } + + NSData* currentItemsData = [[NSData alloc] initWithBase64EncodedString:row[@"currentItems"] options:0]; + NSDictionary* currentItemsDict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)currentItemsData, 0, NULL, NULL); + if (![currentItemsDict isKindOfClass:[NSDictionary class]]) { + currentItemsDict = [NSDictionary dictionary]; + } + + NSData* futureData = [[NSData alloc] initWithBase64EncodedString:row[@"futureData"] options:0]; + NSDictionary* futureDataDict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)futureData, 0, NULL, NULL); + if (![futureDataDict isKindOfClass:[NSDictionary class]]) { + futureDataDict = [NSDictionary dictionary]; + } + + NSData* signaturesData = [[NSData alloc] initWithBase64EncodedString:row[@"signatures"] options:0]; + NSDictionary* signatures = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)signaturesData, 0, NULL, NULL); + if (![signatures isKindOfClass:[NSDictionary class]]) { + signatures = [NSDictionary dictionary]; + } + + NSData* schemaData = [[NSData alloc] initWithBase64EncodedString:row[@"schema"] options:0]; + NSDictionary* schemaDict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)schemaData, 0, NULL, NULL); + if (![schemaDict isKindOfClass:[NSDictionary class]]) { + schemaDict = __thisBuildsSchema; + } + + return [[self alloc] initWithDigestValue:digest zone:zone generationCount:generationCount leafRecordIDs:leafRecordIDs peerManifestIDs:peerManifestIDs currentItems:currentItemsDict futureData:futureDataDict signatures:signatures signerID:signerID schema:schemaDict encodedRecord:encodedRecord]; +} + ++ (NSArray*)sqlColumns +{ + return @[@"ckzone", @"gencount", @"digest", @"signatures", @"signerID", @"leafIDs", @"peerManifests", @"currentItems", @"futureData", @"schema", @"ckrecord"]; +} + ++ (NSString*)sqlTable +{ + return @"ckmanifest"; +} + ++ (NSUInteger)greatestKnownGenerationCount +{ + __block NSUInteger result = 0; + [self queryMaxValueForField:@"gencount" inTable:self.sqlTable where:nil columns:@[@"gencount"] processRow:^(NSDictionary* row) { + result = [row[@"gencount"] integerValue]; + }]; + + [CKKSPendingManifest queryMaxValueForField:@"gencount" inTable:[CKKSPendingManifest sqlTable] where:nil columns:@[@"gencount"] processRow:^(NSDictionary* row) { + result = MAX(result, (NSUInteger)[row[@"gencount"] integerValue]); + }]; + + return result; +} + +- (instancetype)initWithDigestValue:(NSData*)digestValue zone:(NSString*)zone generationCount:(NSUInteger)generationCount leafRecordIDs:(NSArray*)leafRecordIDs peerManifestIDs:(NSArray*)peerManifestIDs currentItems:(NSDictionary*)currentItems futureData:(NSDictionary*)futureData signatures:(NSDictionary*)signatures signerID:(NSString*)signerID schema:(NSDictionary*)schema helper:(CKKSManifestInjectionPointHelper*)helper +{ + if (self = [super init]) { + _digestValue = digestValue; + _zoneName = zone; + _generationCount = generationCount; + _leafRecordIDs = [leafRecordIDs copy]; + _currentItemsDict = currentItems ? [currentItems mutableCopy] : [NSMutableDictionary dictionary]; + _futureData = futureData ? [futureData copy] : @{}; + _signaturesDict = [signatures copy]; + _signerID = signerID; + _schema = schema ? schema.copy : __thisBuildsSchema; + + if ([peerManifestIDs.firstObject isEqualToString:signerID]) { + _peerManifestIDs = peerManifestIDs; + } + else { + NSMutableArray* tempPeerManifests = [[NSMutableArray alloc] initWithObjects:signerID, nil]; + if (peerManifestIDs) { + [tempPeerManifests addObjectsFromArray:peerManifestIDs]; + } + _peerManifestIDs = tempPeerManifests; + } + + _helper = helper ?: [self defaultHelperForSignerID:signerID]; + if (!_helper) { + _helper = [[CKKSManifestInjectionPointHelper alloc] init]; + } + } + + return self; +} + +- (instancetype)initWithDigestValue:(NSData*)digestValue zone:(NSString*)zone generationCount:(NSUInteger)generationCount leafRecordIDs:(NSArray*)leafRecordIDs peerManifestIDs:(NSArray*)peerManifestIDs currentItems:(NSDictionary*)currentItems futureData:(NSDictionary*)futureData signatures:(NSDictionary*)signatures signerID:(NSString*)signerID schema:(NSDictionary*)schema +{ + return [self initWithDigestValue:digestValue zone:zone generationCount:generationCount leafRecordIDs:leafRecordIDs peerManifestIDs:peerManifestIDs currentItems:currentItems futureData:futureData signatures:signatures signerID:signerID schema:schema helper:nil]; +} + +- (instancetype)initWithDigestValue:(NSData*)digestValue zone:(NSString*)zone generationCount:(NSUInteger)generationCount leafRecordIDs:(NSArray*)leafRecordIDs peerManifestIDs:(NSArray*)peerManifestIDs currentItems:(NSDictionary*)currentItems futureData:(NSDictionary*)futureData signatures:(NSDictionary*)signatures signerID:(NSString*)signerID schema:(NSDictionary*)schema encodedRecord:(NSData*)encodedRecord +{ + if (self = [self initWithDigestValue:digestValue zone:zone generationCount:generationCount leafRecordIDs:leafRecordIDs peerManifestIDs:peerManifestIDs currentItems:currentItems futureData:futureData signatures:signatures signerID:signerID schema:schema]) { + self.encodedCKRecord = encodedRecord; + } + + return self; +} + +- (instancetype)initWithCKRecord:(CKRecord*)record +{ + NSError* error = nil; + NSString* signatureBase64String = record[SecCKRecordManifestSignaturesKey]; + if (!signatureBase64String) { + ckkserror("ckksmanifest", record.recordID.zoneID, "attempt to create manifest from CKRecord that does not have signatures attached: %@", record); + [[CKKSAnalyticsLogger logger] logHardFailureForEventNamed:@"CKKSManifestCreateFromCKRecord" withAttributes:@{CKKSManifestZoneKey : record.recordID.zoneID.zoneName}]; + return nil; + } + NSData* signatureDERData = [[NSData alloc] initWithBase64EncodedString:signatureBase64String options:0]; + NSDictionary* signaturesDict = [self signatureDictFromDERData:signatureDERData error:&error]; + if (error) { + ckkserror("ckksmanifest", record.recordID.zoneID, "failed to initialize CKKSManifest from CKRecord because we could not form a signature dict from the record: %@", record); + [[CKKSAnalyticsLogger logger] logHardFailureForEventNamed:@"CKKSManifestCreateFromCKRecord" withAttributes:@{CKKSManifestZoneKey : record.recordID.zoneID.zoneName}]; + return nil; + } + + NSDictionary* schemaDict = nil; + NSString* schemaBase64String = record[SecCKRecordManifestSchemaKey]; + if (schemaBase64String) { + NSData* schemaData = [[NSData alloc] initWithBase64EncodedString:schemaBase64String options:0]; + schemaDict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)schemaData, 0, NULL, NULL); + } + if (![schemaDict isKindOfClass:[NSDictionary class]]) { + schemaDict = __thisBuildsSchema; + } + + NSString* digestBase64String = record[SecCKRecordManifestDigestValueKey]; + if (!digestBase64String) { + ckkserror("ckksmanifest", record.recordID.zoneID, "attempt to create manifest from CKRecord that does not have a digest attached: %@", record); + [[CKKSAnalyticsLogger logger] logHardFailureForEventNamed:@"CKKSManifestCreateFromCKRecord" withAttributes:@{CKKSManifestZoneKey : record.recordID.zoneID.zoneName}]; + return nil; + } + NSData* digestData = [[NSData alloc] initWithBase64EncodedString:digestBase64String options:0]; + + if (self = [self initWithDigestValue:digestData + zone:record.recordID.zoneID.zoneName + generationCount:[record[SecCKRecordManifestGenerationCountKey] unsignedIntegerValue] + leafRecordIDs:record[SecCKRecordManifestLeafRecordIDsKey] + peerManifestIDs:record[SecCKRecordManifestPeerManifestRecordIDsKey] + currentItems:record[SecCKRecordManifestCurrentItemsKey] + futureData:[self futureDataDictFromRecord:record withSchema:schemaDict] + signatures:signaturesDict + signerID:record[SecCKRecordManifestSignerIDKey] + schema:schemaDict]) { + self.storedCKRecord = record; + [[CKKSAnalyticsLogger logger] logSuccessForEventNamed:@"CKKSManifestCreateFromCKRecord"]; + } + else { + [[CKKSAnalyticsLogger logger] logHardFailureForEventNamed:@"CKKSManifestCreateFromCKRecord" withAttributes:@{CKKSManifestZoneKey : record.recordID.zoneID.zoneName}]; + } + + return self; +} + +- (CKKSManifestInjectionPointHelper*)defaultHelperForSignerID:(NSString*)signerID +{ + return __helpersDict[signerID]; +} + +- (NSDictionary*)signatureDictFromDERData:(NSData*)derData error:(NSError**)error +{ + CFErrorRef localError = NULL; + NSDictionary* signaturesDict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)derData, 0, NULL, &localError); + if (![signaturesDict isKindOfClass:[NSDictionary class]]) { + ckkserror("ckksmanifest", self, "failed to decode signatures der dict with error: %@", localError); + if (error) { + *error = (__bridge_transfer NSError*)localError; + } + } + + return signaturesDict; +} + +- (NSData*)derDataFromSignatureDict:(NSDictionary*)signatureDict error:(NSError**)error +{ + CFErrorRef localError = NULL; + NSData* derData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFPropertyListRef)signatureDict, &localError); + if (!derData) { + ckkserror("ckksmanifest", self, "failed to encode signatures dict to der with error: %@", localError); + if (error) { + *error = (__bridge_transfer NSError*)localError; + } + } + + return derData; +} + +- (NSArray*)peerManifestsFromDERData:(NSData*)derData error:(NSError**)error +{ + CFErrorRef localError = NULL; + NSArray* peerManifests = (__bridge_transfer NSArray*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)derData, 0, NULL, &localError); + if (![peerManifests isKindOfClass:[NSArray class]]) { + ckkserror("ckksmanifest", self, "failed to decode peer manifests der array with error: %@", localError); + if (error) { + *error = (__bridge_transfer NSError*)localError; + } + } + + return peerManifests; +} + +- (NSData*)derDataFromPeerManifests:(NSArray*)peerManifests error:(NSError**)error +{ + CFErrorRef localError = NULL; + NSData* derData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFPropertyListRef)peerManifests, &localError); + if (!derData) { + ckkserror("ckksmanifest", self, "failed to encode peer manifests to der with error: %@", localError); + if (error) { + *error = (__bridge_transfer NSError*)localError; + } + } + + return derData; +} + +- (NSDictionary*)futureDataDictFromRecord:(CKRecord*)record withSchema:(NSDictionary*)cloudSchema +{ + NSMutableDictionary* futureData = [NSMutableDictionary dictionary]; + [cloudSchema enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSData* obj, BOOL* stop) { + if (![__thisBuildsSchema.allKeys containsObject:key]) { + futureData[key] = record[key]; + } + }]; + + return futureData; +} + +- (BOOL)updateWithRecord:(CKRecord*)record error:(NSError**)error +{ + if ([CKKSManifestInjectionPointHelper ignoreChanges]) { + return YES; // don't set off any alarms here - just pretend we did it + } + + NSData* signatureDERData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestSignaturesKey] options:0]; + NSDictionary* signaturesDict = [self signatureDictFromDERData:signatureDERData error:error]; + if (!signaturesDict) { + return NO; + } + + NSData* cloudSchemaData = record[SecCKRecordManifestSchemaKey]; + NSDictionary* cloudSchemaDict = (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)cloudSchemaData, 0, NULL, NULL); + if (![cloudSchemaDict isKindOfClass:[NSDictionary class]]) { + cloudSchemaDict = __thisBuildsSchema; + } + + _digestValue = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestDigestValueKey] options:0]; + _generationCount = [record[SecCKRecordManifestGenerationCountKey] unsignedIntegerValue]; + _leafRecordIDs = record[SecCKRecordManifestLeafRecordIDsKey]; + _peerManifestIDs = record[SecCKRecordManifestPeerManifestRecordIDsKey]; + _currentItemsDict = [record[SecCKRecordManifestCurrentItemsKey] mutableCopy]; + if (!_currentItemsDict) { + _currentItemsDict = [NSMutableDictionary dictionary]; + } + _futureData = [[self futureDataDictFromRecord:record withSchema:cloudSchemaDict] copy]; + _signaturesDict = signaturesDict; + _signerID = record[SecCKRecordManifestSignerIDKey]; + _schema = cloudSchemaDict; + self.storedCKRecord = record; + + _derData = nil; + return YES; +} + +- (NSDictionary*)sqlValues +{ + 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); + } + + dictionary[key] = value; + }; + + NSMutableDictionary* sqlValues = [[NSMutableDictionary alloc] init]; + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"ckzone", _zoneName); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"gencount", [NSNumber numberWithUnsignedInteger:_generationCount]); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"digest", self.digestValue); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"signatures", [[self derDataFromSignatureDict:self.signatures error:nil] base64EncodedStringWithOptions:0]); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"signerID", _signerID); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"leafIDs", [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFPropertyListRef)_leafRecordIDs, NULL) base64EncodedStringWithOptions:0]); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"peerManifests", [[self derDataFromPeerManifests:_peerManifestIDs error:nil] base64EncodedStringWithOptions:0]); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"currentItems", [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFPropertyListRef)_currentItemsDict, NULL) base64EncodedStringWithOptions:0]); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"futureData", [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFPropertyListRef)_futureData, NULL) base64EncodedStringWithOptions:0]); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"schema", [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFPropertyListRef)_schema, NULL) base64EncodedStringWithOptions:0]); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"ckrecord", [self.encodedCKRecord base64EncodedStringWithOptions:0]); + + return sqlValues; +} + +- (NSDictionary*)whereClauseToFindSelf +{ + return @{ @"ckzone" : CKKSNilToNSNull(_zoneName), + @"gencount" : [NSNumber numberWithUnsignedInteger:_generationCount], + @"signerID" : CKKSNilToNSNull(_signerID) }; +} + +- (NSString*)CKRecordName +{ + return [NSString stringWithFormat:@"Manifest:-:%@:-:%@:-:%lu", _zoneName, _signerID, (unsigned long)_generationCount]; +} + ++ (NSDictionary*)whereClauseForRecordName:(NSString*)recordName +{ + NSArray* components = [recordName componentsSeparatedByString:@":-:"]; + if (components.count < 4) { + secerror("CKKSManifest: could not parse components from record name: %@", recordName); + } + + return @{ @"ckzone" : components[1], + @"signerID" : components[2], + @"gencount" : components[3] }; +} + +- (CKRecord*)updateCKRecord:(CKRecord*)record zoneID:(CKRecordZoneID*)zoneID +{ + if (![record.recordType isEqualToString:SecCKRecordManifestType]) { + @throw [NSException exceptionWithName:@"WrongCKRecordTypeException" reason:[NSString stringWithFormat:@"CKRecorType (%@) was not %@", record.recordType, SecCKRecordManifestType] userInfo:nil]; + } + + NSData* signatureDERData = [self derDataFromSignatureDict:self.signatures error:nil]; + if (!signatureDERData) { + [[CKKSAnalyticsLogger logger] logHardFailureForEventNamed:@"CKKSManifestUpdateRecord" withAttributes:@{CKKSManifestZoneKey : zoneID.zoneName, CKKSManifestSignerIDKey : _signerID, CKKSManifestGenCountKey : @(_generationCount)}]; + return record; + } + + record[SecCKRecordManifestDigestValueKey] = [self.digestValue base64EncodedStringWithOptions:0]; + record[SecCKRecordManifestGenerationCountKey] = [NSNumber numberWithUnsignedInteger:_generationCount]; + record[SecCKRecordManifestLeafRecordIDsKey] = _leafRecordIDs; + record[SecCKRecordManifestPeerManifestRecordIDsKey] = _peerManifestIDs; + record[SecCKRecordManifestCurrentItemsKey] = [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)_currentItemsDict, NULL) base64EncodedStringWithOptions:0]; + record[SecCKRecordManifestSignaturesKey] = [signatureDERData base64EncodedStringWithOptions:0]; + record[SecCKRecordManifestSignerIDKey] = _signerID; + record[SecCKRecordManifestSchemaKey] = [(__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFDictionaryRef)_schema, NULL) base64EncodedStringWithOptions:0]; + + [_futureData enumerateKeysAndObjectsUsingBlock:^(NSString* key, id futureField, BOOL* stop) { + record[key] = futureField; + }]; + + [[CKKSAnalyticsLogger logger] logSuccessForEventNamed:@"CKKSManifestUpdateRecord"]; + return record; +} + +- (bool)matchesCKRecord:(CKRecord*)record +{ + if (![record.recordType isEqualToString:SecCKRecordManifestType]) { + return false; + } + + NSError* error = nil; + NSData* signatureDERData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestSignaturesKey] options:0]; + NSDictionary* signaturesDict = [self signatureDictFromDERData:signatureDERData error:&error]; + if (!signaturesDict || error) { + return NO; + } + + NSData* digestData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestDigestValueKey] options:0]; + return [digestData isEqual:self.digestValue] && + [record[SecCKRecordManifestGenerationCountKey] unsignedIntegerValue] == _generationCount && + [record[SecCKRecordManifestPeerManifestRecordIDsKey] isEqual:_peerManifestIDs] && + [signaturesDict isEqual:self.signatures] && + [record[SecCKRecordManifestSignerIDKey] isEqual:_signerID]; +} + +- (void)setFromCKRecord:(CKRecord*)record +{ + NSError* error = nil; + if (![self updateWithRecord:record error:&error]) { + ckkserror("ckksmanifest", self, "failed to update manifest from CKRecord with error: %@", error); + } +} + +- (NSData*)derData +{ + if (!_derData) { + NSError* error = nil; + _derData = ManifestDERData(_zoneName, self.digestValue, _peerManifestIDs, _currentItemsDict, _generationCount, _futureData, _schema, &error); + if (error) { + ckkserror("ckksmanifest", self, "error encoding manifest into DER: %@", error); + _derData = nil; + } + } + + return _derData; +} + +- (BOOL)validateWithError:(NSError**)error +{ + __block BOOL verified = false; + NSData* manifestDerData = self.derData; + if (manifestDerData) { + __block NSError* localError = nil; + + [_helper performWithPeerVerifyingKeys:^(NSDictionary* _Nullable peerKeys, NSError* _Nullable error) { + if(error) { + ckkserror("ckksmanifest", self, "Error fetching peer verifying keys: %@", error); + } + SFECPublicKey* verifyingKey = peerKeys[self->_signerID]; + if (verifyingKey) { + SFEC_X962SigningOperation* signingOperation = [self.class signatureOperation]; + SFSignedData* signedData = [[SFSignedData alloc] initWithData:manifestDerData signature:self.signatures[CKKSManifestEC384SignatureKey]]; + verified = [signingOperation verify:signedData withKey:verifyingKey error:&localError] == NULL ? false : true; + + } + else { + localError = [NSError errorWithDomain:CKKSManifestErrorDomain + code:CKKSManifestErrorVerifyingKeyNotFound + userInfo:@{NSLocalizedDescriptionKey : [NSString localizedStringWithFormat:@"could not find manifest public key for peer %@", self->_signerID], + NSUnderlyingErrorKey: CKKSNilToNSNull(error)}]; + } + }]; + + if (error) { + *error = localError; + } + } + + if (verified) { + [[CKKSAnalyticsLogger logger] logSuccessForEventNamed:@"CKKSManifestValidateSelf"]; + } + else { + [[CKKSAnalyticsLogger logger] logSoftFailureForEventNamed:@"CKKSManifestValidateSelf" withAttributes:@{CKKSManifestZoneKey : _zoneName, CKKSManifestSignerIDKey : _signerID, CKKSManifestGenerationCountKey : @(_generationCount)}]; + } + + return verified; +} + +- (BOOL)validateItem:(CKKSItem*)item withError:(NSError**)error +{ + NSString* uuid = item.uuid; + CKKSManifestLeafRecord* leafRecord = [self leafRecordForItemUUID:uuid]; + NSData* expectedItemDigest = leafRecord.recordDigestDict[uuid]; + if ([[self.class digestForData:item.encitem] isEqual:expectedItemDigest]) { + return YES; + } + else if (error) { + *error = [NSError errorWithDomain:CKKSManifestErrorDomain code:CKKSManifestErrorInvalidDigest userInfo:@{NSLocalizedDescriptionKey : @"could not validate item because the digest is invalid"}]; + } + + return NO; +} + +- (BOOL)validateCurrentItem:(CKKSCurrentItemPointer*)currentItem withError:(NSError**)error +{ + BOOL result = [currentItem.currentItemUUID isEqualToString:[_currentItemsDict valueForKey:currentItem.identifier]]; + if (!result && error) { + *error = [NSError errorWithDomain:CKKSManifestErrorDomain code:CKKSManifestErrorCurrentItemUUIDNotFound userInfo:@{NSLocalizedDescriptionKey :@"could not validate current item because the UUID does not match the manifest"}]; + } + + return result; +} + +- (BOOL)itemUUIDExistsInManifest:(NSString*)uuid +{ + CKKSManifestLeafRecord* leafRecord = [self leafRecordForItemUUID:uuid]; + return leafRecord.recordDigestDict[uuid] != nil; +} + +- (BOOL)contentsAreEqualToManifest:(CKKSManifest*)otherManifest +{ + return [_digestValue isEqual:otherManifest.digestValue]; +} + +- (CKKSManifestLeafRecord*)leafRecordForID:(NSString*)leafRecordID +{ + NSError* error = nil; + CKKSManifestLeafRecord* leafRecord = [CKKSManifestLeafRecord leafRecordForID:leafRecordID error:&error]; + if (error || !leafRecord) { + ckkserror("ckksmanifest", self, "failed to lookup manifest leaf record with id: %@ error: %@", leafRecordID, error); + } + + return leafRecord; +} + +- (CKKSManifestLeafRecord*)leafRecordForItemUUID:(NSString*)uuid +{ + NSInteger bucketIndex = LeafBucketIndexForUUID(uuid); + NSString* leafRecordID = _leafRecordIDs[bucketIndex]; + return [self leafRecordForID:leafRecordID]; +} + +- (void)clearDigest +{ + _digestValue = nil; + _derData = nil; + _signaturesDict = nil; +} + +- (NSData*)digestValue +{ + if (!_digestValue) { + _digestValue = [self.class digestValueForLeafRecords:self.leafRecords]; + } + + return _digestValue; +} + +- (NSArray*)leafRecords +{ + NSMutableArray* leafRecords = [[NSMutableArray alloc] initWithCapacity:_leafRecordIDs.count]; + for (NSString* recordID in _leafRecordIDs) { + CKKSManifestLeafRecord* leafRecord = [self leafRecordForID:recordID]; + if(leafRecord) { + [leafRecords addObject:leafRecord]; + } else { + ckkserror("ckksmanifest", self, "failed to fetch leaf record from CKManifest for %@", recordID); + // TODO: auto bug capture? + } + } + + return leafRecords; +} + +- (NSString*)ckRecordType +{ + return SecCKRecordManifestType; +} + +- (void)nilAllIvars +{ + _derData = nil; + _digestValue = nil; + _signerID = nil; + _zoneName = nil; + _leafRecordIDs = nil; + _peerManifestIDs = nil; + _currentItemsDict = nil; + _futureData = nil; + _signaturesDict = nil; + _schema = nil; +} + +@end + +@implementation CKKSPendingManifest + +@synthesize committedLeafRecordIDs = _committedLeafRecordIDs; + ++ (NSString*)sqlTable +{ + return @"pending_manifest"; +} + +- (BOOL)isReadyToCommit +{ + for (NSString* leafRecordID in self.leafRecordIDs) { + if ([CKKSManifestLeafRecord recordExistsForID:leafRecordID] || [CKKSManifestPendingLeafRecord recordExistsForID:leafRecordID]) { + continue; + } + else { + ckksinfo("ckksmanifest", self, "Not ready to commit manifest, yet - missing leaf record ID: %@", leafRecordID); + return NO; + } + } + + return YES; +} + +- (CKKSManifest*)commitToDatabaseWithError:(NSError**)error +{ + NSError* localError = nil; + + _committedLeafRecordIDs = [[NSMutableArray alloc] init]; + + for (NSString* leafRecordID in self.leafRecordIDs) { + CKKSManifestPendingLeafRecord* pendingLeaf = [CKKSManifestPendingLeafRecord leafRecordForID:leafRecordID error:&localError]; + if (pendingLeaf) { + CKKSManifestLeafRecord* committedLeaf = [pendingLeaf commitToDatabaseWithError:error]; + if (committedLeaf) { + [_committedLeafRecordIDs addObject:committedLeaf.CKRecordName]; + } + else { + return nil; + } + } + else { + CKKSManifestLeafRecord* existingLeaf = [CKKSManifestLeafRecord leafRecordForID:leafRecordID error:&localError]; + if (existingLeaf) { + [_committedLeafRecordIDs addObject:existingLeaf.CKRecordName]; + continue; + } + } + + if (localError) { + if (error) { + *error = localError; + } + return nil; + } + } + + CKKSManifest* manifest = [CKKSManifest manifestForPendingManifest:self]; + if ([manifest saveToDatabase:error]) { + [self deleteFromDatabase:error]; + return manifest; + } + else { + return nil; + } +} + +@end + +@implementation CKKSEgoManifest + ++ (CKKSManifestInjectionPointHelper*)egoHelper +{ + return __egoHelper ?: [[CKKSManifestInjectionPointHelper alloc] init]; +} + ++ (NSArray*)leafRecordsForItems:(NSArray*)items manifestName:(NSString*)manifestName zone:(NSString*)zone +{ + NSMutableArray* leafRecords = [[NSMutableArray alloc] init]; + for (NSInteger i = 0; i < NUM_MANIFEST_LEAF_RECORDS; i++) { + [leafRecords addObject:[CKKSEgoManifestLeafRecord newLeafRecordInZone:zone]]; + } + + for (CKKSItem* item in items) { + CKKSEgoManifestLeafRecord* leafRecord = leafRecords[LeafBucketIndexForUUID(item.uuid)]; + [leafRecord addOrUpdateRecordUUID:item.uuid withEncryptedItemData:item.encitem]; + } + + return leafRecords; +} + ++ (nullable CKKSEgoManifest*)tryCurrentEgoManifestForZone:(NSString*)zone +{ + __block CKKSEgoManifest* manifest = nil; + [self.egoHelper performWithEgoPeerID:^(NSString * _Nullable egoPeerID, NSError * _Nullable error) { + if(error) { + ckkserrorwithzonename("ckksmanifest", zone, "Error getting peer ID: %@", error); + return; + } + if (!egoPeerID) { + ckkserrorwithzonename("ckksmanifest", zone, "can't get ego peer ID right now - the device probably hasn't been unlocked yet"); + return; + } + + NSDictionary* whereDict = @{ @"ckzone" : zone, @"signerID" : egoPeerID }; + [self queryMaxValueForField:@"gencount" inTable:self.sqlTable where:whereDict columns:self.sqlColumns processRow:^(NSDictionary* row) { + manifest = [self fromDatabaseRow:row]; + }]; + }]; + + return manifest; +} + ++ (nullable instancetype)newFakeManifestForZone:(NSString*)zone withItemRecords:(NSArray*)itemRecords currentItems:(NSDictionary*)currentItems signerID:(NSString*)signerID keyPair:(SFECKeyPair*)keyPair error:(NSError**)error +{ + CKKSManifestInjectionPointHelper* helper = [[CKKSManifestInjectionPointHelper alloc] initWithPeerID:signerID keyPair:keyPair isEgoPeer:NO]; + CKKSEgoManifest* manifest = [self newManifestForZone:zone withItems:@[] peerManifestIDs:@[] currentItems:currentItems error:error helper:helper]; + manifest.signerID = signerID; + manifest.helper = helper; + [manifest updateWithNewOrChangedRecords:itemRecords deletedRecordIDs:@[]]; + return manifest; +} + ++ (nullable instancetype)newManifestForZone:(NSString*)zone withItems:(NSArray*)items peerManifestIDs:(NSArray*)peerManifestIDs currentItems:(NSDictionary*)currentItems error:(NSError**)error +{ + return [self newManifestForZone:zone withItems:items peerManifestIDs:peerManifestIDs currentItems:currentItems error:error helper:self.egoHelper]; +} + ++ (nullable instancetype)newManifestForZone:(NSString*)zone withItems:(NSArray*)items peerManifestIDs:(NSArray*)peerManifestIDs currentItems:(NSDictionary*)currentItems error:(NSError**)error helper:(CKKSManifestInjectionPointHelper*)helper +{ + __block NSError* localError = nil; + NSArray* leafRecords = [self leafRecordsForItems:items manifestName:nil zone:zone]; + NSData* digestValue = [self digestValueForLeafRecords:leafRecords]; + + NSInteger generationCount = [self greatestKnownGenerationCount] + 1; + + __block CKKSEgoManifest* result = nil; + [helper performWithEgoPeerID:^(NSString* _Nullable egoPeerID, NSError* _Nullable err) { + if (err) { + localError = err; + } + else if (egoPeerID) { + result = [[self alloc] initWithDigestValue:digestValue zone:zone generationCount:generationCount leafRecords:leafRecords peerManifestIDs:peerManifestIDs currentItems:currentItems futureData:[NSDictionary dictionary] signatures:nil signerID:egoPeerID schema:__thisBuildsSchema]; + } + else { + localError = [NSError errorWithDomain:CKKSManifestErrorDomain code:CKKSManifestErrorManifestGenerationFailed userInfo:@{NSLocalizedDescriptionKey : @"failed to generate ego manifest because egoPeerID is nil"}]; + } + }]; + + if (!result && !localError) { + localError = [NSError errorWithDomain:CKKSManifestErrorDomain code:CKKSManifestErrorManifestGenerationFailed userInfo:@{NSLocalizedDescriptionKey : @"failed to generate ego manifest"}]; + } + if (error) { + *error = localError; + } + + return result; +} + ++ (instancetype)fromDatabaseWhere:(NSDictionary *)whereDict error:(NSError * __autoreleasing *)error { + CKKSEgoManifest* manifest = [super fromDatabaseWhere:whereDict error:error]; + if(!manifest) { + return nil; + } + + // Try to load leaf records + if(![manifest loadLeafRecords:manifest.zoneID.zoneName error:error]) { + return nil; + } + + return manifest; +} + ++ (instancetype)tryFromDatabaseWhere:(NSDictionary *)whereDict error:(NSError * __autoreleasing *)error { + CKKSEgoManifest* manifest = [super fromDatabaseWhere:whereDict error:error]; + if(!manifest) { + return nil; + } + + // Try to load leaf records + // Failing to load leaf records on a manifest that exists is an error, even in tryFromDatabaseWhere. + if(![manifest loadLeafRecords:manifest.zoneID.zoneName error:error]) { + return nil; + } + + return manifest; +} + +- (bool)loadLeafRecords:(NSString*)ckzone error:(NSError * __autoreleasing *)error { + NSMutableArray* leafRecords = [[NSMutableArray alloc] initWithCapacity:self.leafRecordIDs.count]; + for (NSString* leafID in self.leafRecordIDs) { + CKKSEgoManifestLeafRecord* leafRecord = [CKKSEgoManifestLeafRecord fromDatabaseWhere:@{@"uuid" : [CKKSManifestLeafRecord leafUUIDForRecordID:leafID], @"ckzone" : ckzone} error:error]; + if (leafRecord) { + [leafRecords addObject:leafRecord]; + } else { + secerror("ckksmanifest: error loading leaf record from database: %@", error ? *error : nil); + return false; + } + } + + self->_leafRecords = leafRecords; + return true; +} + ++ (NSDictionary*)generateSignaturesWithHelper:(CKKSManifestInjectionPointHelper*)helper derData:(NSData*)manifestDerData error:(NSError**)error +{ + __block NSData* signature = nil; + __block NSError* localError = nil; + [helper performWithSigningKey:^(SFECKeyPair* _Nullable signingKey, NSError* _Nullable err) { + if (err) { + localError = err; + return; + } + + if (signingKey) { + SFEC_X962SigningOperation* signingOperation = [self signatureOperation]; + SFSignedData* signedData = [signingOperation sign:manifestDerData withKey:signingKey error:&localError]; + signature = signedData.signature; + } + }]; + + if(error) { + *error = localError; + } + + return signature ? @{CKKSManifestEC384SignatureKey : signature} : nil; +} + +- (instancetype)initWithDigestValue:(NSData*)digestValue zone:(NSString*)zone generationCount:(NSUInteger)generationCount leafRecords:(NSArray*)leafRecords peerManifestIDs:(NSArray*)peerManifestIDs currentItems:(NSDictionary*)currentItems futureData:(NSDictionary*)futureData signatures:(NSDictionary*)signatures signerID:(NSString*)signerID schema:(NSDictionary*)schema +{ + NSMutableArray* leafRecordIDs = [[NSMutableArray alloc] initWithCapacity:leafRecords.count]; + for (CKKSManifestLeafRecord* leafRecord in leafRecords) { + [leafRecordIDs addObject:leafRecord.CKRecordName]; + } + + if (self = [super initWithDigestValue:digestValue zone:zone generationCount:generationCount leafRecordIDs:leafRecordIDs peerManifestIDs:peerManifestIDs currentItems:currentItems futureData:futureData signatures:signatures signerID:signerID schema:schema helper:[CKKSEgoManifest egoHelper]]) { + _leafRecords = leafRecords.copy; + } + + return self; +} + +- (void)updateWithNewOrChangedRecords:(NSArray*)newOrChangedRecords deletedRecordIDs:(NSArray*)deletedRecordIDs +{ + if ([CKKSManifestInjectionPointHelper ignoreChanges]) { + return; + } + + for (CKRecordID* deletedRecord in deletedRecordIDs) { + NSString* deletedUUID = deletedRecord.recordName; + CKKSEgoManifestLeafRecord* leafRecord = [self leafRecordForItemUUID:deletedUUID]; + [leafRecord deleteItemWithUUID:deletedUUID]; + } + + for (CKRecord* record in newOrChangedRecords) { + CKKSEgoManifestLeafRecord* leafRecord = (CKKSEgoManifestLeafRecord*)[self leafRecordForItemUUID:record.recordID.recordName]; + [leafRecord addOrUpdateRecord:record]; + } + + [self clearDigest]; + _generationCount = [self.class greatestKnownGenerationCount] + 1; +} + +- (void)setCurrentItemUUID:(NSString*)newCurrentItemUUID forIdentifier:(NSString*)currentPointerIdentifier +{ + _currentItemsDict[currentPointerIdentifier] = newCurrentItemUUID; + [self clearDigest]; + _generationCount = [self.class greatestKnownGenerationCount] + 1; +} + +- (CKKSEgoManifestLeafRecord*)leafRecordForItemUUID:(NSString*)uuid +{ + NSUInteger leafBucket = LeafBucketIndexForUUID(uuid); + if(_leafRecords.count > leafBucket) { + return _leafRecords[leafBucket]; + } else { + return nil; + } +} + +- (NSArray*)leafRecords +{ + return _leafRecords; +} + +- (NSArray*)allCKRecordsWithZoneID:(CKRecordZoneID*)zoneID +{ + NSMutableArray* records = [[NSMutableArray alloc] initWithCapacity:_leafRecords.count + 1]; + [records addObject:[self CKRecordWithZoneID:zoneID]]; + + for (CKKSManifestLeafRecord* leafRecord in _leafRecords) { + [records addObject:[leafRecord CKRecordWithZoneID:zoneID]]; + } + + return records; +} + +- (bool)saveToDatabase:(NSError**)error +{ + bool result = [super saveToDatabase:error]; + if (result) { + for (CKKSManifestLeafRecord* leafRecord in _leafRecords) { + result &= [leafRecord saveToDatabase:error]; + } + } + + return result; +} + +- (NSDictionary*)signatures +{ + if (!_signaturesDict) { + _signaturesDict = [self.class generateSignaturesWithHelper:self.helper derData:self.derData error:nil]; + } + + return _signaturesDict; +} + +- (void)setSignatures:(NSDictionary*)signatures +{ + _signaturesDict = signatures; +} + +- (CKKSManifestInjectionPointHelper*)defaultHelperForSignerID:(NSString*)signerID +{ + CKKSManifestInjectionPointHelper* helper = __helpersDict[signerID]; + return helper ?: __egoHelper; +} + +@end + +@implementation CKKSManifestInjectionPointHelper { + NSString* _peerID; + SFECKeyPair* _keyPair; +} + ++ (void)registerHelper:(CKKSManifestInjectionPointHelper*)helper forPeer:(NSString*)peerID +{ + if (!__helpersDict) { + __helpersDict = [[NSMutableDictionary alloc] init]; + } + + __helpersDict[peerID] = helper; +} + ++ (void)registerEgoPeerID:(NSString*)egoPeerID keyPair:(SFECKeyPair*)keyPair +{ + __egoHelper = [[self alloc] initWithPeerID:egoPeerID keyPair:keyPair isEgoPeer:YES]; +} + ++ (BOOL)ignoreChanges +{ + return __ignoreChanges; +} + ++ (void)setIgnoreChanges:(BOOL)ignoreChanges +{ + __ignoreChanges = ignoreChanges ? YES : NO; +} + +- (instancetype)initWithPeerID:(NSString*)peerID keyPair:(SFECKeyPair*)keyPair isEgoPeer:(BOOL)isEgoPeer +{ + if (self = [super init]) { + _peerID = peerID; + _keyPair = keyPair; + if (isEgoPeer) { + __egoHelper = self; + } + else { + [self.class registerHelper:self forPeer:peerID]; + } + } + + return self; +} + +- (NSString*)description +{ + return [NSString stringWithFormat:@"%@ peerID: (%@)", [super description], _peerID]; +} + +- (void)performWithSigningKey:(void (^)(SFECKeyPair* _Nullable signingKey, NSError* _Nullable error))handler +{ + if (s_accountInfo) { + if(s_accountInfo.setupError) { + handler(nil, s_accountInfo.setupError); + } else { + handler(s_accountInfo.signingKey, nil); + } + } + else if (_keyPair) { + handler(_keyPair, nil); + } + else { + SOSCCPerformWithOctagonSigningKey(^(SecKeyRef signingSecKey, CFErrorRef err) { + SFECKeyPair* key = nil; + if (!err && signingSecKey) { + key = [[SFECKeyPair alloc] initWithSecKey:signingSecKey]; + } + + handler(key, (__bridge NSError*)err); + }); + } +} + +- (void)performWithEgoPeerID:(void (^)(NSString* _Nullable egoPeerID, NSError* _Nullable error))handler +{ + if (s_accountInfo) { + if(s_accountInfo.setupError) { + handler(nil, s_accountInfo.setupError); + } else { + handler(s_accountInfo.egoPeerID, nil); + } + } + else if (_peerID) { + handler(_peerID, nil); + } + else { + NSError* error = nil; + SOSPeerInfoRef egoPeerInfo = SOSCCCopyMyPeerInfo(NULL); + NSString* egoPeerID = egoPeerInfo ? (__bridge NSString*)SOSPeerInfoGetPeerID(egoPeerInfo) : nil; + handler(egoPeerID, error); + CFReleaseNull(egoPeerInfo); + } +} + +- (void)performWithPeerVerifyingKeys:(void (^)(NSDictionary* _Nullable peerKeys, NSError* _Nullable error))handler +{ + if (s_accountInfo) { + if(s_accountInfo.setupError) { + handler(nil, s_accountInfo.setupError); + } else { + handler(s_accountInfo.peerVerifyingKeys, nil); + } + } + else if (__egoHelper || __helpersDict) { + NSMutableDictionary* verifyingKeys = [[NSMutableDictionary alloc] init]; + [__helpersDict enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull peer, CKKSManifestInjectionPointHelper* _Nonnull helper, BOOL* _Nonnull stop) { + verifyingKeys[peer] = helper.keyPair.publicKey; + }]; + if (__egoHelper.keyPair) { + verifyingKeys[__egoHelper.peerID] = __egoHelper.keyPair.publicKey; + } + handler(verifyingKeys, nil); + } + else { + CFErrorRef error = NULL; + NSMutableDictionary* peerKeys = [NSMutableDictionary dictionary]; + CFArrayRef peerInfos = SOSCCCopyValidPeerPeerInfo(&error); + if (!peerInfos || error) { + handler(nil, (__bridge NSError*)error); + CFReleaseNull(peerInfos); + CFReleaseNull(error); + return; + } + + CFArrayForEach(peerInfos, ^(const void* peerInfoPtr) { + SOSPeerInfoRef peerInfo = (SOSPeerInfoRef)peerInfoPtr; + CFErrorRef blockError = NULL; + SecKeyRef secPublicKey = SOSPeerInfoCopyOctagonPubKey(peerInfo, &blockError); + if (!secPublicKey || error) { + CFReleaseNull(blockError); + return; + } + + SFECPublicKey* publicKey = [[SFECPublicKey alloc] initWithSecKey:secPublicKey]; + CFReleaseNull(secPublicKey); + NSString* peerID = (__bridge NSString*)SOSPeerInfoGetPeerID(peerInfo); + peerKeys[peerID] = publicKey; + }); + + handler(peerKeys, nil); + CFReleaseNull(peerInfos); + } +} + +- (SFECKeyPair*)keyPair +{ + return _keyPair; +} + +- (NSString*)peerID +{ + return _peerID; +} + +@end + +@implementation CKKSAccountInfo + +@synthesize signingKey = _signingKey; +@synthesize peerVerifyingKeys = _peerVerifyingKeys; +@synthesize egoPeerID = _egoPeerID; + +@end + +#endif diff --git a/keychain/ckks/CKKSManifestLeafRecord.h b/keychain/ckks/CKKSManifestLeafRecord.h new file mode 100644 index 00000000..3e69d18b --- /dev/null +++ b/keychain/ckks/CKKSManifestLeafRecord.h @@ -0,0 +1,65 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "CKKSRecordHolder.h" +#import + +@class CKRecord; +@class CKKSItem; + +NS_ASSUME_NONNULL_BEGIN + +@interface CKKSManifestLeafRecord : CKKSCKRecordHolder + ++ (BOOL)recordExistsForID:(NSString*)recordID; ++ (instancetype)leafRecordForID:(NSString*)recordID error:(NSError* __autoreleasing *)error; ++ (instancetype)tryLeafRecordForID:(NSString*)recordID error:(NSError* __autoreleasing *)error; ++ (NSString*)leafUUIDForRecordID:(NSString*)recordID; + +@property (nonatomic, readonly) NSString* uuid; +@property (nonatomic, readonly) NSData* digestValue; +@property (nonatomic, readonly) NSDictionary* recordDigestDict; // keyed by record UUID + +@end + +@interface CKKSManifestPendingLeafRecord : CKKSManifestLeafRecord + +- (nullable CKKSManifestLeafRecord*)commitToDatabaseWithError:(NSError**)error; + +@end + +@interface CKKSEgoManifestLeafRecord : CKKSManifestLeafRecord + ++ (instancetype)newLeafRecordInZone:(NSString*)zone; + +- (void)addOrUpdateRecordUUID:(NSString*)uuid withEncryptedItemData:(NSData*)itemData; +- (void)addOrUpdateRecord:(CKRecord*)record; +- (void)deleteItemWithUUID:(NSString*)uuid; + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/keychain/ckks/CKKSManifestLeafRecord.m b/keychain/ckks/CKKSManifestLeafRecord.m new file mode 100644 index 00000000..ac39b869 --- /dev/null +++ b/keychain/ckks/CKKSManifestLeafRecord.m @@ -0,0 +1,317 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "CKKSManifestLeafRecord.h" +#import "CKKSManifest.h" +#import "CKKSItem.h" +#import "utilities/der_plist.h" +#import +#import + +@interface CKKSManifestLeafRecord () { + NSString* _uuid; + NSMutableDictionary* _recordDigestDict; + NSString* _zoneName; + NSData* _derData; + NSData* _digestValue; +} + +@property (nonatomic, readonly) NSString* zoneName; +@property (nonatomic, readonly) NSData* derData; + +- (void)clearDigest; + +@end + +@interface CKKSEgoManifestLeafRecord () + +@property (nonatomic, readonly) NSMutableDictionary* recordDigestDict; + +@end + +static NSData* NodeDERData(NSDictionary* recordDigestDict, NSError** error) +{ + return (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFPropertyListRef)recordDigestDict, (CFErrorRef*)(void*)error); +} + +static NSDictionary* RecordDigestDictFromDER(NSData* data, NSError** error) +{ + return (__bridge_transfer NSDictionary*)CFPropertyListCreateWithDERData(NULL, (__bridge CFDataRef)data, 0, NULL, (CFErrorRef*)(void*)error); +} + +@implementation CKKSManifestLeafRecord + +@synthesize zoneName = _zoneName; +@synthesize recordDigestDict = _recordDigestDict; + ++ (BOOL)recordExistsForID:(NSString*)recordID +{ + __block BOOL result = NO; + + [CKKSSQLDatabaseObject queryDatabaseTable:self.sqlTable where:@{@"UUID" : recordID} columns:@[@"UUID"] groupBy:nil orderBy:nil limit:1 processRow:^(NSDictionary* row) { + result = YES; + } error:nil]; + + return result; +} + ++ (NSString*)leafUUIDForRecordID:(NSString*)recordID +{ + NSArray* components = [recordID componentsSeparatedByString:@":-:"]; + return components.count > 1 ? components[1] : recordID; +} + ++ (instancetype)leafRecordForID:(NSString*)recordID error:(NSError* __autoreleasing *)error +{ + return [self fromDatabaseWhere:@{@"UUID" : [self leafUUIDForRecordID:recordID]} error:error]; +} + ++ (instancetype)tryLeafRecordForID:(NSString*)recordID error:(NSError* __autoreleasing *)error +{ + return [self tryFromDatabaseWhere:@{@"UUID" : [self leafUUIDForRecordID:recordID]} error:error]; +} + + ++ (instancetype)leafRecordForPendingRecord:(CKKSManifestPendingLeafRecord*)pendingRecord +{ + return [[self alloc] initWithUUID:pendingRecord.uuid digest:pendingRecord.digestValue recordDigestDict:pendingRecord.recordDigestDict zone:pendingRecord.zoneName encodedRecord:pendingRecord.encodedCKRecord]; +} + ++ (instancetype)fromDatabaseRow:(NSDictionary*)row +{ + NSString* zone = row[@"ckzone"]; + NSString* uuid = row[@"UUID"]; + + NSString* digestBase64String = row[@"digest"]; + NSData* digest = [digestBase64String isKindOfClass:[NSString class]] ? [[NSData alloc] initWithBase64EncodedString:digestBase64String options:0] : nil; + + NSString* encodedRecordBase64String = row[@"ckrecord"]; + NSData* encodedRecord = [encodedRecordBase64String isKindOfClass:[NSString class]] ? [[NSData alloc] initWithBase64EncodedString:encodedRecordBase64String options:0] : nil; + + NSString* entryDigestBase64String = row[@"entryDigests"]; + NSData* entryDigestData = [entryDigestBase64String isKindOfClass:[NSString class]] ? [[NSData alloc] initWithBase64EncodedString:row[@"entryDigests"] options:0] : nil; + NSDictionary* entryDigestsDict = entryDigestData ? RecordDigestDictFromDER(entryDigestData, nil) : @{}; + + return [[self alloc] initWithUUID:uuid digest:digest recordDigestDict:entryDigestsDict zone:zone encodedRecord:encodedRecord]; +} + ++ (NSArray*)sqlColumns +{ + return @[@"ckzone", @"UUID", @"digest", @"entryDigests", @"ckrecord"]; +} + ++ (NSString*)sqlTable +{ + return @"ckmanifest_leaf"; +} + +- (NSString*)description +{ + return [NSString stringWithFormat:@"%@ %@ records: %lu", [super description], self.uuid, (unsigned long)self.recordDigestDict.allValues.count]; +} + +- (instancetype)initWithCKRecord:(CKRecord*)record +{ + NSError* error = nil; + NSData* derData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestLeafDERKey] options:0]; + NSDictionary* recordDigestDict = RecordDigestDictFromDER(derData, &error); + if (!recordDigestDict) { + secerror("failed to decode manifest leaf node DER with error: %@", error); + return nil; + } + + NSData* digestData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestLeafDigestKey] options:0]; + return [self initWithUUID:[self.class leafUUIDForRecordID:record.recordID.recordName] digest:digestData recordDigestDict:recordDigestDict zone:record.recordID.zoneID.zoneName]; +} + +- (instancetype)initWithUUID:(NSString*)uuid digest:(NSData*)digest recordDigestDict:(NSDictionary*)recordDigestDict zone:(NSString*)zone +{ + if (self = [super init]) { + _uuid = uuid; + _digestValue = digest; + _recordDigestDict = [recordDigestDict mutableCopy]; + _zoneName = zone; + } + + return self; +} + +- (instancetype)initWithUUID:(NSString*)uuid digest:(NSData*)digest recordDigestDict:(NSDictionary*)recordDigestDict zone:(NSString*)zone encodedRecord:(NSData*)encodedRecord +{ + if (self = [self initWithUUID:uuid digest:digest recordDigestDict:recordDigestDict zone:zone]) { + self.encodedCKRecord = encodedRecord; + } + + return self; +} + +- (NSDictionary*)sqlValues +{ + 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); + } + + dictionary[key] = value; + }; + + NSMutableDictionary* sqlValues = [[NSMutableDictionary alloc] init]; + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"ckzone", _zoneName); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"UUID", _uuid); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"digest", [self.digestValue base64EncodedStringWithOptions:0]); + addValueSafelyToDictionaryAndLogIfNil(sqlValues, @"entryDigests", [NodeDERData(_recordDigestDict, nil) base64EncodedStringWithOptions:0]); + sqlValues[@"ckrecord"] = CKKSNilToNSNull([self.encodedCKRecord base64EncodedStringWithOptions:0]); + + return sqlValues; +} + +- (NSDictionary*)whereClauseToFindSelf +{ + return @{ @"ckzone" : CKKSNilToNSNull(_zoneName), + @"UUID" : CKKSNilToNSNull(_uuid) }; +} + +- (NSString*)CKRecordName +{ + return [NSString stringWithFormat:@"ManifestLeafRecord:-:%@", _uuid]; +} + +- (NSString*)ckRecordType +{ + return SecCKRecordManifestLeafType; +} + +- (CKRecord*)updateCKRecord:(CKRecord*)record zoneID:(CKRecordZoneID*)zoneID +{ + record[SecCKRecordManifestLeafDERKey] = [self.derData base64EncodedStringWithOptions:0]; + record[SecCKRecordManifestLeafDigestKey] = [self.digestValue base64EncodedStringWithOptions:0]; + return record; +} + +- (void)setFromCKRecord:(CKRecord*)record +{ + NSError* error = nil; + NSData* derData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestLeafDERKey] options:0]; + NSDictionary* recordDigestDict = RecordDigestDictFromDER(derData, &error); + if (!recordDigestDict || error) { + secerror("failed to decode manifest leaf node DER with error: %@", error); + return; + } + + self.storedCKRecord = record; + _uuid = [self.class leafUUIDForRecordID:[self.class leafUUIDForRecordID:record.recordID.recordName]]; + _digestValue = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestLeafDigestKey] options:0]; + _recordDigestDict = [recordDigestDict mutableCopy]; +} + +- (bool)matchesCKRecord:(CKRecord*)record +{ + if (![record.recordType isEqualToString:SecCKRecordManifestLeafType]) { + return false; + } + + NSData* digestData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestLeafDigestKey] options:0]; + return [digestData isEqual:self.digestValue]; +} + +- (NSData*)derData +{ + if (!_derData) { + NSError* error = nil; + _derData = NodeDERData(_recordDigestDict, &error); + NSAssert(!error, @"failed to encode manifest leaf node DER with error: %@", error); + } + + return _derData; +} + +- (NSData*)digestValue +{ + if (!_digestValue) { + _digestValue = [SFSHA384DigestOperation digest:self.derData]; + } + + return _digestValue; +} + +- (void)clearDigest +{ + _digestValue = nil; + _derData = nil; +} + +@end + +@implementation CKKSManifestPendingLeafRecord + ++ (NSString*)sqlTable +{ + return @"pending_manifest_leaf"; +} + +- (CKKSManifestLeafRecord*)commitToDatabaseWithError:(NSError**)error +{ + CKKSManifestLeafRecord* leafRecord = [CKKSManifestLeafRecord leafRecordForPendingRecord:self]; + if ([leafRecord saveToDatabase:error]) { + [self deleteFromDatabase:error]; + return leafRecord; + } + else { + return nil; + } +} + +@end + +@implementation CKKSEgoManifestLeafRecord + +@dynamic recordDigestDict; + ++ (instancetype)newLeafRecordInZone:(NSString*)zone +{ + return [[self alloc] initWithUUID:[[NSUUID UUID] UUIDString] digest:nil recordDigestDict:@{} zone:zone]; +} + +- (void)addOrUpdateRecordUUID:(NSString*)uuid withEncryptedItemData:(NSData*)itemData +{ + self.recordDigestDict[uuid] = [SFSHA384DigestOperation digest:itemData]; + [self clearDigest]; +} + +- (void)addOrUpdateRecord:(CKRecord*)record +{ + [self addOrUpdateRecordUUID:record.recordID.recordName withEncryptedItemData:record[SecCKRecordDataKey]]; +} + +- (void)deleteItemWithUUID:(NSString*)uuid +{ + [self.recordDigestDict removeObjectForKey:uuid]; + [self clearDigest]; +} + +@end + +#endif diff --git a/keychain/ckks/CKKSMirrorEntry.h b/keychain/ckks/CKKSMirrorEntry.h new file mode 100644 index 00000000..e0f83a6e --- /dev/null +++ b/keychain/ckks/CKKSMirrorEntry.h @@ -0,0 +1,58 @@ +/* + * 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 "CKKSSQLDatabaseObject.h" +#import "CKKSItem.h" +#include +#include + +#ifndef CKKSMirrorEntry_h +#define CKKSMirrorEntry_h + +#if OCTAGON + +#import + +@class CKKSWrappedAESSIVKey; + +@interface CKKSMirrorEntry : CKKSSQLDatabaseObject + +@property CKKSItem* item; +@property NSString* uuid; + +@property uint64_t wasCurrent; + +-(instancetype)initWithCKKSItem:(CKKSItem*)item; +-(instancetype)initWithCKRecord:(CKRecord*)record; +-(void)setFromCKRecord: (CKRecord*) record; +- (bool)matchesCKRecord: (CKRecord*) record; + ++ (instancetype) fromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (NSDictionary*)countsByParentKey:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + +@end + +#endif +#endif /* CKKSOutgoingQueueEntry_h */ diff --git a/keychain/ckks/CKKSMirrorEntry.m b/keychain/ckks/CKKSMirrorEntry.m new file mode 100644 index 00000000..7cd9d6fe --- /dev/null +++ b/keychain/ckks/CKKSMirrorEntry.m @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#import + +#import "CKKSKeychainView.h" + +#include +#include +#include + +#if OCTAGON + +#import +#import "CKKSOutgoingQueueEntry.h" +#import "CKKSMirrorEntry.h" +#import "CKKSSIV.h" + +@implementation CKKSMirrorEntry + +-(instancetype)initWithCKKSItem:(CKKSItem*)item { + if((self = [super init])) { + _item = item; + _wasCurrent = 0; + } + return self; +} + +-(instancetype)initWithCKRecord:(CKRecord*)record { + if((self = [super init])) { + _item = [[CKKSItem alloc] initWithCKRecord:record]; + + _wasCurrent = [record[SecCKRecordServerWasCurrent] unsignedLongLongValue]; + } + return self; +} + +- (NSString*)description { + return [NSString stringWithFormat: @"<%@(%@): %@>", + NSStringFromClass([self class]), + self.item.zoneID.zoneName, + self.item.uuid]; +} + +-(void)setFromCKRecord: (CKRecord*) record { + [self.item setFromCKRecord: record]; + _wasCurrent = [record[SecCKRecordServerWasCurrent] unsignedLongLongValue]; +} + +- (bool)matchesCKRecord: (CKRecord*) record { + bool matches = [self.item matchesCKRecord: record]; + + if(matches) { + + // 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"); + matches = false; + } + } + return matches; +} + +#pragma mark - Database Operations + ++ (instancetype) fromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error]; +} + ++ (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error]; +} + +#pragma mark - Property access to underlying CKKSItem + +-(NSString*)uuid { + return self.item.uuid; +} + +-(void)setUuid:(NSString *)uuid { + self.item.uuid = uuid; +} + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*) sqlTable { + return @"ckmirror"; +} + ++ (NSArray*)sqlColumns { + return [[CKKSItem sqlColumns] arrayByAddingObjectsFromArray: @[@"wascurrent"]]; +} + +- (NSDictionary*) whereClauseToFindSelf { + return [self.item whereClauseToFindSelf]; +} + +- (NSDictionary*)sqlValues { + NSMutableDictionary* values = [[self.item sqlValues] mutableCopy]; + values[@"wascurrent"] = [NSNumber numberWithUnsignedLongLong:self.wasCurrent]; + return values; +} + ++ (instancetype) fromDatabaseRow: (NSDictionary*) row { + CKKSMirrorEntry* ckme = [[CKKSMirrorEntry alloc] initWithCKKSItem: [CKKSItem fromDatabaseRow:row]]; + + // This appears to be the best way to get an unsigned long long out of a string. + ckme.wasCurrent = [[[[NSNumberFormatter alloc] init] numberFromString:CKKSNSNullToNil(row[@"wascurrent"])] unsignedLongLongValue]; + return ckme; +} + ++ (NSDictionary*)countsByParentKey:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + NSMutableDictionary* results = [[NSMutableDictionary alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [[self class] sqlTable] + where: @{@"ckzone": CKKSNilToNSNull(zoneID.zoneName)} + columns: @[@"parentKeyUUID", @"count(rowid)"] + groupBy: @[@"parentKeyUUID"] + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + results[row[@"parentKeyUUID"]] = [NSNumber numberWithInteger: [row[@"count(rowid)"] integerValue]]; + } + error: error]; + return results; +} + + +@end + +#endif diff --git a/keychain/ckks/CKKSNearFutureScheduler.h b/keychain/ckks/CKKSNearFutureScheduler.h new file mode 100644 index 00000000..fa7bac49 --- /dev/null +++ b/keychain/ckks/CKKSNearFutureScheduler.h @@ -0,0 +1,59 @@ +/* + * 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 +#import + +/* + * The CKKSNearFutureScheduler is intended to rate-limit an operation. When + * triggered, it will schedule the operation to take place in the future. + * Further triggers during the delay period will not cause the operation to + * occur again, but they may cause the delay period to extend. + * + * Triggers after the delay period will start another delay period. + */ + +@interface CKKSNearFutureScheduler : NSObject + +@property (readonly) NSDate* nextFireTime; +@property void (^futureOperation)(void); + +-(instancetype)initWithName:(NSString*)name + delay:(dispatch_time_t)ns + keepProcessAlive:(bool)keepProcessAlive + block:(void (^)(void))futureOperation; + +-(instancetype)initWithName:(NSString*)name + initialDelay:(dispatch_time_t)initialDelay + continuingDelay:(dispatch_time_t)continuingDelay + keepProcessAlive:(bool)keepProcessAlive + block:(void (^)(void))futureOperation; + +-(void)trigger; + +-(void)cancel; + +// Don't trigger again until at least this much time has passed. +-(void)waitUntil:(uint64_t)delay; + +@end diff --git a/keychain/ckks/CKKSNearFutureScheduler.m b/keychain/ckks/CKKSNearFutureScheduler.m new file mode 100644 index 00000000..3a2f049d --- /dev/null +++ b/keychain/ckks/CKKSNearFutureScheduler.m @@ -0,0 +1,183 @@ +/* + * 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 "CKKSNearFutureScheduler.h" +#import "CKKSCondition.h" +#include + +@interface CKKSNearFutureScheduler () +@property NSString* name; +@property dispatch_time_t initialDelay; +@property dispatch_time_t continuingDelay; + +@property NSDate* predictedNextFireTime; +@property bool liveRequest; +@property CKKSCondition* liveRequestReceived; // Triggered when liveRequest goes to true. + +@property dispatch_source_t timer; +@property dispatch_queue_t queue; + +@property bool keepProcessAlive; +@property os_transaction_t transaction; +@end + +@implementation CKKSNearFutureScheduler + +-(instancetype)initWithName:(NSString*)name delay:(dispatch_time_t)ns keepProcessAlive:(bool)keepProcessAlive block:(void (^)(void))futureOperation +{ + return [self initWithName:name initialDelay:ns continuingDelay:ns keepProcessAlive:keepProcessAlive block:futureOperation]; +} + +-(instancetype)initWithName:(NSString*)name + initialDelay:(dispatch_time_t)initialDelay + continuingDelay:(dispatch_time_t)continuingDelay + keepProcessAlive:(bool)keepProcessAlive + block:(void (^)(void))futureOperation +{ + if((self = [super init])) { + _name = name; + + _queue = dispatch_queue_create([[NSString stringWithFormat:@"near-future-scheduler-%@",name] UTF8String], DISPATCH_QUEUE_SERIAL); + _initialDelay = initialDelay; + _continuingDelay = continuingDelay; + _futureOperation = futureOperation; + + _liveRequest = false; + _liveRequestReceived = [[CKKSCondition alloc] init]; + _predictedNextFireTime = nil; + + _keepProcessAlive = keepProcessAlive; + } + return self; +} + +-(NSString*)description { + NSDate* nextAt = self.nextFireTime; + if(nextAt) { + NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + return [NSString stringWithFormat: @" requestedDelay ? self.initialDelay : requestedDelay; + + dispatch_source_set_timer(self.timer, + dispatch_walltime(NULL, actualDelay), + self.continuingDelay, + 50 * NSEC_PER_MSEC); + dispatch_resume(self.timer); + + self.predictedNextFireTime = [NSDate dateWithTimeIntervalSinceNow: (NSTimeInterval) ((double) actualDelay) / (double) NSEC_PER_SEC]; + }; +} + +-(void)cancel { + dispatch_sync(self.queue, ^{ + if(self.timer != nil && 0 == dispatch_source_testcancel(self.timer)) { + dispatch_source_cancel(self.timer); + } + }); +} + +@end diff --git a/keychain/ckks/CKKSNewTLKOperation.h b/keychain/ckks/CKKSNewTLKOperation.h new file mode 100644 index 00000000..918dd147 --- /dev/null +++ b/keychain/ckks/CKKSNewTLKOperation.h @@ -0,0 +1,40 @@ +/* + * 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 +#import "keychain/ckks/CKKSGroupOperation.h" + +#if OCTAGON + +@class CKKSKeychainView; + +@interface CKKSNewTLKOperation : CKKSGroupOperation +@property (weak) CKKSKeychainView* ckks; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup; + +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/CKKSNewTLKOperation.m b/keychain/ckks/CKKSNewTLKOperation.m new file mode 100644 index 00000000..aec9dfaa --- /dev/null +++ b/keychain/ckks/CKKSNewTLKOperation.m @@ -0,0 +1,336 @@ +/* + * 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 "CKKSKeychainView.h" +#import "CKKSCurrentKeyPointer.h" +#import "CKKSKey.h" +#import "CKKSNewTLKOperation.h" +#import "CKKSGroupOperation.h" +#import "CKKSNearFutureScheduler.h" +#import "keychain/ckks/CloudKitCategories.h" + +#if OCTAGON + +@interface CKKSNewTLKOperation () +@property NSBlockOperation* cloudkitModifyOperationFinished; +@property CKOperationGroup* ckoperationGroup; +@end + +@implementation CKKSNewTLKOperation + +- (instancetype)init { + return nil; +} +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup { + if(self = [super init]) { + _ckks = ckks; + _ckoperationGroup = ckoperationGroup; + } + return self; +} + +- (void)groupStart { + /* + * Rolling keys is an essential operation, and must be transactional: either completing successfully or + * failing entirely. Also, in the case of failure, some other peer has beaten us to CloudKit and changed + * the keys stored there (which we must now fetch and handle): the keys we attempted to upload are useless. + + * Therefore, we'll skip the normal OutgoingQueue behavior, and persist keys in-memory until such time as + * CloudKit tells us the operation succeeds or fails, at which point we'll commit them or throw them away. + * + * Note that this means edge cases in the case of secd dying in the middle of this operation; our normal + * retry mechanisms won't work. We'll have to make the policy decision to re-roll the keys if needed upon + * the next launch of secd (or, the write will succeed after we die, and we'll handle receiving the CK + * items as if a different peer uploaded them). + */ + + __weak __typeof(self) weakSelf = self; + + CKKSKeychainView* ckks = self.ckks; + + if(self.cancelled) { + ckksnotice("ckkstlk", ckks, "CKKSNewTLKOperation cancelled, quitting"); + return; + } + + if(!ckks) { + ckkserror("ckkstlk", ckks, "no CKKS object"); + return; + } + + // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety. + [ckks dispatchSync: ^bool{ + if(self.cancelled) { + ckksnotice("ckkstlk", ckks, "CKKSNewTLKOperation cancelled, quitting"); + return false; + } + + ckks.lastNewTLKOperation = self; + + NSError* error = nil; + + ckksinfo("ckkstlk", ckks, "Generating new TLK"); + + // Promote to strong reference + CKKSKeychainView* ckks = self.ckks; + + CKKSKey* newTLK = nil; + CKKSKey* newClassAKey = nil; + CKKSKey* newClassCKey = nil; + CKKSKey* wrappedOldTLK = nil; + + NSMutableArray* recordsToSave = [[NSMutableArray alloc] init]; + NSMutableArray* recordIDsToDelete = [[NSMutableArray alloc] init]; + + // Now, prepare data for the operation: + + // We must find the current TLK (to wrap it to the new TLK). + NSError* localerror = nil; + CKKSKey* oldTLK = [CKKSKey currentKeyForClass: SecCKKSKeyClassTLK zoneID:ckks.zoneID error: &localerror]; + if(localerror) { + ckkserror("ckkstlk", ckks, "couldn't load the current TLK: %@", localerror); + // TODO: not loading the old TLK is fine, but only if there aren't any TLKs + } + + [oldTLK ensureKeyLoaded: &error]; + + 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; + } + + // Generate new hierarchy: + // newTLK + // / | \ + // / | \ + // / | \ + // oldTLK classA classC + + newTLK = [[CKKSKey alloc] initSelfWrappedWithAESKey:[CKKSAESSIVKey randomKey] + uuid:[[NSUUID UUID] UUIDString] + keyclass:SecCKKSKeyClassTLK + state:SecCKKSProcessedStateLocal + zoneID:ckks.zoneID + encodedCKRecord:nil + currentkey:true]; + + newClassAKey = [CKKSKey randomKeyWrappedByParent: newTLK keyclass: SecCKKSKeyClassA error: &error]; + newClassCKey = [CKKSKey randomKeyWrappedByParent: newTLK keyclass: SecCKKSKeyClassC error: &error]; + + 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; + } + + CKKSCurrentKeyPointer* currentTLKPointer = [CKKSCurrentKeyPointer forKeyClass: SecCKKSKeyClassTLK withKeyUUID:newTLK.uuid zoneID:ckks.zoneID error: &error]; + CKKSCurrentKeyPointer* currentClassAPointer = [CKKSCurrentKeyPointer forKeyClass: SecCKKSKeyClassA withKeyUUID:newClassAKey.uuid zoneID:ckks.zoneID error: &error]; + CKKSCurrentKeyPointer* currentClassCPointer = [CKKSCurrentKeyPointer forKeyClass: SecCKKSKeyClassC withKeyUUID:newClassCKey.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; + } + + // Wrap old TLK under the new TLK + wrappedOldTLK = [oldTLK copy]; + 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; + } + + [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; + } + + wrappedOldTLK.currentkey = false; + } + + [recordsToSave addObject: [newTLK CKRecordWithZoneID: ckks.zoneID]]; + [recordsToSave addObject: [newClassAKey CKRecordWithZoneID: ckks.zoneID]]; + [recordsToSave addObject: [newClassCKey CKRecordWithZoneID: ckks.zoneID]]; + + [recordsToSave addObject: [currentTLKPointer CKRecordWithZoneID: ckks.zoneID]]; + [recordsToSave addObject: [currentClassAPointer CKRecordWithZoneID: ckks.zoneID]]; + [recordsToSave addObject: [currentClassCPointer CKRecordWithZoneID: ckks.zoneID]]; + + if(wrappedOldTLK) { + [recordsToSave addObject: [wrappedOldTLK CKRecordWithZoneID: ckks.zoneID]]; + } + + // Save the proposed keys to the keychain. Note that we might reject this TLK later, but in that case, this TLK is just orphaned. No worries! + ckksinfo("ckkstlk", ckks, "Saving new keys %@ to database %@", recordsToSave, ckks.database); + + [newTLK saveKeyMaterialToKeychain: &error]; + [newClassAKey saveKeyMaterialToKeychain: &error]; + [newClassCKey saveKeyMaterialToKeychain: &error]; + if(error) { + 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; + } + + // Use the spare operation trick to wait for the CKModifyRecordsOperation to complete + self.cloudkitModifyOperationFinished = [NSBlockOperation named:@"newtlk-cloudkit-modify-operation-finished" withBlock:^{}]; + [self dependOnBeforeGroupFinished: self.cloudkitModifyOperationFinished]; + + CKModifyRecordsOperation* modifyRecordsOp = nil; + + // Get the CloudKit operation ready... + modifyRecordsOp = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave recordIDsToDelete:recordIDsToDelete]; + modifyRecordsOp.atomic = YES; + modifyRecordsOp.longLived = NO; // The keys are only in memory; mark this explicitly not long-lived + modifyRecordsOp.timeoutIntervalForRequest = 2; + modifyRecordsOp.qualityOfService = NSQualityOfServiceUtility; // relatively important. Use Utility. + modifyRecordsOp.group = self.ckoperationGroup; + ckksnotice("ckkstlk", ckks, "Operation group is %@", self.ckoperationGroup); + + NSMutableDictionary* attemptedRecords = [[NSMutableDictionary alloc] init]; + for(CKRecord* record in recordsToSave) { + attemptedRecords[record] = record; + } + + modifyRecordsOp.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) blockCKKS = strongSelf.ckks; + + // These should all fail or succeed as one. Do the hard work in the records completion block. + if(!error) { + ckksnotice("ckkstlk", blockCKKS, "Successfully completed upload for %@", record.recordID.recordName); + } else { + ckkserror("ckkstlk", blockCKKS, "error on row: %@ %@", error, record); + } + }; + + + modifyRecordsOp.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *ckerror) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf || !strongCKKS) { + ckkserror("ckkstlk", strongCKKS, "received callback for released object"); + return; + } + + [strongCKKS dispatchSync: ^bool{ + if(ckerror == nil) { + ckksnotice("ckkstlk", strongCKKS, "Completed TLK CloudKit operation"); + + // Success. Persist the keys to the CKKS database. + NSError* localerror = nil; + + // Save the new CKRecords to the before persisting to database + for(CKRecord* record in savedRecords) { + if([newTLK matchesCKRecord: record]) { + newTLK.storedCKRecord = record; + } else if([newClassAKey matchesCKRecord: record]) { + newClassAKey.storedCKRecord = record; + } else if([newClassCKey matchesCKRecord: record]) { + newClassCKey.storedCKRecord = record; + } else if([wrappedOldTLK matchesCKRecord: record]) { + wrappedOldTLK.storedCKRecord = record; + + } else if([currentTLKPointer matchesCKRecord: record]) { + currentTLKPointer.storedCKRecord = record; + } else if([currentClassAPointer matchesCKRecord: record]) { + currentClassAPointer.storedCKRecord = record; + } else if([currentClassCPointer matchesCKRecord: record]) { + currentClassCPointer.storedCKRecord = record; + } + } + + [newTLK saveToDatabaseAsOnlyCurrentKeyForClassAndState: &localerror]; + [newClassAKey saveToDatabaseAsOnlyCurrentKeyForClassAndState: &localerror]; + [newClassCKey saveToDatabaseAsOnlyCurrentKeyForClassAndState: &localerror]; + + [currentTLKPointer saveToDatabase: &localerror]; + [currentClassAPointer saveToDatabase: &localerror]; + [currentClassCPointer saveToDatabase: &localerror]; + + [wrappedOldTLK saveToDatabase: &localerror]; + + // TLKs are already saved in the local keychain; fire off a backup + CKKSNearFutureScheduler* tlkNotifier = strongCKKS.savedTLKNotifier; + ckksnotice("ckkstlk", strongCKKS, "triggering new TLK notification: %@", tlkNotifier); + [tlkNotifier trigger]; + + if(localerror != nil) { + ckkserror("ckkstlk", strongCKKS, "couldn't save new key hierarchy to database; this is very bad: %@", localerror); + [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: localerror]; + return false; + } else { + // Everything is groovy. + [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateReady withError: nil]; + } + } else { + ckkserror("ckkstlk", strongCKKS, "couldn't save new key hierarchy to CloudKit: %@", ckerror); + [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateNewTLKsFailed withError: nil]; + + [strongCKKS _onqueueCKWriteFailed:ckerror attemptedRecordsChanged:attemptedRecords]; + + // Delete these keys from the keychain only if CloudKit positively told us the write failed. + // Other failures _might_ leave the writes written to cloudkit; who can say? + if([ckerror ckksIsCKErrorRecordChangedError]) { + NSError* localerror = nil; + [newTLK deleteKeyMaterialFromKeychain: &localerror]; + [newClassAKey deleteKeyMaterialFromKeychain: &localerror]; + [newClassCKey deleteKeyMaterialFromKeychain: &localerror]; + if(localerror) { + ckkserror("ckkstlk", strongCKKS, "couldn't delete now-useless key material from keychain: %@", localerror); + } + } else { + ckksnotice("ckkstlk", strongCKKS, "Error is too scary; not deleting likely-useless key material from keychain"); + } + } + return true; + }]; + + // Notify that we're done + [strongSelf.operationQueue addOperation: strongSelf.cloudkitModifyOperationFinished]; + }; + + [ckks.database addOperation: modifyRecordsOp]; + return true; + }]; +} + +- (void)cancel { + [self.cloudkitModifyOperationFinished cancel]; + [super cancel]; +} + +@end; + +#endif diff --git a/keychain/ckks/CKKSNotifier.h b/keychain/ckks/CKKSNotifier.h new file mode 100644 index 00000000..85324ce4 --- /dev/null +++ b/keychain/ckks/CKKSNotifier.h @@ -0,0 +1,35 @@ +/* + * 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 + +// There's terrible testing support for notify_post, but that's what our clients +// are listening for. Use this structure to mock out notification sending for testing. + +@protocol CKKSNotifier ++(void)post:(NSString*) notification; +@end + +@interface CKKSNotifyPostNotifier : NSObject ++(void)post:(NSString*) notification; +@end diff --git a/keychain/ckks/CKKSNotifier.m b/keychain/ckks/CKKSNotifier.m new file mode 100644 index 00000000..916a4675 --- /dev/null +++ b/keychain/ckks/CKKSNotifier.m @@ -0,0 +1,37 @@ +/* + * 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 "CKKSNotifier.h" +#import +#import + +@implementation CKKSNotifyPostNotifier + ++(void)post:(NSString*)notification { + if(notification) { + secnotice("ckks", "posting notification %@", notification); + notify_post([notification UTF8String]); + } +} + +@end diff --git a/keychain/ckks/CKKSOutgoingQueueEntry.h b/keychain/ckks/CKKSOutgoingQueueEntry.h new file mode 100644 index 00000000..f8d1516f --- /dev/null +++ b/keychain/ckks/CKKSOutgoingQueueEntry.h @@ -0,0 +1,67 @@ +/* + * 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 "CKKSSQLDatabaseObject.h" +#import "CKKSItem.h" +#import "CKKSMirrorEntry.h" +#include +#include + +#ifndef CKKSOutgoingQueueEntry_h +#define CKKSOutgoingQueueEntry_h + +#if OCTAGON +#import + +@class CKKSKeychainView; + +@interface CKKSOutgoingQueueEntry : CKKSSQLDatabaseObject + +@property CKKSItem* item; +@property NSString* uuid; // property access to underlying CKKSItem + +@property NSString* action; +@property NSString* state; +@property NSString* accessgroup; +@property NSDate* waitUntil; // If non-null, the time at which this entry should be processed + +- (instancetype) initWithCKKSItem:(CKKSItem*) item + action:(NSString*) action + state:(NSString*) state + waitUntil:(NSDate*) waitUntil + accessGroup:(NSString*) accessgroup; + ++ (instancetype) withItem: (SecDbItemRef) item action: (NSString*) action ckks:(CKKSKeychainView*)ckks error: (NSError * __autoreleasing *) error; ++ (instancetype) fromDatabase: (NSString*) uuid state: (NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase: (NSString*) uuid state: (NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (NSArray*) fetch:(ssize_t) n state: (NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; ++ (NSArray*) allInState: (NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + ++ (NSDictionary*)countsByState:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error; + +@end + +#endif +#endif /* CKKSOutgoingQueueEntry_h */ diff --git a/keychain/ckks/CKKSOutgoingQueueEntry.m b/keychain/ckks/CKKSOutgoingQueueEntry.m new file mode 100644 index 00000000..e0e85c80 --- /dev/null +++ b/keychain/ckks/CKKSOutgoingQueueEntry.m @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#import + +#import "CKKSKeychainView.h" + +#include + +#include +#include +#include + +#if OCTAGON + +#import +#import "CKKSOutgoingQueueEntry.h" +#import "CKKSItemEncrypter.h" +#import "CKKSKey.h" + + +@implementation CKKSOutgoingQueueEntry + +- (NSString*)description { + return [NSString stringWithFormat: @"<%@(%@): %@ %@ (%@)>", + NSStringFromClass([self class]), + self.item.zoneID.zoneName, + self.action, + self.item.uuid, + self.state]; +} + +- (instancetype) initWithCKKSItem:(CKKSItem*) item + action: (NSString*) action + state: (NSString*) state + waitUntil: (NSDate*) waitUntil + accessGroup: (NSString*) accessgroup +{ + if((self = [super init])) { + _item = item; + _action = action; + _state = state; + _accessgroup = accessgroup; + _waitUntil = waitUntil; + } + + return self; +} + +- (BOOL)isEqual: (id) object { + if(![object isKindOfClass:[CKKSOutgoingQueueEntry class]]) { + return NO; + } + + CKKSOutgoingQueueEntry* obj = (CKKSOutgoingQueueEntry*) object; + + return ([self.item isEqual: obj.item] && + [self.action isEqual: obj.action] && + [self.state isEqual: obj.state] && + ((self.waitUntil == nil && obj.waitUntil == nil) || (fabs([self.waitUntil timeIntervalSinceDate: obj.waitUntil]) < 1)) && + [self.accessgroup isEqual: obj.accessgroup] && + true) ? YES : NO; +} + ++ (instancetype)withItem: (SecDbItemRef) item action: (NSString*) action ckks:(CKKSKeychainView*) ckks error: (NSError * __autoreleasing *) error { + CFErrorRef cferror = NULL; + CKKSKey* key = nil; + NSString* uuid = nil; + NSString* accessgroup = nil; + + NSInteger newGenerationCount = -1; + + + NSMutableDictionary* objd = nil; + + key = [ckks keyForItem: item error:error]; + if(!key) { + return nil; + } + + objd = (__bridge_transfer NSMutableDictionary*) SecDbItemCopyPListWithMask(item, kSecDbSyncFlag, &cferror); + if(!objd) { + SecTranslateError(error, cferror); + return nil; + } + + // Object classes aren't in the item plist, set them specifically + [objd setObject: (__bridge NSString*) item->class->name forKey: (__bridge NSString*) kSecClass]; + + uuid = (__bridge_transfer NSString*) CFRetain(SecDbItemGetValue(item, &v10itemuuid, &cferror)); + if(!uuid || cferror) { + SecTranslateError(error, cferror); + return nil; + } + if([uuid isKindOfClass:[NSNull class]]) { + NSError* localerror = [NSError errorWithDomain:@"securityd" + code:CKKSNoUUIDOnItem + userInfo:@{NSLocalizedDescriptionKey: @"UUID not found in object"}]; + + secerror("ckksitem: couldn't fetch UUID: %@ %@", localerror, item); + if(error) { + *error = localerror; + } + return nil; + } + + accessgroup = (__bridge_transfer NSString*) CFRetain(SecDbItemGetValue(item, &v6agrp, &cferror)); + if(!accessgroup || cferror) { + SecTranslateError(error, cferror); + return nil; + } + if([accessgroup isKindOfClass:[NSNull class]]) { + // That's okay; this is only used for rate limiting. + secerror("ckksitem: couldn't fetch accessgroup: %@", item); + accessgroup = @"no-group"; + } + + + CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:ckks.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: + // (add, modify) => add + // (add, delete) => no-op + // (delete, add) => modify + NSString* actualAction = action; + + CKKSOutgoingQueueEntry* existingOQE = [CKKSOutgoingQueueEntry tryFromDatabase:uuid state:SecCKKSStateNew zoneID:ckks.zoneID error:error]; + if(existingOQE) { + if([existingOQE.action isEqual: SecCKKSActionAdd]) { + if([action isEqual:SecCKKSActionModify]) { + actualAction = SecCKKSActionAdd; + } else if([action isEqual:SecCKKSActionDelete]) { + // we're deleting an add. If there's a ckme, keep as a delete + if(!ckme) { + // Otherwise, remove from outgoingqueue and don't make a new OQE. + [existingOQE deleteFromDatabase:error]; + return nil; + } + } + } + + if([existingOQE.action isEqual: SecCKKSActionDelete] && [action isEqual:SecCKKSActionAdd]) { + actualAction = SecCKKSActionModify; + } + + } + + newGenerationCount = ckme ? ckme.item.generationCount : (NSInteger) 0; // TODO: this is wrong + + // Pull out any unencrypted fields + NSNumber* pcsServiceIdentifier = objd[(id)kSecAttrPCSPlaintextServiceIdentifier]; + objd[(id)kSecAttrPCSPlaintextServiceIdentifier] = nil; + + NSData* pcsPublicKey = objd[(id)kSecAttrPCSPlaintextPublicKey]; + objd[(id)kSecAttrPCSPlaintextPublicKey] = nil; + + NSData* pcsPublicIdentity = objd[(id)kSecAttrPCSPlaintextPublicIdentity]; + objd[(id)kSecAttrPCSPlaintextPublicIdentity] = nil; + + CKKSItem* baseitem = [[CKKSItem alloc] initWithUUID:uuid + parentKeyUUID:key.uuid + zoneID:ckks.zoneID + encodedCKRecord:nil + encItem:nil + wrappedkey:nil + generationCount:newGenerationCount + encver:currentCKKSItemEncryptionVersion + plaintextPCSServiceIdentifier:pcsServiceIdentifier + plaintextPCSPublicKey:pcsPublicKey + plaintextPCSPublicIdentity:pcsPublicIdentity]; + + CKKSItem* encryptedItem = [CKKSItemEncrypter encryptCKKSItem:baseitem + dataDictionary:objd + updatingCKKSItem:ckme.item + parentkey:key + error:error]; + + if(!encryptedItem) { + return nil; + } + + return [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem:encryptedItem + action:actualAction + state:SecCKKSStateNew + waitUntil:nil + accessGroup:accessgroup]; +} + +#pragma mark - Property access to underlying CKKSItem + +-(NSString*)uuid { + return self.item.uuid; +} + +-(void)setUuid:(NSString *)uuid { + self.item.uuid = uuid; +} + +#pragma mark - Database Operations + ++ (instancetype) fromDatabase: (NSString*) uuid state: (NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"state": CKKSNilToNSNull(state), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error]; +} + ++ (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error]; +} + ++ (instancetype) tryFromDatabase: (NSString*) uuid state: (NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"state":CKKSNilToNSNull(state), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error]; +} + ++ (NSArray*) fetch:(ssize_t) n state: (NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self fetch:n where: @{@"state":CKKSNilToNSNull(state), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error:error]; +} + ++ (NSArray*) allInState: (NSString*) state zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + return [self allWhere: @{@"state":CKKSNilToNSNull(state), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error:error]; +} + + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*)sqlTable { + return @"outgoingqueue"; +} + ++ (NSArray*)sqlColumns { + return [[CKKSItem sqlColumns] arrayByAddingObjectsFromArray: @[@"action", @"state", @"waituntil", @"accessgroup"]]; +} + +- (NSDictionary*)whereClauseToFindSelf { + return @{@"UUID": self.uuid, @"state": self.state, @"ckzone":self.item.zoneID.zoneName}; +} + +- (NSDictionary*)sqlValues { + NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init]; + + NSMutableDictionary* values = [[self.item sqlValues] mutableCopy]; + values[@"action"] = self.action; + values[@"state"] = self.state; + values[@"waituntil"] = CKKSNilToNSNull(self.waitUntil ? [dateFormat stringFromDate: self.waitUntil] : nil); + values[@"accessgroup"] = self.accessgroup; + + return values; +} + + ++ (instancetype)fromDatabaseRow: (NSDictionary*) row { + NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init]; + + return [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem:[CKKSItem fromDatabaseRow: row] + action:row[@"action"] + state:row[@"state"] + waitUntil:[row[@"waituntil"] isEqual: [NSNull null]] ? nil : [dateFormat dateFromString: row[@"waituntil"]] + accessGroup:row[@"accessgroup"]]; +} + ++ (NSDictionary*)countsByState:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error { + NSMutableDictionary* results = [[NSMutableDictionary alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [[self class] sqlTable] + where: @{@"ckzone": CKKSNilToNSNull(zoneID.zoneName)} + columns: @[@"state", @"count(rowid)"] + groupBy: @[@"state"] + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + results[row[@"state"]] = [NSNumber numberWithInteger: [row[@"count(rowid)"] integerValue]]; + } + error: error]; + return results; +} + +@end + +#endif diff --git a/OSX/libsecurity_codesigning/lib/SecIntegrity.h b/keychain/ckks/CKKSOutgoingQueueOperation.h similarity index 61% rename from OSX/libsecurity_codesigning/lib/SecIntegrity.h rename to keychain/ckks/CKKSOutgoingQueueOperation.h index 4c92f44e..aeeed762 100644 --- a/OSX/libsecurity_codesigning/lib/SecIntegrity.h +++ b/keychain/ckks/CKKSOutgoingQueueOperation.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2007,2011 Apple Inc. All Rights Reserved. - * + * 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, @@ -17,33 +17,28 @@ * 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 SecIntegrity - This header provides functionality that allows a program to use its own - code signature to extend trust to parts of its bundle that it covers. - - This file does not help you verify code signatures themselves; use SecCode.h - for that. It is reasonable to use SecCode.h and SecIntegrity.h together. -*/ -#ifndef _H_SECINTEGRITY -#define _H_SECINTEGRITY +#import +#import "keychain/ckks/CKKSGroupOperation.h" -#include +#if OCTAGON -#ifdef __cplusplus -extern "C" { -#endif +#import +@class CKKSKeychainView; +@interface CKKSOutgoingQueueOperation : CKKSGroupOperation +@property (weak) CKKSKeychainView* ckks; +@property CKOperationGroup* ckoperationGroup; +@property size_t itemsProcessed; -#ifdef __cplusplus -} -#endif +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup; -#endif //_H_SECINTEGRITY +@end +#endif // OCTAGON diff --git a/keychain/ckks/CKKSOutgoingQueueOperation.m b/keychain/ckks/CKKSOutgoingQueueOperation.m new file mode 100644 index 00000000..45b61f97 --- /dev/null +++ b/keychain/ckks/CKKSOutgoingQueueOperation.m @@ -0,0 +1,533 @@ +/* + * 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 "CKKSKeychainView.h" +#import "CKKSCurrentKeyPointer.h" +#import "CKKSOutgoingQueueOperation.h" +#import "CKKSIncomingQueueEntry.h" +#import "CKKSItemEncrypter.h" +#import "CKKSOutgoingQueueEntry.h" +#import "CKKSReencryptOutgoingItemsOperation.h" +#import "CKKSManifest.h" +#import "CKKSAnalyticsLogger.h" + +#include +#include +#include +#include +#import "CKKSPowerCollection.h" + +#if OCTAGON + +@interface CKKSOutgoingQueueOperation() +@property CKModifyRecordsOperation* modifyRecordsOperation; +@end + +@implementation CKKSOutgoingQueueOperation + +- (instancetype)init { + if(self = [super init]) { + } + return nil; +} +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup { + if(self = [super init]) { + _ckks = ckks; + _ckoperationGroup = ckoperationGroup; + + [self addNullableDependency:ckks.viewSetupOperation]; + [self addNullableDependency:ckks.holdOutgoingQueueOperation]; + + // Depend on all previous CKKSOutgoingQueueOperations + [self linearDependencies:ckks.outgoingQueueOperations]; + + // We also depend on the view being setup and the key hierarchy being reasonable + [self addNullableDependency:ckks.viewSetupOperation]; + [self addNullableDependency:ckks.keyStateReadyDependency]; + } + return self; +} + +- (void) groupStart { + // Synchronous, on some thread. Get back on the CKKS queue for thread-safety. + __weak __typeof(self) weakSelf = self; + + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksoutgoing", ckks, "no ckks object"); + return; + } + + [ckks dispatchSyncWithAccountQueue: ^bool{ + ckks.lastOutgoingQueueOperation = self; + if(self.cancelled) { + ckksnotice("ckksoutgoing", ckks, "CKKSOutgoingQueueOperation cancelled, quitting"); + return false; + } + + NSError* error = nil; + + // We only actually care about queue items in the 'new' state + NSArray * queueEntries = [CKKSOutgoingQueueEntry fetch:SecCKKSOutgoingQueueItemsAtOnce state: SecCKKSStateNew zoneID:ckks.zoneID error:&error]; + + if(error != nil) { + ckkserror("ckksoutgoing", ckks, "Error fetching outgoing queue records: %@", error); + self.error = error; + return false; + } + + ckksinfo("ckksoutgoing", ckks, "processing outgoing queue: %@", queueEntries); + + NSMutableDictionary* recordsToSave = [[NSMutableDictionary alloc] init]; + NSMutableSet* oqesModified = [[NSMutableSet alloc] init]; + NSMutableArray* recordIDsToDelete = [[NSMutableArray alloc] init]; + + CKKSCurrentKeyPointer* currentClassAKeyPointer = [CKKSCurrentKeyPointer fromDatabase: SecCKKSKeyClassA zoneID:ckks.zoneID error: &error]; + CKKSCurrentKeyPointer* currentClassCKeyPointer = [CKKSCurrentKeyPointer fromDatabase: SecCKKSKeyClassC zoneID:ckks.zoneID error: &error]; + NSMutableDictionary* currentKeysToSave = [[NSMutableDictionary alloc] init]; + bool needsReencrypt = false; + + if(error != nil) { + ckkserror("ckksoutgoing", ckks, "Couldn't load current class keys: %@", error); + return false; + } + + for(CKKSOutgoingQueueEntry* oqe in queueEntries) { + if(self.cancelled) { + secdebug("ckksoutgoing", "CKKSOutgoingQueueOperation cancelled, quitting"); + return false; + } + + CKKSOutgoingQueueEntry* inflight = [CKKSOutgoingQueueEntry tryFromDatabase: oqe.uuid state:SecCKKSStateInFlight zoneID:ckks.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; + } + + // If this item is not a delete, check the encryption status of this item. + if(![oqe.action isEqualToString: SecCKKSActionDelete]) { + // Check if this item is encrypted under a current key + if([oqe.item.parentKeyUUID isEqualToString: currentClassAKeyPointer.currentKeyUUID]) { + // Excellent. + currentKeysToSave[SecCKKSKeyClassA] = currentClassAKeyPointer; + + } else if([oqe.item.parentKeyUUID isEqualToString: currentClassCKeyPointer.currentKeyUUID]) { + // Works for us! + currentKeysToSave[SecCKKSKeyClassC] = currentClassCKeyPointer; + + } 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); + [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateReencrypt error:&error]; + if(error) { + ckkserror("ckksoutgoing", ckks, "couldn't save oqe to database: %@", error); + self.error = error; + error = nil; + } + needsReencrypt = true; + continue; + } + } + + if([oqe.action isEqualToString: SecCKKSActionAdd]) { + CKRecord* record = [oqe.item CKRecordWithZoneID: ckks.zoneID]; + recordsToSave[record.recordID] = record; + [oqesModified addObject: record.recordID]; + + [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateInFlight error:&error]; + if(error) { + ckkserror("ckksoutgoing", ckks, "couldn't save state for CKKSOutgoingQueueEntry: %@", error); + self.error = error; + } + + } else if ([oqe.action isEqualToString: SecCKKSActionDelete]) { + [recordIDsToDelete addObject: [[CKRecordID alloc] initWithRecordName: oqe.item.uuid zoneID: ckks.zoneID]]; + + [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateInFlight error:&error]; + if(error) { + ckkserror("ckksoutgoing", ckks, "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]; + 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); + // treat as an add. + CKRecord* record = [oqe.item CKRecordWithZoneID: ckks.zoneID]; + recordsToSave[record.recordID] = record; + [oqesModified addObject: record.recordID]; + + [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateInFlight error:&error]; + if(error) { + ckkserror("ckksoutgoing", ckks, "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); + [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateReencrypt error:&error]; + if(error) { + ckkserror("ckksoutgoing", ckks, "couldn't save oqe to database: %@", error); + self.error = error; + error = nil; + } + needsReencrypt = true; + continue; + } + // Grab the old ckrecord and update it + CKRecord* record = [oqe.item updateCKRecord: ckme.item.storedCKRecord zoneID: ckks.zoneID]; + recordsToSave[record.recordID] = record; + [oqesModified addObject: record.recordID]; + + [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateInFlight error:&error]; + if(error) { + ckkserror("ckksoutgoing", ckks, "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]; + } + + if([recordsToSave count] == 0 && [recordIDsToDelete count] == 0) { + // Nothing to do! exit. + ckksnotice("ckksoutgoing", ckks, "Nothing in outgoing queue to process"); + if(self.ckoperationGroup) { + ckksnotice("ckksoutgoing", ckks, "End of operation group: %@", self.ckoperationGroup); + } + return true; + } + + self.itemsProcessed = recordsToSave.count; + + NSBlockOperation* modifyComplete = [[NSBlockOperation alloc] init]; + 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*, NSArray*, NSError*) = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *ckerror) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf || !strongCKKS) { + ckkserror("ckksoutgoing", strongCKKS, "received callback for released object"); + return; + } + + [strongCKKS dispatchSync: ^bool{ + if(ckerror) { + ckkserror("ckksoutgoing", strongCKKS, "error processing outgoing queue: %@", ckerror); + + // Tell CKKS about any out-of-date records + [strongCKKS _onqueueCKWriteFailed:ckerror attemptedRecordsChanged:recordsToSave]; + + // Check if these are due to key records being out of date. We'll see a CKErrorBatchRequestFailed, with a bunch of errors inside + if([ckerror.domain isEqualToString:CKErrorDomain] && (ckerror.code == CKErrorPartialFailure)) { + NSMutableDictionary* failedRecords = ckerror.userInfo[CKPartialErrorsByItemIDKey]; + ckksnotice("ckksoutgoing", strongCKKS, "failed records %@", failedRecords); + for(CKRecordID* recordID in failedRecords.allKeys) { + NSError* recordError = failedRecords[recordID]; + + if(recordError.code == CKErrorServerRecordChanged) { + if([recordID.recordName isEqualToString: SecCKKSKeyClassA] || + [recordID.recordName isEqualToString: SecCKKSKeyClassC]) { + // The current key pointers have updated without our knowledge, so CloudKit failed this operation. Mark all records as 'needs reencryption' and kick that off. + [strongSelf _onqueueModifyAllRecordsAsReencrypt: failedRecords.allKeys]; + + ckksnotice("ckksoutgoing", strongCKKS, "initiate key fetch and reencrypt"); + // Nudge the key state machine, so that it runs off to fetch the new keys + [strongCKKS _onqueueKeyStateMachineRequestFetch]; + // This will wait for the key hierarchy to become 'ready' + CKKSReencryptOutgoingItemsOperation* op = [[CKKSReencryptOutgoingItemsOperation alloc] initWithCKKSKeychainView:strongCKKS ckoperationGroup:strongSelf.ckoperationGroup]; + [strongCKKS scheduleOperation: op]; + + // Quit the loop so we only do this once + break; + } else { + // CKErrorServerRecordChanged on an item update means that we've been overwritten. + if([oqesModified containsObject:recordID]) { + [self _onqueueModifyRecordAsError:recordID recordError:recordError]; + } + } + } else if(recordError.code == CKErrorBatchRequestFailed) { + // Also fine. This record only didn't succeed because something else failed. + // OQEs should be placed back into the 'new' state, unless they've been overwritten by a new OQE. Other records should be ignored. + + if([oqesModified containsObject:recordID]) { + NSError* error = nil; + CKKSOutgoingQueueEntry* inflightOQE = [CKKSOutgoingQueueEntry tryFromDatabase:recordID.recordName state:SecCKKSStateInFlight zoneID:recordID.zoneID error:&error]; + CKKSOutgoingQueueEntry* newOQE = [CKKSOutgoingQueueEntry tryFromDatabase:recordID.recordName state:SecCKKSStateNew zoneID:recordID.zoneID error:&error]; + if(error) { + ckkserror("ckksoutgoing", strongCKKS, "Couldn't try to fetch an overwriting OQE: %@", error); + } + + if(newOQE) { + ckksnotice("ckksoutgoing", strongCKKS, "New modification has come in behind failed change for %@; dropping failed change", inflightOQE); + [strongCKKS _onqueueChangeOutgoingQueueEntry:inflightOQE toState:SecCKKSStateDeleted error:&error]; + if(error) { + ckkserror("ckksoutgoing", strongCKKS, "Couldn't delete in-flight OQE: %@", error); + } + } else { + [strongCKKS _onqueueChangeOutgoingQueueEntry:inflightOQE toState:SecCKKSStateNew error:&error]; + } + } + + } else if ([recordID.recordName hasPrefix:@"Manifest:-:"] || [recordID.recordName hasPrefix:@"ManifestLeafRecord:-:"]) { + [[CKKSAnalyticsLogger logger] logSoftFailureForEventNamed:@"ManifestUpload" withAttributes:@{CKKSManifestZoneKey : strongCKKS.zoneID.zoneName, CKKSManifestSignerIDKey : strongCKKS.egoManifest.signerID, CKKSManifestGenCountKey : @(strongCKKS.egoManifest.generationCount)}]; + } 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); + if([oqesModified containsObject:recordID]) { + [self _onqueueModifyRecordAsError:recordID recordError:recordError]; + } + } + } + } + + strongSelf.error = error; + return true; + } + + ckksnotice("ckksoutgoing", strongCKKS, "Completed processing outgoing queue"); + 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]; + [strongCKKS _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateDeleted error:&error]; + if(error) { + ckkserror("ckksoutgoing", strongCKKS, "Couldn't update %@ in outgoingqueue: %@", record.recordID.recordName, error); + strongSelf.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); + strongSelf.error = error; + } + + [plstats storedOQE:oqe]; + + // And the CKCurrentKeyRecords (do we need to do this? Will the server update the change tag on a save which saves nothing?) + } else if([record.recordType isEqualToString: SecCKRecordCurrentKeyType]) { + CKKSCurrentKeyPointer* currentkey = [[CKKSCurrentKeyPointer alloc] initWithCKRecord: record]; + [currentkey saveToDatabase: &error]; + if(error) { + ckkserror("ckksoutgoing", strongCKKS, "Couldn't save %@ to currentkey: %@", record.recordID.recordName, error); + strongSelf.error = error; + } + + } else if ([record.recordType isEqualToString:SecCKRecordDeviceStateType]) { + CKKSDeviceStateEntry* newcdse = [[CKKSDeviceStateEntry alloc] initWithCKRecord:record]; + [newcdse saveToDatabase:&error]; + if(error) { + ckkserror("ckksoutgoing", strongCKKS, "Couldn't save %@ to ckdevicestate: %@", record.recordID.recordName, error); + strongSelf.error = error; + } + + } else if ([record.recordType isEqualToString:SecCKRecordManifestType]) { + [[CKKSAnalyticsLogger logger] logSuccessForEventNamed:@"ManifestUpload"]; + } else if (![record.recordType isEqualToString:SecCKRecordManifestLeafType]) { + ckkserror("ckksoutgoing", strongCKKS, "unknown record type in results: %@", record); + } + } + + // Delete the deleted record IDs + for(CKRecordID* ckrecordID in deletedRecordIDs) { + + NSError* error = nil; + CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase: ckrecordID.recordName state: SecCKKSStateInFlight zoneID:strongCKKS.zoneID error:&error]; + [strongCKKS _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateDeleted error:&error]; + if(error) { + ckkserror("ckksoutgoing", strongCKKS, "Couldn't delete %@ from outgoingqueue: %@", ckrecordID.recordName, error); + strongSelf.error = error; + } + error = nil; + CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase: ckrecordID.recordName zoneID:strongCKKS.zoneID error:&error]; + [ckme deleteFromDatabase: &error]; + if(error) { + ckkserror("ckksoutgoing", strongCKKS, "Couldn't delete %@ from ckmirror: %@", ckrecordID.recordName, error); + strongSelf.error = error; + } + + [plstats deletedOQE:oqe]; + } + + [plstats commit]; + + if(strongSelf.error) { + ckkserror("ckksoutgoing", strongCKKS, "Operation failed; rolling back: %@", strongSelf.error); + return false; + } + return true; + }]; + + + [strongSelf.operationQueue addOperation: modifyComplete]; + // Kick off another queue process. We expect it to exit instantly, but who knows! + [strongCKKS processOutgoingQueue:self.ckoperationGroup]; + }; + + ckksinfo("ckksoutgoing", ckks, "Current keys to update: %@", currentKeysToSave); + for(CKKSCurrentKeyPointer* keypointer in currentKeysToSave.allValues) { + CKRecord* record = [keypointer CKRecordWithZoneID: ckks.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]; + if(cdseError) { + ckkserror("ckksoutgoing", ckks, "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"); + } else { + // Add the CDSE to the outgoing records + // TODO: maybe only do this every few hours? + ckksnotice("ckksoutgoing", ckks, "Updating device state: %@", cdse); + recordsToSave[cdseRecord.recordID] = cdseRecord; + } + + ckksinfo("ckksoutgoing", ckks, "Saving records %@ to CloudKit zone %@", recordsToSave, ckks.zoneID); + + self.modifyRecordsOperation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave.allValues recordIDsToDelete:recordIDsToDelete]; + self.modifyRecordsOperation.atomic = TRUE; + self.modifyRecordsOperation.timeoutIntervalForRequest = 2; + self.modifyRecordsOperation.qualityOfService = NSQualityOfServiceUtility; + self.modifyRecordsOperation.savePolicy = CKRecordSaveIfServerRecordUnchanged; + self.modifyRecordsOperation.group = self.ckoperationGroup; + ckksnotice("ckksoutgoing", ckks, "Operation group is %@", self.ckoperationGroup); + + self.modifyRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) blockCKKS = strongSelf.ckks; + + if(!error) { + ckksnotice("ckksoutgoing", blockCKKS, "Record upload successful for %@", record.recordID.recordName); + } else { + ckkserror("ckksoutgoing", blockCKKS, "error on row: %@ %@", record, error); + } + }; + + self.modifyRecordsOperation.modifyRecordsCompletionBlock = modifyRecordsCompletionBlock; + [self dependOnBeforeGroupFinished: self.modifyRecordsOperation]; + [ckks.database addOperation: self.modifyRecordsOperation]; + + return true; + }]; +} + +- (void)_onqueueModifyRecordAsError:(CKRecordID*)recordID recordError:(NSError*)itemerror { + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksoutgoing", ckks, "no CKKS object"); + return; + } + + dispatch_assert_queue(ckks.queue); + + NSError* error = nil; + uint64_t count = 0; + + // At this stage, cloudkit doesn't give us record types + if([recordID.recordName isEqualToString: SecCKKSKeyClassA] || + [recordID.recordName isEqualToString: SecCKKSKeyClassC] || + [recordID.recordName hasPrefix:@"Manifest:-:"] || + [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]; + [ckks _onqueueErrorOutgoingQueueEntry: oqe itemError: itemerror error:&error]; + if(error) { + ckkserror("ckksoutgoing", ckks, "Couldn't set OQE %@ as error: %@", recordID.recordName, error); + self.error = error; + } + count ++; + } +} + + +- (void)_onqueueModifyAllRecordsAsReencrypt: (NSArray*) recordIDs { + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksoutgoing", ckks, "no CKKS object"); + return; + } + + dispatch_assert_queue(ckks.queue); + + NSError* error = nil; + uint64_t count = 0; + + for(CKRecordID* recordID in recordIDs) { + // At this stage, cloudkit doesn't give us record types + if([recordID.recordName isEqualToString: SecCKKSKeyClassA] || + [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]; + [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateReencrypt error:&error]; + if(error) { + ckkserror("ckksoutgoing", ckks, "Couldn't set OQE %@ as reencrypt: %@", recordID.recordName, error); + self.error = error; + } + count ++; + } + } + + SecADAddValueForScalarKey((__bridge CFStringRef) SecCKKSAggdItemReencryption, count); +} + +@end; + +#endif diff --git a/keychain/ckks/CKKSProcessReceivedKeysOperation.h b/keychain/ckks/CKKSProcessReceivedKeysOperation.h new file mode 100644 index 00000000..55a67c9e --- /dev/null +++ b/keychain/ckks/CKKSProcessReceivedKeysOperation.h @@ -0,0 +1,34 @@ +/* + * 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 + +@class CKKSKeychainView; + +@interface CKKSProcessReceivedKeysOperation : NSOperation +@property (weak) CKKSKeychainView* ckks; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks; + +@end diff --git a/keychain/ckks/CKKSProcessReceivedKeysOperation.m b/keychain/ckks/CKKSProcessReceivedKeysOperation.m new file mode 100644 index 00000000..3c0d23a3 --- /dev/null +++ b/keychain/ckks/CKKSProcessReceivedKeysOperation.m @@ -0,0 +1,212 @@ +/* + * 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 + +#import "CKKSKeychainView.h" +#import "CKKSCurrentKeyPointer.h" +#import "CKKSKey.h" +#import "CKKSProcessReceivedKeysOperation.h" + +#if OCTAGON + +@implementation CKKSProcessReceivedKeysOperation + +- (instancetype)init { + return nil; +} +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks { + if(self = [super init]) { + _ckks = ckks; + } + return self; +} + +- (void) main { + // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety. + + // Take a strong reference. + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + secerror("ckkskeys: No CKKS object"); + return; + } + + if(self.cancelled) { + ckksinfo("ckkskey", ckks, "CKKSProcessReceivedKeysOperation cancelled, quitting"); + return; + } + + [ckks dispatchSync: ^bool{ + if(self.cancelled) { + ckksinfo("ckkskey", ckks, "CKKSProcessReceivedKeysOperation cancelled, quitting"); + return false; + } + + ckks.lastProcessReceivedKeysOperation = self; + + NSError* error = nil; + CKKSKey* tlk = nil; + CKKSKey* topKey = nil; + + // The synckeys table contains everything that's in CloudKit, if looked at correctly. + // Updates from CloudKit are marked 'remote'; everything else is 'local'. + + // Step 1. Find all remote keys. + NSArray* remoteKeys = [CKKSKey remoteKeys:ckks.zoneID error:&error]; + if(!remoteKeys) { + ckkserror("ckkskey", ckks, "couldn't fetch list of remote keys: %@", error); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:error]; + return false; + } + + if([remoteKeys count] == 0u) { + ckksnotice("ckkskey", ckks, "No remote keys? Quitting."); + // Not a ready state, more of a quizzical one? The key state machine will know what to do. + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateReady withError:error]; + return false; + } + + ckksinfo("ckkskey", ckks, "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]; + + // 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; + + 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:%@ %@ %@", + currentTLKPointer, currentClassAPointer, currentClassCPointer, error, localerror); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateBadCurrentPointers withError:error]; + return true; + } + + for(CKKSKey* key in remoteKeys) { + // Find the active TLK. + if([key.uuid isEqualToString: currentTLKPointer.currentKeyUUID]) { + if([key wrapsSelf]) { + tlk = key; + } else { + ckkserror("ckkskey", ckks, "current TLK doesn't wrap itself: %@", key); + // TODO: re-fetch? + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateReady withError:error]; + return true; + } + } + } + + if(!tlk) { + ckkserror("ckkskey", ckks, "couldn't find active TLK: %@", currentTLKPointer); + // TODO: re-fetch? + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateReady withError:error]; + return true; + } + + // This key is our proposed TLK. Check with the CKKS object. + if(![ckks checkTLK: 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); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForTLK withError:nil]; + 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); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForUnlock withError:nil]; + return true; + } else { + // Otherwise, something has gone horribly wrong. enter error state. + ckkserror("ckkskey", ckks, "CKKS claims %@ is not a valid TLK: %@", tlk, error); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:[NSError errorWithDomain: @"securityd" code:0 userInfo:@{NSLocalizedDescriptionKey: @"invalid TLK from CloudKit", NSUnderlyingErrorKey: error}]]; + return true; + } + } + + // Ensure that new keys wrap to the TLK. + for(CKKSKey* key in remoteKeys) { + if(key == tlk) { + continue; + } + + topKey = [key topKeyInAnyState:&error]; + + if(error != nil || ![topKey.uuid isEqual: tlk.uuid]) { + ckkserror("ckkskey", ckks, "new key %@ is orphaned (%@)", key, error); + // TODO: possibly re-fetch. Maybe not an actual error state. + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError: error ? error : [NSError errorWithDomain: @"securityd" code:0 userInfo:@{NSLocalizedDescriptionKey: @"orphaned key in hierarchy", NSUnderlyingErrorKey: error}]]; + return true; + } + + // Okay, it wraps to the TLK. Can we unwrap it? + if(![key unwrapViaKeyHierarchy:&error] || error != nil) { + ckkserror("ckkskey", ckks, "new key %@ claims to wrap to TLK, but we can't unwrap it: %@", topKey, error); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError: error ? error : [NSError errorWithDomain: @"securityd" code:0 userInfo:@{NSLocalizedDescriptionKey: @"orphaned/couldn't unwrap key in hierarchy", NSUnderlyingErrorKey: error}]]; + return true; + } + + ckksnotice("ckkskey", ckks, "New key %@ wraps to tlk %@", key, tlk); + } + + + // We're happy with this key hierarchy. Save it. + for(CKKSKey* key in remoteKeys) { + key.state = SecCKKSProcessedStateLocal; + + if([key.uuid isEqualToString: currentClassAPointer.currentKeyUUID] || + [key.uuid isEqualToString: currentClassCPointer.currentKeyUUID]) { + [key saveToDatabaseAsOnlyCurrentKeyForClassAndState: &error]; + } else { + [key saveToDatabase: &error]; + } + + [key saveKeyMaterialToKeychain: &error]; + + if(error) { + ckkserror("ckkskey", ckks, "couldn't save newly local key %@ to database: %@", key, error); + [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError: error]; + return false; + } + } + + if(!error) { + ckksnotice("ckkskey", ckks, "Accepted new key hierarchy"); + [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateReady withError: nil]; + } else { + ckkserror("ckkskey", ckks, "error accepting new key hierarchy: %@", error); + [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error]; + } + return true; + }]; +} + +@end; + +#endif diff --git a/keychain/ckks/CKKSRateLimiter.h b/keychain/ckks/CKKSRateLimiter.h new file mode 100644 index 00000000..8dc8f2f7 --- /dev/null +++ b/keychain/ckks/CKKSRateLimiter.h @@ -0,0 +1,62 @@ +/* + * 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 RateLimiter_h +#define RateLimiter_h + +#if OCTAGON + +#import +#import "CKKSOutgoingQueueEntry.h" + +@interface CKKSRateLimiter : NSObject + +@property (readonly, nonnull) NSDictionary * config; // of NSString : NSNumber + +/*! + * @brief Find out whether outgoing items are okay to send. + * @param entry The outgoing object being judged. + * @param time Current time. + * @param limitTime In case of badness, this will contain the time at which the object may be sent. + * @return Badness score from 0 (fine to send immediately) to 5 (overload, keep back), or -1 in case caller does not provide an NSDate object. + * + * judge:at: will set the limitTime object to nil in case of 0 badness. For badnesses 1-4 the time object will indicate when it is okay to send the entry. + * At badness 5 judge:at: has determined there is too much activity so the caller should hold off altogether. The limitTime object will indicate when + * this overloaded state will end. + */ +- (int)judge:(CKKSOutgoingQueueEntry * _Nonnull const)entry + at:(NSDate * _Nonnull)time + limitTime:(NSDate * _Nonnull __autoreleasing * _Nonnull) limitTime; + +- (instancetype _Nullable)init; +- (instancetype _Nullable)initWithCoder:(NSCoder * _Nullable)coder NS_DESIGNATED_INITIALIZER; +- (NSUInteger)stateSize; +- (void)reset; +- (NSString * _Nonnull)diagnostics; + ++ (BOOL)supportsSecureCoding; + +@end + +#endif +#endif diff --git a/keychain/ckks/CKKSRateLimiter.m b/keychain/ckks/CKKSRateLimiter.m new file mode 100644 index 00000000..5f2aae70 --- /dev/null +++ b/keychain/ckks/CKKSRateLimiter.m @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON +#import "CKKSRateLimiter.h" +#import +#import + +#if !TARGET_OS_BRIDGE +#import +#import "keychain/analytics/awd/AWDMetricIds_Keychain.h" +#import "keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.h" +#import "keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.h" +#import "keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.h" +#endif + +typedef NS_ENUM(int, BucketType) { + All, + Group, + UUID, +}; + +@interface CKKSRateLimiter() +@property (readwrite, nonnull) NSDictionary *config; +@property NSMutableDictionary *buckets; +@property NSDate *overloadUntil; +#if !TARGET_OS_BRIDGE +@property NSMutableArray *badnessData; +@property AWDServerConnection *awdConnection; +#define CKKSRateLimiterName @"ckks-original" +#endif +@end + +@implementation CKKSRateLimiter + +- (instancetype)init { + return [self initWithCoder:nil]; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super init]; + if (self) { + if (coder) { + _buckets = [coder decodeObjectOfClasses:[NSSet setWithObjects:[NSMutableDictionary class], + [NSString class], + [NSDate class], + nil] + forKey:@"buckets"]; + } else { + _buckets = [NSMutableDictionary new]; + } + _overloadUntil = nil; + // this should be done from a downloadable plist, rdar://problem/29945628 + _config = [NSDictionary dictionaryWithObjectsAndKeys: + @30 , @"rateAll", + @120 , @"rateGroup", + @600 , @"rateUUID", + @20 , @"capacityAll", + @10 , @"capacityGroup", + @3 , @"capacityUUID", + @250 , @"trimSize", + @3600, @"trimTime", + @1800, @"overloadDuration", nil]; +#if !TARGET_OS_BRIDGE + _badnessData = [[NSMutableArray alloc] initWithObjects:@0, @0, @0, @0, @0, @0, nil]; + _awdConnection = [[AWDServerConnection alloc] initWithComponentId:AWDComponentId_Keychain]; + [self setUpAwdMetrics]; +#endif + } + return self; +} + +- (BOOL)isEqual: (id) object { + if(![object isKindOfClass:[CKKSRateLimiter class]]) { + return NO; + } + + CKKSRateLimiter* obj = (CKKSRateLimiter*) object; + + return ([self.config isEqual: obj.config] && + [self.buckets isEqual: obj.buckets] && + ((self.overloadUntil == nil && obj.overloadUntil == nil) || ([self.overloadUntil isEqual: obj.overloadUntil]))) ? YES : NO; +} + +- (int)rate:(enum BucketType)type { + switch (type) { + case All: + return [self.config[@"rateAll"] intValue]; + case Group: + return [self.config[@"rateGroup"] intValue]; + case UUID: + return [self.config[@"rateUUID"] intValue]; + } +} + +- (int)capacity:(enum BucketType)type { + switch (type) { + case All: + return [self.config[@"capacityAll"] intValue]; + case Group: + return [self.config[@"capacityGroup"] intValue]; + case UUID: + return [self.config[@"capacityUUID"] intValue]; + } +} + +- (NSDate *)consumeTokenFromBucket:(NSString *)name + type:(enum BucketType)type + at:(NSDate *)time { + NSDate *threshold = [time dateByAddingTimeInterval:-([self capacity:type] * [self rate:type])]; + NSDate *bucket = self.buckets[name]; + + if (!bucket || [bucket timeIntervalSinceDate:threshold] < 0) { + bucket = threshold; + } + + // Implicitly track the number of tokens in the bucket. + // "Would the token I need have been generated in the past or in the future?" + bucket = [bucket dateByAddingTimeInterval:[self rate:type]]; + self.buckets[name] = bucket; + return ([bucket timeIntervalSinceDate:time] <= 0) ? nil : [bucket copy]; +} + +- (int)judge:(CKKSOutgoingQueueEntry * _Nonnull const)entry + at:(NSDate * _Nonnull)time + limitTime:(NSDate * _Nonnull __autoreleasing * _Nonnull) limitTime +{ + if (self.overloadUntil) { + if ([time timeIntervalSinceDate:self.overloadUntil] >= 0) { + [self trim:time]; + } + if (self.overloadUntil) { + *limitTime = [self.overloadUntil copy]; + return 5; + } + } + + NSDate *all = self.buckets[@"All"]; + if ((all && [time timeIntervalSinceDate:all] > [self.config[@"trimTime"] intValue]) || + self.buckets.count >= [self.config[@"trimSize"] unsignedIntValue]) { + [self trim:time]; + if (self.overloadUntil) { + *limitTime = self.overloadUntil; + return 5; + } + } + + int badness = 0; + NSDate *sendTime = [self consumeTokenFromBucket:@"All" type:All at:time]; + if (sendTime) { + badness = 1; + } + NSDate *backoff = [self consumeTokenFromBucket:[NSString stringWithFormat:@"G:%@", entry.accessgroup] type:Group at:time]; + if (backoff) { + sendTime = sendTime == nil ? backoff : [sendTime laterDate:backoff]; + badness = ([backoff timeIntervalSinceDate: + [time dateByAddingTimeInterval:([self rate:Group] * 2)]] < 0) ? 2 : 3; + } + backoff = [self consumeTokenFromBucket:[NSString stringWithFormat:@"U:%@", entry.uuid] type:UUID at:time]; + if (backoff) { + sendTime = sendTime == nil ? backoff : [sendTime laterDate:backoff]; + badness = 4; + } + +#if !TARGET_OS_BRIDGE + self.badnessData[badness] = @([self.badnessData[badness] intValue] + 1); +#endif + + *limitTime = sendTime; + return badness; +} + +- (NSUInteger)stateSize { + return self.buckets.count; +} + +- (void)reset { + self.buckets = [NSMutableDictionary new]; + self.overloadUntil = nil; +} + +- (void)trim:(NSDate *)time { + int threshold = [self.config[@"trimTime"] intValue]; + NSSet *toRemove = [self.buckets keysOfEntriesPassingTest:^BOOL(NSString *key, NSDate *obj, BOOL *stop) { + return [time timeIntervalSinceDate:obj] > threshold; + }]; + + // Nothing to remove means everybody keeps being noisy. Tell them to go away. + if ([toRemove count] == 0) { + self.overloadUntil = [self.buckets[@"All"] dateByAddingTimeInterval:[self.config[@"overloadDuration"] intValue]]; +#if !TARGET_OS_BRIDGE + AWDKeychainCKKSRateLimiterOverload *metric = [AWDKeychainCKKSRateLimiterOverload new]; + metric.durationMsec = [self.overloadUntil timeIntervalSinceDate:time]; + metric.ratelimitertype = CKKSRateLimiterName; + AWDPostMetric(AWDComponentId_Keychain, metric); +#endif + seccritical("RateLimiter overloaded until %@", self.overloadUntil); + } else { + self.overloadUntil = nil; + [self.buckets removeObjectsForKeys:[toRemove allObjects]]; + } +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.buckets forKey:@"buckets"]; +} + +- (NSString *)diagnostics { + NSMutableString *diag = [NSMutableString stringWithFormat:@"RateLimiter config: %@\n", [self.config description]]; + + if (self.overloadUntil != nil) { + [diag appendFormat:@"Overloaded until %@, %lu total buckets\n", self.overloadUntil, (unsigned long)[self.buckets count]]; + } else { + [diag appendFormat:@"Not overloaded, %lu total buckets\n", (unsigned long)[self.buckets count]]; + } + + NSArray *offenders = [self topOffendingAccessGroups:10]; + if (offenders) { + [diag appendFormat:@"%lu congested buckets. Top offenders: \n%@ range %@ to %@\n", + (unsigned long)[offenders count], offenders, self.buckets[offenders[0]], self.buckets[offenders[[offenders count] - 1]]]; + } else { + [diag appendString:@"No buckets congested"]; + } + + return diag; +} + +- (NSArray *)topOffendingAccessGroups:(NSUInteger)num { + NSDate *now = [NSDate date]; + NSSet *congestedKeys = [self.buckets keysOfEntriesPassingTest:^BOOL(NSString *key, NSDate *obj, BOOL *stop) { + if (![key hasPrefix:@"G:"]) { + return NO; + } + return [now timeIntervalSinceDate:obj] <= 0 ? NO : YES; + }]; + + if ([congestedKeys count] > 0) { + // Marker must be type NSDate but can be anything since we know all objects will be in the dictionary + NSDictionary *congested = [NSDictionary dictionaryWithObjects:[self.buckets objectsForKeys:[congestedKeys allObjects] + notFoundMarker:[NSDate date]] + forKeys:[congestedKeys allObjects]]; + NSArray *sortedKeys = [[[congested keysSortedByValueUsingSelector:@selector(compare:)] reverseObjectEnumerator] allObjects]; + if ([sortedKeys count] > num) { + return [sortedKeys subarrayWithRange:NSMakeRange(0, num)]; + } else { + return sortedKeys; + } + } else { + return nil; + } +} + +#if !TARGET_OS_BRIDGE +- (void)setUpAwdMetrics { + [self.awdConnection registerQueriableMetric:AWDMetricId_Keychain_CKKSRateLimiterTopWriters callback:^(UInt32 metricId) { + AWDKeychainCKKSRateLimiterTopWriters *metric = [AWDKeychainCKKSRateLimiterTopWriters new]; + NSArray *offenders = [self topOffendingAccessGroups:3]; + if (offenders) { + for (NSString *offender in offenders) { + [metric addWriter:offender]; + } + } + metric.ratelimitertype = CKKSRateLimiterName; + AWDPostMetric(metricId, metric); + }]; + + [self.awdConnection registerQueriableMetric:AWDMetricId_Keychain_CKKSRateLimiterAggregatedScores callback:^(UInt32 metricId) { + AWDKeychainCKKSRateLimiterAggregatedScores *metric = [AWDKeychainCKKSRateLimiterAggregatedScores new]; + for (NSNumber *num in self.badnessData) { + [metric addData:[num unsignedIntValue]]; + } + metric.ratelimitertype = CKKSRateLimiterName; + AWDPostMetric(metricId, metric); + self.badnessData = [[NSMutableArray alloc] initWithObjects:@0, @0, @0, @0, @0, @0, nil]; + }]; +} +#endif + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSRecordHolder.h b/keychain/ckks/CKKSRecordHolder.h new file mode 100644 index 00000000..b044e959 --- /dev/null +++ b/keychain/ckks/CKKSRecordHolder.h @@ -0,0 +1,60 @@ +/* + * 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 +#include + +#ifndef CKKSRecordHolder_h +#define CKKSRecordHolder_h + +#if OCTAGON + +#import "keychain/ckks/CKKSSQLDatabaseObject.h" +#import + +@class CKKSWrappedAESSIVKey; + +// Helper class that includes a single encoded CKRecord +@interface CKKSCKRecordHolder : CKKSSQLDatabaseObject { +} + +- (instancetype)initWithCKRecord: (CKRecord*) record; +- (instancetype)initWithCKRecordType: (NSString*) recordType encodedCKRecord: (NSData*) encodedCKRecord zoneID:(CKRecordZoneID*)zoneID; + +@property (copy) CKRecordZoneID* zoneID; +@property (copy) NSString* ckRecordType; +@property (copy) NSData* encodedCKRecord; +@property (getter=storedCKRecord,setter=setStoredCKRecord:) CKRecord* storedCKRecord; + +- (CKRecord*) CKRecordWithZoneID: (CKRecordZoneID*) zoneID; + +// All of the following are virtual: you must override to use +- (NSString*) CKRecordName; +- (CKRecord*) updateCKRecord: (CKRecord*) record zoneID: (CKRecordZoneID*) zoneID; +- (void) setFromCKRecord: (CKRecord*) record; // When you override this, make sure to call [setStoredCKRecord] +- (bool) matchesCKRecord: (CKRecord*) record; + +@end + +#endif +#endif /* CKKSRecordHolder_h */ diff --git a/keychain/ckks/CKKSRecordHolder.m b/keychain/ckks/CKKSRecordHolder.m new file mode 100644 index 00000000..e42bfaa0 --- /dev/null +++ b/keychain/ckks/CKKSRecordHolder.m @@ -0,0 +1,135 @@ +/* + * 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@ + */ + +#include + +#import +#import "CKKSItem.h" +#import "CKKSSIV.h" + +#include +#include +#include + +#if OCTAGON + +#import + + +@implementation CKKSCKRecordHolder + +- (instancetype) initWithCKRecord: (CKRecord*) record { + if(self = [super init]) { + self.zoneID = record.recordID.zoneID; + [self setFromCKRecord:record]; + } + return self; +} + +- (instancetype)initWithCKRecordType: (NSString*) recordType encodedCKRecord: (NSData*) encodedCKRecord zoneID:(CKRecordZoneID*)zoneID { + if(self = [super init]) { + _zoneID = zoneID; + _ckRecordType = recordType; + _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); + } + } + return self; +} + +- (CKRecord*) storedCKRecord { + if(!_encodedCKRecord) { + return nil; + } + NSKeyedUnarchiver *coder = [[NSKeyedUnarchiver alloc] initForReadingWithData:_encodedCKRecord]; + coder.requiresSecureCoding = YES; + CKRecord* ckRecord = [[CKRecord alloc] initWithCoder:coder]; + [coder finishDecoding]; + + return ckRecord; +} + +- (void) setStoredCKRecord: (CKRecord*) ckRecord { + if(!ckRecord) { + _encodedCKRecord = nil; + return; + } + self.zoneID = ckRecord.recordID.zoneID; + self.ckRecordType = ckRecord.recordType; + + NSMutableData* data = [NSMutableData data]; + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; + [ckRecord encodeWithCoder:archiver]; + [archiver finishEncoding]; + _encodedCKRecord = data; +} + +- (CKRecord*) CKRecordWithZoneID: (CKRecordZoneID*) zoneID { + CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName: [self CKRecordName] zoneID: zoneID]; + CKRecord* record = nil; + + if(self.encodedCKRecord == nil) { + record = [[CKRecord alloc] initWithRecordType:self.ckRecordType recordID:recordID]; + } else { + record = self.storedCKRecord; + } + + [self updateCKRecord:record zoneID:zoneID]; + + self.storedCKRecord = record; + return record; +} + +- (NSString*) CKRecordName { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ must override %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd)] + userInfo:nil]; +} +- (CKRecord*) updateCKRecord: (CKRecord*) record zoneID: (CKRecordZoneID*) zoneID { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ must override %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd)] + userInfo:nil]; +} +- (void) setFromCKRecord: (CKRecord*) record { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ must override %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd)] + userInfo:nil]; +} +- (bool) matchesCKRecord: (CKRecord*) record { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ must override %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + CKKSCKRecordHolder *rhCopy = [super copyWithZone:zone]; + rhCopy->_zoneID = _zoneID; + rhCopy->_ckRecordType = _ckRecordType; + rhCopy->_encodedCKRecord = _encodedCKRecord; + return rhCopy; +} +@end + +#endif diff --git a/keychain/ckks/CKKSReencryptOutgoingItemsOperation.h b/keychain/ckks/CKKSReencryptOutgoingItemsOperation.h new file mode 100644 index 00000000..4a163ebd --- /dev/null +++ b/keychain/ckks/CKKSReencryptOutgoingItemsOperation.h @@ -0,0 +1,41 @@ +/* + * 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@ + */ + +#if OCTAGON +#import +#import +#import "keychain/ckks/CKKSGroupOperation.h" + +@class CKKSKeychainView; + +@interface CKKSReencryptOutgoingItemsOperation : CKKSResultOperation + +@property (weak) CKKSKeychainView* ckks; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup; + +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/CKKSReencryptOutgoingItemsOperation.m b/keychain/ckks/CKKSReencryptOutgoingItemsOperation.m new file mode 100644 index 00000000..44956f0f --- /dev/null +++ b/keychain/ckks/CKKSReencryptOutgoingItemsOperation.m @@ -0,0 +1,188 @@ +/* + * 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 "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSCurrentKeyPointer.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSReencryptOutgoingItemsOperation.h" +#import "keychain/ckks/CKKSItemEncrypter.h" + +#if OCTAGON + +// 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 + +- (instancetype)init { + return nil; +} +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup { + if(self = [super init]) { + _ckks = ckks; + _ckoperationGroup = ckoperationGroup; + + [self addNullableDependency:ckks.viewSetupOperation]; + [self addNullableDependency:ckks.holdReencryptOutgoingItemsOperation]; + + // We also depend on the key hierarchy being reasonable + [self addNullableDependency:ckks.keyStateReadyDependency]; + + } + return self; +} + +- (void) main { + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksreencrypt", ckks, "no CKKS object"); + return; + } + + [ckks dispatchSync: ^bool{ + if(self.cancelled) { + ckksnotice("ckksreencrypt", ckks, "CKKSReencryptOutgoingItemsOperation cancelled, quitting"); + return false; + } + + ckks.lastReencryptOutgoingItemsOperation = self; + + NSError* error = nil; + bool newItems = false; + + NSArray* oqes = [CKKSOutgoingQueueEntry allInState: SecCKKSStateReencrypt zoneID:ckks.zoneID error:&error]; + if(error) { + ckkserror("ckksreencrypt", ckks, "Error fetching oqes from database: %@", error); + self.error = error; + return false; + } + + 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); + self.error = error; + error = nil; + continue; + } + if(newOQE) { + ckksinfo("ckksreencrypt", ckks, "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); + self.error = error; + error = nil; + continue; + } + continue; + } + + ckksinfo("ckksreencrypt", ckks, "Reencrypting item %@", oqe); + + NSDictionary* item = [CKKSItemEncrypter decryptItemToDictionary: oqe.item error:&error]; + if(error) { + if ([error.domain isEqualToString:@"securityd"] && error.code == errSecItemNotFound) { + ckkserror("ckksreencrypt", ckks, "Coudn't find key in keychain; attempting to poke key hierarchy: %@", error) + [ckks _onqueueAdvanceKeyStateMachineToState: nil withError: nil]; + } else { + ckkserror("ckksreencrypt", ckks, "Couldn't decrypt item %@: %@", oqe, error); + } + self.error = error; + error = nil; + continue; + } + + // Pick a key whose class matches the keyclass that this item + CKKSKey* originalKey = [CKKSKey fromDatabase: oqe.item.parentKeyUUID zoneID:ckks.zoneID error:&error]; + if(error) { + ckkserror("ckksreencrypt", ckks, "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]; + [newkey ensureKeyLoaded: &error]; + if(error) { + ckkserror("ckksreencrypt", ckks, "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]; + if(error) { + ckkserror("ckksreencrypt", ckks, "Couldn't fetch ckme (%@) for item %@: %@", oqe.item.parentKeyUUID, oqe, error); + self.error = error; + error = nil; + continue; + } + + CKKSItem* encryptedItem = [CKKSItemEncrypter encryptCKKSItem:oqe.item + dataDictionary:item + updatingCKKSItem:ckme.item + parentkey:newkey + error:&error]; + + if(error) { + ckkserror("ckksreencrypt", ckks, "Couldn't encrypt under the new key %@: %@", newkey, error); + self.error = error; + error = nil; + continue; + } + + CKKSOutgoingQueueEntry* replacement = [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem:encryptedItem + action:oqe.action + state:SecCKKSStateNew + waitUntil:nil + accessGroup:oqe.accessgroup]; + + // Don't use the CKKSKeychainView state change here, since we're doing a wholesale item swap. + [oqe deleteFromDatabase:&error]; + [replacement saveToDatabase:&error]; + if(error) { + ckkserror("ckksreencrypt", ckks, "Couldn't save newly-encrypted oqe %@: %@", replacement, error); + self.error = error; + error = nil; + continue; + } + + newItems = true; + } + + if(newItems) { + [ckks processOutgoingQueue:self.ckoperationGroup]; + } + return true; + }]; +} + +@end; + +#endif diff --git a/keychain/ckks/CKKSSIV.h b/keychain/ckks/CKKSSIV.h new file mode 100644 index 00000000..b47983b0 --- /dev/null +++ b/keychain/ckks/CKKSSIV.h @@ -0,0 +1,62 @@ +/* + * 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 + +// For AES-SIV 512. + +#define CKKSKeySize (512/8) +#define CKKSWrappedKeySize (CKKSKeySize+16) + +@interface CKKSBaseAESSIVKey : NSObject { + @package + uint8_t key[CKKSWrappedKeySize]; // subclasses can use less than the whole buffer, and set key to be precise + size_t size; +} +- (instancetype)init; +- (instancetype)initWithBytes:(uint8_t *)bytes len:(size_t)len; +- (void)zeroKey; +- (instancetype)copyWithZone:(NSZone *)zone; + +// Mostly for testing. +- (instancetype)initWithBase64: (NSString*) base64bytes; +- (BOOL)isEqual: (id) object; +@end + +@interface CKKSWrappedAESSIVKey : CKKSBaseAESSIVKey +- (instancetype)initWithData: (NSData*) data; +- (NSData*)wrappedData; +- (NSString*) base64WrappedKey; +@end + +@interface CKKSAESSIVKey : CKKSBaseAESSIVKey ++ (instancetype)randomKey; + +- (CKKSWrappedAESSIVKey*)wrapAESKey: (CKKSAESSIVKey*) keyToWrap error: (NSError * __autoreleasing *) error; +- (CKKSAESSIVKey*)unwrapAESKey: (CKKSWrappedAESSIVKey*) keyToUnwrap error: (NSError * __autoreleasing *) error; + +// Encrypt and decrypt data into buffers. Adds a nonce for ciphertext protection. +- (NSData*)encryptData: (NSData*) plaintext authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error; +- (NSData*)decryptData: (NSData*) ciphertext authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error; + +@end diff --git a/keychain/ckks/CKKSSIV.m b/keychain/ckks/CKKSSIV.m new file mode 100644 index 00000000..3097ee94 --- /dev/null +++ b/keychain/ckks/CKKSSIV.m @@ -0,0 +1,391 @@ +/* + * 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@ + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include + +#import +#import + +#import "CKKSSIV.h" + +#include +#include +#include +#include + +@implementation CKKSBaseAESSIVKey +- (instancetype)init { + if(self = [super init]) { + self->size = CKKSWrappedKeySize; + [self zeroKey]; + } + return self; +} +- (instancetype)initWithBytes:(uint8_t *)bytes len:(size_t)len { + if(self = [super init]) { + if(len <= CKKSWrappedKeySize) { + self->size = len; + memcpy(self->key, bytes, self->size); + } + } + return self; +} +- (instancetype)initWithBase64:(NSString*)base64bytes { + if(self = [super init]) { + NSData* data = [[NSData alloc] initWithBase64EncodedString: base64bytes options:0]; + + if(!data) { + return nil; + } + + if(data.length <= CKKSWrappedKeySize) { + self->size = data.length; + memcpy(self->key, data.bytes, self->size); + } + } + return self; +} + +- (BOOL)isEqual: (id) object { + if(![object isKindOfClass:[CKKSBaseAESSIVKey class]]) { + return NO; + } + + CKKSBaseAESSIVKey* obj = (CKKSBaseAESSIVKey*) object; + if (self->size == obj->size && 0 == memcmp(self->key, obj->key, self->size)) { + return YES; + } else { + return NO; + } +} + +- (void)dealloc { + [self zeroKey]; +} + +- (void)zeroKey { + memset_s(self->key, self->size, 0x00, CKKSWrappedKeySize); +} + +- (instancetype)copyWithZone:(NSZone *)zone { + return [[[self class] allocWithZone:zone] initWithBytes:self->key len:self->size]; +} + +@end + +@implementation CKKSWrappedAESSIVKey +- (instancetype)init { + if(self = [super init]) { + self->size = CKKSWrappedKeySize; + } + return self; +} +- (instancetype)initWithBytes:(uint8_t *)bytes len:(size_t)len { + if(len != CKKSWrappedKeySize) { + @throw [NSException + exceptionWithName:@"WrongKeySizeException" + reason:[NSString stringWithFormat: @"length (%lu) was not %d", len, CKKSWrappedKeySize] + userInfo:nil]; + } + if(self = [super initWithBytes: bytes len: len]) { + } + return self; +} +- (instancetype)initWithBase64:(NSString*)base64bytes { + if(self = [super initWithBase64: base64bytes]) { + if(self->size != CKKSWrappedKeySize) { + @throw [NSException + exceptionWithName:@"WrongKeySizeException" + reason:[NSString stringWithFormat: @"length (%lu) was not %d", self->size, CKKSWrappedKeySize] + userInfo:nil]; + } + } + return self; +} +- (instancetype)initWithData: (NSData*) data { + if(data.length != CKKSWrappedKeySize) { + @throw [NSException + exceptionWithName:@"WrongKeySizeException" + reason:[NSString stringWithFormat: @"length (%lu) was not %d", (unsigned long) data.length, CKKSWrappedKeySize] + userInfo:nil]; + } + if(self = [super initWithBytes: (uint8_t*) data.bytes len: data.length]) { + } + return self; +} +- (NSData*) wrappedData { + return [[NSData alloc] initWithBytes:self->key length:self->size]; +} +- (NSString*) base64WrappedKey { + return [[self wrappedData] base64EncodedStringWithOptions:0]; +} + +@end + +@implementation CKKSAESSIVKey +- (instancetype)init { + if(self = [super init]) { + self->size = CKKSKeySize; + } + return self; +} +- (instancetype)initWithBytes:(uint8_t *)bytes len:(size_t)len { + if(len != CKKSKeySize) { + @throw [NSException + exceptionWithName:@"WrongKeySizeException" + reason:[NSString stringWithFormat: @"length (%lu) was not %d", len, CKKSKeySize] + userInfo:nil]; + } + if(self = [super initWithBytes: bytes len: len]) { + } + return self; +} +- (instancetype)initWithBase64:(NSString*)base64bytes { + if(self = [super initWithBase64: base64bytes]) { + if(self->size != CKKSKeySize) { + @throw [NSException + exceptionWithName:@"WrongKeySizeException" + reason:[NSString stringWithFormat: @"length (%lu) was not %d", self->size, CKKSKeySize] + userInfo:nil]; + } + } + return self; +} + ++ (instancetype)randomKey { + CKKSAESSIVKey* key = [[CKKSAESSIVKey alloc] init]; + + CCRNGStatus status = CCRandomGenerateBytes(key->key, key->size); + if(status != kCCSuccess) { + @throw [NSException + exceptionWithName:@"randomnessException" + reason:[NSString stringWithFormat: @"CCRandomGenerateBytes failed with %d", status] + userInfo:nil]; + } + + return key; +} + +- (CKKSWrappedAESSIVKey*)wrapAESKey: (CKKSAESSIVKey*) keyToWrap error: (NSError * __autoreleasing *) error { + NSError* localerror = nil; + bool success = false; + + CKKSWrappedAESSIVKey* wrappedKey = nil; + uint8_t buffer[CKKSWrappedKeySize] = {}; + + size_t ciphertextLength = ccsiv_ciphertext_size(ccaes_siv_encrypt_mode(), CKKSKeySize); + require_action_quiet(ciphertextLength == CKKSWrappedKeySize, out, localerror = [NSError errorWithDomain:@"securityd" + code:errSecParam + userInfo:@{NSLocalizedDescriptionKey: @"wrapped key size does not match key size"}]); + + success = [self doSIV: ccaes_siv_encrypt_mode() + nonce: nil + text: [[NSData alloc] initWithBytesNoCopy: (void*) (keyToWrap->key) length: keyToWrap->size freeWhenDone: NO] + buffer: buffer bufferLength: sizeof(buffer) + authenticatedData: nil + error: error]; + require_quiet(success, out); + + wrappedKey = [[CKKSWrappedAESSIVKey alloc] initWithBytes:buffer len:sizeof(buffer)]; +out: + memset_s(buffer, sizeof(buffer), 0x00, CKKSKeySize); + if(error && localerror != nil) { + *error = localerror; + } + return wrappedKey; +} + +- (CKKSAESSIVKey*)unwrapAESKey: (CKKSWrappedAESSIVKey*) keyToUnwrap error: (NSError * __autoreleasing *) error { + NSError* localerror = nil; + bool success = false; + + CKKSAESSIVKey* unwrappedKey = nil; + uint8_t buffer[CKKSKeySize] = {}; + + size_t plaintextLength = ccsiv_plaintext_size(ccaes_siv_decrypt_mode(), CKKSWrappedKeySize); + require_action_quiet(plaintextLength == CKKSKeySize, out, localerror = [NSError errorWithDomain:@"securityd" + code:errSecParam + userInfo:@{NSLocalizedDescriptionKey: @"unwrapped key size does not match key size"}]); + + success = [self doSIV: ccaes_siv_decrypt_mode() + nonce: nil + text: [[NSData alloc] initWithBytesNoCopy: (void*) (keyToUnwrap->key) length: keyToUnwrap->size freeWhenDone: NO] + buffer: buffer bufferLength:sizeof(buffer) + authenticatedData: nil + error: error]; + + require_quiet(success, out); + + unwrappedKey = [[CKKSAESSIVKey alloc] initWithBytes: buffer len:sizeof(buffer)]; +out: + memset_s(buffer, sizeof(buffer), 0x00, CKKSKeySize); + if(error && localerror != nil) { + *error = localerror; + } + return unwrappedKey; +} + + +- (NSData*)encryptData: (NSData*) plaintext authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error { + size_t nonceLength = (128/8); + size_t ciphertextLength = 0; + + NSMutableData* buffer = nil; + NSMutableData* nonce = nil; + + bool success = false; + + const struct ccmode_siv* mode = ccaes_siv_encrypt_mode(); + + // alloc space for nonce and ciphertext. + nonce = [[NSMutableData alloc] initWithLength: nonceLength]; + CCRNGStatus status = CCRandomGenerateBytes(nonce.mutableBytes, nonce.length); + if(status != kCCSuccess) { + if(error) { + *error = [NSError errorWithDomain:@"CommonCrypto" + code:status + userInfo:@{NSLocalizedDescriptionKey: @"IV generation failed"}]; + } + return nil; + } + + ciphertextLength = ccsiv_ciphertext_size(mode, plaintext.length); + buffer = [[NSMutableData alloc] initWithLength: ciphertextLength]; + + success = [self doSIV: mode + nonce: nonce + text: plaintext + buffer: buffer.mutableBytes + bufferLength: buffer.length + authenticatedData: ad error: error]; + + if(!success) { + return nil; + } + + NSMutableData* ret = [[NSMutableData alloc] init]; + [ret appendData: nonce]; + [ret appendData: buffer]; + return ret; +} + +- (NSData*)decryptData: (NSData*) ciphertext authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error { + size_t nonceLength = (128/8); + size_t ciphertextLength = 0; + size_t plaintextLength = 0; + + NSMutableData* plaintext = nil; + NSData* nonce = nil; + NSData* text = nil; + + bool success = false; + + const struct ccmode_siv* mode = ccaes_siv_decrypt_mode(); + + // compute sizes. + nonceLength = (128/8); + if(ciphertext.length <= nonceLength) { + if(error) { + *error = [NSError errorWithDomain:@"securityd" + code:4 + userInfo:@{NSLocalizedDescriptionKey: @"ciphertext too short"}]; + } + return nil; + } + + ciphertextLength = ciphertext.length - (nonceLength); + + // pointer arithmetic. tsk tsk. + nonce = [[NSData alloc] initWithBytesNoCopy: (void*) ciphertext.bytes length: nonceLength freeWhenDone: NO]; + text = [[NSData alloc] initWithBytesNoCopy: (void*) (ciphertext.bytes + nonceLength) length: ciphertextLength freeWhenDone: NO]; + + // alloc space for plaintext + plaintextLength = ccsiv_plaintext_size(mode, ciphertextLength); + plaintext = [[NSMutableData alloc] initWithLength: plaintextLength]; + + success = [self doSIV: mode + nonce: nonce + text: text + buffer: plaintext.mutableBytes + bufferLength: plaintext.length + authenticatedData: ad error: error]; + + if(!success) { + return nil; + } + + return plaintext; +} + +// Does NOT check buffer size. Make sure you get it right for the mode you're requesting! +- (bool)doSIV: (const struct ccmode_siv*) mode nonce: (NSData*) nonce text: (NSData*) text buffer: (uint8_t*) buffer bufferLength: (size_t) bufferLength authenticatedData: (NSDictionary*) ad error: (NSError * __autoreleasing *) error { + + NSArray* adKeys = nil; + NSError* localerror = nil; + int status = 0; + + ccsiv_ctx_decl(mode->size, ctx); + + require_action_quiet(mode, out, localerror = [NSError errorWithDomain:@"securityd" + code:1 + userInfo:@{NSLocalizedDescriptionKey: @"no mode given"}]); + + status = ccsiv_init(mode, ctx, self->size, self->key); + require_action_quiet(status == 0, out, localerror = [NSError errorWithDomain:@"corecrypto" + code:status + userInfo:@{NSLocalizedDescriptionKey: @"could not ccsiv_init"}]); + + if(nonce) { + status = ccsiv_set_nonce(mode, ctx, nonce.length, nonce.bytes); + require_action_quiet(status == 0, out, localerror = [NSError errorWithDomain:@"corecrypto" + code:status + userInfo:@{NSLocalizedDescriptionKey: @"could not ccsiv_set_nonce"}]); + } + + // Add authenticated data, sorted by Key Order + adKeys = [[ad allKeys] sortedArrayUsingSelector:@selector(compare:)]; + for(NSString* adKey in adKeys) { + NSData* adValue = [ad objectForKey: adKey]; + status = ccsiv_aad(mode, ctx, adValue.length, adValue.bytes); + require_action_quiet(status == 0, out, localerror = [NSError errorWithDomain:@"corecrypto" + code:status + userInfo:@{NSLocalizedDescriptionKey: @"could not ccsiv_aad"}]); + } + + // Actually go. + status = ccsiv_crypt(mode, ctx, text.length, text.bytes, buffer); + require_action_quiet(status == 0, out, localerror = [NSError errorWithDomain:@"corecrypto" + code:status + userInfo:@{NSLocalizedDescriptionKey: @"could not ccsiv_crypt"}]); +out: + ccsiv_ctx_clear(mode->size, ctx); + + if(error) { + *error = localerror; + } + return localerror == NULL; +} + + +@end diff --git a/keychain/ckks/CKKSSQLDatabaseObject.h b/keychain/ckks/CKKSSQLDatabaseObject.h new file mode 100644 index 00000000..d016e35d --- /dev/null +++ b/keychain/ckks/CKKSSQLDatabaseObject.h @@ -0,0 +1,110 @@ +/* + * 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 DatabaseObject_h +#define DatabaseObject_h + +#include +#include + +#define CKKSNilToNSNull(obj) ({ id o = (obj); o ? o : [NSNull null]; }) +#define CKKSNSNullToNil(obj) ({ id o = (obj); ([o isEqual: [NSNull null]]) ? nil : o; }) + +#define CKKSIsNull(x) ({ id y = (x); ((y == nil) || ([y isEqual: [NSNull null]])); }) +#define CKKSUnbase64NullableString(x) (!CKKSIsNull(x) ? [[NSData alloc] initWithBase64EncodedString:x options:0] : nil) + +@interface CKKSSQLDatabaseObject : NSObject { + +} + +@property (copy) NSDictionary* originalSelfWhereClause; + +- (bool) saveToDatabase: (NSError * __autoreleasing *) error; +- (bool) saveToDatabaseWithConnection: (SecDbConnectionRef) conn error: (NSError * __autoreleasing *) error; +- (bool) deleteFromDatabase: (NSError * __autoreleasing *) error; ++ (bool) deleteAll: (NSError * __autoreleasing *) error; + +// Load the object from the database, and error if it doesn't exist ++ (instancetype) fromDatabaseWhere: (NSDictionary*) whereDict error: (NSError * __autoreleasing *) error; + +// Load the object from the database, and return nil if it doesn't exist ++ (instancetype) tryFromDatabaseWhere: (NSDictionary*) whereDict error: (NSError * __autoreleasing *) error; + ++ (NSArray*) all: (NSError * __autoreleasing *) error; ++ (NSArray*) allWhere: (NSDictionary*) whereDict error: (NSError * __autoreleasing *) error; + +// Like all() above, but with limits on how many will return ++ (NSArray*)fetch:(size_t)count error: (NSError * __autoreleasing *) error; ++ (NSArray*)fetch:(size_t)count where:(NSDictionary*)whereDict error: (NSError * __autoreleasing *) error; ++ (NSArray*)fetch: (size_t)count where:(NSDictionary*)whereDict orderBy:(NSArray*) orderColumns error: (NSError * __autoreleasing *) error; + + ++ (bool) saveToDatabaseTable: (NSString*) table row: (NSDictionary*) row connection: (SecDbConnectionRef) dbconn error: (NSError * __autoreleasing *) error; ++ (bool) deleteFromTable: (NSString*) table where: (NSDictionary*) whereDict connection:(SecDbConnectionRef) dbconn error: (NSError * __autoreleasing *) error; + ++ (bool) queryDatabaseTable:(NSString*) table + where:(NSDictionary*) whereDict + columns:(NSArray*) names + groupBy:(NSArray*) groupColumns + orderBy:(NSArray*) orderColumns + limit:(ssize_t)limit + processRow:(void (^)(NSDictionary*)) processRow + error:(NSError * __autoreleasing *) error; + ++ (bool)queryMaxValueForField:(NSString*)maxField inTable:(NSString*)table where:(NSDictionary*)whereDict columns:(NSArray*)names processRow:(void (^)(NSDictionary*))processRow; + +// Note: if you don't use the SQLDatabase methods of loading yourself, +// make sure you call this directly after loading. +- (instancetype) memoizeOriginalSelfWhereClause; + +#pragma mark - Subclasses must implement the following: + +// Given a row from the database, make this object ++ (instancetype) fromDatabaseRow: (NSDictionary*) row; + +// Return the columns, in order, that this row wants to fetch ++ (NSArray*) sqlColumns; + +// Return the table name for objects of this class ++ (NSString*) sqlTable; + +// Return the columns and values, in order, that this row wants to save +- (NSDictionary*) sqlValues; + +// Return a set of key-value pairs that will uniquely find This Row in the table +- (NSDictionary*) whereClauseToFindSelf; + +- (instancetype)copyWithZone:(NSZone *)zone; +@end + +// Helper class to use with where clauses +// If you pass in one of these instead of a concrete value, its substring will be used directly, instead of binding the value as a named parameter +@interface CKKSSQLWhereObject : NSObject +@property NSString* sqlOp; +@property NSString* contents; +- (instancetype) initWithOperation:(NSString*)op string: (NSString*) str; ++ (instancetype) op:(NSString*)op string:(NSString*) str; ++ (instancetype)op:(NSString*) op stringValue: (NSString*) str; // Will add single quotes around your value. +@end + +#endif /* DatabaseObject_h */ diff --git a/keychain/ckks/CKKSSQLDatabaseObject.m b/keychain/ckks/CKKSSQLDatabaseObject.m new file mode 100644 index 00000000..205a8775 --- /dev/null +++ b/keychain/ckks/CKKSSQLDatabaseObject.m @@ -0,0 +1,455 @@ +/* + * 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 +#import "CKKSSQLDatabaseObject.h" +#include + +#import "CKKSKeychainView.h" + +@implementation CKKSSQLDatabaseObject + ++ (bool) saveToDatabaseTable: (NSString*) table row: (NSDictionary*) row connection: (SecDbConnectionRef) dbconn error: (NSError * __autoreleasing *) error { + __block CFErrorRef cferror = NULL; + + bool (^doWithConnection)(SecDbConnectionRef) = ^bool (SecDbConnectionRef dbconn) { + NSString * columns = [row.allKeys componentsJoinedByString:@", "]; + NSMutableString * values = [[NSMutableString alloc] init]; + for(NSUInteger i = 0; i < [row.allKeys count]; i++) { + if(i != 0) { + [values appendString: @",?"]; + } else { + [values appendString: @"?"]; + } + } + + NSString *sql = [[NSString alloc] initWithFormat: @"INSERT OR REPLACE into %@ (%@) VALUES (%@);", table, columns, values]; + + SecDbPrepare(dbconn, (__bridge CFStringRef) sql, &cferror, ^void (sqlite3_stmt *stmt) { + [row.allKeys enumerateObjectsUsingBlock:^(id _Nonnull key, NSUInteger i, BOOL * _Nonnull stop) { + SecDbBindObject(stmt, (int)(i+1), (__bridge CFStringRef) row[key], &cferror); + }]; + + SecDbStep(dbconn, stmt, &cferror, ^(bool *stop) { + // don't do anything, I guess? + }); + }); + + return true; + }; + + if(dbconn) { + doWithConnection(dbconn); + } else { + kc_with_dbt(true, &cferror, doWithConnection); + } + + bool ret = cferror == NULL; + + SecTranslateError(error, cferror); + + return ret; +} + ++ (NSString*) makeWhereClause: (NSDictionary*) whereDict { + if(!whereDict) { + return @""; + } + NSMutableString * whereClause = [[NSMutableString alloc] init]; + __block bool conjunction = false; + [whereDict enumerateKeysAndObjectsUsingBlock: ^(NSString* key, NSNumber* value, BOOL* stop) { + if(!conjunction) { + [whereClause appendFormat: @" WHERE "]; + } else { + [whereClause appendFormat: @" AND "]; + } + + if([value class] == [CKKSSQLWhereObject class]) { + // Use this string verbatim + CKKSSQLWhereObject* whereob = (CKKSSQLWhereObject*) value; + [whereClause appendFormat: @"%@%@%@", key, whereob.sqlOp, whereob.contents]; + } else { + [whereClause appendFormat: @"%@=(?)", key]; + } + + conjunction = true; + }]; + return whereClause; +} + ++ (NSString*) groupByClause: (NSArray*) columns { + if(!columns) { + return @""; + } + NSMutableString * groupByClause = [[NSMutableString alloc] init]; + __block bool conjunction = false; + [columns enumerateObjectsUsingBlock: ^(NSString* column, NSUInteger i, BOOL* stop) { + if(!conjunction) { + [groupByClause appendFormat: @" GROUP BY "]; + } else { + [groupByClause appendFormat: @", "]; + } + + [groupByClause appendFormat: @"%@", column]; + + conjunction = true; + }]; + return groupByClause; +} + ++ (NSString*)orderByClause: (NSArray*) columns { + if(!columns || columns.count == 0u) { + return @""; + } + NSMutableString * orderByClause = [[NSMutableString alloc] init]; + __block bool conjunction = false; + [columns enumerateObjectsUsingBlock: ^(NSString* column, NSUInteger i, BOOL* stop) { + if(!conjunction) { + [orderByClause appendFormat: @" ORDER BY "]; + } else { + [orderByClause appendFormat: @", "]; + } + + [orderByClause appendFormat: @"%@", column]; + + conjunction = true; + }]; + return orderByClause; +} + ++ (bool) deleteFromTable: (NSString*) table where: (NSDictionary*) whereDict connection:(SecDbConnectionRef) dbconn error: (NSError * __autoreleasing *) error { + __block CFErrorRef cferror = NULL; + + bool (^doWithConnection)(SecDbConnectionRef) = ^bool (SecDbConnectionRef dbconn) { + NSString* whereClause = [CKKSSQLDatabaseObject makeWhereClause: whereDict]; + + NSString * sql = [[NSString alloc] initWithFormat: @"DELETE FROM %@%@;", table, whereClause]; + SecDbPrepare(dbconn, (__bridge CFStringRef) sql, &cferror, ^void (sqlite3_stmt *stmt) { + + [whereDict.allKeys enumerateObjectsUsingBlock:^(id _Nonnull key, NSUInteger i, BOOL * _Nonnull stop) { + if([whereDict[key] class] != [CKKSSQLWhereObject class]) { + SecDbBindObject(stmt, (int)(i+1), (__bridge CFStringRef) whereDict[key], &cferror); + } + }]; + + SecDbStep(dbconn, stmt, &cferror, ^(bool *stop) { + }); + }); + return true; + }; + + if(dbconn) { + doWithConnection(dbconn); + } else { + kc_with_dbt(true, &cferror, doWithConnection); + } + + // Deletes finish in a single step, so if we didn't get an error, the delete 'happened' + bool status = (cferror == nil); + + if(error) { + *error = (NSError*) CFBridgingRelease(cferror); + } else { + CFReleaseNull(cferror); + } + + return status; +} + ++ (bool) queryDatabaseTable:(NSString*) table + where:(NSDictionary*) whereDict + columns:(NSArray*) names + groupBy:(NSArray*) groupColumns + orderBy:(NSArray*) orderColumns + limit:(ssize_t)limit + processRow:(void (^)(NSDictionary*)) processRow + error:(NSError * __autoreleasing *) error { + __block CFErrorRef cferror = NULL; + + kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbconn) { + NSString * columns = [names componentsJoinedByString:@", "]; + NSString * whereClause = [CKKSSQLDatabaseObject makeWhereClause: whereDict]; + NSString * groupByClause = [CKKSSQLDatabaseObject groupByClause: groupColumns]; + NSString * orderByClause = [CKKSSQLDatabaseObject orderByClause: orderColumns]; + NSString * limitClause = (limit > 0 ? [NSString stringWithFormat:@" LIMIT %lu", limit] : @""); + + NSString * sql = [[NSString alloc] initWithFormat: @"SELECT %@ FROM %@%@%@%@%@;", columns, table, whereClause, groupByClause, orderByClause, limitClause]; + SecDbPrepare(dbconn, (__bridge CFStringRef) sql, &cferror, ^void (sqlite3_stmt *stmt) { + [whereDict.allKeys enumerateObjectsUsingBlock:^(id _Nonnull key, NSUInteger i, BOOL * _Nonnull stop) { + if([whereDict[key] class] != [CKKSSQLWhereObject class]) { + SecDbBindObject(stmt, (int)(i+1), (__bridge CFStringRef) whereDict[key], &cferror); + } + }]; + + SecDbStep(dbconn, stmt, &cferror, ^(bool *stop) { + __block NSMutableDictionary* row = [[NSMutableDictionary alloc] init]; + + [names enumerateObjectsUsingBlock:^(id _Nonnull name, NSUInteger i, BOOL * _Nonnull stop) { + const char * col = (const char *) sqlite3_column_text(stmt, (int)i); + row[name] = col ? [NSString stringWithUTF8String:col] : [NSNull null]; + }]; + + processRow(row); + }); + }); + return true; + }); + + bool ret = (cferror == NULL); + SecTranslateError(error, cferror); + return ret; +} + ++ (bool)queryMaxValueForField:(NSString*)maxField inTable:(NSString*)table where:(NSDictionary*)whereDict columns:(NSArray*)names processRow:(void (^)(NSDictionary*))processRow +{ + __block CFErrorRef cferror = NULL; + + kc_with_dbt(false, &cferror, ^bool(SecDbConnectionRef dbconn) { + NSString* columns = [[names componentsJoinedByString:@", "] stringByAppendingFormat:@", %@", maxField]; + NSString* whereClause = [CKKSSQLDatabaseObject makeWhereClause:whereDict]; + + NSString* sql = [[NSString alloc] initWithFormat:@"SELECT %@ FROM %@%@", columns, table, whereClause]; + SecDbPrepare(dbconn, (__bridge CFStringRef)sql, &cferror, ^(sqlite3_stmt* stmt) { + [whereDict.allKeys enumerateObjectsUsingBlock:^(id _Nonnull key, NSUInteger i, BOOL* _Nonnull stop) { + if ([whereDict[key] class] != [CKKSSQLWhereObject class]) { + SecDbBindObject(stmt, (int)(i+1), (__bridge CFStringRef) whereDict[key], &cferror); + } + }]; + + SecDbStep(dbconn, stmt, &cferror, ^(bool*stop) { + __block NSMutableDictionary* row = [[NSMutableDictionary alloc] init]; + + [names enumerateObjectsUsingBlock:^(id _Nonnull name, NSUInteger i, BOOL * _Nonnull stop) { + const char * col = (const char *) sqlite3_column_text(stmt, (int)i); + row[name] = col ? [NSString stringWithUTF8String:col] : [NSNull null]; + }]; + + processRow(row); + }); + }); + + return true; + }); + + bool ret = (cferror == NULL); + return ret; +} + +#pragma mark - Instance methods + +- (bool) saveToDatabase: (NSError * __autoreleasing *) error { + return [self saveToDatabaseWithConnection:nil error: error]; +} + +- (bool) saveToDatabaseWithConnection: (SecDbConnectionRef) conn error: (NSError * __autoreleasing *) error { + // Todo: turn this into a transaction + + NSDictionary* currentWhereClause = [self whereClauseToFindSelf]; + + // First, if we were loaded from the database and the where clause has changed, delete the old record. + if(self.originalSelfWhereClause && ![self.originalSelfWhereClause isEqualToDictionary: currentWhereClause]) { + secdebug("ckkssql", "Primary key changed; removing old row at %@", self.originalSelfWhereClause); + if(![CKKSSQLDatabaseObject deleteFromTable:[[self class] sqlTable] where: self.originalSelfWhereClause connection:conn error: error]) { + return false; + } + } + + bool ok = [CKKSSQLDatabaseObject saveToDatabaseTable: [[self class] sqlTable] + row: [self sqlValues] + connection: conn + error: error]; + + if(ok) { + secdebug("ckkssql", "Saved %@", self); + } else { + secdebug("ckkssql", "Couldn't save %@: %@", self, error ? *error : @"unknown"); + } + return ok; +} + +- (bool) deleteFromDatabase: (NSError * __autoreleasing *) error { + bool ok = [CKKSSQLDatabaseObject deleteFromTable:[[self class] sqlTable] where: [self whereClauseToFindSelf] connection:nil error: error]; + + if(ok) { + secdebug("ckkssql", "Deleted %@", self); + } else { + secdebug("ckkssql", "Couldn't delete %@: %@", self, error ? *error : @"unknown"); + } + return ok; +} + ++ (bool) deleteAll: (NSError * __autoreleasing *) error { + bool ok = [CKKSSQLDatabaseObject deleteFromTable:[self sqlTable] where: nil connection:nil error: error]; + + if(ok) { + secdebug("ckkssql", "Deleted all %@", self); + } else { + secdebug("ckkssql", "Couldn't delete all %@: %@", self, error ? *error : @"unknown"); + } + return ok; +} + ++ (instancetype) fromDatabaseWhere: (NSDictionary*) whereDict error: (NSError * __autoreleasing *) error { + id ret = [self tryFromDatabaseWhere: whereDict error:error]; + + if(!ret && error) { + *error = [NSError errorWithDomain:@"securityd" + code:errSecItemNotFound + userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat: @"%@ does not exist in database where %@", [self class], whereDict]}]; + } + + return ret; +} + ++ (instancetype) tryFromDatabaseWhere: (NSDictionary*) whereDict error: (NSError * __autoreleasing *) error { + __block id ret = nil; + + [CKKSSQLDatabaseObject queryDatabaseTable: [self sqlTable] + where: whereDict + columns: [self sqlColumns] + groupBy: nil + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + ret = [[self fromDatabaseRow: row] memoizeOriginalSelfWhereClause]; + } + error: error]; + + return ret; +} + ++ (NSArray*) all: (NSError * __autoreleasing *) error { + return [self allWhere: nil error:error]; +} + ++ (NSArray*) allWhere: (NSDictionary*) whereDict error: (NSError * __autoreleasing *) error { + __block NSMutableArray* items = [[NSMutableArray alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [self sqlTable] + where: whereDict + columns: [self sqlColumns] + groupBy: nil + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + [items addObject: [[self fromDatabaseRow: row] memoizeOriginalSelfWhereClause]]; + } + error: error]; + + return items; +} + ++ (NSArray*)fetch: (size_t)count error: (NSError * __autoreleasing *) error { + return [self fetch: count where:nil orderBy:nil error:error]; +} + ++ (NSArray*)fetch: (size_t)count where:(NSDictionary*)whereDict error: (NSError * __autoreleasing *) error { + return [self fetch: count where:whereDict orderBy:nil error:error]; +} + ++ (NSArray*)fetch:(size_t)count + where:(NSDictionary*)whereDict + orderBy:(NSArray*) orderColumns + error:(NSError * __autoreleasing *) error { + __block NSMutableArray* items = [[NSMutableArray alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [self sqlTable] + where: whereDict + columns: [self sqlColumns] + groupBy:nil + orderBy:orderColumns + limit: (ssize_t) count + processRow: ^(NSDictionary* row) { + [items addObject: [[self fromDatabaseRow: row] memoizeOriginalSelfWhereClause]]; + } + error: error]; + + return items; +} + +- (instancetype) memoizeOriginalSelfWhereClause { + _originalSelfWhereClause = [self whereClauseToFindSelf]; + return self; +} + +#pragma mark - Subclass methods + ++ (instancetype) fromDatabaseRow:(NSDictionary *)row { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"A subclass must override %@", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + ++ (NSString*) sqlTable { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"A subclass must override %@", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + ++ (NSArray*) sqlColumns { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"A subclass must override %@", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (NSDictionary*) sqlValues { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"A subclass must override %@", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (NSDictionary*) whereClauseToFindSelf { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"A subclass must override %@", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { + CKKSSQLDatabaseObject *dbCopy = [[[self class] allocWithZone:zone] init]; + dbCopy->_originalSelfWhereClause = _originalSelfWhereClause; + return dbCopy; +} +@end + +#pragma mark - CKKSSQLWhereObject + +@implementation CKKSSQLWhereObject +- (instancetype)initWithOperation:(NSString*)op string: (NSString*) str { + if(self = [super init]) { + _sqlOp = op; + _contents = str; + } + return self; +} + ++ (instancetype)op:(NSString*) op string: (NSString*) str { + return [[CKKSSQLWhereObject alloc] initWithOperation:op string: str]; +} + ++ (instancetype)op:(NSString*) op stringValue: (NSString*) str { + return [[CKKSSQLWhereObject alloc] initWithOperation:op string:[NSString stringWithFormat:@"'%@'", str]]; +} + + +@end diff --git a/keychain/ckks/CKKSScanLocalItemsOperation.h b/keychain/ckks/CKKSScanLocalItemsOperation.h new file mode 100644 index 00000000..cd02e822 --- /dev/null +++ b/keychain/ckks/CKKSScanLocalItemsOperation.h @@ -0,0 +1,44 @@ +/* + * 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 + +#import "keychain/ckks/CKKSGroupOperation.h" + +#if OCTAGON + +@class CKKSKeychainView; +@class CKKSEgoManifest; + +@interface CKKSScanLocalItemsOperation : CKKSResultOperation +@property (weak) CKKSKeychainView* ckks; + +@property size_t recordsFound; +@property size_t recordsAdded; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup; + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSScanLocalItemsOperation.m b/keychain/ckks/CKKSScanLocalItemsOperation.m new file mode 100644 index 00000000..b1544981 --- /dev/null +++ b/keychain/ckks/CKKSScanLocalItemsOperation.m @@ -0,0 +1,274 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSNearFutureScheduler.h" +#import "keychain/ckks/CKKSScanLocalItemsOperation.h" +#import "keychain/ckks/CKKSMirrorEntry.h" +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSGroupOperation.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSViewManager.h" +#import "keychain/ckks/CKKSManifest.h" + +#include +#include +#include +#include + +@interface CKKSScanLocalItemsOperation () +@property CKOperationGroup* ckoperationGroup; +@end + +@implementation CKKSScanLocalItemsOperation + +- (instancetype)init { + return nil; +} +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup { + if(self = [super init]) { + _ckks = ckks; + _ckoperationGroup = ckoperationGroup; + _recordsFound = 0; + _recordsAdded = 0; + } + return self; +} + +- (void) main { + // Take a strong reference. + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksscan", ckks, "no CKKS object"); + return; + } + + [ckks dispatchSyncWithAccountQueue: ^bool{ + if(self.cancelled) { + ckksnotice("ckksscan", ckks, "CKKSScanLocalItemsOperation cancelled, quitting"); + return false; + } + ckks.lastScanLocalItemsOperation = self; + + NSMutableArray* itemsForManifest = [NSMutableArray array]; + + // First, query for all synchronizable items + __block CFErrorRef cferror = NULL; + __block NSError* error = nil; + __block bool newEntries = false; + + // 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; + } + + NSDictionary* queryAttributes = @{(__bridge NSString*) kSecClass: (__bridge NSString*) (*class)->name, + (__bridge NSString*) kSecReturnRef: @(YES), + (__bridge NSString*) kSecAttrSynchronizable: @(YES), + (__bridge NSString*) kSecAttrTombstone: @(NO), + // This works ~as long as~ item views are chosen by view hint only. It's a significant perf win, though. + // SpinTracer: CKKSScanLocalItemsOperation expensive on M8 machines + (__bridge NSString*) kSecAttrSyncViewHint: ckks.zoneName, + }; + ckksinfo("ckksscan", ckks, "Scanning all synchronizable items for: %@", queryAttributes); + + Query *q = query_create_with_limit( (__bridge CFDictionaryRef) queryAttributes, NULL, kSecMatchUnlimited, &cferror); + bool ok = false; + + if(cferror) { + ckkserror("ckksscan", ckks, "couldn't create query: %@", cferror); + SecTranslateError(&error, cferror); + self.error = error; + continue; + } + + ok = kc_with_dbt(true, &cferror, ^(SecDbConnectionRef dbt) { + return SecDbItemQuery(q, NULL, dbt, &cferror, ^(SecDbItemRef item, bool *stop) { + ckksnotice("ckksscan", ckks, "scanning item: %@", item); + + SecDbItemRef itemToSave = NULL; + + // First check: is this a tombstone? If so, skip with prejudice. + if(SecDbItemIsTombstone(item)) { + ckksinfo("ckksscan", ckks, "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; + } + + // 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; + } + + // 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); + + } 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]; + } + ckksinfo("ckksscan", ckks, "Existing mirror entry with UUID %@", uuid); + return; + } + + // 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) { + ckksinfo("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); + } + + // Hurray, we can help! + self.recordsFound += 1; + + CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry withItem: itemToSave action: SecCKKSActionAdd ckks:ckks error: &error]; + + if(error) { + ckkserror("ckksscan", ckks, "Need to upload %@, but can't create outgoing entry: %@", item, error); + self.error = error; + CFReleaseNull(itemToSave); + return; + } + + ckksnotice("ckksscan", ckks, "Syncing new item: %@ %@", oqe, itemToSave); + CFReleaseNull(itemToSave); + + [oqe saveToDatabase: &error]; + if(error) { + ckkserror("ckksscan", ckks, "Need to upload %@ %@, but can't save to database: %@", item, oqe, error); + self.error = error; + return; + } + 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; + } + + ok = query_notify_and_destroy(q, ok, &cferror); + + if(cferror || !ok) { + ckkserror("ckksscan", ckks, "couldn't delete query: %@", cferror); + SecTranslateError(&error, cferror); + self.error = error; + continue; + } + } + + 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; + } + + [manifest saveToDatabase:&error]; + if (error) { + ckkserror("ckksscan", ckks, "could not save manifest to database: %@", error); + self.error = error; + return false; + } + + ckks.egoManifest = manifest; + } + + if(newEntries) { + // Schedule a "view changed" notification + [ckks.notifyViewChangedScheduler trigger]; + + // notify CKKS that it should process these new entries + [ckks processOutgoingQueue:self.ckoperationGroup]; + } + + return true; + }]; +} + +@end; + +#endif diff --git a/keychain/ckks/CKKSSynchronizeOperation.h b/keychain/ckks/CKKSSynchronizeOperation.h new file mode 100644 index 00000000..70534d0e --- /dev/null +++ b/keychain/ckks/CKKSSynchronizeOperation.h @@ -0,0 +1,40 @@ +/* + * 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 +#import "keychain/ckks/CKKSGroupOperation.h" + +#if OCTAGON + +@class CKKSKeychainView; + +@interface CKKSSynchronizeOperation : CKKSGroupOperation +@property (weak) CKKSKeychainView* ckks; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks; + +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/CKKSSynchronizeOperation.m b/keychain/ckks/CKKSSynchronizeOperation.m new file mode 100644 index 00000000..c1c77318 --- /dev/null +++ b/keychain/ckks/CKKSSynchronizeOperation.m @@ -0,0 +1,164 @@ +/* + * 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 "CKKSKeychainView.h" +#import "CKKSGroupOperation.h" +#import "CKKSSynchronizeOperation.h" +#import "CKKSFetchAllRecordZoneChangesOperation.h" +#import "CKKSScanLocalItemsOperation.h" +#import "keychain/ckks/CloudKitCategories.h" + +#if OCTAGON + +@interface CKKSSynchronizeOperation () +@property int32_t restartCount; +@end + +@implementation CKKSSynchronizeOperation + +- (instancetype)init { + return nil; +} +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks { + if(self = [super init]) { + _ckks = ckks; + _restartCount = 0; + } + return self; +} + +- (void)groupStart { + __weak __typeof(self) weakSelf = self; + + /* + * Synchronizations (or resynchronizations) are complicated beasts. We will: + * + * 1. Finish processing the outgoing queue. You can't be in-sync with cloudkit if you have an update that hasn't propagated. + * 2. Kick off a normal CloudKit fetch. + * 3. Process the incoming queue as normal. + * (Note that this requires the keybag to be unlocked.) + * + * So far, this is normal operation. Now: + * + * 4. Start another CloudKit fetch, giving it the nil change tag. This fetches all objects in CloudKit. + * 4a. Compare those objects against our local mirror. If any discrepancies, this is a bug. + * 4b. All conflicts: CloudKit data wins. + * 4c. All items we have that CloudKit doesn't: delete locally. + * + * 5. Process the incoming queue again. This should be empty. + * 6. Scan the local keychain for items which exist locally but are not in CloudKit. Upload them. + * 7. If there are any such items in 6, restart the sync. + */ + + // Promote to strong reference + CKKSKeychainView* ckks = self.ckks; + + // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety. + [ckks dispatchSync: ^bool{ + if(self.cancelled) { + ckksnotice("ckksresync", ckks, "CKKSSynchronizeOperation cancelled, quitting"); + return false; + } + + ckks.lastSynchronizeOperation = self; + + uint32_t steps = 7; + + ckksinfo("ckksresync", ckks, "Beginning resynchronize (attempt %u)", self.restartCount); + + CKOperationGroup* operationGroup = [CKOperationGroup CKKSGroupWithName:@"ckks-resync"]; + + // Step 1 + CKKSOutgoingQueueOperation* outgoingOp = [ckks processOutgoingQueue: operationGroup]; + outgoingOp.name = [NSString stringWithFormat: @"resync-step%u-outgoing", self.restartCount * steps + 1]; + [self dependOnBeforeGroupFinished:outgoingOp]; + + // Step 2 + CKKSFetchAllRecordZoneChangesOperation* fetchOp = [[CKKSFetchAllRecordZoneChangesOperation alloc] initWithCKKSKeychainView:ckks ckoperationGroup:operationGroup]; + fetchOp.name = [NSString stringWithFormat: @"resync-step%u-fetch", self.restartCount * steps + 2]; + [fetchOp addSuccessDependency: outgoingOp]; + [self runBeforeGroupFinished: fetchOp]; + + // Step 3 + CKKSIncomingQueueOperation* incomingOp = [[CKKSIncomingQueueOperation alloc] initWithCKKSKeychainView:ckks errorOnClassAFailure:true]; + incomingOp.name = [NSString stringWithFormat: @"resync-step%u-incoming", self.restartCount * steps + 3]; + [incomingOp addSuccessDependency:fetchOp]; + [self runBeforeGroupFinished:incomingOp]; + + // Now, get serious: + + // Step 4 + CKKSFetchAllRecordZoneChangesOperation* fetchAllOp = [[CKKSFetchAllRecordZoneChangesOperation alloc] initWithCKKSKeychainView:ckks ckoperationGroup:operationGroup]; + fetchAllOp.resync = true; + fetchAllOp.name = [NSString stringWithFormat: @"resync-step%u-fetchAll", self.restartCount * steps + 4]; + [fetchAllOp addSuccessDependency: incomingOp]; + [self runBeforeGroupFinished: fetchAllOp]; + + // Step 5 + CKKSIncomingQueueOperation* incomingResyncOp = [[CKKSIncomingQueueOperation alloc] initWithCKKSKeychainView:ckks errorOnClassAFailure:true]; + incomingResyncOp.name = [NSString stringWithFormat: @"resync-step%u-incoming", self.restartCount * steps + 5]; + [incomingResyncOp addSuccessDependency: fetchAllOp]; + [self runBeforeGroupFinished:incomingResyncOp]; + + // Step 6 + CKKSScanLocalItemsOperation* scan = [[CKKSScanLocalItemsOperation alloc] initWithCKKSKeychainView:ckks ckoperationGroup:operationGroup]; + scan.name = [NSString stringWithFormat: @"resync-step%u-scan", self.restartCount * steps + 6]; + [scan addSuccessDependency: incomingResyncOp]; + [self runBeforeGroupFinished: scan]; + + // Step 7: + CKKSResultOperation* restart = [[CKKSResultOperation alloc] init]; + restart.name = [NSString stringWithFormat: @"resync-step%u-consider-restart", self.restartCount * steps + 7]; + [restart addExecutionBlock:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckksresync: received callback for released object"); + return; + } + + if(scan.recordsFound > 0) { + if(strongSelf.restartCount >= 3) { + // we've restarted too many times. Fail and stop. + ckkserror("ckksresync", ckks, "restarted synchronization too often; Failing"); + strongSelf.error = [NSError errorWithDomain:@"securityd" + code:2 + userInfo:@{NSLocalizedDescriptionKey: @"resynchronization restarted too many times; churn in database?"}]; + } else { + // restart the sync operation. + strongSelf.restartCount += 1; + ckkserror("ckksresync", ckks, "restarting synchronization operation due to new local items"); + [strongSelf groupStart]; + } + } + }]; + + [restart addSuccessDependency: scan]; + [self runBeforeGroupFinished: restart]; + + return true; + }]; +} + +@end; + +#endif diff --git a/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.h b/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.h new file mode 100644 index 00000000..4fdb370d --- /dev/null +++ b/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.h @@ -0,0 +1,41 @@ +/* + * 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 "keychain/ckks/CKKSGroupOperation.h" +#import "keychain/ckks/CKKSKeychainView.h" + +#if OCTAGON + +@interface CKKSUpdateCurrentItemPointerOperation : CKKSGroupOperation +@property (weak) CKKSKeychainView* ckks; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*) ckks + currentPointer:(NSString*)identifier + oldItemUUID:(NSString*)oldItemUUID + newItemUUID:(NSString*)newItemUUID + ckoperationGroup:(CKOperationGroup*)ckoperationGroup; +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m b/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m new file mode 100644 index 00000000..2e2e1d20 --- /dev/null +++ b/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSIncomingQueueEntry.h" +#import "keychain/ckks/CKKSCurrentItemPointer.h" +#import "keychain/ckks/CKKSUpdateCurrentItemPointerOperation.h" +#import "keychain/ckks/CKKSManifest.h" + +#import + +@interface CKKSUpdateCurrentItemPointerOperation () +@property CKModifyRecordsOperation* modifyRecordsOperation; +@property CKOperationGroup* ckoperationGroup; + +@property NSString* currentPointerIdentifier; +@property NSString* oldCurrentItemUUID; +@property NSString* currentItemUUID; +@end + +@implementation CKKSUpdateCurrentItemPointerOperation + +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*) ckks + currentPointer:(NSString*)identifier + oldItemUUID:(NSString*)oldItemUUID + newItemUUID:(NSString*)newItemUUID + ckoperationGroup:(CKOperationGroup*)ckoperationGroup +{ + if((self = [super init])) { + _ckks = ckks; + + _currentPointerIdentifier = identifier; + _oldCurrentItemUUID = oldItemUUID; + _currentItemUUID = newItemUUID; + _ckoperationGroup = ckoperationGroup; + } + return self; +} + +- (void)groupStart { + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckkscurrent", ckks, "no CKKS object"); + self.error = [NSError errorWithDomain:@"securityd" code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"no CKKS object"}]; + return; + } + + __weak __typeof(self) weakSelf = self; + + [ckks dispatchSyncWithAccountQueue:^bool { + if(self.cancelled) { + ckksnotice("ckksscan", ckks, "CKKSUpdateCurrentItemPointerOperation cancelled, quitting"); + return false; + } + + NSError* error = nil; + + // Ensure that there's no pending pointer update + CKKSCurrentItemPointer* cipPending = [CKKSCurrentItemPointer tryFromDatabase:self.currentPointerIdentifier state:SecCKKSProcessedStateRemote zoneID:ckks.zoneID error:&error]; + if(cipPending) { + self.error = [NSError errorWithDomain:@"securityd" code:errSecItemInvalidValue + userInfo:@{NSLocalizedDescriptionKey: [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; + } + + CKKSCurrentItemPointer* cip = [CKKSCurrentItemPointer tryFromDatabase:self.currentPointerIdentifier state:SecCKKSProcessedStateLocal zoneID:ckks.zoneID error:&error]; + + if(cip) { + // Ensure that the itempointer matches the old item + if(![cip.currentItemUUID isEqualToString: self.oldCurrentItemUUID]) { + ckksnotice("ckkscurrent", ckks, "Caller's idea of the current item pointer for %@ doesn't match; rejecting change of current", cip); + self.error = [NSError errorWithDomain:@"securityd" code:errSecItemInvalidValue + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Current pointer does not match given value of '%@', aborting", self.oldCurrentItemUUID]}]; + return false; + } + // Cool. Since you know what you're updating, you're allowed to update! + cip.currentItemUUID = self.currentItemUUID; + + } else if(self.oldCurrentItemUUID) { + // Error case: the client thinks there's a current pointer, but we don't have one + ckksnotice("ckkscurrent", ckks, "Requested to update a current item pointer but one doesn't exist at %@; rejecting change of current", self.currentPointerIdentifier); + self.error = [NSError errorWithDomain:@"securityd" code:errSecItemInvalidValue + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Current pointer does not match given value of '%@', aborting", self.oldCurrentItemUUID]}]; + return false; + } else { + // No current item pointer? How exciting! Let's make you a nice new one. + cip = [[CKKSCurrentItemPointer alloc] initForIdentifier:self.currentPointerIdentifier currentItemUUID:self.currentItemUUID state:SecCKKSProcessedStateLocal zoneID:ckks.zoneID encodedCKRecord:nil]; + ckksnotice("ckkscurrent", ckks, "Creating a new current item pointer: %@", cip); + } + + // Check if either item is currently in any sync queue, and fail if so + NSArray* oqes = [CKKSOutgoingQueueEntry allUUIDs:&error]; + NSArray* iqes = [CKKSIncomingQueueEntry allUUIDs:&error]; + if([oqes containsObject:self.currentItemUUID] || [iqes containsObject:self.currentItemUUID]) { + error = [NSError errorWithDomain:@"securityd" code:errSecItemInvalidValue + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"New item(%@) is being synced; can't set current pointer.", self.currentItemUUID]}]; + } + if([oqes containsObject: self.oldCurrentItemUUID] || [iqes containsObject:self.oldCurrentItemUUID]) { + error = [NSError errorWithDomain:@"securityd" code:errSecItemInvalidValue + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Old item(%@) is being synced; can't set current pointer.", self.oldCurrentItemUUID]}]; + } + + if(error) { + ckkserror("ckkscurrent", ckks, "Error attempting to update current item pointer %@: %@", self.currentPointerIdentifier, error); + self.error = error; + return false; + } + + // Make sure the item is synced, though! + CKKSMirrorEntry* ckme = [CKKSMirrorEntry fromDatabase:cip.currentItemUUID zoneID:ckks.zoneID error:&error]; + if(!ckme || error) { + ckkserror("ckkscurrent", ckks, "Error attempting to set a current item pointer to an item that isn't synced: %@ %@", cip, ckme); + // Why can't you put nulls in dictionary literals? + if(error) { + error = [NSError errorWithDomain:@"securityd" + code:errSecItemNotFound + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"No synced item matching (%@); can't set current pointer.", cip.currentItemUUID], + NSUnderlyingErrorKey:error, + }]; + } else { + error = [NSError errorWithDomain:@"securityd" + code:errSecItemNotFound + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"No synced item matching (%@); can't set current pointer.", cip.currentItemUUID], + }]; + } + self.error = error; + return false; + } + + if ([CKKSManifest shouldSyncManifests]) { + [ckks.egoManifest setCurrentItemUUID:self.currentItemUUID forIdentifier:self.currentPointerIdentifier]; + } + + ckksnotice("ckkscurrent", ckks, "Saving new current item pointer %@", cip); + + NSMutableDictionary* recordsToSave = [[NSMutableDictionary alloc] init]; + 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"; + [self dependOnBeforeGroupFinished: modifyComplete]; + + self.modifyRecordsOperation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave.allValues recordIDsToDelete:nil]; + self.modifyRecordsOperation.atomic = TRUE; + self.modifyRecordsOperation.timeoutIntervalForRequest = 2; + self.modifyRecordsOperation.qualityOfService = NSQualityOfServiceUtility; + self.modifyRecordsOperation.savePolicy = CKRecordSaveIfServerRecordUnchanged; + self.modifyRecordsOperation.group = self.ckoperationGroup; + + self.modifyRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) blockCKKS = strongSelf.ckks; + + if(!error) { + ckksnotice("ckkscurrent", blockCKKS, "Current pointer upload successful for %@: %@", record.recordID.recordName, record); + } else { + ckkserror("ckkscurrent", blockCKKS, "error on row: %@ %@", error, record); + } + }; + + self.modifyRecordsOperation.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *ckerror) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf || !strongCKKS) { + ckkserror("ckkscurrent", strongCKKS, "received callback for released object"); + strongSelf.error = [NSError errorWithDomain:@"securityd" code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"no CKKS object"}]; + [strongCKKS scheduleOperation: modifyComplete]; + return; + } + + if(ckerror) { + ckkserror("ckkscurrent", strongCKKS, "CloudKit returned an error: %@", ckerror); + strongSelf.error = ckerror; + + [ckks dispatchSync:^bool { + return [ckks _onqueueCKWriteFailed:ckerror attemptedRecordsChanged:recordsToSave]; + }]; + + [strongCKKS scheduleOperation: modifyComplete]; + return; + } + + __block NSError* error = nil; + + [strongCKKS dispatchSync: ^bool{ + for(CKRecord* record in savedRecords) { + // Save the item records + if([record.recordType isEqualToString: SecCKRecordCurrentItemType]) { + if([cip matchesCKRecord: record]) { + cip.storedCKRecord = record; + [cip saveToDatabase:&error]; + if(error) { + ckkserror("ckkscurrent", strongCKKS, "Couldn't save new current pointer to database: %@", error); + } + } else { + ckkserror("ckkscurrent", strongCKKS, "CloudKit record does not match saved record, ignoring: %@ %@", record, cip); + } + } + else if ([CKKSManifest shouldSyncManifests] && [record.recordType isEqualToString:SecCKRecordManifestType]) { + CKKSManifest* manifest = [[CKKSManifest alloc] initWithCKRecord:record]; + [manifest saveToDatabase:&error]; + if (error) { + ckkserror("ckkscurrent", strongCKKS, "Couldn't save %@ to manifest: %@", record.recordID.recordName, error); + strongSelf.error = error; + } + } + + // Schedule a 'view changed' notification + [strongCKKS.notifyViewChangedScheduler trigger]; + } + return true; + }]; + + strongSelf.error = error; + [strongCKKS scheduleOperation: modifyComplete]; + }; + + [self dependOnBeforeGroupFinished: self.modifyRecordsOperation]; + [ckks.database addOperation: self.modifyRecordsOperation]; + + return true; + }]; +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSUpdateDeviceStateOperation.h b/keychain/ckks/CKKSUpdateDeviceStateOperation.h new file mode 100644 index 00000000..0d82e7a7 --- /dev/null +++ b/keychain/ckks/CKKSUpdateDeviceStateOperation.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import "keychain/ckks/CKKSGroupOperation.h" +#import "keychain/ckks/CKKSDeviceStateEntry.h" +#import + +@interface CKKSUpdateDeviceStateOperation : CKKSGroupOperation +@property (weak) CKKSKeychainView* ckks; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks rateLimit:(bool)rateLimit ckoperationGroup:(CKOperationGroup*)group; +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSUpdateDeviceStateOperation.m b/keychain/ckks/CKKSUpdateDeviceStateOperation.m new file mode 100644 index 00000000..b112b527 --- /dev/null +++ b/keychain/ckks/CKKSUpdateDeviceStateOperation.m @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSUpdateDeviceStateOperation.h" +#import "keychain/ckks/CKKSCurrentKeyPointer.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSLockStateTracker.h" +#import "keychain/ckks/CKKSSQLDatabaseObject.h" + +@interface CKKSUpdateDeviceStateOperation () +@property CKModifyRecordsOperation* modifyRecordsOperation; +@property CKOperationGroup* group; +@property bool rateLimit; +@end + +@implementation CKKSUpdateDeviceStateOperation + +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks rateLimit:(bool)rateLimit ckoperationGroup:(CKOperationGroup*)group { + if((self = [super init])) { + _ckks = ckks; + _group = group; + _rateLimit = rateLimit; + } + return self; +} + +- (void)groupStart { + CKKSKeychainView* ckks = self.ckks; + if(!ckks) { + ckkserror("ckksdevice", ckks, "no CKKS object"); + self.error = [NSError errorWithDomain:@"securityd" code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"no CKKS object"}]; + return; + } + + CKKSCKAccountStateTracker* accountTracker = ckks.accountTracker; + if(!accountTracker) { + ckkserror("ckksdevice", ckks, "no AccountTracker object"); + self.error = [NSError errorWithDomain:@"securityd" code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"no AccountTracker object"}]; + return; + } + + __weak __typeof(self) weakSelf = self; + + // We must have the ck device ID to run this operation. + if([accountTracker.ckdeviceIDInitialized wait:200*NSEC_PER_SEC]) { + ckkserror("ckksdevice", ckks, "CK device ID not initialized, quitting"); + self.error = [NSError errorWithDomain:@"securityd" code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"CK device ID not initialized"}]; + return; + } + + if(!accountTracker.ckdeviceID) { + ckkserror("ckksdevice", ckks, "CK device ID not initialized, quitting"); + self.error = [NSError errorWithDomain:@"securityd" + code:errSecInternalError + userInfo:@{NSLocalizedDescriptionKey: @"CK device ID null", NSUnderlyingErrorKey:CKKSNilToNSNull(accountTracker.ckdeviceIDError)}]; + return; + } + + [ckks dispatchSyncWithAccountQueue:^bool { + NSError* error = nil; + + CKKSDeviceStateEntry* cdse = [ckks _onqueueCurrentDeviceStateEntry:&error]; + if(error) { + ckkserror("ckksdevice", ckks, "Error creating device state entry; quitting: %@", error); + return false; + } + + if(self.rateLimit) { + NSDate* lastUpdate = cdse.storedCKRecord.modificationDate; + + // Only upload this every 3 days + NSDate* now = [NSDate date]; + NSDateComponents* offset = [[NSDateComponents alloc] init]; + [offset setHour:-3 * 24]; + NSDate* deadline = [[NSCalendar currentCalendar] dateByAddingComponents:offset toDate:now options:0]; + + if(lastUpdate == nil || [lastUpdate compare: deadline] == NSOrderedAscending) { + ckksnotice("ckksdevice", ckks, "Not rate-limiting: last updated %@ vs %@", lastUpdate, deadline); + } else { + ckksnotice("ckksdevice", ckks, "Last update is within 3 days (%@); rate-limiting this operation", lastUpdate); + self.error = [NSError errorWithDomain:@"securityd" + code:errSecInternalError + userInfo:@{NSLocalizedDescriptionKey: @"Rate-limited the CKKSUpdateDeviceStateOperation"}]; + return false; + } + } + + ckksnotice("ckksdevice", ckks, "Saving new device state %@", cdse); + + NSArray* recordsToSave = @[[cdse CKRecordWithZoneID:ckks.zoneID]]; + + // Start a CKModifyRecordsOperation to save this new/updated record. + NSBlockOperation* modifyComplete = [[NSBlockOperation alloc] init]; + modifyComplete.name = @"updateDeviceState-modifyRecordsComplete"; + [self dependOnBeforeGroupFinished: modifyComplete]; + + self.modifyRecordsOperation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave recordIDsToDelete:nil]; + self.modifyRecordsOperation.atomic = TRUE; + self.modifyRecordsOperation.timeoutIntervalForRequest = 2; + self.modifyRecordsOperation.qualityOfService = NSQualityOfServiceUtility; + self.modifyRecordsOperation.savePolicy = CKRecordSaveAllKeys; // Overwrite anything in CloudKit: this is our state now + self.modifyRecordsOperation.group = self.group; + + self.modifyRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) blockCKKS = strongSelf.ckks; + + if(!error) { + ckksnotice("ckksdevice", blockCKKS, "Device state record upload successful for %@: %@", record.recordID.recordName, record); + } else { + ckkserror("ckksdevice", blockCKKS, "error on row: %@ %@", error, record); + } + }; + + self.modifyRecordsOperation.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *ckerror) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + __strong __typeof(strongSelf.ckks) strongCKKS = strongSelf.ckks; + if(!strongSelf || !strongCKKS) { + ckkserror("ckksdevice", strongCKKS, "received callback for released object"); + strongSelf.error = [NSError errorWithDomain:@"securityd" code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey: @"no CKKS object"}]; + [strongSelf runBeforeGroupFinished:modifyComplete]; + return; + } + + if(ckerror) { + ckkserror("ckksdevice", strongCKKS, "CloudKit returned an error: %@", ckerror); + strongSelf.error = ckerror; + [strongSelf runBeforeGroupFinished:modifyComplete]; + return; + } + + __block NSError* error = nil; + + [strongCKKS dispatchSync: ^bool{ + for(CKRecord* record in savedRecords) { + // Save the item records + if([record.recordType isEqualToString: SecCKRecordDeviceStateType]) { + CKKSDeviceStateEntry* newcdse = [[CKKSDeviceStateEntry alloc] initWithCKRecord:record]; + [newcdse saveToDatabase:&error]; + if(error) { + ckkserror("ckksdevice", strongCKKS, "Couldn't save new device state(%@) to database: %@", newcdse, error); + } + } + } + return true; + }]; + + strongSelf.error = error; + [strongSelf runBeforeGroupFinished:modifyComplete]; + }; + + [self dependOnBeforeGroupFinished: self.modifyRecordsOperation]; + [ckks.database addOperation: self.modifyRecordsOperation]; + + return true; + }]; +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CKKSViewManager.h b/keychain/ckks/CKKSViewManager.h new file mode 100644 index 00000000..699575b9 --- /dev/null +++ b/keychain/ckks/CKKSViewManager.h @@ -0,0 +1,129 @@ +/* + * 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 +#include +#import "keychain/ckks/CKKS.h" + +#import "keychain/ckks/CKKSControlProtocol.h" +#if OCTAGON +#import "keychain/ckks/CloudKitDependencies.h" +#import "keychain/ckks/CKKSAPSReceiver.h" +#import "keychain/ckks/CKKSCKAccountStateTracker.h" +#import "keychain/ckks/CKKSLockStateTracker.h" +#import "keychain/ckks/CKKSRateLimiter.h" +#import "keychain/ckks/CKKSNotifier.h" +#import "keychain/ckks/CKKSCondition.h" +#endif + +@class CKKSKeychainView, CKKSRateLimiter; + +#if !OCTAGON +@interface CKKSViewManager : NSObject +#else +@interface CKKSViewManager : NSObject + +@property CKContainer* container; +@property CKKSCKAccountStateTracker* accountTracker; +@property CKKSLockStateTracker* lockStateTracker; +@property bool initializeNewZones; + +// Signaled when SecCKKSInitialize is complete, as it's async and likes to fire after tests are complete +@property CKKSCondition* completedSecCKKSInitialize; + +@property CKKSRateLimiter* globalRateLimiter; + +// Set this and all newly-created zones will wait to do setup until it completes. +// this gives you a bit more control than initializedNewZones above. +@property NSOperation* zoneStartupDependency; + +- (instancetype)initCloudKitWithContainerName: (NSString*) containerName usePCS:(bool)usePCS; +- (instancetype)initWithContainerName: (NSString*) containerNamee + usePCS: (bool)usePCS + fetchRecordZoneChangesOperationClass: (Class) fetchRecordZoneChangesOperationClass + modifySubscriptionsOperationClass: (Class) modifySubscriptionsOperationClass + modifyRecordZonesOperationClass: (Class) modifyRecordZonesOperationClass + apsConnectionClass: (Class) apsConnectionClass + nsnotificationCenterClass: (Class) nsnotificationCenterClass + notifierClass: (Class) notifierClass + setupHold:(NSOperation*) setupHold; + +- (CKKSKeychainView*)findView:(NSString*)viewName; +- (CKKSKeychainView*)findOrCreateView:(NSString*)viewName; ++ (CKKSKeychainView*)findOrCreateView:(NSString*)viewName; +- (void)setView: (CKKSKeychainView*) obj; +- (void)clearView:(NSString*) viewName; + +- (NSDictionary*)activeTLKs; + +// Call this to bring zones up (and to do so automatically in the future) +- (void)initializeZones; + +- (NSString*)viewNameForItem: (SecDbItemRef) item; + +- (void) handleKeychainEventDbConnection: (SecDbConnectionRef) dbconn source:(SecDbTransactionSource)txionSource added: (SecDbItemRef) added deleted: (SecDbItemRef) deleted; + +-(void)setCurrentItemForAccessGroup:(SecDbItemRef)newItem + hash:(NSData*)newItemSHA1 + accessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + viewHint:(NSString*)viewHint + replacing:(SecDbItemRef)oldItem + hash:(NSData*)oldItemSHA1 + complete:(void (^) (NSError* operror)) complete; + +-(void)getCurrentItemForAccessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + viewHint:(NSString*)viewHint + fetchCloudValue:(bool)fetchCloudValue + complete:(void (^) (NSString* uuid, NSError* operror)) complete; + +- (NSString*)viewNameForAttributes: (NSDictionary*) item; + +- (void)registerSyncStatusCallback: (NSString*) uuid callback: (SecBoolNSErrorCallback) callback; + +// Cancels pending operations owned by this view manager +- (void)cancelPendingOperations; + +// Use these to acquire (and set) the singleton ++ (instancetype) manager; ++ (instancetype) resetManager: (bool) reset setTo: (CKKSViewManager*) obj; + +// Called by XPC every 24 hours +-(void)xpc24HrNotification; + +/* Interface to CCKS control channel */ +- (xpc_endpoint_t)xpcControlEndpoint; + +/* White-box testing only */ +- (CKKSKeychainView*)restartZone:(NSString*)viewName; + +// Returns the viewList for a CKKSViewManager ++(NSSet*)viewList; + +// Notify sbd to re-backup. +-(void)notifyNewTLKsInKeychain; ++(void)syncBackupAndNotifyAboutSync; + +#endif // OCTAGON +@end diff --git a/keychain/ckks/CKKSViewManager.m b/keychain/ckks/CKKSViewManager.m new file mode 100644 index 00000000..7b6b38f5 --- /dev/null +++ b/keychain/ckks/CKKSViewManager.m @@ -0,0 +1,832 @@ +/* + * 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 "keychain/ckks/CKKSViewManager.h" +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSSynchronizeOperation.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" +#import "keychain/ckks/CKKSNearFutureScheduler.h" +#import "keychain/ckks/CKKSNotifier.h" +#import "keychain/ckks/CKKSCondition.h" +#import "keychain/ckks/CloudKitCategories.h" +#import "CKKSAnalyticsLogger.h" + +#import "SecEntitlements.h" + +#include +#include +#include +#include + +#import +#import + +#include +#include + +#if OCTAGON +#import +#import +#endif + +@interface CKKSViewManager () +#if OCTAGON +@property NSXPCListener *listener; + +// Once you set these, all CKKSKeychainViews created will use them +@property (readonly) Class fetchRecordZoneChangesOperationClass; +@property (readonly) Class modifySubscriptionsOperationClass; +@property (readonly) Class modifyRecordZonesOperationClass; +@property (readonly) Class apsConnectionClass; +@property (readonly) Class notifierClass; +@property (readonly) Class nsnotificationCenterClass; + +@property NSMutableDictionary* views; + +@property NSMutableDictionary* pendingSyncCallbacks; +@property CKKSNearFutureScheduler* savedTLKNotifier;; +@property NSOperationQueue* operationQueue; +#endif +@end + +@implementation CKKSViewManager +#if OCTAGON + +- (instancetype)initCloudKitWithContainerName: (NSString*) containerName usePCS:(bool)usePCS { + return [self initWithContainerName:containerName + usePCS:usePCS + fetchRecordZoneChangesOperationClass:[CKFetchRecordZoneChangesOperation class] + modifySubscriptionsOperationClass:[CKModifySubscriptionsOperation class] + modifyRecordZonesOperationClass:[CKModifyRecordZonesOperation class] + apsConnectionClass:[APSConnection class] + nsnotificationCenterClass:[NSNotificationCenter class] + notifierClass:[CKKSNotifyPostNotifier class] + setupHold:nil]; +} + +- (instancetype)initWithContainerName: (NSString*) containerName + usePCS:(bool)usePCS + fetchRecordZoneChangesOperationClass: (Class) fetchRecordZoneChangesOperationClass + modifySubscriptionsOperationClass: (Class) modifySubscriptionsOperationClass + modifyRecordZonesOperationClass: (Class) modifyRecordZonesOperationClass + apsConnectionClass: (Class) apsConnectionClass + nsnotificationCenterClass: (Class) nsnotificationCenterClass + notifierClass: (Class) notifierClass + setupHold: (NSOperation*) setupHold { + if(self = [super init]) { + _fetchRecordZoneChangesOperationClass = fetchRecordZoneChangesOperationClass; + _modifySubscriptionsOperationClass = modifySubscriptionsOperationClass; + _modifyRecordZonesOperationClass = modifyRecordZonesOperationClass; + _apsConnectionClass = apsConnectionClass; + _nsnotificationCenterClass = nsnotificationCenterClass; + _notifierClass = notifierClass; + + _container = [self makeCKContainer: containerName usePCS:usePCS]; + _accountTracker = [[CKKSCKAccountStateTracker alloc] init:self.container nsnotificationCenterClass:nsnotificationCenterClass]; + _lockStateTracker = [[CKKSLockStateTracker alloc] init]; + + _operationQueue = [[NSOperationQueue alloc] init]; + + _views = [[NSMutableDictionary alloc] init]; + _pendingSyncCallbacks = [[NSMutableDictionary alloc] init]; + + _zoneStartupDependency = setupHold; + _initializeNewZones = false; + + _completedSecCKKSInitialize = [[CKKSCondition alloc] init]; + + __weak __typeof(self) weakSelf = self; + _savedTLKNotifier = [[CKKSNearFutureScheduler alloc] initWithName: @"newtlks" delay:5*NSEC_PER_SEC keepProcessAlive:true block:^{ + [weakSelf notifyNewTLKsInKeychain]; + }]; + + _listener = [NSXPCListener anonymousListener]; + _listener.delegate = self; + [_listener resume]; + } + return self; +} + +-(CKContainer*)makeCKContainer:(NSString*)containerName usePCS:(bool)usePCS { + CKContainer* container = [CKContainer containerWithIdentifier:containerName]; + if(!usePCS) { + CKContainerOptions* containerOptions = [[CKContainerOptions alloc] init]; + containerOptions.bypassPCSEncryption = YES; + + // We don't have a great way to set these, so replace the entire container object + container = [[CKContainer alloc] initWithContainerID: container.containerID options:containerOptions]; + } + return container; +} + +-(void)dealloc { + [self clearAllViews]; +} + +dispatch_queue_t globalZoneStateQueue = NULL; +dispatch_once_t globalZoneStateQueueOnce; + +// We can't load the rate limiter in an init method, as the method might end up calling itself (if the database layer isn't yet initialized). +// Lazy-load it here. +- (CKKSRateLimiter*)getGlobalRateLimiter { + dispatch_once(&globalZoneStateQueueOnce, ^{ + globalZoneStateQueue = dispatch_queue_create("CKKS global zone state", DISPATCH_QUEUE_SERIAL); + }); + + if(_globalRateLimiter != nil) { + return _globalRateLimiter; + } + + __block CKKSRateLimiter* blocklimit = nil; + + dispatch_sync(globalZoneStateQueue, ^{ + NSError* error = nil; + + // Special object containing state for all zones. Currently, just the rate limiter. + CKKSZoneStateEntry* allEntry = [CKKSZoneStateEntry tryFromDatabase: @"all" error:&error]; + + if(error) { + secerror("CKKSViewManager: couldn't load global zone state: %@", error); + } + + if(!error && allEntry.rateLimiter) { + blocklimit = allEntry.rateLimiter; + } else { + blocklimit = [[CKKSRateLimiter alloc] init]; + } + }); + _globalRateLimiter = blocklimit; + return _globalRateLimiter; +} + +// Mostly exists to be mocked out. ++(NSSet*)viewList { + return CFBridgingRelease(SOSViewCopyViewSet(kViewSetCKKS)); +} + +- (void)setView: (CKKSKeychainView*) obj { + CKKSKeychainView* kcv = nil; + + @synchronized(self.views) { + kcv = self.views[obj.zoneName]; + self.views[obj.zoneName] = obj; + } + + if(kcv) { + [kcv cancelAllOperations]; + } +} + +- (void)clearAllViews { + NSArray* tempviews = nil; + @synchronized(self.views) { + tempviews = [self.views.allValues copy]; + [self.views removeAllObjects]; + } + + for(CKKSKeychainView* view in tempviews) { + [view cancelAllOperations]; + } +} + +- (void)clearView:(NSString*) viewName { + CKKSKeychainView* kcv = nil; + @synchronized(self.views) { + kcv = self.views[viewName]; + self.views[viewName] = nil; + } + + if(kcv) { + [kcv cancelAllOperations]; + } +} + +- (CKKSKeychainView*)findView:(NSString*)viewName { + if(!viewName) { + return nil; + } + @synchronized(self.views) { + return self.views[viewName]; + } +} + +- (CKKSKeychainView*)findOrCreateView:(NSString*)viewName { + @synchronized(self.views) { + CKKSKeychainView* kcv = self.views[viewName]; + if(kcv) { + return kcv; + } + + self.views[viewName] = [[CKKSKeychainView alloc] initWithContainer: self.container + zoneName: viewName + accountTracker: self.accountTracker + lockStateTracker: self.lockStateTracker + savedTLKNotifier: self.savedTLKNotifier + fetchRecordZoneChangesOperationClass: self.fetchRecordZoneChangesOperationClass + modifySubscriptionsOperationClass: self.modifySubscriptionsOperationClass + modifyRecordZonesOperationClass: self.modifyRecordZonesOperationClass + apsConnectionClass: self.apsConnectionClass + notifierClass: self.notifierClass]; + + if(self.zoneStartupDependency) { + [self.views[viewName].zoneSetupOperation addDependency: self.zoneStartupDependency]; + } + + if(self.initializeNewZones) { + [self.views[viewName] initializeZone]; + } + + return self.views[viewName]; + } +} ++ (CKKSKeychainView*)findOrCreateView:(NSString*)viewName { + return [[CKKSViewManager manager] findOrCreateView: viewName]; +} + +- (NSDictionary *)activeTLKs +{ + NSMutableDictionary *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; +} + +- (CKKSKeychainView*)restartZone:(NSString*)viewName { + @synchronized(self.views) { + self.views[viewName] = nil; + } + return [self findOrCreateView: viewName]; +} + +// Allows all views to begin initializing, and opens the floodgates so that new views will be initalized immediately +- (void)initializeZones { + if(!SecCKKSIsEnabled()) { + secnotice("ckks", "Not initializing CKKS view set as CKKS is disabled"); + return; + } + + @synchronized(self.views) { + self.initializeNewZones = true; + + NSSet* viewSet = [CKKSViewManager viewList]; + for(NSString* s in viewSet) { + [self findOrCreateView:s]; // initializes any newly-created views + } + } +} + +- (NSString*)viewNameForViewHint: (NSString*) viewHint { + // For now, choose view based on viewhints. + if(viewHint && ![viewHint isEqual: [NSNull null]]) { + return viewHint; + } + + // If there isn't a provided view hint, use the "keychain" view if we're testing. Otherwise, nil. + if(SecCKKSTestsEnabled()) { + return @"keychain"; + } else { + return nil; + } +} + +- (NSString*)viewNameForItem: (SecDbItemRef) item { + CFErrorRef cferror = NULL; + NSString* viewHint = (__bridge NSString*) SecDbItemGetValue(item, &v7vwht, &cferror); + + if(cferror) { + secerror("ckks: Couldn't fetch the viewhint for some reason: %@", cferror); + CFReleaseNull(cferror); + viewHint = nil; + } + + return [self viewNameForViewHint: viewHint]; +} + +- (NSString*)viewNameForAttributes: (NSDictionary*) item { + return [self viewNameForViewHint: item[(id)kSecAttrSyncViewHint]]; +} + +- (void)registerSyncStatusCallback: (NSString*) uuid callback: (SecBoolNSErrorCallback) callback { + // Someone is requesting future notification of this item. + @synchronized(self.pendingSyncCallbacks) { + self.pendingSyncCallbacks[uuid] = callback; + } +} + +- (void) handleKeychainEventDbConnection: (SecDbConnectionRef) dbconn source:(SecDbTransactionSource)txionSource added: (SecDbItemRef) added deleted: (SecDbItemRef) deleted { + + SecDbItemRef modified = added ? added : deleted; + + NSString* viewName = [self viewNameForItem: modified]; + NSString* keyViewName = [CKKSKey isItemKeyForKeychainView: modified]; + + if(keyViewName) { + // This might be some key material for this view! Poke it. + CKKSKeychainView* view = [self findView: keyViewName]; + + if(!SecCKKSTestDisableKeyNotifications()) { + ckksnotice("ckks", view, "Potential new key material from %@ (source %lu)", keyViewName, txionSource); + [view keyStateMachineRequestProcess]; + } else { + ckksnotice("ckks", view, "Ignoring potential new key material from %@ (source %lu)", keyViewName, txionSource); + } + return; + } + + // When SOS is in charge of a view, CKKS is not. + // Since this isn't a CKKS key item, we don't care about it. + if(txionSource == kSecDbSOSTransaction) { + secinfo("ckks", "Ignoring new non-CKKS item in kSecDbSOSTransaction notification"); + } + + // Looks like a normal item. Proceed! + CKKSKeychainView* view = [self findView:viewName]; + + NSString* uuid = (__bridge NSString*) SecDbItemGetValue(modified, &v10itemuuid, NULL); + SecBoolNSErrorCallback syncCallback = nil; + if(uuid) { + @synchronized(self.pendingSyncCallbacks) { + syncCallback = self.pendingSyncCallbacks[uuid]; + self.pendingSyncCallbacks[uuid] = nil; + + if(syncCallback) { + secinfo("ckks", "Have a pending callback for %@; passing along", uuid); + } + } + } + + if(!view) { + secinfo("ckks", "No CKKS view for %@, skipping: %@", viewName, modified); + if(syncCallback) { + syncCallback(false, [NSError errorWithDomain:@"securityd" + code:kSOSCCNoSuchView + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No syncing view for '%@'", viewName]}]); + } + return; + } + + ckksnotice("ckks", view, "Routing item to zone %@: %@", viewName, modified); + [view handleKeychainEventDbConnection: dbconn added:added deleted:deleted rateLimiter:self.globalRateLimiter syncCallback: syncCallback]; +} + +-(void)setCurrentItemForAccessGroup:(SecDbItemRef)newItem + hash:(NSData*)newItemSHA1 + accessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + viewHint:(NSString*)viewHint + replacing:(SecDbItemRef)oldItem + hash:(NSData*)oldItemSHA1 + complete:(void (^) (NSError* operror)) complete +{ + CKKSKeychainView* view = [self findView:viewHint]; + + if(!view) { + secinfo("ckks", "No CKKS view for %@, skipping current request", viewHint); + complete([NSError errorWithDomain:@"securityd" + code:kSOSCCNoSuchView + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No syncing view for view hint '%@'", viewHint]}]); + return; + } + + [view setCurrentItemForAccessGroup:newItem + hash:newItemSHA1 + accessGroup:accessGroup + identifier:identifier + replacing:oldItem + hash:oldItemSHA1 + complete:complete]; +} + +-(void)getCurrentItemForAccessGroup:(NSString*)accessGroup + identifier:(NSString*)identifier + viewHint:(NSString*)viewHint + fetchCloudValue:(bool)fetchCloudValue + complete:(void (^) (NSString* uuid, NSError* operror)) complete +{ + CKKSKeychainView* view = [self findView:viewHint]; + if(!view) { + secinfo("ckks", "No CKKS view for %@, skipping current fetch request", viewHint); + complete(NULL, [NSError errorWithDomain:@"securityd" + code:kSOSCCNoSuchView + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No view for '%@'", viewHint]}]); + return; + } + + [view getCurrentItemForAccessGroup:accessGroup + identifier:identifier + fetchCloudValue:fetchCloudValue + complete:complete]; +} + + ++ (instancetype) manager { + return [self resetManager: false setTo: nil]; +} + ++ (instancetype) resetManager: (bool) reset setTo: (CKKSViewManager*) obj { + static CKKSViewManager* manager = nil; + + if([CKDatabase class] == nil) { + secerror("CKKS: CloudKit.framework appears to not be linked. Can't create CKKS objects."); + return nil; + } + + if(!manager || reset || obj) { + @synchronized([self class]) { + if(obj != nil) { + [manager clearAllViews]; + manager = obj; + } else { + if(reset) { + [manager clearAllViews]; + manager = nil; + } else if (manager == nil) { + manager = [[CKKSViewManager alloc] initCloudKitWithContainerName:SecCKKSContainerName usePCS:SecCKKSContainerUsePCS]; + } + } + } + } + + return manager; +} + +- (void)cancelPendingOperations { + [self.savedTLKNotifier cancel]; +} + +-(void)notifyNewTLKsInKeychain { + // Why two functions here? Limitation of OCMock, unfortunately: can't stub and expect the same method + secnotice("ckksbackup", "New TLKs have arrived"); + [CKKSViewManager syncBackupAndNotifyAboutSync]; +} + ++(void)syncBackupAndNotifyAboutSync { + SOSAccount* account = (__bridge SOSAccount*)SOSKeychainAccountGetSharedAccount(); + + [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + CFErrorRef error = NULL; + NSSet* ignore = CFBridgingRelease(SOSAccountCopyBackupPeersAndForceSync(txn, &error)); + (void)ignore; + + if(error) { + secerror("ckksbackup: Couldn't process sync with backup peers: %@", error); + } else { + secnotice("ckksbackup", "telling CloudServices about TLK arrival"); + notify_post(kSecItemBackupNotification); + }; + }]; +} + +#pragma mark - XPC Endpoint + +- (xpc_endpoint_t)xpcControlEndpoint { + return [_listener.endpoint _endpoint]; +} + +- (BOOL)listener:(__unused NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection { + NSNumber *num = [newConnection valueForEntitlement:(__bridge NSString *)kSecEntitlementPrivateCKKS]; + if (![num isKindOfClass:[NSNumber class]] || ![num boolValue]) { + secinfo("ckks", "Client pid: %d doesn't have entitlement: %@", + [newConnection processIdentifier], kSecEntitlementPrivateCKKS); + return NO; + } + newConnection.exportedInterface = CKKSSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(CKKSControlProtocol)]); + newConnection.exportedObject = self; + + [newConnection resume]; + + return YES; +} +#pragma mark - RPCs to manage and report state + +- (void)performanceCounters:(void(^)(NSDictionary *counter))reply { + reply(@{ @"fake" : @(10) }); +} + +- (void)rpcResetLocal:(NSString*)viewName reply: (void(^)(NSError* result)) reply { + NSArray* actualViews = nil; + if(viewName) { + secnotice("ckksreset", "Received a local reset RPC for zone %@", viewName); + CKKSKeychainView* view = self.views[viewName]; + + if(!view) { + secerror("ckks: Zone %@ does not exist!", viewName); + reply([NSError errorWithDomain:@"securityd" + code:kSOSCCNoSuchView + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No view for '%@'", viewName]}]); + return; + } + + actualViews = @[view]; + } else { + secnotice("ckksreset", "Received a local reset RPC for all zones"); + @synchronized(self.views) { + // Can't safely iterate a mutable collection, so copy it. + actualViews = [self.views.allValues copy]; + } + } + + CKKSResultOperation* op = [CKKSResultOperation named:@"local-reset-zones-waiter" withBlock:^{}]; + + for(CKKSKeychainView* view in actualViews) { + ckksnotice("ckksreset", view, "Beginning local reset for %@", view); + [op addSuccessDependency:[view resetLocalData]]; + } + + [op timeout:120*NSEC_PER_SEC]; + [self.operationQueue addOperation: op]; + + [op waitUntilFinished]; + if(op.error) { + secnotice("ckksreset", "Completed rpcResetLocal"); + } else { + secnotice("ckksreset", "Completed rpcResetLocal with error: %@", op.error); + } + reply(op.error); +} + +- (void)rpcResetCloudKit:(NSString*)viewName reply: (void(^)(NSError* result)) reply { + NSArray* actualViews = nil; + if(viewName) { + secnotice("ckksreset", "Received a cloudkit reset RPC for zone %@", viewName); + CKKSKeychainView* view = self.views[viewName]; + + if(!view) { + secerror("ckks: Zone %@ does not exist!", viewName); + reply([NSError errorWithDomain:@"securityd" + code:kSOSCCNoSuchView + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No view for '%@'", viewName]}]); + return; + } + + actualViews = @[view]; + } else { + secnotice("ckksreset", "Received a cloudkit reset RPC for all zones"); + @synchronized(self.views) { + // Can't safely iterate a mutable collection, so copy it. + actualViews = [self.views.allValues copy]; + } + } + + CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-reset-zones-waiter" withBlock:^{}]; + + for(CKKSKeychainView* view in actualViews) { + ckksnotice("ckksreset", view, "Beginning CloudKit reset for %@", view); + [op addSuccessDependency:[view resetCloudKitZone]]; + } + + [op timeout:120*NSEC_PER_SEC]; + [self.operationQueue addOperation: op]; + + [op waitUntilFinished]; + if(op.error) { + secnotice("ckksreset", "Completed rpcResetCloudKit"); + } else { + secnotice("ckksreset", "Completed rpcResetCloudKit with error: %@", op.error); + } + reply(op.error); +} + +- (void)rpcResync:(NSString*)viewName reply: (void(^)(NSError* result)) reply { + secnotice("ckksresync", "Received a resync RPC for zone %@. Beginning resync...", viewName); + + NSArray* actualViews = nil; + if(viewName) { + secnotice("ckks", "Received a resync RPC for zone %@", viewName); + CKKSKeychainView* view = self.views[viewName]; + + if(!view) { + secerror("ckks: Zone %@ does not exist!", viewName); + reply(nil); + return; + } + + actualViews = @[view]; + + } else { + @synchronized(self.views) { + // Can't safely iterate a mutable collection, so copy it. + actualViews = [self.views.allValues copy]; + } + } + + CKKSResultOperation* op = [[CKKSResultOperation alloc] init]; + op.name = @"rpc-resync"; + __weak __typeof(op) weakOp = op; + [op addExecutionBlock:^{ + __strong __typeof(op) strongOp = weakOp; + secnotice("ckks", "Ending rsync rpc with %@", strongOp.error); + }]; + + for(CKKSKeychainView* view in actualViews) { + ckksnotice("ckksresync", view, "Beginning resync for %@", view); + + CKKSSynchronizeOperation* resyncOp = [view resyncWithCloud]; + [op addSuccessDependency:resyncOp]; + } + + [op timeout:120*NSEC_PER_SEC]; + [self.operationQueue addOperation:op]; + [op waitUntilFinished]; + reply(op.error); +} + +- (void)rpcStatus: (NSString*)viewName reply: (void(^)(NSArray* result, NSError* error)) reply { + NSMutableArray* a = [[NSMutableArray alloc] init]; + + NSArray* actualViews = nil; + if(viewName) { + secnotice("ckks", "Received a status RPC for zone %@", viewName); + CKKSKeychainView* view = self.views[viewName]; + + if(!view) { + secerror("ckks: Zone %@ does not exist!", viewName); + reply(nil, nil); + return; + } + + actualViews = @[view]; + + } else { + @synchronized(self.views) { + // Can't safely iterate a mutable collection, so copy it. + actualViews = self.views.allValues; + } + } + + for(CKKSKeychainView* view in actualViews) { + ckksnotice("ckks", view, "Fetching status for %@", view.zoneName); + NSDictionary* status = [view status]; + ckksinfo("ckks", view, "Status is %@", status); + if(status) { + [a addObject: status]; + } + } + reply(a, nil); + return; +} + +- (void)rpcFetchAndProcessChanges:(NSString*)viewName reply: (void(^)(NSError* result))reply { + [self rpcFetchAndProcessChanges:viewName classA:false reply: (void(^)(NSError* result))reply]; +} + +- (void)rpcFetchAndProcessClassAChanges:(NSString*)viewName reply: (void(^)(NSError* result))reply { + [self rpcFetchAndProcessChanges:viewName classA:true reply:(void(^)(NSError* result))reply]; +} + +- (void)rpcFetchAndProcessChanges:(NSString*)viewName classA:(bool)classAError reply: (void(^)(NSError* result)) reply { + NSArray* actualViews = nil; + if(viewName) { + secnotice("ckks", "Received a fetch RPC for zone %@", viewName); + CKKSKeychainView* view = self.views[viewName]; + + if(!view) { + secerror("ckks: Zone %@ does not exist!", viewName); + reply([NSError errorWithDomain:@"securityd" + code:kSOSCCNoSuchView + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No view for '%@'", viewName]}]); + return; + } + + actualViews = @[view]; + } else { + secnotice("ckks", "Received a fetch RPC for all zones"); + @synchronized(self.views) { + // Can't safely iterate a mutable collection, so copy it. + actualViews = [self.views.allValues copy]; + } + } + + CKKSResultOperation* blockOp = [[CKKSResultOperation alloc] init]; + blockOp.name = @"rpc-fetch-and-process-result"; + __weak __typeof(blockOp) weakBlockOp = blockOp; + // Use the completion block instead of the operation block, so that it runs even if the cancel fires + [blockOp setCompletionBlock:^{ + __strong __typeof(blockOp) strongBlockOp = weakBlockOp; + [strongBlockOp allDependentsSuccessful]; + reply(strongBlockOp.error); + }]; + + for(CKKSKeychainView* view in actualViews) { + ckksnotice("ckks", view, "Beginning fetch for %@", view); + + CKKSResultOperation* op = [view processIncomingQueue:classAError after:[view.zoneChangeFetcher requestSuccessfulFetch: CKKSFetchBecauseAPIFetchRequest]]; + [blockOp addDependency:op]; + } + + [self.operationQueue addOperation: [blockOp timeout:60*NSEC_PER_SEC]]; +} + +- (void)rpcPushOutgoingChanges:(NSString*)viewName reply: (void(^)(NSError* result))reply { + NSArray* actualViews = nil; + if(viewName) { + secnotice("ckks", "Received a push RPC for zone %@", viewName); + CKKSKeychainView* view = self.views[viewName]; + + if(!view) { + secerror("ckks: Zone %@ does not exist!", viewName); + reply([NSError errorWithDomain:@"securityd" + code:kSOSCCNoSuchView + userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No view for '%@'", viewName]}]); + return; + } + + actualViews = @[view]; + } else { + secnotice("ckks", "Received a push RPC for all zones"); + @synchronized(self.views) { + // Can't safely iterate a mutable collection, so copy it. + actualViews = [self.views.allValues copy]; + } + } + + CKKSResultOperation* blockOp = [[CKKSResultOperation alloc] init]; + blockOp.name = @"rpc-push"; + __weak __typeof(blockOp) weakBlockOp = blockOp; + // Use the completion block instead of the operation block, so that it runs even if the cancel fires + [blockOp setCompletionBlock:^{ + __strong __typeof(blockOp) strongBlockOp = weakBlockOp; + [strongBlockOp allDependentsSuccessful]; + reply(strongBlockOp.error); + }]; + + for(CKKSKeychainView* view in actualViews) { + ckksnotice("ckks-rpc", view, "Beginning push for %@", view); + + CKKSResultOperation* op = [view processOutgoingQueue: [CKOperationGroup CKKSGroupWithName:@"rpc-push"]]; + [blockOp addDependency:op]; + } + + [self.operationQueue addOperation: [blockOp timeout:60*NSEC_PER_SEC]]; +} + +- (void)rpcGetAnalyticsSysdiagnoseWithReply:(void (^)(NSString* sysdiagnose, NSError* error))reply +{ + NSError* error = nil; + NSString* sysdiagnose = [[CKKSAnalyticsLogger logger] getSysdiagnoseDumpWithError:&error]; + reply(sysdiagnose, error); +} + +- (void)rpcGetAnalyticsJSONWithReply:(void (^)(NSData* json, NSError* error))reply +{ + NSError* error = nil; + NSData* json = [[CKKSAnalyticsLogger logger] getLoggingJSONWithError:&error]; + reply(json, error); +} + +- (void)rpcForceUploadAnalyticsWithReply:(void (^)(BOOL success, NSError* error))reply +{ + NSError* error = nil; + BOOL result = [[CKKSAnalyticsLogger logger] forceUploadWithError:&error]; + reply(result, error); +} + +-(void)xpc24HrNotification { + // XPC has poked us and said we should do some cleanup! + + // For now, poke the views and tell them to update their device states if they'd like + NSArray* actualViews = nil; + @synchronized(self.views) { + // Can't safely iterate a mutable collection, so copy it. + actualViews = self.views.allValues; + } + + secnotice("ckks", "Received a 24hr notification from XPC"); + CKOperationGroup* group = [CKOperationGroup CKKSGroupWithName:@"periodic-device-state-update"]; + for(CKKSKeychainView* view in actualViews) { + ckksnotice("ckks", view, "Starting device state XPC update"); + // Let the update know it should rate-limit itself + [view updateDeviceState:true ckoperationGroup:group]; + } +} + +#endif // OCTAGON +@end diff --git a/keychain/ckks/CKKSZone.h b/keychain/ckks/CKKSZone.h new file mode 100644 index 00000000..9db60dd5 --- /dev/null +++ b/keychain/ckks/CKKSZone.h @@ -0,0 +1,126 @@ +/* + * 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 CKKSZone_h +#define CKKSZone_h + +#import + +#if OCTAGON +#import "keychain/ckks/CloudKitDependencies.h" +#import "keychain/ckks/CKKSCKAccountStateTracker.h" +#endif + +#if OCTAGON +@interface CKKSZone : NSObject { + CKContainer* _container; + CKDatabase* _database; + CKRecordZone* _zone; +} +#else +@interface CKKSZone : NSObject { +} +#endif + +@property (readonly) NSString* zoneName; + +@property bool setupStarted; +@property bool setupComplete; +@property CKKSGroupOperation* zoneSetupOperation; + +@property bool zoneCreated; +@property bool zoneSubscribed; +@property NSError* zoneCreatedError; +@property NSError* zoneSubscribedError; + +#if OCTAGON +@property CKKSAccountStatus accountStatus; + +@property (readonly) CKContainer* container; +@property (readonly) CKDatabase* database; + +@property (weak) CKKSCKAccountStateTracker* accountTracker; + +@property (readonly) CKRecordZone* zone; +@property (readonly) CKRecordZoneID* zoneID; + +// Dependencies (for injection) +@property (readonly) Class fetchRecordZoneChangesOperationClass; +@property (readonly) Class modifySubscriptionsOperationClass; +@property (readonly) Class modifyRecordZonesOperationClass; +@property (readonly) Class apsConnectionClass; + +@property dispatch_queue_t queue; + +- (instancetype)initWithContainer: (CKContainer*) container + zoneName: (NSString*) zoneName + accountTracker:(CKKSCKAccountStateTracker*) tracker + fetchRecordZoneChangesOperationClass: (Class) fetchRecordZoneChangesOperationClass + modifySubscriptionsOperationClass: (Class) modifySubscriptionsOperationClass + modifyRecordZonesOperationClass: (Class) modifyRecordZonesOperationClass + apsConnectionClass: (Class) apsConnectionClass; + + +- (NSOperation*) createSetupOperation: (bool) zoneCreated zoneSubscribed: (bool) zoneSubscribed; + +- (CKKSResultOperation*) beginResetCloudKitZoneOperation; + +// 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 +- (void)handleCKLogin; + +// 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; + +// 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. +- (void) dispatchSync: (bool (^)(void)) block; + +// Call this to reset this object's setup, so you can call createSetupOperation again. +- (void)resetSetup; + +#endif +@end + +#endif /* CKKSZone_h */ diff --git a/keychain/ckks/CKKSZone.m b/keychain/ckks/CKKSZone.m new file mode 100644 index 00000000..30790c43 --- /dev/null +++ b/keychain/ckks/CKKSZone.m @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#import + +#if OCTAGON +#import "CloudKitDependencies.h" +#import "keychain/ckks/CKKSCKAccountStateTracker.h" +#import +#import +#endif + +#import "CKKSKeychainView.h" +#import "CKKSZone.h" + +#include + +@interface CKKSZone() +#if OCTAGON + +@property CKDatabaseOperation* zoneCreationOperation; +@property CKDatabaseOperation* zoneDeletionOperation; +@property CKDatabaseOperation* zoneSubscriptionOperation; + +@property bool acceptingNewOperations; +@property NSOperationQueue* operationQueue; +@property NSOperation* accountLoggedInDependency; + +@property NSHashTable* accountOperations; +#endif +@end + +@implementation CKKSZone + +#if OCTAGON + +- (instancetype)initWithContainer: (CKContainer*) container + zoneName: (NSString*) zoneName + accountTracker:(CKKSCKAccountStateTracker*) tracker + fetchRecordZoneChangesOperationClass: (Class) fetchRecordZoneChangesOperationClass + modifySubscriptionsOperationClass: (Class) modifySubscriptionsOperationClass + modifyRecordZonesOperationClass: (Class) modifyRecordZonesOperationClass + apsConnectionClass: (Class) apsConnectionClass +{ + if(self = [super init]) { + _container = container; + _zoneName = zoneName; + _accountTracker = tracker; + + _database = [_container privateCloudDatabase]; + _zone = [[CKRecordZone alloc] initWithZoneID: [[CKRecordZoneID alloc] initWithZoneName:zoneName ownerName:CKCurrentUserDefaultName]]; + + // Every subclass must set up call beginSetup at least once. + _accountStatus = CKKSAccountStatusUnknown; + [self resetSetup]; + + _accountOperations = [NSHashTable weakObjectsHashTable]; + + _fetchRecordZoneChangesOperationClass = fetchRecordZoneChangesOperationClass; + _modifySubscriptionsOperationClass = modifySubscriptionsOperationClass; + _modifyRecordZonesOperationClass = modifyRecordZonesOperationClass; + _apsConnectionClass = apsConnectionClass; + + _queue = dispatch_queue_create([[NSString stringWithFormat:@"CKKSQueue.%@.zone.%@", container.containerIdentifier, zoneName] UTF8String], DISPATCH_QUEUE_SERIAL); + _operationQueue = [[NSOperationQueue alloc] init]; + _acceptingNewOperations = true; + } + return self; +} + +// Initialize this object so that we can call beginSetup again +- (void)resetSetup { + self.setupStarted = false; + self.setupComplete = false; + + if([self.zoneSetupOperation isPending]) { + // Nothing to do here: there's already an existing zoneSetupOperation + } else { + self.zoneSetupOperation = [[CKKSGroupOperation alloc] init]; + self.zoneSetupOperation.name = @"zone-setup-operation"; + } + + if([self.accountLoggedInDependency isPending]) { + // Nothing to do here: there's already an existing accountLoggedInDependency + } else { + __weak __typeof(self) weakSelf = self; + self.accountLoggedInDependency = [NSBlockOperation blockOperationWithBlock:^{ + ckksnotice("ckkszone", weakSelf, "CloudKit account logged in."); + }]; + self.accountLoggedInDependency.name = @"account-logged-in-dependency"; + } + + 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]; +} + + +-(void)ckAccountStatusChange: (CKKSAccountStatus)oldStatus to:(CKKSAccountStatus)currentStatus { + + // dispatch this on a serial queue, so we get each transition in order + [self dispatchSync: ^bool { + ckksnotice("ckkszone", self, "%@ Received notification of CloudKit account status change, moving from %@ to %@", + self.zoneID.zoneName, + [CKKSCKAccountStateTracker stringFromAccountStatus: self.accountStatus], + [CKKSCKAccountStateTracker stringFromAccountStatus: currentStatus]); + CKKSAccountStatus oldStatus = self.accountStatus; + self.accountStatus = currentStatus; + + switch(currentStatus) { + case CKKSAccountStatusAvailable: { + + ckksinfo("ckkszone", self, "logging in while setup started: %d and complete: %d", self.setupStarted, self.setupComplete); + + // This is only a login if we're not in the middle of setup, and the previous state was not logged in + if(!(self.setupStarted ^ self.setupComplete) && oldStatus != CKKSAccountStatusAvailable) { + [self resetSetup]; + [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."); + + self.accountLoggedInDependency = [NSBlockOperation blockOperationWithBlock:^{ + ckksnotice("ckkszone", self, "CloudKit account logged in again."); + }]; + self.accountLoggedInDependency.name = @"account-logged-in-dependency"; + + [self.operationQueue cancelAllOperations]; + [self handleCKLogout]; + + // now we're in a logged out state. Optimistically prepare for a log in! + [self resetSetup]; + } + 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); + + self.accountLoggedInDependency = [NSBlockOperation blockOperationWithBlock:^{ + ckksnotice("ckkszone", self, "CloudKit account restored from 'unknown'."); + }]; + self.accountLoggedInDependency.name = @"account-logged-in-dependency"; + + [self.operationQueue cancelAllOperations]; + [self resetSetup]; + } + break; + } + + return true; + }]; +} + +- (NSOperation*) createSetupOperation: (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, skip doing it again. + if(self.setupStarted) { + ckksinfo("ckkszone", self, "skipping startup: it's already started"); + return self.zoneSetupOperation; + } + + if(self.zoneSetupOperation == nil) { + ckkserror("ckkszone", self, "trying to set up but the setup operation is gone; what happened?"); + return nil; + } + + self.zoneCreated = zoneCreated; + self.zoneSubscribed = zoneSubscribed; + + // Zone setups and teardowns are due to either 1) first CKKS launch or 2) the user logging in to iCloud. + // Therefore, they're QoS UserInitiated. + self.zoneSetupOperation.queuePriority = NSOperationQueuePriorityNormal; + self.zoneSetupOperation.qualityOfService = NSQualityOfServiceUserInitiated; + + ckksnotice("ckkszone", self, "Setting up zone %@", self.zoneName); + self.setupStarted = true; + + __weak __typeof(self) weakSelf = self; + + // First, check the account status. If it's sufficient, add the necessary CloudKit operations to this operation + NSBlockOperation* doSetup = [NSBlockOperation blockOperationWithBlock:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckkszone", strongSelf, "received callback for released object"); + return; + } + + __block bool ret = false; + [strongSelf dispatchSync: ^bool { + strongSelf.accountStatus = [strongSelf.accountTracker currentCKAccountStatusAndNotifyOnChange:strongSelf]; + + switch(strongSelf.accountStatus) { + case CKKSAccountStatusNoAccount: + ckkserror("ckkszone", strongSelf, "No CloudKit account; quitting setup for %@", strongSelf.zoneID.zoneName); + [strongSelf handleCKLogout]; + ret = true; + break; + case CKKSAccountStatusAvailable: + if(strongSelf.accountLoggedInDependency) { + [strongSelf.operationQueue addOperation: strongSelf.accountLoggedInDependency]; + strongSelf.accountLoggedInDependency = nil; + } + break; + case CKKSAccountStatusUnknown: + ckkserror("ckkszone", strongSelf, "CloudKit account status currently unknown; stopping setup for %@", strongSelf.zoneID.zoneName); + ret = true; + break; + } + + return true; + }]; + + NSBlockOperation* setupCompleteOperation = [NSBlockOperation blockOperationWithBlock:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckkszone: received callback for released object"); + return; + } + + ckksinfo("ckkszone", strongSelf, "%@: Setup complete", strongSelf.zoneName); + strongSelf.setupComplete = true; + }]; + setupCompleteOperation.name = @"zone-setup-complete-operation"; + + // If we don't have an CloudKit account, don't bother continuing + if(ret) { + [strongSelf.zoneSetupOperation runBeforeGroupFinished:setupCompleteOperation]; + return; + } + + // We have an account, so fetch the push environment and bring up APS + [strongSelf.container serverPreferredPushEnvironmentWithCompletionHandler: ^(NSString *apsPushEnvString, NSError *error) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckkszone: received callback for released object"); + return; + } + + if(error || (apsPushEnvString == nil)) { + ckkserror("ckkszone", strongSelf, "Received error fetching preferred push environment (%@). Keychain syncing is highly degraded: %@", apsPushEnvString, error); + } else { + CKKSAPSReceiver* aps = [CKKSAPSReceiver receiverForEnvironment:apsPushEnvString + namedDelegatePort:SecCKKSAPSNamedPort + apsConnectionClass:strongSelf.apsConnectionClass]; + [aps register:strongSelf forZoneID:strongSelf.zoneID]; + } + }]; + + NSBlockOperation* modifyRecordZonesCompleteOperation = nil; + if(!zoneCreated) { + ckksnotice("ckkszone", strongSelf, "Creating CloudKit zone '%@'", strongSelf.zoneName); + CKDatabaseOperation* zoneCreationOperation = [[strongSelf.modifyRecordZonesOperationClass alloc] initWithRecordZonesToSave: @[strongSelf.zone] recordZoneIDsToDelete: nil]; + zoneCreationOperation.queuePriority = NSOperationQueuePriorityNormal; + zoneCreationOperation.qualityOfService = NSQualityOfServiceUserInitiated; + zoneCreationOperation.database = strongSelf.database; + zoneCreationOperation.name = @"zone-creation-operation"; + + // Completion blocks don't count for dependencies. Use this intermediate operation hack instead. + modifyRecordZonesCompleteOperation = [[NSBlockOperation alloc] init]; + modifyRecordZonesCompleteOperation.name = @"zone-creation-finished"; + + zoneCreationOperation.modifyRecordZonesCompletionBlock = ^(NSArray *savedRecordZones, NSArray *deletedRecordZoneIDs, NSError *operationError) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckkszone: received callback for released object"); + return; + } + + __strong __typeof(weakSelf) strongSubSelf = weakSelf; + + if(!operationError) { + ckksnotice("ckkszone", strongSubSelf, "Successfully created zone %@", strongSubSelf.zoneName); + strongSubSelf.zoneCreated = true; + } else { + ckkserror("ckkszone", strongSubSelf, "Couldn't create zone %@; %@", strongSubSelf.zoneName, operationError); + } + strongSubSelf.zoneCreatedError = operationError; + + [strongSubSelf.operationQueue addOperation: modifyRecordZonesCompleteOperation]; + }; + + ckksnotice("ckkszone", strongSelf, "Adding CKKSModifyRecordZonesOperation: %@ %@", zoneCreationOperation, zoneCreationOperation.dependencies); + strongSelf.zoneCreationOperation = zoneCreationOperation; + [setupCompleteOperation addDependency: modifyRecordZonesCompleteOperation]; + [strongSelf.zoneSetupOperation runBeforeGroupFinished: zoneCreationOperation]; + [strongSelf.zoneSetupOperation dependOnBeforeGroupFinished: modifyRecordZonesCompleteOperation]; + } else { + ckksinfo("ckkszone", strongSelf, "no need to create the zone '%@'", strongSelf.zoneName); + } + + if(!zoneSubscribed) { + ckksnotice("ckkszone", strongSelf, "Creating CloudKit record zone subscription for %@", strongSelf.zoneName); + CKRecordZoneSubscription* subscription = [[CKRecordZoneSubscription alloc] initWithZoneID: strongSelf.zoneID subscriptionID:[@"zone:" stringByAppendingString: strongSelf.zoneName]]; + CKNotificationInfo* notificationInfo = [[CKNotificationInfo alloc] init]; + + notificationInfo.shouldSendContentAvailable = false; + subscription.notificationInfo = notificationInfo; + + CKDatabaseOperation* zoneSubscriptionOperation = [[strongSelf.modifySubscriptionsOperationClass alloc] initWithSubscriptionsToSave: @[subscription] subscriptionIDsToDelete: nil]; + + zoneSubscriptionOperation.queuePriority = NSOperationQueuePriorityNormal; + zoneSubscriptionOperation.qualityOfService = NSQualityOfServiceUserInitiated; + zoneSubscriptionOperation.database = strongSelf.database; + zoneSubscriptionOperation.name = @"zone-subscription-operation"; + + // Completion blocks don't count for dependencies. Use this intermediate operation hack instead. + NSBlockOperation* zoneSubscriptionCompleteOperation = [[NSBlockOperation alloc] init]; + zoneSubscriptionCompleteOperation.name = @"zone-subscription-complete"; + zoneSubscriptionOperation.modifySubscriptionsCompletionBlock = ^(NSArray * _Nullable savedSubscriptions, NSArray * _Nullable deletedSubscriptionIDs, NSError * _Nullable operationError) { + __strong __typeof(weakSelf) strongSubSelf = weakSelf; + if(!strongSubSelf) { + ckkserror("ckkszone", strongSubSelf, "received callback for released object"); + return; + } + + if(!operationError) { + ckksnotice("ckkszone", strongSubSelf, "Successfully subscribed to %@", savedSubscriptions); + + // Success; write that down. TODO: actually ensure that the saved subscription matches what we asked for + for(CKSubscription* sub in savedSubscriptions) { + ckksnotice("ckkszone", strongSubSelf, "Successfully subscribed to %@", sub.subscriptionID); + strongSubSelf.zoneSubscribed = true; + } + } else { + ckkserror("ckkszone", strongSubSelf, "Couldn't create cloudkit zone subscription; keychain syncing is severely degraded: %@", operationError); + } + + strongSubSelf.zoneSubscribedError = operationError; + strongSubSelf.zoneSubscriptionOperation = nil; + + [strongSubSelf.operationQueue addOperation: zoneSubscriptionCompleteOperation]; + }; + + if(modifyRecordZonesCompleteOperation) { + [zoneSubscriptionOperation addDependency:modifyRecordZonesCompleteOperation]; + } + strongSelf.zoneSubscriptionOperation = zoneSubscriptionOperation; + [setupCompleteOperation addDependency: zoneSubscriptionCompleteOperation]; + [strongSelf.zoneSetupOperation runBeforeGroupFinished:zoneSubscriptionOperation]; + [strongSelf.zoneSetupOperation dependOnBeforeGroupFinished: zoneSubscriptionCompleteOperation]; + } else { + ckksinfo("ckkszone", strongSelf, "no need to create database subscription"); + } + + [strongSelf.zoneSetupOperation runBeforeGroupFinished:setupCompleteOperation]; + }]; + doSetup.name = @"begin-zone-setup"; + + [self.zoneSetupOperation runBeforeGroupFinished:doSetup]; + + return self.zoneSetupOperation; +} + + +- (CKKSResultOperation*)beginResetCloudKitZoneOperation { + if(!SecCKKSIsEnabled()) { + ckksinfo("ckkszone", self, "Skipping CloudKit reset due to disabled CKKS"); + return nil; + } + + // 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 + CKDatabaseOperation* zoneDeletionOperation = [[self.modifyRecordZonesOperationClass alloc] initWithRecordZonesToSave: nil recordZoneIDsToDelete: @[self.zoneID]]; + zoneDeletionOperation.queuePriority = NSOperationQueuePriorityNormal; + zoneDeletionOperation.qualityOfService = NSQualityOfServiceUserInitiated; + zoneDeletionOperation.database = self.database; + + CKKSResultOperation* doneOp = [CKKSResultOperation named:@"zone-reset-watcher" withBlock:^{}]; + + __weak __typeof(self) weakSelf = self; + + zoneDeletionOperation.modifyRecordZonesCompletionBlock = ^(NSArray *savedRecordZones, NSArray *deletedRecordZoneIDs, NSError *operationError) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + ckkserror("ckkszone", strongSelf, "received callback for released object"); + return; + } + + ckksinfo("ckkszone", strongSelf, "record zones deletion %@ completed with error: %@", deletedRecordZoneIDs, operationError); + [strongSelf resetSetup]; + + doneOp.error = operationError; + [strongSelf.operationQueue addOperation: doneOp]; + }; + + // If the zone creation operation is still pending, wait for it to complete before attempting zone deletion + [zoneDeletionOperation addNullableDependency: self.zoneCreationOperation]; + + ckksinfo("ckkszone", self, "deleting zone with %@ %@", zoneDeletionOperation, zoneDeletionOperation.dependencies); + // Don't use scheduleOperation: zone deletions should be attempted even if we're "logged out" + [self.operationQueue addOperation: zoneDeletionOperation]; + self.zoneDeletionOperation = zoneDeletionOperation; + return doneOp; +} + +- (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, ignoring"); +} + +- (void)handleCKLogout { + ckksinfo("ckkszone", self, "received a notification of CK logout, ignoring"); +} + +- (bool)scheduleOperation: (NSOperation*) op { + if(!self.acceptingNewOperations) { + ckksdebug("ckkszone", self, "attempted to schedule an operation on a cancelled zone, ignoring"); + return false; + } + + if(self.accountLoggedInDependency) { + [op addDependency: 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 { + // 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 { + [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, ^{ + ok = block(); + if(!ok) { + ckkserror("ckkszone", self, "CKKSZone block returned false"); + } + }); +} + + +#endif /* OCTAGON */ +@end + + + diff --git a/keychain/ckks/CKKSZoneChangeFetcher.h b/keychain/ckks/CKKSZoneChangeFetcher.h new file mode 100644 index 00000000..49dc7878 --- /dev/null +++ b/keychain/ckks/CKKSZoneChangeFetcher.h @@ -0,0 +1,72 @@ +/* + * 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 + +#if OCTAGON + +/* Fetch Reasons */ +@protocol SecCKKSFetchBecause +@end +typedef NSString CKKSFetchBecause; +extern CKKSFetchBecause* const CKKSFetchBecauseAPNS; +extern CKKSFetchBecause* const CKKSFetchBecauseAPIFetchRequest; +extern CKKSFetchBecause* const CKKSFetchBecauseCurrentItemFetchRequest; +extern CKKSFetchBecause* const CKKSFetchBecauseInitialStart; +extern CKKSFetchBecause* const CKKSFetchBecauseSecuritydRestart; +extern CKKSFetchBecause* const CKKSFetchBecausePreviousFetchFailed; +extern CKKSFetchBecause* const CKKSFetchBecauseKeyHierarchy; +extern CKKSFetchBecause* const CKKSFetchBecauseTesting; + +@protocol CKKSChangeFetcherErrorOracle +- (bool) isFatalCKFetchError: (NSError*) error; +@end + +/* + * This class implements a CloudKit-fetch-with-retry. + * In the case of network or other failures, it'll issue retries. + * Only in the case of a clean fetch will its operation dependency resolve. + */ + +@class CKKSKeychainView; +#import "keychain/ckks/CKKSGroupOperation.h" +#import + +@interface CKKSZoneChangeFetcher : NSObject + +@property (weak) CKKSKeychainView* ckks; +@property CKRecordZoneID* zoneID; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks; + +- (CKKSResultOperation*)requestSuccessfulFetch:(CKKSFetchBecause*)why; +- (CKKSResultOperation*)requestSuccessfulResyncFetch:(CKKSFetchBecause*)why; + +-(void)cancel; +@end + + +#endif + + diff --git a/keychain/ckks/CKKSZoneChangeFetcher.m b/keychain/ckks/CKKSZoneChangeFetcher.m new file mode 100644 index 00000000..40a797dd --- /dev/null +++ b/keychain/ckks/CKKSZoneChangeFetcher.m @@ -0,0 +1,256 @@ +/* + * 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 + +#if OCTAGON + +#import + +#import "keychain/ckks/CKKSZoneChangeFetcher.h" +#import "keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h" +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSNearFutureScheduler.h" +#import "keychain/ckks/CloudKitCategories.h" + +CKKSFetchBecause* const CKKSFetchBecauseAPNS = (CKKSFetchBecause*) @"apns"; +CKKSFetchBecause* const CKKSFetchBecauseAPIFetchRequest = (CKKSFetchBecause*) @"api"; +CKKSFetchBecause* const CKKSFetchBecauseCurrentItemFetchRequest = (CKKSFetchBecause*) @"currentitemcheck"; +CKKSFetchBecause* const CKKSFetchBecauseInitialStart = (CKKSFetchBecause*) @"initialfetch"; +CKKSFetchBecause* const CKKSFetchBecauseSecuritydRestart = (CKKSFetchBecause*) @"restart"; +CKKSFetchBecause* const CKKSFetchBecausePreviousFetchFailed = (CKKSFetchBecause*) @"fetchfailed"; +CKKSFetchBecause* const CKKSFetchBecauseKeyHierarchy = (CKKSFetchBecause*) @"keyhierarchy"; +CKKSFetchBecause* const CKKSFetchBecauseTesting = (CKKSFetchBecause*) @"testing"; + +@interface CKKSZoneChangeFetcher () +@property NSString* name; +@property dispatch_queue_t queue; + +@property CKKSFetchAllRecordZoneChangesOperation* currentFetch; +@property CKKSResultOperation* currentProcessResult; + +@property NSMutableSet* currentFetchReasons; +@property bool newRequests; // true if there's someone pending on successfulFetchDependency +@property bool newResyncRequests; // true if someone asked for a refetch operation +@property CKKSResultOperation* successfulFetchDependency; + +@property CKKSNearFutureScheduler* fetchScheduler; +@end + +@implementation CKKSZoneChangeFetcher + +- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks { + if((self = [super init])) { + _ckks = ckks; + _zoneID = ckks.zoneID; + + _currentFetchReasons = [[NSMutableSet alloc] init]; + + _name = [NSString stringWithFormat:@"zone-change-fetcher-%@", _zoneID.zoneName]; + _queue = dispatch_queue_create([_name UTF8String], DISPATCH_QUEUE_SERIAL); + [self newSuccesfulFetchDependency]; + + _newRequests = false; + + // If we're testing, for the initial delay, use 0.2 second. Otherwise, 2s. + dispatch_time_t initialDelay = (SecCKKSTestsEnabled() ? 200 * NSEC_PER_MSEC : 2 * NSEC_PER_SEC); + + // If we're testing, for the initial delay, use 2 second. Otherwise, 30s. + dispatch_time_t continuingDelay = (SecCKKSTestsEnabled() ? 2 * NSEC_PER_SEC : 30 * NSEC_PER_SEC); + + __weak __typeof(self) weakSelf = self; + _fetchScheduler = [[CKKSNearFutureScheduler alloc] initWithName:[NSString stringWithFormat:@"zone-change-fetch-scheduler-%@", self.zoneID.zoneName] + initialDelay:initialDelay + continuingDelay:continuingDelay + keepProcessAlive:false + block:^{ + [weakSelf maybeCreateNewFetch]; + }]; + } + return self; +} + +- (NSString*)description { + NSDate* nextFetchAt = self.fetchScheduler.nextFireTime; + if(nextFetchAt) { + NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + return [NSString stringWithFormat: @" +#include + +#ifndef CKKSZoneStateEntry_h +#define CKKSZoneStateEntry_h + +#if OCTAGON + +#import + +/* + * This class hold the state for a particular zone: has the zone been created, have we subscribed to it, + * what's the current change token, etc. + * + * It also holds the zone's current "rate limiter" state. Currently, though, there is only a single, global + * rate limiter. Therefore, each individual zone's state will have no data in the rate limiter slot, and we'll + * create a global zone state entry holding the global rate limiter state. This split behavior allows us to bring + * up zone-specific rate limiters under the global rate limiter later without database changes, if we decide + * that's useful. + */ + +@class CKKSRateLimiter; + +@interface CKKSZoneStateEntry : CKKSSQLDatabaseObject { + +} + +@property NSString* ckzone; +@property bool ckzonecreated; +@property bool ckzonesubscribed; +@property (getter=getChangeToken,setter=setChangeToken:) CKServerChangeToken* changeToken; +@property NSData* encodedChangeToken; +@property NSDate* lastFetchTime; + +@property CKKSRateLimiter* rateLimiter; +@property NSData* encodedRateLimiter; + ++ (instancetype) state: (NSString*) ckzone; + ++ (instancetype) fromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error; ++ (instancetype) tryFromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error; + +- (instancetype) initWithCKZone: (NSString*) ckzone zoneCreated: (bool) ckzonecreated zoneSubscribed: (bool) ckzonesubscribed changeToken: (NSData*) changetoken lastFetch: (NSDate*) lastFetch encodedRateLimiter: (NSData*) encodedRateLimiter; + +- (CKServerChangeToken*) getChangeToken; +- (void) setChangeToken: (CKServerChangeToken*) token; + +- (BOOL)isEqual: (id) object; +@end + +#endif +#endif /* CKKSZoneStateEntry_h */ diff --git a/keychain/ckks/CKKSZoneStateEntry.m b/keychain/ckks/CKKSZoneStateEntry.m new file mode 100644 index 00000000..a433aff5 --- /dev/null +++ b/keychain/ckks/CKKSZoneStateEntry.m @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include + +#import + +#import "CKKSKeychainView.h" + +#include +#include +#include + +#if OCTAGON + +#import +#import "CKKSZoneStateEntry.h" +#import "keychain/ckks/CKKSRateLimiter.h" + + +@implementation CKKSZoneStateEntry + +- (instancetype) initWithCKZone: (NSString*) ckzone zoneCreated: (bool) ckzonecreated zoneSubscribed: (bool) ckzonesubscribed changeToken: (NSData*) changetoken lastFetch: (NSDate*) lastFetch encodedRateLimiter: (NSData*) encodedRateLimiter { + if(self = [super init]) { + _ckzone = ckzone; + _ckzonecreated = ckzonecreated; + _ckzonesubscribed = ckzonesubscribed; + _encodedChangeToken = changetoken; + _lastFetchTime = lastFetch; + + self.encodedRateLimiter = encodedRateLimiter; + } + return self; +} + +- (BOOL)isEqual: (id) object { + if(![object isKindOfClass:[CKKSZoneStateEntry class]]) { + return NO; + } + + CKKSZoneStateEntry* obj = (CKKSZoneStateEntry*) object; + + return ([self.ckzone isEqualToString: obj.ckzone] && + self.ckzonecreated == obj.ckzonecreated && + self.ckzonesubscribed == obj.ckzonesubscribed && + ((self.encodedChangeToken == nil && obj.encodedChangeToken == nil) || [self.encodedChangeToken isEqual: obj.encodedChangeToken]) && + ((self.lastFetchTime == nil && obj.lastFetchTime == nil) || [self.lastFetchTime isEqualToDate: obj.lastFetchTime]) && + ((self.rateLimiter == nil && obj.rateLimiter == nil) || [self.rateLimiter isEqual: obj.rateLimiter]) + ) ? YES : NO; +} + ++ (instancetype) state: (NSString*) ckzone { + NSError* error = nil; + CKKSZoneStateEntry* ret = [CKKSZoneStateEntry tryFromDatabase:ckzone error:&error]; + + if(error) { + secerror("CKKS: error fetching CKState(%@): %@", ckzone, error); + } + + if(!ret) { + ret = [[CKKSZoneStateEntry alloc] initWithCKZone: ckzone zoneCreated: false zoneSubscribed: false changeToken: nil lastFetch:nil encodedRateLimiter: nil]; + } + return ret; +} + +- (CKServerChangeToken*) getChangeToken { + if(self.encodedChangeToken) { + NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:self.encodedChangeToken]; + unarchiver.requiresSecureCoding = YES; + return [unarchiver decodeObjectOfClass:[CKServerChangeToken class] forKey:NSKeyedArchiveRootObjectKey]; + } else { + return nil; + } +} + +- (void) setChangeToken: (CKServerChangeToken*) token { + self.encodedChangeToken = token ? [NSKeyedArchiver archivedDataWithRootObject:token] : nil; +} + +- (NSData*)encodedRateLimiter { + if(self.rateLimiter == nil) { + return nil; + } + return [NSKeyedArchiver archivedDataWithRootObject: self.rateLimiter]; +} + +- (void)setEncodedRateLimiter:(NSData *)encodedRateLimiter { + if(encodedRateLimiter == nil) { + self.rateLimiter = nil; + return; + } + + NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedRateLimiter]; + unarchiver.requiresSecureCoding = YES; + self.rateLimiter = [unarchiver decodeObjectOfClass: [CKKSRateLimiter class] forKey:NSKeyedArchiveRootObjectKey]; +} + +#pragma mark - Database Operations + ++ (instancetype) fromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error { + return [self fromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error]; +} + ++ (instancetype) tryFromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error { + return [self tryFromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error]; +} + +#pragma mark - CKKSSQLDatabaseObject methods + ++ (NSString*) sqlTable { + return @"ckstate"; +} + ++ (NSArray*) sqlColumns { + return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter"]; +} + +- (NSDictionary*) whereClauseToFindSelf { + return @{@"ckzone": self.ckzone}; +} + +- (NSDictionary*) sqlValues { + NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init]; + + return @{@"ckzone": self.ckzone, + @"ckzonecreated": [NSNumber numberWithBool:self.ckzonecreated], + @"ckzonesubscribed": [NSNumber numberWithBool:self.ckzonesubscribed], + @"changetoken": CKKSNilToNSNull([self.encodedChangeToken base64EncodedStringWithOptions:0]), + @"lastfetch": CKKSNilToNSNull(self.lastFetchTime ? [dateFormat stringFromDate: self.lastFetchTime] : nil), + @"ratelimiter": CKKSNilToNSNull([self.encodedRateLimiter base64EncodedStringWithOptions:0]) + }; +} + ++ (instancetype) fromDatabaseRow: (NSDictionary*) row { + NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init]; + + return [[CKKSZoneStateEntry alloc] initWithCKZone: row[@"ckzone"] + zoneCreated: [row[@"ckzonecreated"] boolValue] + zoneSubscribed: [row[@"ckzonesubscribed"] boolValue] + changeToken: ![row[@"changetoken"] isEqual: [NSNull null]] ? + [[NSData alloc] initWithBase64EncodedString: row[@"changetoken"] options:0] : + nil + lastFetch: [row[@"lastfetch"] isEqual: [NSNull null]] ? nil : [dateFormat dateFromString: row[@"lastfetch"]] + encodedRateLimiter: [row[@"ratelimiter"] isEqual: [NSNull null]] ? nil : [[NSData alloc] initWithBase64EncodedString: row[@"ratelimiter"] options:0] + ]; +} + +@end + +#endif diff --git a/keychain/ckks/CloudKitCategories.h b/keychain/ckks/CloudKitCategories.h new file mode 100644 index 00000000..9c98c2fd --- /dev/null +++ b/keychain/ckks/CloudKitCategories.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import +#import + +@interface CKOperationGroup (CKKS) ++(instancetype) CKKSGroupWithName:(NSString*)name; +@end + +@interface NSError (CKKS) + +// Returns true if this is a CloudKit error where +// 1) An atomic write failed +// 2) Every single suberror is either CKErrorServerRecordChanged or CKErrorUnknownItem +-(bool) ckksIsCKErrorRecordChangedError; +@end + +#endif // OCTAGON diff --git a/keychain/ckks/CloudKitCategories.m b/keychain/ckks/CloudKitCategories.m new file mode 100644 index 00000000..64be4265 --- /dev/null +++ b/keychain/ckks/CloudKitCategories.m @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import "keychain/ckks/CloudKitCategories.h" + +@implementation CKOperationGroup (CKKS) ++(instancetype) CKKSGroupWithName:(NSString*)name { + CKOperationGroup* operationGroup = [[CKOperationGroup alloc] init]; + operationGroup.expectedSendSize = CKOperationGroupTransferSizeKilobytes; + operationGroup.expectedReceiveSize = CKOperationGroupTransferSizeKilobytes; + operationGroup.name = name; + return operationGroup; +} +@end + +@implementation NSError (CKKS) + +-(bool) ckksIsCKErrorRecordChangedError { + NSDictionary* partialErrors = self.userInfo[CKPartialErrorsByItemIDKey]; + if([self.domain isEqualToString:CKErrorDomain] && self.code == CKErrorPartialFailure && partialErrors) { + // Check if this error was "you're out of date" + + for(NSError* error in partialErrors.objectEnumerator) { + if((![error.domain isEqualToString:CKErrorDomain]) || (error.code != CKErrorBatchRequestFailed && error.code != CKErrorServerRecordChanged && error.code != CKErrorUnknownItem)) { + // There's an error in there that isn't CKErrorServerRecordChanged, CKErrorBatchRequestFailed, or CKErrorUnknownItem. Don't handle nicely... + return false; + } + } + + return true; + } + return false; +} + +@end + +#endif //OCTAGON diff --git a/keychain/ckks/CloudKitDependencies.h b/keychain/ckks/CloudKitDependencies.h new file mode 100644 index 00000000..d3bb1b3f --- /dev/null +++ b/keychain/ckks/CloudKitDependencies.h @@ -0,0 +1,125 @@ +/* + * 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 CloudKitDependencies_h +#define CloudKitDependencies_h + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/* CKModifyRecordZonesOperation */ +@protocol CKKSModifyRecordZonesOperation ++ (instancetype)alloc; +- (instancetype)initWithRecordZonesToSave:(nullable NSArray *)recordZonesToSave recordZoneIDsToDelete:(nullable NSArray *)recordZoneIDsToDelete; + +@property (nonatomic, strong, nullable) CKDatabase *database; +@property (nonatomic, copy, nullable) NSArray *recordZonesToSave; +@property (nonatomic, copy, nullable) NSArray *recordZoneIDsToDelete; +@property NSOperationQueuePriority queuePriority; +@property NSQualityOfService qualityOfService; + +@property (nonatomic, copy, nullable) void (^modifyRecordZonesCompletionBlock)(NSArray * _Nullable savedRecordZones, NSArray * _Nullable deletedRecordZoneIDs, NSError * _Nullable operationError); + +@end + +@interface CKModifyRecordZonesOperation (SecCKKSModifyRecordZonesOperation) ; +@end + +/* CKModifySubscriptionsOperation */ +@protocol CKKSModifySubscriptionsOperation ++ (instancetype)alloc; +- (instancetype)initWithSubscriptionsToSave:(nullable NSArray *)subscriptionsToSave subscriptionIDsToDelete:(nullable NSArray *)subscriptionIDsToDelete; + +@property (nonatomic, strong, nullable) CKDatabase *database; +@property (nonatomic, copy, nullable) NSArray *subscriptionsToSave; +@property (nonatomic, copy, nullable) NSArray *subscriptionIDsToDelete; +@property NSOperationQueuePriority queuePriority; +@property NSQualityOfService qualityOfService; +@property (nonatomic, strong, nullable) CKOperationGroup *group; + +@property (nonatomic, copy, nullable) void (^modifySubscriptionsCompletionBlock)(NSArray * _Nullable savedSubscriptions, NSArray * _Nullable deletedSubscriptionIDs, NSError * _Nullable operationError); +@end + +@interface CKModifySubscriptionsOperation (SecCKKSModifySubscriptionsOperation) ; +@end + +/* CKFetchRecordZoneChangesOperation */ +@protocol CKKSFetchRecordZoneChangesOperation ++ (instancetype)alloc; +- (instancetype)initWithRecordZoneIDs:(NSArray *)recordZoneIDs optionsByRecordZoneID:(nullable NSDictionary *)optionsByRecordZoneID; + +@property (nonatomic, copy, nullable) NSArray *recordZoneIDs; +@property (nonatomic, copy, nullable) NSDictionary *optionsByRecordZoneID; + +@property (nonatomic, assign) BOOL fetchAllChanges; +@property (nonatomic, copy, nullable) void (^recordChangedBlock)(CKRecord *record); +@property (nonatomic, copy, nullable) void (^recordWithIDWasDeletedBlock)(CKRecordID *recordID, NSString *recordType); +@property (nonatomic, copy, nullable) void (^recordZoneChangeTokensUpdatedBlock)(CKRecordZoneID *recordZoneID, CKServerChangeToken * _Nullable serverChangeToken, NSData * _Nullable clientChangeTokenData); +@property (nonatomic, copy, nullable) void (^recordZoneFetchCompletionBlock)(CKRecordZoneID *recordZoneID, CKServerChangeToken * _Nullable serverChangeToken, NSData * _Nullable clientChangeTokenData, BOOL moreComing, NSError * _Nullable recordZoneError); +@property (nonatomic, copy, nullable) void (^fetchRecordZoneChangesCompletionBlock)(NSError * _Nullable operationError); + +@property (nonatomic, strong, nullable) CKOperationGroup *group; +@end + +@interface CKFetchRecordZoneChangesOperation () ; +@end + +/* APSConnection */ +@protocol CKKSAPSConnection ++ (instancetype)alloc; +- (id)initWithEnvironmentName:(NSString *)environmentName namedDelegatePort:(NSString*)namedDelegatePort queue:(dispatch_queue_t)queue; + +- (void)setEnabledTopics:(NSArray *)enabledTopics; + +@property (nonatomic, readwrite, assign) id delegate; +@end + +@interface APSConnection (SecCKKSAPSConnection) ; +@end + +/* NSNotificationCenter */ +@protocol CKKSNSNotificationCenter ++ (instancetype)defaultCenter; +- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject; +- (void)removeObserver:(id)observer; +@end +@interface NSNotificationCenter () +@end + +/* Since CKDatabase doesn't share any types with NSOperationQueue, tell the type system about addOperation */ +@protocol CKKSOperationQueue +- (void)addOperation:(NSOperation *)operation; +@end + +@interface CKDatabase () ; +@end + +@interface NSOperationQueue () ; +@end + +NS_ASSUME_NONNULL_END + +#endif /* CloudKitDependencies_h */ diff --git a/keychain/ckks/RateLimiter.h b/keychain/ckks/RateLimiter.h new file mode 100644 index 00000000..7e986c6f --- /dev/null +++ b/keychain/ckks/RateLimiter.h @@ -0,0 +1,132 @@ +/* + * 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 RateLimiter_h +#define RateLimiter_h + +#import + +@interface RateLimiter : NSObject + +@property (readonly, nonatomic, nonnull) NSDictionary *config; +@property (readonly, nonatomic) NSUInteger stateSize; +@property (readonly, nonatomic, nullable) NSString *assetType; + +typedef NS_ENUM(NSInteger, RateLimiterBadness) { + RateLimiterBadnessClear = 0, // everything is fine, process right now + RateLimiterBadnessCongested, + RateLimiterBadnessSeverelyCongested, + RateLimiterBadnessGridlocked, + RateLimiterBadnessOverloaded, // everything is on fire, go away +}; + +- (instancetype _Nullable)initWithConfig:(NSDictionary * _Nonnull)config; +- (instancetype _Nullable)initWithPlistFromURL:(NSURL * _Nonnull)url; +- (instancetype _Nullable)initWithAssetType:(NSString * _Nonnull)type; // Not implemented yet +- (instancetype _Nullable)initWithCoder:(NSCoder * _Nonnull)coder; +- (instancetype _Nullable)init NS_UNAVAILABLE; + +/*! + * @brief Find out whether objects may be processed or must wait. + * @param obj The object being judged. + * @param time Current time. + * @param limitTime Assigned okay-to-process time. Nil when object may be processed immediately. + * @return RateLimiterBadness enum value indicating current congestion situation, or to signal + * + * judge:at: will set the limitTime object to nil in case of 0 badness. For badnesses 1-4 the time object will indicate when it is okay to send the entry. + * At badness 5 judge:at: has determined there is too much activity so the caller should hold off altogether. The limitTime object will indicate when + * this overloaded state will end. + */ +- (NSInteger)judge:(id _Nonnull)obj at:(NSDate * _Nonnull)time limitTime:(NSDate * _Nullable __autoreleasing * _Nonnull)limitTime; + +- (void)reset; +- (NSString * _Nonnull)diagnostics; ++ (BOOL)supportsSecureCoding; + +// TODO: +// implement config loading from MobileAsset + +@end + +#endif /* RateLimiter_h */ + +/* Annotated example plist + + + + + + general + + + maxStateSize + 250 + + maxItemAge + 3600 + + overloadDuration + 1800 + + name + CKKS + + MAType + + + topOffendersPropertyIndex + + + + groups + + + + property + global + capacity + 20 + rate + 30 + badness + 1 + + + + property + UUID + + capacity + 3 + + rate + 600 + + badness + 3 + + + + + +*/ diff --git a/keychain/ckks/RateLimiter.m b/keychain/ckks/RateLimiter.m new file mode 100644 index 00000000..810651bc --- /dev/null +++ b/keychain/ckks/RateLimiter.m @@ -0,0 +1,364 @@ +/* + * 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 "RateLimiter.h" +#import +#import "sec_action.h" +#import // For clarity. Also included in debugging.h + +#if !TARGET_OS_BRIDGE +#import +#import "keychain/analytics/awd/AWDMetricIds_Keychain.h" +#import "keychain/analytics/awd/AWDKeychainCKKSRateLimiterOverload.h" +#import "keychain/analytics/awd/AWDKeychainCKKSRateLimiterTopWriters.h" +#import "keychain/analytics/awd/AWDKeychainCKKSRateLimiterAggregatedScores.h" +#endif + +@interface RateLimiter() +@property (readwrite, nonatomic, nonnull) NSDictionary *config; +@property (nonatomic) NSArray *> *groups; +@property (nonatomic) NSDate *lastJudgment; +@property (nonatomic) NSDate *overloadUntil; +@property (nonatomic) NSString *assetType; +#if !TARGET_OS_BRIDGE +@property (nonatomic) NSMutableArray *badnessData; +@property (nonatomic) AWDServerConnection *awdConnection; +#endif +@end + +@implementation RateLimiter + +- (instancetype)initWithConfig:(NSDictionary *)config { + self = [super init]; + if (self) { + _config = config; + _assetType = nil; + [self reset]; + [self setUpAwdMetrics]; + } + return self; +} + +- (instancetype)initWithPlistFromURL:(NSURL *)url { + self = [super init]; + if (self) { + _config = [NSDictionary dictionaryWithContentsOfURL:url]; + if (!_config) { + secerror("RateLimiter[?]: could not read config from %@", url); + return nil; + } + _assetType = nil; + [self reset]; + [self setUpAwdMetrics]; + } + return self; +} + +// TODO implement MobileAsset loading +- (instancetype)initWithAssetType:(NSString *)type { + return nil; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + if (!coder) { + return nil; + } + self = [super init]; + if (self) { + _groups = [coder decodeObjectOfClasses:[NSSet setWithObjects: [NSArray class], + [NSMutableDictionary class], + [NSString class], + [NSDate class], + nil] + forKey:@"RLgroups"]; + _overloadUntil = [coder decodeObjectOfClass:[NSDate class] forKey:@"RLoverLoadedUntil"]; + _lastJudgment = [coder decodeObjectOfClass:[NSDate class] forKey:@"RLlastJudgment"]; + _assetType = [coder decodeObjectOfClass:[NSString class] forKey:@"RLassetType"]; +#if !TARGET_OS_BRIDGE + _badnessData = [coder decodeObjectOfClasses:[NSSet setWithObjects: [NSArray class], + [NSNumber class], + nil] + forKey:@"RLbadnessData"]; +#endif + if (!_assetType) { + // This list of types might be wrong. Be careful. + _config = [coder decodeObjectOfClasses:[NSSet setWithObjects: [NSMutableArray class], + [NSDictionary class], + [NSString class], + [NSNumber class], + [NSDate class], + nil] + forKey:@"RLconfig"]; + } + [self setUpAwdMetrics]; + } + return self; +} + +- (NSInteger)judge:(id _Nonnull)obj at:(NSDate * _Nonnull)time limitTime:(NSDate * _Nullable __autoreleasing * _Nonnull)limitTime { + + //sudo defaults write /Library/Preferences/com.apple.security DisableKeychainRateLimiting -bool YES + NSNumber *disabled = CFBridgingRelease(CFPreferencesCopyValue(CFSTR("DisableKeychainRateLimiting"), + CFSTR("com.apple.security"), + kCFPreferencesAnyUser, kCFPreferencesAnyHost)); + if ([disabled isKindOfClass:[NSNumber class]] && [disabled boolValue] == YES) { + static dispatch_once_t token; + static sec_action_t action; + dispatch_once(&token, ^{ + action = sec_action_create("ratelimiterdisabledlogevent", 60); + sec_action_set_handler(action, ^{ + secnotice("ratelimit", "Rate limiting disabled, returning automatic all-clear"); + }); + }); + sec_action_perform(action); + + *limitTime = nil; + return RateLimiterBadnessClear; + } + + RateLimiterBadness badness = RateLimiterBadnessClear; + + if (self.overloadUntil) { + if ([time timeIntervalSinceDate:self.overloadUntil] >= 0) { + [self trim:time]; + } + if (self.overloadUntil) { + *limitTime = self.overloadUntil; + badness = RateLimiterBadnessOverloaded; + } + } + + if (badness == RateLimiterBadnessClear && + ((self.lastJudgment && [time timeIntervalSinceDate:self.lastJudgment] > [self.config[@"general"][@"maxItemAge"] intValue]) || + [self stateSize] > [self.config[@"general"][@"maxStateSize"] unsignedIntegerValue])) { + [self trim:time]; + if (self.overloadUntil) { + *limitTime = self.overloadUntil; + badness = RateLimiterBadnessOverloaded; + } + } + + if (badness != RateLimiterBadnessClear) { +#if !TARGET_OS_BRIDGE + self.badnessData[badness] = @(self.badnessData[badness].intValue + 1); +#endif + return badness; + } + + NSDate *resultTime = [NSDate distantPast]; + for (unsigned long idx = 0; idx < self.groups.count; ++idx) { + NSDictionary *groupConfig = self.config[@"groups"][idx]; + NSString *name; + if (idx == 0) { + name = groupConfig[@"property"]; // global bucket, does not correspond to object property + } else { + name = [self getPropertyValue:groupConfig[@"property"] object:obj]; + } + // Pretend this property doesn't exist. Should be returning an error instead but currently it's only used with + // approved properties 'accessGroup' and 'uuid' and if the item doesn't have either it's sad times anyway. + // Improve rate limiter error handling + if (!name) { + secerror("RateLimiter[%@]: Got nil instead of property named %@", self.config[@"general"][@"name"], groupConfig[@"property"]); + continue; + } + NSDate *singleTokenTime = [self consumeTokenFromBucket:self.groups[idx] + config:groupConfig + name:name + at:time]; + if (singleTokenTime) { + resultTime = [resultTime laterDate:singleTokenTime]; + badness = MAX([groupConfig[@"badness"] intValue], badness); + } + } + +#if !TARGET_OS_BRIDGE + self.badnessData[badness] = @(self.badnessData[badness].intValue + 1); +#endif + *limitTime = badness == RateLimiterBadnessClear ? nil : resultTime; + self.lastJudgment = time; + return badness; +} + +- (NSDate *)consumeTokenFromBucket:(NSMutableDictionary *)group + config:(NSDictionary *)config + name:(NSString *)name + at:(NSDate *)time { + NSDate *threshold = [time dateByAddingTimeInterval:-([config[@"capacity"] intValue] * [config[@"rate"] intValue])]; + NSDate *bucket = group[name]; + + if (!bucket || [bucket timeIntervalSinceDate:threshold] < 0) { + bucket = threshold; + } + + // Implicitly track the number of tokens in the bucket. + // "Would the token I need have been generated in the past or in the future?" + bucket = [bucket dateByAddingTimeInterval:[config[@"rate"] intValue]]; + group[name] = bucket; + return ([bucket timeIntervalSinceDate:time] <= 0) ? nil : bucket; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[RateLimiter class]]) { + return NO; + } + RateLimiter *other = (RateLimiter *)object; + return ([self.config isEqual:other.config] && + [self.groups isEqual:other.groups] && + [self.lastJudgment isEqual:other.lastJudgment] && + ((self.overloadUntil == nil && other.overloadUntil == nil) || [self.overloadUntil isEqual:other.overloadUntil]) && + ((self.assetType == nil && other.assetType == nil) || [self.assetType isEqualToString:other.assetType])); +} + +- (void)reset { + NSMutableArray *newgroups = [NSMutableArray new]; + for (unsigned long idx = 0; idx < [self.config[@"groups"] count]; ++idx) { + [newgroups addObject:[NSMutableDictionary new]]; + } + self.groups = newgroups; + self.lastJudgment = [NSDate distantPast]; // will cause extraneous trim on first judgment but on empty groups + self.overloadUntil = nil; +#if !TARGET_OS_BRIDGE + // Corresponds to the number of RateLimiterBadness enum values + self.badnessData = [[NSMutableArray alloc] initWithObjects:@0, @0, @0, @0, @0, nil]; +#endif +} + +- (void)trim:(NSDate *)time { + int threshold = [self.config[@"general"][@"maxItemAge"] intValue]; + for (NSMutableDictionary *group in self.groups) { + NSSet *toRemove = [group keysOfEntriesPassingTest:^BOOL(NSString *key, NSDate *obj, BOOL *stop) { + return [time timeIntervalSinceDate:obj] > threshold; + }]; + [group removeObjectsForKeys:[toRemove allObjects]]; + } + + 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"] intValue]]; + secerror("RateLimiter[%@] state size %lu exceeds max %lu, overloaded until %@", + self.config[@"general"][@"name"], + (unsigned long)[self stateSize], + [self.config[@"general"][@"maxStateSize"] unsignedLongValue], + self.overloadUntil); +#if !TARGET_OS_BRIDGE + AWDKeychainCKKSRateLimiterOverload *metric = [AWDKeychainCKKSRateLimiterOverload new]; + metric.ratelimitertype = self.config[@"general"][@"name"]; + AWDPostMetric(AWDComponentId_Keychain, metric); +#endif + } else { + self.overloadUntil = nil; + } +} + +- (NSUInteger)stateSize { + NSUInteger size = 0; + for (NSMutableDictionary *group in self.groups) { + size += [group count]; + } + return size; +} + +- (NSString *)diagnostics { + return [NSString stringWithFormat:@"RateLimiter[%@]\nconfig:%@\ngroups:%@\noverloaded:%@\nlastJudgment:%@", + self.config[@"general"][@"name"], + self.config, + self.groups, + self.overloadUntil, + self.lastJudgment]; +} + +//This could probably be improved, rdar://problem/33416163 +- (NSString *)getPropertyValue:(NSString *)selectorString object:(id)obj { + if ([selectorString isEqualToString:@"accessGroup"] || + [selectorString isEqualToString:@"uuid"]) { + + SEL selector = NSSelectorFromString(selectorString); + IMP imp = [obj methodForSelector:selector]; + NSString *(*func)(id, SEL) = (void *)imp; + return func(obj, selector); + } else { + seccritical("RateLimter[%@]: \"%@\" is not an approved selector string", self.config[@"general"][@"name"], selectorString); + return nil; + } +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:_groups forKey:@"RLgroups"]; + [coder encodeObject:_overloadUntil forKey:@"RLoverloadedUntil"]; + [coder encodeObject:_lastJudgment forKey:@"RLlastJudgment"]; + [coder encodeObject:_assetType forKey:@"RLassetType"]; + if (!_assetType) { + [coder encodeObject:_config forKey:@"RLconfig"]; + } +#if !TARGET_OS_BRIDGE + [coder encodeObject:_badnessData forKey:@"RLbadnessData"]; +#endif +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (NSArray *)topOffenders:(int)num { + NSInteger idx = [self.config[@"general"][@"topOffendersPropertyIndex"] integerValue]; + NSDate *now = [NSDate date]; + NSSet *contenderkeys = [self.groups[idx] keysOfEntriesPassingTest:^BOOL(NSString *key, NSDate *obj, BOOL *stop) { + return [now timeIntervalSinceDate:obj] > 0 ? YES : NO; + }]; + if ([contenderkeys count] == 0) { + return [NSArray new]; + } + NSDictionary *contenders = [NSDictionary dictionaryWithObjects:[self.groups[idx] objectsForKeys:[contenderkeys allObjects] + notFoundMarker:[NSDate date]] + forKeys:[contenderkeys allObjects]]; + return [[[contenders keysSortedByValueUsingSelector:@selector(compare:)] reverseObjectEnumerator] allObjects]; +} + +- (void)setUpAwdMetrics { +#if !TARGET_OS_BRIDGE + self.awdConnection = [[AWDServerConnection alloc] initWithComponentId:AWDComponentId_Keychain]; + + [self.awdConnection registerQueriableMetric:AWDMetricId_Keychain_CKKSRateLimiterTopWriters callback:^(UInt32 metricId) { + AWDKeychainCKKSRateLimiterTopWriters *metric = [AWDKeychainCKKSRateLimiterTopWriters new]; + NSArray *offenders = [self topOffenders:3]; + for (NSString *offender in offenders) { + [metric addWriter:offender]; + } + metric.ratelimitertype = self.config[@"general"][@"name"]; + AWDPostMetric(metricId, metric); + }]; + + [self.awdConnection registerQueriableMetric:AWDMetricId_Keychain_CKKSRateLimiterAggregatedScores callback:^(UInt32 metricId) { + AWDKeychainCKKSRateLimiterAggregatedScores *metric = [AWDKeychainCKKSRateLimiterAggregatedScores new]; + for (NSNumber *num in self.badnessData) { + [metric addData:[num unsignedIntValue]]; + } + metric.ratelimitertype = self.config[@"general"][@"name"]; + AWDPostMetric(metricId, metric); + // Corresponds to the number of RateLimiterBadness enum values + self.badnessData = [[NSMutableArray alloc] initWithObjects:@0, @0, @0, @0, @0, nil]; + }]; +#endif +} + +@end diff --git a/keychain/ckks/tests/CKKSAPSReceiverTests.m b/keychain/ckks/tests/CKKSAPSReceiverTests.m new file mode 100644 index 00000000..4b8fb997 --- /dev/null +++ b/keychain/ckks/tests/CKKSAPSReceiverTests.m @@ -0,0 +1,194 @@ +/* + * 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 +#import +#import +#import +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSAPSReceiver.h" +#import "keychain/ckks/tests/MockCloudKit.h" +#import "keychain/ckks/CKKSCondition.h" + +@interface CKKSAPSNotificationReceiver : NSObject +@property XCTestExpectation* expectation; +@property void (^block)(CKRecordZoneNotification* notification); + +- (instancetype)initWithExpectation:(XCTestExpectation*)expectation; +- (instancetype)initWithExpectation:(XCTestExpectation*)expectation block:(void (^)(CKRecordZoneNotification* notification))block; +@end + +@implementation CKKSAPSNotificationReceiver +- (instancetype)initWithExpectation:(XCTestExpectation*)expectation { + return [self initWithExpectation:expectation block:nil]; +} + +- (instancetype)initWithExpectation:(XCTestExpectation*)expectation block:(void (^)(CKRecordZoneNotification* notification))block +{ + if((self = [super init])) { + _expectation = expectation; + _block = block; + } + return self; +} + +- (void)notifyZoneChange: (CKRecordZoneNotification*) notification { + [self.expectation fulfill]; + self.block(notification); +} +@end + + + +@interface CKKSAPSReceiverTests : XCTestCase +@property CKRecordZoneID* testZoneID; +@end + +@implementation CKKSAPSReceiverTests + +- (APSIncomingMessage*)messageForZoneID:(CKRecordZoneID*)zoneID { + // reverse engineered from source code. Ugly. + + NSMutableDictionary* zoneInfo = [[NSMutableDictionary alloc] init]; + zoneInfo[@"zid"] = zoneID.zoneName; // kCKNotificationCKRecordZoneRecordZoneIDKey + + NSMutableDictionary* ckinfo = [[NSMutableDictionary alloc] init]; + ckinfo[@"fet"] = zoneInfo; // kCKNotificationCKRecordZoneKey + + NSMutableDictionary* d = [[NSMutableDictionary alloc] init]; + d[@"ck"] = ckinfo; // kCKNotificationCKKey + + return [[APSIncomingMessage alloc] initWithTopic:@"i'm-not-sure" userInfo:d]; +} + +- (void)setUp { + [super setUp]; + + self.testZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName]; + + // Make sure our helpers work properly + APSIncomingMessage* message = [self messageForZoneID:self.testZoneID]; + XCTAssertNotNil(message, "Should have received a APSIncomingMessage"); + + CKNotification* notification = [CKNotification notificationFromRemoteNotificationDictionary:message.userInfo]; + XCTAssertNotNil(notification, "Should have received a CKNotification"); + XCTAssert([notification isKindOfClass: [CKRecordZoneNotification class]], "Should have received a CKRecordZoneNotification"); + CKRecordZoneNotification* ckrzn = (CKRecordZoneNotification*) notification; + + XCTAssertEqual(self.testZoneID, ckrzn.recordZoneID, "Should have received a notification for the test zone"); +} + +- (void)tearDown { + self.testZoneID = nil; + + [super tearDown]; +} + + +- (void)testRegisterAndReceive { + __weak __typeof(self)weakSelf = self; + + CKKSAPSReceiver* apsr = [[CKKSAPSReceiver alloc] initWithEnvironmentName:@"testenvironment" + namedDelegatePort:SecCKKSAPSNamedPort + apsConnectionClass:[FakeAPSConnection class]]; + + XCTAssertNotNil(apsr, "Should have received a CKKSAPSReceiver"); + + CKKSAPSNotificationReceiver* anr = [[CKKSAPSNotificationReceiver alloc] initWithExpectation:[self expectationWithDescription:@"receive 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"); + }]; + + CKKSCondition* registered = [apsr register:anr forZoneID:self.testZoneID]; + XCTAssertEqual(0, [registered wait:1*NSEC_PER_SEC], "Registration should have completed within a second"); + APSIncomingMessage* message = [self messageForZoneID:self.testZoneID]; + XCTAssertNotNil(message, "Should have received a APSIncomingMessage"); + + [apsr connection:apsr.apsConnection didReceiveIncomingMessage:message]; + + [self waitForExpectationsWithTimeout:5.0 handler:nil]; +} + +- (void)testRegisterMultipleAndReceive { + __weak __typeof(self)weakSelf = self; + + CKKSAPSReceiver* apsr = [[CKKSAPSReceiver alloc] initWithEnvironmentName:@"testenvironment" + namedDelegatePort:SecCKKSAPSNamedPort + apsConnectionClass:[FakeAPSConnection class]]; + + XCTAssertNotNil(apsr, "Should have received a CKKSAPSReceiver"); + + 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 register:anr forZoneID:self.testZoneID]; + CKKSCondition* registered2 = [apsr register: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:[self messageForZoneID:self.testZoneID]]; + [apsr connection:apsr.apsConnection didReceiveIncomingMessage:[self messageForZoneID:otherZoneID]]; + + [self waitForExpectationsWithTimeout:5.0 handler:nil]; +} + +- (void)testReceiveNullNotificationIfRegisteredAfterDelivery { + CKKSAPSReceiver* apsr = [[CKKSAPSReceiver alloc] initWithEnvironmentName:@"testenvironment" + namedDelegatePort:SecCKKSAPSNamedPort + apsConnectionClass:[FakeAPSConnection class]]; + XCTAssertNotNil(apsr, "Should have received a CKKSAPSReceiver"); + + // Receives a notification for the test zone + APSIncomingMessage* message = [self messageForZoneID:self.testZoneID]; + XCTAssertNotNil(message, "Should have received a APSIncomingMessage"); + [apsr connection:apsr.apsConnection didReceiveIncomingMessage:message]; + + CKKSAPSNotificationReceiver* anr = [[CKKSAPSNotificationReceiver alloc] initWithExpectation:[self expectationWithDescription:@"receive notification"] + block: + ^(CKRecordZoneNotification* notification) { + XCTAssertNil(notification, "Should not have received a notification, since we weren't alive to receive it"); + }]; + + CKKSCondition* registered = [apsr register:anr forZoneID:self.testZoneID]; + XCTAssertEqual(0, [registered wait:1*NSEC_PER_SEC], "Registration should have completed within a second"); + + [self waitForExpectationsWithTimeout:5.0 handler:nil]; +} + +@end diff --git a/keychain/ckks/tests/CKKSCloudKitTests.m b/keychain/ckks/tests/CKKSCloudKitTests.m new file mode 100644 index 00000000..42d5af38 --- /dev/null +++ b/keychain/ckks/tests/CKKSCloudKitTests.m @@ -0,0 +1,593 @@ +/* + * 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 +#import +#import + +#import +#import +#import +#if NO_SERVER +#include +#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/ckks/tests/MockCloudKit.h" + +@interface CKKSCloudKitTests : XCTestCase + +@property NSOperationQueue *operationQueue; +@property NSBlockOperation *ckksHoldOperation; +@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(); + [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]; + self.ckksHoldOperation = [NSBlockOperation new]; + [self.ckksHoldOperation addExecutionBlock:^{ + secnotice("ckks", "CKKS testing hold released"); + }]; + + CKKSViewManager* manager = [[CKKSViewManager alloc] initWithContainerName:containerName + usePCS:SecCKKSContainerUsePCS + fetchRecordZoneChangesOperationClass:[CKFetchRecordZoneChangesOperation class] + modifySubscriptionsOperationClass:[CKModifySubscriptionsOperation class] + modifyRecordZonesOperationClass:[CKModifyRecordZonesOperation class] + apsConnectionClass:[APSConnection class] + nsnotificationCenterClass:[NSNotificationCenter class] + notifierClass:[FakeCKKSNotifier class] + setupHold:self.ckksHoldOperation]; + [CKKSViewManager resetManager:false setTo: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"]; + [self.kcv.zoneSetupOperation addDependency: self.ckksHoldOperation]; +} + +- (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 { + if(self.ckksHoldOperation) { + [self.operationQueue addOperation: self.ckksHoldOperation]; + self.ckksHoldOperation = nil; + } +} + +- (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 { + CKFetchRecordZoneChangesOptions *options = [CKFetchRecordZoneChangesOptions new]; + options.previousServerChangeToken = nil; + + CKFetchRecordZoneChangesOperation *op = [[CKFetchRecordZoneChangesOperation alloc] initWithRecordZoneIDs:@[self.zoneID] optionsByRecordZoneID:@{self.zoneID : options}]; + op.qualityOfService = NSQualityOfServiceUserInitiated; + 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", synckeys);} + if (currkeys != 3) {XCTFail(@"Unexpected number of current keys: %lu", 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*)records { + CKModifyRecordsOperation *op = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:records recordIDsToDelete:nil]; + op.qualityOfService = NSQualityOfServiceUserInitiated; + op.configuration.container = self.container; + + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + __block BOOL result = NO; + op.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, + NSArray *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 new file mode 100644 index 00000000..6c6c23c4 --- /dev/null +++ b/keychain/ckks/tests/CKKSCloudKitTestsInfo.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/keychain/ckks/tests/CKKSConditionTests.m b/keychain/ckks/tests/CKKSConditionTests.m new file mode 100644 index 00000000..65f06415 --- /dev/null +++ b/keychain/ckks/tests/CKKSConditionTests.m @@ -0,0 +1,83 @@ +/* + * 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 +#import +#import "keychain/ckks/CKKSCondition.h" +#import + +@interface CKKSConditionTests : XCTestCase +@end + +@implementation CKKSConditionTests + +- (void)setUp { + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + +-(void)testConditionAfterFulfill { + CKKSCondition* c = [[CKKSCondition alloc] init]; + + [c fulfill]; + XCTAssertEqual(0, [c wait:100*NSEC_PER_MSEC], "first wait after fulfill succeeds"); + XCTAssertEqual(0, [c wait:100*NSEC_PER_MSEC], "second wait after fulfill succeeds"); + XCTAssertEqual(0, [c wait:100*NSEC_PER_MSEC], "third wait after fulfill succeeds"); +} + +-(void)testConditionTimeout { + CKKSCondition* c = [[CKKSCondition alloc] init]; + XCTAssertNotEqual(0, [c wait:100*NSEC_PER_MSEC], "waiting without fulfilling times out"); +} + +-(void)testConditionWait { + CKKSCondition* c = [[CKKSCondition alloc] init]; + + dispatch_queue_t queue = dispatch_queue_create("testConditionWait", DISPATCH_QUEUE_CONCURRENT); + + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"wait ended (too soon)"]; + toofastexpectation.inverted = YES; + + XCTestExpectation *expectation = [self expectationWithDescription:@"wait ended"]; + + dispatch_async(queue, ^{ + XCTAssertEqual(0, [c wait:1*NSEC_PER_SEC], "Wait did not time out"); + [toofastexpectation fulfill]; + [expectation fulfill]; + }); + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(150 * NSEC_PER_MSEC)), queue, ^{ + [c fulfill]; + }); + + // Make sure it waits at least 0.1 seconds + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + + // But finishes within .6s (total) + [self waitForExpectations: @[expectation] timeout:0.5]; +} + +@end diff --git a/keychain/ckks/tests/CKKSDispatchTests.m b/keychain/ckks/tests/CKKSDispatchTests.m new file mode 100644 index 00000000..eff091fc --- /dev/null +++ b/keychain/ckks/tests/CKKSDispatchTests.m @@ -0,0 +1,249 @@ +/* + * 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@ + */ + +#include +#import +#import "keychain/ckks/CKKSNearFutureScheduler.h" + +@interface CKKSNearFutureSchedulerTests : XCTestCase + +@end + +@implementation CKKSNearFutureSchedulerTests + +- (void)setUp { + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testOneShot { + XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"]; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay:50*NSEC_PER_MSEC keepProcessAlive:true block:^{ + [expectation fulfill]; + }]; + + [scheduler trigger]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testOneShotDelay { + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.inverted = YES; + + XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"]; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [toofastexpectation fulfill]; + [expectation fulfill]; + }]; + + [scheduler trigger]; + + // Make sure it waits at least 0.1 seconds + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + + // But finishes within 1.1s (total) + [self waitForExpectations: @[expectation] timeout:1]; +} + +- (void)testOneShotManyTrigger { + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.inverted = YES; + + XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"]; + expectation.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:true block:^{ + [toofastexpectation fulfill]; + [expectation fulfill]; + }]; + + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + + // Make sure it waits at least 0.1 seconds + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + + // But finishes within .6s (total) + [self waitForExpectations: @[expectation] timeout:0.5]; + + // Ensure we don't get called again in the next 0.3 s + XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"]; + waitmore.inverted = YES; + [self waitForExpectations: @[waitmore] timeout: 0.3]; +} + + +- (void)testMultiShot { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [first fulfill]; + [second fulfill]; + }]; + + [scheduler trigger]; + + [self waitForExpectations: @[first] timeout:0.2]; + + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + + [self waitForExpectations: @[second] timeout:0.2]; + + XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"]; + waitmore.inverted = YES; + [self waitForExpectations: @[waitmore] timeout: 0.2]; +} + +- (void)testMultiShotDelays { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"]; + longdelay.inverted = YES; + longdelay.expectedFulfillmentCount = 2; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" initialDelay: 50*NSEC_PER_MSEC continuingDelay:300*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [first fulfill]; + [longdelay fulfill]; + [second fulfill]; + }]; + + [scheduler trigger]; + + [self waitForExpectations: @[first] timeout:0.2]; + + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + + // longdelay should NOT be fulfilled twice in the first 0.3 seconds + [self waitForExpectations: @[longdelay] timeout:0.2]; + + // But second should be fulfilled in the first 0.8 seconds + [self waitForExpectations: @[second] timeout:0.5]; + + XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"]; + waitmore.inverted = YES; + [self waitForExpectations: @[waitmore] timeout: 0.2]; +} + +- (void)testCancel { + XCTestExpectation *cancelexpectation = [self expectationWithDescription:@"FutureScheduler fired (after cancel)"]; + cancelexpectation.inverted = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:true block:^{ + [cancelexpectation fulfill]; + }]; + + [scheduler trigger]; + [scheduler cancel]; + + // Make sure it does not fire in 0.5 s + [self waitForExpectations: @[cancelexpectation] timeout:0.2]; +} + +- (void)testDelayedNoShot { + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.inverted = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [toofastexpectation fulfill]; + }]; + + // Tell the scheduler to wait, but don't trigger it. It shouldn't fire. + [scheduler waitUntil: 50*NSEC_PER_MSEC]; + + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; +} + +- (void)testDelayedOneShot { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.inverted = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [first fulfill]; + [toofastexpectation fulfill]; + }]; + + [scheduler waitUntil: 150*NSEC_PER_MSEC]; + [scheduler trigger]; + + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + [self waitForExpectations: @[first] timeout:0.2]; +} + +- (void)testDelayedMultiShot { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.expectedFulfillmentCount = 2; + toofastexpectation.inverted = YES; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [first fulfill]; + [second fulfill]; + [toofastexpectation fulfill]; + }]; + + [scheduler trigger]; + [self waitForExpectations: @[first] timeout:0.2]; + + [scheduler waitUntil: 150*NSEC_PER_MSEC]; + [scheduler trigger]; + + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + [self waitForExpectations: @[second] timeout:0.3]; +} + +@end diff --git a/keychain/ckks/tests/CKKSEncryptionTests.m b/keychain/ckks/tests/CKKSEncryptionTests.m new file mode 100644 index 00000000..1b2d0073 --- /dev/null +++ b/keychain/ckks/tests/CKKSEncryptionTests.m @@ -0,0 +1,653 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import +#import "CloudKitMockXCTest.h" + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSItem.h" +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSIncomingQueueEntry.h" +#import "keychain/ckks/CKKSItemEncrypter.h" + +#include +#include + +@interface CloudKitKeychainEncryptionTests : CloudKitMockXCTest +@end + +@implementation CloudKitKeychainEncryptionTests + ++ (void)setUp { + // We don't really want to spin up the whole machinery for the encryption tests + SecCKKSDisable(); + + [super setUp]; +} + +- (void)setUp { + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + ++ (void)tearDown { + [super tearDown]; + SecCKKSResetSyncing(); +} + +- (void)testKeyGeneration { + CKKSAESSIVKey* key1 = [CKKSAESSIVKey randomKey]; + CKKSAESSIVKey* key2 = [CKKSAESSIVKey randomKey]; + CKKSAESSIVKey* fixedkey1 = [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="]; + XCTAssertNotNil(fixedkey1, "fixedkey1 generated from base64"); + CKKSAESSIVKey* fixedkey2 = [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="]; + XCTAssertNotNil(fixedkey2, "fixedkey2 generated from base64"); + + XCTAssertEqualObjects(fixedkey1, fixedkey2, "matching fixed keys match"); + XCTAssertNotEqualObjects(fixedkey1, key1, "fixed key and random key do not match"); + XCTAssertNotEqualObjects(key1, key2, "two random keys do not match"); + + XCTAssertNil([[CKKSAESSIVKey alloc] initWithBase64: @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA------AAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="], "Invalid base64 does not generate a key"); +} + +- (void)testBasicEncryption { + NSString* plaintext = @"plaintext is plain"; + NSData* plaintextData = [plaintext dataUsingEncoding: NSUTF8StringEncoding]; + + NSError* error = nil; + + CKKSKey* key = [[CKKSKey alloc] initSelfWrappedWithAESKey: [[CKKSAESSIVKey alloc] initWithBase64: @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="] + uuid:@"8b2aeb7f-4af3-43e9-b6e6-70d5c728ebf7" + keyclass:SecCKKSKeyClassC + state: SecCKKSProcessedStateLocal + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encodedCKRecord: nil + currentkey: true]; + + NSData* ciphertext = [key encryptData: plaintextData authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertext, "Received a ciphertext"); + NSData* roundtrip = [key decryptData: ciphertext authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtrip, "Received a plaintext"); + XCTAssertEqualObjects(plaintextData, roundtrip, "roundtripped data matches input"); + + NSData* shortDecrypt = [key decryptData: [@"asdf" dataUsingEncoding:NSUTF8StringEncoding] authenticatedData:nil error:&error]; + XCTAssertNotNil(error, "Decrypting a short plaintext returned an error"); + XCTAssertNil(shortDecrypt, "Decrypting a short plaintext returned nil"); + error = nil; + + // Check that we're adding enough entropy + NSData* ciphertextAgain = [key encryptData: plaintextData authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertextAgain, "Received a ciphertext"); + NSData* roundtripAgain = [key decryptData: ciphertextAgain authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtripAgain, "Received a plaintext"); + XCTAssertEqualObjects(plaintextData, roundtripAgain, "roundtripped data matches input"); + + XCTAssertNotEqualObjects(ciphertext, ciphertextAgain, "two encryptions of same input produce different outputs"); + + // Do it all again + CKKSKey* key2 = [[CKKSKey alloc] initSelfWrappedWithAESKey: [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="] + uuid:@"f5e7f20f-0885-48f9-b75d-9f0cfd2171b6" + keyclass:SecCKKSKeyClassC + state: SecCKKSProcessedStateLocal + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encodedCKRecord: nil + currentkey: true]; + + NSData* ciphertext2 = [key2 encryptData: plaintextData authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertext2, "Received a ciphertext"); + NSData* roundtrip2 = [key decryptData: ciphertext authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtrip2, "Received a plaintext"); + XCTAssertEqualObjects(plaintextData, roundtrip2, "roundtripped data matches input"); + + XCTAssertNotEqualObjects(ciphertext, ciphertext2, "ciphertexts with distinct keys are distinct"); +} + +- (void)testAuthEncryption { + NSString* plaintext = @"plaintext is plain"; + NSData* plaintextData = [plaintext dataUsingEncoding: NSUTF8StringEncoding]; + + NSError* error = nil; + + CKKSKey* key = [[CKKSKey alloc] initSelfWrappedWithAESKey: [[CKKSAESSIVKey alloc] initWithBase64: @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="] + uuid:@"8b2aeb7f-4af3-43e9-b6e6-70d5c728ebf7" + keyclass:SecCKKSKeyClassC + state:SecCKKSProcessedStateLocal + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encodedCKRecord:nil + currentkey:true]; + NSDictionary* ad = @{ @"test": [@"data" dataUsingEncoding: NSUTF8StringEncoding] }; + + NSData* ciphertext = [key encryptData: plaintextData authenticatedData: ad error: &error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertext, "Received a ciphertext"); + NSData* roundtrip = [key decryptData: ciphertext authenticatedData: ad error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtrip, "Received a plaintext"); + XCTAssertEqualObjects(plaintextData, roundtrip, "roundtripped data matches input"); + + // Without AD, decryption should fail + roundtrip = [key decryptData: ciphertext authenticatedData: nil error: &error]; + XCTAssertNotNil(error, "Not passing in the authenticated data causes break"); + XCTAssertNil(roundtrip, "on error, don't receive plaintext"); + error = nil; + + roundtrip = [key decryptData: ciphertext authenticatedData: @{ @"test": [@"wrongdata" dataUsingEncoding: NSUTF8StringEncoding] } error: &error]; + XCTAssertNotNil(error, "Wrong authenticated data causes break"); + XCTAssertNil(roundtrip, "on error, don't receive plaintext"); + error = nil; +} + +- (void)testDictionaryEncryption { + NSDictionary* plaintext = @{ @"test": [@"data" dataUsingEncoding: NSUTF8StringEncoding], + @"more": [@"testdata" dataUsingEncoding: NSUTF8StringEncoding] }; + NSDictionary* roundtrip; + + NSError* error = nil; + + CKKSKey* key = [[CKKSKey alloc] initSelfWrappedWithAESKey: [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="] + uuid:@"f5e7f20f-0885-48f9-b75d-9f0cfd2171b6" + keyclass:SecCKKSKeyClassC + state: SecCKKSProcessedStateLocal + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encodedCKRecord: nil + currentkey: true]; + + NSData* ciphertext = [CKKSItemEncrypter encryptDictionary: plaintext key: key.aessivkey authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertext, "Received a ciphertext"); + roundtrip = [CKKSItemEncrypter decryptDictionary: ciphertext key: key.aessivkey authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtrip, "Received a plaintext"); + XCTAssertEqualObjects(plaintext, roundtrip, "roundtripped dictionary matches input"); + + NSDictionary* authenticatedData = @{@"data": [@"auth" dataUsingEncoding: NSUTF8StringEncoding], @"moredata": [@"unauth" dataUsingEncoding: NSUTF8StringEncoding]}; + NSDictionary* unauthenticatedData = @{@"data": [@"notequal" dataUsingEncoding: NSUTF8StringEncoding], @"moredata": [@"unauth" dataUsingEncoding: NSUTF8StringEncoding]}; + + NSData* authciphertext = [CKKSItemEncrypter encryptDictionary: plaintext key: key.aessivkey authenticatedData: authenticatedData error: &error]; + XCTAssertNil(error, "No error encrypting plaintext with authenticated data"); + XCTAssertNotNil(authciphertext, "Received a ciphertext"); + roundtrip = [CKKSItemEncrypter decryptDictionary: authciphertext key: key.aessivkey authenticatedData: authenticatedData error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip with authenticated data"); + XCTAssertNotNil(roundtrip, "Received a plaintext"); + XCTAssertEqualObjects(plaintext, roundtrip, "roundtripped dictionary matches input"); + + roundtrip = [CKKSItemEncrypter decryptDictionary: authciphertext key: key.aessivkey authenticatedData: unauthenticatedData error: &error]; + XCTAssertNotNil(error, "Error decrypting roundtrip with bad authenticated data"); + XCTAssertNil(roundtrip, "Did not receive a plaintext when authenticated data is wrong"); +} + +- (void)testKeyWrapping { + CKKSAESSIVKey* key = [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="]; + + CKKSAESSIVKey* keyToWrap = [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="]; + + NSError* error = nil; + + CKKSWrappedAESSIVKey* wrappedKey = [key wrapAESKey: keyToWrap error:&error]; + XCTAssertNil(error, "no error wrapping key"); + XCTAssertNotNil(wrappedKey, "wrapped key was returned"); + + XCTAssert(0 != memcmp(keyToWrap->key, (wrappedKey->key)+(CKKSWrappedKeySize - CKKSKeySize), CKKSKeySize), "wrapped key is different from original key"); + + CKKSAESSIVKey* unwrappedKey = [key unwrapAESKey: wrappedKey error:&error]; + XCTAssertNil(error, "no error unwrapping key"); + XCTAssertNotNil(unwrappedKey, "unwrapped key was returned"); + + XCTAssert(0 == memcmp(keyToWrap->key, unwrappedKey->key, CKKSKeySize), "unwrapped key matches original key"); + XCTAssertEqualObjects(keyToWrap, unwrappedKey, "unwrapped key matches original key"); +} + +- (void)testKeyWrappingFailure { + CKKSAESSIVKey* key = [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="]; + + CKKSAESSIVKey* keyToWrap = [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="]; + + NSError* error = nil; + + CKKSWrappedAESSIVKey* wrappedKey = [key wrapAESKey: keyToWrap error:&error]; + XCTAssertNil(error, "no error wrapping key"); + XCTAssertNotNil(wrappedKey, "wrapped key was returned"); + + XCTAssert(0 != memcmp(keyToWrap->key, (wrappedKey->key)+(CKKSWrappedKeySize - CKKSKeySize), CKKSKeySize), "wrapped key is different from original key"); + wrappedKey->key[0] ^= 0x1; + + CKKSAESSIVKey* unwrappedKey = [key unwrapAESKey: wrappedKey error:&error]; + XCTAssertNotNil(error, "error unwrapping key"); + XCTAssertNil(unwrappedKey, "unwrapped key was not returned in error case"); +} + +- (void)testKeyHierarchy { + NSError* error = nil; + NSData* testCKRecord = [@"nonsense" dataUsingEncoding:NSUTF8StringEncoding]; + CKKSKey* tlk = [self fakeTLK:self.testZoneID]; + + [tlk saveToDatabase:&error]; + [tlk saveKeyMaterialToKeychain:&error]; + XCTAssertNil(error, "tlk saved to database without error"); + + CKKSKey* level1 = [CKKSKey randomKeyWrappedByParent: tlk keyclass:SecCKKSKeyClassA error:&error]; + level1.encodedCKRecord = testCKRecord; + 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"); + + 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"); + + NSString* level2UUID = level2.uuid; + + // Fetch the level2 key from the database. + CKKSKey* extractedkey = [CKKSKey fromDatabase:level2UUID zoneID:self.testZoneID error:&error]; + [extractedkey unwrapViaKeyHierarchy: &error]; + XCTAssertNotNil(extractedkey, "could fetch key again"); + XCTAssertNil(error, "no error fetching key from database"); + + CKKSAESSIVKey* extracedaeskey = [extractedkey ensureKeyLoaded:&error]; + XCTAssertNotNil(extractedkey, "fetched key could unwrap"); + XCTAssertNil(error, "no error forcing unwrap on fetched key"); + + XCTAssertEqualObjects(level2.aessivkey, extracedaeskey, @"fetched aes key is equal to saved key"); +} + +- (void)ensureKeychainSaveLoad: (CKKSKey*) key { + NSError* error = nil; + [key saveToDatabase:&error]; + XCTAssertNil(error, "no error saving to database"); + [key saveKeyMaterialToKeychain:&error]; + XCTAssertNil(error, "no error saving to keychain"); + + CKKSKey* loadedKey = [CKKSKey fromDatabase:key.uuid zoneID:self.testZoneID error:&error]; + XCTAssertNil(error, "no error loading from database"); + XCTAssertNotNil(loadedKey, "Received an item back from the database"); + + XCTAssert([loadedKey loadKeyMaterialFromKeychain:&error], "could load key material back from keychain"); + XCTAssertNil(error, "no error loading key from keychain"); + + XCTAssertEqualObjects(loadedKey.aessivkey, key.aessivkey, "Loaded key is identical after save/load"); +} + +- (void)testKeychainSave { + NSError* error = nil; + NSData* testCKRecord = [@"nonsense" dataUsingEncoding:NSUTF8StringEncoding]; + CKKSKey* tlk = [self fakeTLK:self.testZoneID]; + [self ensureKeychainSaveLoad: tlk]; + + // Ensure that Class A and Class C can do the same thing + CKKSKey* classA = [CKKSKey randomKeyWrappedByParent: tlk keyclass:SecCKKSKeyClassA error:&error]; + classA.encodedCKRecord = testCKRecord; + XCTAssertNil(error, "No error creating random class A key"); + [self ensureKeychainSaveLoad: classA]; + CKKSKey* classC = [CKKSKey randomKeyWrappedByParent: tlk keyclass:SecCKKSKeyClassC error:&error]; + classC.encodedCKRecord = testCKRecord; + XCTAssertNil(error, "No error creating random class C key"); + [self ensureKeychainSaveLoad: classC]; +} + +- (BOOL)tryDecryptWithProperAuthData:(CKKSItem*)ciphertext plaintext:(NSDictionary*)plaintext { + NSDictionary* roundtrip; + NSError *error = nil; + roundtrip = [CKKSItemEncrypter decryptItemToDictionary: (CKKSItem*) ciphertext error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtrip, "Received a plaintext"); + XCTAssertEqualObjects(plaintext, roundtrip, "roundtripped dictionary matches input"); + return error == nil && roundtrip != nil && [plaintext isEqualToDictionary:roundtrip]; +} + +- (BOOL)tryDecryptWithBrokenAuthData:(CKKSItem *)ciphertext { + NSDictionary* brokenAuthentication; + NSError *error = nil; + brokenAuthentication = [CKKSItemEncrypter decryptItemToDictionary: (CKKSItem*) ciphertext error: &error]; + XCTAssertNotNil(error, "Error exists decrypting ciphertext with bad authenticated data: %@", error); + XCTAssertNil(brokenAuthentication, "Did not receive a plaintext if authenticated data was mucked with"); + return error != nil && brokenAuthentication == nil; +} + +- (void)testItemDictionaryEncryption { + NSDictionary* plaintext = @{ @"test": [@"data" dataUsingEncoding: NSUTF8StringEncoding], + @"more": [@"testdata" dataUsingEncoding: NSUTF8StringEncoding] }; + NSError* error = nil; + NSString *uuid = @"8b2aeb7f-4af3-43e9-b6e6-70d5c728ebf7"; + + CKKSKey* key = [self fakeTLK:self.testZoneID]; + [key saveToDatabase: &error]; + [key saveKeyMaterialToKeychain:&error]; + XCTAssertNil(error, @"could save the fake TLK to the database"); + + CKKSItem* ciphertext = [CKKSItemEncrypter encryptCKKSItem: [[CKKSItem alloc] initWithUUID:uuid + parentKeyUUID:key.uuid + zoneID:self.testZoneID] + dataDictionary:plaintext + updatingCKKSItem:nil + parentkey:key + error:&error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertext, "Received a ciphertext"); + XCTAssertEqual(ciphertext.encver, currentCKKSItemEncryptionVersion, "Encryption sets the current protocol version"); + + [self tryDecryptWithProperAuthData:ciphertext plaintext:plaintext]; + + // Make sure these fields are authenticated and that authentication works. + // Messing with them should make the item not decrypt. + ciphertext.generationCount = 100; + XCTAssertTrue([self tryDecryptWithBrokenAuthData:ciphertext], "Decryption with broken authentication data fails"); + ciphertext.generationCount = 0; + XCTAssertTrue([self tryDecryptWithProperAuthData:ciphertext plaintext:plaintext], "Decryption with authentication data succeeds"); + + ciphertext.encver += 1; + XCTAssertTrue([self tryDecryptWithBrokenAuthData:ciphertext], "Decryption with broken authentication data fails"); + ciphertext.encver -= 1; + XCTAssertTrue([self tryDecryptWithProperAuthData:ciphertext plaintext:plaintext], "Decryption with authentication data succeeds"); + + ciphertext.uuid = @"x"; + XCTAssertTrue([self tryDecryptWithBrokenAuthData:ciphertext], "Decryption with broken authentication data fails"); + ciphertext.uuid = uuid; + XCTAssertTrue([self tryDecryptWithProperAuthData:ciphertext plaintext:plaintext], "Decryption with authentication data succeeds"); +} + +- (void)testEncryptionVersions { + NSDictionary* plaintext = @{ @"test": [@"data" dataUsingEncoding: NSUTF8StringEncoding], + @"more": [@"testdata" dataUsingEncoding: NSUTF8StringEncoding] }; + NSDictionary* output; + NSError *error = nil; + NSData* data = [NSPropertyListSerialization dataWithPropertyList:plaintext + format:NSPropertyListBinaryFormat_v1_0 + options:0 + error:&error]; + XCTAssertNil(error); + CKKSKey* key = [self fakeTLK:self.testZoneID]; + [key saveToDatabase: &error]; + [key saveKeyMaterialToKeychain:&error]; + XCTAssertNil(error, @"could save the fake TLK to the database"); + + CKKSAESSIVKey* keyToWrap = [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="]; + CKKSWrappedAESSIVKey* wrappedKey = [key wrapAESKey: keyToWrap error:&error]; + XCTAssertNil(error, "no error wrapping key"); + XCTAssertNotNil(wrappedKey, "wrapped key was returned"); + CKKSItem* baseitem = [[CKKSItem alloc] initWithUUID:@"abc" + parentKeyUUID:key.uuid + zoneID:self.testZoneID + encItem:data + wrappedkey:wrappedKey + generationCount:0 + encver:CKKSItemEncryptionVersionNone]; + XCTAssertNotNil(baseitem, "Constructed CKKSItem"); + + // First try versionNone. Should fail, we don't support unencrypted data + output = [CKKSItemEncrypter decryptItemToDictionary:baseitem error:&error]; + XCTAssert(error, "Did not failed to decrypt v0 item"); + XCTAssertNil(output, "Did not failed to decrypt v0 item"); + error = nil; + output = nil; + + // Then try version1. Should take actual decryption path and fail because there's no properly encrypted data. + baseitem.encver = CKKSItemEncryptionVersion1; + output = [CKKSItemEncrypter decryptItemToDictionary:baseitem error:&error]; + XCTAssertNotNil(error, "Taking v1 codepath without encrypted item fails"); + XCTAssertEqualObjects(error.localizedDescription, @"could not ccsiv_crypt", "Error specifically failure to ccsiv_crypt"); + XCTAssertNil(output, "Did not receive output from failed decryption call"); + error = nil; + output = nil; + + // Finally, some unknown version should fail immediately + baseitem.encver = 100; + output = [CKKSItemEncrypter decryptItemToDictionary:baseitem error:&error]; + XCTAssertNotNil(error); + NSString *errstr = [NSString stringWithFormat:@"%@", error.localizedDescription]; + NSString *expected = @"Unrecognized encryption version: 100"; + XCTAssertEqualObjects(expected, errstr, "Error is specific to unrecognized version failure"); + XCTAssertNil(output); +} + +- (void)testKeychainPersistence { + + NSString* plaintext = @"plaintext is plain"; + NSData* plaintextData = [plaintext dataUsingEncoding: NSUTF8StringEncoding]; + + NSError* error = nil; + + NSString* uuid = @"f5e7f20f-0885-48f9-b75d-9f0cfd2171b6"; + + CKKSKey* key = [[CKKSKey alloc] initSelfWrappedWithAESKey: [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="] + uuid:uuid + keyclass:SecCKKSKeyClassA + state:SecCKKSProcessedStateLocal + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encodedCKRecord: nil + currentkey: true]; + + NSData* ciphertext = [key encryptData: plaintextData authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertext, "Received a ciphertext"); + NSData* roundtrip = [key decryptData: ciphertext authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtrip, "Received a plaintext"); + XCTAssertEqualObjects(plaintextData, roundtrip, "roundtripped data matches input"); + + // Check that there is no key material in the keychain + CKKSKey* reloadedKey = [CKKSKey keyFromKeychain:uuid + parentKeyUUID:uuid + keyclass:SecCKKSKeyClassA + state:SecCKKSProcessedStateLocal + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encodedCKRecord:nil + currentkey:true + error:&error]; + + XCTAssertNotNil(error, "error exists when there's nothing in the keychain"); + XCTAssertNil(reloadedKey, "no key object when there's nothing in the keychain"); + error = nil; + + [key saveKeyMaterialToKeychain:&error]; + XCTAssertNil(error, "Could save key material to keychain"); + + // Reload the key material and check that it works + reloadedKey = [CKKSKey keyFromKeychain:uuid + parentKeyUUID:uuid + keyclass:SecCKKSKeyClassA + state:SecCKKSProcessedStateLocal + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encodedCKRecord:nil + currentkey:true + error:&error]; + + XCTAssertNil(error, "No error loading key from keychain"); + XCTAssertNotNil(reloadedKey, "Could load key from keychain"); + + NSData* ciphertext2 = [reloadedKey encryptData: plaintextData authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertext2, "Received a ciphertext"); + NSData* roundtrip2 = [reloadedKey decryptData: ciphertext2 authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtrip2, "Received a plaintext"); + XCTAssertEqualObjects(plaintextData, roundtrip2, "roundtripped data matches input"); + + XCTAssertEqualObjects(key.aessivkey, reloadedKey.aessivkey, "reloaded AES key is equal to generated key"); + + [key deleteKeyMaterialFromKeychain: &error]; + XCTAssertNil(error, "could delete key material from keychain"); + + // Check that there is no key material in the keychain + // Note that TLKs will be stashed (and deleteKeyMaterial won't delete the stash), and so this test would fail for a TLK + + reloadedKey = [CKKSKey keyFromKeychain:uuid + parentKeyUUID:uuid + keyclass:SecCKKSKeyClassA + state:SecCKKSProcessedStateLocal + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encodedCKRecord:nil + currentkey:true + error:&error]; + + XCTAssertNotNil(error, "error exists when there's nothing in the keychain"); + XCTAssertNil(reloadedKey, "no key object when there's nothing in the keychain"); + error = nil; +} + +- (BOOL)padAndUnpadDataWithLength:(NSUInteger)dataLength blockSize:(NSUInteger)blockSize extra:(BOOL)extra { + // Test it works + NSMutableData *data = [NSMutableData dataWithLength:dataLength]; + memset((unsigned char *)[data mutableBytes], 0x55, dataLength); + NSMutableData *orig = [data mutableCopy]; + NSData *padded = [CKKSItemEncrypter padData:data blockSize:blockSize additionalBlock:extra]; + XCTAssertNotNil(padded, "Padding never returns nil"); + XCTAssertEqualObjects(data, orig, "Input object unmodified"); + XCTAssertTrue(padded.length % blockSize == 0, "Padded data aligns on %lu-byte blocksize", (unsigned long)blockSize); + XCTAssertTrue(padded.length > data.length, "At least one byte of padding has been added"); + NSData *unpadded = [CKKSItemEncrypter removePaddingFromData:padded]; + XCTAssertNotNil(unpadded, "Successfully removed padding again"); + + // Test it fails by poking some byte in the padding + NSMutableData *glitch = [NSMutableData dataWithData:padded]; + NSUInteger offsetFromTop = glitch.length - arc4random_uniform((unsigned)(glitch.length - data.length)) - 1; + uint8_t poke = ((uint8_t)arc4random_uniform(0xFF) & 0x7E) + 1; // This gets most of the values while excluding 0 and 0x80 + unsigned char *bytes = [glitch mutableBytes]; + bytes[offsetFromTop] = poke; + XCTAssertNil([CKKSItemEncrypter removePaddingFromData:glitch], "Cannot remove broken padding (len %lu, dlen %lu, plen %lu glitchidx %lu, glitchval 0x%x)", (unsigned long)glitch.length, (unsigned long)data.length, (unsigned long)glitch.length - data.length, (unsigned long)offsetFromTop, poke); + + return padded && unpadded && [unpadded isEqual:data]; +} + +- (void)testPadding { + [self runPaddingTest:NO]; + [self runPaddingTest:YES]; + + NSData *data = nil; + XCTAssertNil([CKKSItemEncrypter removePaddingFromData:[NSData data]], "zero data valid ?"); + + data = [CKKSItemEncrypter removePaddingFromData:[NSData dataWithBytes:"\x80" length:1]]; + XCTAssert(data && data.length == 0, "data wrong size"); + + data = [CKKSItemEncrypter removePaddingFromData:[NSData dataWithBytes:"\x80\x00" length:2]]; + XCTAssert(data && data.length == 0, "data wrong size"); + data = [CKKSItemEncrypter removePaddingFromData:[NSData dataWithBytes:"\x80\x00\x00" length:3]]; + XCTAssert(data && data.length == 0, "data wrong size"); + data = [CKKSItemEncrypter removePaddingFromData:[NSData dataWithBytes:"\x80\x80\x80" length:3]]; + XCTAssert(data && data.length == 2, "data wrong size"); + data = [CKKSItemEncrypter removePaddingFromData:[NSData dataWithBytes:"\x80\x80\x00" length:3]]; + XCTAssert(data && data.length == 1, "data wrong size"); + data = [CKKSItemEncrypter removePaddingFromData:[NSData dataWithBytes:"\x00\x80\x00" length:3]]; + XCTAssert(data && data.length == 1, "data wrong size"); + +} + +- (void)runPaddingTest:(BOOL)extra { + + // Aligned, arbitrary lengths + for (int idx = 1; idx <= 128; ++idx) { + XCTAssertTrue([self padAndUnpadDataWithLength:idx blockSize:idx extra:extra], "Padding aligned data succeeds"); + } + + // Off-by-one, arbitrary lengths + for (int idx = 1; idx <= 128; ++idx) { + XCTAssertTrue([self padAndUnpadDataWithLength:idx - 1 blockSize:idx extra:extra], "Padding aligned data succeeds"); + XCTAssertTrue([self padAndUnpadDataWithLength:idx + 1 blockSize:idx extra:extra], "Padding aligned data succeeds"); + } + + // Misaligned, arbitrary lengths + for (int idx = 1; idx <= 1000; ++idx) { + NSUInteger dataSize = arc4random_uniform(128) + 1; + NSUInteger blockSize = arc4random_uniform(128) + 1; + XCTAssertTrue([self padAndUnpadDataWithLength:dataSize blockSize:blockSize extra:extra], "Padding data lenght %lu to blockSize %lu succeeds", (unsigned long)dataSize, (unsigned long)blockSize); + } + + // Special case: blocksize 0 results in 1 byte of padding always + NSMutableData *data = [NSMutableData dataWithLength:23]; + 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"); + NSData *unpadded = [CKKSItemEncrypter removePaddingFromData:padded]; + XCTAssertNotNil(unpadded, "Successfully removed padding again"); + XCTAssertEqualObjects(data, unpadded, "Data effectively unmodified through padding-unpadding trip"); + + // Nonpadded data + unpadded = [CKKSItemEncrypter removePaddingFromData:data]; + XCTAssertNil(unpadded, "Cannot remove padding where none exists"); + + // Feeding nil + padded = [CKKSItemEncrypter padData:nil blockSize:0 additionalBlock:extra]; + XCTAssertNotNil(padded, "padData always returns a data object"); + XCTAssertEqual(padded.length, extra ? 2ul : 1ul, "Length of padded nil object is padding byte only--two if extra"); + unpadded = [CKKSItemEncrypter removePaddingFromData:nil]; + XCTAssertNil(unpadded, "Removing padding from nil is senseless"); +} + +- (BOOL)encryptAndDecryptDictionary:(NSDictionary*)data key:(CKKSKey *)key { + NSDictionary* roundtrip; + NSError *error = nil; + NSData* ciphertext = [CKKSItemEncrypter encryptDictionary: data key: key.aessivkey authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error encrypting plaintext"); + XCTAssertNotNil(ciphertext, "Received a ciphertext"); + // AES-SIV adds 32 bytes, need to subtract them + XCTAssertTrue((ciphertext.length - 32) % SecCKKSItemPaddingBlockSize == 0, "Ciphertext aligned on %lu-byte boundary", (unsigned long)SecCKKSItemPaddingBlockSize); + roundtrip = [CKKSItemEncrypter decryptDictionary: ciphertext key: key.aessivkey authenticatedData: nil error: &error]; + XCTAssertNil(error, "No error decrypting roundtrip"); + XCTAssertNotNil(roundtrip, "Received a plaintext"); + XCTAssertEqualObjects(data, roundtrip, "roundtripped dictionary matches input"); + return (ciphertext.length - 32) % SecCKKSItemPaddingBlockSize == 0 && roundtrip && error == nil && [data isEqualToDictionary:roundtrip]; +} + +- (void)testDictionaryPadding { + // Pad a bunch of bytes to nearest boundary + NSDictionary* unaligned_74 = @{ @"test": [@"data" dataUsingEncoding: NSUTF8StringEncoding], + @"more": [@"testdata" dataUsingEncoding: NSUTF8StringEncoding] }; + // Pad precisely one byte + NSDictionary* unaligned_79 = @{ @"test12345": [@"data" dataUsingEncoding: NSUTF8StringEncoding], + @"more": [@"testdata" dataUsingEncoding: NSUTF8StringEncoding] }; + // Already on boundary, pad until next boundary + NSDictionary* aligned_80 = @{ @"test123456": [@"data" dataUsingEncoding: NSUTF8StringEncoding], + @"more": [@"testdata" dataUsingEncoding: NSUTF8StringEncoding] }; + CKKSKey* key = [[CKKSKey alloc] initSelfWrappedWithAESKey: [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="] + uuid:@"f5e7f20f-0885-48f9-b75d-9f0cfd2171b6" + keyclass:SecCKKSKeyClassC + state:SecCKKSProcessedStateLocal + zoneID:nil + encodedCKRecord:nil + currentkey:true]; + + XCTAssertTrue([self encryptAndDecryptDictionary:unaligned_74 key:key], "Roundtrip with unaligned data succeeds"); + XCTAssertTrue([self encryptAndDecryptDictionary:unaligned_79 key:key], "Roundtrip with unaligned data succeeds"); + XCTAssertTrue([self encryptAndDecryptDictionary:aligned_80 key:key], "Roundtrip with aligned data succeeds"); +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/tests/CKKSLoggerTests.m b/keychain/ckks/tests/CKKSLoggerTests.m new file mode 100644 index 00000000..42ca79d6 --- /dev/null +++ b/keychain/ckks/tests/CKKSLoggerTests.m @@ -0,0 +1,230 @@ +/* + * 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 "CKKSTests.h" +#import "keychain/ckks/CKKSAnalyticsLogger.h" +#import +#import +#import + +static NSString* tablePath = nil; + +@interface SQLiteTests : XCTestCase +@end + +@implementation SQLiteTests + ++ (void)setUp +{ + [super setUp]; + + tablePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test_table.db"]; +} + +- (void)setUp +{ + [super setUp]; + + [[NSFileManager defaultManager] removeItemAtPath:tablePath error:nil]; +} + +- (void)tearDown +{ + [[NSFileManager defaultManager] removeItemAtPath:tablePath error:nil]; + + [super tearDown]; +} + +- (void)testCreateLoggingDatabase +{ + NSString* schema = @"CREATE table test (test_column INTEGER);"; + SFSQLite* sqlTable = [[SFSQLite alloc] initWithPath:tablePath schema:schema]; + XCTAssertTrue([sqlTable openWithError:nil]); + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:tablePath]); + [sqlTable close]; +} + +- (void)testInsertAndDelete +{ + NSString* schema = @"CREATE table test (test_column INTEGER);"; + SFSQLite* sqlTable = [[SFSQLite alloc] initWithPath:tablePath schema:schema]; + XCTAssertTrue([sqlTable openWithError:nil]); + + [sqlTable insertOrReplaceInto:@"test" values:@{@"test_column" : @(1)}]; + [sqlTable insertOrReplaceInto:@"test" values:@{@"test_column" : @(2)}]; + [sqlTable insertOrReplaceInto:@"test" values:@{@"test_column" : @(3)}]; + XCTAssertTrue([[sqlTable selectAllFrom:@"test" where:nil bindings:nil] count] == 3); + + [sqlTable deleteFrom:@"test" where:@"test_column = ?" bindings:@[@3]]; + XCTAssertTrue([[sqlTable selectAllFrom:@"test" where:nil bindings:nil] count] == 2); + + [sqlTable executeSQL:@"delete from test"]; + XCTAssertTrue([[sqlTable selectAllFrom:@"test" where:nil bindings:nil] count] == 0); +} + +@end + +@interface CKKSAnalyticsLoggerTests : CloudKitKeychainSyncingTestsBase +@end + +@implementation CKKSAnalyticsLoggerTests + +- (void)testLoggingJSONGenerated +{ + [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, 8); + + NSError* error = nil; + NSData* json = [[CKKSAnalyticsLogger logger] getLoggingJSONWithError:&error]; + XCTAssertNotNil(json, @"failed to generate logging json"); + XCTAssertNil(error, @"encourntered error getting logging json: %@", error); + + NSDictionary* dictionary = [NSJSONSerialization JSONObjectWithData:json options:0 error:&error]; + XCTAssertNotNil(dictionary, @"failed to generate dictionary from json data"); + XCTAssertNil(error, @"encountered error deserializing json: %@", error); + XCTAssertTrue([dictionary isKindOfClass:[NSDictionary class]], @"did not get the class we expected from json deserialization"); +} + +- (void)testSplunkDefaultTopicNameExists +{ + CKKSAnalyticsLogger* logger = [CKKSAnalyticsLogger logger]; + dispatch_sync(logger.splunkLoggingQueue, ^{ + XCTAssertNotNil(logger.splunkTopicName); + }); +} + +- (void)testSplunkDefaultBagURLExists +{ + CKKSAnalyticsLogger* logger = [CKKSAnalyticsLogger logger]; + dispatch_sync(logger.splunkLoggingQueue, ^{ + XCTAssertNotNil(logger.splunkBagURL); + }); +} + +// test_KeychainCKKS | CKKSTests failed: "Failed subtests: -[CloudKitKeychainSyncingTests testSplunkUploadURLExists]" [j71ap][CoreOSTigris15Z240][bats-e-27-204-1] +#if 0 +- (void)testSplunkUploadURLExists +{ + CKKSAnalyticsLogger* logger = [CKKSAnalyticsLogger logger]; + dispatch_sync(logger.splunkLoggingQueue, ^{ + logger.ignoreServerDisablingMessages = YES; + XCTAssertNotNil(logger.splunkUploadURL); + }); +} +#endif + +- (void)testLastSuccessfulSyncDate +{ + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + 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]; + + NSDate* syncDate = [[CKKSAnalyticsLogger logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassC inView:self.keychainView]; + XCTAssertNotNil(syncDate, "Failed to get a last successful sync date"); + NSDate* nowDate = [NSDate dateWithTimeIntervalSinceNow:0]; + NSTimeInterval timeIntervalSinceSyncDate = [nowDate timeIntervalSinceDate:syncDate]; + XCTAssertTrue(timeIntervalSinceSyncDate >= 0.0 && timeIntervalSinceSyncDate <= 15.0, "Last sync date does not look like a reasonable one"); +} + +- (void)testExtraValuesToUploadToServer +{ + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + 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]; + + NSDictionary* extraValues = [[CKKSAnalyticsLogger logger] extraValuesToUploadToServer]; + XCTAssertTrue([extraValues[@"keychain-TLKs"] boolValue]); + XCTAssertTrue([extraValues[@"keychain-inSyncA"] boolValue]); + XCTAssertTrue([extraValues[@"keychain-inSyncC"] boolValue]); + XCTAssertTrue([extraValues[@"keychain-IQNOE"] boolValue]); + XCTAssertTrue([extraValues[@"keychain-OQNOE"] boolValue]); + XCTAssertTrue([extraValues[@"keychain-inSync"] boolValue]); +} + +- (void)testNilEventDoesNotCrashTheSystem +{ + CKKSAnalyticsLogger* logger = [CKKSAnalyticsLogger logger]; + [logger logSuccessForEventNamed:nil]; + + NSData* json = nil; + NSError* error = nil; + XCTAssertNoThrow(json = [logger getLoggingJSONWithError:&error]); + XCTAssertNotNil(json, @"Failed to get JSON after logging nil event"); + XCTAssertNil(error, @"Got error when grabbing JSON after logging nil event: %@", error); +} + +- (void)testRaceToCreateLoggers +{ + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + for (NSInteger i = 0; i < 5; i++) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + CKKSAnalyticsLogger* logger = [CKKSAnalyticsLogger logger]; + [logger logSuccessForEvent:(CKKSAnalyticsFailableEvent*)@"test_event" inView:self.keychainView]; + dispatch_semaphore_signal(semaphore); + }); + } + + for (NSInteger i = 0; i < 5; i++) { + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + } +} + +- (void)testSysdiagnoseDump +{ + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + 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]; + + NSError* error = nil; + NSString* sysdiagnose = [[CKKSAnalyticsLogger logger] getSysdiagnoseDumpWithError:&error]; + XCTAssertNil(error, @"encountered an error grabbing CKKS analytics sysdiagnose: %@", error); + XCTAssertTrue(sysdiagnose.length > 0, @"failed to get a sysdiagnose from CKKS analytics"); +} + +@end diff --git a/keychain/ckks/tests/CKKSManifestTests.m b/keychain/ckks/tests/CKKSManifestTests.m new file mode 100644 index 00000000..fb0aa2e5 --- /dev/null +++ b/keychain/ckks/tests/CKKSManifestTests.m @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import "CKKSTests.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" +#import "keychain/ckks/CKKSManifest.h" +#import "keychain/ckks/CKKSMirrorEntry.h" +#import "keychain/ckks/CKKSViewManager.h" +#import "keychain/ckks/CKKSCurrentItemPointer.h" +#import +#include +#import +#import +#import +#import + +@interface CKKSManifestTests : CloudKitKeychainSyncingTestsBase { + BOOL _manifestIsSetup; + CKKSEgoManifest* _egoManifest; + id _manifestMock; + id _fakeSigner1Mock; +} + +@end + +@implementation CKKSManifestTests + +- (NSArray*)mirrorItemsForExistingItems +{ + NSArray* records = [self.keychainZone.currentDatabase.allValues filteredArrayUsingPredicate: [NSPredicate predicateWithFormat:@"self.recordType like %@", SecCKRecordItemType]]; + NSMutableArray* items = [[NSMutableArray alloc] init]; + __weak __typeof(self) weakSelf = self; + __block NSError* error = nil; + [self.keychainView dispatchSync:^bool(void) { + 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); + XCTAssertNotNil(mirrorEntry, @"failed to generate mirror entry"); + if (mirrorEntry) { + [items addObject:mirrorEntry.item]; + } + } + + return YES; + }]; + + return items; +} + +- (void)setUp +{ + // Lie to our superclass about how the world is + (void)[CKKSManifest shouldSyncManifests]; // initialize. + SecCKKSSetSyncManifests(false); + SecCKKSSetEnforceManifests(false); + + [super setUp]; + + // Always sync manifests, and never enforce them + SecCKKSSetSyncManifests(true); + SecCKKSSetEnforceManifests(false); + + XCTAssertTrue([CKKSManifest shouldSyncManifests], "Manifests syncing is enabled"); + XCTAssertFalse([CKKSManifest shouldEnforceManifests], "Manifests enforcement is disabled"); + + NSError* error = nil; + + [CKKSManifestInjectionPointHelper setIgnoreChanges:NO]; + + // Test starts with keys in CloudKit (so we can create items later) + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + [self addGenericPassword:@"data" account:@"first"]; + [self addGenericPassword:@"data" account:@"second"]; + [self addGenericPassword:@"data" account:@"third"]; + [self addGenericPassword:@"data" account:@"fourth"]; + NSUInteger passwordCount = 4u; + + [self checkGenericPassword:@"data" account:@"first"]; + [self checkGenericPassword:@"data" account:@"second"]; + [self checkGenericPassword:@"data" account:@"third"]; + [self checkGenericPassword:@"data" account:@"fourth"]; + + [self expectCKModifyItemRecords:passwordCount currentKeyPointerRecords:1 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + // Wait for uploads to happen + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForCKModifications]; + XCTAssertEqual(self.keychainZone.currentDatabase.count, SYSTEM_DB_RECORD_COUNT + passwordCount, "Have 6+passwordCount objects in cloudkit"); + + NSArray* items = [self mirrorItemsForExistingItems]; + _egoManifest = [CKKSEgoManifest newManifestForZone:self.keychainZoneID.zoneName withItems:items peerManifestIDs:@[] currentItems:@{} error:&error]; + XCTAssertNil(error, @"no error encountered generating ego manifest"); + XCTAssertNotNil(_egoManifest, @"generated ego manifest"); +} + +- (void)tearDown { + _egoManifest = nil; + [super tearDown]; +} + +- (void)testSaveEgoManifest +{ + if (![CKKSManifest shouldSyncManifests]) { + return; + } + + NSError* error; + [_egoManifest saveToDatabase:&error]; + XCTAssertNil(error, @"error encountered attempting to save ego manifest: %@", error); +} + +- (void)testManifestValidatesItems +{ + if (![CKKSManifest shouldSyncManifests]) { + return; + } + + NSError* error = nil; + for (CKKSItem* mirrorItem in [self mirrorItemsForExistingItems]) { + XCTAssertTrue([_egoManifest validateItem:mirrorItem withError:&error], @"failed to validate item against manifest"); + XCTAssertNil(error, @"error generated attempting to validate item against manifest: %@", error); + } +} + +- (void)disable32852700testManifestDoesNotValidateUnknownItems +{ + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + NSArray* knownItems = [self mirrorItemsForExistingItems]; + [self addGenericPassword:@"data" account:@"unknown_account"]; + [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID]; + OCMVerifyAllWithDelay(self.mockDatabase, 4); + [self waitForCKModifications]; + + NSArray* newItems = [self mirrorItemsForExistingItems]; + CKKSItem* unknownItem = nil; + for (CKKSItem* item in newItems) { + BOOL found = NO; + for (CKKSItem* knownItem in knownItems) { + if ([knownItem.CKRecordName isEqualToString:item.CKRecordName]) { + found = YES; + break; + } + } + + if (!found) { + unknownItem = item; + break; + } + } + + NSError* error = nil; + XCTAssertNotNil(_egoManifest, @"have an ego manifest"); + XCTAssertFalse([_egoManifest validateItem:unknownItem withError:&error], @"erroneously validated an unknown item against the manifest"); + XCTAssertNotNil(error, @"failed to generate error when trying to validate an unknown item against the manifest"); +} + +- (void)testManifestValidatesCurrentItems +{ + NSError* error = nil; + CKKSItem* item = [[self mirrorItemsForExistingItems] firstObject]; + [_egoManifest setCurrentItemUUID:item.uuid forIdentifier:@"testCurrentItemIdentifier"]; + CKKSCurrentItemPointer* currentItemPointer = [[CKKSCurrentItemPointer alloc] initForIdentifier:@"testCurrentItemIdentifier" currentItemUUID:item.uuid state:SecCKKSProcessedStateLocal zoneID:self.keychainZoneID encodedCKRecord:nil]; + XCTAssertTrue([_egoManifest validateCurrentItem:currentItemPointer withError:&error], @"failed to validate current item against manifest"); + XCTAssertNil(error, @"error encountered validating current item: %@", error); +} + +- (void)testManifestDoesNotValidateUnknownCurrentItems +{ + NSError* error = nil; + CKKSItem* item = [[self mirrorItemsForExistingItems] firstObject]; + CKKSCurrentItemPointer* currentItemPointer = [[CKKSCurrentItemPointer alloc] initForIdentifier:@"testCurrentItemIdentifier" currentItemUUID:item.uuid state:SecCKKSProcessedStateLocal zoneID:self.keychainZoneID encodedCKRecord:nil]; + XCTAssertFalse([_egoManifest validateCurrentItem:currentItemPointer withError:&error], @"erroneously validated an uunknown current item against the manifest"); + XCTAssertNotNil(error, @"failed to generate error when trying to validate an unknown item against the manifest %@", error); +} + +- (void)testEgoManifestValidates +{ + if (![CKKSManifest shouldSyncManifests]) { + return; + } + + NSError* error = nil; + XCTAssertTrue([_egoManifest validateWithError:&error], @"failed to validate our own ego manifest"); + XCTAssertNil(error, @"error generated attempting to validate ego manifest: %@", error); +} + +- (void)testEgoManifestCreatedOnUpload +{ + if (![CKKSManifest shouldSyncManifests]) { + return; + } + + CKKSEgoManifest* manifest = [CKKSEgoManifest tryCurrentEgoManifestForZone:self.keychainZoneID.zoneName]; + XCTAssertNotNil(manifest, @"created some items, but we don't have a current manifest"); +} + +- (void)disable32852700testGenerationCountIncreaseOnChanges +{ + if (![CKKSManifest shouldSyncManifests]) { + return; + } + + NSInteger initialManifestGenerationCount = [[CKKSEgoManifest tryCurrentEgoManifestForZone:self.keychainZoneID.zoneName] generationCount]; + + [self addGenericPassword:@"data" account:@"GenerationCountIncrease"]; + [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID]; + OCMVerifyAllWithDelay(self.mockDatabase, 4); + [self waitForCKModifications]; + + NSInteger postUpdateGenerationCount = [[CKKSEgoManifest tryCurrentEgoManifestForZone:self.keychainZoneID.zoneName] generationCount]; + XCTAssertGreaterThan(postUpdateGenerationCount, initialManifestGenerationCount, @"the manifest after the update does not have a larger generation count as expected"); +} + +- (NSDictionary*)receiveOneItemInManifest:(BOOL)inManifest +{ + if (!inManifest) { + [CKKSManifestInjectionPointHelper setIgnoreChanges:YES]; + } + + NSError* error = nil; + + NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccount : @"account-delete-me", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitOne, + }; + + CFTypeRef item = NULL; + XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not yet exist"); + + CKRecord* ckr = [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"]; + + SFECKeyPair* keyPair = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; + CKKSEgoManifest* manifest = [CKKSEgoManifest newFakeManifestForZone:self.keychainZoneID.zoneName withItemRecords:@[ckr] currentItems:@{} signerID:@"FakeSigner-1" keyPair:keyPair error:&error]; + [manifest saveToDatabase:&error]; + XCTAssertNil(error, @"error encountered generating fake manifest: %@", error); + XCTAssertNotNil(manifest, @"failed to generate a fake manifest"); + + [self.keychainZone addToZone:ckr]; + for (CKRecord* record in [manifest allCKRecordsWithZoneID:self.keychainZoneID]) { + [self.keychainZone addToZone:record]; + } + + // Trigger a notification (with hilariously fake data) + [self.keychainView notifyZoneChange:nil]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + return query; +} + +- (void)testReceiveManifest +{ + if (![CKKSManifest shouldSyncManifests]) { + return; + } + + NSError* error = nil; + + NSDictionary* itemQuery = [self receiveOneItemInManifest:YES]; + CFTypeRef item = NULL; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef)itemQuery, &item), "item should exist now"); + + CKKSManifest* fetchedManifest = [CKKSManifest manifestForZone:self.keychainZoneID.zoneName peerID:@"FakeSigner-1" error:&error]; + XCTAssertNil(error, @"error encountered fetching expected manifest from database: %@", error); + XCTAssertNotNil(fetchedManifest, @"failed to fetch manifest expected in database"); + + CKKSMirrorEntry* fetchedEntry = [CKKSMirrorEntry tryFromDatabase:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.keychainZoneID error:&error]; + XCTAssertNil(error, @"error encountered fetching expected item from database: %@", error); + XCTAssertNotNil(fetchedEntry, @"failed to fetch item expected in database"); + + XCTAssertTrue([fetchedManifest validateWithError:&error], @"failed to validate fetched manifest with error: %@", error); + XCTAssertTrue([fetchedManifest validateItem:fetchedEntry.item withError:&error], @"failed to validate item (%@) against manifest with error: %@", fetchedEntry, error); +} + +- (void)testUnauthorizedItemRejected +{ + if (![CKKSManifest shouldSyncManifests] || ![CKKSManifest shouldEnforceManifests]) { + return; + } + + NSDictionary* itemQuery = [self receiveOneItemInManifest:NO]; + CFTypeRef item = NULL; + XCTAssertNotEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef)itemQuery, &item), "item should have been rejected"); +} + +- (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]); +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m b/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m new file mode 100644 index 00000000..eff091fc --- /dev/null +++ b/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m @@ -0,0 +1,249 @@ +/* + * 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@ + */ + +#include +#import +#import "keychain/ckks/CKKSNearFutureScheduler.h" + +@interface CKKSNearFutureSchedulerTests : XCTestCase + +@end + +@implementation CKKSNearFutureSchedulerTests + +- (void)setUp { + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testOneShot { + XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"]; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay:50*NSEC_PER_MSEC keepProcessAlive:true block:^{ + [expectation fulfill]; + }]; + + [scheduler trigger]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)testOneShotDelay { + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.inverted = YES; + + XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"]; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [toofastexpectation fulfill]; + [expectation fulfill]; + }]; + + [scheduler trigger]; + + // Make sure it waits at least 0.1 seconds + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + + // But finishes within 1.1s (total) + [self waitForExpectations: @[expectation] timeout:1]; +} + +- (void)testOneShotManyTrigger { + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.inverted = YES; + + XCTestExpectation *expectation = [self expectationWithDescription:@"FutureScheduler fired"]; + expectation.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 200*NSEC_PER_MSEC keepProcessAlive:true block:^{ + [toofastexpectation fulfill]; + [expectation fulfill]; + }]; + + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + + // Make sure it waits at least 0.1 seconds + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + + // But finishes within .6s (total) + [self waitForExpectations: @[expectation] timeout:0.5]; + + // Ensure we don't get called again in the next 0.3 s + XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"]; + waitmore.inverted = YES; + [self waitForExpectations: @[waitmore] timeout: 0.3]; +} + + +- (void)testMultiShot { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [first fulfill]; + [second fulfill]; + }]; + + [scheduler trigger]; + + [self waitForExpectations: @[first] timeout:0.2]; + + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + + [self waitForExpectations: @[second] timeout:0.2]; + + XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"]; + waitmore.inverted = YES; + [self waitForExpectations: @[waitmore] timeout: 0.2]; +} + +- (void)testMultiShotDelays { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"]; + longdelay.inverted = YES; + longdelay.expectedFulfillmentCount = 2; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" initialDelay: 50*NSEC_PER_MSEC continuingDelay:300*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [first fulfill]; + [longdelay fulfill]; + [second fulfill]; + }]; + + [scheduler trigger]; + + [self waitForExpectations: @[first] timeout:0.2]; + + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + + // longdelay should NOT be fulfilled twice in the first 0.3 seconds + [self waitForExpectations: @[longdelay] timeout:0.2]; + + // But second should be fulfilled in the first 0.8 seconds + [self waitForExpectations: @[second] timeout:0.5]; + + XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"]; + waitmore.inverted = YES; + [self waitForExpectations: @[waitmore] timeout: 0.2]; +} + +- (void)testCancel { + XCTestExpectation *cancelexpectation = [self expectationWithDescription:@"FutureScheduler fired (after cancel)"]; + cancelexpectation.inverted = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 100*NSEC_PER_MSEC keepProcessAlive:true block:^{ + [cancelexpectation fulfill]; + }]; + + [scheduler trigger]; + [scheduler cancel]; + + // Make sure it does not fire in 0.5 s + [self waitForExpectations: @[cancelexpectation] timeout:0.2]; +} + +- (void)testDelayedNoShot { + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.inverted = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [toofastexpectation fulfill]; + }]; + + // Tell the scheduler to wait, but don't trigger it. It shouldn't fire. + [scheduler waitUntil: 50*NSEC_PER_MSEC]; + + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; +} + +- (void)testDelayedOneShot { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.inverted = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [first fulfill]; + [toofastexpectation fulfill]; + }]; + + [scheduler waitUntil: 150*NSEC_PER_MSEC]; + [scheduler trigger]; + + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + [self waitForExpectations: @[first] timeout:0.2]; +} + +- (void)testDelayedMultiShot { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *toofastexpectation = [self expectationWithDescription:@"FutureScheduler fired (too soon)"]; + toofastexpectation.expectedFulfillmentCount = 2; + toofastexpectation.inverted = YES; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay: 10*NSEC_PER_MSEC keepProcessAlive:false block:^{ + [first fulfill]; + [second fulfill]; + [toofastexpectation fulfill]; + }]; + + [scheduler trigger]; + [self waitForExpectations: @[first] timeout:0.2]; + + [scheduler waitUntil: 150*NSEC_PER_MSEC]; + [scheduler trigger]; + + [self waitForExpectations: @[toofastexpectation] timeout:0.1]; + [self waitForExpectations: @[second] timeout:0.3]; +} + +@end diff --git a/keychain/ckks/tests/CKKSOperationTests.m b/keychain/ckks/tests/CKKSOperationTests.m new file mode 100644 index 00000000..1eab4c61 --- /dev/null +++ b/keychain/ckks/tests/CKKSOperationTests.m @@ -0,0 +1,414 @@ +/* + * 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 + +#import "keychain/ckks/CKKSGroupOperation.h" + +// Helper Operations +@interface CKKSResultCancelOperation : CKKSResultOperation +- (instancetype) init; +@end + +@implementation CKKSResultCancelOperation +- (instancetype)init { + if(self = [super init]) { + __weak __typeof(self) weakSelf = self; + [self addExecutionBlock:^{ + [weakSelf cancel]; + }]; + } + return self; +} +@end + + + +@interface CKKSResultErrorOperation : CKKSResultOperation +- (instancetype) init; +@end + +@implementation CKKSResultErrorOperation +- (instancetype)init { + if(self = [super init]) { + __weak __typeof(self) weakSelf = self; + [self addExecutionBlock:^{ + weakSelf.error = [NSError errorWithDomain:@"test domain" code:5 userInfo:nil]; + }]; + } + return self; +} +@end + + +@interface CKKSOperationTests : XCTestCase +@property NSOperationQueue* queue; +@end + +// Remaining tests to write: +// TODO: subclass of CKKSResultOperation implementing main() respects addSuccessDependency without any special code +// TODO: chain of automatic dependencies +// TODO: test showing that CKKSGroupOperations don't start if they success-depend on a failed CKKSResultOperation + +@implementation CKKSOperationTests + +- (void)setUp { + [super setUp]; + + self.queue = [[NSOperationQueue alloc] init]; +} + +- (void)tearDown { + [self.queue cancelAllOperations]; + self.queue = nil; + + [super tearDown]; +} + +- (void)testResultOperation { + CKKSResultOperation* op = [[CKKSResultOperation alloc] init]; + __weak __typeof(op) weakOp = op; + + [op addExecutionBlock:^{ + weakOp.error = [NSError errorWithDomain:@"test domain" code:0 userInfo:nil]; + }]; + + [self.queue addOperation: op]; + + [op waitUntilFinished]; + + XCTAssertNotNil(op.error, "errors can persist"); +} + +- (void)testResultSuccessDependency { + __block bool firstRun = false; + __block bool secondRun = false; + + CKKSResultOperation* first = [[CKKSResultOperation alloc] init]; + [first addExecutionBlock:^{ + firstRun = true; + }]; + + CKKSResultOperation* second = [[CKKSResultOperation alloc] init]; + [second addExecutionBlock:^{ + XCTAssertTrue(firstRun); + secondRun = true; + }]; + [second addSuccessDependency: first]; + + [self.queue addOperation: second]; + [self.queue addOperation: first]; + + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertTrue(firstRun); + XCTAssertTrue(secondRun); + + XCTAssertTrue(first.finished, "First operation finished"); + XCTAssertFalse(first.cancelled, "First operation not cancelled"); + XCTAssertTrue(second.finished, "Second operation finished"); + XCTAssertFalse(second.cancelled, "Second operation not cancelled"); +} + +- (void)testResultSuccessDependencyCancel { + CKKSResultCancelOperation* first = [[CKKSResultCancelOperation alloc] init]; + + CKKSResultOperation* second = [[CKKSResultOperation alloc] init]; + [second addExecutionBlock:^{ + XCTFail("Second operation should never run"); + }]; + [second addSuccessDependency: first]; + + [self.queue addOperation: second]; + [self.queue addOperation: first]; + + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertTrue(first.finished, "First operation finished"); + XCTAssertTrue(first.cancelled, "First operation is canceled (as requested)"); + + XCTAssertTrue(second.cancelled, "Second operation is canceled"); + XCTAssertTrue(second.finished, "Second operation finished"); + XCTAssertNotNil(second.error, "Error is generated when CKKSResultOperation is cancelled"); + XCTAssertEqual(second.error.code, CKKSResultSubresultCancelled, "Error code is CKKSResultSubresultCancelled"); +} + +- (void)testResultSuccessDependencyError { + CKKSResultErrorOperation* first = [[CKKSResultErrorOperation alloc] init]; + + CKKSResultOperation* second = [[CKKSResultOperation alloc] init]; + [second addExecutionBlock:^{ + XCTFail("Second operation should never run"); + }]; + [second addSuccessDependency: first]; + + [self.queue addOperation: second]; + [self.queue addOperation: first]; + + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertTrue(first.finished, "First operation finished"); + XCTAssertFalse(first.cancelled, "First operation is not canceled"); + XCTAssertNotNil(first.error, "First operation has an error"); + + XCTAssertTrue(second.cancelled, "Second operation is canceled"); + XCTAssertTrue(second.finished, "Second operation finished"); + XCTAssertNotNil(second.error, "Error is generated when dependent CKKSResultOperation has an error"); + XCTAssertEqual(second.error.code, CKKSResultSubresultError, "Error code is CKKSResultSubresultError"); + + XCTAssertNotNil(second.error.userInfo[NSUnderlyingErrorKey], "Passed up the error from the first operation"); + XCTAssertEqual([second.error.userInfo[NSUnderlyingErrorKey] code], 5, "Passed up the right error from the first operation"); +} + +- (void)testResultTimeout { + __block bool firstRun = false; + __block bool secondRun = false; + + CKKSResultOperation* first = [[CKKSResultOperation alloc] init]; + [first addExecutionBlock:^{ + firstRun = true; + }]; + + CKKSResultOperation* second = [[CKKSResultOperation alloc] init]; + [second addExecutionBlock:^{ + XCTAssertTrue(firstRun); + secondRun = true; + }]; + [second addDependency: first]; + + [self.queue addOperation: [second timeout:(50)* NSEC_PER_MSEC]]; + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertFalse(firstRun); + XCTAssertFalse(secondRun); + + XCTAssertFalse(first.finished, "First operation not finished"); + XCTAssertFalse(first.cancelled, "First operation not cancelled"); + XCTAssertTrue(second.finished, "Second operation finished"); + XCTAssertTrue(second.cancelled, "Second operation cancelled"); + XCTAssertNotNil(second.error, "Second operation has an error"); + XCTAssertEqual(second.error.code, CKKSResultTimedOut, "Second operation error is good"); +} + +- (void)testResultNoTimeout { + __block bool firstRun = false; + __block bool secondRun = false; + + CKKSResultOperation* first = [[CKKSResultOperation alloc] init]; + [first addExecutionBlock:^{ + firstRun = true; + }]; + + CKKSResultOperation* second = [[CKKSResultOperation alloc] init]; + [second addExecutionBlock:^{ + XCTAssertTrue(firstRun); + secondRun = true; + }]; + [second addDependency: first]; + + [self.queue addOperation: [second timeout:(100)* NSEC_PER_MSEC]]; + [self.queue addOperation: first]; + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertTrue(firstRun); + XCTAssertTrue(secondRun); + + XCTAssertTrue(first.finished, "First operation finished"); + XCTAssertFalse(first.cancelled, "First operation not cancelled"); + XCTAssertTrue(second.finished, "Second operation finished"); + XCTAssertFalse(second.cancelled, "Second operation not cancelled"); + XCTAssertNil(second.error, "Second operation has no error"); +} + +- (void)testResultFinishDate +{ + CKKSResultOperation* operation = [[CKKSResultOperation alloc] init]; + XCTAssertNil(operation.finishDate, "Result operation does not have a finish date before it is run"); + + [operation addExecutionBlock:^{ + NSLog(@"test execution block"); + }]; + + [self.queue addOperation:operation]; + [self.queue waitUntilAllOperationsAreFinished]; + sleep(0.1); // wait for the completion block to have time to fire + XCTAssertNotNil(operation.finishDate, "Result operation has a finish date after everything is done"); + NSTimeInterval timeIntervalSinceFinishDate = [[NSDate date] timeIntervalSinceDate:operation.finishDate]; + XCTAssertTrue(timeIntervalSinceFinishDate >= 0.0 && timeIntervalSinceFinishDate <= 10.0, "Result operation finish datelooks reasonable"); +} + +- (void)testGroupOperation { + CKKSGroupOperation* group = [[CKKSGroupOperation alloc] init]; + + CKKSResultOperation* op1 = [[CKKSResultOperation alloc] init]; + [group runBeforeGroupFinished: op1]; + + CKKSResultOperation* op2 = [[CKKSResultOperation alloc] init]; + [group runBeforeGroupFinished: op2]; + + [self.queue addOperation: group]; + + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertEqual(op1.finished, YES, "First operation finished"); + XCTAssertEqual(op2.finished, YES, "Second operation finished"); + XCTAssertEqual(group.finished, YES, "Group operation finished"); + + XCTAssertEqual(op1.cancelled, NO, "First operation not cancelled"); + XCTAssertEqual(op2.cancelled, NO, "Second operation cancelled"); + XCTAssertEqual(group.cancelled, NO, "Group operation not cancelled"); + + XCTAssertNil(op1.error, "First operation: no error"); + XCTAssertNil(op2.error, "Second operation: no error"); + XCTAssertNil(group.error, "Group operation: no error"); +} + +- (void)testGroupOperationCancel { + CKKSGroupOperation* group = [[CKKSGroupOperation alloc] init]; + + CKKSResultOperation* op1 = [[CKKSResultOperation alloc] init]; + [group runBeforeGroupFinished: op1]; + + CKKSResultCancelOperation* op2 = [[CKKSResultCancelOperation alloc] init]; + [group runBeforeGroupFinished: op2]; + + [self.queue addOperation: group]; + + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertEqual(op1.finished, YES, "First operation finished"); + XCTAssertEqual(op2.finished, YES, "Second operation finished"); + XCTAssertEqual(group.finished, YES, "Group operation finished"); + + XCTAssertEqual(op1.cancelled, NO, "First operation not cancelled"); + XCTAssertEqual(op2.cancelled, YES, "Second operation not cancelled"); + XCTAssertEqual(group.cancelled, NO, "Group operation not cancelled"); + + XCTAssertNil(op1.error, "First operation: no error"); + XCTAssertNil(op2.error, "Second operation: no error"); + XCTAssertNotNil(group.error, "Group operation: no error"); + XCTAssertEqual(group.error.code, CKKSResultSubresultCancelled, "Error code is CKKSResultSubresultCancelled"); +} + +- (void)testGroupOperationTimeout { + CKKSGroupOperation* group = [[CKKSGroupOperation alloc] init]; + + __block bool run1 = false; + CKKSResultOperation* op1 = [CKKSResultOperation operationWithBlock: ^{ + run1 = true; + }]; + [group runBeforeGroupFinished: op1]; + + __block bool run2 = false; + CKKSResultOperation* op2 = [CKKSResultOperation operationWithBlock: ^{ + run2 = true; + }]; + [group runBeforeGroupFinished: op2]; + + CKKSResultOperation* never = [[CKKSResultOperation alloc] init]; + [group addDependency: never]; + + [group timeout:50*NSEC_PER_MSEC]; + [self.queue addOperation: group]; + + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertEqual(op1.finished, YES, "First operation finished"); + XCTAssertEqual(op2.finished, YES, "Second operation finished"); + XCTAssertEqual(group.finished, YES, "Group operation finished"); + + XCTAssertEqual(op1.cancelled, YES, "First operation cancelled"); + XCTAssertEqual(op2.cancelled, YES, "Second operation cancelled"); + XCTAssertEqual(group.cancelled, YES, "Group operation cancelled"); + + XCTAssertFalse(run1, "First operation did not run"); + XCTAssertFalse(run2, "Second operation did not run"); + + XCTAssertNil(op1.error, "First operation: no error"); + XCTAssertNil(op2.error, "Second operation: no error"); + XCTAssertNotNil(group.error, "Group operation: error"); + XCTAssertEqual(group.error.code, CKKSResultTimedOut, "Error code is CKKSResultTimedOut"); +} + +- (void)testGroupOperationError { + CKKSGroupOperation* group = [[CKKSGroupOperation alloc] init]; + + CKKSResultOperation* op1 = [[CKKSResultOperation alloc] init]; + [group runBeforeGroupFinished: op1]; + + CKKSResultErrorOperation* op2 = [[CKKSResultErrorOperation alloc] init]; + [group runBeforeGroupFinished: op2]; + + [self.queue addOperation: group]; + + [self.queue waitUntilAllOperationsAreFinished]; + + XCTAssertEqual(op1.finished, YES, "First operation finished"); + XCTAssertEqual(op2.finished, YES, "Second operation finished"); + XCTAssertEqual(group.finished, YES, "Group operation finished"); + + XCTAssertEqual(op1.cancelled, NO, "First operation not cancelled"); + XCTAssertEqual(op2.cancelled, NO, "Second operation cancelled"); + XCTAssertEqual(group.cancelled, NO, "Group operation not cancelled"); + + XCTAssertNil(op1.error, "First operation: no error"); + XCTAssertNotNil(op2.error, "Second operation: error (as expected)"); + XCTAssertEqual(op2.error.code, 5, "Rght error from the erroring operation"); + + XCTAssertNotNil(group.error, "Error is generated when dependent CKKSResultOperation has an error"); + XCTAssertEqual(group.error.code, CKKSResultSubresultError, "Error code is CKKSResultSubresultError"); + XCTAssertNotNil(group.error.userInfo[NSUnderlyingErrorKey], "Passed up the error from the first operation"); + XCTAssertEqual([group.error.userInfo[NSUnderlyingErrorKey] code], 5, "Passed up the right error from the first operation"); +} + +- (void)testGroupOperationPending { + CKKSGroupOperation* group = [[CKKSGroupOperation alloc] init]; + + CKKSResultOperation* op1 = [[CKKSResultOperation alloc] init]; + [group runBeforeGroupFinished: op1]; + + CKKSResultOperation* op2 = [[CKKSResultOperation alloc] init]; + [group addDependency: op2]; + + [self.queue addOperation: group]; + + XCTAssertTrue([group isPending], "group operation hasn't started yet"); + + [self.queue addOperation: op2]; + [self.queue waitUntilAllOperationsAreFinished]; + XCTAssertFalse([group isPending], "group operation has started"); + + XCTAssertEqual(op1.finished, YES, "First operation finished"); + XCTAssertEqual(op2.finished, YES, "Second operation finished"); + XCTAssertEqual(group.finished, YES, "Group operation finished"); + + XCTAssertEqual(op1.cancelled, NO, "First operation not cancelled"); + XCTAssertEqual(op2.cancelled, NO, "Second operation cancelled"); + XCTAssertEqual(group.cancelled, NO, "Group operation not cancelled"); + + XCTAssertNil(op1.error, "First operation: no error"); + XCTAssertNil(op2.error, "Second operation: no error"); + XCTAssertNil(group.error, "Group operation: no error"); +} + +@end diff --git a/keychain/ckks/tests/CKKSRateLimiterTests.m b/keychain/ckks/tests/CKKSRateLimiterTests.m new file mode 100644 index 00000000..acb9e697 --- /dev/null +++ b/keychain/ckks/tests/CKKSRateLimiterTests.m @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSRateLimiter.h" + +@interface CKKSRateLimiterTests : XCTestCase +- (CKKSOutgoingQueueEntry *)oqe; +@property CKKSRateLimiter *rl; +@property NSDictionary *conf; +@property CKKSOutgoingQueueEntry *oqe; +@property NSDate *date; +@property NSDate *compare; +@end + +@implementation CKKSRateLimiterTests + +- (void)setUp { + [super setUp]; + self.rl = [CKKSRateLimiter new]; + self.conf = [self.rl config]; + self.oqe = [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem: + [[CKKSItem alloc] initWithUUID:@"123" + parentKeyUUID:@"" + zoneID:[[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName] + encItem:nil + wrappedkey:nil + generationCount:1 + encver:0] + action:@"" + state:@"" + waitUntil:nil + accessGroup:@"defaultgroup"]; +} + +- (void)tearDown { + [super tearDown]; + self.rl = nil; + self.conf = nil; + self.oqe = nil; +} + +- (int) get:(NSDictionary *)dict key:(NSString *)key { + id obj = dict[key]; + XCTAssertNotNil(obj, "Key %@ is in the dictionary", key); + XCTAssert([obj isKindOfClass:[NSNumber class]], "Value for %@ is an NSNumber (%@)", key, [obj class]); + XCTAssertGreaterThan([obj intValue], 0, "Value for %@ is at least non-zero", key); + return [obj intValue]; +} + +- (void) testConfig { + [self get:[self.rl config] key:@"rateAll"]; + [self get:[self.rl config] key:@"rateGroup"]; + [self get:[self.rl config] key:@"rateUUID"]; + [self get:[self.rl config] key:@"capacityAll"]; + [self get:[self.rl config] key:@"capacityGroup"]; + [self get:[self.rl config] key:@"capacityUUID"]; + [self get:[self.rl config] key:@"trimSize"]; + [self get:[self.rl config] key:@"trimTime"]; +} + +- (void) testBasics { + NSDate *date = [NSDate date]; + NSDate *limit = nil; + + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "judge single item"); + XCTAssertNil(limit, "NSDate argument nil for zero result"); + XCTAssertEqual([self.rl stateSize], 3UL, "RL contains three nodes after single judgment"); + [self.rl reset]; + XCTAssertEqual([self.rl stateSize], 0UL, "RL is empty after reset"); +} + +- (void)testAll { + NSDate *date = [NSDate date]; + NSDate *limit = nil; + int capacityAll = [self get:[self.rl config] key:@"capacityAll"]; + int rateAll = [self get:[self.rl config] key:@"rateAll"]; + + for (int idx = 0; idx < capacityAll; ++idx) { + self.oqe.accessgroup = [NSString stringWithFormat:@"%d", idx]; + self.oqe.uuid = [NSString stringWithFormat:@"%d", idx]; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Repeat (%d) All succeeds, limit %d", idx, capacityAll); + XCTAssertNil(limit, "Time nil while under All limit"); + } + + self.oqe.accessgroup = @"Ga"; + self.oqe.uuid = @"Ua"; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 1, "Repeat All implies congestion"); + int delta = [limit timeIntervalSinceDate:date]; + XCTAssert(delta > 0 && delta <= rateAll, "send-OK at most one All token into the future"); + self.oqe.accessgroup = @"Gb"; + self.oqe.uuid = @"Ub"; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 1, "Repeat All, still congested"); + delta = [limit timeIntervalSinceDate:date]; + XCTAssert(delta > rateAll && delta <= (2 * rateAll), "send-OK between one and two All tokens into the future"); + + self.oqe.accessgroup = @"Gc"; + self.oqe.uuid = @"Uc"; + date = [limit dateByAddingTimeInterval:rateAll]; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Repeat All is fine after waiting"); + XCTAssertEqual([self.rl stateSize], (unsigned long)(2 * (capacityAll + 3) + 1), "state size is %d", 2 * (capacityAll + 3) + 1); +} + +- (void)testGroup { + NSDate *date = [NSDate date]; + NSDate *limit = nil; + int capacityGroup = [self get:[self.rl config] key:@"capacityGroup"]; + int rateGroup = [self get:[self.rl config] key:@"rateGroup"]; + + for (int idx = 0; idx < capacityGroup; ++idx) { + self.oqe.uuid = [NSString stringWithFormat:@"%d",idx]; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Repeat (%d) Group succeeds, limit %d", idx, capacityGroup); + XCTAssertNil(limit, "sendTime nil while under Group limit"); + } + + self.oqe.uuid = @"a"; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 2, "Repeat Group entry not good"); + int delta = [limit timeIntervalSinceDate:date]; + XCTAssert(delta > 0 && delta <= rateGroup, "send-OK at most one Group token into the future"); + + self.oqe.uuid = @"b"; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 3, "Repeat Group entry still not good"); + delta = [limit timeIntervalSinceDate:date]; + XCTAssert(delta > rateGroup && delta <= (2 * rateGroup), "send-OK between one and two Group tokens into the future"); + self.oqe.uuid = @"c"; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 3, "Repeat Group entry extra bad after not quitting"); + delta = [limit timeIntervalSinceDate:date]; + XCTAssert(delta > (2 * rateGroup) && delta <= (3 * rateGroup), "send-OK between two and three Group tokens into the future"); + + self.oqe.uuid = @"d"; + date = [limit dateByAddingTimeInterval:rateGroup]; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Repeat Group is fine after waiting"); + XCTAssertEqual([self.rl stateSize], (unsigned long)(capacityGroup + 6), "State size is %d", capacityGroup + 6); + +} + +- (void)testUUID { + NSDate *date = [NSDate date]; + NSDate *limit = nil; + int capacityUUID = [self get:[self.rl config] key:@"capacityUUID"]; + int rateUUID = [self get:[self.rl config] key:@"rateUUID"]; + + for (int idx = 0; idx < capacityUUID; ++idx) { + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Repeat (%d) UUID succeeds, limit %d", idx, capacityUUID); + XCTAssertNil(limit, "Time unmodified while under UUID limit"); + } + + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 4, "Repeat UUID over limit is bad behavior"); + int delta = [limit timeIntervalSinceDate:date]; + XCTAssert(delta > 0 && delta <= rateUUID, "Received send-OK at most one UUID token into the future"); + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 4, "Repeat over-limit UUID is bad behavior"); + delta = [limit timeIntervalSinceDate:date]; + XCTAssert(delta > rateUUID && delta <= (2 * rateUUID), "send-OK between one and two UUID tokens into the future"); + + // test UUID success after borrow + date = [limit dateByAddingTimeInterval:rateUUID]; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Repeat UUID is fine after waiting"); + XCTAssertEqual([self.rl stateSize], 3UL, "state size is 3"); + +} + +- (void)testTrimTime { + NSDate *date = [NSDate date]; + NSDate *limit = nil; + int trimTime = [self get:[self.rl config] key:@"trimTime"]; + int capacityAll = [self get:[self.rl config] key:@"capacityAll"]; + + for (int idx = 0; idx < capacityAll; ++idx) { + self.oqe.accessgroup = [NSString stringWithFormat:@"%d", idx]; + self.oqe.uuid = [NSString stringWithFormat:@"%d", idx]; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Repeat (%d) All succeeds, limit %d", idx, capacityAll); + XCTAssertNil(limit, "Time nil while under All limit"); + } + + XCTAssertEqual([self.rl stateSize], (unsigned long)(2 * capacityAll + 1), "state size is %d", 2 * capacityAll + 1); + + date = [date dateByAddingTimeInterval:trimTime + 1]; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Entry addition succeeds after long silence"); + XCTAssertEqual([self.rl stateSize], 3UL, "Trim has wiped out all buckets except from call immediately before"); +} + +- (void)testTrimSize { + NSDate *date = [NSDate date]; + NSDate *limit = nil; + NSDate *compare = [date copy]; + int trimSize = [self get:[self.rl config] key:@"trimSize"]; + int trimTime = [self get:[self.rl config] key:@"trimTime"]; + int rateAll = [self get:[self.rl config] key:@"rateAll"]; + + self.oqe.accessgroup = @"a"; + self.oqe.uuid = @"a"; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 0, "Adding single item, no problem"); + + // Cannot fill state completely due to repeated judgements, it'll trigger overload otherwise + for (int idx = 0; [self.rl stateSize] < (unsigned long)(trimSize - 2); ++idx) { + self.oqe.accessgroup = [NSString stringWithFormat:@"%d", idx]; + self.oqe.uuid = [NSString stringWithFormat:@"%d", idx]; + for (int i = 0; i < rateAll; ++i) { + XCTAssertLessThan([self.rl judge:self.oqe at:date limitTime:&limit], 5, "Adding items and hitting their dates"); + date = [compare copy]; + } + } + + unsigned long statesize = [self.rl stateSize]; + + self.oqe.accessgroup = @"b"; + self.oqe.uuid = @"b"; + XCTAssertLessThan([self.rl judge:self.oqe at:date limitTime:&limit], 5, "Top off state"); + + date = [compare dateByAddingTimeInterval:trimTime]; + + XCTAssertLessThan([self.rl judge:self.oqe at:date limitTime:&limit], 5, "New entry after at least one has expired fits"); + XCTAssertEqual([self.rl stateSize], statesize, "Item 'a' was trimmed and 'b' got added"); +} + +- (void)testOverload { + NSDate *date = [NSDate date]; + NSDate *limit = nil; + int trimSize = [self get:[self.rl config] key:@"trimSize"]; + //int rateAll = [self get:[self.rl config] key:@"rateAll"];; + int overloadDuration = [self get:[self.rl config] key:@"overloadDuration"];; + + for (int idx = 0; idx < (trimSize / 2); ++idx) { + self.oqe.accessgroup = [NSString stringWithFormat:@"%d", idx]; + self.oqe.uuid = [NSString stringWithFormat:@"%d", idx]; + XCTAssertLessThan([self.rl judge:self.oqe at:date limitTime:&limit], 5, "No overload triggered yet ramming data into RL"); + } + + NSDate *preOverload = [limit copy]; + self.oqe.accessgroup = @"a"; + self.oqe.uuid = @"a"; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 5, "Triggered overload"); + NSDate *postOverload = [preOverload dateByAddingTimeInterval:overloadDuration]; + // NSDates are doubles so we add a little rounding error leeway + XCTAssertEqualWithAccuracy(limit.timeIntervalSinceReferenceDate, postOverload.timeIntervalSinceReferenceDate, 1, "Got expected overload duration"); + + unsigned long statesize = [self.rl stateSize]; + + self.oqe.accessgroup = @"b"; + self.oqe.uuid = @"b"; + XCTAssertEqual([self.rl judge:self.oqe at:date limitTime:&limit], 5, "Overload"); + XCTAssertEqual(statesize, [self.rl stateSize], "No items added during overload"); + + XCTAssertEqual([self.rl judge:self.oqe at:limit limitTime:&limit], 0, "Judgment succeeds post-overload"); +} + +- (void)testEncoding { + NSDate* date = [NSDate date]; + NSDate* limit = nil; + [self.rl judge:self.oqe at:date limitTime:&limit]; + + NSMutableData* data = [[NSMutableData alloc] init]; + NSKeyedArchiver* encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data]; + [encoder encodeObject: self.rl forKey:@"unneeded"]; + [encoder finishEncoding]; + XCTAssertNotNil(data, "Still have our data object"); + XCTAssertTrue(data.length > 0u, "Encoder produced some data"); + + NSKeyedUnarchiver* decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData: data]; + decoder.requiresSecureCoding = YES; + CKKSRateLimiter* rl = [decoder decodeObjectOfClass: [CKKSRateLimiter class] forKey:@"unneeded"]; + XCTAssertNotNil(rl, "Decoded data into a CKKSRateLimiter"); + + XCTAssertEqualObjects(self.rl, rl, "RateLimiter objects are equal after encoding/decoding"); +} + +@end + +#endif //OCTAGON diff --git a/keychain/ckks/tests/CKKSSOSTests.m b/keychain/ckks/tests/CKKSSOSTests.m new file mode 100644 index 00000000..a6956929 --- /dev/null +++ b/keychain/ckks/tests/CKKSSOSTests.m @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import +#import +#import +#import + +#include + +#import "keychain/ckks/tests/CloudKitMockXCTest.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSCurrentKeyPointer.h" +#import "keychain/ckks/CKKSItemEncrypter.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSIncomingQueueEntry.h" +#import "keychain/ckks/CKKSSynchronizeOperation.h" +#import "keychain/ckks/CKKSViewManager.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" +#import "keychain/ckks/CKKSManifest.h" + +#import "keychain/ckks/tests/MockCloudKit.h" + +#include +#include +#include +#include +#include +#include +#include +@interface CloudKitKeychainSyncingSOSIntegrationTests : CloudKitKeychainSyncingMockXCTest + +@property CKRecordZoneID* engramZoneID; +@property CKKSKeychainView* engramView; +@property FakeCKZone* engramZone; +@property (readonly) ZoneKeys* engramZoneKeys; + +@property CKRecordZoneID* manateeZoneID; +@property CKKSKeychainView* manateeView; +@property FakeCKZone* manateeZone; +@property (readonly) ZoneKeys* manateeZoneKeys; + +@property CKRecordZoneID* autoUnlockZoneID; +@property CKKSKeychainView* autoUnlockView; +@property FakeCKZone* autoUnlockZone; +@property (readonly) ZoneKeys* autoUnlockZoneKeys; + +@property CKRecordZoneID* healthZoneID; +@property CKKSKeychainView* healthView; +@property FakeCKZone* healthZone; +@property (readonly) ZoneKeys* healthZoneKeys; + + +@end + +@implementation CloudKitKeychainSyncingSOSIntegrationTests ++ (void)setUp { + SecCKKSEnable(); + SecCKKSResetSyncing(); + [super setUp]; +} + +- (void)setUp { + // No manifests. + (void)[CKKSManifest shouldSyncManifests]; // initialize. + SecCKKSSetSyncManifests(false); + SecCKKSSetEnforceManifests(false); + + [super setUp]; + SecCKKSTestSetDisableSOS(false); + + // Wait for the ViewManager to be brought up + XCTAssertEqual(0, [self.injectedManager.completedSecCKKSInitialize wait:4*NSEC_PER_SEC], "No timeout waiting for SecCKKSInitialize"); + + self.engramZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"Engram" ownerName:CKCurrentUserDefaultName]; + self.engramZone = [[FakeCKZone alloc] initZone: self.engramZoneID]; + self.zones[self.engramZoneID] = self.engramZone; + self.engramView = [[CKKSViewManager manager] findView:@"Engram"]; + XCTAssertNotNil(self.engramView, "CKKSViewManager created the Engram view"); + + self.manateeZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"Manatee" ownerName:CKCurrentUserDefaultName]; + self.manateeZone = [[FakeCKZone alloc] initZone: self.manateeZoneID]; + self.zones[self.manateeZoneID] = self.manateeZone; + self.manateeView = [[CKKSViewManager manager] findView:@"Manatee"]; + XCTAssertNotNil(self.manateeView, "CKKSViewManager created the Manatee view"); + + self.autoUnlockZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"AutoUnlock" ownerName:CKCurrentUserDefaultName]; + self.autoUnlockZone = [[FakeCKZone alloc] initZone: self.autoUnlockZoneID]; + self.zones[self.autoUnlockZoneID] = self.autoUnlockZone; + self.autoUnlockView = [[CKKSViewManager manager] findView:@"AutoUnlock"]; + XCTAssertNotNil(self.autoUnlockView, "CKKSViewManager created the AutoUnlock view"); + + self.healthZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"Health" ownerName:CKCurrentUserDefaultName]; + self.healthZone = [[FakeCKZone alloc] initZone: self.healthZoneID]; + self.zones[self.healthZoneID] = self.healthZone; + self.healthView = [[CKKSViewManager manager] findView:@"Health"]; + XCTAssertNotNil(self.autoUnlockView, "CKKSViewManager created the Health view"); +} + ++ (void)tearDown { + SecCKKSTestSetDisableSOS(true); + [super tearDown]; + SecCKKSResetSyncing(); +} + +- (void)tearDown { + [self.engramView cancelAllOperations]; + [self.engramView waitUntilAllOperationsAreFinished]; + + [self.manateeView cancelAllOperations]; + [self.manateeView waitUntilAllOperationsAreFinished]; + + [self.autoUnlockView cancelAllOperations]; + [self.autoUnlockView waitUntilAllOperationsAreFinished]; + + [self.healthView cancelAllOperations]; + [self.healthView waitUntilAllOperationsAreFinished]; + + [super tearDown]; +} + +- (ZoneKeys*)engramZoneKeys { + return self.keys[self.engramZoneID]; +} + +- (ZoneKeys*)manateeZoneKeys { + return self.keys[self.manateeZoneID]; +} + +-(void)saveFakeKeyHierarchiesToLocalDatabase { + [self createAndSaveFakeKeyHierarchy: self.engramZoneID]; + [self createAndSaveFakeKeyHierarchy: self.manateeZoneID]; + [self createAndSaveFakeKeyHierarchy: self.autoUnlockZoneID]; + [self createAndSaveFakeKeyHierarchy: self.healthZoneID]; +} + +-(void)testAddEngramManateeItems { + [self saveFakeKeyHierarchiesToLocalDatabase]; // Make life easy for this test. + + [self startCKKSSubsystem]; + + XCTestExpectation* engramChanged = [self expectChangeForView:self.engramZoneID.zoneName]; + XCTestExpectation* pcsChanged = [self expectChangeForView:@"PCS"]; + XCTestExpectation* manateeChanged = [self expectChangeForView:self.manateeZoneID.zoneName]; + + // We expect a single record to be uploaded to the engram view. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.engramZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me-engram" viewHint:(NSString*) kSecAttrViewHintEngram]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForExpectations:@[engramChanged] timeout:1]; + [self waitForExpectations:@[pcsChanged] timeout:1]; + + pcsChanged = [self expectChangeForView:@"PCS"]; + + // We expect a single record to be uploaded to the manatee view. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.manateeZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me-manatee" viewHint:(NSString*) kSecAttrViewHintManatee]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForExpectations:@[manateeChanged] timeout:1]; + [self waitForExpectations:@[pcsChanged] timeout:1]; +} + +-(void)testAddAutoUnlockItems { + [self saveFakeKeyHierarchiesToLocalDatabase]; // Make life easy for this test. + + [self startCKKSSubsystem]; + + XCTestExpectation* autoUnlockChanged = [self expectChangeForView:self.autoUnlockZoneID.zoneName]; + // AutoUnlock is NOT is PCS view, so it should not send the fake 'PCS' view notification + XCTestExpectation* pcsChanged = [self expectChangeForView:@"PCS"]; + pcsChanged.inverted = YES; + + // We expect a single record to be uploaded to the AutoUnlock view. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.autoUnlockZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me-autounlock" viewHint:(NSString*) kSecAttrViewHintAutoUnlock]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForExpectations:@[autoUnlockChanged] timeout:1]; + [self waitForExpectations:@[pcsChanged] timeout:0.2]; +} + +-(void)testAddHealthItems { + [self saveFakeKeyHierarchiesToLocalDatabase]; // Make life easy for this test. + + [self startCKKSSubsystem]; + + XCTestExpectation* healthChanged = [self expectChangeForView:self.healthZoneID.zoneName]; + // AutoUnlock is NOT is PCS view, so it should not send the fake 'PCS' view notification + XCTestExpectation* pcsChanged = [self expectChangeForView:@"PCS"]; + pcsChanged.inverted = YES; + + // We expect a single record to be uploaded to the Health view. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.healthZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me-autounlock" viewHint:(NSString*) kSecAttrViewHintHealth]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForExpectations:@[healthChanged] timeout:1]; + [self waitForExpectations:@[pcsChanged] timeout:0.2]; +} + +-(void)testAddOtherViewHintItem { + [self saveFakeKeyHierarchiesToLocalDatabase]; // Make life easy for this test. + + [self startCKKSSubsystem]; + + // We expect no uploads to CKKS. + [self addGenericPassword: @"data" account: @"account-delete-me-no-viewhint"]; + [self addGenericPassword: @"data" account: @"account-delete-me-password" viewHint:(NSString*) kSOSViewAutofillPasswords]; + + sleep(1); + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testReceiveItemInView { + [self saveFakeKeyHierarchiesToLocalDatabase]; // Make life easy for this test. + [self startCKKSSubsystem]; + + [self waitForKeyHierarchyReadinesses]; + + [self findGenericPassword:@"account-delete-me" expecting:errSecItemNotFound]; + + CKRecord* ckr = [self createFakeRecord:self.engramZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"]; + [self.engramZone addToZone: ckr]; + + XCTestExpectation* engramChanged = [self expectChangeForView:self.engramZoneID.zoneName]; + XCTestExpectation* pcsChanged = [self expectChangeForView:@"PCS"]; + + // Trigger a notification (with hilariously fake data) + [self.engramView notifyZoneChange:nil]; + + [self.engramView waitForFetchAndIncomingQueueProcessing]; + [self findGenericPassword:@"account-delete-me" expecting:errSecSuccess]; + + [self waitForExpectations:@[engramChanged] timeout:1]; + [self waitForExpectations:@[pcsChanged] timeout:1]; +} + +- (void)testFindManateePiggyTLKs { + [self saveFakeKeyHierarchyToLocalDatabase:self.manateeZoneID]; + [self saveTLKMaterialToKeychain:self.manateeZoneID]; + + NSDictionary* piggyTLKs = [self SOSPiggyBackCopyFromKeychain]; + + [self deleteTLKMaterialFromKeychain:self.manateeZoneID]; + + [self SOSPiggyBackAddToKeychain:piggyTLKs]; + + NSError* error = nil; + [self.manateeZoneKeys.tlk loadKeyMaterialFromKeychain:&error]; + XCTAssertNil(error, "No error loading tlk from piggy contents"); +} + +- (void)testFindPiggyTLKs { + [self putFakeKeyHierachiesInCloudKit]; + [self saveTLKsToKeychain]; + + NSDictionary* piggyTLKs = [self SOSPiggyBackCopyFromKeychain]; + + [self deleteTLKMaterialsFromKeychain]; + + [self SOSPiggyBackAddToKeychain:piggyTLKs]; + + NSError* error = nil; + [self.manateeZoneKeys.tlk loadKeyMaterialFromKeychain:&error]; + XCTAssertNil(error, "No error loading manatee tlk from piggy contents"); + + [self.engramZoneKeys.tlk loadKeyMaterialFromKeychain:&error]; + XCTAssertNil(error, "No error loading engram tlk from piggy contents"); + + [self.autoUnlockZoneKeys.tlk loadKeyMaterialFromKeychain:&error]; + XCTAssertNil(error, "No error loading AutoUnlock tlk from piggy contents"); + + [self.healthZoneKeys.tlk loadKeyMaterialFromKeychain:&error]; + XCTAssertNil(error, "No error loading Health 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]; + + }); + NSLog(@"using temp path: %@", tempPath); + return tempPath; +} + +-(void)testPiggybackingData{ + [self putFakeKeyHierachiesInCloudKit]; + [self saveTLKsToKeychain]; + + [self startCKKSSubsystem]; + + [self waitForKeyHierarchyReadinesses]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + /* + * Pull data from keychain and view manager + */ + + NSDictionary* piggydata = [self SOSPiggyBackCopyFromKeychain]; + NSArray* icloudidentities = piggydata[@"idents"]; + NSArray* tlks = piggydata[@"tlk"]; + + XCTAssertEqual([tlks count], [[CKKSViewManager viewList] count], "TLKs not same as views"); + + XCTAssertNotNil(tlks, "tlks not set"); + XCTAssertNotEqual([tlks count], (NSUInteger)0, "0 tlks"); + XCTAssertNotNil(icloudidentities, "idents not set"); + XCTAssertNotEqual([icloudidentities count], (NSUInteger)0, "0 icloudidentities"); + + 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"); + + /* + * Check that they make it accross + */ + + const uint8_t* der = [initial bytes]; + const uint8_t *der_end = der + [initial length]; + + NSDictionary *result = SOSPiggyCopyInitialSyncData(&der, der_end); + XCTAssertNotNil(result, "Initial not set"); + NSArray *copiedTLKs = result[@"tlks"]; + XCTAssertNotNil(copiedTLKs, "tlks not set"); + XCTAssertEqual([copiedTLKs count], [tlks count], "tlks count not same"); + + NSArray *copiediCloudidentities = result[@"idents"]; + XCTAssertNotNil(copiediCloudidentities, "idents not set"); + XCTAssertEqual([copiediCloudidentities count], [icloudidentities count], "ident count not same"); +} + +-(void)testVerifyTLKSorting { + char key[32*2] = {0}; + NSArray *tlks = @[ + @{ + @"acct" : @"11111111", + @"srvr" : @"Manatee", + @"v_Data" : [NSData dataWithBytes:key length:sizeof(key)], + @"auth" : @YES, + }, + @{ + @"acct" : @"55555555", + @"srvr" : @"Health", + @"v_Data" : [NSData dataWithBytes:key length:sizeof(key)], + }, + @{ + @"acct" : @"22222222", + @"srvr" : @"Engram", + @"v_Data" : [NSData dataWithBytes:key length:sizeof(key)], + @"auth" : @YES, + }, + @{ + @"acct" : @"44444444", + @"srvr" : @"Manatee", + @"v_Data" : [NSData dataWithBytes:key length:sizeof(key)], + }, + @{ + @"acct" : @"33333333", + @"srvr" : @"Health", + @"v_Data" : [NSData dataWithBytes:key length:sizeof(key)], + @"auth" : @YES, + }, + ]; + + NSArray* sortedTLKs = SOSAccountSortTLKS(tlks); + XCTAssertNotNil(sortedTLKs, "sortedTLKs not set"); + + NSLog(@"TLKs: %@", tlks); + NSLog(@"sortedTLKs: %@", sortedTLKs); + + NSArray *expectedOrder = @[ @"11111111", @"22222222", @"33333333", @"44444444", @"55555555"]; + [sortedTLKs enumerateObjectsUsingBlock:^(NSDictionary *tlk, NSUInteger idx, BOOL * _Nonnull stop) { + NSString *uuid = tlk[@"acct"]; + XCTAssertEqualObjects(uuid, expectedOrder[idx], "wrong order"); + }]; +} + + +- (void)testAcceptExistingPiggyKeyHierarchy { + // Test starts with no keys in CKKS database, but one in our fake CloudKit. + // Test also begins with the TLK having arrived in the local keychain (via SOS) + [self putFakeKeyHierachiesInCloudKit]; + [self saveTLKsToKeychain]; + NSDictionary* piggyTLKS = [self SOSPiggyBackCopyFromKeychain]; + [self SOSPiggyBackAddToKeychain:piggyTLKS]; + [self deleteTLKMaterialsFromKeychain]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should not try to write anything to the CloudKit database while it's accepting the keys + [self.manateeView waitForKeyHierarchyReadiness]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Verify that there are three local keys, and three local current key records + __weak __typeof(self) weakSelf = self; + [self.manateeView dispatchSync: ^bool{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + NSError* error = nil; + + NSArray* keys = [CKKSKey localKeys:strongSelf.manateeZoneID error:&error]; + XCTAssertNil(error, "no error fetching keys"); + XCTAssertEqual(keys.count, 3u, "Three keys in local database"); + + NSArray* currentkeys = [CKKSCurrentKeyPointer all:strongSelf.manateeZoneID error:&error]; + XCTAssertNil(error, "no error fetching current keys"); + XCTAssertEqual(currentkeys.count, 3u, "Three current key pointers in local database"); + + // Ensure that the manatee syncable TLK is created from a piggy + NSDictionary* query = @{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrDescription: SecCKKSKeyClassTLK, + (id)kSecAttrAccount: strongSelf.manateeZoneKeys.tlk.uuid, + (id)kSecAttrServer: strongSelf.manateeZoneID.zoneName, + (id)kSecAttrSynchronizable: @YES, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @YES, + }; + CFTypeRef result = nil; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef)query, &result), "Found a syncable TLK"); + XCTAssertNotNil((__bridge id) result, "Received a result from SecItemCopyMatching"); + CFReleaseNull(result); + + return false; + }]; +} + +-(void)putFakeKeyHierachiesInCloudKit{ + [self putFakeKeyHierarchyInCloudKit: self.engramZoneID]; + [self putFakeKeyHierarchyInCloudKit: self.manateeZoneID]; + [self putFakeKeyHierarchyInCloudKit: self.autoUnlockZoneID]; + [self putFakeKeyHierarchyInCloudKit: self.healthZoneID]; +} +-(void)saveTLKsToKeychain{ + [self saveTLKMaterialToKeychain:self.engramZoneID]; + [self saveTLKMaterialToKeychain:self.manateeZoneID]; + [self saveTLKMaterialToKeychain:self.autoUnlockZoneID]; + [self saveTLKMaterialToKeychain:self.healthZoneID]; +} +-(void)deleteTLKMaterialsFromKeychain{ + [self deleteTLKMaterialFromKeychain: self.engramZoneID]; + [self deleteTLKMaterialFromKeychain: self.manateeZoneID]; + [self deleteTLKMaterialFromKeychain: self.autoUnlockZoneID]; + [self deleteTLKMaterialFromKeychain: self.healthZoneID]; +} + +-(void)waitForKeyHierarchyReadinesses { + [self.manateeView waitForKeyHierarchyReadiness]; + [self.engramView waitForKeyHierarchyReadiness]; + [self.autoUnlockView waitForKeyHierarchyReadiness]; + [self.healthView waitForKeyHierarchyReadiness]; +} + +-(void)testAcceptExistingAndUsePiggyKeyHierarchy { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierachiesInCloudKit]; + [self saveTLKsToKeychain]; + NSDictionary* piggyData = [self SOSPiggyBackCopyFromKeychain]; + [self deleteTLKMaterialsFromKeychain]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should not try to write anything to the CloudKit database. + sleep(1); + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now, save the TLK to the keychain (to simulate it coming in later via piggybacking). + [self SOSPiggyBackAddToKeychain:piggyData]; + [self waitForKeyHierarchyReadinesses]; + + // We expect a single record to be uploaded for each key class + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.manateeZoneID checkItem: [self checkClassCBlock:self.manateeZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me-manatee" viewHint:(id)kSecAttrViewHintManatee]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.manateeZoneID checkItem: [self checkClassABlock:self.manateeZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:(id)kSecAttrViewHintManatee + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/tests/CKKSSQLTests.m b/keychain/ckks/tests/CKKSSQLTests.m new file mode 100644 index 00000000..fe958b56 --- /dev/null +++ b/keychain/ckks/tests/CKKSSQLTests.m @@ -0,0 +1,582 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import +#import "CloudKitMockXCTest.h" + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" +#import "keychain/ckks/CKKSDeviceStateEntry.h" +#import "keychain/ckks/CKKSRateLimiter.h" + +#include + +@interface CloudKitKeychainSQLTests : CloudKitMockXCTest +@end + +@implementation CloudKitKeychainSQLTests + ++ (void)setUp { + [super setUp]; +} + +- (void)setUp { + SecCKKSDisable(); + [super setUp]; +} + +- (void)tearDown { + [super tearDown]; + SecCKKSResetSyncing(); +} + +- (void)addTestZoneEntries { + CKKSOutgoingQueueEntry* one = [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem: + [[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] + action:SecCKKSActionAdd + state:SecCKKSStateError + waitUntil:nil + accessGroup:@"nope"]; + + + CKKSOutgoingQueueEntry* two = [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem: + [[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] + action:SecCKKSActionAdd + state:SecCKKSStateNew + waitUntil:nil + accessGroup:@"nope"]; + + CKKSOutgoingQueueEntry* three = [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem: + [[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] + action:SecCKKSActionModify + state:SecCKKSStateError + waitUntil:nil + accessGroup:@"nope"]; + + NSError* error = nil; + [one saveToDatabase:&error]; + [two saveToDatabase: &error]; + [three saveToDatabase: &error]; + XCTAssertNil(error, "no error saving ZoneStateEntries to database"); +} + +- (void)testCKKSOutgoingQueueEntry { + NSString* testUUID = @"157A3171-0677-451B-9EAE-0DDC4D4315B0"; + NSUUID* testKeyUUID = [[NSUUID alloc] init]; + + NSError * nserror; + __block CFErrorRef error = NULL; + + CKKSOutgoingQueueEntry* shouldFail = [CKKSOutgoingQueueEntry fromDatabase:testUUID state:SecCKKSStateInFlight zoneID:self.testZoneID error: &nserror]; + XCTAssertNil(shouldFail, "Can't find a nonexisting object"); + XCTAssertNotNil(nserror, "NSError exists when things break"); + + __weak __typeof(self) weakSelf = self; + kc_with_dbt(true, &error, ^bool (SecDbConnectionRef dbconn) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "called while self still exists"); + + NSString * sql = @"insert INTO outgoingqueue (UUID, parentKeyUUID, ckzone, action, state, accessgroup, gencount, encitem, wrappedkey, encver) VALUES (?,?,?,?,?,?,?,?,?,?);"; + SecDbPrepare(dbconn, (__bridge CFStringRef) sql, &error, ^void (sqlite3_stmt *stmt) { + SecDbBindText(stmt, 1, [testUUID UTF8String], strlen([testUUID UTF8String]), NULL, &error); + SecDbBindText(stmt, 2, [[testKeyUUID UUIDString] UTF8String], strlen([[testKeyUUID UUIDString] UTF8String]), NULL, &error); + SecDbBindObject(stmt, 3, (__bridge CFStringRef) weakSelf.testZoneID.zoneName, &error); + SecDbBindText(stmt, 4, "newitem", strlen("newitem"), NULL, &error); + SecDbBindText(stmt, 5, "unprocessed", strlen("unprocessed"), NULL, &error); + SecDbBindText(stmt, 6, "com.apple.access", strlen("com.apple.access"), NULL, &error); + SecDbBindText(stmt, 7, "0", strlen("0"), NULL, &error); + SecDbBindText(stmt, 8, "bm9uc2Vuc2UK", strlen("bm9uc2Vuc2UK"), NULL, &error); + SecDbBindObject(stmt, 9, CFSTR("KFfL58XtugiYNoD859EjG0StfrYd6eakm0CQrgX7iO+DEo4kio3WbEeA1kctCU0GaeTGsRFpbdy4oo6jXhVu7cZqB0svhUPGq55aGnszUjI="), &error); + SecDbBindText(stmt, 10, "0", strlen("0"), NULL, &error); + + SecDbStep(dbconn, stmt, &error, ^(bool *stop) { + // don't do anything, I guess? + }); + + XCTAssertNil((__bridge NSError*)error, @"no error occurred while adding row to database"); + + CFReleaseNull(error); + }); + XCTAssertNil((__bridge NSError*)error, @"no error occurred preparing sql"); + + CFReleaseNull(error); + return true; + }); + + // Create another oqe with different values + 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]; + CKKSOutgoingQueueEntry* other = [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem:baseitem + action:SecCKKSActionAdd + state:SecCKKSStateError + waitUntil:[NSDate date] + accessGroup:@"nope"]; + [other saveToDatabase:&nserror]; + XCTAssertNil(nserror, "no error occurred saving to database"); + + CKKSOutgoingQueueEntry * oqe = [CKKSOutgoingQueueEntry fromDatabase:testUUID state:@"unprocessed" zoneID:self.testZoneID error: &nserror]; + XCTAssertNil(nserror, "no error occurred creating from database"); + + XCTAssertNotNil(oqe, "load outgoing queue entry from database"); + XCTAssertEqualObjects(oqe.state, @"unprocessed", "state matches what was in the DB"); + + oqe.item.parentKeyUUID = @"not a parent key either"; + oqe.action = @"null"; + oqe.state = @"savedtocloud"; + oqe.accessgroup = @"com.evil.access"; + oqe.item.generationCount = (NSInteger) 1; + oqe.item.base64encitem = @"bW9yZW5vbnNlbnNlCg=="; + oqe.item.encver = 1; + + XCTAssertTrue([oqe saveToDatabase: &nserror], "saving to database"); + + CKKSOutgoingQueueEntry * oqe2 = [CKKSOutgoingQueueEntry fromDatabase:testUUID state:@"savedtocloud" zoneID:self.testZoneID error: &nserror]; + XCTAssertNil(nserror, "no error occurred"); + + XCTAssertEqualObjects(oqe2.item.parentKeyUUID, @"not a parent key either", @"parent key uuid persisted through db save and load"); + XCTAssertEqualObjects(oqe2.item.zoneID , self.testZoneID , @"zone id persisted through db save and load"); + XCTAssertEqualObjects(oqe2.action , @"null" , @"action persisted through db save and load"); + XCTAssertEqualObjects(oqe2.state , @"savedtocloud" , @"state persisted through db save and load"); + XCTAssertEqual( oqe2.waitUntil , nil , @"no date when none given"); + XCTAssertEqualObjects(oqe2.accessgroup , @"com.evil.access" , @"accessgroup persisted through db save and load"); + XCTAssertEqual( oqe2.item.generationCount, (NSUInteger) 1 , @"generationCount persisted through db save and load"); + XCTAssertEqualObjects(oqe2.item.base64encitem, @"bW9yZW5vbnNlbnNlCg==" , @"encitem persisted through db save and load"); + XCTAssertEqual( oqe2.item.encver, 1 , @"encver persisted through db save and load"); + XCTAssertEqualObjects([oqe2.item.wrappedkey base64WrappedKey], @"KFfL58XtugiYNoD859EjG0StfrYd6eakm0CQrgX7iO+DEo4kio3WbEeA1kctCU0GaeTGsRFpbdy4oo6jXhVu7cZqB0svhUPGq55aGnszUjI=", + @"wrapped key persisted through db save and load"); + + // Test 'all' methods + NSArray* oqes = [CKKSOutgoingQueueEntry all:&nserror]; + XCTAssertNil(nserror, "no error occurred"); + XCTAssertNotNil(oqes, "receive oqes from database"); + XCTAssert([oqes count] == 2, "received 2 oqes from all"); + + NSArray* oqeswhere = [CKKSOutgoingQueueEntry allWhere: @{@"state": @"savedtocloud"} error:&nserror]; + XCTAssertNil(nserror, "no error occurred"); + XCTAssertNotNil(oqeswhere, "receive oqes from database"); + XCTAssert([oqeswhere count] == 1, "received 1 oqe from allWhere"); + + // Test row deletion + nserror = nil; + [oqe2 deleteFromDatabase:&nserror]; + XCTAssertNil(nserror, "No NSError exists when deleting existing item"); + 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"); + + // Test loading other + nserror = nil; + CKKSOutgoingQueueEntry* other2 = [CKKSOutgoingQueueEntry fromDatabase: other.item.uuid state:SecCKKSStateError zoneID:self.testZoneID error:&nserror]; + XCTAssertNil(nserror, "No error loading other2 from database"); + XCTAssertNotNil(other2, "Able to re-load other."); + XCTAssertEqualObjects(other, other2, "loaded object is equal to object"); +} + +-(void)testCKKSZoneStateEntrySQL { + CKKSZoneStateEntry* zse = [[CKKSZoneStateEntry alloc] initWithCKZone: @"sqltest" + zoneCreated: true + zoneSubscribed: true + changeToken: [@"nonsense" dataUsingEncoding:NSUTF8StringEncoding] + lastFetch: [NSDate date] + encodedRateLimiter:nil]; + zse.rateLimiter = [[CKKSRateLimiter alloc] init]; + + CKKSZoneStateEntry* zseClone = [[CKKSZoneStateEntry alloc] initWithCKZone: @"sqltest" + zoneCreated: true + zoneSubscribed: true + changeToken: [@"nonsense" dataUsingEncoding:NSUTF8StringEncoding] + lastFetch: zse.lastFetchTime + encodedRateLimiter:zse.encodedRateLimiter]; + + CKKSZoneStateEntry* zseDifferent = [[CKKSZoneStateEntry alloc] initWithCKZone: @"sqltest" + zoneCreated: true + zoneSubscribed: true + changeToken: [@"allnonsense" dataUsingEncoding:NSUTF8StringEncoding] + lastFetch: zse.lastFetchTime + encodedRateLimiter:zse.encodedRateLimiter]; + XCTAssertEqualObjects(zse, zseClone, "CKKSZoneStateEntry isEqual of equal objects seems sane"); + XCTAssertNotEqualObjects(zse, zseDifferent, "CKKSZoneStateEntry isEqual of nonequal objects seems sane"); + + NSError* error = nil; + CKKSZoneStateEntry* loaded = [CKKSZoneStateEntry tryFromDatabase: @"sqltest" error:&error]; + 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"); + + loaded = [CKKSZoneStateEntry tryFromDatabase: @"sqltest" error:&error]; + XCTAssertNil(error, "No error trying to load saved record"); + XCTAssertNotNil(loaded, "CKKSZoneStateEntry came back out of database"); + + XCTAssertEqualObjects(zse.ckzone, loaded.ckzone, "ckzone persisted through db save and load"); + XCTAssertEqual (zse.ckzonecreated, loaded.ckzonecreated, "ckzonecreated persisted through db save and load"); + XCTAssertEqual (zse.ckzonesubscribed, loaded.ckzonesubscribed, "ckzonesubscribed persisted through db save and load"); + XCTAssertEqualObjects(zse.encodedChangeToken, loaded.encodedChangeToken, "encodedChangeToken persisted through db save and load"); + + XCTAssert([[NSCalendar currentCalendar] isDate:zse.lastFetchTime equalToDate: loaded.lastFetchTime toUnitGranularity:NSCalendarUnitSecond], + "lastFetchTime persisted through db save and load"); +} + +-(void)testRoundtripCKKSDeviceStateEntry { + // Very simple test: can these objects roundtrip through the db? + NSString* testUUID = @"157A3171-0677-451B-9EAE-0DDC4D4315B0"; + CKKSDeviceStateEntry* cdse = [[CKKSDeviceStateEntry alloc] initForDevice:testUUID + circlePeerID:@"asdf" + circleStatus:kSOSCCInCircle + keyState:SecCKKSZoneKeyStateReady + currentTLKUUID:@"tlk" + currentClassAUUID:@"classA" + currentClassCUUID:@"classC" + zoneID:self.testZoneID + encodedCKRecord:nil]; + XCTAssertNotNil(cdse, "Constructor works"); + NSError* saveError = nil; + [cdse saveToDatabase:&saveError]; + XCTAssertNil(saveError, "No error saving cdse to database"); + + NSError* loadError = nil; + CKKSDeviceStateEntry* loadedCDSE = [CKKSDeviceStateEntry fromDatabase:testUUID zoneID:self.testZoneID error:&loadError]; + XCTAssertNil(loadError, "No error loading CDSE"); + XCTAssertNotNil(loadedCDSE, "Received a CDSE back"); + + XCTAssertEqualObjects(cdse, loadedCDSE, "Roundtripping CKKSDeviceStateEntry ends up with equivalent objects"); +} + +// disabled, as CKKS syncing is disabled in this class. +// To re-enable, need to add flags CKKS syncing to perform queue actions but not automatically start queue processing operations +-(void)disabledtestItemAddCreatesCKKSOutgoingQueueEntry { + CFMutableDictionaryRef attrs; + CFDataRef data; + + NSError* error; + + NSArray* oqes = [CKKSOutgoingQueueEntry all: &error]; + XCTAssertEqual([oqes count], 0ul, @"Nothing in outgoing queue"); + XCTAssertNil(error, @"No error loading queue"); + + attrs = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); + CFDictionarySetValue( attrs, kSecClass, kSecClassGenericPassword ); + CFDictionarySetValue( attrs, kSecAttrAccessible, kSecAttrAccessibleAlways ); + CFDictionarySetValue( attrs, kSecAttrLabel, CFSTR( "TestLabel" ) ); + CFDictionarySetValue( attrs, kSecAttrDescription, CFSTR( "TestDescription" ) ); + CFDictionarySetValue( attrs, kSecAttrAccount, CFSTR( "TestAccount" ) ); + CFDictionarySetValue( attrs, kSecAttrService, CFSTR( "TestService" ) ); + CFDictionarySetValue( attrs, kSecAttrAccessGroup, CFSTR("com.apple.lakitu")); + data = CFDataCreate( NULL, (const uint8_t *) "important data", strlen("important data")); + CFDictionarySetValue( attrs, kSecValueData, data ); + CFRelease( data ); + + XCTAssertEqual(SecItemAdd(attrs, NULL), errSecSuccess, @"Adding item works flawlessly"); + + oqes = [CKKSOutgoingQueueEntry all: &error]; + XCTAssertEqual([oqes count], 1ul, @"Single entry in outgoing queue after adding item"); + XCTAssertNil(error, @"No error loading queue"); + + CFDictionarySetValue( attrs, kSecAttrLabel, CFSTR( "TestLabel2" ) ); + CFDictionarySetValue( attrs, kSecAttrAccount, CFSTR( "TestAccount2" ) ); + CFDictionarySetValue( attrs, kSecAttrService, CFSTR( "TestService2" ) ); + XCTAssertEqual(SecItemAdd(attrs, NULL), errSecSuccess); + CFRelease( attrs ); + + oqes = [CKKSOutgoingQueueEntry all: &error]; + XCTAssertEqual([oqes count], 2ul, @"Two entries in outgoing queue after adding item"); + XCTAssertNil(error, @"No error loading queue"); +} + +- (void)testCKKSKey { + CKKSKey* key = nil; + NSString* testUUID = @"157A3171-0677-451B-9EAE-0DDC4D4315B0"; + NSString* testParentUUID = @"f5e7f20f-0885-48f9-b75d-9f0cfd2171b6"; + + NSData* testCKRecord = [@"nonsense" dataUsingEncoding:NSUTF8StringEncoding]; + + CKKSWrappedAESSIVKey* wrappedkey = [[CKKSWrappedAESSIVKey alloc] initWithBase64:@"KFfL58XtugiYNoD859EjG0StfrYd6eakm0CQrgX7iO+DEo4kio3WbEeA1kctCU0GaeTGsRFpbdy4oo6jXhVu7cZqB0svhUPGq55aGnszUjI="]; + + NSError* error = nil; + + key = [CKKSKey fromDatabase:testUUID zoneID:self.testZoneID error:&error]; + XCTAssertNil(key, "key does not exist yet"); + XCTAssertNotNil(error, "error exists when things go wrong"); + error = nil; + + key = [[CKKSKey alloc] initWithWrappedAESKey: wrappedkey + uuid: testUUID + parentKeyUUID:testParentUUID + keyclass:SecCKKSKeyClassA + state: SecCKKSProcessedStateLocal + zoneID:self.testZoneID + encodedCKRecord:testCKRecord + currentkey:true]; + XCTAssertNotNil(key, "could create key"); + + [key saveToDatabase: &error]; + XCTAssertNil(error, "could save key to database"); + error = nil; + + CKKSKey* key2 = [CKKSKey fromDatabase:testUUID zoneID:self.testZoneID error:&error]; + XCTAssertNil(error, "no error exists when loading key"); + XCTAssertNotNil(key2, "key was fetched properly"); + + XCTAssertEqualObjects(key.uuid, key2.uuid, "key uuids match"); + XCTAssertEqualObjects(key.parentKeyUUID, key2.parentKeyUUID, "parent key uuids match"); + XCTAssertEqualObjects(key.state, key2.state, "key states match"); + XCTAssertEqualObjects(key.encodedCKRecord, key2.encodedCKRecord, "encodedCKRecord match"); + XCTAssertEqualObjects(key.wrappedkey, key2.wrappedkey, "wrapped keys match"); + XCTAssertEqual(key.currentkey, key2.currentkey, "currentkey match"); +} + +- (void)testWhere { + NSError* error = nil; + + NSData* testCKRecord = [@"nonsense" dataUsingEncoding:NSUTF8StringEncoding]; + + CKKSKey* tlk = [[CKKSKey alloc] initSelfWrappedWithAESKey: [[CKKSAESSIVKey alloc] initWithBase64: @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="] + uuid:@"8b2aeb7f-4af3-43e9-b6e6-70d5c728ebf7" + keyclass:SecCKKSKeyClassTLK + state: SecCKKSProcessedStateLocal + zoneID:self.testZoneID + encodedCKRecord: testCKRecord + currentkey: true]; + XCTAssertTrue([tlk saveToDatabase: &error], "TLK saved to database"); + XCTAssertNil(error, "no error saving TLK to database"); + + CKKSKey* wrappedKey = [[CKKSKey alloc] initWrappedBy: tlk + AESKey:[CKKSAESSIVKey randomKey] + uuid:@"157A3171-0677-451B-9EAE-0DDC4D4315B0" + keyclass:SecCKKSKeyClassC + state: SecCKKSProcessedStateLocal + zoneID:self.testZoneID + encodedCKRecord:testCKRecord + currentkey:true]; + XCTAssertTrue([wrappedKey saveToDatabase: &error], "key saved to database"); + XCTAssertNil(error, "no error saving key to database"); + + NSArray* 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([tlks count], 1ul, "Received one row (and expected one row)"); + + NSArray* selfWrapped = [CKKSKey allWhere: @{@"parentKeyUUID": [CKKSSQLWhereObject op:@"=" string:@"uuid"]} error: &error]; + XCTAssertNotNil(selfWrapped, "Returned some array from allWhere"); + XCTAssertNil(error, "no error back from allWhere"); + XCTAssertEqual([selfWrapped count], 1ul, "Received one row (and expected one row)"); +} + +- (void)testGroupBy { + [self addTestZoneEntries]; + NSError* error = nil; + + __block NSMutableDictionary* results = [[NSMutableDictionary alloc] init]; + NSDictionary* expectedResults = nil; + + [CKKSSQLDatabaseObject queryDatabaseTable: [CKKSOutgoingQueueEntry sqlTable] + where: nil + columns: @[@"action", @"count(rowid)"] + groupBy: @[@"action"] + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + results[row[@"action"]] = row[@"count(rowid)"]; + } + error: &error]; + + XCTAssertNil(error, "no error doing group by query"); + expectedResults = @{ + SecCKKSActionAdd: @"2", + SecCKKSActionModify: @"1" + }; + XCTAssertEqualObjects(results, expectedResults, "Recieved correct group by result"); + + // Now test with a where clause: + results = [[NSMutableDictionary alloc] init]; + [CKKSSQLDatabaseObject queryDatabaseTable: [CKKSOutgoingQueueEntry sqlTable] + where: @{@"state": SecCKKSStateError} + columns: @[@"action", @"count(rowid)"] + groupBy: @[@"action"] + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + results[row[@"action"]] = row[@"count(rowid)"]; + } + error: &error]; + + XCTAssertNil(error, "no error doing where+group by query"); + expectedResults = @{ + SecCKKSActionAdd: @"1", + SecCKKSActionModify: @"1" + }; + XCTAssertEqualObjects(results, expectedResults, "Recieved correct where+group by result"); +} + +- (void)testOrderBy { + [self addTestZoneEntries]; + NSError* error = nil; + + __block NSMutableArray* rows = [[NSMutableArray alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [CKKSOutgoingQueueEntry sqlTable] + where: nil + columns: @[@"action", @"uuid"] + groupBy:nil + orderBy:@[@"uuid"] + limit:-1 + processRow: ^(NSDictionary* row) { + [rows addObject:row]; + } + error: &error]; + + XCTAssertNil(error, "no error doing order by query"); + XCTAssertEqual(rows.count, 3u, "got three items"); + + XCTAssertEqual([rows[0][@"uuid"] compare: rows[1][@"uuid"]], NSOrderedAscending, "first order is fine"); + XCTAssertEqual([rows[1][@"uuid"] compare: rows[2][@"uuid"]], NSOrderedAscending, "second order is fine"); + + // Check that order-by + limit works to page + __block NSString* lastUUID = nil; + __block NSString* uuid = nil; + uint64_t count = 0; + + while(count == 0 || uuid != nil) { + uuid = nil; + [CKKSSQLDatabaseObject queryDatabaseTable: [CKKSOutgoingQueueEntry sqlTable] + where: lastUUID ? @{@"UUID": [CKKSSQLWhereObject op:@">" stringValue:lastUUID]} : nil + columns: @[@"action", @"UUID"] + groupBy:nil + orderBy:@[@"uuid"] + limit:1 + processRow: ^(NSDictionary* row) { + XCTAssertNil(uuid, "Only one row returned"); + uuid = row[@"UUID"]; + } + error: &error]; + XCTAssertNil(error, "No error doing SQL"); + if(uuid && lastUUID) { + XCTAssertEqual([lastUUID compare:uuid], NSOrderedAscending, "uuids returning in right order"); + } + lastUUID = uuid; + count += 1; + } + XCTAssertEqual(count, 4u, "Received 3 objects (and 1 nil)"); +} + +- (void)testLimit { + [self addTestZoneEntries]; + NSError* error = nil; + + __block NSMutableDictionary* results = [[NSMutableDictionary alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [CKKSOutgoingQueueEntry sqlTable] + where: nil + columns: @[@"uuid", @"action"] + groupBy: nil + orderBy:nil + limit: -1 + processRow: ^(NSDictionary* row) { + results[row[@"uuid"]] = row[@"action"]; + } + error: &error]; + + XCTAssertNil(error, "no error doing vanilla query"); + XCTAssertEqual(results.count, 3u, "Received three elements in normal query"); + results = [[NSMutableDictionary alloc] init]; + + [CKKSSQLDatabaseObject queryDatabaseTable: [CKKSOutgoingQueueEntry sqlTable] + where: nil + columns: @[@"uuid", @"action"] + groupBy: nil + orderBy:nil + limit: 1 + processRow: ^(NSDictionary* row) { + results[row[@"uuid"]] = row[@"action"]; + } + error: &error]; + + XCTAssertNil(error, "no error doing limit query"); + XCTAssertEqual(results.count, 1u, "Received one element in limited query"); + results = [[NSMutableDictionary alloc] init]; + + // Now test with a where clause: + results = [[NSMutableDictionary alloc] init]; + [CKKSSQLDatabaseObject queryDatabaseTable: [CKKSOutgoingQueueEntry sqlTable] + where: @{@"state": SecCKKSStateError} + columns: @[@"uuid", @"action"] + groupBy: nil + orderBy:nil + limit: 3 + processRow: ^(NSDictionary* row) { + results[row[@"uuid"]] = row[@"action"]; + } + error: &error]; + + XCTAssertNil(error, "no error doing limit+where query"); + XCTAssertEqual(results.count, 2u, "Received two elements in where+limited query"); + results = [[NSMutableDictionary alloc] init]; + + results = [[NSMutableDictionary alloc] init]; + [CKKSSQLDatabaseObject queryDatabaseTable: [CKKSOutgoingQueueEntry sqlTable] + where: @{@"state": SecCKKSStateError} + columns: @[@"uuid", @"action"] + groupBy: nil + orderBy:nil + limit: 1 + processRow: ^(NSDictionary* row) { + results[row[@"uuid"]] = row[@"action"]; + } + error: &error]; + + XCTAssertNil(error, "no error doing limit+where query"); + XCTAssertEqual(results.count, 1u, "Received one element in where+limited query"); + results = [[NSMutableDictionary alloc] init]; +} + +@end + +#endif diff --git a/keychain/ckks/tests/CKKSTests+API.h b/keychain/ckks/tests/CKKSTests+API.h new file mode 100644 index 00000000..50687728 --- /dev/null +++ b/keychain/ckks/tests/CKKSTests+API.h @@ -0,0 +1,49 @@ +/* + * 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 +#import +#import "keychain/ckks/tests/CKKSTests.h" + +@interface CloudKitKeychainSyncingTests (APITests) + +- (BOOL (^) (CKRecord*)) checkPCSFieldsBlock: (CKRecordZoneID*) zoneID + PCSServiceIdentifier:(NSNumber*)servIdentifier + PCSPublicKey:(NSData*)publicKey + PCSPublicIdentity:(NSData*)publicIdentity; + +-(NSMutableDictionary*)pcsAddItemQuery:(NSString*)account + data:(NSData*)data + serviceIdentifier:(NSNumber*)serviceIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity; + +-(NSDictionary*)pcsAddItem:(NSString*)account + data:(NSData*)data + serviceIdentifier:(NSNumber*)serviceIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:(bool)expectingSync; + + +@end diff --git a/keychain/ckks/tests/CKKSTests+API.m b/keychain/ckks/tests/CKKSTests+API.m new file mode 100644 index 00000000..ec3659ff --- /dev/null +++ b/keychain/ckks/tests/CKKSTests+API.m @@ -0,0 +1,778 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import +#import +#import + +#include +#include +#include +#import + +#import "keychain/ckks/tests/CloudKitMockXCTest.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSItem.h" +#import "keychain/ckks/CKKSItemEncrypter.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSViewManager.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" + +#import "keychain/ckks/tests/MockCloudKit.h" + +#import "keychain/ckks/tests/CKKSTests.h" +#import "keychain/ckks/tests/CKKSTests+API.h" + +@implementation CloudKitKeychainSyncingTests (APITests) + +- (void)testSecuritydClientBringup { + CFErrorRef cferror = nil; + xpc_endpoint_t endpoint = SecCreateSecuritydXPCServerEndpoint(&cferror); + XCTAssertNil((__bridge id)cferror, "No error creating securityd endpoint"); + XCTAssertNotNil(endpoint, "Received securityd endpoint"); + + NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SecuritydXPCProtocol)]; + [SecuritydXPCClient configureSecuritydXPCProtocol: interface]; + XCTAssertNotNil(interface, "Received a configured CKKS interface"); + + NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; + [listenerEndpoint _setEndpoint:endpoint]; + + NSXPCConnection* connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; + XCTAssertNotNil(connection , "Received an active connection"); + + connection.remoteObjectInterface = interface; +} + +-(NSMutableDictionary*)pcsAddItemQuery:(NSString*)account + data:(NSData*)data + serviceIdentifier:(NSNumber*)serviceIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity +{ + return [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecReturnPersistentRef: @YES, + (id)kSecReturnAttributes: @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecAttrAccount : account, + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : data, + (id)kSecAttrDeriveSyncIDFromItemAttributes : (id)kCFBooleanTrue, + (id)kSecAttrPCSPlaintextServiceIdentifier : serviceIdentifier, + (id)kSecAttrPCSPlaintextPublicKey : publicKey, + (id)kSecAttrPCSPlaintextPublicIdentity : publicIdentity, + } mutableCopy]; +} + +-(NSDictionary*)pcsAddItem:(NSString*)account + data:(NSData*)data + serviceIdentifier:(NSNumber*)serviceIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:(bool)expectingSync +{ + NSMutableDictionary* query = [self pcsAddItemQuery:account + data:data + serviceIdentifier:(NSNumber*)serviceIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity]; + CFTypeRef result = NULL; + XCTestExpectation* syncExpectation = [self expectationWithDescription: @"callback occurs"]; + + XCTAssertEqual(errSecSuccess, _SecItemAddAndNotifyOnSync((__bridge CFDictionaryRef) query, &result, ^(bool didSync, CFErrorRef error) { + if(expectingSync) { + XCTAssertTrue(didSync, "Item synced"); + XCTAssertNil((__bridge NSError*)error, "No error syncing item"); + } else { + XCTAssertFalse(didSync, "Item did not sync"); + XCTAssertNotNil((__bridge NSError*)error, "Error syncing item"); + } + + [syncExpectation fulfill]; + }), @"_SecItemAddAndNotifyOnSync succeeded"); + + // Verify that the item was written to CloudKit + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // In real code, you'd need to wait for the _SecItemAddAndNotifyOnSync callback to succeed before proceeding + [self waitForExpectations:@[syncExpectation] timeout:8.0]; + + return (NSDictionary*) CFBridgingRelease(result); +} + + +- (void)testAddAndNotifyOnSync { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [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)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"); + + [self waitForExpectationsWithTimeout:5.0 handler:nil]; +} + +- (void)testAddAndNotifyOnSyncFailure { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + // Due to item UUID selection, this item will be added with UUID DD7C2F9B-B22D-3B90-C299-E3B48174BFA3. + // Add it to CloudKit first! + CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3"]; + [self.keychainZone addToZone: ckr]; + + + // Go for it! + [self expectCKAtomicModifyItemRecordsUpdateFailure: self.keychainZoneID]; + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecAttrAccount : @"testaccount", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding], + } mutableCopy]; + + XCTestExpectation* blockExpectation = [self expectationWithDescription: @"callback occurs"]; + + XCTAssertEqual(errSecSuccess, _SecItemAddAndNotifyOnSync((__bridge CFDictionaryRef) query, NULL, ^(bool didSync, CFErrorRef error) { + XCTAssertFalse(didSync, "Item did not sync (as expected)"); + XCTAssertNotNil((__bridge NSError*)error, "error exists when item fails to sync"); + + [blockExpectation fulfill]; + }), @"_SecItemAddAndNotifyOnSync succeeded"); + + [self waitForExpectationsWithTimeout:5.0 handler:nil]; + [self waitForCKModifications]; +} + +- (void)testAddAndNotifyOnSyncLoggedOut { + // Test starts with nothing in database and the user logged out of CloudKit. We expect no CKKS operations. + self.accountStatus = CKAccountStatusNoAccount; + self.silentFetchesAllowed = false; + [self startCKKSSubsystem]; + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecAttrAccount : @"testaccount", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding], + } mutableCopy]; + + XCTestExpectation* blockExpectation = [self expectationWithDescription: @"callback occurs"]; + + XCTAssertEqual(errSecSuccess, _SecItemAddAndNotifyOnSync((__bridge CFDictionaryRef) query, NULL, ^(bool didSync, CFErrorRef error) { + XCTAssertFalse(didSync, "Item did not sync (with no iCloud account)"); + XCTAssertNotNil((__bridge NSError*)error, "Error exists syncing item while logged out"); + + [blockExpectation fulfill]; + }), @"_SecItemAddAndNotifyOnSync succeeded"); + + [self waitForExpectationsWithTimeout:5.0 handler:nil]; +} + +- (BOOL (^) (CKRecord*)) checkPCSFieldsBlock: (CKRecordZoneID*) zoneID + PCSServiceIdentifier:(NSNumber*)servIdentifier + PCSPublicKey:(NSData*)publicKey + PCSPublicIdentity:(NSData*)publicIdentity +{ + __weak __typeof(self) weakSelf = self; + return ^BOOL(CKRecord* record) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + XCTAssert([record[SecCKRecordPCSServiceIdentifier] isEqual: servIdentifier], "PCS Service identifier matches input"); + XCTAssert([record[SecCKRecordPCSPublicKey] isEqual: publicKey], "PCS Public Key matches input"); + XCTAssert([record[SecCKRecordPCSPublicIdentity] isEqual: publicIdentity], "PCS Public Identity matches input"); + + if([record[SecCKRecordPCSServiceIdentifier] isEqual: servIdentifier] && + [record[SecCKRecordPCSPublicKey] isEqual: publicKey] && + [record[SecCKRecordPCSPublicIdentity] isEqual: publicIdentity]) { + return YES; + } else { + return NO; + } + }; +} + +- (void)testPCSUnencryptedFieldsAdd { + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecAttrAccount : @"testaccount", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding], + (id)kSecAttrDeriveSyncIDFromItemAttributes : (id)kCFBooleanTrue, + (id)kSecAttrPCSPlaintextServiceIdentifier : servIdentifier, + (id)kSecAttrPCSPlaintextPublicKey : publicKey, + (id)kSecAttrPCSPlaintextPublicIdentity : publicIdentity, + } mutableCopy]; + + XCTAssertEqual(errSecSuccess, SecItemAdd((__bridge CFDictionaryRef) query, NULL), @"SecItemAdd succeeded"); + + // Verify that the item is written to CloudKit + OCMVerifyAllWithDelay(self.mockDatabase, 4); + + CFTypeRef item = NULL; + query[(id)kSecValueData] = nil; + query[(id)kSecReturnAttributes] = @YES; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should still exist"); + + NSDictionary* itemAttributes = (NSDictionary*) CFBridgingRelease(item); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextServiceIdentifier], servIdentifier, "Service Identifier exists"); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextPublicKey], publicKey, "public key exists"); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextPublicIdentity], publicIdentity, "public identity exists"); + + // Find the item record in CloudKit. Since we're using kSecAttrDeriveSyncIDFromItemAttributes, + // the record ID is likely DD7C2F9B-B22D-3B90-C299-E3B48174BFA3 + [self waitForCKModifications]; + CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName: @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[recordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + XCTAssertEqualObjects(record[SecCKRecordPCSServiceIdentifier], servIdentifier, "Service identifier sent to cloudkit"); + XCTAssertEqualObjects(record[SecCKRecordPCSPublicKey], publicKey, "public key sent to cloudkit"); + XCTAssertEqualObjects(record[SecCKRecordPCSPublicIdentity], publicIdentity, "public identity sent to cloudkit"); +} + +- (void)testPCSUnencryptedFieldsModify { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecAttrAccount : @"testaccount", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding], + (id)kSecAttrDeriveSyncIDFromItemAttributes : (id)kCFBooleanTrue, + (id)kSecAttrPCSPlaintextServiceIdentifier : servIdentifier, + (id)kSecAttrPCSPlaintextPublicKey : publicKey, + (id)kSecAttrPCSPlaintextPublicIdentity : publicIdentity, + } mutableCopy]; + + XCTAssertEqual(errSecSuccess, SecItemAdd((__bridge CFDictionaryRef) query, NULL), @"SecItemAdd succeeded"); + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForCKModifications]; + + query[(id)kSecValueData] = nil; + query[(id)kSecAttrPCSPlaintextServiceIdentifier] = nil; + query[(id)kSecAttrPCSPlaintextPublicKey] = nil; + query[(id)kSecAttrPCSPlaintextPublicIdentity] = nil; + + servIdentifier = @1; + publicKey = [@"new public key" dataUsingEncoding:NSUTF8StringEncoding]; + + NSNumber* newServiceIdentifier = @10; + NSData* newPublicKey = [@"new public key" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* newPublicIdentity = [@"new public identity" dataUsingEncoding:NSUTF8StringEncoding]; + + NSDictionary* update = @{ + (id)kSecAttrPCSPlaintextServiceIdentifier : newServiceIdentifier, + (id)kSecAttrPCSPlaintextPublicKey : newPublicKey, + (id)kSecAttrPCSPlaintextPublicIdentity : newPublicIdentity, + }; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)newServiceIdentifier + PCSPublicKey:newPublicKey + PCSPublicIdentity:newPublicIdentity]]; + + XCTAssertEqual(errSecSuccess, SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef) update), @"SecItemUpdate succeeded"); + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + CFTypeRef item = NULL; + query[(id)kSecValueData] = nil; + query[(id)kSecReturnAttributes] = @YES; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should still exist"); + + NSDictionary* itemAttributes = (NSDictionary*) CFBridgingRelease(item); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextServiceIdentifier], newServiceIdentifier, "Service Identifier exists"); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextPublicKey], newPublicKey, "public key exists"); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextPublicIdentity], newPublicIdentity, "public identity exists"); + + // Find the item record in CloudKit. Since we're using kSecAttrDeriveSyncIDFromItemAttributes, + // the record ID is likely DD7C2F9B-B22D-3B90-C299-E3B48174BFA3 + [self waitForCKModifications]; + CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName: @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[recordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + XCTAssertEqualObjects(record[SecCKRecordPCSServiceIdentifier], newServiceIdentifier, "Service identifier sent to cloudkit"); + XCTAssertEqualObjects(record[SecCKRecordPCSPublicKey], newPublicKey, "public key sent to cloudkit"); + XCTAssertEqualObjects(record[SecCKRecordPCSPublicIdentity], newPublicIdentity, "public identity sent to cloudkit"); +} + +// As of [ CKKS: Re-authenticate PCSPublicFields], these fields are NOT server-modifiable. This test proves it. +- (void)testPCSUnencryptedFieldsServerModifyFail { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecAttrAccount : @"testaccount", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding], + (id)kSecAttrDeriveSyncIDFromItemAttributes : (id)kCFBooleanTrue, + (id)kSecAttrPCSPlaintextServiceIdentifier : servIdentifier, + (id)kSecAttrPCSPlaintextPublicKey : publicKey, + (id)kSecAttrPCSPlaintextPublicIdentity : publicIdentity, + } mutableCopy]; + + XCTAssertEqual(errSecSuccess, SecItemAdd((__bridge CFDictionaryRef) query, NULL), @"SecItemAdd succeeded"); + + OCMVerifyAllWithDelay(self.mockDatabase, 4); + [self waitForCKModifications]; + + // Find the item record in CloudKit. Since we're using kSecAttrDeriveSyncIDFromItemAttributes, + // the record ID is likely DD7C2F9B-B22D-3B90-C299-E3B48174BFA3 + CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName: @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[recordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + // Items are encrypted using encv2 + XCTAssertEqualObjects(record[SecCKRecordEncryptionVersionKey], [NSNumber numberWithInteger:(int) CKKSItemEncryptionVersion2], "Uploaded using encv2"); + + if(!record) { + // Test has already failed; find the record just to be nice. + for(CKRecord* maybe in self.keychainZone.currentDatabase.allValues) { + if(maybe[SecCKRecordPCSServiceIdentifier] != nil) { + record = maybe; + } + } + } + + NSNumber* newServiceIdentifier = @10; + NSData* newPublicKey = [@"new public key" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* newPublicIdentity = [@"new public identity" dataUsingEncoding:NSUTF8StringEncoding]; + + // Change the public key and public identity + record = [record copyWithZone: nil]; + record[SecCKRecordPCSServiceIdentifier] = newServiceIdentifier; + record[SecCKRecordPCSPublicKey] = newPublicKey; + record[SecCKRecordPCSPublicIdentity] = newPublicIdentity; + [self.keychainZone addToZone: record]; + + // Trigger a notification + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + CFTypeRef item = NULL; + query[(id)kSecValueData] = nil; + query[(id)kSecAttrPCSPlaintextServiceIdentifier] = nil; + query[(id)kSecAttrPCSPlaintextPublicKey] = nil; + query[(id)kSecAttrPCSPlaintextPublicIdentity] = nil; + query[(id)kSecReturnAttributes] = @YES; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should still exist"); + + NSDictionary* itemAttributes = (NSDictionary*) CFBridgingRelease(item); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextServiceIdentifier], servIdentifier, "service identifier is not updated"); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextPublicKey], publicKey, "public key not updated"); + XCTAssertEqualObjects(itemAttributes[(id)kSecAttrPCSPlaintextPublicIdentity], publicIdentity, "public identity not updated"); +} + +-(void)testPCSUnencryptedFieldsRecieveUnauthenticatedFields { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + NSError* error = nil; + + // Manually encrypt an item + NSString* recordName = @"7B598D31-F9C5-481E-98AC-5A507ACB2D85"; + CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName:recordName zoneID:self.keychainZoneID]; + NSDictionary* item = [self fakeRecordDictionary: @"account-delete-me" zoneID:self.keychainZoneID]; + CKKSItem* cipheritem = [[CKKSItem alloc] initWithUUID:recordID.recordName + parentKeyUUID:self.keychainZoneKeys.classC.uuid + zoneID:recordID.zoneID]; + CKKSKey* itemkey = [CKKSKey randomKeyWrappedByParent: self.keychainZoneKeys.classC error:&error]; + XCTAssertNotNil(itemkey, "Got a key"); + cipheritem.wrappedkey = itemkey.wrappedkey; + XCTAssertNotNil(cipheritem.wrappedkey, "Got a wrapped key"); + + cipheritem.encver = CKKSItemEncryptionVersion1; + + // This item has the PCS public fields, but they are not authenticated + cipheritem.plaintextPCSServiceIdentifier = servIdentifier; + cipheritem.plaintextPCSPublicKey = publicKey; + cipheritem.plaintextPCSPublicIdentity = publicIdentity; + + NSDictionary* authenticatedData = [cipheritem makeAuthenticatedDataDictionaryUpdatingCKKSItem: nil encryptionVersion:CKKSItemEncryptionVersion1]; + cipheritem.encitem = [CKKSItemEncrypter encryptDictionary:item key:itemkey.aessivkey authenticatedData:authenticatedData error:&error]; + XCTAssertNil(error, "no error encrypting object"); + XCTAssertNotNil(cipheritem.encitem, "Recieved ciphertext"); + + [self.keychainZone addToZone:[cipheritem CKRecordWithZoneID: recordID.zoneID]]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + NSDictionary* query = @{(id)kSecClass: (id)kSecClassGenericPassword, + (id)kSecReturnAttributes: @YES, + (id)kSecAttrSynchronizable: @YES, + (id)kSecAttrAccount: @"account-delete-me", + (id)kSecMatchLimit: (id)kSecMatchLimitOne, + }; + CFTypeRef cfresult = NULL; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &cfresult), "Found synced item"); + + NSDictionary* result = CFBridgingRelease(cfresult); + XCTAssertEqualObjects(result[(id)kSecAttrPCSPlaintextServiceIdentifier], servIdentifier, "Received PCS service identifier"); + XCTAssertEqualObjects(result[(id)kSecAttrPCSPlaintextPublicKey], publicKey, "Received PCS public key"); + XCTAssertEqualObjects(result[(id)kSecAttrPCSPlaintextPublicIdentity], publicIdentity, "Received PCS public identity"); +} + +-(void)testPCSUnencryptedFieldsRecieveAuthenticatedFields { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + NSError* error = nil; + + // Manually encrypt an item + NSString* recordName = @"7B598D31-F9C5-481E-98AC-5A507ACB2D85"; + CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName:recordName zoneID:self.keychainZoneID]; + NSDictionary* item = [self fakeRecordDictionary: @"account-delete-me" zoneID:self.keychainZoneID]; + CKKSItem* cipheritem = [[CKKSItem alloc] initWithUUID:recordID.recordName + parentKeyUUID:self.keychainZoneKeys.classC.uuid + zoneID:recordID.zoneID]; + CKKSKey* itemkey = [CKKSKey randomKeyWrappedByParent: self.keychainZoneKeys.classC error:&error]; + XCTAssertNotNil(itemkey, "Got a key"); + cipheritem.wrappedkey = itemkey.wrappedkey; + XCTAssertNotNil(cipheritem.wrappedkey, "Got a wrapped key"); + + cipheritem.encver = CKKSItemEncryptionVersion2; + + // This item has the PCS public fields, and they are authenticated (since we're using v2) + cipheritem.plaintextPCSServiceIdentifier = servIdentifier; + cipheritem.plaintextPCSPublicKey = publicKey; + cipheritem.plaintextPCSPublicIdentity = publicIdentity; + + // Use version 2, so PCS plaintext fields will be authenticated + NSMutableDictionary* authenticatedData = [[cipheritem makeAuthenticatedDataDictionaryUpdatingCKKSItem: nil encryptionVersion:CKKSItemEncryptionVersion2] mutableCopy]; + + cipheritem.encitem = [CKKSItemEncrypter encryptDictionary:item key:itemkey.aessivkey authenticatedData:authenticatedData error:&error]; + XCTAssertNil(error, "no error encrypting object"); + XCTAssertNotNil(cipheritem.encitem, "Recieved ciphertext"); + + [self.keychainZone addToZone:[cipheritem CKRecordWithZoneID: recordID.zoneID]]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + NSDictionary* query = @{(id)kSecClass: (id)kSecClassGenericPassword, + (id)kSecReturnAttributes: @YES, + (id)kSecAttrSynchronizable: @YES, + (id)kSecAttrAccount: @"account-delete-me", + (id)kSecMatchLimit: (id)kSecMatchLimitOne, + }; + CFTypeRef cfresult = NULL; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &cfresult), "Found synced item"); + + NSDictionary* result = CFBridgingRelease(cfresult); + XCTAssertEqualObjects(result[(id)kSecAttrPCSPlaintextServiceIdentifier], servIdentifier, "Received PCS service identifier"); + XCTAssertEqualObjects(result[(id)kSecAttrPCSPlaintextPublicKey], publicKey, "Received PCS public key"); + XCTAssertEqualObjects(result[(id)kSecAttrPCSPlaintextPublicIdentity], publicIdentity, "Received PCS public identity"); + + // Test that if this item is updated, it remains encrypted in v2 + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + [self updateGenericPassword:@"different password" account:@"account-delete-me"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 4); + [self waitForCKModifications]; + + CKRecord* newRecord = self.keychainZone.currentDatabase[recordID]; + XCTAssertEqualObjects(newRecord[SecCKRecordPCSServiceIdentifier], servIdentifier, "Didn't change service identifier"); + XCTAssertEqualObjects(newRecord[SecCKRecordPCSPublicKey], publicKey, "Didn't change public key"); + XCTAssertEqualObjects(newRecord[SecCKRecordPCSPublicIdentity], publicIdentity, "Didn't change public identity"); + XCTAssertEqualObjects(newRecord[SecCKRecordEncryptionVersionKey], [NSNumber numberWithInteger:(int) CKKSItemEncryptionVersion2], "Uploaded using encv2"); +} + +-(void)testResetLocal { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [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, 8); + + // After the local reset, we expect: a fetch, then nothing + self.silentFetchesAllowed = false; + [self expectCKFetch]; + + dispatch_semaphore_t resetSemaphore = dispatch_semaphore_create(0); + [self.injectedManager rpcResetLocal:nil reply:^(NSError* result) { + XCTAssertNil(result, "no error resetting local"); + secnotice("ckks", "Received a rpcResetLocal callback"); + dispatch_semaphore_signal(resetSemaphore); + }]; + + XCTAssertEqual(0, dispatch_semaphore_wait(resetSemaphore, 4*NSEC_PER_SEC), "Semaphore wait did not time out"); + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +-(void)testResetLocalWhileLoggedOut { + // We're "logged in to" cloudkit but not in circle. + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + self.silentFetchesAllowed = false; + + // Test starts with local TLK and key hierarhcy in our fake cloudkit + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + NSData* changeTokenData = [[[NSUUID UUID] UUIDString] dataUsingEncoding:NSUTF8StringEncoding]; + CKServerChangeToken* changeToken = [[CKServerChangeToken alloc] initWithData:changeTokenData]; + [self.keychainView dispatchSync: ^bool{ + 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"); + }]; + + dispatch_semaphore_t resetSemaphore = dispatch_semaphore_create(0); + [self.injectedManager rpcResetLocal:nil reply:^(NSError* result) { + XCTAssertNil(result, "no error resetting cloudkit"); + secnotice("ckks", "Received a rpcResetLocal callback"); + dispatch_semaphore_signal(resetSemaphore); + }]; + + XCTAssertEqual(0, dispatch_semaphore_wait(resetSemaphore, 400*NSEC_PER_SEC), "Semaphore wait did not time out"); + + [self.keychainView dispatchSync: ^bool{ + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.keychainView.zoneName]; + XCTAssertNotEqualObjects(changeToken, ckse.changeToken, "Change token is reset"); + }]; + + // Now log in, and see what happens! It should re-fetch, pick up the old key hierarchy, and use it + self.silentFetchesAllowed = true; + self.circleStatus = kSOSCCInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem:[self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +-(void)testResetCloudKitZone { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [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, 8); + + // We expect a key hierarchy upload, and then the class C item upload + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + + dispatch_semaphore_t resetSemaphore = dispatch_semaphore_create(0); + [self.injectedManager rpcResetCloudKit:nil reply:^(NSError* result) { + XCTAssertNil(result, "no error resetting cloudkit"); + secnotice("ckks", "Received a resetCloudKit callback"); + dispatch_semaphore_signal(resetSemaphore); + }]; + + XCTAssertEqual(0, dispatch_semaphore_wait(resetSemaphore, 4*NSEC_PER_SEC), "Semaphore wait did not time out"); + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +-(void)testResetCloudKitZoneWhileLoggedOut { + // We're "logged in to" cloudkit but not in circle. + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + self.silentFetchesAllowed = false; + + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"]; + [self.keychainZone addToZone: ckr]; + + XCTAssertNotNil(self.keychainZone.currentDatabase, "Zone exists"); + XCTAssertNotNil(self.keychainZone.currentDatabase[ckr.recordID], "An item exists in the fake zone"); + + dispatch_semaphore_t resetSemaphore = dispatch_semaphore_create(0); + [self.injectedManager rpcResetCloudKit:nil reply:^(NSError* result) { + XCTAssertNil(result, "no error resetting cloudkit"); + secnotice("ckks", "Received a resetCloudKit callback"); + dispatch_semaphore_signal(resetSemaphore); + }]; + + XCTAssertEqual(0, dispatch_semaphore_wait(resetSemaphore, 400*NSEC_PER_SEC), "Semaphore wait did not time out"); + + XCTAssertNil(self.keychainZone.currentDatabase, "No zone anymore!"); + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now log in, and see what happens! It should create the zone again and upload a whole new key hierarchy + self.silentFetchesAllowed = true; + self.circleStatus = kSOSCCInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem:[self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/tests/CKKSTests+Coalesce.m b/keychain/ckks/tests/CKKSTests+Coalesce.m new file mode 100644 index 00000000..7ee14611 --- /dev/null +++ b/keychain/ckks/tests/CKKSTests+Coalesce.m @@ -0,0 +1,120 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/tests/CKKSTests.h" +#import "keychain/ckks/tests/CloudKitMockXCTest.h" + +// Break abstraction. +@interface CKKSKeychainView(test) +@property NSOperationQueue* operationQueue; +@end + +@implementation CloudKitKeychainSyncingTests (CoalesceTests) +// These tests check that, if CKKS doesn't start processing an item before a new update comes in, +// each case is properly handled. + +- (void)testCoalesceAddModifyItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + NSString* account = @"account-delete-me"; + + [self addGenericPassword: @"data" account: account]; + [self updateGenericPassword: @"otherdata" account:account]; + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + OCMVerifyAllWithDelay(self.mockDatabase, 4); +} + +- (void)testCoalesceAddModifyModifyItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + NSString* account = @"account-delete-me"; + + [self addGenericPassword: @"data" account: account]; + [self updateGenericPassword: @"otherdata" account:account]; + [self updateGenericPassword: @"again" account:account]; + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + OCMVerifyAllWithDelay(self.mockDatabase, 4); +} + +- (void)testCoalesceAddModifyDeleteItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + NSString* account = @"account-delete-me"; + + [self addGenericPassword: @"data" account: account]; + [self updateGenericPassword: @"otherdata" account:account]; + [self deleteGenericPassword: account]; + + // We expect no uploads. + [self startCKKSSubsystem]; + [self.keychainView waitUntilAllOperationsAreFinished]; + OCMVerifyAllWithDelay(self.mockDatabase, 4); +} + +- (void)testCoalesceDeleteAddItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + NSString* account = @"account-delete-me"; + + [self addGenericPassword: @"data" account: account]; + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self startCKKSSubsystem]; + OCMVerifyAllWithDelay(self.mockDatabase, 4); + [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. + + [self.keychainView.operationQueue waitUntilAllOperationsAreFinished]; + self.keychainView.operationQueue.suspended = YES; + [self deleteGenericPassword: account]; + [self addGenericPassword: @"data" account: account]; + + [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; + OCMVerifyAllWithDelay(self.mockDatabase, 4); +} + +@end + +#endif diff --git a/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m b/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m new file mode 100644 index 00000000..f73f4c8d --- /dev/null +++ b/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m @@ -0,0 +1,751 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import +#import +#import + +#include +#include +#include + +#import "keychain/ckks/tests/CloudKitMockXCTest.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSCurrentItemPointer.h" +#import "keychain/ckks/CKKSMirrorEntry.h" + +#import "keychain/ckks/tests/MockCloudKit.h" + +#import "keychain/ckks/tests/CKKSTests.h" +#import "keychain/ckks/tests/CKKSTests+API.h" + +@implementation CloudKitKeychainSyncingTests (CurrentPointerAPITests) + +-(void)fetchCurrentPointer:(bool)cached persistentRef:(NSData*)persistentRef +{ + XCTestExpectation* currentExpectation = [self expectationWithDescription: @"callback occurs"]; + SecItemFetchCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + cached, + ^(CFDataRef currentPersistentRef, CFErrorRef cferror) { + XCTAssertNotNil((__bridge id)currentPersistentRef, "current item exists"); + XCTAssertNil((__bridge id)cferror, "no error exists when there's a current item"); + XCTAssertEqualObjects(persistentRef, (__bridge id)currentPersistentRef, "persistent ref matches expected persistent ref"); + [currentExpectation fulfill]; + }); + [self waitForExpectationsWithTimeout:8.0 handler:nil]; +} +-(void)fetchCurrentPointerExpectingError:(bool)cached +{ + XCTestExpectation* currentExpectation = [self expectationWithDescription: @"callback occurs"]; + SecItemFetchCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + cached, + ^(CFDataRef currentPersistentRef, CFErrorRef cferror) { + XCTAssertNil((__bridge id)currentPersistentRef, "no current item exists"); + XCTAssertNotNil((__bridge id)cferror, "Error exists when there's a current item"); + [currentExpectation fulfill]; + }); + [self waitForExpectationsWithTimeout:8.0 handler:nil]; +} + +- (void)testPCSFetchCurrentPointerCachedAndUncached { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + [self.keychainView waitForKeyHierarchyReadiness]; + + // Ensure that local queries don't hit the server. + self.silentFetchesAllowed = false; + [self fetchCurrentPointerExpectingError:false]; + + // And ensure that global queries do. + [self expectCKFetch]; + [self fetchCurrentPointerExpectingError:true]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + SecResetLocalSecuritydXPCFakeEntitlements(); +} + +- (void)testPCSCurrentPointerAddAndUpdate { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + // Let things shake themselves out. + [self.keychainView waitForKeyHierarchyReadiness]; + + // Ensure there's no current pointer + [self fetchCurrentPointerExpectingError:false]; + + XCTestExpectation* keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + NSDictionary* result = [self pcsAddItem:@"testaccount" + data:[@"asdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:(NSNumber*)servIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:true]; + XCTAssertNotNil(result, "Received result from adding item"); + [self waitForExpectations:@[keychainChanged] timeout:1]; + + // Check that the record is where we expect it in CloudKit + [self waitForCKModifications]; + CKRecordID* pcsItemRecordID = [[CKRecordID alloc] initWithRecordName: @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[pcsItemRecordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + NSData* persistentRef = result[(id)kSecValuePersistentRef]; + NSData* sha1 = result[(id)kSecAttrSHA1]; + + [self expectCKModifyRecords:@{SecCKRecordCurrentItemType: [NSNumber numberWithUnsignedInteger: 1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord:nil + runAfterModification:nil]; + + // Set the 'current' pointer. + XCTestExpectation* setCurrentExpectation = [self expectationWithDescription: @"callback occurs"]; + + // Ensure that setting the current pointer sends a notification + keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName]; + + SecItemSetCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + (__bridge CFDataRef)persistentRef, + (__bridge CFDataRef)sha1, NULL, NULL, ^ (CFErrorRef cferror) { + NSError* error = (__bridge NSError*)cferror; + XCTAssertNil(error, "No error setting current item"); + [setCurrentExpectation fulfill]; + }); + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForExpectations:@[keychainChanged] timeout:1]; + [self waitForCKModifications]; + + [self waitForExpectationsWithTimeout:8.0 handler:nil]; + + CKRecord* currentItemPointer = self.keychainZone.currentDatabase[[[CKRecordID alloc] initWithRecordName:@"com.apple.security.ckks-pcsservice" zoneID:self.keychainZoneID]]; + XCTAssertNotNil(currentItemPointer, "Found a CKRecord at the expected location in CloudKit"); + XCTAssertEqualObjects(currentItemPointer.recordType, SecCKRecordCurrentItemType, "Saved CKRecord is correct type"); + XCTAssertEqualObjects(((CKReference*)currentItemPointer[SecCKRecordItemRefKey]).recordID, pcsItemRecordID, "Current Item record points to correct record"); + + // Check that the status APIs return the right value + [self fetchCurrentPointer:false persistentRef:persistentRef]; + + // Rad. If we got here, adding a new current item pointer works. Let's see if we can modify one. + keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + result = [self pcsAddItem:@"tOTHER-ITEM" + data:[@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:(NSNumber*)servIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:true]; + XCTAssertNotNil(result, "Received result from adding item"); + [self waitForExpectations:@[keychainChanged] timeout:1]; + + // Check that the record is where we expect it + [self waitForCKModifications]; + CKRecordID* pcsOtherItemRecordID = [[CKRecordID alloc] initWithRecordName: @"878BEAA6-1EE9-1079-1025-E6832AC8F2F3" zoneID:self.keychainZoneID]; + CKRecord* recordOther = self.keychainZone.currentDatabase[pcsOtherItemRecordID]; + XCTAssertNotNil(recordOther, "Found other record in CloudKit at expected UUID"); + + NSData* otherPersistentRef = result[(id)kSecValuePersistentRef]; + NSData* otherSha1 = result[(id)kSecAttrSHA1]; + + // change the 'current' pointer. + + // Refetch the old item's hash, just in case it's changed (it does, about 50% of the time. I'm not sure why). + CFTypeRef cfresult = NULL; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) @{ + (id)kSecValuePersistentRef : persistentRef, + (id)kSecReturnAttributes : @YES, + }, &cfresult), "Found original item by persistent reference"); + + XCTAssertNotNil((__bridge id)cfresult, "Received an item by finding persistent reference"); + NSData* actualSHA1 = CFBridgingRelease(CFRetainSafe(CFDictionaryGetValue(cfresult, kSecAttrSHA1))); + XCTAssertNotNil(actualSHA1, "Have a SHA1 for the original item"); + CFReleaseNull(cfresult); + + if(![actualSHA1 isEqual:sha1]) { + secnotice("ckks", "SHA1s don't match, but why?"); + } + + XCTestExpectation* otherSetCurrentExpectation = [self expectationWithDescription: @"callback occurs"]; + + [self expectCKModifyRecords:@{SecCKRecordCurrentItemType: [NSNumber numberWithUnsignedInteger: 1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord:nil + runAfterModification:nil]; + + // Ensure that setting the current pointer sends a notification + keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName]; + + SecItemSetCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + (__bridge CFDataRef)otherPersistentRef, + (__bridge CFDataRef)otherSha1, + (__bridge CFDataRef)persistentRef, + (__bridge CFDataRef)actualSHA1, ^ (CFErrorRef cferror) { + NSError* error = (__bridge NSError*)cferror; + XCTAssertNil(error, "No error setting current item"); + [otherSetCurrentExpectation fulfill]; + }); + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForExpectations:@[keychainChanged] timeout:1]; + [self waitForCKModifications]; + + [self waitForExpectationsWithTimeout:8.0 handler:nil]; + + currentItemPointer = self.keychainZone.currentDatabase[[[CKRecordID alloc] initWithRecordName:@"com.apple.security.ckks-pcsservice" zoneID:self.keychainZoneID]]; + XCTAssertNotNil(currentItemPointer, "Found a CKRecord at the expected location in CloudKit"); + XCTAssertEqualObjects(currentItemPointer.recordType, SecCKRecordCurrentItemType, "Saved CKRecord is correct type"); + XCTAssertEqualObjects(((CKReference*)currentItemPointer[SecCKRecordItemRefKey]).recordID, pcsOtherItemRecordID, "Current Item record points to updated record"); + + // And: again + [self fetchCurrentPointer:false persistentRef:otherPersistentRef]; + [self fetchCurrentPointer:true persistentRef:otherPersistentRef]; + + SecResetLocalSecuritydXPCFakeEntitlements(); +} + +- (void)testPCSCurrentPointerAddNoCloudKitAccount { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + // Entirely signed out of iCloud. all current record writes should fail. + self.accountStatus = CKAccountStatusNoAccount; + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + self.silentFetchesAllowed = false; + [self startCKKSSubsystem]; + + // Ensure there's no current pointer + [self fetchCurrentPointerExpectingError:false]; + + // Should NOT add an item to CloudKit + NSDictionary* result = [self pcsAddItem:@"testaccount" + data:[@"asdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:(NSNumber*)servIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:false]; + XCTAssertNotNil(result, "Received result from adding item"); + + NSData* persistentRef = result[(id)kSecValuePersistentRef]; + NSData* sha1 = result[(id)kSecAttrSHA1]; + + // Set the 'current' pointer. This should fail. + XCTestExpectation* setCurrentExpectation = [self expectationWithDescription: @"callback occurs"]; + + SecItemSetCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + (__bridge CFDataRef)persistentRef, + (__bridge CFDataRef)sha1, NULL, NULL, ^ (CFErrorRef cferror) { + NSError* error = (__bridge NSError*)cferror; + XCTAssertNotNil(error, "Error setting current item with no CloudKit account"); + [setCurrentExpectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:8.0 handler:nil]; + SecResetLocalSecuritydXPCFakeEntitlements(); +} + +- (void)testPCSCurrentPointerAddNonSyncItem { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + NSMutableDictionary* query = [self pcsAddItemQuery:@"account" + data:[@"asdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:servIdentifier + publicKey:publicKey + publicIdentity:publicIdentity]; + query[(id)kSecAttrSynchronizable] = @NO; + + CFTypeRef cfresult = NULL; + XCTestExpectation* syncExpectation = [self expectationWithDescription: @"_SecItemAddAndNotifyOnSync callback occured"]; + + // Note that you will NOT receive a notification here, since you're adding a nonsync item + syncExpectation.inverted = YES; + + XCTAssertEqual(errSecSuccess, _SecItemAddAndNotifyOnSync((__bridge CFDictionaryRef) query, &cfresult, ^(bool didSync, CFErrorRef error) { + XCTAssertFalse(didSync, "Item did not sync"); + XCTAssertNotNil((__bridge NSError*)error, "Error syncing item"); + + [syncExpectation fulfill]; + }), @"_SecItemAddAndNotifyOnSync succeeded"); + + // We don't expect this callback to fire, so give it a second or so + [self waitForExpectations:@[syncExpectation] timeout:2.0]; + + NSDictionary* result = CFBridgingRelease(cfresult); + + XCTAssertNotNil(result, "Received result from adding item"); + + NSData* persistentRef = result[(id)kSecValuePersistentRef]; + NSData* sha1 = result[(id)kSecAttrSHA1]; + + // Set the 'current' pointer. This should fail. + XCTestExpectation* setCurrentExpectation = [self expectationWithDescription: @"callback occurs"]; + + SecItemSetCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + (__bridge CFDataRef)persistentRef, + (__bridge CFDataRef)sha1, NULL, NULL, ^ (CFErrorRef cferror) { + NSError* error = (__bridge NSError*)cferror; + XCTAssertNotNil(error, "Error setting current item to nonsyncable item"); + [setCurrentExpectation fulfill]; + }); + + [self waitForExpectations:@[setCurrentExpectation] timeout:8.0]; + SecResetLocalSecuritydXPCFakeEntitlements(); +} + +- (void)testPCSCurrentPointerReceive { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + // Let things shake themselves out. + [self.keychainView waitForKeyHierarchyReadiness]; + + // Ensure there's no current pointer + [self fetchCurrentPointerExpectingError:false]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + XCTestExpectation* keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName]; + + NSDictionary* result = [self pcsAddItem:@"testaccount" + data:[@"asdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:(NSNumber*)servIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:true]; + XCTAssertNotNil(result, "Received result from adding item"); + NSData* persistentRef = result[(id)kSecValuePersistentRef]; + + [self waitForExpectations:@[keychainChanged] timeout:1]; + + // Check that the record is where we expect it in CloudKit + [self waitForCKModifications]; + CKRecordID* pcsItemRecordID = [[CKRecordID alloc] initWithRecordName: @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[pcsItemRecordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + // Still no current pointer. + [self fetchCurrentPointerExpectingError:false]; + + // Another machine comes along and updates the pointer! + CKKSCurrentItemPointer* cip = [[CKKSCurrentItemPointer alloc] initForIdentifier:@"com.apple.security.ckks-pcsservice" + currentItemUUID:@"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" + state:SecCKKSProcessedStateRemote + zoneID:self.keychainZoneID + encodedCKRecord:nil]; + [self.keychainZone addToZone: [cip CKRecordWithZoneID:self.keychainZoneID]]; + CKRecordID* currentPointerRecordID = [[CKRecordID alloc] initWithRecordName: @"com.apple.security.ckks-pcsservice" zoneID:self.keychainZoneID]; + CKRecord* currentPointerRecord = self.keychainZone.currentDatabase[currentPointerRecordID]; + XCTAssertNotNil(currentPointerRecord, "Found record in CloudKit at expected UUID"); + + // Ensure that receiving the current item pointer generates a notification + keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName]; + + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + [self waitForExpectations:@[keychainChanged] timeout:1]; + + [self fetchCurrentPointer:false persistentRef:persistentRef]; + + SecResetLocalSecuritydXPCFakeEntitlements(); +} + + +- (void)testPCSCurrentPointerReceiveDelete { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + // Let things shake themselves out. + [self.keychainView waitForKeyHierarchyReadiness]; + + // Ensure there's no current pointer + [self fetchCurrentPointerExpectingError:false]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + NSDictionary* result = [self pcsAddItem:@"testaccount" + data:[@"asdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:(NSNumber*)servIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:true]; + XCTAssertNotNil(result, "Received result from adding item"); + NSData* persistentRef = result[(id)kSecValuePersistentRef]; + + // Check that the record is where we expect it in CloudKit + [self waitForCKModifications]; + CKRecordID* pcsItemRecordID = [[CKRecordID alloc] initWithRecordName: @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[pcsItemRecordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + // Still no current pointer. + [self fetchCurrentPointerExpectingError:false]; + + // Another machine comes along and updates the pointer! + CKKSCurrentItemPointer* cip = [[CKKSCurrentItemPointer alloc] initForIdentifier:@"com.apple.security.ckks-pcsservice" + currentItemUUID:@"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" + state:SecCKKSProcessedStateRemote + zoneID:self.keychainZoneID + encodedCKRecord:nil]; + [self.keychainZone addToZone: [cip CKRecordWithZoneID:self.keychainZoneID]]; + CKRecordID* currentPointerRecordID = [[CKRecordID alloc] initWithRecordName: @"com.apple.security.ckks-pcsservice" zoneID:self.keychainZoneID]; + CKRecord* currentPointerRecord = self.keychainZone.currentDatabase[currentPointerRecordID]; + XCTAssertNotNil(currentPointerRecord, "Found record in CloudKit at expected UUID"); + + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + [self fetchCurrentPointer:false persistentRef:persistentRef]; + + // Ensure that receiving the current item pointer generates a notification + XCTestExpectation* keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName]; + + // Another machine comes along and deletes the pointer! + [self.keychainZone deleteCKRecordIDFromZone: currentPointerRecordID]; + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + [self waitForExpectations:@[keychainChanged] timeout:1]; + + [self fetchCurrentPointerExpectingError:false]; + + SecResetLocalSecuritydXPCFakeEntitlements(); +} + + +- (void)testPCSCurrentPointerRecoverFromRecordExistsError { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + // Let things shake themselves out. + [self.keychainView waitForKeyHierarchyReadiness]; + + // Ensure there's no current pointer + [self fetchCurrentPointerExpectingError:false]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + NSDictionary* result = [self pcsAddItem:@"testaccount" + data:[@"asdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:(NSNumber*)servIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:true]; + XCTAssertNotNil(result, "Received result from adding item"); + + // Check that the record is where we expect it in CloudKit + [self waitForCKModifications]; + NSString* recordUUID = @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3"; + CKRecordID* pcsItemRecordID = [[CKRecordID alloc] initWithRecordName:recordUUID zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[pcsItemRecordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + // Someone else sets the current record pointer + CKKSCurrentItemPointer* cip = [[CKKSCurrentItemPointer alloc] initForIdentifier:@"com.apple.security.ckks-pcsservice" + currentItemUUID:recordUUID + state:SecCKKSProcessedStateRemote + zoneID:self.keychainZoneID + encodedCKRecord:nil]; + XCTAssertNotNil(cip, "Should have created a CIP"); + CKRecord* cipRecord = [cip CKRecordWithZoneID:self.keychainZoneID]; + XCTAssertNotNil(cipRecord, "Should have created a CKRecord for this CIP"); + [self.keychainZone addToZone: cipRecord]; + + NSData* persistentRef = result[(id)kSecValuePersistentRef]; + NSData* sha1 = result[(id)kSecAttrSHA1]; + + [self expectCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID]; + + // Set the 'current' pointer. + XCTestExpectation* setCurrentExpectation = [self expectationWithDescription: @"callback occurs"]; + + SecItemSetCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + (__bridge CFDataRef)persistentRef, + (__bridge CFDataRef)sha1, NULL, NULL, ^ (CFErrorRef cferror) { + NSError* error = (__bridge NSError*)cferror; + XCTAssertNotNil(error, "Should have received an error setting current item (because of conflict)"); + [setCurrentExpectation fulfill]; + }); + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForCKModifications]; + [self waitForExpectationsWithTimeout:8.0 handler:nil]; + + [self.keychainView waitUntilAllOperationsAreFinished]; + + [self fetchCurrentPointer:false persistentRef:persistentRef]; + + SecResetLocalSecuritydXPCFakeEntitlements(); +} + +- (void)testPCSCurrentPointerWasCurrent { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + // Let things shake themselves out. + [self.keychainView waitForKeyHierarchyReadiness]; + + // Ensure there's no current pointer + [self fetchCurrentPointerExpectingError:false]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + NSDictionary* result = [self pcsAddItem:@"testaccount" + data:[@"asdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:(NSNumber*)servIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:true]; + XCTAssertNotNil(result, "Received result from adding item"); + + // Check that the record is where we expect it in CloudKit + [self waitForCKModifications]; + CKRecordID* pcsItemRecordID = [[CKRecordID alloc] initWithRecordName: @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[pcsItemRecordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + NSData* persistentRef = result[(id)kSecValuePersistentRef]; + NSData* sha1 = result[(id)kSecAttrSHA1]; + + [self expectCKModifyRecords:@{SecCKRecordCurrentItemType: [NSNumber numberWithUnsignedInteger: 1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord:nil + runAfterModification:nil]; + + // Set the 'current' pointer. + XCTestExpectation* setCurrentExpectation = [self expectationWithDescription: @"callback occurs"]; + + SecItemSetCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + (__bridge CFDataRef)persistentRef, + (__bridge CFDataRef)sha1, NULL, NULL, ^ (CFErrorRef cferror) { + NSError* error = (__bridge NSError*)cferror; + XCTAssertNil(error, "No error setting current item"); + [setCurrentExpectation fulfill]; + }); + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForExpectationsWithTimeout:8.0 handler:nil]; + [self waitForCKModifications]; + + // Set the 'was current' flag on the record + CKRecord* modifiedRecord = [record copy]; + modifiedRecord[SecCKRecordServerWasCurrent] = [NSNumber numberWithInteger:10]; + [self.keychainZone addToZone:modifiedRecord]; + + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + // Check that the number is on the CKKSMirrorEntry + [self.keychainView dispatchSync: ^bool { + NSError* error = nil; + CKKSMirrorEntry* ckme = [CKKSMirrorEntry fromDatabase:@"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID error:&error]; + + XCTAssertNil(error, "no error fetching ckme"); + XCTAssertNotNil(ckme, "Received a ckme"); + + XCTAssertEqual(ckme.wasCurrent, 10u, "Properly received wasCurrent"); + + return true; + }]; +} + +-(void)testPCSCurrentPointerWriteFailure { + SecResetLocalSecuritydXPCFakeEntitlements(); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSPlaintextFields, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSWriteCurrentItemPointers, kCFBooleanTrue); + SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateCKKSReadCurrentItemPointers, kCFBooleanTrue); + + NSNumber* servIdentifier = @3; + NSData* publicKey = [@"asdfasdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSData* publicIdentity = [@"somedata" dataUsingEncoding:NSUTF8StringEncoding]; + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + // Let things shake themselves out. + [self.keychainView waitForKeyHierarchyReadiness]; + + // Ensure there's no current pointer + [self fetchCurrentPointerExpectingError:false]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkPCSFieldsBlock:self.keychainZoneID + PCSServiceIdentifier:(NSNumber *)servIdentifier + PCSPublicKey:publicKey + PCSPublicIdentity:publicIdentity]]; + + NSDictionary* result = [self pcsAddItem:@"testaccount" + data:[@"asdf" dataUsingEncoding:NSUTF8StringEncoding] + serviceIdentifier:(NSNumber*)servIdentifier + publicKey:(NSData*)publicKey + publicIdentity:(NSData*)publicIdentity + expectingSync:true]; + XCTAssertNotNil(result, "Received result from adding item"); + + // Check that the record is where we expect it in CloudKit + [self waitForCKModifications]; + CKRecordID* pcsItemRecordID = [[CKRecordID alloc] initWithRecordName: @"DD7C2F9B-B22D-3B90-C299-E3B48174BFA3" zoneID:self.keychainZoneID]; + CKRecord* record = self.keychainZone.currentDatabase[pcsItemRecordID]; + XCTAssertNotNil(record, "Found record in CloudKit at expected UUID"); + + NSData* persistentRef = result[(id)kSecValuePersistentRef]; + NSData* sha1 = result[(id)kSecAttrSHA1]; + + [self failNextCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID]; + + // Set the 'current' pointer. + XCTestExpectation* setCurrentExpectation = [self expectationWithDescription: @"callback occurs"]; + + SecItemSetCurrentItemAcrossAllDevices((__bridge CFStringRef)@"com.apple.security.ckks", + (__bridge CFStringRef)@"pcsservice", + (__bridge CFStringRef)@"keychain", + (__bridge CFDataRef)persistentRef, + (__bridge CFDataRef)sha1, NULL, NULL, ^ (CFErrorRef cferror) { + NSError* error = (__bridge NSError*)cferror; + XCTAssertNotNil(error, "Error setting current item when the write fails"); + [setCurrentExpectation fulfill]; + }); + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self waitForExpectationsWithTimeout:8.0 handler:nil]; + + SecResetLocalSecuritydXPCFakeEntitlements(); +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/tests/CKKSTests.h b/keychain/ckks/tests/CKKSTests.h new file mode 100644 index 00000000..8fe3be4f --- /dev/null +++ b/keychain/ckks/tests/CKKSTests.h @@ -0,0 +1,53 @@ +/* + * 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 +#import +#import + +#include + +#import "keychain/ckks/tests/CloudKitMockXCTest.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" +#import "keychain/ckks/CKKSManifest.h" +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/tests/MockCloudKit.h" + +// 1 master manifest, 72 manifest leaf nodes = 73 +// 3 keys, 3 current keys, and 1 device state entry +#define SYSTEM_DB_RECORD_COUNT (7 + ([CKKSManifest shouldSyncManifests] ? 73 : 0)) + +@interface CloudKitKeychainSyncingTestsBase : CloudKitKeychainSyncingMockXCTest +@property CKRecordZoneID* keychainZoneID; +@property CKKSKeychainView* keychainView; +@property FakeCKZone* keychainZone; + +@property (readonly) ZoneKeys* keychainZoneKeys; + +- (ZoneKeys*)keychainZoneKeys; +@end + +@interface CloudKitKeychainSyncingTests : CloudKitKeychainSyncingTestsBase +@end + diff --git a/keychain/ckks/tests/CKKSTests.m b/keychain/ckks/tests/CKKSTests.m new file mode 100644 index 00000000..1f946199 --- /dev/null +++ b/keychain/ckks/tests/CKKSTests.m @@ -0,0 +1,2790 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "CKKSTests.h" +#import +#import +#import +#import + +#include + +#import "keychain/ckks/tests/CloudKitMockXCTest.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSControlProtocol.h" +#import "keychain/ckks/CKKSCurrentKeyPointer.h" +#import "keychain/ckks/CKKSItemEncrypter.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSIncomingQueueEntry.h" +#import "keychain/ckks/CKKSSynchronizeOperation.h" +#import "keychain/ckks/CKKSViewManager.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" +#import "keychain/ckks/CKKSManifest.h" +#import "keychain/ckks/CKKSAnalyticsLogger.h" +#import "keychain/ckks/CKKSHealKeyHierarchyOperation.h" +#import "keychain/ckks/CKKSZoneChangeFetcher.h" + +#import "keychain/ckks/tests/MockCloudKit.h" + +#import "keychain/ckks/tests/CKKSTests.h" + +@implementation CloudKitKeychainSyncingTestsBase + +- (ZoneKeys*)keychainZoneKeys { + return self.keys[self.keychainZoneID]; +} + +// Override our base class +-(NSSet*)managedViewList { + return [NSSet setWithObject:@"keychain"]; +} + ++ (void)setUp { + SecCKKSEnable(); + SecCKKSResetSyncing(); + [super setUp]; +} + +- (void)setUp { + [super setUp]; + + self.keychainZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"keychain" ownerName:CKCurrentUserDefaultName]; + self.keychainZone = [[FakeCKZone alloc] initZone: self.keychainZoneID]; + + SFECKeyPair* keyPair = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; + [CKKSManifestInjectionPointHelper registerEgoPeerID:@"MeMyselfAndI" keyPair:keyPair]; + + // Wait for the ViewManager to be brought up + XCTAssertEqual(0, [self.injectedManager.completedSecCKKSInitialize wait:4*NSEC_PER_SEC], "No timeout waiting for SecCKKSInitialize"); + + self.keychainView = [[CKKSViewManager manager] findView:@"keychain"]; + XCTAssertNotNil(self.keychainView, "CKKSViewManager created the keychain view"); + + // Check that your environment is set up correctly + XCTAssertFalse([CKKSManifest shouldSyncManifests], "Manifests syncing is disabled"); + XCTAssertFalse([CKKSManifest shouldEnforceManifests], "Manifests enforcement is disabled"); +} + ++ (void)tearDown { + [super tearDown]; + SecCKKSResetSyncing(); +} + +- (void)tearDown { + // Fetch status, to make sure we can + NSDictionary* status = [self.keychainView status]; + (void)status; + + self.keychainView = nil; + self.keychainZoneID = nil; + + [super tearDown]; +} + +- (FakeCKZone*)keychainZone { + return self.zones[self.keychainZoneID]; +} + +- (void)setKeychainZone: (FakeCKZone*) zone { + self.zones[self.keychainZoneID] = zone; +} + +@end + +@implementation CloudKitKeychainSyncingTests + +#pragma mark - Tests + +- (void)testAddItem { + [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, 8); +} + +- (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, 8); + + NSDictionary* tlks = [[CKKSViewManager manager] activeTLKs]; + + XCTAssertEqual([tlks count], (NSUInteger)1, "One TLK"); + XCTAssertNotNil(tlks[@"keychain"], "keychain have a UUID"); +} + + +- (void)testAddMultipleItems { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me-2"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me-3"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testAddItemWithoutUUID { + // Test starts with no keys in database, a key hierarchy in our fake CloudKit, and the TLK safely in the local keychain. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + [self startCKKSSubsystem]; + + [self.keychainView waitUntilAllOperationsAreFinished]; + + 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]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testModifyItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + NSString* account = @"account-delete-me"; + + [self startCKKSSubsystem]; + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // And then modified. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self updateGenericPassword: @"otherdata" account:account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testModifyItemImmediately { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + NSString* account = @"account-delete-me"; + + [self startCKKSSubsystem]; + [self holdCloudKitModifications]; + + // We expect a single record to be uploaded, but need to hold the operation from finishing until we can modify the item locally + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"data"]]; + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Right now, the write in CloudKit is pending. Make the local modification... + [self updateGenericPassword: @"otherdata" account:account]; + + // And then schedule the update + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"otherdata"]]; + [self releaseCloudKitModificationHold]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testModifyItemPrimaryKey { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + NSString* account = @"account-delete-me"; + + [self startCKKSSubsystem]; + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // And then modified. Since we're changing the "primary key", we expect to delete the old record and upload a new one. + [self expectCKModifyItemRecords:1 deletedRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:nil]; + [self updateAccountOfGenericPassword: @"new-account-delete-me" account:account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testModifyItemDuringReencrypt { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + NSString* account = @"account-delete-me"; + + [self startCKKSSubsystem]; + [self holdCloudKitModifications]; + + // We expect a single record to be uploaded, but need to hold the operation from finishing until we can modify the item locally + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"data"]]; + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Right now, the write in CloudKit is pending. Make the local modification... + [self updateGenericPassword: @"otherdata" account:account]; + + // And then schedule the update, but for the final version of the password + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"third"]]; + + // Stop the reencrypt operation from happening + self.keychainView.holdReencryptOutgoingItemsOperation = [CKKSGroupOperation named:@"reencrypt-hold" withBlock: ^{ + secnotice("ckks", "releasing reencryption hold"); + }]; + + // The cloudkit operation finishes, letting the next OQO proceed (and set up the reencryption operation) + [self releaseCloudKitModificationHold]; + + // And wait for this to finish... + [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]]; + // And once more to quiesce. + [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]]; + + // 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"); + }]; + + [self updateGenericPassword: @"third" account:account]; + + // Run the reencrypt items operation to completion. + [self.operationQueue addOperation: self.keychainView.holdReencryptOutgoingItemsOperation]; + [self.keychainView waitForOperationsOfClass:[CKKSReencryptOutgoingItemsOperation class]]; + + [self.operationQueue addOperation: self.keychainView.holdOutgoingQueueOperation]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self.keychainView waitUntilAllOperationsAreFinished]; + [self waitForCKModifications]; +} + +- (void)testModifyItemBeforeReencrypt { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + NSString* account = @"account-delete-me"; + + [self startCKKSSubsystem]; + [self holdCloudKitModifications]; + + // We expect a single record to be uploaded, but need to hold the operation from finishing until we can modify the item locally + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"data"]]; + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Right now, the write in CloudKit is pending. Make the local modification... + [self updateGenericPassword: @"otherdata" account:account]; + + // And then schedule the update, but for the final version of the password + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"third"]]; + + // Stop the reencrypt operation from happening + self.keychainView.holdReencryptOutgoingItemsOperation = [CKKSGroupOperation named:@"reencrypt-hold" withBlock: ^{ + secnotice("ckks", "releasing reencryption hold"); + }]; + + // The cloudkit operation finishes, letting the next OQO proceed (and set up the reencryption operation) + [self releaseCloudKitModificationHold]; + + // And wait for this to finish... + [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]]; + // And once more to quiesce. + [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]]; + + [self updateGenericPassword: @"third" account:account]; + + // Item should upload. + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Run the reencrypt items operation to completion. + [self.operationQueue addOperation: self.keychainView.holdReencryptOutgoingItemsOperation]; + [self.keychainView waitForOperationsOfClass:[CKKSReencryptOutgoingItemsOperation class]]; + + [self.keychainView waitUntilAllOperationsAreFinished]; + [self waitForCKModifications]; +} + +- (void)testModifyItemDuringNetworkFailure { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + NSString* account = @"account-delete-me"; + + [self startCKKSSubsystem]; + [self holdCloudKitModifications]; + + // We expect a single record to be uploaded, but need to hold the operation from finishing until we can modify the item locally + [self failNextCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID]; + + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Right now, the write in CloudKit is pending. Make the local modification... + [self updateGenericPassword: @"otherdata" account:account]; + + // And then schedule the update, but for the final version of the password + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"otherdata"]]; + + // The cloudkit operation finishes, letting the next OQO proceed (and set up uploading the new item) + [self releaseCloudKitModificationHold]; + + // Item should upload. + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self.keychainView waitUntilAllOperationsAreFinished]; + [self waitForCKModifications]; +} + +- (void)testDeleteItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [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, 8); + + // We expect a single record to be deleted. + [self expectCKDeleteItemRecords: 1 zoneID:self.keychainZoneID]; + [self deleteGenericPassword:@"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testDeleteItemImmediatelyAfterModify { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + NSString* account = @"account-delete-me"; + + [self startCKKSSubsystem]; + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now, hold the modify + [self holdCloudKitModifications]; + + // We expect a single record to be uploaded, but need to hold the operation from finishing until we can modify the item locally + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"otherdata"]]; + + [self updateGenericPassword: @"otherdata" account:account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Right now, the write in CloudKit is pending. Make the local deletion... + [self deleteGenericPassword:account]; + + // And then schedule the update + [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID]; + [self releaseCloudKitModificationHold]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testDeleteItemAfterFetchAfterModify { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + NSString* account = @"account-delete-me"; + + [self startCKKSSubsystem]; + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now, hold the modify + //[self holdCloudKitModifications]; + + // We expect a single record to be uploaded, but need to hold the operation from finishing until we can modify the item locally + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"otherdata"]]; + + [self updateGenericPassword: @"otherdata" account:account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // 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."); + }]; + 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.keychainView waitForFetchAndIncomingQueueProcessing]; + [self.operationQueue addOperation:blockOutgoing]; + [outgoingQueueOperation waitUntilFinished]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + + +- (void)testReceiveItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccount : @"account-delete-me", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitOne, + }; + + CFTypeRef item = NULL; + XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not yet exist"); + + 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]; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should exist now"); +} + +- (void)testReceiveManyItems { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D00" withAccount:@"account0"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D01" withAccount:@"account1"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D02" withAccount:@"account2"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D03" withAccount:@"account3"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D04" withAccount:@"account4"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D05" withAccount:@"account5"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D06" withAccount:@"account6"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D07" withAccount:@"account7"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D08" withAccount:@"account8"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D09" withAccount:@"account9"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D10" withAccount:@"account10"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D11" withAccount:@"account11"]]; + + // Trigger a notification (with hilariously fake data) + [self.keychainView notifyZoneChange:nil]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + [self findGenericPassword: @"account0" expecting:errSecSuccess]; + [self findGenericPassword: @"account1" expecting:errSecSuccess]; + [self findGenericPassword: @"account2" expecting:errSecSuccess]; + [self findGenericPassword: @"account3" expecting:errSecSuccess]; + [self findGenericPassword: @"account4" expecting:errSecSuccess]; + [self findGenericPassword: @"account5" expecting:errSecSuccess]; + [self findGenericPassword: @"account6" expecting:errSecSuccess]; + [self findGenericPassword: @"account7" expecting:errSecSuccess]; + [self findGenericPassword: @"account8" expecting:errSecSuccess]; + [self findGenericPassword: @"account9" expecting:errSecSuccess]; + [self findGenericPassword: @"account10" expecting:errSecSuccess]; + [self findGenericPassword: @"account11" expecting:errSecSuccess]; +} + +- (void)testReceiveCollidingItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccount : @"account-delete-me", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitOne, + }; + + CFTypeRef item = NULL; + XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not yet exist"); + + CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName: @"7B598D31-F9C5-481E-98AC-5A507ACB2D85"]; + CKRecord* ckr2 = [self createFakeRecord: self.keychainZoneID recordName: @"F9C58D31-7B59-481E-98AC-5A507ACB2D85"]; + + [self.keychainZone addToZone: ckr]; + [self.keychainZone addToZone: ckr2]; + + // We expect a delete operation with the "higher" UUID. + [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID]; + + // Trigger a notification (with hilariously fake data) + [self.keychainView notifyZoneChange:nil]; + + OCMVerifyAllWithDelay(self.mockDatabase, 6); + 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"); +} + +-(void)testReceiveItemDelete { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccount : @"account-delete-me", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitOne, + }; + + CFTypeRef item = NULL; + XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not yet exist"); + + [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.keychainView waitForFetchAndIncomingQueueProcessing]; + + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should exist now"); + CFReleaseNull(item); + + // Trigger a delete + [self.keychainZone deleteCKRecordIDFromZone: [ckr recordID]]; + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should no longer exist"); +} + +-(void)testReceiveItemPhantomDelete { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccount : @"account-delete-me", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitOne, + }; + + CFTypeRef item = NULL; + XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not yet exist"); + + [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.keychainView waitForFetchAndIncomingQueueProcessing]; + + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should exist now"); + CFReleaseNull(item); + + [self.keychainView waitUntilAllOperationsAreFinished]; + + // Trigger a delete + [self.keychainZone deleteCKRecordIDFromZone: [ckr recordID]]; + + // and add another, incorrect IQE + [self.keychainView dispatchSync: ^bool { + // Inefficient, but hey, it works + CKRecord* record = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-FFFF-FFFF-5A507ACB2D85"]; + CKKSItem* fakeItem = [[CKKSItem alloc] initWithCKRecord: record]; + + CKKSIncomingQueueEntry* iqe = [[CKKSIncomingQueueEntry alloc] initWithCKKSItem:fakeItem + action:SecCKKSActionDelete + state:SecCKKSStateNew]; + XCTAssertNotNil(iqe, "could create fake IQE"); + NSError* error = nil; + XCTAssert([iqe saveToDatabase: &error], "Saved fake IQE to database"); + XCTAssertNil(error, "No error saving fake IQE to database"); + return true; + }]; + + [self.keychainView 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 { + 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"); + }]; +} + +-(void)testReceiveConflictOnJustAddedItem { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + [self startCKKSSubsystem]; + + [self.keychainView waitUntilAllOperationsAreFinished]; + + // Place a hold on processing the outgoing queue. + CKKSResultOperation* blockOutgoing = [CKKSResultOperation operationWithBlock:^{ + secnotice("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."); + }]; + 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 { + NSError* error = nil; + NSArray* uuids = [CKKSOutgoingQueueEntry allUUIDs:&error]; + XCTAssertNil(error, "no error fetching uuids"); + XCTAssertEqual(uuids.count, 1u, "There's exactly one outgoing queue entry"); + 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.keychainView.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseTesting] waitUntilFinished]; + + // Allow the outgoing queue operation to proceed + [self.operationQueue addOperation:blockOutgoing]; + [outgoingQueueOperation waitUntilFinished]; + + // Allow the incoming queue operation to proceed + [self.operationQueue addOperation:blockIncoming]; + [incomingQueueOperation waitUntilFinished]; + + [self checkGenericPassword:@"data" account:@"account-delete-me"]; + + [self.keychainView waitUntilAllOperationsAreFinished]; +} + +-(void)testReceiveUnknownField { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + NSError* error = nil; + + // Manually encrypt an item + NSString* recordName = @"7B598D31-F9C5-481E-98AC-5A507ACB2D85"; + CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName:recordName zoneID:self.keychainZoneID]; + NSDictionary* item = [self fakeRecordDictionary: @"account-delete-me" zoneID:self.keychainZoneID]; + CKKSItem* cipheritem = [[CKKSItem alloc] initWithUUID:recordID.recordName + parentKeyUUID:self.keychainZoneKeys.classA.uuid + zoneID:recordID.zoneID]; + CKKSKey* itemkey = [CKKSKey randomKeyWrappedByParent: self.keychainZoneKeys.classA error:&error]; + XCTAssertNotNil(itemkey, "Got a key"); + cipheritem.wrappedkey = itemkey.wrappedkey; + XCTAssertNotNil(cipheritem.wrappedkey, "Got a wrapped key"); + + NSData* future_data_field = [@"asdf" dataUsingEncoding:NSUTF8StringEncoding]; + NSString* future_string_field = @"authstring"; + NSString* future_server_field = @"server_can_change_at_any_time"; + NSNumber* future_number_field = [NSNumber numberWithInt:30]; + + // Use version 2, so future fields will be authenticated + cipheritem.encver = CKKSItemEncryptionVersion2; + NSMutableDictionary* authenticatedData = [[cipheritem makeAuthenticatedDataDictionaryUpdatingCKKSItem: nil encryptionVersion:CKKSItemEncryptionVersion2] mutableCopy]; + + authenticatedData[@"future_data_field"] = future_data_field; + authenticatedData[@"future_string_field"] = [future_string_field dataUsingEncoding:NSUTF8StringEncoding]; + + uint64_t n = OSSwapHostToLittleConstInt64([future_number_field unsignedLongValue]); + authenticatedData[@"future_number_field"] = [NSData dataWithBytes:&n length:sizeof(n)]; + + + cipheritem.encitem = [CKKSItemEncrypter encryptDictionary:item key:itemkey.aessivkey authenticatedData:authenticatedData error:&error]; + XCTAssertNil(error, "no error encrypting object"); + XCTAssertNotNil(cipheritem.encitem, "Recieved ciphertext"); + + CKRecord* ckr = [cipheritem CKRecordWithZoneID: recordID.zoneID]; + ckr[@"future_data_field"] = future_data_field; + ckr[@"future_string_field"] = future_string_field; + ckr[@"future_number_field"] = future_number_field; + ckr[@"server_new_server_field"] = future_server_field; + [self.keychainZone addToZone:ckr]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + NSDictionary* query = @{(id)kSecClass: (id)kSecClassGenericPassword, + (id)kSecReturnAttributes: @YES, + (id)kSecAttrSynchronizable: @YES, + (id)kSecAttrAccount: @"account-delete-me", + (id)kSecMatchLimit: (id)kSecMatchLimitOne, + }; + CFTypeRef cfresult = NULL; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &cfresult), "Found synced item"); + + // Test that if this item is updated, it remains encrypted in v2, and future_field still exists + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self updateGenericPassword:@"different password" account:@"account-delete-me"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForCKModifications]; + + CKRecord* newRecord = self.keychainZone.currentDatabase[recordID]; + XCTAssertEqualObjects(newRecord[@"future_data_field"], future_data_field, "future_data_field still exists"); + XCTAssertEqualObjects(newRecord[@"future_string_field"], future_string_field, "future_string_field still exists"); + XCTAssertEqualObjects(newRecord[@"future_number_field"], future_number_field, "future_string_field still exists"); + XCTAssertEqualObjects(newRecord[@"server_new_server_field"], future_server_field, "future_server_field stille exists"); + + CKKSItem* newItem = [[CKKSItem alloc] initWithCKRecord:newRecord]; + CKKSAESSIVKey* newItemKey = [self.keychainZoneKeys.classA unwrapAESKey:newItem.wrappedkey error:&error]; + XCTAssertNil(error, "No error unwrapping AES key"); + XCTAssertNotNil(newItemKey, "Have an unwrapped AES key for this item"); + + NSDictionary* uploadedData = [CKKSItemEncrypter decryptDictionary:newRecord[SecCKRecordDataKey] + key:newItemKey + authenticatedData:authenticatedData + error:&error]; + XCTAssertNil(error, "No error decrypting dictionary"); + XCTAssertNotNil(uploadedData, "Authenticated re-uploaded data including future_field"); + XCTAssertEqualObjects(uploadedData[@"v_Data"], [@"different password" dataUsingEncoding:NSUTF8StringEncoding], "Passwords match"); +} + + +-(void)testReceiveRecordEncryptedv1 { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + NSError* error = nil; + + // Manually encrypt an item + NSString* recordName = @"7B598D31-F9C5-481E-98AC-5A507ACB2D85"; + CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName:recordName zoneID:self.keychainZoneID]; + NSDictionary* item = [self fakeRecordDictionary: @"account-delete-me" zoneID:self.keychainZoneID]; + CKKSItem* cipheritem = [[CKKSItem alloc] initWithUUID:recordID.recordName + parentKeyUUID:self.keychainZoneKeys.classC.uuid + zoneID:recordID.zoneID]; + CKKSKey* itemkey = [CKKSKey randomKeyWrappedByParent: self.keychainZoneKeys.classC error:&error]; + XCTAssertNotNil(itemkey, "Got a key"); + cipheritem.wrappedkey = itemkey.wrappedkey; + XCTAssertNotNil(cipheritem.wrappedkey, "Got a wrapped key"); + + cipheritem.encver = CKKSItemEncryptionVersion1; + + NSMutableDictionary* authenticatedData = [[cipheritem makeAuthenticatedDataDictionaryUpdatingCKKSItem: nil encryptionVersion:cipheritem.encver] mutableCopy]; + + cipheritem.encitem = [CKKSItemEncrypter encryptDictionary:item key:itemkey.aessivkey authenticatedData:authenticatedData error:&error]; + XCTAssertNil(error, "no error encrypting object"); + XCTAssertNotNil(cipheritem.encitem, "Recieved ciphertext"); + + [self.keychainZone addToZone:[cipheritem CKRecordWithZoneID: recordID.zoneID]]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + NSDictionary* query = @{(id)kSecClass: (id)kSecClassGenericPassword, + (id)kSecReturnAttributes: @YES, + (id)kSecAttrSynchronizable: @YES, + (id)kSecAttrAccount: @"account-delete-me", + (id)kSecMatchLimit: (id)kSecMatchLimitOne, + }; + CFTypeRef cfresult = NULL; + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &cfresult), "Found synced item"); + CFReleaseNull(cfresult); + + // Test that if this item is updated, it is encrypted in v2 + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self updateGenericPassword:@"different password" account:@"account-delete-me"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 4); + [self waitForCKModifications]; + + CKRecord* newRecord = self.keychainZone.currentDatabase[recordID]; + XCTAssertEqualObjects(newRecord[SecCKRecordEncryptionVersionKey], [NSNumber numberWithInteger:(int) CKKSItemEncryptionVersion2], "Uploaded using encv2"); +} + +- (void)testUploadPagination { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + 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]; + + OCMVerifyAllWithDelay(self.mockDatabase, 160); +} + +- (void)testUploadInitialKeyHierarchy { + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testUploadInitialKeyHierarchyAfterLockedStart { + // 'Lock' the keybag + self.aksLockState = true; + [self.lockStateTracker recheck]; + + [self startCKKSSubsystem]; + + // Wait for the key hierarchy state machine to get stuck waiting for the unlock dependency. No uploads should occur. + while(!([self.keychainView.keyStateMachineOperation isPending] && [self.keychainView.keyStateMachineOperation.dependencies containsObject:self.lockStateTracker.unlockDependency])) { + sleep(0.1); + } + + // After unlock, the key hierarchy should be created. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + self.aksLockState = false; + [self.lockStateTracker recheck]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // 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"]]; + + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testReceiveKeyHierarchyAfterLockedStart { + // 'Lock' the keybag + self.aksLockState = true; + [self.lockStateTracker recheck]; + + [self startCKKSSubsystem]; + + // Wait for the key hierarchy state machine to get stuck waiting for the unlock dependency. No uploads should occur. + while(!([self.keychainView.keyStateMachineOperation isPending] && [self.keychainView.keyStateMachineOperation.dependencies containsObject:self.lockStateTracker.unlockDependency])) { + sleep(0.1); + } + + // Now, another device comes along and creates the hierarchy; we download it; and it and sends us the TLK + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self.keychainView notifyZoneChange:nil]; + [[self.keychainView.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseTesting] waitUntilFinished]; + + self.aksLockState = false; + [self.lockStateTracker recheck]; + + // After unlock, the TLK arrives + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + // 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"]]; + + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testUploadAndUseKeyHierarchy { + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + + NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccount : @"account-delete-me", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitOne, + }; + CFTypeRef item = NULL; + XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not exist"); + + OCMVerifyAllWithDelay(self.mockDatabase, 1); + + [self waitForCKModifications]; + + // 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"]]; + + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // now, expect a single class A record to be uploaded + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + + XCTAssertEqual(errSecSuccess, SecItemAdd((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.sos", + (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, + (id)kSecAttrAccount : @"account-class-A", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding], + }, NULL), @"Adding class A item"); + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testUploadInitialKeyHierarchyTriggersBackup { + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + // We also expect the view manager's notifyNewTLKsInKeychain call to fire (after some delay) + id mockVM = OCMPartialMock(self.injectedManager); + OCMExpect([mockVM notifyNewTLKsInKeychain]); + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + OCMVerifyAllWithDelay(mockVM, 10); + + [mockVM stopMocking]; +} + +- (void)testAcceptExistingKeyHierarchy { + // Test starts with no keys in CKKS database, but one in our fake CloudKit. + // Test also begins with the TLK having arrived in the local keychain (via SOS) + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should not try to write anything to the CloudKit database while it's accepting the keys + [self.keychainView waitForKeyHierarchyReadiness]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Verify that there are three local keys, and three local current key records + __weak __typeof(self) weakSelf = self; + [self.keychainView dispatchSync: ^bool{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + NSError* error = nil; + + NSArray* keys = [CKKSKey localKeys:strongSelf.keychainZoneID error:&error]; + XCTAssertNil(error, "no error fetching keys"); + XCTAssertEqual(keys.count, 3u, "Three keys in local database"); + + NSArray* currentkeys = [CKKSCurrentKeyPointer all: &error]; + XCTAssertNil(error, "no error fetching current keys"); + XCTAssertEqual(currentkeys.count, 3u, "Three current key pointers in local database"); + + return false; + }]; +} + +- (void)testAcceptExistingAndUseKeyHierarchy { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should not try to write anything to the CloudKit database. + sleep(1); + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now, save the TLK to the keychain (to simulate it coming in later via SOS). + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // Wait for the key hierarchy to sort itself out, to make it easier on this test; see testOnboardOldItemsWithExistingKeyHierarchy for the other test. + [self.keychainView waitForKeyHierarchyReadiness]; + + // We expect a single record to be uploaded for each key class + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + XCTAssertEqual(errSecSuccess, SecItemAdd((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.sos", + (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, + (id)kSecAttrAccount : @"account-class-A", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding], + }, NULL), @"Adding class A item"); + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + + + +- (void)testAcceptExistingKeyHierarchyDespiteLocked { + // Test starts with no keys in CKKS database, but one in our fake CloudKit. + // Test also begins with the TLK having arrived in the local keychain (via SOS) + // However, the CKKSKeychainView's "checkTLK" method should return a keychain error the first time through, indicating that the keybag is locked + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + self.aksLockState = true; + [self.lockStateTracker recheck]; + + id partialKVMock = OCMPartialMock(self.keychainView); + OCMExpect([partialKVMock checkTLK: [OCMArg any] error: [OCMArg setTo:[[NSError alloc] initWithDomain:@"securityd" code:errSecInteractionNotAllowed userInfo:nil]]]).andReturn(false); + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(partialKVMock, 4); + + // Now that all operations are complete, 'unlock' AKS + self.aksLockState = false; + [self.lockStateTracker recheck]; + + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 4); + + // Verify that there are three local keys, and three local current key records + __weak __typeof(self) weakSelf = self; + [self.keychainView dispatchSync: ^bool{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + NSError* error = nil; + + NSArray* keys = [CKKSKey localKeys:strongSelf.keychainZoneID error:&error]; + XCTAssertNil(error, "no error fetching keys"); + XCTAssertEqual(keys.count, 3u, "Three keys in local database"); + + NSArray* currentkeys = [CKKSCurrentKeyPointer all: &error]; + XCTAssertNil(error, "no error fetching current keys"); + XCTAssertEqual(currentkeys.count, 3u, "Three current key pointers in local database"); + + return false; + }]; + + [partialKVMock stopMocking]; +} + +- (void)testReceiveClassCWhileALocked { + // Test starts with a key hierarchy already existing. + [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; + [self startCKKSSubsystem]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + [self.keychainView waitForKeyHierarchyReadiness]; + + [self findGenericPassword:@"classCItem" expecting:errSecItemNotFound]; + [self findGenericPassword:@"classAItem" expecting:errSecItemNotFound]; + + // 'Lock' the keybag + self.aksLockState = true; + [self.lockStateTracker recheck]; + + XCTAssertNotNil(self.keychainZoneKeys, "Have zone keys for zone"); + XCTAssertNotNil(self.keychainZoneKeys.classA, "Have class A key for zone"); + XCTAssertNotNil(self.keychainZoneKeys.classC, "Have class C key for zone"); + + [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]; + // 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"); + + CKKSResultOperation* erroringOp = [self.keychainView processIncomingQueue:true]; + [erroringOp waitUntilFinished]; + XCTAssertNotNil(erroringOp.error, "error exists while processing a class A item"); + + [self findGenericPassword:@"classCItem" expecting:errSecSuccess]; + [self findGenericPassword:@"classAItem" expecting:errSecItemNotFound]; + + self.aksLockState = false; + [self.lockStateTracker recheck]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + [self findGenericPassword:@"classCItem" expecting:errSecSuccess]; + [self findGenericPassword:@"classAItem" expecting:errSecSuccess]; +} + +- (void)testExternalKeyRoll { + // Test starts with no keys in database, a key hierarchy in our fake CloudKit, and the TLK safely in the local keychain. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should not try to write anything to the CloudKit database. + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + __weak __typeof(self) weakSelf = self; + + // 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, 8); + [self waitForCKModifications]; + + [self rollFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + // Trigger a notification + [self.keychainView notifyZoneChange:nil]; + + // Make life easy on this test; testAcceptKeyConflictAndUploadReencryptedItem will check the case when we don't receive the notification + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + // Verify that there are six local keys, and three local current key records + [self.keychainView dispatchSync: ^bool{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + NSError* error = nil; + NSArray* keys = [CKKSKey localKeys:self.keychainZoneID error:&error]; + XCTAssertNil(error, "no error fetching keys"); + XCTAssertEqual(keys.count, 6u, "Six keys in local database"); + + NSArray* currentkeys = [CKKSCurrentKeyPointer all: &error]; + XCTAssertNil(error, "no error fetching current keys"); + XCTAssertEqual(currentkeys.count, 3u, "Three current key pointers in local database"); + + for(CKKSCurrentKeyPointer* key in currentkeys) { + if([key.keyclass isEqualToString: SecCKKSKeyClassTLK]) { + XCTAssertEqualObjects(key.currentKeyUUID, strongSelf.keychainZoneKeys.tlk.uuid); + } else if([key.keyclass isEqualToString: SecCKKSKeyClassA]) { + XCTAssertEqualObjects(key.currentKeyUUID, strongSelf.keychainZoneKeys.classA.uuid); + } else if([key.keyclass isEqualToString: SecCKKSKeyClassC]) { + XCTAssertEqualObjects(key.currentKeyUUID, strongSelf.keychainZoneKeys.classC.uuid); + } else { + 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.keychainView waitForFetchAndIncomingQueueProcessing]; + + [self addGenericPassword: @"data" account: @"account-delete-me-rolled-key"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testAcceptKeyConflictAndUploadReencryptedItem { + // Test starts with no keys in database, a key hierarchy in our fake CloudKit, and the TLK safely in the local keychain. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + [self startCKKSSubsystem]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + // 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, 8); + [self waitForCKModifications]; + + [self rollFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // Do not trigger a notification here. This should cause a conflict updating the current key records + + // We expect a single record to be uploaded, but that the write will be rejected + // We then expect that item to be reuploaded with the current key + + [self expectCKAtomicModifyItemRecordsUpdateFailure: self.keychainZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me-rolled-key"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under rolled class C key in hierarchy"]]; + + // New key arrives via SOS! + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testOnboardOldItems { + // In this test, we'll check if the CKKS subsystem will pick up a keychain item which existed before the key hierarchy, both with and without a UUID attached at item creation + + // Test starts with nothing in CloudKit, and CKKS blocked. Add one item without a UUID... + + SecCKKSTestSetDisableAutomaticUUID(true); + [self addGenericPassword: @"data" account: @"account-delete-me-no-UUID" expecting:errSecSuccess message: @"Add item (no UUID) to keychain"]; + + // and an item with a UUID... + SecCKKSTestSetDisableAutomaticUUID(false); + [self addGenericPassword: @"data" account: @"account-delete-me-with-UUID" expecting:errSecSuccess message: @"Add item (w/ UUID) to keychain"]; + + // We expect an upload of the key hierarchy + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + // We then expect an upload of the added items + [self expectCKModifyItemRecords: 2 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + + +- (void)testOnboardOldItemsWithExistingKeyHierarchyExtantTLK { + // Test starts key hierarchy in our fake CloudKit, the TLK arrived in the local keychain, and CKKS blocked. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + // Add one item without a UUID... + SecCKKSTestSetDisableAutomaticUUID(true); + [self addGenericPassword: @"data" account: @"account-delete-me-no-UUID" expecting:errSecSuccess message: @"Add item (no UUID) to keychain"]; + + // and an item with a UUID... + SecCKKSTestSetDisableAutomaticUUID(false); + [self addGenericPassword: @"data" account: @"account-delete-me-with-UUID" expecting:errSecSuccess message: @"Add item (w/ UUID) to keychain"]; + + // Now that we have an item in the keychain, allow CKKS to spin up. It should upload the item, using the key hierarchy already extant + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 2 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testOnboardOldItemsWithExistingKeyHierarchyLateTLK { + // Test starts key hierarchy in our fake CloudKit, and CKKS blocked. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // Add one item without a UUID... + SecCKKSTestSetDisableAutomaticUUID(true); + [self addGenericPassword: @"data" account: @"account-delete-me-no-UUID" expecting:errSecSuccess message: @"Add item (no UUID) to keychain"]; + + // and an item with a UUID... + SecCKKSTestSetDisableAutomaticUUID(false); + [self addGenericPassword: @"data" account: @"account-delete-me-with-UUID" expecting:errSecSuccess message: @"Add item (w/ UUID) to keychain"]; + + // Now that we have an item in the keychain, allow CKKS to spin up. It should upload the item, using the key hierarchy already extant + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // No write yet... + sleep(0.5); + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now, save the TLK to the keychain (to simulate it coming in via SOS). + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords: 2 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (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!) + __block NSError* error = nil; + + // Test starts with keys in CloudKit (so we can create items later) + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + [self addGenericPassword: @"data" account: @"first"]; + [self addGenericPassword: @"data" account: @"second"]; + [self addGenericPassword: @"data" account: @"third"]; + [self addGenericPassword: @"data" account: @"fourth"]; + NSUInteger passwordCount = 4u; + + [self checkGenericPassword: @"data" account: @"first"]; + [self checkGenericPassword: @"data" account: @"second"]; + [self checkGenericPassword: @"data" account: @"third"]; + [self checkGenericPassword: @"data" account: @"fourth"]; + + [self expectCKModifyItemRecords: passwordCount currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + + // Wait for uploads to happen + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForCKModifications]; + XCTAssertEqual(self.keychainZone.currentDatabase.count, SYSTEM_DB_RECORD_COUNT+passwordCount, "Have 6+passwordCount objects in cloudkit"); + + // Now, corrupt away! + // Extract all passwordCount items for Corruption + NSArray* items = [self.keychainZone.currentDatabase.allValues filteredArrayUsingPredicate: [NSPredicate predicateWithFormat:@"self.recordType like %@", SecCKRecordItemType]]; + XCTAssertEqual(items.count, passwordCount, "Have %lu Items in cloudkit", (unsigned long)passwordCount); + + // For the first record, delete all traces of it from CKKS. But! it remains in local keychain. + // Expected outcome: CKKS resyncs; item exists again. + CKRecord* delete = items[0]; + NSString* deleteAccount = [[self decryptRecord: delete] objectForKey: (__bridge id) kSecAttrAccount]; + XCTAssertNotNil(deleteAccount, "received an account for the local delete object"); + + __weak __typeof(self) weakSelf = self; + [self.keychainView dispatchSync:^bool{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:delete.recordID.recordName zoneID:strongSelf.keychainZoneID error:&error]; + if(ckme) { + [ckme deleteFromDatabase: &error]; + } + XCTAssertNil(error, "no error removing CKME"); + CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry tryFromDatabase:delete.recordID.recordName zoneID:strongSelf.keychainZoneID error:&error]; + if(oqe) { + [oqe deleteFromDatabase: &error]; + } + XCTAssertNil(error, "no error removing OQE"); + CKKSIncomingQueueEntry* iqe = [CKKSIncomingQueueEntry tryFromDatabase:delete.recordID.recordName zoneID:strongSelf.keychainZoneID error:&error]; + if(iqe) { + [iqe deleteFromDatabase: &error]; + } + XCTAssertNil(error, "no error removing IQE"); + return true; + }]; + + // For the second record, delete all traces of it from CloudKit. + // Expected outcome: deleted locally + CKRecord* remoteDelete = items[1]; + NSString* remoteDeleteAccount = [[self decryptRecord: remoteDelete] objectForKey: (__bridge id) kSecAttrAccount]; + XCTAssertNotNil(remoteDeleteAccount, "received an account for the remote delete object"); + + [self.keychainZone deleteCKRecordIDFromZone: remoteDelete.recordID]; + for(NSMutableDictionary* database in self.keychainZone.pastDatabases.allValues) { + [database removeObjectForKey: remoteDelete.recordID]; + } + + // The third record gets modified in CloudKit, but not locally. + // Expected outcome: use the CloudKit version + CKRecord* remoteDataChanged = items[2]; + NSMutableDictionary* remoteDataDictionary = [[self decryptRecord: remoteDataChanged] mutableCopy]; + NSString* remoteDataChangedAccount = [remoteDataDictionary objectForKey: (__bridge id) kSecAttrAccount]; + XCTAssertNotNil(remoteDataChangedAccount, "Received an account for the remote-data-changed object"); + remoteDataDictionary[(__bridge id) kSecValueData] = [@"CloudKitWins" dataUsingEncoding: NSUTF8StringEncoding]; + + CKRecord* newData = [self newRecord: remoteDataChanged.recordID withNewItemData: remoteDataDictionary]; + [self.keychainZone addToZone: newData]; + for(NSMutableDictionary* database in self.keychainZone.pastDatabases.allValues) { + database[remoteDataChanged.recordID] = newData; + } + + // The fourth record stays in-sync. Good work, everyone! + // Expected outcome: stays in-sync + NSString* insyncAccount = [[self decryptRecord: items[3]] objectForKey: (__bridge id) kSecAttrAccount]; + XCTAssertNotNil(insyncAccount, "Received an account for the in-sync object"); + + // The fifth 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"; + CKRecord* ckr = [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" withAccount: remoteOnlyAccount]; + [self.keychainZone addToZone: ckr]; + for(NSMutableDictionary* database in self.keychainZone.pastDatabases.allValues) { + database[ckr.recordID] = ckr; + } + + ckksnotice("ckksresync", self.keychainView, "local delete: %@ %@", delete.recordID.recordName, deleteAccount); + ckksnotice("ckksresync", self.keychainView, "Remote deletion: %@ %@", remoteDelete.recordID.recordName, remoteDeleteAccount); + 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, "Remote only: %@ %@", ckr.recordID.recordName, remoteOnlyAccount); + + CKKSSynchronizeOperation* resyncOperation = [self.keychainView resyncWithCloud]; + [resyncOperation waitUntilFinished]; + + XCTAssertNil(resyncOperation.error, "No error during the resync operation"); + + // Now do some checking. Remember, we don't know which record we corrupted, so use the parsed account variables to check. + + [self findGenericPassword: deleteAccount expecting: errSecSuccess]; + [self findGenericPassword: remoteDeleteAccount expecting: errSecItemNotFound]; + [self findGenericPassword: remoteDataChangedAccount expecting: errSecSuccess]; + [self findGenericPassword: insyncAccount expecting: errSecSuccess]; + [self findGenericPassword: remoteOnlyAccount expecting: errSecSuccess]; + + [self checkGenericPassword: @"data" account: deleteAccount]; + //[self checkGenericPassword: @"data" account: remoteDeleteAccount]; + [self checkGenericPassword: @"CloudKitWins" account: remoteDataChangedAccount]; + [self checkGenericPassword: @"data" account: insyncAccount]; + [self checkGenericPassword: @"data" account: remoteOnlyAccount]; + + [self.keychainView dispatchSync:^bool{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + CKKSMirrorEntry* ckme = nil; + + ckme = [CKKSMirrorEntry tryFromDatabase:delete.recordID.recordName zoneID:strongSelf.keychainZoneID error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(ckme); + + ckme = [CKKSMirrorEntry tryFromDatabase:remoteDelete.recordID.recordName zoneID:strongSelf.keychainZoneID error:&error]; + XCTAssertNil(error); + XCTAssertNil(ckme); // deleted! + + ckme = [CKKSMirrorEntry tryFromDatabase:remoteDataChanged.recordID.recordName zoneID:strongSelf.keychainZoneID error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(ckme); + + ckme = [CKKSMirrorEntry tryFromDatabase:items[3].recordID.recordName zoneID:strongSelf.keychainZoneID error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(ckme); + + ckme = [CKKSMirrorEntry tryFromDatabase:ckr.recordID.recordName zoneID:strongSelf.keychainZoneID error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(ckme); + return true; + }]; +} + +- (void)testMultipleZoneAdd { + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + // Bring up a new zone: we expect a key hierarchy upload. + [self.injectedManager findOrCreateView:(id)kSecAttrViewHintAppleTV]; + CKRecordZoneID* appleTVZoneID = [[CKRecordZoneID alloc] initWithZoneName:(__bridge NSString*) kSecAttrViewHintAppleTV ownerName:CKCurrentUserDefaultName]; + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:appleTVZoneID]; + + // We also expect the view manager's notifyNewTLKsInKeychain call to fire once (after some delay) + id mockVM = OCMPartialMock(self.injectedManager); + OCMExpect([mockVM notifyNewTLKsInKeychain]); + + // Let the horses loose + [self startCKKSSubsystem]; + + // We expect a single record to be uploaded to the 'keychain' view + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // We expect a single record to be uploaded to the 'atv' view + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:appleTVZoneID]; + [self addGenericPassword: @"atv" + account: @"tvaccount" + viewHint:(__bridge NSString*) kSecAttrViewHintAppleTV + access:(id)kSecAttrAccessibleAfterFirstUnlock + expecting:errSecSuccess message:@"AppleTV view-hinted object"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + OCMVerifyAllWithDelay(mockVM, 10); + [mockVM stopMocking]; +} + +- (void)testMultipleZoneDelete { + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID: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, 8); + + // Bring up a new zone: we expect a key hierarchy and an item. + [self.injectedManager findOrCreateView:(id)kSecAttrViewHintAppleTV]; + CKRecordZoneID* appleTVZoneID = [[CKRecordZoneID alloc] initWithZoneName:(__bridge NSString*) kSecAttrViewHintAppleTV ownerName:CKCurrentUserDefaultName]; + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:appleTVZoneID]; + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:appleTVZoneID]; + + [self addGenericPassword: @"atv" + account: @"tvaccount" + viewHint:(__bridge NSString*) kSecAttrViewHintAppleTV + access:(id)kSecAttrAccessibleAfterFirstUnlock + expecting:errSecSuccess + message:@"AppleTV view-hinted object"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // We expect a single record to be deleted from the ATV zone + [self expectCKDeleteItemRecords: 1 zoneID:appleTVZoneID]; + [self deleteGenericPassword:@"tvaccount"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now we expect a single record to be deleted from the test zone + [self expectCKDeleteItemRecords: 1 zoneID:self.keychainZoneID]; + [self deleteGenericPassword:@"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRestartWithoutRefetch { + // Restarting the CKKS operation should check that it's been 15 minutes since the last fetch before it fetches again. Simulate this. + + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + [self startCKKSSubsystem]; + + [self.keychainView waitForKeyHierarchyReadiness]; + [self waitForCKModifications]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Tear down the CKKS object and disallos fetches + [self.keychainView cancelAllOperations]; + self.silentFetchesAllowed = false; + + self.keychainView = [[CKKSViewManager manager] restartZone: self.keychainZoneID.zoneName]; + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Okay, cool, rad, now let's set the date to be very long ago and check that there's positively a fetch + [self.keychainView cancelAllOperations]; + self.silentFetchesAllowed = false; + + [self.keychainView dispatchSync: ^bool { + NSError* error = nil; + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:self.keychainZoneID.zoneName error:&error]; + + XCTAssertNil(error, "no error pulling ckse from database"); + XCTAssertNotNil(ckse, "received a ckse"); + + ckse.lastFetchTime = [NSDate distantPast]; + [ckse saveToDatabase: &error]; + XCTAssertNil(error, "no error saving to database"); + return true; + }]; + + [self expectCKFetch]; + self.keychainView = [[CKKSViewManager manager] restartZone: self.keychainZoneID.zoneName]; + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromZoneCreationFailure { + // Fail the zone creation. + self.zones[self.keychainZoneID] = nil; // delete the autocreated zone + [self failNextZoneCreation:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should figure out the issue, and fix it. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + XCTAssertNil(self.zones[self.keychainZoneID].creationError, "Creation error was unset (and so CKKS probably dealt with the error"); +} + +- (void)testRecoverFromZoneSubscriptionFailure { + // Fail the zone subscription. + [self failNextZoneSubscription:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should figure out the issue, and fix it. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + XCTAssertNil(self.zones[self.keychainZoneID].subscriptionError, "Subscription error was unset (and so CKKS probably dealt with the error"); +} + +- (void)testRecoverFromZoneSubscriptionFailureDueToZoneNotExisting { + // This is different from testRecoverFromZoneSubscriptionFailure, since the zone is gone. CKKS must attempt to re-create the zone. + + // Silently fail the zone creation + self.zones[self.keychainZoneID] = nil; // delete the autocreated zone + [self failNextZoneCreationSilently:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should figure out the issue, and fix it. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + XCTAssertFalse(self.zones[self.keychainZoneID].flag, "Zone flag was reset"); + XCTAssertNil(self.zones[self.keychainZoneID].subscriptionError, "Subscription error was unset (and so CKKS probably dealt with the error"); +} + +- (void)testRecoverFromDeletedTLKWithStashedTLK { + // We need to handle the case where our syncable TLKs are deleted for some reason. The device that has them might resurrect them + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + NSError* error = nil; + [self.keychainZoneKeys.tlk deleteKeyMaterialFromKeychain:&error]; + XCTAssertNil(error, "Should have received no error deleting the new TLK from the keychain"); + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // CKKS should recreate the syncable TLK. + [self checkNSyncableTLKsInKeychain: 1]; +} + +- (void)testRecoverFromDeletedTLKWithStashedTLKUponRestart { + // We need to handle the case where our syncable TLKs are deleted for some reason. The device that has them might resurrect them + + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + // Tear down the CKKS object + [self.keychainView cancelAllOperations]; + + NSError* error = nil; + [self.keychainZoneKeys.tlk deleteKeyMaterialFromKeychain:&error]; + XCTAssertNil(error, "Should have received no error deleting the new TLK from the keychain"); + + self.keychainView = [[CKKSViewManager manager] restartZone: self.keychainZoneID.zoneName]; + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // CKKS should recreate the syncable TLK. + [self checkNSyncableTLKsInKeychain: 1]; +} + +- (void)testRecoverFromTLKWriteFailure { + // We need to handle the case where a device's first TLK write doesn't go through (due to whatever reason). + // Test starts with nothing in CloudKit, and will fail the first TLK write. + NSError* noNetwork = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkUnavailable userInfo:@{}]; + [self failNextCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID blockAfterReject:nil withError:noNetwork]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should figure out the issue, and fix it. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self.keychainView waitForKeyHierarchyReadiness]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // A network failure creating new TLKs shouldn't delete the 'failed' syncable one. + [self checkNSyncableTLKsInKeychain: 2]; +} + +- (void)testRecoverFromTLKRace { + // We need to handle the case where a device's first TLK write doesn't go through (due to whatever reason). + // Test starts with nothing in CloudKit, and will fail the first TLK write. + [self failNextCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID blockAfterReject: ^{ + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + }]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The first TLK write should fail, and then our fake TLKs should be there in CloudKit. + // It shouldn't write anything back up to CloudKit. + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now the TLKs arrive from the other device... + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + [self.keychainView waitForKeyHierarchyReadiness]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // A race failure creating new TLKs should delete the old syncable one. + [self checkNSyncableTLKsInKeychain: 1]; +} + +- (void)testRecoverFromNullCurrentKeyPointers { + // The current key pointers in cloudkit shouldn't ever not exist if keys do. But, if they don't, CKKS must recover. + + // Test starts with a broken key hierarchy in our fake CloudKit, but the TLK already arrived. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + ZoneKeys* zonekeys = self.keys[self.keychainZoneID]; + FakeCKZone* ckzone = self.zones[self.keychainZoneID]; + ckzone.currentDatabase[zonekeys.currentTLKPointer.storedCKRecord.recordID][SecCKRecordParentKeyRefKey] = nil; + ckzone.currentDatabase[zonekeys.currentClassAPointer.storedCKRecord.recordID][SecCKRecordParentKeyRefKey] = nil; + ckzone.currentDatabase[zonekeys.currentClassCPointer.storedCKRecord.recordID][SecCKRecordParentKeyRefKey] = nil; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should figure out the issue, and fix it. + [self expectCKModifyKeyRecords: 0 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self.keychainView waitForKeyHierarchyReadiness]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromNoCurrentKeyPointers { + // The current key pointers in cloudkit shouldn't ever point to nil. But, if they do, CKKS must recover. + + // Test starts with a broken key hierarchy in our fake CloudKit, but the TLK already arrived. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + ZoneKeys* zonekeys = self.keys[self.keychainZoneID]; + XCTAssertNil([self.zones[self.keychainZoneID] deleteCKRecordIDFromZone: zonekeys.currentTLKPointer.storedCKRecord.recordID], "Deleted TLK pointer from zone"); + XCTAssertNil([self.zones[self.keychainZoneID] deleteCKRecordIDFromZone: zonekeys.currentClassAPointer.storedCKRecord.recordID], "Deleted class a pointer from zone"); + XCTAssertNil([self.zones[self.keychainZoneID] deleteCKRecordIDFromZone: zonekeys.currentClassCPointer.storedCKRecord.recordID], "Deleted class c pointer from zone"); + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should figure out the issue, and fix it. + [self expectCKModifyKeyRecords: 0 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self.keychainView waitForKeyHierarchyReadiness]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromBadChangeTag { + // We received a report where a machine appeared to have an up-to-date change tag, but was continuously attempting to create a new TLK hierarchy. No idea why. + + // Test starts with a broken key hierarchy in our fake CloudKit, but a (incorrectly) up-to-date change tag stored locally. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + SecCKKSTestSetDisableKeyNotifications(true); // Don't tell CKKS about this key material; we're pretending like this is a securityd restart + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + SecCKKSTestSetDisableKeyNotifications(false); + + [self.keychainView dispatchSync: ^bool { + NSError* error = nil; + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.keychainZoneID.zoneName]; + XCTAssertNotNil(ckse, "should have received a ckse"); + + ckse.ckzonecreated = true; + ckse.ckzonesubscribed = true; + ckse.changeToken = self.keychainZone.currentChangeToken; + + [ckse saveToDatabase: &error]; + XCTAssertNil(error, "shouldn't have gotten an error saving to database"); + return true; + }]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should try to write TLKs, but fail + [self expectCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID]; + OCMVerifyAllWithDelay(self.mockDatabase, 16); + + // CKKS should then happily use the keys in CloudKit + [self createClassCItemAndWaitForUpload:self.keychainZoneID account:@"account-delete-me"]; + [self createClassAItemAndWaitForUpload:self.keychainZoneID account:@"account-delete-me-class-a"]; +} + +- (void)testRecoverFromDeletedKeysNewItem { + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + // 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"]]; + + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self waitForCKModifications]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + // Now, delete the local keys from the keychain (but leave the synced TLK) + SecCKKSTestSetDisableKeyNotifications(true); + XCTAssertEqual(errSecSuccess, SecItemDelete((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, + }), @"Deleting local keys"); + SecCKKSTestSetDisableKeyNotifications(false); + + NSError* error = nil; + [self.keychainZoneKeys.classC loadKeyMaterialFromKeychain:&error]; + XCTAssertNotNil(error, "Error loading class C key material from keychain"); + + // 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"]]; + + [self addGenericPassword: @"datadata" account: @"account-no-keys"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // We expect a single class A record to be uploaded. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID + checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromDeletedKeysReceive { + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + [self waitForCKModifications]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" withAccount:@"account0"]; + + // Now, delete the local keys from the keychain (but leave the synced TLK) + SecCKKSTestSetDisableKeyNotifications(true); + XCTAssertEqual(errSecSuccess, SecItemDelete((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, + }), @"Deleting local keys"); + SecCKKSTestSetDisableKeyNotifications(false); + + // Trigger a notification (with hilariously fake data) + [self.keychainZone addToZone: ckr]; + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + [self findGenericPassword: @"account0" expecting:errSecSuccess]; +} + +- (void)disabledtestRecoverDeletedTLKAndPause { + // If the TLK disappears halfway through, well, that's no good. But we should make it into waitfortlk. + + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" withAccount:@"account0"]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + // Now, delete the local keys from the keychain + SecCKKSTestSetDisableKeyNotifications(true); + XCTAssertEqual(errSecSuccess, SecItemDelete((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, + }), @"Deleting local keys"); + XCTAssertEqual(errSecSuccess, SecItemDelete((__bridge CFDictionaryRef)@{ + (id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrNoLegacy : @YES, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + }), @"Deleting TLK"); + SecCKKSTestSetDisableKeyNotifications(false); + + // Trigger a notification (with hilariously fake data) + [self.keychainZone addToZone: ckr]; + [self.keychainView notifyZoneChange:nil]; + + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + [self.keychainView waitForOperationsOfClass:[CKKSHealKeyHierarchyOperation class]]; + + XCTAssertEqual(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateWaitForTLK, "CKKS re-entered waitfortlk"); +} + +- (void)testRecoverFromBadCurrentKeyPointer { + // The current key pointers in cloudkit shouldn't ever point to missing entries. But, if they do, CKKS must recover. + + // Test starts with a broken key hierarchy in our fake CloudKit, but the TLK already arrived. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + ZoneKeys* zonekeys = self.keys[self.keychainZoneID]; + FakeCKZone* ckzone = self.zones[self.keychainZoneID]; + ckzone.currentDatabase[zonekeys.currentTLKPointer.storedCKRecord.recordID][SecCKRecordParentKeyRefKey] = [[CKReference alloc] initWithRecordID: [[CKRecordID alloc] initWithRecordName: @"not a real tlk" zoneID: self.keychainZoneID] action: CKReferenceActionNone]; + ckzone.currentDatabase[zonekeys.currentClassAPointer.storedCKRecord.recordID][SecCKRecordParentKeyRefKey] = [[CKReference alloc] initWithRecordID: [[CKRecordID alloc] initWithRecordName: @"not a real class a key" zoneID: self.keychainZoneID] action: CKReferenceActionNone]; + ckzone.currentDatabase[zonekeys.currentClassCPointer.storedCKRecord.recordID][SecCKRecordParentKeyRefKey] = [[CKReference alloc] initWithRecordID: [[CKRecordID alloc] initWithRecordName: @"not a real class c key" zoneID: self.keychainZoneID] action: CKReferenceActionNone]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // The CKKS subsystem should figure out the issue, and fix it. + [self expectCKModifyKeyRecords: 0 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self.keychainView waitForKeyHierarchyReadiness]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromCloudKitFetchFail { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // The first two CKRecordZoneChanges should fail with a 'network unavailable' error. + [self.keychainZone failNextFetchWith:[[NSError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkUnavailable userInfo:@{}]]; + [self.keychainZone failNextFetchWith:[[NSError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkUnavailable userInfo:@{}]]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // Now, save the TLK to the keychain (to simulate it coming in later via SOS). + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // 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, 12); + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromCloudKitFetchFailWithDelay { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // The first CKRecordZoneChanges should fail with a 'delay' error. + self.silentFetchesAllowed = false; + [self.keychainZone failNextFetchWith:[[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorRequestRateLimited userInfo:@{CKErrorRetryAfterKey : [NSNumber numberWithInt:4]}]]; + [self expectCKFetch]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // Ensure it doesn't fetch within these three seconds (if it does, an exception will throw). + sleep(3); + + // Okay, you can fetch again. + [self expectCKFetch]; + + // Now, save the TLK to the keychain (to simulate it coming in later via SOS). + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // 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, 8); +} + +- (void)testRecoverFromCloudKitOldChangeToken { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // Now, save the TLK to the keychain (to simulate it coming in later via SOS). + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // 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, 8); + + // Delete all old database states, to destroy the change tag validity + [self.keychainZone.pastDatabases removeAllObjects]; + + // We expect a total local flush and refetch + self.silentFetchesAllowed = false; + [self expectCKFetch]; // one to fail with a CKErrorChangeTokenExpired error + [self expectCKFetch]; // and one to succeed + + // Trigger a fake change notification + [self.keychainView notifyZoneChange:nil]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // And check that a new upload happens just fine. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromCloudKitUnknownDeviceStateRecord { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // Save a new device state record with some fake etag + [self.keychainView dispatchSync: ^bool { + CKKSDeviceStateEntry* cdse = [[CKKSDeviceStateEntry alloc] initForDevice:self.ckDeviceID + circlePeerID:self.circlePeerID + circleStatus:kSOSCCInCircle + keyState:SecCKKSZoneKeyStateWaitForTLK + currentTLKUUID:nil + currentClassAUUID:nil + currentClassCUUID:nil + zoneID:self.keychainZoneID + encodedCKRecord:nil]; + XCTAssertNotNil(cdse, "Should have created a fake CDSE"); + CKRecord* record = [cdse CKRecordWithZoneID:self.keychainZoneID]; + XCTAssertNotNil(record, "Should have created a fake CDSE CKRecord"); + record.etag = @"fake etag"; + cdse.storedCKRecord = record; + + NSError* error = nil; + [cdse saveToDatabase:&error]; + XCTAssertNil(error, @"No error saving cdse to database"); + + return true; + }]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // We expect a record failure, since the device state record is broke + [self expectCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID]; + + // And then we expect a clean write + [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID + checkItem:[self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + + [self addGenericPassword: @"data" account: @"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromCloudKitUnknownItemRecord { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + [self findGenericPassword:@"account-delete-me" expecting:errSecItemNotFound]; + + CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"]; + [self.keychainZone addToZone:ckr]; + + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + [self findGenericPassword:@"account-delete-me" expecting:errSecSuccess]; + + // Delete the record from CloudKit, but miss the notification + XCTAssertNil([self.keychainZone deleteCKRecordIDFromZone: ckr.recordID], "Deleting the record from fake CloudKit should succeed"); + + // Expect a failed upload when we modify the item + [self expectCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID]; + [self updateGenericPassword:@"never seen again" account:@"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self.keychainView waitUntilAllOperationsAreFinished]; + + // And the item should be disappeared from the local keychain + [self findGenericPassword:@"account-delete-me" expecting:errSecItemNotFound]; +} + +- (void)testRecoverFromCloudKitUserDeletedZone { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // Now, save the TLK to the keychain (to simulate it coming in later via SOS). + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // 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, 8); + + // The first CKRecordZoneChanges should fail with a 'CKErrorUserDeletedZone' error. + [self.keychainZone failNextFetchWith:[[NSError alloc] initWithDomain:CKErrorDomain code:CKErrorUserDeletedZone userInfo:@{}]]; + + // We expect a key hierarchy upload, and then the class C item upload + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + [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]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // And check that a new upload occurs. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testRecoverFromCloudKitZoneNotFound { + // Test starts with nothing in database, but one in our fake CloudKit. + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + // Now, save the TLK to the keychain (to simulate it coming in later via SOS). + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + // 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, 8); + + // The next CKRecordZoneChanges should fail with a 'zone not found' error. + NSError* zoneNotFoundError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain + code:CKErrorZoneNotFound + userInfo:@{}]; + NSError* error = [[CKPrettyError alloc] initWithDomain:CKErrorDomain + code:CKErrorPartialFailure + userInfo:@{CKPartialErrorsByItemIDKey: @{self.keychainZoneID:zoneNotFoundError}}]; + [self.keychainZone failNextFetchWith:error]; + + // We expect a key hierarchy upload, and then the class C item upload + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + [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]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // And check that a new upload occurs. + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; + + [self addGenericPassword:@"asdf" + account:@"account-class-A" + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testNoCloudKitAccount { + // Test starts with nothing in database and the user logged out of CloudKit. We expect no CKKS operations. + self.accountStatus = CKAccountStatusNoAccount; + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + self.silentFetchesAllowed = false; + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self addGenericPassword: @"data" account: @"account-delete-me"]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + // simulate a NSNotification callback (but still logged out) + self.accountStatus = CKAccountStatusNoAccount; + [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal]; + + // 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]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Test that there are no items in the database (since we never logged in) + [self checkNoCKKSData: self.keychainView]; +} + +- (void)testSACloudKitAccount { + // Test starts with nothing in database and the user logged into CloudKit and in circle, but the account is not HSA2. + self.circleStatus = kSOSCCInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + self.accountStatus = CKAccountStatusAvailable; + self.supportsDeviceToDeviceEncryption = NO; + + self.silentFetchesAllowed = false; + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // There should be no uploads, even when we save keychain items and enter/exit circle + [self addGenericPassword: @"data" account: @"account-delete-me"]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + [self addGenericPassword: @"data" account: @"account-delete-me-2"]; + + self.circleStatus = kSOSCCInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + [self addGenericPassword: @"data" account: @"account-delete-me-3"]; + + [self.keychainView waitUntilAllOperationsAreFinished]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Test that there are no items in the database (since we never were in an HSA2 account) + [self checkNoCKKSData: self.keychainView]; +} + +- (void)testNoCircle { + // Test starts with nothing in database and the user logged into CloudKit, but out of Circle. + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + self.accountStatus = CKAccountStatusAvailable; + + self.silentFetchesAllowed = false; + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self addGenericPassword: @"data" account: @"account-delete-me"]; + [self.keychainView waitUntilAllOperationsAreFinished]; + + // simulate a NSNotification callback (but still logged out) + self.accountStatus = CKAccountStatusNoAccount; + [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal]; + + // 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]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Test that there are no items in the database (since we never logged in) + [self checkNoCKKSData: self.keychainView]; +} + +- (void)testCloudKitLogin { + // Test starts with nothing in database and the user logged out of CloudKit. We expect no CKKS operations. + self.accountStatus = CKAccountStatusNoAccount; + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + [self startCKKSSubsystem]; + + [self.keychainView waitUntilAllOperationsAreFinished]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // simulate a cloudkit login and NSNotification callback + self.accountStatus = CKAccountStatusAvailable; + [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal]; + + // No writes yet, since we're not in circle + [self.keychainView waitUntilAllOperationsAreFinished]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // We expect some sort of TLK/key hierarchy upload once we are notified of entering the circle. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + self.circleStatus = kSOSCCInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForCKModifications]; + + // 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"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForCKModifications]; +} + +- (void)testCloudKitLogoutLogin { + // Test starts with nothing in database. We expect some sort of TLK/key hierarchy upload. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + [self startCKKSSubsystem]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + // 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"]]; + [self addGenericPassword: @"data" account: @"account-delete-me"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + // simulate a cloudkit logout and NSNotification callback + self.accountStatus = CKAccountStatusNoAccount; + [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal]; + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + // Test that there are no items in the database after logout + [self.keychainView waitUntilAllOperationsAreFinished]; + [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]; + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + // simulate a cloudkit login + // We should expect CKKS to re-find the key hierarchy it already uploaded, and then send up the two records we added during the pause + [self expectCKModifyItemRecords: 2 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + + self.accountStatus = CKAccountStatusAvailable; + [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal]; + self.circleStatus = kSOSCCInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + // Let everything settle... + [self.keychainView waitUntilAllOperationsAreFinished]; + + // Logout again + self.accountStatus = CKAccountStatusNoAccount; + [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal]; + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + // Test that there are no items in the database after logout + [self.keychainView waitUntilAllOperationsAreFinished]; + [self checkNoCKKSData: self.keychainView]; + + // There should be no further uploads, even when we save keychain items + [self addGenericPassword: @"data" account: @"account-delete-me-5"]; + [self addGenericPassword: @"data" account: @"account-delete-me-6"]; + + [self.keychainView waitUntilAllOperationsAreFinished]; + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + // simulate a cloudkit login + // We should expect CKKS to re-find the key hierarchy it already uploaded, and then send up the two records we added during the pause + [self expectCKModifyItemRecords: 2 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + + self.accountStatus = CKAccountStatusAvailable; + [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal]; + self.circleStatus = kSOSCCInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); +} + +- (void)testCloudKitLoginRace { + // Test starts with nothing in database, and 'in circle', but securityd hasn't received notification if we're logged into CloudKit. + // CKKS should not call handleLogout. + + id partialKVMock = OCMPartialMock(self.keychainView); + OCMReject([partialKVMock handleCKLogout]); + + self.circleStatus = kSOSCCInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + [self startCKKSSubsystemOnly]; // note: don't unblock the ck account state object yet... + + // Add a keychain item, but make sure it doesn't upload yet. + [self addGenericPassword: @"data" account: @"account-delete-me"]; + + [self.keychainView waitUntilAllOperationsAreFinished]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Now that we're here (and handleCKLogout hasn't been called), bring the account up + + // We expect some sort of TLK/key hierarchy upload once we are notified of entering the circle. + [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 zoneID:self.keychainZoneID]; + + // 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"]]; + + self.accountStatus = CKAccountStatusAvailable; + [self startCKAccountStatusMock]; + + // simulate another NSNotification callback + [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [self waitForCKModifications]; + + // Make sure new items upload too + [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-2"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [self.keychainView waitUntilAllOperationsAreFinished]; + [self waitForCKModifications]; + [self.keychainView cancelAllOperations]; + + [partialKVMock stopMocking]; +} + +- (void)testDeviceStateUploadGood { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + __weak __typeof(self) weakSelf = self; + [self expectCKModifyRecords: @{SecCKRecordDeviceStateType: [NSNumber numberWithInt:1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord: ^BOOL (CKRecord* record){ + if([record.recordType isEqualToString: SecCKRecordDeviceStateType]) { + // Check that all the things matches + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + ZoneKeys* zoneKeys = strongSelf.keys[strongSelf.keychainZoneID]; + XCTAssertNotNil(zoneKeys, "Have zone keys for %@", strongSelf.keychainZoneID); + + XCTAssertEqualObjects(record[SecCKRecordCirclePeerID], @"fake-circle-id", "peer ID matches what we gave it"); + XCTAssertEqualObjects(record[SecCKRecordCircleStatus], [NSNumber numberWithInt:kSOSCCInCircle], "device is in circle"); + XCTAssertEqualObjects(record[SecCKRecordKeyState], CKKSZoneKeyToNumber(SecCKKSZoneKeyStateReady), "Device is in ready"); + + XCTAssertEqualObjects([record[SecCKRecordCurrentTLK] recordID].recordName, zoneKeys.tlk.uuid, "Correct TLK uuid"); + XCTAssertEqualObjects([record[SecCKRecordCurrentClassA] recordID].recordName, zoneKeys.classA.uuid, "Correct class A uuid"); + XCTAssertEqualObjects([record[SecCKRecordCurrentClassC] recordID].recordName, zoneKeys.classC.uuid, "Correct class C uuid"); + return YES; + } else { + return NO; + } + } + runAfterModification:nil]; + + [self.keychainView updateDeviceState:false ckoperationGroup:nil]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testDeviceStateUploadRateLimited { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + __weak __typeof(self) weakSelf = self; + [self expectCKModifyRecords: @{SecCKRecordDeviceStateType: [NSNumber numberWithInt:1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord: ^BOOL (CKRecord* record){ + if([record.recordType isEqualToString: SecCKRecordDeviceStateType]) { + // Check that all the things matches + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + ZoneKeys* zoneKeys = strongSelf.keys[strongSelf.keychainZoneID]; + XCTAssertNotNil(zoneKeys, "Have zone keys for %@", strongSelf.keychainZoneID); + + XCTAssertEqualObjects(record[SecCKRecordCirclePeerID], @"fake-circle-id", "peer ID matches what we gave it"); + XCTAssertEqualObjects(record[SecCKRecordCircleStatus], [NSNumber numberWithInt:kSOSCCInCircle], "device is in circle"); + XCTAssertEqualObjects(record[SecCKRecordKeyState], CKKSZoneKeyToNumber(SecCKKSZoneKeyStateReady), "Device is in ready"); + + XCTAssertEqualObjects([record[SecCKRecordCurrentTLK] recordID].recordName, zoneKeys.tlk.uuid, "Correct TLK uuid"); + XCTAssertEqualObjects([record[SecCKRecordCurrentClassA] recordID].recordName, zoneKeys.classA.uuid, "Correct class A uuid"); + XCTAssertEqualObjects([record[SecCKRecordCurrentClassC] recordID].recordName, zoneKeys.classC.uuid, "Correct class C uuid"); + return YES; + } else { + return NO; + } + } + runAfterModification:nil]; + + CKKSUpdateDeviceStateOperation* op = [self.keychainView updateDeviceState:true ckoperationGroup:nil]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [op waitUntilFinished]; + + // Check that an immediate rate-limited retry doesn't upload anything + op = [self.keychainView updateDeviceState:true ckoperationGroup:nil]; + [op waitUntilFinished]; + + // But not rate-limiting works just fine! + [self expectCKModifyRecords:@{SecCKRecordDeviceStateType: [NSNumber numberWithInt:1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord:nil + runAfterModification:nil]; + op = [self.keychainView updateDeviceState:false ckoperationGroup:nil]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + [op waitUntilFinished]; + + // And now, if the update is old enough, that'll work too + [self.keychainView dispatchSync:^bool { + NSError* error = nil; + CKKSDeviceStateEntry* cdse = [CKKSDeviceStateEntry fromDatabase:self.accountStateTracker.ckdeviceID zoneID:self.keychainZoneID error:&error]; + XCTAssertNil(error, "No error fetching device state entry"); + XCTAssertNotNil(cdse, "Fetched device state entry"); + + CKRecord* record = cdse.storedCKRecord; + + NSDate* m = record.modificationDate; + XCTAssertNotNil(m, "Have modification date"); + + // Four days ago! + NSDateComponents* offset = [[NSDateComponents alloc] init]; + [offset setHour:-4 * 24]; + NSDate* m2 = [[NSCalendar currentCalendar] dateByAddingComponents:offset toDate:m options:0]; + + XCTAssertNotNil(m2, "Made modification date"); + + record.modificationDate = m2; + [cdse setStoredCKRecord:record]; + + [cdse saveToDatabase:&error]; + XCTAssertNil(error, "No error saving device state entry"); + + return true; + }]; + + // And now the rate-limiting doesn't get in the way + [self expectCKModifyRecords:@{SecCKRecordDeviceStateType: [NSNumber numberWithInt:1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord:nil + runAfterModification:nil]; + op = [self.keychainView updateDeviceState:true ckoperationGroup:nil]; + OCMVerifyAllWithDelay(self.mockDatabase, 12); + [op waitUntilFinished]; +} + +- (void)testDeviceStateUploadRateLimitedAfterNormalUpload { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID]; + [self addGenericPassword:@"password" account:@"account-delete-me"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + // Check that an immediate rate-limited retry doesn't upload anything + CKKSUpdateDeviceStateOperation* op = [self.keychainView updateDeviceState:true ckoperationGroup:nil]; + [op waitUntilFinished]; +} + +- (void)testDeviceStateReceive { + [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. + + ZoneKeys* zoneKeys = self.keys[self.keychainZoneID]; + XCTAssertNotNil(zoneKeys, "Have zone keys for %@", self.keychainZoneID); + + [self startCKKSSubsystem]; + [self.keychainView waitForKeyHierarchyReadiness]; + + CKKSDeviceStateEntry* cdse = [[CKKSDeviceStateEntry alloc] initForDevice:@"otherdevice" + circlePeerID:@"asdfasdf" + circleStatus:kSOSCCInCircle + keyState:SecCKKSZoneKeyStateReady + currentTLKUUID:zoneKeys.tlk.uuid + currentClassAUUID:zoneKeys.classA.uuid + currentClassCUUID:zoneKeys.classC.uuid + zoneID:self.keychainZoneID + encodedCKRecord:nil]; + CKRecord* record = [cdse CKRecordWithZoneID:self.keychainZoneID]; + [self.keychainZone addToZone:record]; + + // Trigger a notification (with hilariously fake data) + [self.keychainView notifyZoneChange:nil]; + [self.keychainView waitForFetchAndIncomingQueueProcessing]; + + [self.keychainView dispatchSync: ^bool { + NSError* error = nil; + NSArray* cdses = [CKKSDeviceStateEntry allInZone:self.keychainZoneID error:&error]; + XCTAssertNil(error, "No error fetching CDSEs"); + XCTAssertNotNil(cdses, "An array of CDSEs was returned"); + XCTAssert(cdses.count >= 1u, "At least one CDSE came back"); + + CKKSDeviceStateEntry* item = nil; + for(CKKSDeviceStateEntry* dbcdse in cdses) { + if([dbcdse.device isEqualToString:@"otherdevice"]) { + item = dbcdse; + } + } + XCTAssertNotNil(item, "Found a cdse for otherdevice"); + + XCTAssertEqualObjects(cdse, item, "Saved item matches pre-cloudkit item"); + + XCTAssertEqualObjects(item.circlePeerID, @"asdfasdf", "correct peer id"); + XCTAssertEqualObjects(item.keyState, SecCKKSZoneKeyStateReady, "correct key state"); + XCTAssertEqualObjects(item.currentTLKUUID, zoneKeys.tlk.uuid, "correct tlk uuid"); + XCTAssertEqualObjects(item.currentClassAUUID, zoneKeys.classA.uuid, "correct classA uuid"); + XCTAssertEqualObjects(item.currentClassCUUID, zoneKeys.classC.uuid, "correct classC uuid"); + + return false; + }]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testDeviceStateUploadBadKeyState { + // This test has stuff in CloudKit, but no TLKs. It should become very sad. + [self putFakeKeyHierarchyInCloudKit: self.keychainZoneID]; + + [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:8*NSEC_PER_SEC], "CKKS entered waitfortlk"); + XCTAssertEqual(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateWaitForTLK, "CKKS entered waitfortlk"); + + __weak __typeof(self) weakSelf = self; + [self expectCKModifyRecords: @{SecCKRecordDeviceStateType: [NSNumber numberWithInt:1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord: ^BOOL (CKRecord* record){ + if([record.recordType isEqualToString: SecCKRecordDeviceStateType]) { + // Check that all the things matches + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + XCTAssertEqualObjects(record[SecCKRecordCirclePeerID], @"fake-circle-id", "peer ID matches what we gave it"); + XCTAssertEqualObjects(record[SecCKRecordCircleStatus], [NSNumber numberWithInt:kSOSCCInCircle], "device is in circle"); + XCTAssertEqualObjects(record[SecCKRecordKeyState], CKKSZoneKeyToNumber(SecCKKSZoneKeyStateWaitForTLK), "Device is in waitfortlk"); + + XCTAssertNil(record[SecCKRecordCurrentTLK] , "No TLK"); + XCTAssertNil(record[SecCKRecordCurrentClassA], "No class A key"); + XCTAssertNil(record[SecCKRecordCurrentClassC], "No class C key"); + return YES; + } else { + return NO; + } + } + runAfterModification:nil]; + + [self.keychainView updateDeviceState:false ckoperationGroup:nil]; + + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)testDeviceStateUploadBadCircleState { + self.circleStatus = kSOSCCNotInCircle; + [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal]; + + // This test has stuff in CloudKit, but no TLKs. + [self putFakeKeyHierarchyInCloudKit: self.keychainZoneID]; + + [self startCKKSSubsystem]; + + // Since CKKS should start up enough to get back into the error state and then back into initializing state, wait for that to happen. + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateError] wait:8*NSEC_PER_SEC], "CKKS entered error"); + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateInitializing] wait:8*NSEC_PER_SEC], "CKKS entered initializing"); + XCTAssertEqual(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateInitializing, "CKKS entered intializing"); + + __weak __typeof(self) weakSelf = self; + [self expectCKModifyRecords: @{SecCKRecordDeviceStateType: [NSNumber numberWithInt:1]} + deletedRecordTypeCounts:nil + zoneID:self.keychainZoneID + checkModifiedRecord: ^BOOL (CKRecord* record){ + if([record.recordType isEqualToString: SecCKRecordDeviceStateType]) { + // Check that all the things matches + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + XCTAssertNil(record[SecCKRecordCirclePeerID], "no peer ID if device is not in circle"); + XCTAssertEqualObjects(record[SecCKRecordCircleStatus], [NSNumber numberWithInt:kSOSCCNotInCircle], "device is not in circle"); + XCTAssertEqualObjects(record[SecCKRecordKeyState], CKKSZoneKeyToNumber(SecCKKSZoneKeyStateInitializing), "Device is in keystate:initializing"); + + XCTAssertNil(record[SecCKRecordCurrentTLK] , "No TLK"); + XCTAssertNil(record[SecCKRecordCurrentClassA], "No class A key"); + XCTAssertNil(record[SecCKRecordCurrentClassC], "No class C key"); + return YES; + } else { + return NO; + } + } + runAfterModification:nil]; + + CKKSUpdateDeviceStateOperation* op = [self.keychainView updateDeviceState:false ckoperationGroup:nil]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); + + [op waitUntilFinished]; + XCTAssertNil(op.error, "No error uploading 'out of circle' device state"); +} + +- (void)testCKKSControlBringup { + xpc_endpoint_t endpoint = SecServerCreateCKKSEndpoint(); + XCTAssertNotNil(endpoint, "Received endpoint"); + + NSXPCInterface *interface = CKKSSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(CKKSControlProtocol)]); + XCTAssertNotNil(interface, "Received a configured CKKS interface"); + + NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; + [listenerEndpoint _setEndpoint:endpoint]; + + NSXPCConnection* connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; + XCTAssertNotNil(connection , "Received an active connection"); + + connection.remoteObjectInterface = interface; +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h new file mode 100644 index 00000000..46ee617a --- /dev/null +++ b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h @@ -0,0 +1,102 @@ +/* + * 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 "CloudKitMockXCTest.h" +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSCurrentKeyPointer.h" + +@class CKKSKey; +@class CKKSCurrentKeyPointer; + +@interface ZoneKeys : CKKSCurrentKeySet +@property CKKSKey* rolledTLK; +@end + +/* + * Builds on the CloudKit mock infrastructure and adds keychain helper methods. + */ + +@interface CloudKitKeychainSyncingMockXCTest : CloudKitMockXCTest + +@property id mockCKKSKey; + +@property NSMutableDictionary* keys; + +// Pass in an oldTLK to wrap it to the new TLK; otherwise, pass nil +- (ZoneKeys*)createFakeKeyHierarchy: (CKRecordZoneID*)zoneID oldTLK:(CKKSKey*) oldTLK; +- (void)saveFakeKeyHierarchyToLocalDatabase: (CKRecordZoneID*)zoneID; +- (void)putFakeKeyHierarchyInCloudKit: (CKRecordZoneID*)zoneID; +- (void)saveTLKMaterialToKeychain: (CKRecordZoneID*)zoneID; +- (void)deleteTLKMaterialFromKeychain: (CKRecordZoneID*)zoneID; +- (void)saveTLKMaterialToKeychainSimulatingSOS: (CKRecordZoneID*)zoneID; +- (void)SOSPiggyBackAddToKeychain:(NSDictionary*)piggydata; +- (NSMutableDictionary*)SOSPiggyBackCopyFromKeychain; +- (NSMutableArray*) SOSPiggyICloudIdentities; + +- (void)saveClassKeyMaterialToKeychain: (CKRecordZoneID*)zoneID; + +// Call this to fake out your test: all keys are created, saved in cloudkit, and saved locally (as if the key state machine had processed them) +- (void)createAndSaveFakeKeyHierarchy: (CKRecordZoneID*)zoneID; + +- (void)rollFakeKeyHierarchyInCloudKit: (CKRecordZoneID*)zoneID; + +- (NSDictionary*)fakeRecordDictionary:(NSString*) account zoneID:(CKRecordZoneID*)zoneID; +- (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName ; +- (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName withAccount: (NSString*) account; +- (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName withAccount: (NSString*) account key:(CKKSKey*)key; + +- (CKRecord*)newRecord: (CKRecordID*) recordID withNewItemData:(NSDictionary*) dictionary; +- (CKRecord*)newRecord: (CKRecordID*) recordID withNewItemData:(NSDictionary*) dictionary key:(CKKSKey*)key; +- (NSDictionary*)decryptRecord: (CKRecord*) record; + +// Do keychain things: +- (void)addGenericPassword: (NSString*) password account: (NSString*) account; +- (void)addGenericPassword: (NSString*) password account: (NSString*) account viewHint:(NSString*)viewHint; +- (void)addGenericPassword: (NSString*) password account: (NSString*) account viewHint: (NSString*) viewHint access:(NSString*)access expecting: (OSStatus) status message: (NSString*) message; +- (void)addGenericPassword: (NSString*) password account: (NSString*) account expecting: (OSStatus) status message: (NSString*) message; + +- (void)updateGenericPassword: (NSString*) newPassword account: (NSString*)account; +- (void)updateAccountOfGenericPassword:(NSString*)newAccount account:(NSString*)account; + +- (void)checkNoCKKSData: (CKKSKeychainView*) view; + +- (void)deleteGenericPassword: (NSString*) account; + +- (void)findGenericPassword: (NSString*) account expecting: (OSStatus) status; +- (void)checkGenericPassword: (NSString*) password account: (NSString*) account; + +- (void)createClassCItemAndWaitForUpload:(CKRecordZoneID*)zoneID account:(NSString*)account; +- (void)createClassAItemAndWaitForUpload:(CKRecordZoneID*)zoneID account:(NSString*)account; + +// Pass the blocks created with these to expectCKModifyItemRecords to check if all items were encrypted with a particular class key +- (BOOL (^) (CKRecord*)) checkClassABlock: (CKRecordZoneID*) zoneID message:(NSString*) message; +- (BOOL (^) (CKRecord*)) checkClassCBlock: (CKRecordZoneID*) zoneID message:(NSString*) message; + +- (BOOL (^) (CKRecord*)) checkPasswordBlock:(CKRecordZoneID*)zoneID + account:(NSString*)account + password:(NSString*)password; + +- (void)checkNSyncableTLKsInKeychain:(size_t)n; + +// Returns an expectation that someone will send an NSNotification that this view changed +-(XCTestExpectation*)expectChangeForView:(NSString*)view; +@end diff --git a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m new file mode 100644 index 00000000..3dfcbe9e --- /dev/null +++ b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#if OCTAGON + +#import + +#import "keychain/ckks/tests/CloudKitMockXCTest.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" + +#import +#import + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSCurrentKeyPointer.h" +#import "keychain/ckks/CKKSItemEncrypter.h" +#import "keychain/ckks/CKKSKey.h" +#import "keychain/ckks/CKKSOutgoingQueueEntry.h" +#import "keychain/ckks/CKKSIncomingQueueEntry.h" +#import "keychain/ckks/CKKSSynchronizeOperation.h" +#import "keychain/ckks/CKKSViewManager.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" +#import "keychain/ckks/CKKSManifest.h" + +#import "Security/SecureObjectSync/SOSAccount.h" +@implementation ZoneKeys +@end + +// No tests here, just helper functions +@implementation CloudKitKeychainSyncingMockXCTest + +- (void)setUp { + // Need to convince your tests to set these, no matter what the on-disk pist says? Uncomment. + (void)[CKKSManifest shouldSyncManifests]; // perfrom initialization + SecCKKSSetSyncManifests(false); + SecCKKSSetEnforceManifests(false); + + // Check that your environment is set up correctly + XCTAssertFalse([CKKSManifest shouldSyncManifests], "Manifests syncing is disabled"); + XCTAssertFalse([CKKSManifest shouldEnforceManifests], "Manifests enforcement is disabled"); + + [super setUp]; + self.keys = [[NSMutableDictionary alloc] init]; + + // Fake out whether class A keys can be loaded from the keychain. + self.mockCKKSKey = OCMClassMock([CKKSKey class]); + __weak __typeof(self) weakSelf = self; + OCMStub([self.mockCKKSKey loadKeyMaterialFromKeychain:[OCMArg checkWithBlock:^BOOL(CKKSKey* key) { + __strong __typeof(self) strongSelf = weakSelf; + return ([key.keyclass isEqualToString: SecCKKSKeyClassA] || [key.keyclass isEqualToString: SecCKKSKeyClassTLK]) && strongSelf.aksLockState; + }] + resave:[OCMArg anyPointer] + error:[OCMArg anyObjectRef]]).andCall(self, @selector(handleLockLoadKeyMaterialFromKeychain:resave:error:)); + + OCMStub([self.mockCKKSKey saveKeyMaterialToKeychain:[OCMArg checkWithBlock:^BOOL(CKKSKey* key) { + __strong __typeof(self) strongSelf = weakSelf; + return ([key.keyclass isEqualToString: SecCKKSKeyClassA] || [key.keyclass isEqualToString: SecCKKSKeyClassTLK]) && strongSelf.aksLockState; + }] + stashTLK:[OCMArg anyObjectRef] + error:[OCMArg anyObjectRef]] + ).andCall(self, @selector(handleLockSaveKeyMaterialToKeychain:stashTLK:error:)); +} + +- (void)tearDown { + [self.mockCKKSKey stopMocking]; + self.mockCKKSKey = nil; + + [super tearDown]; + self.keys = nil; +} + +- (void)createClassCItemAndWaitForUpload:(CKRecordZoneID*)zoneID account:(NSString*)account { + [self expectCKModifyItemRecords:1 + currentKeyPointerRecords:1 + zoneID:zoneID + checkItem:[self checkClassCBlock:zoneID message:@"Object was encrypted under class C key in hierarchy"]]; + [self addGenericPassword: @"data" account: account]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +- (void)createClassAItemAndWaitForUpload:(CKRecordZoneID*)zoneID account:(NSString*)account { + [self expectCKModifyItemRecords:1 + currentKeyPointerRecords:1 + zoneID:zoneID + checkItem: [self checkClassABlock:zoneID message:@"Object was encrypted under class A key in hierarchy"]]; + [self addGenericPassword:@"asdf" + account:account + viewHint:nil + access:(id)kSecAttrAccessibleWhenUnlocked + expecting:errSecSuccess + message:@"Adding class A item"]; + OCMVerifyAllWithDelay(self.mockDatabase, 8); +} + +// Helpers to handle keychain 'locked' loading +-(bool)handleLockLoadKeyMaterialFromKeychain:(CKKSKey*)key resave:(bool*)resavePtr error:(NSError * __autoreleasing *) error { + XCTAssertTrue(self.aksLockState, "Failing a read only when keychain is locked"); + if(error) { + *error = [NSError errorWithDomain:@"securityd" code:errSecInteractionNotAllowed userInfo:nil]; + } + return false; +} + +-(bool)handleLockSaveKeyMaterialToKeychain:(CKKSKey*)key stashTLK:(bool)stashTLK error:(NSError * __autoreleasing *) error { + XCTAssertTrue(self.aksLockState, "Failing a write only when keychain is locked"); + if(error) { + *error = [NSError errorWithDomain:@"securityd" code:errSecInteractionNotAllowed userInfo:nil]; + } + return false; +} + + +- (ZoneKeys*)createFakeKeyHierarchy: (CKRecordZoneID*)zoneID oldTLK:(CKKSKey*) oldTLK { + if(self.keys[zoneID]) { + // Already created. Skip. + return self.keys[zoneID]; + } + + NSError* error = nil; + + ZoneKeys* zonekeys = [[ZoneKeys alloc] init]; + + zonekeys.tlk = [self fakeTLK:zoneID]; + [zonekeys.tlk CKRecordWithZoneID: zoneID]; // no-op here, but memoize in the object + zonekeys.currentTLKPointer = [[CKKSCurrentKeyPointer alloc] initForClass: SecCKKSKeyClassTLK currentKeyUUID: zonekeys.tlk.uuid zoneID:zoneID encodedCKRecord: nil]; + [zonekeys.currentTLKPointer CKRecordWithZoneID: zoneID]; + + if(oldTLK) { + zonekeys.rolledTLK = oldTLK; + [zonekeys.rolledTLK wrapUnder: zonekeys.tlk error:&error]; + XCTAssertNotNil(zonekeys.rolledTLK, "Created a rolled TLK"); + XCTAssertNil(error, "No error creating rolled TLK"); + } + + zonekeys.classA = [CKKSKey randomKeyWrappedByParent: zonekeys.tlk keyclass:SecCKKSKeyClassA error:&error]; + XCTAssertNotNil(zonekeys.classA, "make Class A key"); + zonekeys.classA.currentkey = true; + [zonekeys.classA CKRecordWithZoneID: zoneID]; + zonekeys.currentClassAPointer = [[CKKSCurrentKeyPointer alloc] initForClass: SecCKKSKeyClassA currentKeyUUID: zonekeys.classA.uuid zoneID:zoneID encodedCKRecord: nil]; + [zonekeys.currentClassAPointer CKRecordWithZoneID: zoneID]; + + zonekeys.classC = [CKKSKey randomKeyWrappedByParent: zonekeys.tlk keyclass:SecCKKSKeyClassC error:&error]; + XCTAssertNotNil(zonekeys.classC, "make Class C key"); + zonekeys.classC.currentkey = true; + [zonekeys.classC CKRecordWithZoneID: zoneID]; + zonekeys.currentClassCPointer = [[CKKSCurrentKeyPointer alloc] initForClass: SecCKKSKeyClassC currentKeyUUID: zonekeys.classC.uuid zoneID:zoneID encodedCKRecord: nil]; + [zonekeys.currentClassCPointer CKRecordWithZoneID: zoneID]; + + self.keys[zoneID] = zonekeys; + return zonekeys; +} + +- (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"); + + [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.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.currentClassCPointer saveToDatabase:&error]; + XCTAssertNil(error, "Current Class C pointer saved to database successfully"); +} + +- (void)putFakeKeyHierarchyInCloudKit: (CKRecordZoneID*)zoneID { + ZoneKeys* zonekeys = [self createFakeKeyHierarchy: zoneID oldTLK:nil]; + + [self.zones[zoneID] addToZone: zonekeys.tlk zoneID: zoneID]; + [self.zones[zoneID] addToZone: zonekeys.classA zoneID: zoneID]; + [self.zones[zoneID] addToZone: zonekeys.classC zoneID: zoneID]; + + [self.zones[zoneID] addToZone: zonekeys.currentTLKPointer zoneID: zoneID]; + [self.zones[zoneID] addToZone: zonekeys.currentClassAPointer zoneID: zoneID]; + [self.zones[zoneID] addToZone: zonekeys.currentClassCPointer zoneID: zoneID]; + + if(zonekeys.rolledTLK) { + [self.zones[zoneID] addToZone: zonekeys.rolledTLK zoneID: zoneID]; + } +} + +- (void)rollFakeKeyHierarchyInCloudKit: (CKRecordZoneID*)zoneID { + ZoneKeys* zonekeys = self.keys[zoneID]; + self.keys[zoneID] = nil; + + CKKSKey* oldTLK = zonekeys.tlk; + + [self createFakeKeyHierarchy: zoneID oldTLK:oldTLK]; + [self putFakeKeyHierarchyInCloudKit: zoneID]; +} + +- (void)saveTLKMaterialToKeychainSimulatingSOS: (CKRecordZoneID*)zoneID { + + XCTAssertNotNil(self.keys[zoneID].tlk, "Have a TLK to save for zone %@", zoneID); + + __block CFErrorRef cferror = NULL; + kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) { + bool ok = kc_transaction_type(dbt, kSecDbExclusiveRemoteSOSTransactionType, &cferror, ^bool { + NSError* error = nil; + [self.keys[zoneID].tlk saveKeyMaterialToKeychain: false error:&error]; + XCTAssertNil(error, @"Saved TLK material to keychain"); + return true; + }); + return ok; + }); + + XCTAssertNil( (__bridge NSError*)cferror, @"no error with transaction"); + CFReleaseNull(cferror); +} +static SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, SecKeyRef* outOctagonSigningKey, CFErrorRef *error) +{ + SOSFullPeerInfoRef result = NULL; + SecKeyRef publicKey = NULL; + CFDictionaryRef gestalt = NULL; + + *outSigningKey = GeneratePermanentFullECKey(256, name, error); + + *outOctagonSigningKey = GeneratePermanentFullECKey(384, name, error); + + gestalt = SOSCreatePeerGestaltFromName(name); + + result = SOSFullPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey, *outOctagonSigningKey, error); + + CFReleaseNull(gestalt); + CFReleaseNull(publicKey); + + return result; +} +- (NSMutableArray*) SOSPiggyICloudIdentities +{ + SecKeyRef signingKey = NULL; + SecKeyRef octagonSigningKey = NULL; + NSMutableArray* icloudidentities = [NSMutableArray array]; + + SOSFullPeerInfoRef fpi = SOSCreateFullPeerInfoFromName(CFSTR("Test Peer"), &signingKey, &octagonSigningKey, NULL); + + NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(SOSFullPeerInfoGetPeerInfo(fpi), NULL)); + if (data) + [icloudidentities addObject:data]; + + CFReleaseNull(signingKey); + CFReleaseNull(octagonSigningKey); + + return icloudidentities; +} +static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name) +{ + return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, + kPIUserDefinedDeviceNameKey, name, + NULL); +} +-(NSMutableDictionary*)SOSPiggyBackCopyFromKeychain +{ + __block NSMutableDictionary *piggybackdata = [[NSMutableDictionary alloc] init]; + __block CFErrorRef cferror = NULL; + kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) { + bool ok = kc_transaction_type(dbt, kSecDbExclusiveRemoteSOSTransactionType, &cferror, ^bool { + piggybackdata[@"idents"] = [self SOSPiggyICloudIdentities]; + piggybackdata[@"tlk"] = SOSAccountGetAllTLKs(); + + return true; + }); + return ok; + }); + + XCTAssertNil( (__bridge NSError*)cferror, @"no error with transaction"); + CFReleaseNull(cferror); + return piggybackdata; +} +- (void)SOSPiggyBackAddToKeychain:(NSDictionary*)piggydata{ + __block CFErrorRef cferror = NULL; + kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) { + bool ok = kc_transaction_type(dbt, kSecDbExclusiveRemoteSOSTransactionType, &cferror, ^bool { + NSError* error = nil; + NSArray* icloudidentities = piggydata[@"idents"]; + NSArray* tlk = piggydata[@"tlk"]; + + SOSPiggyBackAddToKeychain(icloudidentities, tlk); + + XCTAssertNil(error, @"Saved TLK-piggy material to keychain"); + return true; + }); + return ok; + }); + + XCTAssertNil( (__bridge NSError*)cferror, @"no error with transaction"); + CFReleaseNull(cferror); +} + +- (void)saveTLKMaterialToKeychain: (CKRecordZoneID*)zoneID { + NSError* error = nil; + XCTAssertNotNil(self.keys[zoneID].tlk, "Have a TLK to save for zone %@", zoneID); + [self.keys[zoneID].tlk saveKeyMaterialToKeychain:&error]; + XCTAssertNil(error, @"Saved TLK material to keychain"); +} + +- (void)deleteTLKMaterialFromKeychain: (CKRecordZoneID*)zoneID { + NSError* error = nil; + XCTAssertNotNil(self.keys[zoneID].tlk, "Have a TLK to save for zone %@", zoneID); + [self.keys[zoneID].tlk deleteKeyMaterialFromKeychain:&error]; + XCTAssertNil(error, @"Saved TLK material to keychain"); +} + +- (void)saveClassKeyMaterialToKeychain: (CKRecordZoneID*)zoneID { + NSError* error = nil; + XCTAssertNotNil(self.keys[zoneID].classA, "Have a Class A to save for zone %@", zoneID); + [self.keys[zoneID].classA saveKeyMaterialToKeychain:&error]; + XCTAssertNil(error, @"Saved Class A material to keychain"); + + XCTAssertNotNil(self.keys[zoneID].classC, "Have a Class C to save for zone %@", zoneID); + [self.keys[zoneID].classC saveKeyMaterialToKeychain:&error]; + XCTAssertNil(error, @"Saved Class C material to keychain"); +} + +- (void)createAndSaveFakeKeyHierarchy: (CKRecordZoneID*)zoneID { + [self saveFakeKeyHierarchyToLocalDatabase: zoneID]; + [self putFakeKeyHierarchyInCloudKit: zoneID]; + [self saveTLKMaterialToKeychain: zoneID]; + [self saveClassKeyMaterialToKeychain: zoneID]; +} + +// Override our base class here: +- (void)expectCKModifyKeyRecords: (NSUInteger) expectedNumberOfRecords currentKeyPointerRecords: (NSUInteger) expectedCurrentKeyRecords zoneID: (CKRecordZoneID*) zoneID { + + __weak __typeof(self) weakSelf = self; + [self expectCKModifyRecords: @{ + SecCKRecordIntermediateKeyType: [NSNumber numberWithUnsignedInteger: expectedNumberOfRecords], + SecCKRecordCurrentKeyType: [NSNumber numberWithUnsignedInteger: expectedCurrentKeyRecords]} + deletedRecordTypeCounts:nil + zoneID:zoneID + checkModifiedRecord:nil + runAfterModification:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + // Reach into our cloudkit database and extract the keys + CKRecordID* currentTLKPointerID = [[CKRecordID alloc] initWithRecordName:SecCKKSKeyClassTLK zoneID:zoneID]; + CKRecordID* currentClassAPointerID = [[CKRecordID alloc] initWithRecordName:SecCKKSKeyClassA zoneID:zoneID]; + CKRecordID* currentClassCPointerID = [[CKRecordID alloc] initWithRecordName:SecCKKSKeyClassC zoneID:zoneID]; + + ZoneKeys* zonekeys = strongSelf.keys[zoneID]; + if(!zonekeys) { + zonekeys = [[ZoneKeys alloc] init]; + strongSelf.keys[zoneID] = zonekeys; + } + + XCTAssertNotNil(strongSelf.zones[zoneID].currentDatabase[currentTLKPointerID], "Have a currentTLKPointer"); + XCTAssertNotNil(strongSelf.zones[zoneID].currentDatabase[currentClassAPointerID], "Have a currentClassAPointer"); + XCTAssertNotNil(strongSelf.zones[zoneID].currentDatabase[currentClassCPointerID], "Have a currentClassCPointer"); + XCTAssertNotNil(strongSelf.zones[zoneID].currentDatabase[currentTLKPointerID][SecCKRecordParentKeyRefKey], "Have a currentTLKPointer parent"); + XCTAssertNotNil(strongSelf.zones[zoneID].currentDatabase[currentClassAPointerID][SecCKRecordParentKeyRefKey], "Have a currentClassAPointer parent"); + XCTAssertNotNil(strongSelf.zones[zoneID].currentDatabase[currentClassCPointerID][SecCKRecordParentKeyRefKey], "Have a currentClassCPointer parent"); + XCTAssertNotNil([strongSelf.zones[zoneID].currentDatabase[currentTLKPointerID][SecCKRecordParentKeyRefKey] recordID].recordName, "Have a currentTLKPointer parent UUID"); + XCTAssertNotNil([strongSelf.zones[zoneID].currentDatabase[currentClassAPointerID][SecCKRecordParentKeyRefKey] recordID].recordName, "Have a currentClassAPointer parent UUID"); + XCTAssertNotNil([strongSelf.zones[zoneID].currentDatabase[currentClassCPointerID][SecCKRecordParentKeyRefKey] recordID].recordName, "Have a currentClassCPointer parent UUID"); + + zonekeys.currentTLKPointer = [[CKKSCurrentKeyPointer alloc] initWithCKRecord: strongSelf.zones[zoneID].currentDatabase[currentTLKPointerID]]; + zonekeys.currentClassAPointer = [[CKKSCurrentKeyPointer alloc] initWithCKRecord: strongSelf.zones[zoneID].currentDatabase[currentClassAPointerID]]; + zonekeys.currentClassCPointer = [[CKKSCurrentKeyPointer alloc] initWithCKRecord: strongSelf.zones[zoneID].currentDatabase[currentClassCPointerID]]; + + XCTAssertNotNil(zonekeys.currentTLKPointer.currentKeyUUID, "Have a currentTLKPointer current UUID"); + XCTAssertNotNil(zonekeys.currentClassAPointer.currentKeyUUID, "Have a currentClassAPointer current UUID"); + XCTAssertNotNil(zonekeys.currentClassCPointer.currentKeyUUID, "Have a currentClassCPointer current UUID"); + + CKRecordID* currentTLKID = [[CKRecordID alloc] initWithRecordName:zonekeys.currentTLKPointer.currentKeyUUID zoneID:zoneID]; + CKRecordID* currentClassAID = [[CKRecordID alloc] initWithRecordName:zonekeys.currentClassAPointer.currentKeyUUID zoneID:zoneID]; + CKRecordID* currentClassCID = [[CKRecordID alloc] initWithRecordName:zonekeys.currentClassCPointer.currentKeyUUID zoneID:zoneID]; + + zonekeys.tlk = [[CKKSKey alloc] initWithCKRecord: strongSelf.zones[zoneID].currentDatabase[currentTLKID]]; + zonekeys.classA = [[CKKSKey alloc] initWithCKRecord: strongSelf.zones[zoneID].currentDatabase[currentClassAID]]; + zonekeys.classC = [[CKKSKey alloc] initWithCKRecord: strongSelf.zones[zoneID].currentDatabase[currentClassCID]]; + + XCTAssertNotNil(zonekeys.tlk, "Have the current TLK"); + XCTAssertNotNil(zonekeys.classA, "Have the current Class A key"); + XCTAssertNotNil(zonekeys.classC, "Have the current Class C key"); + }]; +} + +- (void)checkNoCKKSData: (CKKSKeychainView*) view { + // Test that there are no items in the database + [view dispatchSync:^bool{ + NSError* error = nil; + NSArray* ckmes = [CKKSMirrorEntry all: view.zoneID error:&error]; + XCTAssertNil(error, "No error fetching CKMEs"); + XCTAssertEqual(ckmes.count, 0ul, "No CKMirrorEntries"); + + NSArray* oqes = [CKKSOutgoingQueueEntry all: view.zoneID error:&error]; + XCTAssertNil(error, "No error fetching OQEs"); + XCTAssertEqual(oqes.count, 0ul, "No OutgoingQueueEntries"); + + NSArray* iqes = [CKKSIncomingQueueEntry all: view.zoneID error:&error]; + XCTAssertNil(error, "No error fetching IQEs"); + XCTAssertEqual(iqes.count, 0ul, "No IncomingQueueEntries"); + + NSArray* keys = [CKKSKey all: view.zoneID error:&error]; + XCTAssertNil(error, "No error fetching keys"); + XCTAssertEqual(keys.count, 0ul, "No CKKSKeys"); + + NSArray* 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; + }]; +} + +- (BOOL (^) (CKRecord*)) checkClassABlock: (CKRecordZoneID*) zoneID message:(NSString*) message { + __weak __typeof(self) weakSelf = self; + return ^BOOL(CKRecord* record) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + ZoneKeys* zoneKeys = strongSelf.keys[zoneID]; + XCTAssertNotNil(zoneKeys, "Have zone keys for %@", zoneID); + XCTAssertEqualObjects([record[SecCKRecordParentKeyRefKey] recordID].recordName, zoneKeys.classA.uuid, "%@", message); + return [[record[SecCKRecordParentKeyRefKey] recordID].recordName isEqual: zoneKeys.classA.uuid]; + }; +} + +- (BOOL (^) (CKRecord*)) checkClassCBlock: (CKRecordZoneID*) zoneID message:(NSString*) message { + __weak __typeof(self) weakSelf = self; + return ^BOOL(CKRecord* record) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + ZoneKeys* zoneKeys = strongSelf.keys[zoneID]; + XCTAssertNotNil(zoneKeys, "Have zone keys for %@", zoneID); + XCTAssertEqualObjects([record[SecCKRecordParentKeyRefKey] recordID].recordName, zoneKeys.classC.uuid, "%@", message); + return [[record[SecCKRecordParentKeyRefKey] recordID].recordName isEqual: zoneKeys.classC.uuid]; + }; +} + +- (BOOL (^) (CKRecord*)) checkPasswordBlock:(CKRecordZoneID*)zoneID + account:(NSString*)account + password:(NSString*)password { + __weak __typeof(self) weakSelf = self; + return ^BOOL(CKRecord* record) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + ZoneKeys* zoneKeys = strongSelf.keys[zoneID]; + XCTAssertNotNil(zoneKeys, "Have zone keys for %@", zoneID); + XCTAssertNotNil([record[SecCKRecordParentKeyRefKey] recordID].recordName, "Have a wrapping key"); + + CKKSKey* key = nil; + if([[record[SecCKRecordParentKeyRefKey] recordID].recordName isEqualToString: zoneKeys.classC.uuid]) { + key = zoneKeys.classC; + } else if([[record[SecCKRecordParentKeyRefKey] recordID].recordName isEqualToString: zoneKeys.classA.uuid]) { + key = zoneKeys.classA; + } + XCTAssertNotNil(key, "Found a key via UUID"); + + CKKSMirrorEntry* ckme = [[CKKSMirrorEntry alloc] initWithCKRecord: record]; + + NSError* error = nil; + NSDictionary* dict = [CKKSItemEncrypter decryptItemToDictionary:ckme.item error:&error]; + XCTAssertNil(error, "No error decrypting item"); + XCTAssertEqualObjects(account, dict[(id)kSecAttrAccount], "Account matches"); + XCTAssertEqualObjects([password dataUsingEncoding:NSUTF8StringEncoding], dict[(id)kSecValueData], "Password matches"); + return YES; + }; +} + +- (NSDictionary*)fakeRecordDictionary:(NSString*) account zoneID:(CKRecordZoneID*)zoneID { + 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"; + item[@"vwht"] = @"keychain"; + XCTAssertNil(error, "no error interpreting data as item"); + XCTAssertNotNil(item, "interpreted data as item"); + + if(zoneID && ![zoneID.zoneName isEqualToString:@"keychain"]) { + [item setObject: zoneID.zoneName forKey: (__bridge id) kSecAttrSyncViewHint]; + } + + if(account) { + [item setObject: account forKey: (__bridge id) kSecAttrAccount]; + } + return item; +} + +- (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName { + return [self createFakeRecord: zoneID recordName:recordName withAccount: nil key:nil]; +} + +- (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName withAccount: (NSString*) account { + return [self createFakeRecord: zoneID recordName:recordName withAccount:account key:nil]; +} + +- (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName withAccount: (NSString*) account key:(CKKSKey*)key { + NSDictionary* item = [self fakeRecordDictionary: account zoneID:zoneID]; + + CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:recordName zoneID:zoneID]; + if(key) { + return [self newRecord: ckrid withNewItemData:item key:key]; + } else { + return [self newRecord: ckrid withNewItemData:item]; + } +} + +- (CKRecord*)newRecord: (CKRecordID*) recordID withNewItemData:(NSDictionary*) dictionary { + ZoneKeys* zonekeys = self.keys[recordID.zoneID]; + XCTAssertNotNil(zonekeys, "Have zone keys for zone"); + XCTAssertNotNil(zonekeys.classC, "Have class C key for zone"); + + return [self newRecord:recordID withNewItemData:dictionary key:zonekeys.classC]; +} + +- (CKRecord*)newRecord: (CKRecordID*) recordID withNewItemData:(NSDictionary*) dictionary key:(CKKSKey*)key { + NSError* error = nil; + CKKSItem* cipheritem = [CKKSItemEncrypter encryptCKKSItem:[[CKKSItem alloc] initWithUUID:recordID.recordName + parentKeyUUID:key.uuid + zoneID:recordID.zoneID] + dataDictionary:dictionary + updatingCKKSItem:nil + parentkey:key + error:&error]; + XCTAssertNil(error, "encrypted item with class c key"); + XCTAssertNotNil(cipheritem, "Have an encrypted item"); + + CKRecord* ckr = [cipheritem CKRecordWithZoneID: recordID.zoneID]; + XCTAssertNotNil(ckr, "Created a CKRecord"); + return ckr; +} + +- (NSDictionary*)decryptRecord: (CKRecord*) record { + CKKSItem* item = [[CKKSItem alloc] initWithCKRecord: record]; + + NSError* error = nil; + + NSDictionary* ret = [CKKSItemEncrypter decryptItemToDictionary: item error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(ret); + return ret; +} + +- (void)addGenericPassword: (NSString*) password account: (NSString*) account viewHint: (NSString*) viewHint access: (NSString*) access expecting: (OSStatus) status message: (NSString*) message { + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccessible: access, + (id)kSecAttrAccount : account, + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecValueData : (id) [password dataUsingEncoding:NSUTF8StringEncoding], + } mutableCopy]; + + if(viewHint) { + query[(id)kSecAttrSyncViewHint] = viewHint; + } else { + // Fake it as 'keychain'. This lets CKKSScanLocalItemsOperation for the test-only 'keychain' view find items which would normally not have a view hint. + query[(id)kSecAttrSyncViewHint] = @"keychain"; + } + + XCTAssertEqual(status, SecItemAdd((__bridge CFDictionaryRef) query, NULL), @"%@", message); +} + +- (void)addGenericPassword: (NSString*) password account: (NSString*) account expecting: (OSStatus) status message: (NSString*) message { + [self addGenericPassword:password account:account viewHint:nil access:(id)kSecAttrAccessibleAfterFirstUnlock expecting:errSecSuccess message:message]; + +} + +- (void)addGenericPassword: (NSString*) password account: (NSString*) account { + [self addGenericPassword:password account:account viewHint:nil access:(id)kSecAttrAccessibleAfterFirstUnlock expecting:errSecSuccess message:@"Add item to keychain"]; +} + +- (void)addGenericPassword: (NSString*) password account: (NSString*) account viewHint:(NSString*)viewHint { + [self addGenericPassword:password account:account viewHint:viewHint access:(id)kSecAttrAccessibleAfterFirstUnlock expecting:errSecSuccess message:@"Add item to keychain with a viewhint"]; +} + +- (void)updateGenericPassword: (NSString*) newPassword account: (NSString*)account { + NSDictionary* query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccount : account, + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + }; + + NSDictionary* update = @{ + (id)kSecValueData : (id) [newPassword dataUsingEncoding:NSUTF8StringEncoding], + }; + XCTAssertEqual(errSecSuccess, SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef) update), @"Updating item %@ to %@", account, newPassword); +} + +- (void)updateAccountOfGenericPassword:(NSString*)newAccount + account:(NSString*)account { + NSDictionary* query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrAccount : account, + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + }; + + NSDictionary* update = @{ + (id)kSecAttrAccount : (id) newAccount, + }; + XCTAssertEqual(errSecSuccess, SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef) update), @"Updating item %@ to account %@", account, newAccount); +} + +- (void)deleteGenericPassword: (NSString*) account { + NSDictionary* query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : account, + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + }; + + XCTAssertEqual(errSecSuccess, SecItemDelete((__bridge CFDictionaryRef) query), @"Deleting item %@", account); +} + +- (void)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, + }; + XCTAssertEqual(status, SecItemCopyMatching((__bridge CFDictionaryRef) query, NULL), "Finding item %@", account); +} + +- (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"); +} + +-(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); + return YES; + }]; +} + +- (void)checkNSyncableTLKsInKeychain:(size_t)n { + NSDictionary *query = @{(id)kSecClass : (id)kSecClassInternetPassword, + (id)kSecAttrAccessGroup : @"com.apple.security.ckks", + (id)kSecAttrSynchronizable : (id)kCFBooleanTrue, + (id)kSecAttrDescription: SecCKKSKeyClassTLK, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecReturnAttributes : (id)kCFBooleanTrue, + }; + CFTypeRef result = NULL; + + if(n == 0) { + XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &result), "Should have found no TLKs"); + } else { + XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &result), "Should have found TLKs"); + NSArray* items = (NSArray*) CFBridgingRelease(result); + + XCTAssertEqual(items.count, n, "Should have received %lu items", n); + } +} + +@end + +#endif // OCTAGON diff --git a/keychain/ckks/tests/CloudKitMockXCTest.h b/keychain/ckks/tests/CloudKitMockXCTest.h new file mode 100644 index 00000000..b5dd2435 --- /dev/null +++ b/keychain/ckks/tests/CloudKitMockXCTest.h @@ -0,0 +1,139 @@ +/* + * 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 +#import +#import + +#import + +#import "keychain/ckks/tests/MockCloudKit.h" +#import "keychain/ckks/CKKSCKAccountStateTracker.h" + +@class CKKSKey; +@class CKKSCKRecordHolder; +@class CKKSKeychainView; +@class CKKSViewManager; +@class FakeCKZone; +@class CKKSLockStateTracker; + +@interface CloudKitMockXCTest : XCTestCase + +#if OCTAGON + +@property CKRecordZoneID* testZoneID; + +@property id mockDatabase; +@property id mockContainer; +@property id mockFakeCKModifyRecordZonesOperation; +@property id mockFakeCKModifySubscriptionsOperation; +@property id mockFakeCKFetchRecordZoneChangesOperation; + +@property id mockAccountStateTracker; + +@property CKAccountStatus accountStatus; +@property BOOL supportsDeviceToDeviceEncryption; +@property SOSCCStatus circleStatus; +@property (readonly) NSString* ckDeviceID; +@property (readonly) CKKSCKAccountStateTracker* accountStateTracker; + +@property NSString* circlePeerID; + +@property bool aksLockState; // The current 'AKS lock state' +@property (readonly) CKKSLockStateTracker* lockStateTracker; +@property id mockLockStateTracker; + +@property NSMutableDictionary* zones; + +@property NSOperationQueue* operationQueue; +@property NSBlockOperation* ckksHoldOperation; +@property NSBlockOperation* ckaccountHoldOperation; + +@property NSBlockOperation* ckModifyHoldOperation; + +@property bool silentFetchesAllowed; + +@property id mockCKKSViewManager; +@property CKKSViewManager* injectedManager; + +- (CKKSKey*) fakeTLK: (CKRecordZoneID*)zoneID; + +- (void)expectCKModifyItemRecords: (NSUInteger) expectedNumberOfRecords + currentKeyPointerRecords: (NSUInteger) expectedCurrentKeyRecords + zoneID: (CKRecordZoneID*) zoneID; +- (void)expectCKModifyItemRecords: (NSUInteger) expectedNumberOfRecords + currentKeyPointerRecords: (NSUInteger) expectedCurrentKeyRecords + zoneID: (CKRecordZoneID*) zoneID + checkItem: (BOOL (^)(CKRecord*)) checkItem; + +- (void)expectCKModifyItemRecords:(NSUInteger)expectedNumberOfModifiedRecords + deletedRecords:(NSUInteger)expectedNumberOfDeletedRecords + currentKeyPointerRecords:(NSUInteger)expectedCurrentKeyRecords + zoneID:(CKRecordZoneID*)zoneID + checkItem:(BOOL (^)(CKRecord*))checkItem; + +- (void)expectCKDeleteItemRecords: (NSUInteger) expectedNumberOfRecords zoneID: (CKRecordZoneID*) zoneID; + +- (void)expectCKModifyKeyRecords: (NSUInteger) expectedNumberOfRecords + currentKeyPointerRecords: (NSUInteger) expectedCurrentKeyRecords + zoneID: (CKRecordZoneID*) zoneID; + +- (void)expectCKModifyRecords:(NSDictionary*) expectedRecordTypeCounts + deletedRecordTypeCounts:(NSDictionary*) expectedDeletedRecordTypeCounts + zoneID:(CKRecordZoneID*) zoneID + checkModifiedRecord:(BOOL (^)(CKRecord*)) checkRecord + runAfterModification:(void (^) ())afterModification; + +- (void)failNextCKAtomicModifyItemRecordsUpdateFailure:(CKRecordZoneID*)zoneID; +- (void)failNextCKAtomicModifyItemRecordsUpdateFailure:(CKRecordZoneID*)zoneID blockAfterReject: (void (^)())blockAfterReject; +- (void)failNextCKAtomicModifyItemRecordsUpdateFailure:(CKRecordZoneID*)zoneID blockAfterReject: (void (^)())blockAfterReject withError:(NSError*)error; +- (void)expectCKAtomicModifyItemRecordsUpdateFailure: (CKRecordZoneID*) zoneID; + +- (void)failNextZoneCreation:(CKRecordZoneID*)zoneID; +- (void)failNextZoneCreationSilently:(CKRecordZoneID*)zoneID; +- (void)failNextZoneSubscription:(CKRecordZoneID*)zoneID; +- (void)failNextZoneSubscription:(CKRecordZoneID*)zoneID withError:(NSError*)error; + +// Use this to assert that a fetch occurs (especially if silentFetchesAllowed = false) +- (void)expectCKFetch; + +// Wait until all scheduled cloudkit operations are reflected in the currentDatabase +- (void)waitForCKModifications; + +// Unblocks the CKKS subsystem only. +- (void)startCKKSSubsystemOnly; + +// Unblocks the CKAccount mock subsystem. Until this is called, the tests believe cloudd hasn't returned any account status yet. +- (void)startCKAccountStatusMock; + +// Starts everything. +- (void)startCKKSSubsystem; + +// Blocks the completion (partial or full) of CloudKit modifications +-(void)holdCloudKitModifications; + +// Unblocks the hold you've added with holdCloudKitModifications; CloudKit modifications will finish +-(void)releaseCloudKitModificationHold; + +#endif // OCTAGON +@end diff --git a/keychain/ckks/tests/CloudKitMockXCTest.m b/keychain/ckks/tests/CloudKitMockXCTest.m new file mode 100644 index 00000000..d965ac99 --- /dev/null +++ b/keychain/ckks/tests/CloudKitMockXCTest.m @@ -0,0 +1,793 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "CloudKitMockXCTest.h" + +#import +#import +#import +#import +#import +#import + +#include "OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.h" +#include +#include + +#if NO_SERVER +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "keychain/ckks/CKKSGroupOperation.h" +#include "keychain/ckks/CKKSLockStateTracker.h" + +#import "MockCloudKit.h" + +@interface BoolHolder : NSObject +@property bool state; +@end + +@implementation BoolHolder +@end + +// Inform OCMock about the internals of CKContainer +@interface CKContainer () +- (void)_checkSelfCloudServicesEntitlement; +@end + + +@implementation CloudKitMockXCTest + ++ (void)setUp { + // Turn on testing + SecCKKSTestsEnable(); + [super setUp]; + +#if NO_SERVER + securityd_init_local_spi(); +#endif +} + +- (void)setUp { + [super setUp]; + + // All tests start with the same flag set. + SecCKKSTestResetFlags(); + SecCKKSTestSetDisableSOS(true); + + self.silentFetchesAllowed = true; + + __weak __typeof(self) weakSelf = self; + self.operationQueue = [[NSOperationQueue alloc] init]; + self.operationQueue.maxConcurrentOperationCount = 1; + + self.zones = [[NSMutableDictionary alloc] init]; + + self.mockDatabase = OCMStrictClassMock([CKDatabase class]); + self.mockContainer = OCMClassMock([CKContainer class]); + OCMStub([self.mockContainer containerWithIdentifier:[OCMArg isKindOfClass:[NSString class]]]).andReturn(self.mockContainer); + OCMStub([self.mockContainer defaultContainer]).andReturn(self.mockContainer); + OCMStub([self.mockContainer alloc]).andReturn(self.mockContainer); + OCMStub([self.mockContainer containerIdentifier]).andReturn(SecCKKSContainerName); + OCMStub([self.mockContainer initWithContainerID: [OCMArg any] options: [OCMArg any]]).andReturn(self.mockContainer); + OCMStub([self.mockContainer privateCloudDatabase]).andReturn(self.mockDatabase); + OCMStub([self.mockContainer serverPreferredPushEnvironmentWithCompletionHandler: ([OCMArg invokeBlockWithArgs:@"fake APS push string", [NSNull null], nil])]); + + // If you want to change this, you'll need to update the mock + _ckDeviceID = @"fake-cloudkit-device-id"; + OCMStub([self.mockContainer fetchCurrentDeviceIDWithCompletionHandler: ([OCMArg invokeBlockWithArgs:self.ckDeviceID, [NSNull null], nil])]); + + self.accountStatus = CKAccountStatusAvailable; + self.supportsDeviceToDeviceEncryption = YES; + + // Inject a fake operation dependency into the manager object, so that the tests can perform setup and mock expectations before zone setup begins + // Also blocks all CK account state retrieval operations (but not circle status ones) + self.ckaccountHoldOperation = [NSBlockOperation named:@"ckaccount-hold" withBlock:^{ + secnotice("ckks", "CKKS CK account status test hold released"); + }]; + + OCMStub([self.mockContainer accountStatusWithCompletionHandler: + [OCMArg checkWithBlock:^BOOL(void (^passedBlock) (CKAccountStatus accountStatus, + NSError * _Nullable error)) { + + if(passedBlock) { + __strong __typeof(self) strongSelf = weakSelf; + NSBlockOperation* fulfillBlock = [NSBlockOperation named:@"account-status-completion" withBlock: ^{ + passedBlock(weakSelf.accountStatus, nil); + }]; + [fulfillBlock addDependency: strongSelf.ckaccountHoldOperation]; + [strongSelf.operationQueue addOperation: fulfillBlock]; + + return YES; + } + return NO; + }]]); + + OCMStub([self.mockContainer accountInfoWithCompletionHandler: + [OCMArg checkWithBlock:^BOOL(void (^passedBlock) (CKAccountInfo* accountInfo, + NSError * error)) { + __strong __typeof(self) strongSelf = weakSelf; + if(passedBlock && strongSelf) { + NSBlockOperation* fulfillBlock = [NSBlockOperation named:@"account-info-completion" withBlock: ^{ + __strong __typeof(self) blockStrongSelf = weakSelf; + CKAccountInfo* account = [[CKAccountInfo alloc] init]; + account.accountStatus = blockStrongSelf.accountStatus; + account.supportsDeviceToDeviceEncryption = blockStrongSelf.supportsDeviceToDeviceEncryption; + account.accountPartition = CKAccountPartitionTypeProduction; + passedBlock((CKAccountInfo*)account, nil); + }]; + [fulfillBlock addDependency: strongSelf.ckaccountHoldOperation]; + [strongSelf.operationQueue addOperation: fulfillBlock]; + + return YES; + } + return NO; + }]]); + + self.circleStatus = kSOSCCInCircle; + self.mockAccountStateTracker = OCMClassMock([CKKSCKAccountStateTracker class]); + OCMStub([self.mockAccountStateTracker getCircleStatus]).andCall(self, @selector(circleStatus)); + + // If we're in circle, come up with a fake circle id. Otherwise, return an error. + self.circlePeerID = @"fake-circle-id"; + OCMStub([self.mockAccountStateTracker fetchCirclePeerID: + [OCMArg checkWithBlock:^BOOL(void (^passedBlock) (NSString* peerID, + NSError * error)) { + __strong __typeof(self) strongSelf = weakSelf; + if(passedBlock && strongSelf) { + if(strongSelf.circleStatus == kSOSCCInCircle) { + passedBlock(strongSelf.circlePeerID, nil); + } else { + passedBlock(nil, [NSError errorWithDomain:@"securityd" code:errSecInternalError userInfo:@{NSLocalizedDescriptionKey:@"no account, no circle id"}]); + } + + return YES; + } + return NO; + }]]); + + self.aksLockState = false; // Lie and say AKS is always unlocked + self.mockLockStateTracker = OCMClassMock([CKKSLockStateTracker class]); + OCMStub([self.mockLockStateTracker queryAKSLocked]).andCall(self, @selector(aksLockState)); + + self.mockFakeCKModifyRecordZonesOperation = OCMClassMock([FakeCKModifyRecordZonesOperation class]); + OCMStub([self.mockFakeCKModifyRecordZonesOperation ckdb]).andReturn(self.zones); + + self.mockFakeCKModifySubscriptionsOperation = OCMClassMock([FakeCKModifySubscriptionsOperation class]); + OCMStub([self.mockFakeCKModifySubscriptionsOperation ckdb]).andReturn(self.zones); + + self.mockFakeCKFetchRecordZoneChangesOperation = OCMClassMock([FakeCKFetchRecordZoneChangesOperation class]); + OCMStub([self.mockFakeCKFetchRecordZoneChangesOperation ckdb]).andReturn(self.zones); + + OCMStub([self.mockDatabase addOperation: [OCMArg checkWithBlock:^BOOL(id obj) { + __strong __typeof(self) strongSelf = weakSelf; + BOOL matches = NO; + if ([obj isKindOfClass: [FakeCKFetchRecordZoneChangesOperation class]]) { + if(strongSelf.silentFetchesAllowed) { + matches = YES; + + FakeCKFetchRecordZoneChangesOperation *frzco = (FakeCKFetchRecordZoneChangesOperation *)obj; + [strongSelf.operationQueue addOperation: frzco]; + } + } + return matches; + }]]); + + + self.testZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName]; + + // Inject a fake operation dependency into the manager object, so that the tests can perform setup and mock expectations before zone setup begins + // Also blocks all CK account state retrieval operations (but not circle status ones) + self.ckksHoldOperation = [[NSBlockOperation alloc] init]; + [self.ckksHoldOperation addExecutionBlock:^{ + secnotice("ckks", "CKKS testing hold released"); + }]; + self.ckksHoldOperation.name = @"ckks-hold"; + + self.mockCKKSViewManager = OCMClassMock([CKKSViewManager class]); + OCMStub([self.mockCKKSViewManager viewList]).andCall(self, @selector(managedViewList)); + OCMStub([self.mockCKKSViewManager syncBackupAndNotifyAboutSync]); + + self.injectedManager = [[CKKSViewManager alloc] initWithContainerName:SecCKKSContainerName + usePCS:SecCKKSContainerUsePCS + fetchRecordZoneChangesOperationClass:[FakeCKFetchRecordZoneChangesOperation class] + modifySubscriptionsOperationClass:[FakeCKModifySubscriptionsOperation class] + modifyRecordZonesOperationClass:[FakeCKModifyRecordZonesOperation class] + apsConnectionClass:[FakeAPSConnection class] + nsnotificationCenterClass:[FakeNSNotificationCenter class] + notifierClass:[FakeCKKSNotifier class] + setupHold:self.ckksHoldOperation]; + + [CKKSViewManager resetManager:false setTo:self.injectedManager]; + + // 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; }); +} + +-(CKKSCKAccountStateTracker*)accountStateTracker { + return self.injectedManager.accountTracker; +} + +-(CKKSLockStateTracker*)lockStateTracker { + return self.injectedManager.lockStateTracker; +} + +-(NSSet*)managedViewList { + return (NSSet*) CFBridgingRelease(SOSViewCopyViewSet(kViewSetCKKS)); +} + +-(void)expectCKFetch { + // Create an object for the block to retain and modify + BoolHolder* runAlready = [[BoolHolder alloc] init]; + + __weak __typeof(self) weakSelf = self; + [[self.mockDatabase expect] addOperation: [OCMArg checkWithBlock:^BOOL(id obj) { + __strong __typeof(self) strongSelf = weakSelf; + if(runAlready.state) { + return NO; + } + BOOL matches = NO; + if ([obj isKindOfClass: [FakeCKFetchRecordZoneChangesOperation class]]) { + matches = YES; + runAlready.state = true; + + FakeCKFetchRecordZoneChangesOperation *frzco = (FakeCKFetchRecordZoneChangesOperation *)obj; + [strongSelf.operationQueue addOperation: frzco]; + } + return matches; + }]]; +} + +- (void)startCKKSSubsystem { + [self startCKAccountStatusMock]; + [self startCKKSSubsystemOnly]; +} + +- (void)startCKKSSubsystemOnly { + // Note: currently, based on how we're mocking up the zone creation and zone subscription operation, + // they will 'fire' before this method is called. It's harmless, since the mocks immediately succeed + // and return; it's just a tad confusing. + if([self.ckksHoldOperation isPending]) { + [self.operationQueue addOperation: self.ckksHoldOperation]; + } +} + +- (void)startCKAccountStatusMock { + // Note: currently, based on how we're mocking up the zone creation and zone subscription operation, + // they will 'fire' before this method is called. It's harmless, since the mocks immediately succeed + // and return; it's just a tad confusing. + if([self.ckaccountHoldOperation isPending]) { + [self.operationQueue addOperation: self.ckaccountHoldOperation]; + } +} + +-(void)holdCloudKitModifications { + self.ckModifyHoldOperation = [NSBlockOperation blockOperationWithBlock:^{ + secnotice("ckks", "Released CloudKit modification hold."); + }]; +} +-(void)releaseCloudKitModificationHold { + if([self.ckModifyHoldOperation isPending]) { + [self.operationQueue addOperation: self.ckModifyHoldOperation]; + } +} + +- (void)expectCKModifyItemRecords: (NSUInteger) expectedNumberOfRecords currentKeyPointerRecords: (NSUInteger) expectedCurrentKeyRecords zoneID: (CKRecordZoneID*) zoneID { + [self expectCKModifyItemRecords:expectedNumberOfRecords + currentKeyPointerRecords:expectedCurrentKeyRecords + zoneID:zoneID + checkItem:nil]; +} + +- (void)expectCKModifyItemRecords: (NSUInteger) expectedNumberOfRecords currentKeyPointerRecords: (NSUInteger) expectedCurrentKeyRecords zoneID: (CKRecordZoneID*) zoneID checkItem: (BOOL (^)(CKRecord*)) checkItem { + [self expectCKModifyItemRecords:expectedNumberOfRecords + deletedRecords:0 + currentKeyPointerRecords:expectedCurrentKeyRecords + zoneID:zoneID + checkItem:checkItem]; +} + +- (void)expectCKModifyItemRecords:(NSUInteger)expectedNumberOfModifiedRecords + deletedRecords:(NSUInteger)expectedNumberOfDeletedRecords + currentKeyPointerRecords:(NSUInteger)expectedCurrentKeyRecords + zoneID:(CKRecordZoneID*)zoneID + checkItem:(BOOL (^)(CKRecord*))checkItem { + // We're updating the device state type on every update, so add it in here + NSMutableDictionary* expectedRecords = [@{SecCKRecordItemType: [NSNumber numberWithUnsignedInteger: expectedNumberOfModifiedRecords], + SecCKRecordCurrentKeyType: [NSNumber numberWithUnsignedInteger: expectedCurrentKeyRecords], + SecCKRecordDeviceStateType: [NSNumber numberWithUnsignedInt: 1], + } mutableCopy]; + + if(SecCKKSSyncManifests()) { + expectedRecords[SecCKRecordManifestType] = [NSNumber numberWithInt: 1]; + expectedRecords[SecCKRecordManifestLeafType] = [NSNumber numberWithInt: 72]; + } + + NSDictionary* deletedRecords = nil; + if(expectedNumberOfDeletedRecords != 0) { + deletedRecords = @{SecCKRecordItemType: [NSNumber numberWithUnsignedInteger: expectedNumberOfDeletedRecords]}; + } + + [self expectCKModifyRecords:expectedRecords + deletedRecordTypeCounts:deletedRecords + zoneID:zoneID + checkModifiedRecord: ^BOOL (CKRecord* record){ + if([record.recordType isEqualToString: SecCKRecordItemType] && checkItem) { + return checkItem(record); + } else { + return YES; + } + } + runAfterModification:nil]; +} + + + +- (void)expectCKModifyKeyRecords: (NSUInteger) expectedNumberOfRecords currentKeyPointerRecords: (NSUInteger) expectedCurrentKeyRecords zoneID: (CKRecordZoneID*) zoneID { + NSNumber* nkeys = [NSNumber numberWithUnsignedInteger: expectedNumberOfRecords]; + NSNumber* ncurrentkeys = [NSNumber numberWithUnsignedInteger: expectedCurrentKeyRecords]; + + [self expectCKModifyRecords:@{SecCKRecordIntermediateKeyType: nkeys, SecCKRecordCurrentKeyType: ncurrentkeys} + deletedRecordTypeCounts:nil + zoneID:zoneID + checkModifiedRecord:nil + runAfterModification:nil]; +} + +- (void)expectCKModifyRecords:(NSDictionary*) expectedRecordTypeCounts + deletedRecordTypeCounts:(NSDictionary*) expectedDeletedRecordTypeCounts + zoneID:(CKRecordZoneID*) zoneID + checkModifiedRecord:(BOOL (^)(CKRecord*)) checkModifiedRecord + runAfterModification:(void (^) ())afterModification +{ + __weak __typeof(self) weakSelf = self; + + // Create an object for the block to retain and modify + BoolHolder* runAlready = [[BoolHolder alloc] init]; + + secnotice("fakecloudkit", "expecting an operation matching modifications: %@ deletions: %@", + expectedRecordTypeCounts, expectedDeletedRecordTypeCounts); + + [[self.mockDatabase expect] addOperation:[OCMArg checkWithBlock:^BOOL(id obj) { + secnotice("fakecloudkit", "Received an operation, checking"); + __block bool matches = false; + if(runAlready.state) { + secnotice("fakecloudkit", "Run already, skipping"); + return NO; + } + + if ([obj isKindOfClass:[CKModifyRecordsOperation class]]) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + CKModifyRecordsOperation *op = (CKModifyRecordsOperation *)obj; + matches = true; + + NSMutableDictionary* modifiedRecordTypeCounts = [[NSMutableDictionary alloc] init]; + NSMutableDictionary* deletedRecordTypeCounts = [[NSMutableDictionary alloc] init]; + + // First: check if it matches. If it does, _then_ execute the operation. + // Supports single-zone atomic writes only + + if(!op.atomic) { + // We only care about atomic operations + secnotice("fakecloudkit", "Not an atomic operation; quitting: %@", op); + return NO; + } + + FakeCKZone* zone = strongSelf.zones[zoneID]; + XCTAssertNotNil(zone, "Have a zone for these records"); + + for(CKRecord* record in op.recordsToSave) { + if(![record.recordID.zoneID isEqual: zoneID]) { + secnotice("fakecloudkit", "Modified record zone ID mismatch: %@ %@", zoneID, record.recordID.zoneID); + return NO; + } + + if([zone errorFromSavingRecord: record]) { + secnotice("fakecloudkit", "Record zone rejected record write: %@", record); + return NO; + } + + NSNumber* currentCountNumber = modifiedRecordTypeCounts[record.recordType]; + NSUInteger currentCount = currentCountNumber ? [currentCountNumber unsignedIntegerValue] : 0; + modifiedRecordTypeCounts[record.recordType] = [NSNumber numberWithUnsignedInteger: currentCount + 1]; + } + + for(CKRecordID* recordID in op.recordIDsToDelete) { + if(![recordID.zoneID isEqual: zoneID]) { + matches = false; + secnotice("fakecloudkit", "Deleted record zone ID mismatch: %@ %@", zoneID, recordID.zoneID); + } + + // Find the object in CloudKit, and record its type + CKRecord* record = strongSelf.zones[zoneID].currentDatabase[recordID]; + if(record) { + NSNumber* currentCountNumber = deletedRecordTypeCounts[record.recordType]; + NSUInteger currentCount = currentCountNumber ? [currentCountNumber unsignedIntegerValue] : 0; + deletedRecordTypeCounts[record.recordType] = [NSNumber numberWithUnsignedInteger: currentCount + 1]; + } + } + + NSMutableDictionary* filteredExpectedRecordTypeCounts = [expectedRecordTypeCounts mutableCopy]; + for(NSString* key in filteredExpectedRecordTypeCounts.allKeys) { + if([filteredExpectedRecordTypeCounts[key] isEqual: [NSNumber numberWithInt:0]]) { + filteredExpectedRecordTypeCounts[key] = nil; + } + } + filteredExpectedRecordTypeCounts[SecCKRecordManifestType] = modifiedRecordTypeCounts[SecCKRecordManifestType]; + filteredExpectedRecordTypeCounts[SecCKRecordManifestLeafType] = modifiedRecordTypeCounts[SecCKRecordManifestLeafType]; + + // Inspect that we have exactly the same records as we expect + if(expectedRecordTypeCounts) { + matches &= !![modifiedRecordTypeCounts isEqual: filteredExpectedRecordTypeCounts]; + if(!matches) { + secnotice("fakecloudkit", "Record number mismatch: %@ %@", modifiedRecordTypeCounts, filteredExpectedRecordTypeCounts); + return NO; + } + } else { + matches &= op.recordsToSave.count == 0u; + if(!matches) { + secnotice("fakecloudkit", "Record number mismatch: %@ 0", modifiedRecordTypeCounts); + return NO; + } + } + if(expectedDeletedRecordTypeCounts) { + matches &= !![deletedRecordTypeCounts isEqual: expectedDeletedRecordTypeCounts]; + if(!matches) { + secnotice("fakecloudkit", "Deleted record number mismatch: %@ %@", deletedRecordTypeCounts, expectedDeletedRecordTypeCounts); + return NO; + } + } else { + matches &= op.recordIDsToDelete.count == 0u; + if(!matches) { + secnotice("fakecloudkit", "Deleted record number mismatch: %@ 0", deletedRecordTypeCounts); + return NO; + } + } + + // We have the right number of things, and their etags match. Ensure that they have the right etags + if(matches && checkModifiedRecord) { + // Clearly we have the right number of things. Call checkRecord on them... + for(CKRecord* record in op.recordsToSave) { + matches &= !!(checkModifiedRecord(record)); + if(!matches) { + secnotice("fakecloudkit", "Check record reports NO: %@ 0", record); + return NO; + } + } + } + + if(matches) { + // Emulate cloudkit and schedule the operation for execution. Be sure to wait for this operation + // if you'd like to read the data from this write. + NSBlockOperation* ckop = [NSBlockOperation named:@"cloudkit-write" withBlock: ^{ + @synchronized(zone.currentDatabase) { + NSMutableArray* savedRecords = [[NSMutableArray alloc] init]; + for(CKRecord* record in op.recordsToSave) { + CKRecord* reflectedRecord = [record copy]; + reflectedRecord.modificationDate = [NSDate date]; + + [zone addToZone: reflectedRecord]; + + [savedRecords addObject:reflectedRecord]; + op.perRecordCompletionBlock(reflectedRecord, nil); + } + for(CKRecordID* recordID in op.recordIDsToDelete) { + // I don't believe CloudKit fails an operation if you delete a record that's not there, so: + [zone deleteCKRecordIDFromZone: recordID]; + } + + op.modifyRecordsCompletionBlock(savedRecords, op.recordIDsToDelete, nil); + + if(afterModification) { + afterModification(); + } + + op.isFinished = YES; + } + }]; + [ckop addNullableDependency:strongSelf.ckModifyHoldOperation]; + [strongSelf.operationQueue addOperation: ckop]; + } + } + if(matches) { + runAlready.state = true; + } + return matches ? YES : NO; + }]]; +} + +- (void)failNextZoneCreation:(CKRecordZoneID*)zoneID { + XCTAssertNil(self.zones[zoneID], "Zone does not exist yet"); + self.zones[zoneID] = [[FakeCKZone alloc] initZone: zoneID]; + self.zones[zoneID].creationError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkUnavailable userInfo:@{}]; +} + +// Report success, but don't actually create the zone. +// This way, you can find ZoneNotFound errors later on +- (void)failNextZoneCreationSilently:(CKRecordZoneID*)zoneID { + XCTAssertNil(self.zones[zoneID], "Zone does not exist yet"); + self.zones[zoneID] = [[FakeCKZone alloc] initZone: zoneID]; + self.zones[zoneID].failCreationSilently = true; +} + +- (void)failNextZoneSubscription:(CKRecordZoneID*)zoneID { + XCTAssertNotNil(self.zones[zoneID], "Zone exists"); + self.zones[zoneID].subscriptionError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkUnavailable userInfo:@{}]; +} + +- (void)failNextZoneSubscription:(CKRecordZoneID*)zoneID withError:(NSError*)error { + XCTAssertNotNil(self.zones[zoneID], "Zone exists"); + self.zones[zoneID].subscriptionError = error; +} + +- (void)failNextCKAtomicModifyItemRecordsUpdateFailure:(CKRecordZoneID*)zoneID { + [self failNextCKAtomicModifyItemRecordsUpdateFailure:zoneID blockAfterReject:nil]; +} + +- (void)failNextCKAtomicModifyItemRecordsUpdateFailure:(CKRecordZoneID*)zoneID blockAfterReject: (void (^)())blockAfterReject { + [self failNextCKAtomicModifyItemRecordsUpdateFailure:zoneID blockAfterReject:blockAfterReject withError:nil]; +} + +- (void)failNextCKAtomicModifyItemRecordsUpdateFailure:(CKRecordZoneID*)zoneID blockAfterReject: (void (^)())blockAfterReject withError:(NSError*)error { + __weak __typeof(self) weakSelf = self; + + [[self.mockDatabase expect] addOperation:[OCMArg checkWithBlock:^BOOL(id obj) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + __block bool rejected = false; + if ([obj isKindOfClass:[CKModifyRecordsOperation class]]) { + CKModifyRecordsOperation *op = (CKModifyRecordsOperation *)obj; + + if(!op.atomic) { + // We only care about atomic operations + return NO; + } + + // We want to only match zone updates pertaining to this zone + for(CKRecord* record in op.recordsToSave) { + if(![record.recordID.zoneID isEqual: zoneID]) { + return NO; + } + } + + FakeCKZone* zone = strongSelf.zones[zoneID]; + XCTAssertNotNil(zone, "Have a zone for these records"); + + rejected = true; + + if(error) { + [strongSelf rejectWrite: op withError:error]; + } else { + NSMutableDictionary* failedRecords = [[NSMutableDictionary alloc] init]; + [strongSelf rejectWrite: op failedRecords:failedRecords]; + } + + if(blockAfterReject) { + blockAfterReject(); + } + } + return rejected ? YES : NO; + }]]; +} + +- (void)expectCKAtomicModifyItemRecordsUpdateFailure:(CKRecordZoneID*)zoneID { + __weak __typeof(self) weakSelf = self; + + [[self.mockDatabase expect] addOperation:[OCMArg checkWithBlock:^BOOL(id obj) { + __strong __typeof(weakSelf) strongSelf = weakSelf; + XCTAssertNotNil(strongSelf, "self exists"); + + __block bool rejected = false; + if ([obj isKindOfClass:[CKModifyRecordsOperation class]]) { + CKModifyRecordsOperation *op = (CKModifyRecordsOperation *)obj; + + if(!op.atomic) { + // We only care about atomic operations + return NO; + } + + // We want to only match zone updates pertaining to this zone + for(CKRecord* record in op.recordsToSave) { + if(![record.recordID.zoneID isEqual: zoneID]) { + return NO; + } + } + + FakeCKZone* zone = strongSelf.zones[zoneID]; + XCTAssertNotNil(zone, "Have a zone for these records"); + + NSMutableDictionary* failedRecords = [[NSMutableDictionary alloc] init]; + + @synchronized(zone.currentDatabase) { + for(CKRecord* record in op.recordsToSave) { + // Check if we should allow this transaction + NSError* recordSaveError = [zone errorFromSavingRecord: record]; + if(recordSaveError) { + failedRecords[record.recordID] = recordSaveError; + rejected = true; + } + } + } + + if(rejected) { + [strongSelf rejectWrite: op failedRecords:failedRecords]; + } + } + return rejected ? YES : NO; + }]]; +} + +-(void)rejectWrite:(CKModifyRecordsOperation*)op withError:(NSError*)error { + // Emulate cloudkit and schedule the operation for execution. Be sure to wait for this operation + // if you'd like to read the data from this write. + NSBlockOperation* ckop = [NSBlockOperation named:@"cloudkit-reject-write-error" withBlock: ^{ + op.modifyRecordsCompletionBlock(nil, nil, error); + op.isFinished = YES; + }]; + [ckop addNullableDependency: self.ckModifyHoldOperation]; + [self.operationQueue addOperation: ckop]; +} + +-(void)rejectWrite:(CKModifyRecordsOperation*)op failedRecords:(NSMutableDictionary*)failedRecords { + // Add the batch request failed errors + for(CKRecord* record in op.recordsToSave) { + NSError* exists = failedRecords[record.recordID]; + if(!exists) { + // TODO: might have important userInfo, but we're not mocking that yet + failedRecords[record.recordID] = [[CKPrettyError alloc] initWithDomain: CKErrorDomain code: CKErrorBatchRequestFailed userInfo: @{}]; + } + } + + NSError* error = [[CKPrettyError alloc] initWithDomain: CKErrorDomain code: CKErrorPartialFailure userInfo: @{CKPartialErrorsByItemIDKey: failedRecords}]; + + // Emulate cloudkit and schedule the operation for execution. Be sure to wait for this operation + // if you'd like to read the data from this write. + NSBlockOperation* ckop = [NSBlockOperation named:@"cloudkit-reject-write" withBlock: ^{ + op.modifyRecordsCompletionBlock(nil, nil, error); + op.isFinished = YES; + }]; + [ckop addNullableDependency: self.ckModifyHoldOperation]; + [self.operationQueue addOperation: ckop]; +} + +- (void)expectCKDeleteItemRecords:(NSUInteger)expectedNumberOfRecords + zoneID:(CKRecordZoneID*) zoneID { + + // We're updating the device state type on every update, so add it in here + NSMutableDictionary* expectedRecords = [@{ + SecCKRecordDeviceStateType: [NSNumber numberWithUnsignedInt: 1], + } mutableCopy]; + if(SecCKKSSyncManifests()) { + // TODO: this really shouldn't be 2. + expectedRecords[SecCKRecordManifestType] = [NSNumber numberWithInt: 2]; + expectedRecords[SecCKRecordManifestLeafType] = [NSNumber numberWithInt: 72]; + } + + [self expectCKModifyRecords:expectedRecords + deletedRecordTypeCounts:@{SecCKRecordItemType: [NSNumber numberWithUnsignedInteger: expectedNumberOfRecords]} + zoneID:zoneID + checkModifiedRecord:nil + runAfterModification:nil]; +} + +-(void)waitForCKModifications { + // CloudKit modifications are put on the local queue. + // This is heavyweight but should suffice. + [self.operationQueue waitUntilAllOperationsAreFinished]; +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + + if(SecCKKSIsEnabled()) { + // Ensure we don't have any blocking operations + [self startCKKSSubsystem]; + + [self waitForCKModifications]; + + XCTAssertEqual(0, [self.injectedManager.completedSecCKKSInitialize wait:2*NSEC_PER_SEC], + "Timeout did not occur waiting for SecCKKSInitialize"); + + // Make sure this happens before teardown. + XCTAssertEqual(0, [self.accountStateTracker.finishedInitialCalls wait:1*NSEC_PER_SEC], "Account state tracker initialized itself"); + } + + [super tearDown]; + + [self.injectedManager cancelPendingOperations]; + [CKKSViewManager resetManager:true setTo:nil]; + self.injectedManager = nil; + + [self.mockAccountStateTracker stopMocking]; + self.mockAccountStateTracker = nil; + + [self.mockLockStateTracker stopMocking]; + self.mockLockStateTracker = nil; + + [self.mockCKKSViewManager stopMocking]; + self.mockCKKSViewManager = nil; + + [self.mockFakeCKModifyRecordZonesOperation stopMocking]; + self.mockFakeCKModifyRecordZonesOperation = nil; + + [self.mockFakeCKModifySubscriptionsOperation stopMocking]; + self.mockFakeCKModifySubscriptionsOperation = nil; + + [self.mockFakeCKFetchRecordZoneChangesOperation stopMocking]; + self.mockFakeCKFetchRecordZoneChangesOperation = nil; + + [self.mockDatabase stopMocking]; + self.mockDatabase = nil; + + [self.mockContainer stopMocking]; + self.mockContainer = nil; + + self.zones = nil; + self.operationQueue = nil; + self.ckksHoldOperation = nil; + self.ckaccountHoldOperation = nil; + + SecCKKSTestResetFlags(); +} + +- (CKKSKey*) fakeTLK: (CKRecordZoneID*)zoneID { + CKKSKey* key = [[CKKSKey alloc] initSelfWrappedWithAESKey:[[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="] + uuid:[[NSUUID UUID] UUIDString] + keyclass:SecCKKSKeyClassTLK + state: SecCKKSProcessedStateLocal + zoneID:zoneID + encodedCKRecord: nil + currentkey: true]; + [key CKRecordWithZoneID: zoneID]; + return key; +} + + +@end + +#endif diff --git a/keychain/ckks/tests/Info.plist b/keychain/ckks/tests/Info.plist new file mode 100644 index 00000000..6c6c23c4 --- /dev/null +++ b/keychain/ckks/tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/keychain/ckks/tests/MockCloudKit.h b/keychain/ckks/tests/MockCloudKit.h new file mode 100644 index 00000000..e64c10bb --- /dev/null +++ b/keychain/ckks/tests/MockCloudKit.h @@ -0,0 +1,111 @@ +/* + * 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 +#import + +#import "keychain/ckks/CloudKitDependencies.h" +#import "keychain/ckks/CKKSNotifier.h" + +NS_ASSUME_NONNULL_BEGIN + +@class CKKSCKRecordHolder; +@class FakeCKZone; + +typedef NSMutableDictionary FakeCKDatabase; + + +@interface FakeCKModifyRecordZonesOperation : NSBlockOperation +@property (nullable) NSError* creationError; +@property (nonatomic, nullable) NSMutableArray* recordZonesSaved; +@property (nonatomic, nullable) NSMutableArray* recordZoneIDsDeleted; ++(FakeCKDatabase*) ckdb; +@end + + +@interface FakeCKModifySubscriptionsOperation : NSBlockOperation +@property (nullable) NSError* subscriptionError; +@property (nonatomic, nullable) NSMutableArray *subscriptionsSaved; +@property (nonatomic, nullable) NSMutableArray *subscriptionIDsDeleted; ++(FakeCKDatabase*) ckdb; +@end + + +@interface FakeCKFetchRecordZoneChangesOperation : NSOperation ++(FakeCKDatabase*) ckdb; +@end + + +@interface FakeAPSConnection : NSObject +@end + + +@interface FakeNSNotificationCenter : NSObject ++ (instancetype)defaultCenter; +- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject; +@end + + +@interface FakeCKZone : NSObject +// Used while mocking: database is the contents of the current current CloudKit database, pastDatabase is the state of the world in the past at different change tokens +@property CKRecordZoneID* zoneID; +@property CKServerChangeToken* currentChangeToken; +@property NSMutableDictionary* currentDatabase; +@property NSMutableDictionary*>* pastDatabases; +@property bool flag; // used however you'd like in a test + +// Usually nil. If set, trying to 'create' this zone should fail. +@property (nullable) NSError* creationError; + +// Usually false. If set, trying to 'create' this should should 1) pretend to succeed but 2) delete this zone from existence +@property bool failCreationSilently; + +// Usually nil. If set, trying to subscribe to this zone should fail. +@property (nullable) NSError* subscriptionError; + +- (instancetype)initZone: (CKRecordZoneID*) zoneID; + +- (void)rollChangeToken; + +// Always Succeed +- (void)addToZone: (CKKSCKRecordHolder*) item zoneID: (CKRecordZoneID*) zoneID; +- (void)addToZone: (CKRecord*) record; + +- (void)addCKRecordToZone: (CKRecord*) record; +- (NSError* _Nullable)deleteCKRecordIDFromZone:(CKRecordID*) recordID; + +// Sets up the next fetchChanges to fail with this error +- (void)failNextFetchWith: (NSError*) fetchChangesError; + +// Get the next fetchChanges error. Returns NULL if the fetchChanges should succeed. +- (NSError * _Nullable)popFetchChangesError; + +// Checks if this record add/modification should fail +- (NSError * _Nullable)errorFromSavingRecord:(CKRecord*) record; +@end + +@interface FakeCKKSNotifier : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/ckks/tests/MockCloudKit.m b/keychain/ckks/tests/MockCloudKit.m new file mode 100644 index 00000000..ea44543f --- /dev/null +++ b/keychain/ckks/tests/MockCloudKit.m @@ -0,0 +1,435 @@ +/* + * 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@ + */ + +#if OCTAGON + +#import "keychain/ckks/tests/MockCloudKit.h" +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSRecordHolder.h" + +#import +#import +#include +#import + + +@implementation FakeCKModifyRecordZonesOperation +@synthesize database = _database; +@synthesize recordZonesToSave = _recordZonesToSave; +@synthesize recordZoneIDsToDelete = _recordZoneIDsToDelete; +@synthesize modifyRecordZonesCompletionBlock = _modifyRecordZonesCompletionBlock; + +- (instancetype)initWithRecordZonesToSave:(nullable NSArray *)recordZonesToSave recordZoneIDsToDelete:(nullable NSArray *)recordZoneIDsToDelete { + if(self = [super init]) { + _recordZonesToSave = recordZonesToSave; + _recordZoneIDsToDelete = recordZoneIDsToDelete; + _modifyRecordZonesCompletionBlock = nil; + + _recordZonesSaved = nil; + _recordZoneIDsDeleted = nil; + _creationError = nil; + + __weak __typeof(self) weakSelf = self; + self.completionBlock = ^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckks: received callback for released object"); + return; + } + + strongSelf.modifyRecordZonesCompletionBlock(strongSelf.recordZonesSaved, strongSelf.recordZoneIDsDeleted, strongSelf.creationError); + }; + } + return self; +} + +-(void)main { + // Create the zones we want; delete the ones we don't + // No error handling whatsoever + FakeCKDatabase* ckdb = [FakeCKModifyRecordZonesOperation ckdb]; + + for(CKRecordZone* zone in self.recordZonesToSave) { + bool skipCreation = false; + FakeCKZone* fakezone = ckdb[zone.zoneID]; + if(fakezone.failCreationSilently) { + // Don't report an error, but do delete the zone + ckdb[zone.zoneID] = nil; + skipCreation = true; + + } else if(fakezone.creationError) { + + // Not the best way to do this, but it's an error + // Needs fixing if you want to support multiple zone failures + self.creationError = fakezone.creationError; + + // 'clear' the error + ckdb[zone.zoneID] = nil; + skipCreation = true; + + } else if(fakezone) { + continue; + } + + if(!skipCreation) { + // Create the zone: + secnotice("ckks", "Creating zone %@", zone); + ckdb[zone.zoneID] = [[FakeCKZone alloc] initZone: zone.zoneID]; + } + + if(!self.recordZonesSaved) { + self.recordZonesSaved = [[NSMutableArray alloc] init]; + } + [self.recordZonesSaved addObject:zone]; + } + + for(CKRecordZoneID* zoneID in self.recordZoneIDsToDelete) { + ckdb[zoneID] = nil; + + if(!self.recordZoneIDsDeleted) { + self.recordZoneIDsDeleted = [[NSMutableArray alloc] init]; + } + [self.recordZoneIDsDeleted addObject:zoneID]; + } +} + ++(FakeCKDatabase*) ckdb { + // Shouldn't ever be called: must be mocked out. + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"+ckdb[] must be mocked out for use"] + userInfo:nil]; +} +@end + +@implementation FakeCKModifySubscriptionsOperation +@synthesize database = _database; +@synthesize group = _group; +@synthesize subscriptionsToSave = _subscriptionsToSave; +@synthesize subscriptionIDsToDelete = _subscriptionIDsToDelete; +@synthesize modifySubscriptionsCompletionBlock = _modifySubscriptionsCompletionBlock; + +- (instancetype)initWithSubscriptionsToSave:(nullable NSArray *)subscriptionsToSave subscriptionIDsToDelete:(nullable NSArray *)subscriptionIDsToDelete { + if(self = [super init]) { + _subscriptionsToSave = subscriptionsToSave; + _subscriptionIDsToDelete = subscriptionIDsToDelete; + _modifySubscriptionsCompletionBlock = nil; + + __weak __typeof(self) weakSelf = self; + self.completionBlock = ^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; + if(!strongSelf) { + secerror("ckks: received callback for released object"); + return; + } + + strongSelf.modifySubscriptionsCompletionBlock(strongSelf.subscriptionsSaved, strongSelf.subscriptionIDsDeleted, strongSelf.subscriptionError); + }; + } + return self; +} + +-(void)main { + FakeCKDatabase* ckdb = [FakeCKModifySubscriptionsOperation ckdb]; + + // Are these CKRecordZoneSubscription? Who knows! + for(CKRecordZoneSubscription* subscription in self.subscriptionsToSave) { + FakeCKZone* fakezone = ckdb[subscription.zoneID]; + + if(!fakezone) { + // This is an error: the zone doesn't exist + self.subscriptionError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain + code:CKErrorPartialFailure + userInfo:@{CKPartialErrorsByItemIDKey: + @{subscription.zoneID:[[CKPrettyError alloc] initWithDomain:CKErrorDomain + code:CKErrorZoneNotFound + userInfo:@{}]} + }]; + + } else if(fakezone.subscriptionError) { + // Not the best way to do this, but it's an error + // Needs fixing if you want to support multiple zone failures + self.subscriptionError = fakezone.subscriptionError; + + // 'clear' the error + fakezone.subscriptionError = nil; + } else { + if(!self.subscriptionsSaved) { + self.subscriptionsSaved = [[NSMutableArray alloc] init]; + } + [self.subscriptionsSaved addObject:subscription]; + } + } + + for(NSString* subscriptionID in self.subscriptionIDsToDelete) { + if(!self.subscriptionIDsDeleted) { + self.subscriptionIDsDeleted = [[NSMutableArray alloc] init]; + } + + [self.subscriptionIDsDeleted addObject:subscriptionID]; + } +} + ++(FakeCKDatabase*) ckdb { + // Shouldn't ever be called: must be mocked out. + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"+ckdb[] must be mocked out for use"] + userInfo:nil]; +} +@end + +@implementation FakeCKFetchRecordZoneChangesOperation +@synthesize recordZoneIDs = _recordZoneIDs; +@synthesize optionsByRecordZoneID = _optionsByRecordZoneID; + +@synthesize fetchAllChanges = _fetchAllChanges; +@synthesize recordChangedBlock = _recordChangedBlock; + +@synthesize recordWithIDWasDeletedBlock = _recordWithIDWasDeletedBlock; +@synthesize recordZoneChangeTokensUpdatedBlock = _recordZoneChangeTokensUpdatedBlock; +@synthesize recordZoneFetchCompletionBlock = _recordZoneFetchCompletionBlock; +@synthesize fetchRecordZoneChangesCompletionBlock = _fetchRecordZoneChangesCompletionBlock; + +@synthesize group = _group; + +- (instancetype)initWithRecordZoneIDs:(NSArray *)recordZoneIDs optionsByRecordZoneID:(nullable NSDictionary *)optionsByRecordZoneID { + if(self = [super init]) { + _recordZoneIDs = recordZoneIDs; + _optionsByRecordZoneID = optionsByRecordZoneID; + } + return self; +} + +- (void)main { + // iterate through database, and return items that aren't in lastDatabase + FakeCKDatabase* ckdb = [FakeCKFetchRecordZoneChangesOperation ckdb]; + + for(CKRecordZoneID* zoneID in self.recordZoneIDs) { + FakeCKZone* zone = ckdb[zoneID]; + if(!zone) { + // Only really supports a single zone failure + ckksnotice("fakeck", zoneID, "Fetched for a missing zone %@", zoneID); + NSError* zoneNotFoundError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain + code:CKErrorZoneNotFound + userInfo:@{}]; + NSError* error = [[CKPrettyError alloc] initWithDomain:CKErrorDomain + code:CKErrorPartialFailure + userInfo:@{CKPartialErrorsByItemIDKey: @{zoneID:zoneNotFoundError}}]; + + self.fetchRecordZoneChangesCompletionBlock(error); + return; + } + + // Not precisely correct in the case of multiple zone fetches. However, we don't currently do that, so it'll work for now. + NSError* mockError = [zone popFetchChangesError]; + if(mockError) { + self.fetchRecordZoneChangesCompletionBlock(mockError); + return; + } + + // Extract the database at the last time they asked + CKServerChangeToken* token = self.optionsByRecordZoneID[zoneID].previousServerChangeToken; + NSMutableDictionary* lastDatabase = token ? zone.pastDatabases[token] : nil; + + // You can fetch with the current change token; that's fine + if([token isEqual:zone.currentChangeToken]) { + lastDatabase = zone.currentDatabase; + } + + ckksnotice("fakeck", zone.zoneID, "FakeCKFetchRecordZoneChangesOperation(%@): database is currently %@ change token %@ database then: %@", zone.zoneID, zone.currentDatabase, token, lastDatabase); + + if(!lastDatabase && token) { + ckksnotice("fakeck", zone.zoneID, "no database for this change token: failing fetch with 'CKErrorChangeTokenExpired'"); + self.fetchRecordZoneChangesCompletionBlock([[CKPrettyError alloc] + initWithDomain:CKErrorDomain + code:CKErrorPartialFailure userInfo:@{CKPartialErrorsByItemIDKey: + @{zoneID:[[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorChangeTokenExpired userInfo:@{}]} + }]); + return; + } + + [zone.currentDatabase enumerateKeysAndObjectsUsingBlock:^(CKRecordID * _Nonnull recordID, CKRecord * _Nonnull record, BOOL * _Nonnull stop) { + + id last = [lastDatabase objectForKey: recordID]; + if(!last || ![record isEqual:last]) { + self.recordChangedBlock(record); + } + }]; + + // iterate through lastDatabase, and delete items that aren't in database + [lastDatabase enumerateKeysAndObjectsUsingBlock:^(CKRecordID * _Nonnull recordID, CKRecord * _Nonnull record, BOOL * _Nonnull stop) { + + id current = [zone.currentDatabase objectForKey: recordID]; + if(current == nil) { + self.recordWithIDWasDeletedBlock(recordID, [record recordType]); + } + }]; + + self.recordZoneChangeTokensUpdatedBlock(zoneID, zone.currentChangeToken, nil); + self.recordZoneFetchCompletionBlock(zoneID, zone.currentChangeToken, nil, NO, nil); + self.fetchRecordZoneChangesCompletionBlock(nil); + } +} + ++(FakeCKDatabase*) ckdb { + // Shouldn't ever be called: must be mocked out. + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"+ckdb[] must be mocked out for use"] + userInfo:nil]; +} +@end + + +// Do literally nothing +@implementation FakeAPSConnection +@synthesize delegate; + +- (id)initWithEnvironmentName:(NSString *)environmentName namedDelegatePort:(NSString*)namedDelegatePort queue:(dispatch_queue_t)queue { + if(self = [super init]) { + } + return self; +} + +- (void)setEnabledTopics:(NSArray *)enabledTopics { +} + +@end + +// Do literally nothing +@implementation FakeNSNotificationCenter ++ (instancetype)defaultCenter { + return [[FakeNSNotificationCenter alloc] init]; +} +- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject { +} +- (void)removeObserver:(id)observer { +} +@end + +@interface FakeCKZone () +@property NSMutableArray* fetchErrors; +@end + +@implementation FakeCKZone +- (instancetype)initZone: (CKRecordZoneID*) zoneID { + if(self = [super init]) { + + _zoneID = zoneID; + _currentDatabase = [[NSMutableDictionary alloc] init]; + _pastDatabases = [[NSMutableDictionary alloc] init]; + + _fetchErrors = [[NSMutableArray alloc] init]; + + [self rollChangeToken]; + } + return self; +} + +- (void)rollChangeToken { + NSData* changeToken = [[[NSUUID UUID] UUIDString] dataUsingEncoding:NSUTF8StringEncoding]; + self.currentChangeToken = [[CKServerChangeToken alloc] initWithData: changeToken]; +} + +- (void)addToZone: (CKKSCKRecordHolder*) item zoneID: (CKRecordZoneID*) zoneID { + CKRecord* record = [item CKRecordWithZoneID: zoneID]; + [self addToZone: record]; +} + +- (void)addToZone: (CKRecord*) record { + // Save off this current databse + self.pastDatabases[self.currentChangeToken] = [self.currentDatabase mutableCopy]; + + [self rollChangeToken]; + + record.etag = [self.currentChangeToken description]; + ckksnotice("fakeck", self.zoneID, "change tag: %@", record.recordChangeTag); + record.modificationDate = [NSDate date]; + self.currentDatabase[record.recordID] = record; +} + +- (NSError * _Nullable)errorFromSavingRecord:(CKRecord*) record { + CKRecord* existingRecord = self.currentDatabase[record.recordID]; + if(existingRecord && ![existingRecord.recordChangeTag isEqualToString: record.recordChangeTag]) { + ckksnotice("fakeck", self.zoneID, "change tag mismatch! Fail the write: %@ %@", record, existingRecord); + + // TODO: doesn't yet support CKRecordChangedErrorAncestorRecordKey, since I don't understand it + return [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorServerRecordChanged + userInfo:@{CKRecordChangedErrorClientRecordKey:record, + CKRecordChangedErrorServerRecordKey:existingRecord}]; + } + + if(!existingRecord && record.etag != nil) { + ckksnotice("fakeck", self.zoneID, "update to a record that doesn't exist! Fail the write: %@", record); + return [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorUnknownItem + userInfo:nil]; + } + return nil; +} + +- (void)addCKRecordToZone:(CKRecord*) record { + if([self errorFromSavingRecord: record]) { + ckksnotice("fakeck", self.zoneID, "change tag mismatch! Fail the write!"); + } + + [self addToZone: record]; +} + +- (NSError*)deleteCKRecordIDFromZone:(CKRecordID*) recordID { + // todo: fail somehow + + self.pastDatabases[self.currentChangeToken] = [self.currentDatabase mutableCopy]; + [self rollChangeToken]; + + [self.currentDatabase removeObjectForKey: recordID]; + return nil; +} + +- (void)failNextFetchWith: (NSError*) fetchChangesError { + @synchronized(self.fetchErrors) { + [self.fetchErrors addObject: fetchChangesError]; + } +} + +- (NSError * _Nullable)popFetchChangesError { + NSError* error = nil; + @synchronized(self.fetchErrors) { + if(self.fetchErrors.count > 0) { + error = self.fetchErrors[0]; + [self.fetchErrors removeObjectAtIndex:0]; + } + } + return error; +} +@end + +@implementation FakeCKKSNotifier ++(void)post:(NSString*)notification { + 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); + [[NSNotificationCenter defaultCenter] postNotificationName:notification object:nil]; + } +} +@end + +#endif // OCTAGON + diff --git a/keychain/ckks/tests/RateLimiterTests.m b/keychain/ckks/tests/RateLimiterTests.m new file mode 100644 index 00000000..91bd6bf3 --- /dev/null +++ b/keychain/ckks/tests/RateLimiterTests.m @@ -0,0 +1,292 @@ +/* + * 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 +#import +#import "keychain/ckks/RateLimiter.h" + +@interface TestObject : NSObject +@property NSString *uuid; +- (NSString *)invalid; +@end + +@implementation TestObject +- (instancetype)init { + self = [super init]; + if (self) { + _uuid = [[NSUUID UUID] UUIDString]; + } + return self; +} + +- (instancetype)initWithNilUuid { + self = [super init]; + if (self) { + _uuid = nil; + } + return self; +} + +// It's super illegal for this to get called because of property allowlisting +- (NSString *)invalid { + NSAssert(NO, @"'invalid' is not an approved property"); + return nil; +} +@end + +@interface RateLimiterTests : XCTestCase +@property NSDictionary *config; +@property NSString *filepath; +@property NSDate *time; +@property RateLimiter *RL; +@property TestObject *obj; +@end + +@implementation RateLimiterTests + +- (void)setUp { + [super setUp]; + // instantiate config, write to disk + NSData *configData = [@"\ +\ +\ +\ + general\ + \ + maxStateSize\ + 250\ + maxItemAge\ + 3600\ + overloadDuration\ + 1800\ + name\ + CKKS\ + MAType\ + \ + \ + groups\ + \ + \ + property\ + global\ + capacity\ + 20\ + rate\ + 30\ + badness\ + 1\ + \ + \ + property\ + uuid\ + capacity\ + 3\ + rate\ + 600\ + badness\ + 3\ + \ + \ + property\ + invalid\ + capacity\ + 0\ + rate\ + 60000\ + badness\ + 4\ + \ + \ +\ +\ +" dataUsingEncoding:NSUTF8StringEncoding]; + NSError *err = nil; + _config = [NSPropertyListSerialization propertyListWithData:configData options:NSPropertyListImmutable format:nil error:&err]; + if (!_config) { + XCTFail(@"Could not deserialize property list: %@", err); + } + _filepath = [NSString stringWithFormat:@"/tmp/ratelimitertests_%@.plist", [[NSUUID UUID] UUIDString]]; + if (![configData writeToFile:_filepath atomically:NO]) { + XCTFail(@"Could not write plist to %@", _filepath); + } + _RL = [[RateLimiter alloc] initWithConfig:_config]; + _obj = [TestObject new]; + _time = [NSDate date]; +} + +- (void)tearDown { + NSError *err = nil; + if (![[NSFileManager defaultManager] removeItemAtPath:_filepath error:&err]) { + XCTFail(@"Couldn't delete file %@: %@", _filepath, err); + } + [super tearDown]; +} + +- (void)testInitWithConfig { + self.RL = [[RateLimiter alloc] initWithConfig:self.config]; + XCTAssertNotNil(self.RL, @"RateLimiter with config succeeds"); + XCTAssertNil(self.RL.assetType, @"initWithConfig means no assetType"); + XCTAssertEqualObjects(self.config, self.RL.config, @"config was copied properly"); +} + +- (void)testInitWithPlist { + RateLimiter *RL = [[RateLimiter alloc] initWithPlistFromURL:[NSURL URLWithString:[NSString stringWithFormat:@"file://%@", self.filepath]]]; + XCTAssertNotNil(RL, @"RateLimiter with plist succeeds"); + XCTAssertNil(RL.assetType, @"initWithPlist means no assetType"); + XCTAssertEqualObjects(self.config, RL.config, @"config was loaded properly"); + RL = [[RateLimiter alloc] initWithPlistFromURL:[NSURL URLWithString:[NSString stringWithFormat:@"file://%@.nonexisting", self.filepath]]]; + XCTAssertNil(RL, "Cannot instantiate RateLimiter with invalid plist URL"); +} + +- (void)testEncodingAndDecoding { + NSDate* date = [NSDate date]; + NSDate* limit = nil; + [self.RL judge:self.obj at:date limitTime:&limit]; + + NSMutableData *data = [NSMutableData new]; + NSKeyedArchiver *encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; + encoder.requiresSecureCoding = YES; + [self.RL encodeWithCoder:encoder]; + [encoder finishEncoding]; + XCTAssertEqualObjects(self.config, self.RL.config, @"config unmodified after encoding"); + XCTAssertNil(self.RL.assetType, @"assetType still nil after encoding"); + + NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + decoder.requiresSecureCoding = YES; + RateLimiter *RL2 = [[RateLimiter alloc] initWithCoder:decoder]; + XCTAssertNotNil(RL2, @"Received an object from initWithCoder"); + XCTAssertEqualObjects(self.RL.config, RL2.config, @"config is the same after encoding and decoding"); + XCTAssertTrue([self.RL isEqual:RL2], @"RateLimiters believe they are the same"); + XCTAssertNil(RL2.assetType, @"assetType remains nil"); +} + +- (void)testInitWithAssetType { + // Not implemented yet, expect nil + XCTAssertNil([[RateLimiter alloc] initWithAssetType:@"test"]); +} + +- (void)testReset { + NSDate *limitTime = nil; + [self.RL judge:[TestObject new] at:self.time limitTime:&limitTime]; + XCTAssertEqual([self.RL stateSize], 2ul, @"Single property judged once, state is 1 global plus 1 property"); + [self.RL reset]; + XCTAssertEqual([self.RL stateSize], 0ul, @"No buckets after reset"); + XCTAssertEqualObjects(self.config, self.RL.config); +} + +// Cause it to complain based on one item being hit repeatedly +- (void)testJudgeSingleItem { + NSDate *limitTime = nil; + for (int idx = 0; idx < [self.config[@"groups"][1][@"capacity"] intValue]; ++idx) { + XCTAssertEqual([self.RL judge:self.obj at:self.time limitTime:&limitTime], RateLimiterBadnessClear, @"Received RateLimiterBadnessClear"); + XCTAssertNil(limitTime, @"single object, clear to process right now"); + } + + XCTAssertEqual([self.RL judge:self.obj at:self.time limitTime:&limitTime], RateLimiterBadnessGridlocked, @"Received RateLimiterBadnessGridlocked"); + XCTAssertNotNil(limitTime, @"After hammering same object need to wait now"); + XCTAssertEqualObjects(limitTime, [self.time dateByAddingTimeInterval:[self.config[@"groups"][1][@"rate"] intValue]], @"time: %@, process-OK time is time + rate (%d)", self.time, [self.config[@"groups"][1][@"rate"] intValue]); +} + +// Cause it to complain based on too many items in total +- (void)testJudgeRandomItems { + NSDate *limitTime = nil; + TestObject *obj; + for (int idx = 0; idx < [self.config[@"groups"][0][@"capacity"] intValue]; ++idx) { + obj = [TestObject new]; + XCTAssertEqual([self.RL judge:obj at:self.time limitTime:&limitTime], RateLimiterBadnessClear, @"Received RateLimiterBadnessClear"); + XCTAssertNil(limitTime, @"single object, clear to process right now"); + } + + XCTAssertEqual([self.RL judge:obj at:self.time limitTime:&limitTime], RateLimiterBadnessCongested, @"Received RateLimiterBadnessCongested"); + XCTAssertNotNil(limitTime, @"After hammering same object need to wait now"); + XCTAssertEqualObjects(limitTime, [self.time dateByAddingTimeInterval:[self.config[@"groups"][0][@"rate"] intValue]], @"time: %@, process-OK time is time + rate (%d)", self.time, [self.config[@"groups"][0][@"rate"] intValue]); +} + +- (void)testOverload { + NSDate *limitTime = nil; + while ([self.RL stateSize] <= [self.config[@"general"][@"maxStateSize"] unsignedIntegerValue]) { + TestObject *obj = [TestObject new]; + RateLimiterBadness rlb = [self.RL judge:obj at:self.time limitTime:&limitTime]; + XCTAssertTrue(rlb != RateLimiterBadnessOverloaded, @"No issues judging random objects under max state size"); + } + + // While check is performed at the start of the loop, so now stateSize > maxStateSize. Judge should realize this right away, try to cope, fail and throw a fit + XCTAssertEqual([self.RL judge:self.obj at:self.time limitTime:&limitTime], RateLimiterBadnessOverloaded, @"RateLimiter overloaded"); + XCTAssertEqualObjects(limitTime, [self.time dateByAddingTimeInterval:[self.config[@"general"][@"overloadDuration"] intValue]], @"Overload duration matches expectations"); +} + +- (void)testTrimmingDueToTime { + NSDate *limitTime = nil; + for (int idx = 0; idx < [self.config[@"general"][@"maxStateSize"] intValue]/2; ++idx) { + TestObject *obj = [TestObject new]; + [self.RL judge:obj at:self.time limitTime:&limitTime]; + } + NSUInteger stateSize = [self.RL stateSize]; + XCTAssertEqual(stateSize, [self.config[@"general"][@"maxStateSize"] unsignedIntegerValue] / 2 + 1, @"Number of objects added matches expectations"); + // Advance time enough to age out the existing objects + NSDate *time = [self.time dateByAddingTimeInterval:[self.config[@"general"][@"maxItemAge"] intValue] + 1]; + + // It's been so long, judge should first trim and decide to throw away everything it has + XCTAssertEqual([self.RL judge:self.obj at:time limitTime:&limitTime], RateLimiterBadnessClear, @"New judgment after long time goes fine"); + XCTAssertEqual([self.RL stateSize], 2ul, @"Old items gone, just global and one new item left"); +} + +// RateLimiter is set to ignore properties that return nil +- (void)testNilUuid { + NSDate *limitTime = nil; + TestObject *obj = [[TestObject alloc] initWithNilUuid]; + for (int idx = 0; idx < [self.config[@"groups"][0][@"capacity"] intValue]; ++idx) { + XCTAssertEqual([self.RL judge:obj at:self.time limitTime:&limitTime], RateLimiterBadnessClear, @"Same object with nil property only judged on global rate"); + XCTAssertEqual([self.RL stateSize], 1ul, @"Nil property objects can't be added to state"); + } +} + +- (void)testTrimmingDueToSize { + NSDate *limitTime = nil; + // Put first half of items in + for (int idx = 0; idx < [self.config[@"general"][@"maxStateSize"] intValue] / 2; ++idx) { + TestObject *obj = [TestObject new]; + [self.RL judge:obj at:self.time limitTime:&limitTime]; + } + + NSDate *time = [self.time dateByAddingTimeInterval:[self.config[@"general"][@"maxItemAge"] intValue] / 2]; + + // Put second half in later so trim has something to do afterwards + while ([self.RL stateSize] <= [self.config[@"general"][@"maxStateSize"] unsignedIntegerValue]) { + TestObject *obj = [TestObject new]; + RateLimiterBadness rlb = [self.RL judge:obj at:time limitTime:&limitTime]; + XCTAssertTrue(rlb != RateLimiterBadnessOverloaded, @"No issues judging random objects under max state size"); + } + + NSUInteger expectedStateSize = [self.RL stateSize] - [self.config[@"general"][@"maxStateSize"] intValue] / 2 + 1; + + // Advance time past first batch but before second batch + time = [self.time dateByAddingTimeInterval:[self.config[@"general"][@"maxItemAge"] intValue] + 1]; + // ...which requires adjusting for the fact that the token buckes will be almost full (i.e. further in the past) + time = [time dateByAddingTimeInterval:-(([self.config[@"groups"][1][@"capacity"] integerValue] - 1) * [self.config[@"groups"][1][@"rate"] integerValue])]; + + XCTAssertNotEqual([self.RL judge:self.obj at:time limitTime:&limitTime], RateLimiterBadnessOverloaded, @"Judgment caused RL to trim out old items"); + XCTAssertEqual([self.RL stateSize], expectedStateSize); +} + +@end diff --git a/keychain/ckks/tests/testrunner/KeychainCKKS.plist b/keychain/ckks/tests/testrunner/KeychainCKKS.plist new file mode 100644 index 00000000..9424b386 --- /dev/null +++ b/keychain/ckks/tests/testrunner/KeychainCKKS.plist @@ -0,0 +1,33 @@ + + + + + BATSConfigVersion + 0.1.0 + Project + Security + Tests + + + TestName + CKKSTests + WorkingDirectory + /AppleInternal/XCTests/com.apple.security/ + Command + + BATS_XCTEST_CMD CKKSTests.xctest + + + + + + diff --git a/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist b/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist new file mode 100644 index 00000000..46c3d41e --- /dev/null +++ b/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist @@ -0,0 +1,32 @@ + + + + + com.apple.application-identifier + com.apple.security.KeychainEntitledTestRunner + application-identifier + com.apple.security.KeychainEntitledTestRunner + com.apple.developer.icloud-services + + CloudKit + + com.apple.private.cloudkit.masquerade + + com.apple.private.cloudkit.customAccounts + + com.apple.developer.icloud-container-environment + Development + com.apple.private.aps-connection-initiate + + aps-connection-initiate + + aps-environment + serverPreferred + keychain-access-groups + + com.apple.security.ckks + + keychain-cloud-circle + + + diff --git a/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner.m b/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner.m new file mode 100644 index 00000000..cf5cbc56 --- /dev/null +++ b/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner.m @@ -0,0 +1,221 @@ +// +// KeychainEntitledTestRunner.m +// KeychainEntitledTestRunner +// +// Stolen from Mark Pauley / CDEntitledTestRunner who stole it from Drew Terry / MobileContainerManager +// Copyright 2016-2017 Apple. All rights reserved. +// + +#import +#import +#import + +@interface TestRunner : NSObject { + 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 : @""), ((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 : @""), ((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 ] -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/keychain/ckksctl/ckksctl-Entitlements.plist b/keychain/ckksctl/ckksctl-Entitlements.plist new file mode 100644 index 00000000..4dcb9697 --- /dev/null +++ b/keychain/ckksctl/ckksctl-Entitlements.plist @@ -0,0 +1,8 @@ + + + + + com.apple.private.ckks + + + diff --git a/keychain/ckksctl/ckksctl.h b/keychain/ckksctl/ckksctl.h new file mode 100644 index 00000000..b7032c68 --- /dev/null +++ b/keychain/ckksctl/ckksctl.h @@ -0,0 +1,18 @@ +// +// Security +// + +#import + +@interface CKKSControl : NSObject +- (NSDictionary *)printPerformanceCounters; +- (NSDictionary *)status: (NSString*) view; +- (void)status_custom: (NSString*) view; +- (void)resync: (NSString*) view; + +- (void)resetLocal: (NSString*)view; +- (void)resetCloudKit: (NSString*) view; + +- (void)getAnalyticsJSON; +- (void)forceAnalyticsUpload; +@end diff --git a/keychain/ckksctl/ckksctl.m b/keychain/ckksctl/ckksctl.m new file mode 100644 index 00000000..66d41a60 --- /dev/null +++ b/keychain/ckksctl/ckksctl.m @@ -0,0 +1,599 @@ +// +// Security +// + +#import +#import +#import +#import +#import +#import + +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSControlProtocol.h" +#import "ckksctl.h" + +#include "lib/SecArgParse.h" + +static void nsprintf(NSString *fmt, ...) NS_FORMAT_FUNCTION(1, 2); +static void print_result(NSDictionary *dict, bool json_flag); +static void print_dict(NSDictionary *dict, int ind); +static void print_array(NSArray *array, int ind); +static void print_entry(id k, id v, int ind); + +static void nsprintf(NSString *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + NSString *str = [[NSString alloc] initWithFormat:fmt arguments:ap]; + va_end(ap); + + puts([str UTF8String]); +#if !__has_feature(objc_arc) + [str release]; +#endif +} + +static void print_result(NSDictionary *dict, bool json_flag) +{ + if (json_flag) { + NSError *err; + NSData *json = [NSJSONSerialization dataWithJSONObject:dict + options:(NSJSONWritingPrettyPrinted | NSJSONWritingSortedKeys) + error:&err]; + if (!json) { + NSLog(@"error: %@", err.localizedDescription); + } else { + printf("%s", [[[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding] UTF8String]); + } + } else { + print_dict(dict, 0); + } +} + +static void print_dict(NSDictionary *dict, int ind) +{ + NSArray *sortedKeys = [[dict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + for (id k in sortedKeys) { + id v = dict[k]; + print_entry(k, v, ind); + } +} + +static void print_array(NSArray *array, int ind) +{ + [array enumerateObjectsUsingBlock:^(id v, NSUInteger i, BOOL *stop __unused) { + print_entry(@(i), v, ind); + }]; +} + +static void print_entry(id k, id v, int ind) +{ + if ([v isKindOfClass:[NSDictionary class]]) { + if (ind == 0) { + nsprintf(@"\n%*s%@ -", ind * 4, "", k); + nsprintf(@"%*s========================", ind * 4, ""); + } else if (ind == 1) { + nsprintf(@"\n%*s%@ -", ind * 4, "", k); + nsprintf(@"%*s------------------------", ind * 4, ""); + } else { + nsprintf(@"%*s%@ -", ind * 4, "", k); + } + + print_dict(v, ind + 1); + } else if ([v isKindOfClass:[NSArray class]]) { + nsprintf(@"%*s%@ -", ind * 4, "", k); + print_array(v, ind + 1); + } else { + nsprintf(@"%*s%@: %@", ind * 4, "", k, v); + } +} + +@interface CKKSControl () +@property NSXPCConnection *connection; +@end + +@implementation CKKSControl + +- (instancetype) initWithEndpoint:(xpc_endpoint_t)endpoint +{ + if ((self = [super init]) == NULL) + return NULL; + + NSXPCInterface *interface = CKKSSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(CKKSControlProtocol)]); + NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; + + [listenerEndpoint _setEndpoint:endpoint]; + + self.connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; + if (self.connection == NULL) + return NULL; + + self.connection.remoteObjectInterface = interface; + + [self.connection resume]; + + + return self; +} + +- (NSDictionary *)printPerformanceCounters +{ + NSMutableDictionary *perfDict = [[NSMutableDictionary alloc] init]; +#if OCTAGON + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + perfDict[@"error"] = [error description]; + dispatch_semaphore_signal(sema); + + }] performanceCounters:^(NSDictionary *counters){ + [counters enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSNumber * obj, BOOL *stop) { + perfDict[key] = obj; + }]; + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) { + perfDict[@"error"] = @"timed out waiting for response"; + } +#endif + + return perfDict; +} + +- (void)resetLocal: (NSString*)view { +#if OCTAGON + printf("Beginning local reset for %s...\n", view ? [[view description] UTF8String] : "all zones"); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + + }] rpcResetLocal:view reply:^(NSError* result){ + if(result == NULL) { + printf("reset complete.\n"); + } else { + printf("reset error: %s\n", [[result description] UTF8String]); + } + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +#endif // OCTAGON +} + +- (void)resetCloudKit: (NSString*)view { +#if OCTAGON + printf("Beginning CloudKit reset for %s...\n", view ? [[view description] UTF8String] : "all zones"); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + + }] rpcResetCloudKit:view reply:^(NSError* result){ + if(result == NULL) { + printf("CloudKit Reset complete.\n"); + } else { + printf("Reset error: %s\n", [[result description] UTF8String]); + } + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +#endif // OCTAON +} + +- (void)resync: (NSString*)view { +#if OCTAGON + printf("Beginning resync for %s...\n", view ? [[view description] UTF8String] : "all zones"); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + + }] rpcResync:view reply:^(NSError* result){ + if(result == NULL) { + printf("resync success.\n"); + } else { + printf("resync errored: %s\n", [[result description] UTF8String]); + } + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +#endif // OCTAGON +} + +- (void)getAnalyticsSysdiagnose +{ + printf("Getting analytics sysdiagnose....\n"); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + }] rpcGetAnalyticsSysdiagnoseWithReply:^(NSString* sysdiagnose, NSError* error) { + if (sysdiagnose && !error) { + nsprintf(@"Analytics sysdiagnose:\n\n%@", sysdiagnose); + } + else { + nsprintf(@"error retrieving sysdiagnose: %@", error); + } + + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +} + +- (void)getAnalyticsJSON +{ + printf("Getting analytics json....\n"); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + }] rpcGetAnalyticsJSONWithReply:^(NSData* json, NSError* error) { + if (json && !error) { + nsprintf(@"Analytics JSON:\n\n%@", [[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding]); + } + else { + nsprintf(@"error retrieving JSON: %@", error); + } + + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +} + +- (void)forceAnalyticsUpload +{ + printf("Uploading....\n"); + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + }] rpcForceUploadAnalyticsWithReply:^(BOOL success, NSError* error) { + if (success) { + nsprintf(@"successfully uploaded analytics data"); + } + else { + nsprintf(@"error uploading analytics: %@", error); + } + + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +} + +- (NSDictionary *)status: (NSString*) view { + NSMutableDictionary *status = [[NSMutableDictionary alloc] init]; +#if OCTAGON + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + status[@"error"] = [error description]; + dispatch_semaphore_signal(sema); + + }] rpcStatus: view reply: ^(NSArray* result, NSError* error) { + if(error) { + status[@"error"] = [error description]; + } + + if(result.count == 0u) { + printf("No CKKS views are active.\n"); + } + + + for(NSDictionary* viewStatus in result) { + status[viewStatus[@"view"]] = viewStatus; + } + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5)) != 0) { + status[@"error"] = @"timed out"; + } +#endif // OCTAGON + return status; +} + +- (void)status_custom: (NSString*) view { +#if OCTAGON + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + + }] rpcStatus: view reply: ^(NSArray* result, NSError* error) { + if(error) { + printf("ERROR FETCHING STATUS: %s\n", [[error description] UTF8String]); + } + + if(result.count == 0u) { + printf("No CKKS views are active.\n"); + } + + for(NSDictionary* viewStatus in result) { + NSMutableDictionary* status = [viewStatus mutableCopy]; + + #define pop(d, key) ({ id x = d[key]; d[key] = nil; x; }) + + NSString* viewName = pop(status,@"view"); + NSString* accountStatus = pop(status,@"ckaccountstatus"); + NSString* lockStateTracker = pop(status,@"lockstatetracker"); + NSString* accountTracker = pop(status,@"accounttracker"); + NSString* fetcher = pop(status,@"fetcher"); + NSString* setup = pop(status,@"setup"); + NSString* zoneCreated = pop(status,@"zoneCreated"); + NSString* zoneCreatedError = pop(status,@"zoneCreatedError"); + NSString* zoneSubscribed = pop(status,@"zoneSubscribed"); + NSString* zoneSubscribedError = pop(status,@"zoneSubscribedError"); + NSString* zoneInitializeScheduler = pop(status,@"zoneInitializeScheduler"); + NSString* keystate = pop(status,@"keystate"); + NSString* keyStateError = pop(status,@"keyStateError"); + NSString* statusError = pop(status,@"statusError"); + NSString* currentTLK = pop(status,@"currentTLK"); + NSString* currentClassA = pop(status,@"currentClassA"); + NSString* currentClassC = pop(status,@"currentClassC"); + NSString* currentManifestGeneration = pop(status,@"currentManifestGen"); + + NSDictionary* oqe = pop(status,@"oqe"); + NSDictionary* iqe = pop(status,@"iqe"); + NSDictionary* keys = pop(status,@"keys"); + NSDictionary* ckmirror = pop(status,@"ckmirror"); + NSArray* devicestates = pop(status, @"devicestates"); + + NSString* zoneSetupOperation = pop(status,@"zoneSetupOperation"); + NSString* viewSetupOperation = pop(status,@"viewSetupOperation"); + NSString* keyStateOperation = pop(status,@"keyStateOperation"); + NSString* lastIncomingQueueOperation = pop(status,@"lastIncomingQueueOperation"); + NSString* lastNewTLKOperation = pop(status,@"lastNewTLKOperation"); + NSString* lastOutgoingQueueOperation = pop(status,@"lastOutgoingQueueOperation"); + NSString* lastRecordZoneChangesOperation = pop(status,@"lastRecordZoneChangesOperation"); + NSString* lastProcessReceivedKeysOperation = pop(status,@"lastProcessReceivedKeysOperation"); + NSString* lastReencryptOutgoingItemsOperation = pop(status,@"lastReencryptOutgoingItemsOperation"); + NSString* lastScanLocalItemsOperation = pop(status,@"lastScanLocalItemsOperation"); + + printf("================================================================================\n\n"); + + printf("View: %s\n\n", [viewName UTF8String]); + + if(![statusError isEqual: [NSNull null]]) { + printf("ERROR FETCHING STATUS: %s\n\n", [statusError UTF8String]); + } + + printf("CloudKit account: %s\n", [accountStatus UTF8String]); + printf("Account tracker: %s\n", [accountTracker UTF8String]); + printf("Ran setup operation: %s\n", [setup UTF8String]); + + 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 isEqual: [NSNull null]]) { + printf("Key State Error: %s\n", [keyStateError UTF8String]); + } + printf("Lock state: %s\n", [lockStateTracker UTF8String]); + + printf("Current TLK: %s\n", [currentTLK isEqual: [NSNull null]] ? "null" : [currentTLK UTF8String]); + printf("Current ClassA: %s\n", [currentClassA isEqual: [NSNull null]] ? "null" : [currentClassA UTF8String]); + printf("Current ClassC: %s\n", [currentClassC isEqual: [NSNull null]] ? "null" : [currentClassC 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 isEqual:[NSNull null]] ? "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 isEqual: [NSNull null]] ? "never" : [zoneSetupOperation UTF8String]); + printf("viewSetupOperation: %s\n", [viewSetupOperation isEqual: [NSNull null]] ? "never" : [viewSetupOperation UTF8String]); + printf("keyStateOperation: %s\n", [keyStateOperation isEqual: [NSNull null]] ? "never" : [keyStateOperation UTF8String]); + printf("lastIncomingQueueOperation: %s\n", [lastIncomingQueueOperation isEqual: [NSNull null]] ? "never" : [lastIncomingQueueOperation UTF8String]); + printf("lastNewTLKOperation: %s\n", [lastNewTLKOperation isEqual: [NSNull null]] ? "never" : [lastNewTLKOperation UTF8String]); + printf("lastOutgoingQueueOperation: %s\n", [lastOutgoingQueueOperation isEqual: [NSNull null]] ? "never" : [lastOutgoingQueueOperation UTF8String]); + printf("lastRecordZoneChangesOperation: %s\n", [lastRecordZoneChangesOperation isEqual: [NSNull null]] ? "never" : [lastRecordZoneChangesOperation UTF8String]); + printf("lastProcessReceivedKeysOperation: %s\n", [lastProcessReceivedKeysOperation isEqual: [NSNull null]] ? "never" : [lastProcessReceivedKeysOperation UTF8String]); + printf("lastReencryptOutgoingItemsOperation: %s\n", [lastReencryptOutgoingItemsOperation isEqual: [NSNull null]] ? "never" : [lastReencryptOutgoingItemsOperation UTF8String]); + printf("lastScanLocalItemsOperation: %s\n", [lastScanLocalItemsOperation isEqual: [NSNull null]] ? "never" : [lastScanLocalItemsOperation UTF8String]); + + if(status.allKeys.count > 0u) { + printf("\nExtra information: %s\n", [[status description] UTF8String]); + } + printf("\n"); + } + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +#endif // OCTAGON +} + +- (void)fetch: (NSString*) view { +#if OCTAGON + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + + }] rpcFetchAndProcessChanges:view reply:^(NSError* error) { + if(error) { + printf("Error fetching: %s\n", [[error description] UTF8String]); + } else { + printf("Complete.\n"); + } + + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 65)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +#endif // OCTAGON +} + +- (void)push: (NSString*) view { +#if OCTAGON + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]); + dispatch_semaphore_signal(sema); + + }] rpcPushOutgoingChanges:view reply:^(NSError* error) { + if(error) { + printf("Error pushing: %s\n", [[error description] UTF8String]); + } else { + printf("Complete.\n"); + } + + dispatch_semaphore_signal(sema); + }]; + + if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 65)) != 0) { + printf("\n\nError: timed out waiting for response\n"); + } +#endif // OCTAGON +} + +@end + + +static int perfCounters = false; +static int status = false; +static int resync = false; +static int reset = false; +static int resetCloudKit = false; +static int fetch = false; +static int push = false; +static int json = false; +static int getAnalyticsSysdiagnose = false; +static int getAnalyticsJSON = false; +static int uploadAnalytics = false; + +static char* viewArg = NULL; + +int main(int argc, char **argv) +{ + static struct argument options[] = { + { .shortname='p', .longname="perfcounters", .flag=&perfCounters, .flagval=true, .description="Print CKKS performance counters"}, + { .shortname='j', .longname="json", .flag=&json, .flagval=true, .description="Output in JSON format"}, + { .shortname='v', .longname="view", .argument=&viewArg, .description="Operate on a single view"}, + + { .command="status", .flag=&status, .flagval=true, .description="Report status on CKKS views"}, + { .command="fetch", .flag=&fetch, .flagval=true, .description="Fetch all new changes in CloudKit and attempt to process them"}, + { .command="push", .flag=&push, .flagval=true, .description="Push all pending local changes to CloudKit"}, + { .command="resync", .flag=&resync, .flagval=true, .description="Resync all data with what's in CloudKit"}, + { .command="reset", .flag=&reset, .flagval=true, .description="All local data will be wiped, and data refetched from CloudKit"}, + { .command="reset-cloudkit", .flag=&resetCloudKit, .flagval=true, .description="All data in CloudKit will be removed and replaced with what's local"}, + { .command="get-analytics-sysdiagnose", .flag=&getAnalyticsSysdiagnose, .flagval=true, .description="Retrieve the current sysdiagnose dump for CKKS analytics"}, + { .command="get-analytics", .flag=&getAnalyticsJSON, .flagval=true, .description="Retrieve the current JSON blob that would be uploaded to the logging server if an upload occurred now"}, + { .command="upload-analytics", .flag=&uploadAnalytics, .flagval=true, .description="Force an upload of analytics data to cloud server"}, + {} + }; + + static struct arguments args = { + .programname="ckksctl", + .description="Control and report on CKKS", + .arguments = options, + }; + + if(!options_parse(argc, argv, &args)) { + printf("\n"); + print_usage(&args); + return -1; + } + + @autoreleasepool { + xpc_endpoint_t endpoint = NULL; + + CFErrorRef cferror = NULL; + endpoint = _SecSecuritydCopyCKKSEndpoint(&cferror); + if (endpoint == NULL) { + CFStringRef errorstr = NULL; + + if(cferror) { + errorstr = CFErrorCopyDescription(cferror); + } + + errx(1, "no CKKSControl endpoint available: %s", errorstr ? CFStringGetCStringPtr(errorstr, kCFStringEncodingUTF8) : "unknown error"); + } + + CKKSControl *ctl = [[CKKSControl alloc] initWithEndpoint:endpoint]; + if (ctl == NULL) { + errx(1, "failed to create CKKSControl object"); + } + + NSString* view = viewArg ? [NSString stringWithCString: viewArg encoding: NSUTF8StringEncoding] : nil; + + if(status || perfCounters) { + NSMutableDictionary *statusDict = [[NSMutableDictionary alloc] init]; + statusDict[@"performance"] = [ctl printPerformanceCounters]; + if (!json) { + print_result(statusDict, false); + if (status) { + [ctl status_custom:view]; + } + } else { + if (status) { + statusDict[@"status"] = [ctl status:view]; + } + print_result(statusDict, true); + } + } else if(fetch) { + [ctl fetch:view]; + } else if(push) { + [ctl push:view]; + } else if(reset) { + [ctl resetLocal:view]; + } else if(resetCloudKit) { + [ctl resetCloudKit:view]; + } else if(resync) { + [ctl resync:view]; + } else if(getAnalyticsSysdiagnose) { + [ctl getAnalyticsSysdiagnose]; + } else if(getAnalyticsJSON) { + [ctl getAnalyticsJSON]; + } else if(uploadAnalytics) { + [ctl forceAnalyticsUpload]; + } else { + print_usage(&args); + return -1; + } + } + return 0; +} diff --git a/keychain/trust/.open_source_exclude b/keychain/trust/.open_source_exclude new file mode 100644 index 00000000..e69de29b diff --git a/keychain/trust/TrustedPeers/Info.plist b/keychain/trust/TrustedPeers/Info.plist new file mode 100644 index 00000000..dcf21d96 --- /dev/null +++ b/keychain/trust/TrustedPeers/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2017 Apple, Inc. All rights reserved. + NSPrincipalClass + + + diff --git a/keychain/trust/TrustedPeers/TPCategoryRule.h b/keychain/trust/TrustedPeers/TPCategoryRule.h new file mode 100644 index 00000000..a06b61eb --- /dev/null +++ b/keychain/trust/TrustedPeers/TPCategoryRule.h @@ -0,0 +1,47 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/*! + This class represents a single rule that, if it matches a prefix + of a model ID, assigns a category to that model. + + This class is just a pair of strings, for the prefix: category + mappings contained in a policy's modelToCategory array. + + This class is a value type -- its members are immutable and + instances with identical contents are interchangeable. + */ +@interface TPCategoryRule : NSObject + +@property (nonatomic, readonly) NSString *prefix; +@property (nonatomic, readonly) NSString *category; + ++ (instancetype)ruleWithPrefix:(NSString *)prefix category:(NSString *)category; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPCategoryRule.m b/keychain/trust/TrustedPeers/TPCategoryRule.m new file mode 100644 index 00000000..410f1eb9 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPCategoryRule.m @@ -0,0 +1,72 @@ +/* + * 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 "TPCategoryRule.h" + + +@interface TPCategoryRule () + +@property (nonatomic, copy) NSString *prefix; +@property (nonatomic, copy) NSString *category; + +@end + + +@implementation TPCategoryRule + ++ (instancetype)ruleWithPrefix:(NSString *)prefix category:(NSString *)category +{ + TPCategoryRule *rule = [[TPCategoryRule alloc] init]; + rule.prefix = prefix; + rule.category = category; + return rule; +} + +- (BOOL)isEqualToCategoryRule:(TPCategoryRule *)other +{ + if (other == self) { + return YES; + } + return [self.prefix isEqualToString:other.prefix] + && [self.category isEqualToString:other.category]; +} + +#pragma mark - NSObject + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[TPCategoryRule class]]) { + return NO; + } + return [self isEqualToCategoryRule:object]; +} + +- (NSUInteger)hash +{ + return [self.prefix hash] ^ [self.category hash]; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPCircle.h b/keychain/trust/TrustedPeers/TPCircle.h new file mode 100644 index 00000000..fa2a660a --- /dev/null +++ b/keychain/trust/TrustedPeers/TPCircle.h @@ -0,0 +1,66 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/*! + A "circle" identifies a set of peers that should be included and + a set of peers that should be excluded from trust membership. + + This class is a value type -- its members are immutable and + instances with identical contents are interchangeable. + It overrides isEqual and hash, so that two instances with + identical contents will compare as equal. + */ +@interface TPCircle : NSObject + +@property (nonatomic, readonly) NSString *circleID; +@property (nonatomic, readonly) NSSet* includedPeerIDs; +@property (nonatomic, readonly) NSSet* excludedPeerIDs; + +/*! + A convenience for allocating and initializing an instance from array literals. + */ ++ (instancetype)circleWithIncludedPeerIDs:(nullable NSArray *)includedPeerIDs + excludedPeerIDs:(nullable NSArray *)excludedPeerIDs; + +/*! + A convenience for checking a provided circleID. Returns nil if it does not match. + */ ++ (nullable instancetype)circleWithID:(NSString *)circleID + includedPeerIDs:(nullable NSArray *)includedPeerIDs + excludedPeerIDs:(nullable NSArray *)excludedPeerIDs; + +/*! + Construct a circle that includes a set of peer IDs and excludes a set of peer IDs. + */ +- (instancetype)initWithIncludedPeerIDs:(NSSet *)includedPeerIDs + excludedPeerIDs:(NSSet *)excludedPeerIDs; + +- (BOOL)isEqualToCircle:(TPCircle *)other; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPCircle.m b/keychain/trust/TrustedPeers/TPCircle.m new file mode 100644 index 00000000..6955a2f1 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPCircle.m @@ -0,0 +1,123 @@ +/* + * 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 "TPCircle.h" +#import "TPHash.h" + +@interface TPCircle () +@property (nonatomic, strong) NSString* circleID; +@property (nonatomic, strong) NSSet* includedPeerIDs; +@property (nonatomic, strong) NSSet* excludedPeerIDs; +@end + +@implementation TPCircle + ++ (instancetype)circleWithIncludedPeerIDs:(NSArray *)includedPeerIDs + excludedPeerIDs:(NSArray *)excludedPeerIDs +{ + return [[TPCircle alloc] initWithIncludedPeerIDs:[NSSet setWithArray:includedPeerIDs] + excludedPeerIDs:[NSSet setWithArray:excludedPeerIDs]]; +} + ++ (instancetype)circleWithID:(NSString *)circleID + includedPeerIDs:(NSArray *)includedPeerIDs + excludedPeerIDs:(NSArray *)excludedPeerIDs +{ + TPCircle *circle = [TPCircle circleWithIncludedPeerIDs:includedPeerIDs + excludedPeerIDs:excludedPeerIDs]; + if ([circleID isEqualToString:circle.circleID]) { + return circle; + } else { + return nil; + } +} + +- (instancetype)initWithIncludedPeerIDs:(NSSet *)includedPeerIDs + excludedPeerIDs:(NSSet *)excludedPeerIDs +{ + self = [super init]; + if (self) { + // Copy the sets passed in, so that nobody can mutate them later. + _includedPeerIDs = [includedPeerIDs copy]; + _excludedPeerIDs = [excludedPeerIDs copy]; + + NSArray* sortedInc = [[includedPeerIDs allObjects] sortedArrayUsingSelector:@selector(compare:)]; + NSArray* sortedExc = [[excludedPeerIDs allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + TPHashBuilder* hasher = [[TPHashBuilder alloc] initWithAlgo:kTPHashAlgoSHA256]; + { + const char* inc = "include: "; + [hasher updateWithBytes:inc len:strlen(inc)]; + for (NSString* peerID in sortedInc) { + [hasher updateWithData:[peerID dataUsingEncoding:NSUTF8StringEncoding]]; + } + } + { + const char* exc = "exclude: "; + [hasher updateWithBytes:exc len:strlen(exc)]; + for (NSString* peerID in sortedExc) { + [hasher updateWithData:[peerID dataUsingEncoding:NSUTF8StringEncoding]]; + } + } + _circleID = [hasher finalHash]; + } + return self; +} + +- (BOOL)isEqualToCircle:(TPCircle *)other +{ + return [self.includedPeerIDs isEqualToSet:other.includedPeerIDs] + && [self.excludedPeerIDs isEqualToSet:other.excludedPeerIDs]; +} + +#pragma mark - NSObject + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[TPCircle class]]) { + return NO; + } + return [self isEqualToCircle:object]; +} + +- (NSUInteger)hash +{ + return [self.includedPeerIDs hash] ^ ([self.excludedPeerIDs hash] << 1); +} + +static NSString *setDescription(NSSet *set) +{ + return [[[set allObjects] sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@" "]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"{ in: [%@] ex: [%@] }", + setDescription(self.includedPeerIDs), + setDescription(self.excludedPeerIDs)]; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPDecrypter.h b/keychain/trust/TrustedPeers/TPDecrypter.h new file mode 100644 index 00000000..cc523a78 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPDecrypter.h @@ -0,0 +1,36 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@protocol TPDecrypter + +- (nullable NSData *)decryptData:(NSData *)ciphertext + withKey:(NSData *)key + error:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPEncrypter.h b/keychain/trust/TrustedPeers/TPEncrypter.h new file mode 100644 index 00000000..48f2bea1 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPEncrypter.h @@ -0,0 +1,36 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@protocol TPEncrypter + +@property (nonatomic, readonly) NSData *decryptionKey; + +- (nullable NSData *)encryptData:(NSData *)plaintext error:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPHash.h b/keychain/trust/TrustedPeers/TPHash.h new file mode 100644 index 00000000..af304c29 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPHash.h @@ -0,0 +1,60 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/*! + A hash digest algorithm + */ +typedef NS_ENUM(NSInteger, TPHashAlgo) { + kTPHashAlgoUnknown = -1, + kTPHashAlgoSHA224 = 0, + kTPHashAlgoSHA256, + kTPHashAlgoSHA384, + kTPHashAlgoSHA512, +}; + +/*! + A hash prefixed with the name of the digest algorithm, e.g. + "SHA256:xxxx" where the 'x' are 8-bit bytes. + */ + + +@interface TPHashBuilder : NSObject + ++ (TPHashAlgo)algoOfHash:(NSString *)hash; + +- (instancetype)initWithAlgo:(TPHashAlgo)algo; +- (void)resetWithAlgo:(TPHashAlgo)algo; +- (void)updateWithData:(NSData *)data; +- (void)updateWithBytes:(const void *)data len:(size_t)len; +- (NSString *)finalHash; + ++ (NSString *)hashWithAlgo:(TPHashAlgo)algo ofData:(NSData *)data; ++ (NSString *)hashWithAlgo:(TPHashAlgo)algo ofBytes:(const void *)data len:(size_t)len; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPHash.m b/keychain/trust/TrustedPeers/TPHash.m new file mode 100644 index 00000000..703c034d --- /dev/null +++ b/keychain/trust/TrustedPeers/TPHash.m @@ -0,0 +1,175 @@ +/* + * 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 "TPHash.h" + +#import + +@interface TPHashBuilder () + +@property (nonatomic, assign) TPHashAlgo algo; +@property (nonatomic, assign) CC_SHA256_CTX ctxSHA256; // used by SHA224 and SHA256 +@property (nonatomic, assign) CC_SHA512_CTX ctxSHA512; // used by SHA384 and SHA512 + +@end + +@implementation TPHashBuilder + ++ (TPHashAlgo)algoOfHash:(NSString *)hash +{ + if ([hash hasPrefix:@"SHA224:"]) { + return kTPHashAlgoSHA224; + } + if ([hash hasPrefix:@"SHA256:"]) { + return kTPHashAlgoSHA256; + } + if ([hash hasPrefix:@"SHA384:"]) { + return kTPHashAlgoSHA384; + } + if ([hash hasPrefix:@"SHA512:"]) { + return kTPHashAlgoSHA512; + } + return kTPHashAlgoUnknown; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _algo = kTPHashAlgoUnknown; + } + return self; +} + +- (instancetype)initWithAlgo:(TPHashAlgo)algo +{ + self = [self init]; + [self resetWithAlgo:algo]; + return self; +} + +- (void)resetWithAlgo:(TPHashAlgo)algo +{ + _algo = algo; + switch (algo) { + case kTPHashAlgoSHA224: + CC_SHA224_Init(&_ctxSHA256); + break; + case kTPHashAlgoSHA256: + CC_SHA256_Init(&_ctxSHA256); + break; + case kTPHashAlgoSHA384: + CC_SHA384_Init(&_ctxSHA512); + break; + case kTPHashAlgoSHA512: + CC_SHA512_Init(&_ctxSHA512); + break; + default: + [self throwInvalidAlgo]; + } +} + +- (void)updateWithData:(NSData *)data +{ + [self updateWithBytes:data.bytes len:data.length]; +} + +- (void)updateWithBytes:(const void *)data len:(size_t)len +{ + switch (self.algo) { + case kTPHashAlgoSHA224: + CC_SHA224_Update(&_ctxSHA256, data, (CC_LONG)len); + break; + case kTPHashAlgoSHA256: + CC_SHA256_Update(&_ctxSHA256, data, (CC_LONG)len); + break; + case kTPHashAlgoSHA384: + CC_SHA384_Update(&_ctxSHA512, data, (CC_LONG)len); + break; + case kTPHashAlgoSHA512: + CC_SHA512_Update(&_ctxSHA512, data, (CC_LONG)len); + break; + default: + [self throwInvalidAlgo]; + } +} + +- (NSString *)finalHash +{ + NSMutableData* data = [NSMutableData alloc]; + NSString* name = nil; + switch (self.algo) { + case kTPHashAlgoSHA224: + data = [data initWithLength:224/8]; + CC_SHA224_Final(data.mutableBytes, &_ctxSHA256); + name = @"SHA224"; + break; + case kTPHashAlgoSHA256: + data = [data initWithLength:256/8]; + CC_SHA256_Final(data.mutableBytes, &_ctxSHA256); + name = @"SHA256"; + break; + case kTPHashAlgoSHA384: + data = [data initWithLength:384/8]; + CC_SHA384_Final(data.mutableBytes, &_ctxSHA512); + name = @"SHA384"; + break; + case kTPHashAlgoSHA512: + data = [data initWithLength:512/8]; + CC_SHA512_Final(data.mutableBytes, &_ctxSHA512); + name = @"SHA512"; + break; + default: + [self throwInvalidAlgo]; + } + NSString* hash = [NSString stringWithFormat:@"%@:%@", + name, [data base64EncodedStringWithOptions:0]]; + + // _ctxSHA* was "emptied" by the call to CC_SHA*_Final, + // so require the client to call resetWithAlgo: before reuse. + self.algo = kTPHashAlgoUnknown; + + return hash; +} + +- (void)throwInvalidAlgo +{ + NSException* ex = [NSException exceptionWithName:@"InvalidTPHashAlgo" + reason:@"Invalid TPHash algorithm" + userInfo:nil]; + @throw ex; +} + ++ (NSString *)hashWithAlgo:(TPHashAlgo)algo ofData:(NSData *)data +{ + return [TPHashBuilder hashWithAlgo:algo ofBytes:data.bytes len:data.length]; +} + ++ (NSString *)hashWithAlgo:(TPHashAlgo)algo ofBytes:(const void *)data len:(size_t)len +{ + TPHashBuilder *builder = [[TPHashBuilder alloc] initWithAlgo:algo]; + [builder updateWithBytes:data len:len]; + return [builder finalHash]; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPModel.h b/keychain/trust/TrustedPeers/TPModel.h new file mode 100644 index 00000000..e750acf9 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPModel.h @@ -0,0 +1,253 @@ +/* + * 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 + +#import "TPHash.h" +#import "TPSigningKey.h" +#import "TPDecrypter.h" +#import "TPTypes.h" + +@class TPCircle; +@class TPPeerPermanentInfo; +@class TPPeerStableInfo; +@class TPPeerDynamicInfo; +@class TPVoucher; +@class TPPolicyDocument; + + +typedef NS_OPTIONS(NSUInteger, TPPeerStatus) { + // Set if at least one of the peers I trust trusts me. + TPPeerStatusPartiallyReciprocated = 1 << 0, + + // Set if all of the peers I trust trust me. + TPPeerStatusFullyReciprocated = 1 << 1, + + // Set if I have been kicked out of trust. + TPPeerStatusExcluded = 1 << 2, + + // Set if my epoch is behind the latest epoch. + TPPeerStatusOutdatedEpoch = 1 << 3, + + // Set if my epoch is two or more epochs behind the latest. + TPPeerStatusAncientEpoch = 1 << 4, +}; + + +NS_ASSUME_NONNULL_BEGIN + +/*! + TPModel implements the Octagon Trust model, as per + https://confluence.sd.apple.com/display/KEY/Octagon+Trust + + It maintains a collection of peers and a collection of circles, + to track the peers and circles in CloudKit. + (This class does not communicate with CloudKit. The client of this class does that.) + + Normally there would be just one instance of TPModel, associated with a particular Apple ID. + (This class doesn't need to know what the Apple ID is.) + + This interface does not expose TPPeer* because the caller might mutate the peer object. + All the objects exposed by this interface are immutable. +*/ +@interface TPModel : NSObject + +- (instancetype)initWithDecrypter:(id)decrypter; + +- (TPCounter)latestEpochAmongPeerIDs:(NSSet *)peerIDs; + +- (void)registerPolicyDocument:(TPPolicyDocument *)policyDoc; + +/*! + Register a peer with the given permanentInfo. + + To access this peer invoke other TPModel methods and + pass permanentInfo.peerID as the peerID argument. + + (If a peer with this permanentInfo is already registered then registering it again + does nothing, and the existing TPPeer object internal to TPModel retains its state.) + */ +- (void)registerPeerWithPermanentInfo:(TPPeerPermanentInfo *)permanentInfo; + +- (void)deletePeerWithID:(NSString *)peerID; + +- (BOOL)hasPeerWithID:(NSString *)peerID; + +/*! + Asserts that peerID is registered. + */ +- (TPPeerStatus)statusOfPeerWithID:(NSString *)peerID; + +/*! + Asserts that peerID is registered. + */ +- (TPPeerPermanentInfo *)getPermanentInfoForPeerWithID:(NSString *)peerID; + +/*! + Asserts that peerID is registered. + */ +- (nullable TPPeerStableInfo *)getStableInfoForPeerWithID:(NSString *)peerID; + +/*! + Asserts that peerID is registered. + */ +- (nullable NSData *)getWrappedPrivateKeysForPeerWithID:(NSString *)peerID; + +/*! + Asserts that peerID is registered. + */ +- (void)setWrappedPrivateKeys:(nullable NSData *)wrappedPrivateKeys + forPeerWithID:(NSString *)peerID; + +/*! + Asserts that peerID is registered. + */ +- (nullable TPPeerDynamicInfo *)getDynamicInfoForPeerWithID:(NSString *)peerID; + +/*! + Asserts that peerID is registered. + */ +- (nullable TPCircle *)getCircleForPeerWithID:(NSString *)peerID; + + +- (void)registerCircle:(TPCircle *)circle; + +- (void)deleteCircleWithID:(NSString *)circleID; + +/*! + Returns nil if no circle matching circleID is registered. + */ +- (nullable TPCircle *)circleWithID:(NSString *)circleID; + + +/*! + An "update" with unchanged data is considered success. + Asserts that peerID is registered. + */ +- (TPResult)updateStableInfo:(TPPeerStableInfo *)stableInfo + forPeerWithID:(NSString *)peerID; + +/*! + Returns nil with error if the peer's trustSigningKey is unable to create + a signature because the private key is unavailable, e.g. because the device is locked. + + Asserts peerID is registered. + */ +- (TPPeerStableInfo *)createStableInfoWithDictionary:(NSDictionary *)dict + policyVersion:(TPCounter)policyVersion + policyHash:(NSString *)policyHash + policySecrets:(nullable NSDictionary *)policySecrets + forPeerWithID:(NSString *)peerID + error:(NSError **)error; + + +/*! + An "update" with unchanged data is considered success. + Asserts peerID is registered. + */ +- (TPResult)updateDynamicInfo:(TPPeerDynamicInfo *)dynamicInfo + forPeerWithID:(NSString *)peerID; + + +/*! + The returned voucher is not registered. + Asserts sponsorID is registered. + + Returns nil with nil error if policy determines that the sponsor + is not permitted to introduce this candidate. + + Returns nil with error if the sponsor's trustSigningKey is unable to create + a signature because the private key is unavailable, e.g. because the device is locked. + + The candidate need not be registered before making this call. + */ +- (nullable TPVoucher *)createVoucherForCandidate:(TPPeerPermanentInfo *)candidate + withSponsorID:(NSString *)sponsorID + error:(NSError **)error; + +/*! + Asserts that the sponsor is registered, so that the signature check can be performed. + The beneficiary need not be registered. + */ +- (TPResult)registerVoucher:(TPVoucher *)voucher; + + +- (NSSet *)calculateUnusedCircleIDs; + +/*! + Calculates updated dynamic info for a given peer, + according to the membership convergence algorithm. + + This method does not update the model. The calculated circle is not registered + and the peer is not updated with the calculated dynamicInfo. It is the caller's + responsibility to register/update them once they have been persisted to CloudKit. + + Peers listed in addingPeerIDs are taken to have been explicitly trusted by the user. + When the user adds a member of addingPeerIDs into trust, the peers already trusted + by that new peer are also taken to be trusted, even if the new peer is not qualified by + policy to *introduce* them into trust. This is neccessary in a scenario where a mid-level + device approves a lowly device, and the new lowly device should trust the high-level devices + already in the circle. The mid-level device is not *introducing* the high-level devices. + + Peers listed in removingPeerIDs are excluded from trust. + + Returns nil with error if the peer's trustSigningKey is unable to create + a signature because the private key is unavailable, e.g. because the device is locked. + + Asserts peerID is registered. + */ +- (nullable TPPeerDynamicInfo *)calculateDynamicInfoForPeerWithID:(NSString *)peerID + addingPeerIDs:(nullable NSArray *)addingPeerIDs + removingPeerIDs:(nullable NSArray *)removingPeerIDs + createClique:(nullable NSString* (^)())createClique + updatedCircle:(TPCircle * _Nullable * _Nullable)updatedCircle + error:(NSError **)error; + +/*! + A convenience method for tests, this calls calculateDynamicInfoForPeerWithID, + registers the results and returns the new circle. + */ +- (TPCircle *)advancePeerWithID:(NSString *)peerID + addingPeerIDs:(nullable NSArray *)addingPeerIDs + removingPeerIDs:(nullable NSArray *)removingPeerIDs + createClique:(nullable NSString* (^)())createClique; + +/*! + From our trusted peers, return the subset that is allowed + to access the given view, according to the current policy. + + Asserts peerID is registered. + */ +- (nullable NSSet *)getPeerIDsTrustedByPeerWithID:(NSString *)peerID + toAccessView:(NSString *)view + error:(NSError **)error; + +/*! + Returns a dictionary mapping from each peer ID + to the most recent clock seen from that peer. + */ +- (NSDictionary *)vectorClock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPModel.m b/keychain/trust/TrustedPeers/TPModel.m new file mode 100644 index 00000000..7ec2166a --- /dev/null +++ b/keychain/trust/TrustedPeers/TPModel.m @@ -0,0 +1,730 @@ +/* + * 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 "TPModel.h" +#import "TPPeer.h" +#import "TPHash.h" +#import "TPCircle.h" +#import "TPVoucher.h" +#import "TPPeerPermanentInfo.h" +#import "TPPeerStableInfo.h" +#import "TPPeerDynamicInfo.h" +#import "TPPolicy.h" +#import "TPPolicyDocument.h" + + +@interface TPModel () +@property (nonatomic, strong) NSMutableDictionary* peersByID; +@property (nonatomic, strong) NSMutableDictionary* circlesByID; +@property (nonatomic, strong) NSMutableDictionary* policiesByVersion; +@property (nonatomic, strong) NSMutableSet* vouchers; +@property (nonatomic, strong) id decrypter; +@end + +@implementation TPModel + +- (instancetype)initWithDecrypter:(id)decrypter +{ + self = [super init]; + if (self) { + _peersByID = [[NSMutableDictionary alloc] init]; + _circlesByID = [[NSMutableDictionary alloc] init]; + _policiesByVersion = [[NSMutableDictionary alloc] init]; + _vouchers = [[NSMutableSet alloc] init]; + _decrypter = decrypter; + } + return self; +} + +- (TPCounter)latestEpochAmongPeerIDs:(NSSet *)peerIDs +{ + TPCounter latestEpoch = 0; + for (NSString *peerID in peerIDs) { + TPPeer *peer = self.peersByID[peerID]; + if (nil == peer) { + continue; + } + latestEpoch = MAX(latestEpoch, peer.permanentInfo.epoch); + } + return latestEpoch; +} + +- (void)registerPolicyDocument:(TPPolicyDocument *)policyDoc +{ + NSAssert(policyDoc, @"policyDoc must not be nil"); + self.policiesByVersion[@(policyDoc.policyVersion)] = policyDoc; +} + +- (void)registerPeerWithPermanentInfo:(TPPeerPermanentInfo *)permanentInfo +{ + NSAssert(permanentInfo, @"permanentInfo must not be nil"); + if (nil == [self.peersByID objectForKey:permanentInfo.peerID]) { + TPPeer *peer = [[TPPeer alloc] initWithPermanentInfo:permanentInfo]; + [self.peersByID setObject:peer forKey:peer.peerID]; + } else { + // Do nothing, to avoid overwriting the existing peer object which might have accumulated state. + } +} + +- (void)deletePeerWithID:(NSString *)peerID +{ + [self.peersByID removeObjectForKey:peerID]; +} + +- (BOOL)hasPeerWithID:(NSString *)peerID +{ + return nil != self.peersByID[peerID]; +} + +- (nonnull TPPeer *)peerWithID:(NSString *)peerID +{ + TPPeer *peer = [self.peersByID objectForKey:peerID]; + NSAssert(nil != peer, @"peerID is not registered: %@", peerID); + return peer; +} + +- (TPPeerStatus)statusOfPeerWithID:(NSString *)peerID +{ + TPPeer *peer = [self peerWithID:peerID]; + TPPeerStatus status = 0; + if (0 < [peer.circle.includedPeerIDs count]) { + status |= TPPeerStatusFullyReciprocated; + // This flag might get cleared again, below. + } + for (NSString *otherID in peer.circle.includedPeerIDs) { + if ([peerID isEqualToString:otherID]) { + continue; + } + TPPeer *otherPeer = self.peersByID[otherID]; + if (nil == otherPeer) { + continue; + } + if ([otherPeer.circle.includedPeerIDs containsObject:peerID]) { + status |= TPPeerStatusPartiallyReciprocated; + } else { + status &= ~TPPeerStatusFullyReciprocated; + } + if ([otherPeer.circle.excludedPeerIDs containsObject:peerID]) { + status |= TPPeerStatusExcluded; + } + if (otherPeer.permanentInfo.epoch > peer.permanentInfo.epoch) { + status |= TPPeerStatusOutdatedEpoch; + } + if (otherPeer.permanentInfo.epoch > peer.permanentInfo.epoch + 1) { + status |= TPPeerStatusAncientEpoch; + } + } + if ([peer.circle.excludedPeerIDs containsObject:peerID]) { + status |= TPPeerStatusExcluded; + } + return status; +} + + +- (TPPeerPermanentInfo *)getPermanentInfoForPeerWithID:(NSString *)peerID +{ + return [self peerWithID:peerID].permanentInfo; +} + +- (TPPeerStableInfo *)getStableInfoForPeerWithID:(NSString *)peerID +{ + return [self peerWithID:peerID].stableInfo; +} + +- (NSData *)getWrappedPrivateKeysForPeerWithID:(NSString *)peerID +{ + return [self peerWithID:peerID].wrappedPrivateKeys; +} + +- (void)setWrappedPrivateKeys:(nullable NSData *)wrappedPrivateKeys + forPeerWithID:(NSString *)peerID +{ + [self peerWithID:peerID].wrappedPrivateKeys = wrappedPrivateKeys; +} + +- (TPPeerDynamicInfo *)getDynamicInfoForPeerWithID:(NSString *)peerID +{ + return [self peerWithID:peerID].dynamicInfo; +} + +- (TPCircle *)getCircleForPeerWithID:(NSString *)peerID +{ + return [self peerWithID:peerID].circle; +} + +- (void)registerCircle:(TPCircle *)circle +{ + NSAssert(circle, @"circle must not be nil"); + [self.circlesByID setObject:circle forKey:circle.circleID]; + + // A dynamicInfo might have been set on a peer before we had the circle identified by dynamicInfo.circleID. + // Check if this circle is referenced by any dynamicInfo.circleID. + [self.peersByID enumerateKeysAndObjectsUsingBlock:^(NSString *peerID, TPPeer *peer, BOOL *stop) { + if (nil == peer.circle && [peer.dynamicInfo.circleID isEqualToString:circle.circleID]) { + peer.circle = circle; + } + }]; +} + +- (void)deleteCircleWithID:(NSString *)circleID +{ + [self.peersByID enumerateKeysAndObjectsUsingBlock:^(NSString *peerID, TPPeer *peer, BOOL *stop) { + NSAssert(![circleID isEqualToString:peer.dynamicInfo.circleID], + @"circle being deleted is in use by peer %@, circle %@", peerID, circleID); + }]; + [self.circlesByID removeObjectForKey:circleID]; +} + +- (TPCircle *)circleWithID:(NSString *)circleID +{ + return [self.circlesByID objectForKey:circleID]; +} + +- (TPResult)updateStableInfo:(TPPeerStableInfo *)stableInfo + forPeerWithID:(NSString *)peerID +{ + TPPeer *peer = [self peerWithID:peerID]; + return [peer updateStableInfo:stableInfo]; +} + +- (TPPeerStableInfo *)createStableInfoWithDictionary:(NSDictionary *)dict + policyVersion:(TPCounter)policyVersion + policyHash:(NSString *)policyHash + policySecrets:(nullable NSDictionary *)policySecrets + forPeerWithID:(NSString *)peerID + error:(NSError **)error +{ + TPPeer *peer = [self peerWithID:peerID]; + TPCounter clock = [self maxClock] + 1; + return [TPPeerStableInfo stableInfoWithDict:dict + clock:clock + policyVersion:policyVersion + policyHash:policyHash + policySecrets:policySecrets + trustSigningKey:peer.permanentInfo.trustSigningKey + error:error]; +} + +- (TPResult)updateDynamicInfo:(TPPeerDynamicInfo *)dynamicInfo + forPeerWithID:(NSString *)peerID +{ + TPPeer *peer = [self peerWithID:peerID]; + TPResult result = [peer updateDynamicInfo:dynamicInfo]; + if (result != TPResultOk) { + return result; + } + TPCircle *circle = [self.circlesByID objectForKey:dynamicInfo.circleID]; + if (nil != circle) { + peer.circle = circle; + } else { + // When the corresponding circleID is eventually registered, + // a call to registerCircle: will set peer.circle. + } + return result; +} + +- (TPCounter)maxClock +{ + __block TPCounter maxClock = 0; + [self.peersByID enumerateKeysAndObjectsUsingBlock:^(NSString *peerID, TPPeer *peer, BOOL *stop) { + if (nil != peer.stableInfo) { + maxClock = MAX(maxClock, peer.stableInfo.clock); + } + if (nil != peer.dynamicInfo) { + maxClock = MAX(maxClock, peer.dynamicInfo.clock); + } + }]; + return maxClock; +} + +- (TPCounter)maxRemovals +{ + __block TPCounter maxRemovals = 0; + [self.peersByID enumerateKeysAndObjectsUsingBlock:^(NSString *peerID, TPPeer *peer, BOOL *stop) { + if (nil != peer.dynamicInfo) { + maxRemovals = MAX(maxRemovals, peer.dynamicInfo.removals); + } + }]; + return maxRemovals; +} + +- (TPPeerDynamicInfo *)createDynamicInfoForPeerWithID:(NSString *)peerID + circle:(TPCircle *)circle + clique:(NSString *)clique + newRemovals:(TPCounter)newRemovals + error:(NSError **)error +{ + TPPeer *peer = self.peersByID[peerID]; + + TPCounter clock = [self maxClock] + 1; + TPCounter removals = [self maxRemovals] + newRemovals; + + return [TPPeerDynamicInfo dynamicInfoWithCircleID:circle.circleID + clique:clique + removals:removals + clock:clock + trustSigningKey:peer.permanentInfo.trustSigningKey + error:error]; +} + +- (BOOL)canTrustCandidate:(TPPeerPermanentInfo *)candidate inEpoch:(TPCounter)epoch +{ + return candidate.epoch + 1 >= epoch; +} + +- (BOOL)canIntroduceCandidate:(TPPeerPermanentInfo *)candidate + withSponsor:(TPPeerPermanentInfo *)sponsor + toEpoch:(TPCounter)epoch + underPolicy:(id)policy +{ + if (![self canTrustCandidate:candidate inEpoch:sponsor.epoch]) { + return NO; + } + if (![self canTrustCandidate:candidate inEpoch:epoch]) { + return NO; + } + + NSString *sponsorCategory = [policy categoryForModel:sponsor.modelID]; + NSString *candidateCategory = [policy categoryForModel:candidate.modelID]; + + return [policy trustedPeerInCategory:sponsorCategory canIntroduceCategory:candidateCategory]; +} + +- (nullable TPVoucher *)createVoucherForCandidate:(TPPeerPermanentInfo *)candidate + withSponsorID:(NSString *)sponsorID + error:(NSError **)error +{ + TPPeer *sponsor = [self peerWithID:sponsorID]; + + NSSet *peerIDs = [sponsor.trustedPeerIDs setByAddingObject:candidate.peerID]; + id policy = [self policyForPeerIDs:peerIDs error:error]; + if (nil == policy) { + return nil; + } + + if (![self canIntroduceCandidate:candidate + withSponsor:sponsor.permanentInfo + toEpoch:sponsor.permanentInfo.epoch + underPolicy:policy]) + { + if (error) { + *error = nil; + } + return nil; + } + + // clock is correctly zero if sponsor does not yet have dynamicInfo + TPCounter clock = sponsor.dynamicInfo.clock; + return [TPVoucher voucherWithBeneficiaryID:candidate.peerID + sponsorID:sponsorID + clock:clock + trustSigningKey:sponsor.permanentInfo.trustSigningKey + error:error]; +} + +- (TPResult)registerVoucher:(TPVoucher *)voucher +{ + NSAssert(voucher, @"voucher must not be nil"); + TPPeer *sponsor = [self peerWithID:voucher.sponsorID]; + if (![sponsor.permanentInfo.trustSigningKey checkSignature:voucher.voucherInfoSig matchesData:voucher.voucherInfoPList]) { + return TPResultSignatureMismatch; + } + [self.vouchers addObject:voucher]; + return TPResultOk; +} + +- (NSSet *)calculateUnusedCircleIDs +{ + NSMutableSet* circleIDs = [NSMutableSet setWithArray:[self.circlesByID allKeys]]; + + [self.peersByID enumerateKeysAndObjectsUsingBlock:^(NSString *peerID, TPPeer *peer, BOOL *stop) { + if (nil != peer.dynamicInfo) { + [circleIDs removeObject:peer.dynamicInfo.circleID]; + } + }]; + return circleIDs; +} + +- (nullable NSError *)considerCandidateID:(NSString *)candidateID + withSponsor:(TPPeer *)sponsor + toExpandIncludedPeerIDs:(NSMutableSet*)includedPeerIDs + andExcludedPeerIDs:(NSMutableSet*)excludedPeerIDs + forEpoch:(TPCounter)epoch +{ + if ([includedPeerIDs containsObject:candidateID]) { + // Already included, nothing to do. + return nil; + } + if ([excludedPeerIDs containsObject:candidateID]) { + // Denied. + return nil; + } + + TPPeer *candidate = self.peersByID[candidateID]; + if (nil == candidate) { + return nil; + } + NSMutableSet *peerIDs = [NSMutableSet setWithSet:includedPeerIDs]; + [peerIDs minusSet:excludedPeerIDs]; + [peerIDs addObject:candidateID]; + NSError *error = nil; + id policy = [self policyForPeerIDs:peerIDs error:&error]; + if (nil == policy) { + return error; + } + + if ([self canIntroduceCandidate:candidate.permanentInfo + withSponsor:sponsor.permanentInfo + toEpoch:epoch + underPolicy:policy]) + { + [includedPeerIDs addObject:candidateID]; + [excludedPeerIDs unionSet:candidate.circle.excludedPeerIDs]; + + // The accepted candidate can now be a sponsor. + error = [self recursivelyExpandIncludedPeerIDs:includedPeerIDs + andExcludedPeerIDs:excludedPeerIDs + withPeersTrustedBySponsorID:candidateID + forEpoch:epoch]; + if (nil != error) { + return error; + } + } + return nil; +} + +- (nullable NSError *)considerVouchersSponsoredByPeer:(TPPeer *)sponsor + toReecursivelyExpandIncludedPeerIDs:(NSMutableSet*)includedPeerIDs + andExcludedPeerIDs:(NSMutableSet*)excludedPeerIDs + forEpoch:(TPCounter)epoch +{ + for (TPVoucher *voucher in self.vouchers) { + if ([voucher.sponsorID isEqualToString:sponsor.peerID] + && voucher.clock == sponsor.dynamicInfo.clock) + { + NSError *error = [self considerCandidateID:voucher.beneficiaryID + withSponsor:sponsor + toExpandIncludedPeerIDs:includedPeerIDs + andExcludedPeerIDs:excludedPeerIDs + forEpoch:epoch]; + if (nil != error) { + return error; + } + } + } + return nil; +} + +- (nullable NSError *)recursivelyExpandIncludedPeerIDs:(NSMutableSet*)includedPeerIDs + andExcludedPeerIDs:(NSMutableSet*)excludedPeerIDs + withPeersTrustedBySponsorID:(NSString *)sponsorID + forEpoch:(TPCounter)epoch +{ + TPPeer *sponsor = self.peersByID[sponsorID]; + if (nil == sponsor) { + // It is possible that we might receive a voucher sponsored + // by a peer that has not yet been registered or has been deleted, + // or that a peer will have a circle that includes a peer that + // has not yet been registered or has been deleted. + return nil; + } + [excludedPeerIDs unionSet:sponsor.circle.excludedPeerIDs]; + for (NSString *candidateID in sponsor.circle.includedPeerIDs) { + NSError *error = [self considerCandidateID:candidateID + withSponsor:sponsor + toExpandIncludedPeerIDs:includedPeerIDs + andExcludedPeerIDs:excludedPeerIDs + forEpoch:epoch]; + if (nil != error) { + return error; + } + } + return [self considerVouchersSponsoredByPeer:sponsor + toReecursivelyExpandIncludedPeerIDs:includedPeerIDs + andExcludedPeerIDs:excludedPeerIDs + forEpoch:epoch]; +} + +- (TPPeerDynamicInfo *)calculateDynamicInfoForPeerWithID:(NSString *)peerID + addingPeerIDs:(NSArray *)addingPeerIDs + removingPeerIDs:(NSArray *)removingPeerIDs + createClique:(NSString* (^)())createClique + updatedCircle:(TPCircle **)updatedCircle + error:(NSError **)error +{ + TPPeer *peer = [self peerWithID:peerID]; + TPCounter epoch = peer.permanentInfo.epoch; + + // If we have dynamicInfo then we must know the corresponding circle. + NSAssert(nil != peer.circle || nil == peer.dynamicInfo, @"dynamicInfo without corresponding circle"); + + // If I am excluded by myself then make no changes. I am no longer playing the game. + // This is useful in the case where I have replaced myself with a new peer. + if ([peer.circle.excludedPeerIDs containsObject:peerID]) { + if (updatedCircle) { + *updatedCircle = peer.circle; + } + return peer.dynamicInfo; + } + + NSMutableSet *includedPeerIDs = [NSMutableSet setWithSet:peer.circle.includedPeerIDs]; + NSMutableSet *excludedPeerIDs = [NSMutableSet setWithSet:peer.circle.excludedPeerIDs]; + + // I trust myself by default, though this might be overridden by excludedPeerIDs + [includedPeerIDs addObject:peerID]; + + // The user has explictly told us to trust addingPeerIDs. + // This implies that the peers included in the circles of addingPeerIDs should also be trusted, + // as long epoch tests pass. This is regardless of whether trust policy says a member of addingPeerIDs + // can *introduce* a peer in its circle, because it isn't introducing it, the user already trusts it. + [includedPeerIDs addObjectsFromArray:addingPeerIDs]; + for (NSString *addingPeerID in addingPeerIDs) { + TPPeer *addingPeer = self.peersByID[addingPeerID]; + for (NSString *candidateID in addingPeer.circle.includedPeerIDs) { + TPPeer *candidate = self.peersByID[candidateID]; + if (candidate && [self canTrustCandidate:candidate.permanentInfo inEpoch:epoch]) { + [includedPeerIDs addObject:candidateID]; + } + } + } + + [excludedPeerIDs addObjectsFromArray:removingPeerIDs]; + [includedPeerIDs minusSet:excludedPeerIDs]; + + // We iterate over a copy because the loop will mutate includedPeerIDs + NSSet* sponsorIDs = [includedPeerIDs copy]; + + for (NSString *sponsorID in sponsorIDs) { + NSError *err = [self recursivelyExpandIncludedPeerIDs:includedPeerIDs + andExcludedPeerIDs:excludedPeerIDs + withPeersTrustedBySponsorID:sponsorID + forEpoch:epoch]; + if (nil != err) { + if (error) { + *error = err; + } + return nil; + } + } + NSError *err = [self considerVouchersSponsoredByPeer:peer + toReecursivelyExpandIncludedPeerIDs:includedPeerIDs + andExcludedPeerIDs:excludedPeerIDs + forEpoch:epoch]; + if (nil != err) { + if (error) { + *error = err; + } + return nil; + } + + [includedPeerIDs minusSet:excludedPeerIDs]; + + NSString *clique = [self bestCliqueAmongPeerIDs:includedPeerIDs]; + if (nil == clique) { + clique = peer.dynamicInfo.clique; + } + if (nil == clique && nil != createClique) { + clique = createClique(); + } + if (nil == clique) { + // Either nil == createClique or createClique returned nil. + // We would create a clique but caller has said not to. + // Not an error, it's just what they asked for. + if (error) { + *error = nil; + } + return nil; + } + + TPCircle *newCircle; + if ([excludedPeerIDs containsObject:peerID]) { + // I have been kicked out, and anybody who trusts me should now exclude me. + newCircle = [TPCircle circleWithIncludedPeerIDs:addingPeerIDs excludedPeerIDs:@[peerID]]; + } else { + // Drop items from excludedPeerIDs that predate epoch - 1 + NSSet *filteredExcluded = [excludedPeerIDs objectsPassingTest:^BOOL(NSString *exPeerID, BOOL *stop) { + TPPeer *exPeer = self.peersByID[exPeerID]; + if (nil == exPeer) { + return YES; + } + // If we could trust it then we have to keep it in the exclude list. + return [self canTrustCandidate:exPeer.permanentInfo inEpoch:epoch]; + }]; + newCircle = [TPCircle circleWithIncludedPeerIDs:[includedPeerIDs allObjects] + excludedPeerIDs:[filteredExcluded allObjects]]; + } + if (updatedCircle) { + *updatedCircle = newCircle; + } + return [self createDynamicInfoForPeerWithID:peerID + circle:newCircle + clique:clique + newRemovals:[removingPeerIDs count] + error:error]; +} + +- (NSString *)bestCliqueAmongPeerIDs:(NSSet*)peerIDs +{ + // The "best" clique is considered the one that is last in lexical ordering. + NSString *bestClique = nil; + for (NSString *peerID in peerIDs) { + NSString *clique = self.peersByID[peerID].dynamicInfo.clique; + if (clique) { + if (bestClique && NSOrderedAscending != [bestClique compare:clique]) { + continue; + } + bestClique = clique; + } + } + return bestClique; +} + +- (TPCircle *)advancePeerWithID:(NSString *)peerID + addingPeerIDs:(NSArray *)addingPeerIDs + removingPeerIDs:(NSArray *)removingPeerIDs + createClique:(NSString* (^)())createClique +{ + TPCircle *circle = nil; + TPPeerDynamicInfo *dyn; + dyn = [self calculateDynamicInfoForPeerWithID:peerID + addingPeerIDs:addingPeerIDs + removingPeerIDs:removingPeerIDs + createClique:createClique + updatedCircle:&circle + error:NULL]; + if (dyn) { + [self registerCircle:circle]; + [self updateDynamicInfo:dyn forPeerWithID:peerID]; + return circle; + } else { + return nil; + } +} + +NSString *TPErrorDomain = @"com.apple.security.trustedpeers"; + +enum { + TPErrorUnknownPolicyVersion = 1, + TPErrorPolicyHashMismatch = 2, + TPErrorMissingStableInfo = 3, +}; + + +- (nullable id)policyForPeerIDs:(NSSet *)peerIDs + error:(NSError **)error +{ + NSAssert(peerIDs.count > 0, @"policyForPeerIDs does not accept empty set"); + + TPPolicyDocument *newestPolicyDoc = nil; + + // This will become the union of policySecrets across the members of peerIDs + NSMutableDictionary *secrets = [NSMutableDictionary dictionary]; + + for (NSString *peerID in peerIDs) { + TPPeerStableInfo *stableInfo = [self peerWithID:peerID].stableInfo; + if (nil == stableInfo) { + // Allowing missing stableInfo here might be useful if we are writing a voucher + // for a peer for which we got permanentInfo over some channel that does not + // also convey stableInfo. + continue; + } + for (NSString *name in stableInfo.policySecrets) { + secrets[name] = stableInfo.policySecrets[name]; + } + if (newestPolicyDoc && newestPolicyDoc.policyVersion > stableInfo.policyVersion) { + continue; + } + TPPolicyDocument *policyDoc = self.policiesByVersion[@(stableInfo.policyVersion)]; + if (nil == policyDoc) { + if (error) { + *error = [NSError errorWithDomain:TPErrorDomain + code:TPErrorUnknownPolicyVersion + userInfo:@{ + @"peerID": peerID, + @"policyVersion": @(stableInfo.policyVersion) + }]; + } + return nil; + } + if (![policyDoc.policyHash isEqualToString:stableInfo.policyHash]) { + if (error) { + *error = [NSError errorWithDomain:TPErrorDomain + code:TPErrorPolicyHashMismatch + userInfo:@{ + @"peerID": peerID, + @"policyVersion": @(stableInfo.policyVersion), + @"policyDocHash": policyDoc.policyHash, + @"peerExpectsHash": stableInfo.policyHash + }]; + } + return nil; + } + newestPolicyDoc = policyDoc; + } + if (nil == newestPolicyDoc) { + // Can happen if no members of peerIDs have stableInfo + if (error) { + *error = [NSError errorWithDomain:TPErrorDomain + code:TPErrorMissingStableInfo + userInfo:nil]; + } + return nil; + } + return [newestPolicyDoc policyWithSecrets:secrets decrypter:self.decrypter error:error]; +} + +- (NSSet *)getPeerIDsTrustedByPeerWithID:(NSString *)peerID + toAccessView:(NSString *)view + error:(NSError **)error +{ + TPCircle *circle = [self peerWithID:peerID].circle; + NSMutableSet *peerIDs = [NSMutableSet set]; + + id policy = [self policyForPeerIDs:circle.includedPeerIDs error:error]; + + for (NSString *candidateID in circle.includedPeerIDs) { + TPPeer *candidate = self.peersByID[candidateID]; + if (candidate != nil) { + NSString *category = [policy categoryForModel:candidate.permanentInfo.modelID]; + if ([policy peerInCategory:category canAccessView:view]) { + [peerIDs addObject:candidateID]; + } + } + } + return peerIDs; +} + +- (NSDictionary *)vectorClock +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + + [self.peersByID enumerateKeysAndObjectsUsingBlock:^(NSString *peerID, TPPeer *peer, BOOL *stop) { + if (peer.stableInfo || peer.dynamicInfo) { + TPCounter clock = MAX(peer.stableInfo.clock, peer.dynamicInfo.clock); + dict[peerID] = @(clock); + } + }]; + return dict; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPPeer.h b/keychain/trust/TrustedPeers/TPPeer.h new file mode 100644 index 00000000..ae39c988 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPeer.h @@ -0,0 +1,68 @@ +/* + * 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 + +#import "TPHash.h" +#import "TPSigningKey.h" +#import "TPTypes.h" + +@class TPCircle; +@class TPVoucher; +@class TPPeerPermanentInfo; +@class TPPeerStableInfo; +@class TPPeerDynamicInfo; + +NS_ASSUME_NONNULL_BEGIN + +@interface TPPeer : NSObject + +@property (nonatomic, readonly) NSString* peerID; + +@property (nonatomic, readonly) TPPeerPermanentInfo* permanentInfo; +@property (nonatomic, readonly, nullable) TPPeerStableInfo* stableInfo; +@property (nonatomic, readonly, nullable) TPPeerDynamicInfo* dynamicInfo; +@property (nonatomic, strong) NSData* wrappedPrivateKeys; + +// setCircle asserts that circle.circleID == dynamicInfo.circleID +@property (nonatomic, strong, nullable) TPCircle* circle; + +@property (nonatomic, readonly) NSSet* trustedPeerIDs; + +- (instancetype)initWithPermanentInfo:(TPPeerPermanentInfo *)permanentInfo; + +- (TPResult)updateStableInfo:(TPPeerStableInfo *)stableInfo; + +// Returns YES on success, or NO if: +// - the data or signature is invalid +// - this update makes a change without advancing dynamicInfo.clock +// +// An "update" with unchanged data is considered success. +// +// This call also sets self.circle to nil. +// The caller should subsequently call updateCircle to update it. +- (TPResult)updateDynamicInfo:(TPPeerDynamicInfo *)dynamicInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPPeer.m b/keychain/trust/TrustedPeers/TPPeer.m new file mode 100644 index 00000000..c2e67065 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPeer.m @@ -0,0 +1,108 @@ +/* + * 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 "TPPeer.h" +#import "TPPeerPermanentInfo.h" +#import "TPPeerStableInfo.h" +#import "TPPeerDynamicInfo.h" +#import "TPCircle.h" +#import "TPVoucher.h" + +@interface TPPeer () + +@property (nonatomic, strong) TPPeerPermanentInfo* permanentInfo; +@property (nonatomic, strong) TPPeerStableInfo* stableInfo; +@property (nonatomic, strong) TPPeerDynamicInfo* dynamicInfo; + +@end + + +@implementation TPPeer + +- (NSString *)peerID +{ + return self.permanentInfo.peerID; +} + +- (instancetype)initWithPermanentInfo:(TPPeerPermanentInfo *)permanentInfo +{ + self = [super init]; + if (self) { + _permanentInfo = permanentInfo; + } + return self; +} + +- (TPResult)updateStableInfo:(TPPeerStableInfo *)stableInfo +{ + if (![self.permanentInfo.trustSigningKey checkSignature:stableInfo.stableInfoSig + matchesData:stableInfo.stableInfoPList]) { + return TPResultSignatureMismatch; + } + if ([self.stableInfo isEqualToPeerStableInfo:stableInfo]) { + return TPResultOk; + } + if (self.stableInfo != nil && stableInfo.clock <= self.stableInfo.clock) { + return TPResultClockViolation; + } + self.stableInfo = stableInfo; + return TPResultOk; +} + +- (TPResult)updateDynamicInfo:(TPPeerDynamicInfo *)dynamicInfo +{ + if (![self.permanentInfo.trustSigningKey checkSignature:dynamicInfo.dynamicInfoSig + matchesData:dynamicInfo.dynamicInfoPList]) { + return TPResultSignatureMismatch; + } + if ([self.dynamicInfo isEqualToPeerDynamicInfo:dynamicInfo]) { + return TPResultOk; + } + if (self.dynamicInfo != nil && dynamicInfo.clock <= self.dynamicInfo.clock) { + return TPResultClockViolation; + } + self.dynamicInfo = dynamicInfo; + self.circle = nil; + return TPResultOk; +} + +- (void)setCircle:(TPCircle *)circle +{ + if (nil != circle) { + NSAssert([circle.circleID isEqualToString:self.dynamicInfo.circleID], + @"circle property must match dynamicInfo.circleID"); + } + _circle = circle; +} + +- (NSSet *)trustedPeerIDs +{ + if (self.dynamicInfo) { + NSAssert(self.circle, @"dynamicInfo needs corresponding circle"); + return self.circle.includedPeerIDs; + } else { + return [NSSet setWithObject:self.peerID]; + } +} + +@end diff --git a/keychain/trust/TrustedPeers/TPPeerDynamicInfo.h b/keychain/trust/TrustedPeers/TPPeerDynamicInfo.h new file mode 100644 index 00000000..85b52d72 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPeerDynamicInfo.h @@ -0,0 +1,67 @@ +/* + * 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 + +#import "TPTypes.h" +#import "TPSigningKey.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! + Having an instance of this class does *not* mean that + its signature has been checked. Checking the signature + is up to whoever consumes it. + + This class is a value type -- its members are immutable and + instances with identical contents are interchangeable. + */ +@interface TPPeerDynamicInfo : NSObject + +/*! + Can return nil with error if [trustSigningKey signatureForData:error:] errors. + */ ++ (nullable instancetype)dynamicInfoWithCircleID:(NSString *)circleID + clique:(NSString *)clique + removals:(TPCounter)removals + clock:(TPCounter)clock + trustSigningKey:(id)trustSigningKey + error:(NSError **)error; + +// Returns nil if data cannot be deserialized to a dictionary +// or that dictionary does not contain the expected keys and value types. ++ (nullable instancetype)dynamicInfoWithPListData:(NSData *)dynamicInfoPList + dynamicInfoSig:(NSData *)dynamicInfoSig; + +- (BOOL)isEqualToPeerDynamicInfo:(TPPeerDynamicInfo *)other; + +@property (nonatomic, readonly) NSString *circleID; +@property (nonatomic, readonly) NSString *clique; +@property (nonatomic, readonly) TPCounter removals; +@property (nonatomic, readonly) TPCounter clock; +@property (nonatomic, readonly) NSData *dynamicInfoPList; +@property (nonatomic, readonly) NSData *dynamicInfoSig; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPPeerDynamicInfo.m b/keychain/trust/TrustedPeers/TPPeerDynamicInfo.m new file mode 100644 index 00000000..68399f35 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPeerDynamicInfo.m @@ -0,0 +1,131 @@ +/* + * 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 "TPPeerDynamicInfo.h" +#import "TPUtils.h" + +static const NSString *kCircleID = @"circleID"; +static const NSString *kClique = @"clique"; +static const NSString *kRemovals = @"removals"; +static const NSString *kClock = @"clock"; + + +@interface TPPeerDynamicInfo () + +@property (nonatomic, strong) NSString *circleID; +@property (nonatomic, strong) NSString *clique; +@property (nonatomic, assign) TPCounter removals; +@property (nonatomic, assign) TPCounter clock; +@property (nonatomic, strong) NSData *dynamicInfoPList; +@property (nonatomic, strong) NSData *dynamicInfoSig; + +@end + + +@implementation TPPeerDynamicInfo + ++ (instancetype)dynamicInfoWithCircleID:(NSString *)circleID + clique:(NSString *)clique + removals:(TPCounter)removals + clock:(TPCounter)clock + trustSigningKey:(id)trustSigningKey + error:(NSError **)error +{ + NSDictionary *dict = @{ + kCircleID: circleID, + kClique: clique, + kRemovals: @(removals), + kClock: @(clock) + }; + NSData *data = [TPUtils serializedPListWithDictionary:dict]; + NSData *sig = [trustSigningKey signatureForData:data withError:error]; + if (nil == sig) { + return nil; + } + TPPeerDynamicInfo* info = [self dynamicInfoWithPListData:data dynamicInfoSig:sig]; + assert(info); + return info; +} + ++ (instancetype)dynamicInfoWithPListData:(NSData *)dynamicInfoPList + dynamicInfoSig:(NSData *)dynamicInfoSig +{ + id dict = [NSPropertyListSerialization propertyListWithData:dynamicInfoPList + options:NSPropertyListImmutable + format:nil + error:NULL]; + if (![dict isKindOfClass:[NSDictionary class]]) { + return nil; + } + + TPPeerDynamicInfo* info = [[TPPeerDynamicInfo alloc] init]; + + if (![dict[kCircleID] isKindOfClass:[NSString class]]) { + return nil; + } + info.circleID = dict[kCircleID]; + + if (![dict[kClique] isKindOfClass:[NSString class]]) { + return nil; + } + info.clique = dict[kClique]; + + if (![dict[kRemovals] isKindOfClass:[NSNumber class]]) { + return nil; + } + info.removals = [dict[kRemovals] unsignedLongLongValue]; + + if (![dict[kClock] isKindOfClass:[NSNumber class]]) { + return nil; + } + info.clock = [dict[kClock] unsignedLongLongValue]; + + info.dynamicInfoPList = [dynamicInfoPList copy]; + info.dynamicInfoSig = [dynamicInfoSig copy]; + + return info; +} + +- (BOOL)isEqualToPeerDynamicInfo:(TPPeerDynamicInfo *)other +{ + if (other == self) { + return YES; + } + return [self.dynamicInfoPList isEqualToData:other.dynamicInfoPList] + && [self.dynamicInfoSig isEqualToData:other.dynamicInfoSig]; +} + +#pragma mark - NSObject + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[TPPeerDynamicInfo class]]) { + return NO; + } + return [self isEqualToPeerDynamicInfo:object]; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPPeerPermanentInfo.h b/keychain/trust/TrustedPeers/TPPeerPermanentInfo.h new file mode 100644 index 00000000..3af2cc2c --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPeerPermanentInfo.h @@ -0,0 +1,68 @@ +/* + * 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 + +#import "TPTypes.h" +#import "TPSigningKey.h" +#import "TPHash.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! + This class is a value type -- its members are immutable and + instances with identical contents are interchangeable. + */ +@interface TPPeerPermanentInfo : NSObject + +/*! + Can return nil with error if [trustSigningKey signatureForData:error:] errors. + */ ++ (nullable instancetype)permanentInfoWithMachineID:(NSString *)machineID + modelID:(NSString *)modelID + epoch:(TPCounter)epoch + trustSigningKey:(id)trustSigningKey + peerIDHashAlgo:(TPHashAlgo)peerIDHashAlgo + error:(NSError **)error; + +// Returns nil if: +// - permanentInfoPList cannot be deserialized to a dictionary +// - that dictionary does not contain the expected keys and value types +// - permanentInfoSig does not match permanentInfoPList signed with the trustSigningKey from the dictionary +// - peerID does not match the hash of (permanentInfoPList + permanentInfoSig) ++ (nullable instancetype)permanentInfoWithPeerID:(NSString *)peerID + permanentInfoPList:(NSData *)permanentInfoPList + permanentInfoSig:(NSData *)permanentInfoSig + keyFactory:(id)keyFactory; + +@property (nonatomic, readonly) NSString* machineID; +@property (nonatomic, readonly) NSString* modelID; +@property (nonatomic, readonly) TPCounter epoch; +@property (nonatomic, readonly) id trustSigningKey; +@property (nonatomic, readonly) NSData *permanentInfoPList; +@property (nonatomic, readonly) NSData *permanentInfoSig; +@property (nonatomic, readonly) NSString *peerID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPPeerPermanentInfo.m b/keychain/trust/TrustedPeers/TPPeerPermanentInfo.m new file mode 100644 index 00000000..70672e28 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPeerPermanentInfo.m @@ -0,0 +1,151 @@ +/* + * 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 "TPPeerPermanentInfo.h" +#import "TPUtils.h" + +static const NSString *kMachineID = @"machineID"; +static const NSString *kModelID = @"modelID"; +static const NSString *kEpoch = @"epoch"; +static const NSString *kTrustSigningKey = @"trustSigningKey"; + + +@interface TPPeerPermanentInfo () + +@property (nonatomic, strong) NSString* machineID; +@property (nonatomic, strong) NSString* modelID; +@property (nonatomic, assign) TPCounter epoch; +@property (nonatomic, strong) id trustSigningKey; +@property (nonatomic, strong) NSData *permanentInfoPList; +@property (nonatomic, strong) NSData *permanentInfoSig; +@property (nonatomic, strong) NSString *peerID; + +@end + + +@implementation TPPeerPermanentInfo + ++ (instancetype)permanentInfoWithMachineID:(NSString *)machineID + modelID:(NSString *)modelID + epoch:(TPCounter)epoch + trustSigningKey:(id)trustSigningKey + peerIDHashAlgo:(TPHashAlgo)peerIDHashAlgo + error:(NSError **)error +{ + TPPeerPermanentInfo* info = [[TPPeerPermanentInfo alloc] init]; + info.machineID = [machineID copy]; + info.modelID = [modelID copy]; + info.epoch = epoch; + info.trustSigningKey = trustSigningKey; + + NSDictionary *dict = @{ + kMachineID: machineID, + kModelID: modelID, + kEpoch: @(epoch), + kTrustSigningKey: [trustSigningKey publicKey] + }; + NSData *data = [TPUtils serializedPListWithDictionary:dict]; + NSData *sig = [trustSigningKey signatureForData:data withError:error]; + if (nil == sig) { + return nil; + } + info.permanentInfoPList = data; + info.permanentInfoSig = sig; + info.peerID = [TPPeerPermanentInfo peerIDForPermanentInfoPList:data + permanentInfoSig:sig + peerIDHashAlgo:peerIDHashAlgo]; + return info; +} + ++ (NSString *)peerIDForPermanentInfoPList:(NSData *)permanentInfoPList + permanentInfoSig:(NSData *)permanentInfoSig + peerIDHashAlgo:(TPHashAlgo)peerIDHashAlgo + +{ + TPHashBuilder *hasher = [[TPHashBuilder alloc] initWithAlgo:peerIDHashAlgo]; + [hasher updateWithData:permanentInfoPList]; + [hasher updateWithData:permanentInfoSig]; + return [hasher finalHash]; +} + ++ (instancetype)permanentInfoWithPeerID:(NSString *)peerID + permanentInfoPList:(NSData *)permanentInfoPList + permanentInfoSig:(NSData *)permanentInfoSig + keyFactory:(id)keyFactory +{ + id obj = [NSPropertyListSerialization propertyListWithData:permanentInfoPList + options:NSPropertyListImmutable + format:nil + error:NULL]; + if (![obj isKindOfClass:[NSDictionary class]]) { + return nil; + } + NSDictionary *dict = obj; + + TPPeerPermanentInfo *info = [[TPPeerPermanentInfo alloc] init]; + info.peerID = peerID; + info.permanentInfoPList = permanentInfoPList; + info.permanentInfoSig = permanentInfoSig; + + if (![dict[kMachineID] isKindOfClass:[NSString class]]) { + return nil; + } + info.machineID = dict[kMachineID]; + + if (![dict[kModelID] isKindOfClass:[NSString class]]) { + return nil; + } + info.modelID = dict[kModelID]; + + if (![dict[kEpoch] isKindOfClass:[NSNumber class]]) { + return nil; + } + info.epoch = [dict[kEpoch] unsignedLongLongValue]; + + if (![dict[kTrustSigningKey] isKindOfClass:[NSData class]]) { + return nil; + } + info.trustSigningKey = [keyFactory keyWithPublicKeyData:dict[kTrustSigningKey]]; + if (nil == info.trustSigningKey) { + return nil; + } + if (![info.trustSigningKey checkSignature:permanentInfoSig matchesData:permanentInfoPList]) { + return nil; + } + + // check peerID is hash of (permanentInfoPList + permanentInfoSig) + TPHashAlgo algo = [TPHashBuilder algoOfHash:peerID]; + if (algo == kTPHashAlgoUnknown) { + return nil; + } + NSString* checkHash = [TPPeerPermanentInfo peerIDForPermanentInfoPList:info.permanentInfoPList + permanentInfoSig:info.permanentInfoSig + peerIDHashAlgo:algo]; + if (![checkHash isEqualToString:peerID]) { + return nil; + } + + return info; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPPeerStableInfo.h b/keychain/trust/TrustedPeers/TPPeerStableInfo.h new file mode 100644 index 00000000..4c15b304 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPeerStableInfo.h @@ -0,0 +1,68 @@ +/* + * 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 + +#import "TPTypes.h" +#import "TPSigningKey.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! + Having an instance of this class does *not* mean that + its signature has been checked. Checking the signature + is up to whoever consumes it. + + This class is a value type -- its members are immutable and + instances with identical contents are interchangeable. + */ +@interface TPPeerStableInfo : NSObject + +/*! + Can return nil with error if [trustSigningKey signatureForData:error:] errors. + */ ++ (nullable instancetype)stableInfoWithDict:(NSDictionary *)dict + clock:(TPCounter)clock + policyVersion:(TPCounter)policyVersion + policyHash:(NSString *)policyHash + policySecrets:(nullable NSDictionary *)policySecrets + trustSigningKey:(id)trustSigningKey + error:(NSError **)error; + +// Returns nil if data cannot be deserialized to a dictionary ++ (nullable instancetype)stableInfoWithPListData:(NSData *)stableInfoPList + stableInfoSig:(NSData *)stableInfoSig; + +- (BOOL)isEqualToPeerStableInfo:(TPPeerStableInfo *)other; + +@property (nonatomic, readonly) NSDictionary *dict; +@property (nonatomic, readonly) TPCounter clock; +@property (nonatomic, readonly) TPCounter policyVersion; +@property (nonatomic, readonly) NSString *policyHash; +@property (nonatomic, readonly) NSDictionary *policySecrets; +@property (nonatomic, readonly) NSData *stableInfoPList; +@property (nonatomic, readonly) NSData *stableInfoSig; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPPeerStableInfo.m b/keychain/trust/TrustedPeers/TPPeerStableInfo.m new file mode 100644 index 00000000..9895f146 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPeerStableInfo.m @@ -0,0 +1,144 @@ +/* + * 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 "TPPeerStableInfo.h" +#import "TPUtils.h" + +static const NSString *kClock = @"clock"; +static const NSString *kPolicyVersion = @"policyVersion"; +static const NSString *kPolicyHash = @"policyHash"; +static const NSString *kPolicySecrets = @"policySecrets"; + + +@interface TPPeerStableInfo () + +@property (nonatomic, strong) NSDictionary *dict; +@property (nonatomic, assign) TPCounter clock; +@property (nonatomic, assign) TPCounter policyVersion; +@property (nonatomic, strong) NSString *policyHash; +@property (nonatomic, strong) NSDictionary *policySecrets; +@property (nonatomic, strong) NSData *stableInfoPList; +@property (nonatomic, strong) NSData *stableInfoSig; + +@end + + +@implementation TPPeerStableInfo + ++ (instancetype)stableInfoWithDict:(NSDictionary *)dict + clock:(TPCounter)clock + policyVersion:(TPCounter)policyVersion + policyHash:(NSString *)policyHash + policySecrets:(NSDictionary *)policySecrets + trustSigningKey:(id)trustSigningKey + error:(NSError **)error +{ + NSMutableDictionary *mutDict = [NSMutableDictionary dictionaryWithDictionary:dict]; + mutDict[kClock] = @(clock); + mutDict[kPolicyVersion] = @(policyVersion); + mutDict[kPolicyHash] = policyHash; + mutDict[kPolicySecrets] = policySecrets; + + NSData *data = [TPUtils serializedPListWithDictionary:mutDict]; + NSData *sig = [trustSigningKey signatureForData:data withError:error]; + if (nil == sig) { + return nil; + } + TPPeerStableInfo *info = [self stableInfoWithPListData:data stableInfoSig:sig];; + assert(info); + return info; +} + ++ (instancetype)stableInfoWithPListData:(NSData *)stableInfoPList + stableInfoSig:(NSData *)stableInfoSig +{ + id dict = [NSPropertyListSerialization propertyListWithData:stableInfoPList + options:NSPropertyListImmutable + format:nil + error:NULL]; + if (![dict isKindOfClass:[NSDictionary class]]) { + return nil; + } + + TPPeerStableInfo* info = [[TPPeerStableInfo alloc] init]; + + if (![dict[kClock] isKindOfClass:[NSNumber class]]) { + return nil; + } + info.clock = [dict[kClock] unsignedLongLongValue]; + + if (![dict[kPolicyVersion] isKindOfClass:[NSNumber class]]) { + return nil; + } + info.policyVersion = [dict[kPolicyVersion] unsignedLongLongValue]; + + if (![dict[kPolicyHash] isKindOfClass:[NSString class]]) { + return nil; + } + info.policyHash = dict[kPolicyHash]; + + if ([dict[kPolicySecrets] isKindOfClass:[NSDictionary class]]) { + NSDictionary *secrets = dict[kPolicySecrets]; + for (id name in secrets) { + NSAssert([name isKindOfClass:[NSString class]], @"plist keys must be strings"); + if (![secrets[name] isKindOfClass:[NSData class]]) { + return nil; + } + } + info.policySecrets = secrets; + } else if (nil == dict[kPolicySecrets]) { + info.policySecrets = @{}; + } else { + return nil; + } + + info.dict = dict; + info.stableInfoPList = [stableInfoPList copy]; + info.stableInfoSig = [stableInfoSig copy]; + + return info; +} + +- (BOOL)isEqualToPeerStableInfo:(TPPeerStableInfo *)other +{ + if (other == self) { + return YES; + } + return [self.stableInfoPList isEqualToData:other.stableInfoPList] + && [self.stableInfoSig isEqualToData:other.stableInfoSig]; +} + +#pragma mark - NSObject + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[TPPeerStableInfo class]]) { + return NO; + } + return [self isEqualToPeerStableInfo:object]; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPPolicy.h b/keychain/trust/TrustedPeers/TPPolicy.h new file mode 100644 index 00000000..673cf478 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPolicy.h @@ -0,0 +1,55 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@class TPCategoryRule; + +/*! + TPPolicy represents the ability to calculate Octagon Policy, as per + https://confluence.sd.apple.com/display/KEY/Octagon+Policy + + Instances of this class are typically obtained from TPPolicyDocument, + by passing a (possibly empty) dictionary of secrets to + policyWithSecrets:decrypter:error:. +*/ +@protocol TPPolicy + +- (nullable NSString *)categoryForModel:(NSString *)model; +- (BOOL)trustedPeerInCategory:(NSString *)trustedCategory canIntroduceCategory:(NSString *)candidateCategory; +- (BOOL)peerInCategory:(NSString *)category canAccessView:(NSString *)view; + +@end + + +@interface TPPolicy : NSObject + ++ (instancetype)policyWithModelToCategory:(NSArray *)modelToCategory + categoriesByView:(NSDictionary*> *)categoriesByView + introducersByCategory:(NSDictionary*> *)introducersByCategory; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPPolicy.m b/keychain/trust/TrustedPeers/TPPolicy.m new file mode 100644 index 00000000..72b67648 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPolicy.m @@ -0,0 +1,70 @@ +/* + * 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 "TPPolicy.h" +#import "TPCategoryRule.h" + + +@interface TPPolicy () + +@property (nonatomic, strong) NSArray *modelToCategory; +@property (nonatomic, strong) NSDictionary*> *categoriesByView; +@property (nonatomic, strong) NSDictionary*> *introducersByCategory; + +@end + + +@implementation TPPolicy + ++ (instancetype)policyWithModelToCategory:(NSArray *)modelToCategory + categoriesByView:(NSDictionary*> *)categoriesByView + introducersByCategory:(NSDictionary*> *)introducersByCategory +{ + TPPolicy *policy = [[TPPolicy alloc] init]; + policy.modelToCategory = [modelToCategory copy]; + policy.categoriesByView = [categoriesByView copy]; + policy.introducersByCategory = [introducersByCategory copy]; + return policy; +} + +- (nullable NSString *)categoryForModel:(NSString *)model +{ + for (TPCategoryRule *rule in self.modelToCategory) { + if ([model hasPrefix:rule.prefix]) { + return rule.category; + } + } + return nil; +} + +- (BOOL)trustedPeerInCategory:(NSString *)trustedCategory canIntroduceCategory:(NSString *)candidateCategory +{ + return [self.introducersByCategory[candidateCategory] containsObject:trustedCategory]; +} + +- (BOOL)peerInCategory:(NSString *)category canAccessView:(NSString *)view +{ + return [self.categoriesByView[view] containsObject:category]; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPPolicyDocument.h b/keychain/trust/TrustedPeers/TPPolicyDocument.h new file mode 100644 index 00000000..aa9359ba --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPolicyDocument.h @@ -0,0 +1,68 @@ +/* + * 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 + +#import "TPPolicy.h" +#import "TPEncrypter.h" +#import "TPDecrypter.h" +#import "TPHash.h" +#import "TPTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! + This class is a value type -- its members are immutable and + instances with identical contents are interchangeable. + */ +@interface TPPolicyDocument : NSObject + +@property (nonatomic, readonly) TPCounter policyVersion; +@property (nonatomic, readonly) NSString *policyHash; +@property (nonatomic, readonly) NSData *pList; + ++ (nullable instancetype)policyDocWithHash:(NSString *)policyHash + pList:(NSData *)pList; + ++ (instancetype)policyDocWithVersion:(TPCounter)policyVersion + modelToCategory:(NSArray *)modelToCategory + categoriesByView:(NSDictionary*> *)categoriesByView + introducersByCategory:(NSDictionary*> *)introducersByCategory + redactions:(NSDictionary *)redactions + hashAlgo:(TPHashAlgo)hashAlgo; + ++ (nullable NSData *)redactionWithEncrypter:(id)encrypter + modelToCategory:(nullable NSArray *)modelToCategory + categoriesByView:(nullable NSDictionary*> *)categoriesByView + introducersByCategory:(nullable NSDictionary*> *)introducersByCategory + error:(NSError **)error; + +- (nullable id)policyWithSecrets:(NSDictionary *)secrets + decrypter:(id)decrypter + error:(NSError **)error; + +- (BOOL)isEqualToPolicyDocument:(TPPolicyDocument *)other; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPPolicyDocument.m b/keychain/trust/TrustedPeers/TPPolicyDocument.m new file mode 100644 index 00000000..a1c72c8e --- /dev/null +++ b/keychain/trust/TrustedPeers/TPPolicyDocument.m @@ -0,0 +1,335 @@ +/* + * 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 "TPPolicyDocument.h" +#import "TPPolicy.h" +#import "TPUtils.h" +#import "TPCategoryRule.h" + +static const NSString *kPolicyVersion = @"policyVersion"; +static const NSString *kModelToCategory = @"modelToCategory"; +static const NSString *kCategoriesByView = @"categoriesByView"; +static const NSString *kIntroducersByCategory = @"introducersByCategory"; +static const NSString *kRedactions = @"redactions"; +static const NSString *kPrefix = @"prefix"; +static const NSString *kCategory = @"category"; + +@interface TPPolicyDocument () + +@property (nonatomic, assign) TPCounter policyVersion; +@property (nonatomic, strong) NSString *policyHash; +@property (nonatomic, strong) NSData *pList; + +@property (nonatomic, strong) NSArray *modelToCategory; +@property (nonatomic, strong) NSDictionary*> *categoriesByView; +@property (nonatomic, strong) NSDictionary*> *introducersByCategory; +@property (nonatomic, strong) NSDictionary *redactions; + +@end + + +@implementation TPPolicyDocument + ++ (nullable NSArray *)modelToCategoryFromObj:(id)obj +{ + if (![obj isKindOfClass:[NSArray class]]) { + return nil; + } + NSArray *arr = obj; + NSMutableArray *rules = [[NSMutableArray alloc] initWithCapacity:arr.count]; + for (id item in arr) { + TPCategoryRule *rule = [self categoryRuleFromObj:item]; + if (nil == rule) { + return nil; + } + [rules addObject:rule]; + } + return rules; +} + ++ (nullable TPCategoryRule *)categoryRuleFromObj:(id)obj +{ + if (![obj isKindOfClass:[NSDictionary class]]) { + return nil; + } + NSDictionary *dict = obj; + if (![dict[kPrefix] isKindOfClass:[NSString class]]) { + return nil; + } + if (![dict[kCategory] isKindOfClass:[NSString class]]) { + return nil; + } + return [TPCategoryRule ruleWithPrefix:dict[kPrefix] category:dict[kCategory]]; +} + +// Used for parsing categoriesByView and introducersByCategory +// which both have the same structure. ++ (nullable NSDictionary*> *)dictionaryOfSetsFromObj:(id)obj +{ + if (![obj isKindOfClass:[NSDictionary class]]) { + return nil; + } + NSDictionary *dict = obj; + NSMutableDictionary*> *result = [NSMutableDictionary dictionary]; + for (id key in dict) { + if (![key isKindOfClass:[NSString class]]) { + return nil; + } + id value = dict[key]; + if (![value isKindOfClass:[NSArray class]]) { + return nil; + } + NSArray *arr = value; + for (id item in arr) { + if (![item isKindOfClass:[NSString class]]) { + return nil; + } + } + result[key] = [NSSet setWithArray:arr]; + } + return result; +} + ++ (nullable NSDictionary *)redactionsFromObj:(id)obj +{ + if (![obj isKindOfClass:[NSDictionary class]]) { + return nil; + } + NSDictionary *dict = obj; + for (id key in dict) { + if (![key isKindOfClass:[NSString class]]) { + return nil; + } + id value = dict[key]; + if (![value isKindOfClass:[NSData class]]) { + return nil; + } + } + return dict; +} + ++ (nullable instancetype)policyDocWithHash:(NSString *)policyHash + pList:(NSData *)pList +{ + TPHashAlgo algo = [TPHashBuilder algoOfHash:policyHash]; + NSString *hash = [TPHashBuilder hashWithAlgo:algo ofData:pList]; + if (![policyHash isEqualToString:hash]) { + return nil; + } + TPPolicyDocument *doc = [[TPPolicyDocument alloc] init]; + doc.policyHash = hash; + doc.pList = pList; + + id obj = [NSPropertyListSerialization propertyListWithData:pList + options:NSPropertyListImmutable + format:nil + error:NULL]; + if (![obj isKindOfClass:[NSDictionary class]]) { + return nil; + } + NSDictionary *dict = obj; + + if (![dict[kPolicyVersion] isKindOfClass:[NSNumber class]]) { + return nil; + } + doc.policyVersion = [dict[kPolicyVersion] unsignedLongLongValue]; + + doc.modelToCategory = [self modelToCategoryFromObj:dict[kModelToCategory]]; + if (nil == doc.modelToCategory) { + return nil; + } + doc.categoriesByView = [self dictionaryOfSetsFromObj:dict[kCategoriesByView]]; + if (nil == doc.categoriesByView) { + return nil; + } + doc.introducersByCategory = [self dictionaryOfSetsFromObj:dict[kIntroducersByCategory]]; + if (nil == doc.introducersByCategory) { + return nil; + } + doc.redactions = [self redactionsFromObj:dict[kRedactions]]; + if (nil == doc.redactions) { + return nil; + } + return doc; +} + ++ (instancetype)policyDocWithVersion:(TPCounter)policyVersion + modelToCategory:(NSArray *)modelToCategory + categoriesByView:(NSDictionary*> *)categoriesByView + introducersByCategory:(NSDictionary*> *)introducersByCategory + redactions:(NSDictionary *)redactions + hashAlgo:(TPHashAlgo)hashAlgo +{ + TPPolicyDocument *doc = [[TPPolicyDocument alloc] init]; + + doc.policyVersion = policyVersion; + + doc.modelToCategory = [TPPolicyDocument modelToCategoryFromObj:modelToCategory]; + NSAssert(doc.modelToCategory, @"malformed modelToCategory"); + + doc.categoriesByView = [TPPolicyDocument dictionaryOfSetsFromObj:categoriesByView]; + NSAssert(doc.categoriesByView, @"malformed categoriesByView"); + + doc.introducersByCategory = [TPPolicyDocument dictionaryOfSetsFromObj:introducersByCategory]; + NSAssert(doc.introducersByCategory, @"malformed introducersByCategory"); + + doc.redactions = [redactions copy]; + + NSDictionary *dict = @{ + kPolicyVersion: @(policyVersion), + kModelToCategory: modelToCategory, + kCategoriesByView: categoriesByView, + kIntroducersByCategory: introducersByCategory, + kRedactions: redactions + }; + doc.pList = [TPUtils serializedPListWithDictionary:dict]; + doc.policyHash = [TPHashBuilder hashWithAlgo:hashAlgo ofData:doc.pList]; + + return doc; +} + ++ (nullable NSData *)redactionWithEncrypter:(id)encrypter + modelToCategory:(nullable NSArray *)modelToCategory + categoriesByView:(nullable NSDictionary*> *)categoriesByView + introducersByCategory:(nullable NSDictionary*> *)introducersByCategory + error:(NSError **)error +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (nil != modelToCategory) { + dict[kModelToCategory] = modelToCategory; + } + if (nil != categoriesByView) { + dict[kCategoriesByView] = categoriesByView; + } + if (nil != introducersByCategory) { + dict[kIntroducersByCategory] = introducersByCategory; + } + NSData *plist = [TPUtils serializedPListWithDictionary:dict]; + return [encrypter encryptData:plist error:error]; +} + +- (id)policyWithSecrets:(NSDictionary *)secrets + decrypter:(id)decrypter + error:(NSError **)error +{ + NSArray *modelToCategory = self.modelToCategory; + NSMutableDictionary*> *categoriesByView + = [NSMutableDictionary dictionaryWithDictionary:self.categoriesByView]; + NSMutableDictionary*> *introducersByCategory + = [NSMutableDictionary dictionaryWithDictionary:self.introducersByCategory]; + + // We are going to prepend extra items to modelToCategory. + // To make the resulting array order deterministic we sort secrets by name first. + NSArray *names = [secrets.allKeys sortedArrayUsingSelector:@selector(compare:)]; + for (NSString *name in names) { + NSData *key = secrets[name]; + NSData *ciphertext = self.redactions[name]; + if (nil == ciphertext) { + // This is normal. A new version might have no need to redact + // info that was revealed by keys for a previous version. + continue; + } + NSData *plist = [decrypter decryptData:ciphertext withKey:key error:error]; + if (nil == plist) { + return nil; + } + id obj = [NSPropertyListSerialization propertyListWithData:plist + options:NSPropertyListImmutable + format:nil + error:NULL]; + if (![obj isKindOfClass:[NSDictionary class]]) { + return nil; + } + NSDictionary *dict = obj; + + NSArray *extraModelToCategory; + extraModelToCategory = [TPPolicyDocument modelToCategoryFromObj:dict[kModelToCategory]]; + if (nil != extraModelToCategory) { + // Extra rules are prepended to the list so that they are considered first. + modelToCategory = [extraModelToCategory arrayByAddingObjectsFromArray:modelToCategory]; + } + + NSDictionary*> *extraCategoriesByView; + extraCategoriesByView = [TPPolicyDocument dictionaryOfSetsFromObj:dict[kCategoriesByView]]; + if (nil != extraCategoriesByView) { + [self mergeExtras:extraCategoriesByView intoDictionary:categoriesByView]; + } + + NSDictionary*> *extraIntroducersByCategory; + extraIntroducersByCategory = [TPPolicyDocument dictionaryOfSetsFromObj:dict[kIntroducersByCategory]]; + if (nil != extraIntroducersByCategory) { + [self mergeExtras:extraIntroducersByCategory intoDictionary:introducersByCategory]; + } + } + + return [TPPolicy policyWithModelToCategory:modelToCategory + categoriesByView:categoriesByView + introducersByCategory:introducersByCategory]; +} + +- (void)mergeExtras:(NSDictionary*> *)extras + intoDictionary:(NSMutableDictionary*> *)target +{ + for (NSString *name in extras) { + NSSet* extraSet = extras[name]; + if (target[name] == nil) { + target[name] = extraSet; + } else { + target[name] = [target[name] setByAddingObjectsFromSet:extraSet]; + } + } +} + +- (BOOL)isEqualToPolicyDocument:(TPPolicyDocument *)other +{ + if (other == self) { + return YES; + } + return self.policyVersion == other.policyVersion + && [self.policyHash isEqualToString:other.policyHash] + && [self.pList isEqualToData:other.pList] + && [self.modelToCategory isEqualToArray:other.modelToCategory] + && [self.categoriesByView isEqualToDictionary:other.categoriesByView] + && [self.introducersByCategory isEqualToDictionary:other.introducersByCategory] + && [self.redactions isEqualToDictionary:other.redactions]; +} + +#pragma mark - NSObject + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[TPPolicyDocument class]]) { + return NO; + } + return [self isEqualToPolicyDocument:object]; +} + +- (NSUInteger)hash +{ + return [self.policyHash hash]; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPSigningKey.h b/keychain/trust/TrustedPeers/TPSigningKey.h new file mode 100644 index 00000000..a45159e8 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPSigningKey.h @@ -0,0 +1,52 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +/*! + A protocol for signing blobs and checking signatures. + */ +@protocol TPSigningKey +- (NSData *)publicKey; +- (BOOL)checkSignature:(NSData *)sig matchesData:(NSData *)data; + +/*! + This method uses the private key to create a signature. + It will return nil with an error if the private key is not available, + e.g. due to the device being locked. + */ +- (nullable NSData *)signatureForData:(NSData *)data withError:(NSError **)error; +@end + + +/*! + A protocol for factories that construct TPSigningKey objects. + */ +@protocol TPSigningKeyFactory +// Return nil if data is malformed +- (nullable id )keyWithPublicKeyData:(NSData *)publicKey; +@end + +NS_ASSUME_NONNULL_END diff --git a/OSX/libsecurity_codesigning/lib/SecIntegrityLib.c b/keychain/trust/TrustedPeers/TPTypes.h similarity index 80% rename from OSX/libsecurity_codesigning/lib/SecIntegrityLib.c rename to keychain/trust/TrustedPeers/TPTypes.h index 17b1825a..14893c59 100644 --- a/OSX/libsecurity_codesigning/lib/SecIntegrityLib.c +++ b/keychain/trust/TrustedPeers/TPTypes.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2007,2011 Apple Inc. All Rights Reserved. - * + * 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, @@ -17,7 +17,14 @@ * 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 "SecIntegrityLib.h" + +typedef unsigned long long TPCounter; + +typedef NS_ENUM(NSInteger, TPResult) { + TPResultOk, + TPResultSignatureMismatch, + TPResultClockViolation, +}; diff --git a/keychain/trust/TrustedPeers/TPUtils.h b/keychain/trust/TrustedPeers/TPUtils.h new file mode 100644 index 00000000..b33ae4c1 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPUtils.h @@ -0,0 +1,34 @@ +/* + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface TPUtils : NSObject + ++ (NSData *)serializedPListWithDictionary:(NSDictionary *)dict; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPUtils.m b/keychain/trust/TrustedPeers/TPUtils.m new file mode 100644 index 00000000..063a88bb --- /dev/null +++ b/keychain/trust/TrustedPeers/TPUtils.m @@ -0,0 +1,43 @@ +/* + * 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 "TPUtils.h" + +@implementation TPUtils + ++ (NSData *)serializedPListWithDictionary:(NSDictionary *)dict +{ + NSError *error = nil; + NSData *data = [NSPropertyListSerialization dataWithPropertyList:dict + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:&error]; + if (nil == data) { + @throw [NSException exceptionWithName:@"Failed to serialize" + reason:[error description] + userInfo:nil]; + } + return data; +} + +@end diff --git a/keychain/trust/TrustedPeers/TPVoucher.h b/keychain/trust/TrustedPeers/TPVoucher.h new file mode 100644 index 00000000..05acb427 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPVoucher.h @@ -0,0 +1,72 @@ +/* + * 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 + +#import "TPSigningKey.h" +#import "TPTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +/*! + A voucher is a record signed by a "sponsor" peer to say that + a "beneficiary" peer is trusted. + + The signature is not checked when an TPVoucher instance is + constructed, because the sponsor's signing key might not be + available at that time. + + This class is a value type -- its members are immutable and + instances with identical contents are interchangeable. + It overrides isEqual and hash, so that two instances with + identical contents will compare as equal. + */ +@interface TPVoucher : NSObject + +/*! + Can return nil with error if [trustSigningKey signatureForData:error:] errors. + */ ++ (nullable instancetype)voucherWithBeneficiaryID:(NSString *)beneficiaryID + sponsorID:(NSString *)sponsorID + clock:(TPCounter)clock + trustSigningKey:(id)trustSigningKey + error:(NSError **)error; + +// Returns nil if data cannot be deserialized to a dictionary +// or that dictionary does not contain the expected keys and value types. +// This method performs no signature checking; that should be done later, +// when the sponsor's trustSigningKey is available. ++ (nullable instancetype)voucherWithPList:(NSData *)voucherInfoPList + sig:(NSData *)voucherInfoSig; + +- (BOOL)isEqualToVoucher:(TPVoucher *)other; + +@property (nonatomic, readonly) NSString *beneficiaryID; +@property (nonatomic, readonly) NSString *sponsorID; +@property (nonatomic, readonly) TPCounter clock; +@property (nonatomic, readonly) NSData *voucherInfoPList; +@property (nonatomic, readonly) NSData *voucherInfoSig; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeers/TPVoucher.m b/keychain/trust/TrustedPeers/TPVoucher.m new file mode 100644 index 00000000..fe45a7d6 --- /dev/null +++ b/keychain/trust/TrustedPeers/TPVoucher.m @@ -0,0 +1,129 @@ +/* + * 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 "TPVoucher.h" +#import "TPUtils.h" + +static const NSString *kBeneficiaryID = @"beneficiaryID"; +static const NSString *kSponsorID = @"sponsorID"; +static const NSString *kClock = @"clock"; + + +@interface TPVoucher () +@property (nonatomic, strong) NSString *beneficiaryID; +@property (nonatomic, strong) NSString *sponsorID; +@property (nonatomic, assign) TPCounter clock; +@property (nonatomic, strong) NSData *voucherInfoPList; +@property (nonatomic, strong) NSData *voucherInfoSig; +@end + + +@implementation TPVoucher + ++ (instancetype)voucherWithBeneficiaryID:(NSString *)beneficiaryID + sponsorID:(NSString *)sponsorID + clock:(TPCounter)clock + trustSigningKey:(id)trustSigningKey + error:(NSError **)error +{ + NSDictionary *dict = @{ + kBeneficiaryID: beneficiaryID, + kSponsorID: sponsorID, + kClock: @(clock) + }; + NSData *data = [TPUtils serializedPListWithDictionary:dict]; + NSData *sig = [trustSigningKey signatureForData:data withError:error]; + if (nil == sig) { + return nil; + } + + TPVoucher *voucher = [[TPVoucher alloc] init]; + voucher.beneficiaryID = [beneficiaryID copy]; + voucher.sponsorID = [sponsorID copy]; + voucher.clock = clock; + voucher.voucherInfoPList = data; + voucher.voucherInfoSig = sig; + return voucher; +} + ++ (instancetype)voucherWithPList:(NSData *)voucherInfoPList + sig:(NSData *)voucherInfoSig +{ + TPVoucher *voucher = [[TPVoucher alloc] init]; + voucher.voucherInfoPList = [voucherInfoPList copy]; + voucher.voucherInfoSig = [voucherInfoSig copy]; + + id dict = [NSPropertyListSerialization propertyListWithData:voucherInfoPList + options:NSPropertyListImmutable + format:nil + error:NULL]; + if (![dict isKindOfClass:[NSDictionary class]]) { + return nil; + } + + if (![dict[kBeneficiaryID] isKindOfClass:[NSString class]]) { + return nil; + } + voucher.beneficiaryID = dict[kBeneficiaryID]; + + if (![dict[kSponsorID] isKindOfClass:[NSString class]]) { + return nil; + } + voucher.sponsorID = dict[kSponsorID]; + + if (![dict[kClock] isKindOfClass:[NSNumber class]]) { + return nil; + } + voucher.clock = [dict[kClock] unsignedLongLongValue]; + + return voucher; +} + +- (BOOL)isEqualToVoucher:(TPVoucher *)other +{ + if (other == self) { + return YES; + } + return [self.voucherInfoPList isEqualToData:other.voucherInfoPList] + && [self.voucherInfoSig isEqualToData:other.voucherInfoSig]; +} + +#pragma mark - NSObject + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if (![object isKindOfClass:[TPVoucher class]]) { + return NO; + } + return [self isEqualToVoucher:object]; +} + +- (NSUInteger)hash +{ + return [self.voucherInfoPList hash]; +} + +@end diff --git a/OSX/libsecurity_codesigning/lib/SecIntegrityLib.h b/keychain/trust/TrustedPeers/TrustedPeers.h similarity index 52% rename from OSX/libsecurity_codesigning/lib/SecIntegrityLib.h rename to keychain/trust/TrustedPeers/TrustedPeers.h index 0a0a0c51..0d85290f 100644 --- a/OSX/libsecurity_codesigning/lib/SecIntegrityLib.h +++ b/keychain/trust/TrustedPeers/TrustedPeers.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2007,2011 Apple Inc. All Rights Reserved. - * + * 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, @@ -17,39 +17,29 @@ * 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 SecIntegrityLib - This header provides a subset of the code-integrity API for Code Signing. - This subset functionality is implemented as a static library written - entirely in C, and depends on nothing except the system library and the - C runtime. It is thus suitable to be used by low-level libraries and - other such system facilities. On the other hand, it does not provide the - full functionality of . - - This file is documented as a delta to , which - you should consult as a baseline. -*/ -#ifndef _H_SECINTEGRITYLIB -#define _H_SECINTEGRITYLIB +#import -#include "SecIntegrity.h" +//! Project version number for TrustedPeers. +FOUNDATION_EXPORT double TrustedPeersVersionNumber; -#ifdef __cplusplus -extern "C" { -#endif +//! Project version string for TrustedPeers. +FOUNDATION_EXPORT const unsigned char TrustedPeersVersionString[]; - -/* - This file is not yet published. - */ - - -#ifdef __cplusplus -} -#endif - -#endif //_H_SECINTEGRITYLIB +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/keychain/trust/TrustedPeersTests/Info.plist b/keychain/trust/TrustedPeersTests/Info.plist new file mode 100644 index 00000000..6c6c23c4 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/keychain/trust/TrustedPeersTests/TPCircleTests.m b/keychain/trust/TrustedPeersTests/TPCircleTests.m new file mode 100644 index 00000000..4af9e0fd --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPCircleTests.m @@ -0,0 +1,52 @@ +/* + * 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 +#import + +@interface TPCircleTests : XCTestCase + +@end + +@implementation TPCircleTests + +- (void)testCircleIDChecks { + NSArray *included = @[@"A", @"B"]; + NSArray *excluded = @[@"C", @"D"]; + TPCircle *circle1 = [TPCircle circleWithIncludedPeerIDs:included excludedPeerIDs:excluded]; + TPCircle *circle2 = [TPCircle circleWithID:circle1.circleID includedPeerIDs:included excludedPeerIDs:excluded]; + XCTAssertEqual([circle1 hash], [circle2 hash]); + XCTAssertEqualObjects(circle1, circle2); + XCTAssert([circle1 isEqual:circle1]); + XCTAssertEqualObjects(circle1, circle2); + XCTAssertNotEqualObjects(circle1, @"foo"); + + // (Feel free to change the format of the description output, this is just for test coverage.) + XCTAssertEqualObjects([circle1 description], @"{ in: [A B] ex: [C D] }"); + + // Misuse circle1.circleID here, trying to construct a different circle with nil excludedPeerIDs: + TPCircle *circle3 = [TPCircle circleWithID:circle1.circleID includedPeerIDs:included excludedPeerIDs:nil]; + XCTAssertNil(circle3); +} + +@end diff --git a/OSX/libsecurity_utilities/lib/typedvalue.cpp b/keychain/trust/TrustedPeersTests/TPDummyDecrypter.h similarity index 76% rename from OSX/libsecurity_utilities/lib/typedvalue.cpp rename to keychain/trust/TrustedPeersTests/TPDummyDecrypter.h index 2864be1f..790568ba 100644 --- a/OSX/libsecurity_utilities/lib/typedvalue.cpp +++ b/keychain/trust/TrustedPeersTests/TPDummyDecrypter.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2000-2001,2004,2011,2014 Apple Inc. All Rights Reserved. - * + * 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, @@ -17,22 +17,20 @@ * 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 -// -// typedvalue - type-safe reference transmission of arbitrary types -// -#include "typedvalue.h" +#import +NS_ASSUME_NONNULL_BEGIN -namespace Security { +@interface TPDummyDecrypter : NSObject ++ (instancetype)dummyDecrypter; -GenericValue::~GenericValue() -{ } +@end - -} // end namespace Security +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeersTests/TPDummyDecrypter.m b/keychain/trust/TrustedPeersTests/TPDummyDecrypter.m new file mode 100644 index 00000000..f7df1949 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPDummyDecrypter.m @@ -0,0 +1,49 @@ +/* + * 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 "TPDummyDecrypter.h" + +@implementation TPDummyDecrypter + ++ (instancetype)dummyDecrypter +{ + return [[TPDummyDecrypter alloc] init]; +} + +- (nullable NSData *)decryptData:(NSData *)ciphertext + withKey:(NSData *)key + error:(NSError **)error +{ + // Repeating-key XOR + NSMutableData *plaintext = [NSMutableData dataWithLength:ciphertext.length]; + uint8_t *plainbytes = plaintext.mutableBytes; + const uint8_t *cipherbytes = ciphertext.bytes; + const uint8_t *keybytes = key.bytes; + NSUInteger keylen = key.length; + for (NSUInteger i = 0; i < ciphertext.length; i++) { + plainbytes[i] = cipherbytes[i] ^ keybytes[i % keylen]; + } + return plaintext; +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPDummyEncrypter.h b/keychain/trust/TrustedPeersTests/TPDummyEncrypter.h new file mode 100644 index 00000000..a7d415cc --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPDummyEncrypter.h @@ -0,0 +1,39 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/*! + Weakly "encrypts" data to be decrypted with TPDummyDecrypter. + */ +@interface TPDummyEncrypter : NSObject + ++ (instancetype)dummyEncrypterWithKey:(NSData *)key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeersTests/TPDummyEncrypter.m b/keychain/trust/TrustedPeersTests/TPDummyEncrypter.m new file mode 100644 index 00000000..4a8fbb35 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPDummyEncrypter.m @@ -0,0 +1,48 @@ +/* + * 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 "TPDummyEncrypter.h" +#import "TPDummyDecrypter.h" + +@interface TPDummyEncrypter () +@property (nonatomic, strong) NSData *decryptionKey; +@end + +@implementation TPDummyEncrypter + ++ (instancetype)dummyEncrypterWithKey:(NSData *)key +{ + TPDummyEncrypter *enc = [[TPDummyEncrypter alloc] init]; + enc.decryptionKey = key; + return enc; +} + +- (nullable NSData *)encryptData:(NSData *)plaintext error:(NSError **)error +{ + // It's just XOR with rotating key, so "encryption" == "decryption" + return [[TPDummyDecrypter dummyDecrypter] decryptData:plaintext + withKey:self.decryptionKey + error:error]; +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPDummySigningKey.h b/keychain/trust/TrustedPeersTests/TPDummySigningKey.h new file mode 100644 index 00000000..f6b4211f --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPDummySigningKey.h @@ -0,0 +1,54 @@ +/* + * 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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +/*! + A dummy implementation of TPSigning for testing. + + It uses a very weak hash algorithm and no crypto, just enough for unit tests. + */ +@interface TPDummySigningKey : NSObject + +/*! + Setting this to NO causes signatureForData to return nil with an error. + */ +@property (nonatomic, assign) BOOL privateKeyIsAvailable; + +- (instancetype)initWithPublicKeyData:(NSData *)publicKey; + +@end + + +/*! + A factory that constructs TPDummySigningKey objects. + */ +@interface TPDummySigningKeyFactory : NSObject ++ (instancetype) dummySigningKeyFactory; +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/trust/TrustedPeersTests/TPDummySigningKey.m b/keychain/trust/TrustedPeersTests/TPDummySigningKey.m new file mode 100644 index 00000000..9c613ad9 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPDummySigningKey.m @@ -0,0 +1,85 @@ +/* + * 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 "TPDummySigningKey.h" + +@interface TPDummySigningKey () +@property (nonatomic, strong) NSData *publicKey; +@end + + +@implementation TPDummySigningKey + +- (instancetype)initWithPublicKeyData:(NSData *)publicKey +{ + self = [super init]; + if (self) { + _publicKey = publicKey; + _privateKeyIsAvailable = YES; + } + return self; +} + +- (NSData *)signatureForData:(NSData *)data withError:(NSError **)error +{ + if (self.privateKeyIsAvailable) { + return [self signatureForData:data]; + } else { + if (error) { + *error = [NSError errorWithDomain:@"TPDummySigningKey" code:1 userInfo:nil]; + } + return nil; + } +} + +- (NSData *)signatureForData:(NSData *)data +{ + // A really dumb hash that is just good enough for unit tests. + NSUInteger hash = [self.publicKey hash] ^ [data hash]; + return [NSData dataWithBytes:&hash length:sizeof(hash)]; +} + +- (BOOL)checkSignature:(NSData *)sig matchesData:(NSData *)data +{ + return [sig isEqualToData:[self signatureForData:data]]; +} + +@end + + +@implementation TPDummySigningKeyFactory + +- (id )keyWithPublicKeyData:(NSData *)publicKey +{ + if (0 == publicKey.length) { + return nil; + } + return [[TPDummySigningKey alloc] initWithPublicKeyData:publicKey]; +} + ++ (instancetype) dummySigningKeyFactory +{ + return [[TPDummySigningKeyFactory alloc] init]; +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPDummySigningKeyTests.m b/keychain/trust/TrustedPeersTests/TPDummySigningKeyTests.m new file mode 100644 index 00000000..c67057ba --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPDummySigningKeyTests.m @@ -0,0 +1,43 @@ +/* + * 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 + +#import "TPDummySigningKey.h" + +@interface TPDummySigningKeyTests : XCTestCase + +@end + +@implementation TPDummySigningKeyTests + +- (void)testRoundTrip { + NSData *keyData = [@"The Key" dataUsingEncoding:NSUTF8StringEncoding]; + id key = [[TPDummySigningKey alloc] initWithPublicKeyData:keyData]; + NSData *data = [@"The Text" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *sig = [key signatureForData:data withError:NULL]; + BOOL ok = [key checkSignature:sig matchesData:data]; + XCTAssert(ok); +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPHashTests.m b/keychain/trust/TrustedPeersTests/TPHashTests.m new file mode 100644 index 00000000..6599ca52 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPHashTests.m @@ -0,0 +1,92 @@ +/* + * 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 +#import + +@interface TPHashTests : XCTestCase + +@property (nonatomic, strong) NSData *hello; + +@end + +@implementation TPHashTests + +- (void)setUp +{ + self.hello = [@"hello" dataUsingEncoding:NSUTF8StringEncoding]; +} + +- (void)testSHA224 +{ + NSString *hash = [TPHashBuilder hashWithAlgo:kTPHashAlgoSHA224 ofData:self.hello]; + XCTAssertEqualObjects(hash, @"SHA224:6gmunMZ2jFD87pA+0FRVblv8g0eQfxJZiqJBkw=="); + TPHashAlgo algo = [TPHashBuilder algoOfHash:hash]; + XCTAssertEqual(kTPHashAlgoSHA224, algo); +} + +- (void)testSHA256 +{ + NSString *hash = [TPHashBuilder hashWithAlgo:kTPHashAlgoSHA256 ofData:self.hello]; + XCTAssertEqualObjects(hash, @"SHA256:LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="); + TPHashAlgo algo = [TPHashBuilder algoOfHash:hash]; + XCTAssertEqual(kTPHashAlgoSHA256, algo); +} + +- (void)testSHA384 +{ + NSString *hash = [TPHashBuilder hashWithAlgo:kTPHashAlgoSHA384 ofData:self.hello]; + XCTAssertEqualObjects(hash, @"SHA384:WeF0h3dEjGnea4ANejO7+5/xtGPkQ1TDVTvNucZm+pASWjx5+QOXvfX2oT3oKGhP"); + TPHashAlgo algo = [TPHashBuilder algoOfHash:hash]; + XCTAssertEqual(kTPHashAlgoSHA384, algo); +} + +- (void)testSHA512 +{ + NSString *hash = [TPHashBuilder hashWithAlgo:kTPHashAlgoSHA512 ofData:self.hello]; + XCTAssertEqualObjects(hash, @"SHA512:m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="); + TPHashAlgo algo = [TPHashBuilder algoOfHash:hash]; + XCTAssertEqual(kTPHashAlgoSHA512, algo); +} + +- (void)testBadAlgo +{ + XCTAssertEqual(kTPHashAlgoUnknown, [TPHashBuilder algoOfHash:@""]); + XCTAssertEqual(kTPHashAlgoUnknown, [TPHashBuilder algoOfHash:@"foo"]); + XCTAssertEqual(kTPHashAlgoUnknown, [TPHashBuilder algoOfHash:@"foo:"]); + XCTAssertEqual(kTPHashAlgoUnknown, [TPHashBuilder algoOfHash:@":"]); + XCTAssertEqual(kTPHashAlgoUnknown, [TPHashBuilder algoOfHash:@"foo:bar"]); + XCTAssertEqual(kTPHashAlgoUnknown, [TPHashBuilder algoOfHash:@"SHA256"]); + + XCTAssertThrows([TPHashBuilder hashWithAlgo:kTPHashAlgoUnknown ofData:self.hello]); +} + +- (void)testBadReuse +{ + TPHashBuilder *builder = [[TPHashBuilder alloc] initWithAlgo:kTPHashAlgoSHA256]; + [builder finalHash]; + XCTAssertThrows([builder updateWithData:self.hello]); + XCTAssertThrows([builder finalHash]); +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPModelTests.m b/keychain/trust/TrustedPeersTests/TPModelTests.m new file mode 100644 index 00000000..655c45a4 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPModelTests.m @@ -0,0 +1,831 @@ +/* + * 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 +#import +#import "TPDummySigningKey.h" +#import "TPDummyDecrypter.h" +#import "TPDummyEncrypter.h" + +@interface TPModelTests : XCTestCase + +@property (nonatomic, strong) TPModel *model; +@property (nonatomic, strong) TPPolicyDocument *policyDocV1; +@property (nonatomic, strong) TPPolicyDocument *policyDocV2; +@property (nonatomic, strong) NSString *secretName; +@property (nonatomic, strong) NSData *secretKey; + +@end + +@implementation TPModelTests + +- (TPModel *)makeModel +{ + id decrypter = [TPDummyDecrypter dummyDecrypter]; + TPModel *model = [[TPModel alloc] initWithDecrypter:decrypter]; + [model registerPolicyDocument:self.policyDocV1]; + [model registerPolicyDocument:self.policyDocV2]; + return model; +} + +- (void)setUp +{ + self.secretName = @"foo"; + TPDummyEncrypter *encrypter = [TPDummyEncrypter dummyEncrypterWithKey:[@"sekritkey" dataUsingEncoding:NSUTF8StringEncoding]]; + self.secretKey = encrypter.decryptionKey; + NSData *redaction = [TPPolicyDocument redactionWithEncrypter:encrypter + modelToCategory:@[ @{ @"prefix": @"iCycle", @"category": @"full" } ] + categoriesByView:nil + introducersByCategory:nil + error:NULL]; + + self.policyDocV1 + = [TPPolicyDocument policyDocWithVersion:1 + modelToCategory:@[ + @{ @"prefix": @"iPhone", @"category": @"full" }, + @{ @"prefix": @"iPad", @"category": @"full" }, + @{ @"prefix": @"Mac", @"category": @"full" }, + @{ @"prefix": @"iMac", @"category": @"full" }, + @{ @"prefix": @"AppleTV", @"category": @"tv" }, + @{ @"prefix": @"Watch", @"category": @"watch" }, + ] + categoriesByView:@{ + @"WiFi": @[ @"full", @"tv", @"watch" ], + @"SafariCreditCards": @[ @"full" ], + @"PCSEscrow": @[ @"full" ] + } + introducersByCategory:@{ + @"full": @[ @"full" ], + @"tv": @[ @"full", @"tv" ], + @"watch": @[ @"full", @"watch" ] + } + redactions:@{ + self.secretName: redaction + } + hashAlgo:kTPHashAlgoSHA256]; + + self.policyDocV2 + = [TPPolicyDocument policyDocWithVersion:2 + modelToCategory:@[ + @{ @"prefix": @"iCycle", @"category": @"full" }, // new + @{ @"prefix": @"iPhone", @"category": @"full" }, + @{ @"prefix": @"iPad", @"category": @"full" }, + @{ @"prefix": @"Mac", @"category": @"full" }, + @{ @"prefix": @"iMac", @"category": @"full" }, + @{ @"prefix": @"AppleTV", @"category": @"tv" }, + @{ @"prefix": @"Watch", @"category": @"watch" }, + ] + categoriesByView:@{ + @"WiFi": @[ @"full", @"tv", @"watch" ], + @"SafariCreditCards": @[ @"full" ], + @"PCSEscrow": @[ @"full" ] + } + introducersByCategory:@{ + @"full": @[ @"full" ], + @"tv": @[ @"full", @"tv" ], + @"watch": @[ @"full", @"watch" ] + } + redactions:@{} + hashAlgo:kTPHashAlgoSHA256]; + + self.model = [self makeModel]; +} + +- (TPPeerPermanentInfo *)makePeerWithMachineID:(NSString *)machineID +{ + return [self makePeerWithMachineID:machineID modelID:@"iPhone" epoch:1 key:machineID]; +} + +- (TPPeerPermanentInfo *)makePeerWithMachineID:(NSString *)machineID + modelID:(NSString *)modelID + epoch:(TPCounter)epoch + key:(NSString *)key +{ + NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding]; + id trustSigningKey = [[TPDummySigningKey alloc] initWithPublicKeyData:keyData]; + TPPeerPermanentInfo *permanentInfo + = [TPPeerPermanentInfo permanentInfoWithMachineID:machineID + modelID:modelID + epoch:epoch + trustSigningKey:trustSigningKey + peerIDHashAlgo:kTPHashAlgoSHA256 + error:NULL]; + [self.model registerPeerWithPermanentInfo:permanentInfo]; + + TPPeerStableInfo *stableInfo = [self.model createStableInfoWithDictionary:@{} + policyVersion:self.policyDocV1.policyVersion + policyHash:self.policyDocV1.policyHash + policySecrets:nil + forPeerWithID:permanentInfo.peerID + error:NULL]; + [self.model updateStableInfo:stableInfo forPeerWithID:permanentInfo.peerID]; + return permanentInfo; +} + +static BOOL circleEquals(TPCircle *circle, NSArray *includedPeerIDs, NSArray *excludedPeerIDs) +{ + return [circle isEqualToCircle:[TPCircle circleWithIncludedPeerIDs:includedPeerIDs excludedPeerIDs:excludedPeerIDs]]; +} + +- (void)testModelBasics +{ + NSString *A = [self makePeerWithMachineID:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb"].peerID; + NSString *C = [self makePeerWithMachineID:@"ccc"].peerID; + + TPCircle *circle; + + // A trusts B, establishes clique + circle = [self.model advancePeerWithID:A addingPeerIDs:@[B] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // B trusts A + circle = [self.model advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // A trusts C + circle = [self.model advancePeerWithID:A addingPeerIDs:@[C] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B, C], @[])); + + // C trusts A + circle = [self.model advancePeerWithID:C addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B, C], @[])); + + // Updating B (B should now trust C) + circle = [self.model advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B, C], @[])); + + // Updating B again (should be no change) + circle = [self.model advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B, C], @[])); + + // A decides to exclude B + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:@[B] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, C], @[B])); + + // Updating C (C should now exclude B) + circle = [self.model advancePeerWithID:C addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, C], @[B])); + + // Updating B (B should now exclude itself and include nobody) + circle = [self.model advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[], @[B])); + + // Updating B again (should be no change) + circle = [self.model advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[], @[B])); + + // C decides to exclude itself + circle = [self.model advancePeerWithID:C addingPeerIDs:nil removingPeerIDs:@[C] createClique:nil]; + XCTAssert(circleEquals(circle, @[], @[C])); + + // Updating C (should be no change) + circle = [self.model advancePeerWithID:C addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[], @[C])); + + // Updating A (A should now exclude C) + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A], @[B, C])); +} + +- (void)testPeerReplacement +{ + NSString *A = [self makePeerWithMachineID:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb"].peerID; + NSString *C = [self makePeerWithMachineID:@"ccc"].peerID; + + TPCircle *circle; + + // A trusts B, establishes clique. A is in a drawer. + circle = [self.model advancePeerWithID:A addingPeerIDs:@[B] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // B trusts A + circle = [self.model advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // B decides to replace itself with C. + circle = [self.model advancePeerWithID:B addingPeerIDs:@[C] removingPeerIDs:@[B] createClique:nil]; + XCTAssert(circleEquals(circle, @[C], @[B])); + + // B should be able to update itself without forgetting it trusts C. + circle = [self.model advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[C], @[B])); + + // When A wakes up, it should trust C instead of B. + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, C], @[B])); +} + +- (void)testVoucher +{ + TPPeerPermanentInfo *aaa = [self makePeerWithMachineID:@"aaa"]; + TPPeerPermanentInfo *bbb = [self makePeerWithMachineID:@"bbb"]; + TPPeerPermanentInfo *ccc = [self makePeerWithMachineID:@"ccc"]; + + NSString *A = aaa.peerID; + NSString *B = bbb.peerID; + NSString *C = ccc.peerID; + + TPCircle *circle; + + // A establishes clique. + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[A], @[])); + + // B trusts A + circle = [self.model advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // C trusts A + circle = [self.model advancePeerWithID:C addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, C], @[])); + + // B gets a voucher from A + TPVoucher *voucher = [self.model createVoucherForCandidate:bbb withSponsorID:A error:NULL]; + XCTAssertNotNil(voucher); + XCTAssertEqual(TPResultOk, [self.model registerVoucher:voucher]); + + // Updating C, it sees the voucher and now trusts B + circle = [self.model advancePeerWithID:C addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B, C], @[])); + + // Updating A, it sees the voucher (sponsored by A itself) and now trusts B. + // (A updating its dynamicInfo also expires the voucher.) + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); +} + +- (void)testExpiredVoucher +{ + TPPeerPermanentInfo *aaa = [self makePeerWithMachineID:@"aaa"]; + TPPeerPermanentInfo *bbb = [self makePeerWithMachineID:@"bbb"]; + TPPeerPermanentInfo *ccc = [self makePeerWithMachineID:@"ccc"]; + TPPeerPermanentInfo *ddd = [self makePeerWithMachineID:@"ddd"]; + + NSString *A = aaa.peerID; + NSString *B = bbb.peerID; + NSString *C = ccc.peerID; + NSString *D = ddd.peerID; + + TPCircle *circle; + + // A establishes clique. + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[A], @[])); + + // B trusts A + circle = [self.model advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // C trusts A + circle = [self.model advancePeerWithID:C addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, C], @[])); + + // B gets a voucher from A (but doesn't register the voucher yet because A would notice it) + TPVoucher *voucher = [self.model createVoucherForCandidate:bbb withSponsorID:A error:NULL]; + + // A advances its clock by deciding to trust D + circle = [self.model advancePeerWithID:A addingPeerIDs:@[D] removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, D], @[])); + + // Register the voucher, which is now expired because A has advanced its clock + [self.model registerVoucher:voucher]; + + // Updating C, it ignores the expired voucher for B + circle = [self.model advancePeerWithID:C addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, C, D], @[])); +} + +- (void)testVoucherWithBadSignature +{ + TPPeerPermanentInfo *aaa = [self makePeerWithMachineID:@"aaa"]; + TPPeerPermanentInfo *bbb = [self makePeerWithMachineID:@"bbb"]; + + NSString *A = aaa.peerID; + NSString *B = bbb.peerID; + + TPCircle *circle; + + // A establishes clique. + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[A], @[])); + + // B trusts A + circle = [self.model advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // B gets a voucher from A, but signed by B's key + TPVoucher *voucher = [TPVoucher voucherWithBeneficiaryID:B + sponsorID:A + clock:[self.model getDynamicInfoForPeerWithID:A].clock + trustSigningKey:bbb.trustSigningKey + error:NULL]; + XCTAssertNotNil(voucher); + XCTAssertEqual(TPResultSignatureMismatch, [self.model registerVoucher:voucher]); +} + +- (void)testVoucherPolicy +{ + TPPeerPermanentInfo *aaa = [self makePeerWithMachineID:@"aaa" modelID:@"watch" epoch:1 key:@"aaa"]; + TPPeerPermanentInfo *bbb = [self makePeerWithMachineID:@"bbb"]; + + NSString *A = aaa.peerID; + + // B is a phone trying to get a voucher from A which is a watch + TPVoucher *voucher = [self.model createVoucherForCandidate:bbb withSponsorID:A error:NULL]; + XCTAssertNil(voucher); +} + +- (void)testDynamicInfoReplay +{ + NSString *A = [self makePeerWithMachineID:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb"].peerID; + + TPCircle *circle; + + // A establishes clique, trusts B. + circle = [self.model advancePeerWithID:A addingPeerIDs:@[B] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // Attacker snapshots A's dynamicInfo + TPPeerDynamicInfo *dyn = [self.model getDynamicInfoForPeerWithID:A]; + + // A excludes B + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:@[B] createClique:nil]; + XCTAssert(circleEquals(circle, @[A], @[B])); + + // Attacker replays the old snapshot + XCTAssertEqual(TPResultClockViolation, [self.model updateDynamicInfo:dyn forPeerWithID:A]); + + circle = [self.model getCircleForPeerWithID:A]; + XCTAssert(circleEquals(circle, @[A], @[B])); +} + +- (void)testPhoneApprovingWatch +{ + NSString *phoneA = [self makePeerWithMachineID:@"phoneA" modelID:@"iPhone7,1" epoch:1 key:@"phoneA"].peerID; + NSString *watch = [self makePeerWithMachineID:@"watch" modelID:@"Watch1,1" epoch:1 key:@"watch"].peerID; + + TPCircle *circle; + + // phoneA establishes clique, trusts watch. + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:@[watch] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[phoneA, watch], @[])); +} + +- (void)testWatchApprovingPhone +{ + NSString *phoneA = [self makePeerWithMachineID:@"phoneA" modelID:@"iPhone7,1" epoch:1 key:@"phoneA"].peerID; + NSString *phoneB = [self makePeerWithMachineID:@"phoneB" modelID:@"iPhone7,1" epoch:1 key:@"phoneB"].peerID; + NSString *watch = [self makePeerWithMachineID:@"watch" modelID:@"Watch1,1" epoch:1 key:@"watch"].peerID; + + TPCircle *circle; + + // phoneA establishes clique, trusts watch. + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:@[watch] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[phoneA, watch], @[])); + + // watch trusts phoneA and phoneB + circle = [self.model advancePeerWithID:watch addingPeerIDs:@[phoneA, phoneB] removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[phoneA, phoneB, watch], @[])); + + // phoneA updates, and it should ignore phoneB, so no change. + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[phoneA, watch], @[])); +} + +- (void)testNilCreateClique +{ + NSString *A = [self makePeerWithMachineID:@"aaa"].peerID; + + TPCircle *circle; + + // Try to establish dynamicInfo without providing createClique + circle = [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssertNil(circle); +} + +- (void)testCliqueConvergence +{ + NSString *A = [self makePeerWithMachineID:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb"].peerID; + + TPCircle *circle; + + // A establishes clique1 + circle = [self.model advancePeerWithID:A addingPeerIDs:@[] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[A], @[])); + XCTAssert([[self.model getDynamicInfoForPeerWithID:A].clique isEqualToString:@"clique1"]); + + // B establishes clique2 + circle = [self.model advancePeerWithID:B addingPeerIDs:@[] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique2"; + }]; + XCTAssert(circleEquals(circle, @[B], @[])); + XCTAssert([[self.model getDynamicInfoForPeerWithID:B].clique isEqualToString:@"clique2"]); + + // A trusts B. A should now switch to clique2, which is later than clique1 in lexical order. + circle = [self.model advancePeerWithID:A addingPeerIDs:@[B] removingPeerIDs:@[] createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + XCTAssert([[self.model getDynamicInfoForPeerWithID:A].clique isEqualToString:@"clique2"]); +} + +- (void)testRemovalCounts +{ + NSString *A = [self makePeerWithMachineID:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb"].peerID; + NSString *C = [self makePeerWithMachineID:@"ccc"].peerID; + + // A establishes clique with B and C + [self.model advancePeerWithID:A addingPeerIDs:@[B, C] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssertEqual(0ULL, [self.model getDynamicInfoForPeerWithID:A].removals); + + // B trusts A + [self.model advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssertEqual(0ULL, [self.model getDynamicInfoForPeerWithID:B].removals); + + // A removes C + [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:@[C] createClique:nil]; + XCTAssertEqual(1ULL, [self.model getDynamicInfoForPeerWithID:A].removals); + + // B updates, and now shows 1 removal + [self.model advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssertEqual(1ULL, [self.model getDynamicInfoForPeerWithID:B].removals); +} + +- (void)testCommunicatingModels +{ + TPPeerPermanentInfo *aaa = [self makePeerWithMachineID:@"aaa"]; + TPPeerPermanentInfo *bbb = [self makePeerWithMachineID:@"bbb"]; + TPPeerPermanentInfo *ccc = [self makePeerWithMachineID:@"ccc"]; + + NSString *A = aaa.peerID; + NSString *B = bbb.peerID; + NSString *C = ccc.peerID; + + // A lives on self.model, where it trusts B and C + [self.model advancePeerWithID:A addingPeerIDs:@[B, C] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + + // B lives on model2, where it trusts A + TPModel *model2 = [self makeModel]; + [model2 registerPeerWithPermanentInfo:aaa]; + [model2 registerPeerWithPermanentInfo:bbb]; + [model2 updateStableInfo:[self.model getStableInfoForPeerWithID:A] forPeerWithID:A]; + [model2 updateStableInfo:[self.model getStableInfoForPeerWithID:B] forPeerWithID:B]; + [model2 advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + + // A's circle and dynamicInfo are transmitted from model to model2 + TPCircle *circle = [self.model getCircleForPeerWithID:A]; + TPPeerDynamicInfo *dyn = [self.model getDynamicInfoForPeerWithID:A]; + [model2 updateDynamicInfo:dyn forPeerWithID:A]; + [model2 registerCircle:circle]; + + // B updates in model2, but C is not yet registered so is ignored. + circle = [model2 advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // Now C registers in model2 + [model2 registerPeerWithPermanentInfo:ccc]; + + // B updates in model2, and now it trusts C. + circle = [model2 advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B, C], @[])); +} + +- (void)testCommunicatingModelsWithVouchers +{ + TPPeerPermanentInfo *aaa = [self makePeerWithMachineID:@"aaa"]; + TPPeerPermanentInfo *bbb = [self makePeerWithMachineID:@"bbb"]; + TPPeerPermanentInfo *ccc = [self makePeerWithMachineID:@"ccc"]; + + NSString *A = aaa.peerID; + NSString *B = bbb.peerID; + NSString *C = ccc.peerID; + + // A lives on self.model, where it trusts B + [self.model advancePeerWithID:A addingPeerIDs:@[B] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + + // B lives on model2, where it trusts A + TPModel *model2 = [self makeModel]; + [model2 registerPeerWithPermanentInfo:aaa]; + [model2 registerPeerWithPermanentInfo:bbb]; + [model2 updateStableInfo:[self.model getStableInfoForPeerWithID:A] forPeerWithID:A]; + [model2 updateStableInfo:[self.model getStableInfoForPeerWithID:B] forPeerWithID:B]; + [model2 advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + + // A's circle and dynamicInfo are transmitted from model to model2 + TPCircle *circle = [self.model getCircleForPeerWithID:A]; + TPPeerDynamicInfo *dyn = [self.model getDynamicInfoForPeerWithID:A]; + [model2 updateDynamicInfo:dyn forPeerWithID:A]; + [model2 registerCircle:circle]; + + // A writes a voucher for C, and it is transmitted to model2 + TPVoucher *voucher = [self.model createVoucherForCandidate:ccc withSponsorID:A error:NULL]; + [model2 registerVoucher:voucher]; + + // B updates in model2, but C is not yet registered so is ignored. + circle = [model2 advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B], @[])); + + // Now C registers in model2 + [model2 registerPeerWithPermanentInfo:ccc]; + [model2 updateStableInfo:[self.model getStableInfoForPeerWithID:C] forPeerWithID:C]; + + // B updates in model2, and now it trusts C. + circle = [model2 advancePeerWithID:B addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[A, B, C], @[])); +} + +- (void)testReregisterPeer +{ + TPPeerPermanentInfo *aaa = [self makePeerWithMachineID:@"aaa"]; + + NSString *A = aaa.peerID; + + [self.model advancePeerWithID:A addingPeerIDs:nil removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + + // Registering the peer again should not overwrite its dynamicInfo or other state. + [self.model registerPeerWithPermanentInfo:aaa]; + XCTAssertNotNil([self.model getDynamicInfoForPeerWithID:A]); +} + +- (void)testPeerAccessors +{ + TPPeerPermanentInfo *aaa = [self makePeerWithMachineID:@"aaa"]; + + NSString *A = aaa.peerID; + + XCTAssert([self.model hasPeerWithID:A]); + + TPPeerPermanentInfo *aaa2 = [self.model getPermanentInfoForPeerWithID:A]; + XCTAssertEqualObjects(aaa, aaa2); + + TPPeerStableInfo *info = [self.model createStableInfoWithDictionary:@{ @"hello": @"world" } + policyVersion:1 + policyHash:@"" + policySecrets:nil + forPeerWithID:A + error:NULL]; + XCTAssertEqual(TPResultOk, [self.model updateStableInfo:info forPeerWithID:A]); + + XCTAssertEqualObjects([self.model getStableInfoForPeerWithID:A], info); + + [self.model deletePeerWithID:A]; + XCTAssertFalse([self.model hasPeerWithID:A]); +} + +- (void)testCircleAccessors +{ + TPCircle *circle = [TPCircle circleWithIncludedPeerIDs:@[@"A, B"] excludedPeerIDs:nil]; + XCTAssertNil([self.model circleWithID:circle.circleID]); + [self.model registerCircle:circle]; + XCTAssertNotNil([self.model circleWithID:circle.circleID]); + [self.model deleteCircleWithID:circle.circleID]; + XCTAssertNil([self.model circleWithID:circle.circleID]); +} + +- (void)testLatestEpoch +{ + NSString *A = [self makePeerWithMachineID:@"aaa" modelID:@"iPhone" epoch:0 key:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb" modelID:@"iPhone" epoch:1 key:@"aaa"].peerID; + NSString *C = [self makePeerWithMachineID:@"ccc" modelID:@"iPhone" epoch:2 key:@"aaa"].peerID; + + TPCounter epoch = [self.model latestEpochAmongPeerIDs:[NSSet setWithArray:@[A, B, C]]]; + XCTAssertEqual(epoch, 2ULL); +} + +- (void)testPeerStatus +{ + NSString *A = [self makePeerWithMachineID:@"aaa" modelID:@"iPhone" epoch:0 key:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb" modelID:@"iPhone" epoch:0 key:@"bbb"].peerID; + NSString *C = [self makePeerWithMachineID:@"ccc" modelID:@"iPhone" epoch:0 key:@"ccc"].peerID; + NSString *D = [self makePeerWithMachineID:@"ddd" modelID:@"iPhone" epoch:1 key:@"ddd"].peerID; + NSString *E = [self makePeerWithMachineID:@"eee" modelID:@"iPhone" epoch:2 key:@"eee"].peerID; + + XCTAssertEqual([self.model statusOfPeerWithID:A], 0); + + [self.model advancePeerWithID:A addingPeerIDs:@[B, C] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssertEqual([self.model statusOfPeerWithID:A], 0); + + [self.model advancePeerWithID:B addingPeerIDs:@[A, C] removingPeerIDs:@[] createClique:nil]; + XCTAssertEqual([self.model statusOfPeerWithID:A], TPPeerStatusPartiallyReciprocated); + + [self.model advancePeerWithID:C addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + XCTAssertEqual([self.model statusOfPeerWithID:A], TPPeerStatusPartiallyReciprocated | TPPeerStatusFullyReciprocated); + + [self.model advancePeerWithID:C addingPeerIDs:@[] removingPeerIDs:@[A] createClique:nil]; + XCTAssertEqual([self.model statusOfPeerWithID:A], TPPeerStatusPartiallyReciprocated | TPPeerStatusExcluded); + + [self.model advancePeerWithID:A addingPeerIDs:@[] removingPeerIDs:@[] createClique:nil]; + XCTAssertEqual([self.model statusOfPeerWithID:A], TPPeerStatusExcluded); + + [self.model advancePeerWithID:B addingPeerIDs:@[D] removingPeerIDs:@[] createClique:nil]; + XCTAssertEqual([self.model statusOfPeerWithID:B], TPPeerStatusPartiallyReciprocated | TPPeerStatusOutdatedEpoch); + + [self.model advancePeerWithID:C addingPeerIDs:@[E] removingPeerIDs:@[] createClique:nil]; + [self.model advancePeerWithID:B addingPeerIDs:@[] removingPeerIDs:@[] createClique:nil]; + XCTAssertEqual([self.model statusOfPeerWithID:B], TPPeerStatusPartiallyReciprocated | TPPeerStatusOutdatedEpoch | TPPeerStatusAncientEpoch); +} + +- (void)testCalculateUnusedCircleIDs +{ + NSString *A = [self makePeerWithMachineID:@"aaa" modelID:@"iPhone" epoch:0 key:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb" modelID:@"iPhone" epoch:0 key:@"bbb"].peerID; + + [self.model advancePeerWithID:A addingPeerIDs:@[B] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique1"; + }]; + [self.model advancePeerWithID:B addingPeerIDs:@[B] removingPeerIDs:@[] createClique:nil]; + + NSSet* unused; + unused = [self.model calculateUnusedCircleIDs]; + XCTAssertEqualObjects(unused, [NSSet set]); + + NSString *circleID = [self.model getCircleForPeerWithID:A].circleID; + + [self.model advancePeerWithID:A addingPeerIDs:@[] removingPeerIDs:@[B] createClique:nil]; + + unused = [self.model calculateUnusedCircleIDs]; + XCTAssertEqualObjects(unused, [NSSet setWithObject:circleID]); +} + +- (void)testGetPeerIDsTrustedByPeerWithID +{ + NSString *A = [self makePeerWithMachineID:@"aaa" modelID:@"iPhone7,1" epoch:0 key:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb" modelID:@"iPhone6,2" epoch:0 key:@"bbb"].peerID; + NSString *C = [self makePeerWithMachineID:@"ccc" modelID:@"Watch1,1" epoch:0 key:@"ccc"].peerID; + [self makePeerWithMachineID:@"ddd" modelID:@"iPhone7,1" epoch:0 key:@"ddd"]; + + [self.model advancePeerWithID:A addingPeerIDs:@[B, C] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique1"; + }]; + + // Everyone can access WiFi. Only full peers can access SafariCreditCards + + NSSet* peerIDs; + NSSet* expected; + + peerIDs = [self.model getPeerIDsTrustedByPeerWithID:A toAccessView:@"WiFi" error:NULL]; + expected = [NSSet setWithArray:@[A, B, C]]; + XCTAssertEqualObjects(peerIDs, expected); + + peerIDs = [self.model getPeerIDsTrustedByPeerWithID:A toAccessView:@"SafariCreditCards" error:NULL]; + expected = [NSSet setWithArray:@[A, B]]; + XCTAssertEqualObjects(peerIDs, expected); +} + +- (void)testVectorClock +{ + NSString *A = [self makePeerWithMachineID:@"aaa"].peerID; + NSString *B = [self makePeerWithMachineID:@"bbb"].peerID; + NSString *C = [self makePeerWithMachineID:@"ccc"].peerID; + + [self.model advancePeerWithID:A addingPeerIDs:@[B] removingPeerIDs:@[] createClique:^NSString *{ + return @"clique1"; + }]; + [self.model advancePeerWithID:B addingPeerIDs:@[A] removingPeerIDs:@[] createClique:nil]; + + NSDictionary *dict; + NSDictionary *expected; + + dict = [self.model vectorClock]; + expected = @{ A: @4, B: @5, C: @3 }; + XCTAssertEqualObjects(dict, expected); + + [self.model advancePeerWithID:C addingPeerIDs:@[A] removingPeerIDs:@[B] createClique:nil]; + [self.model advancePeerWithID:A addingPeerIDs:@[] removingPeerIDs:@[] createClique:nil]; + [self.model advancePeerWithID:B addingPeerIDs:@[] removingPeerIDs:@[] createClique:nil]; + + dict = [self.model vectorClock]; + expected = @{ A: @7, B: @8, C: @6 }; + XCTAssertEqualObjects(dict, expected); +} + +- (void)testICycleApprovingPhoneWithNewPolicy +{ + NSString *phoneA = [self makePeerWithMachineID:@"phoneA" modelID:@"iPhone7,1" epoch:1 key:@"phoneA"].peerID; + NSString *phoneB = [self makePeerWithMachineID:@"phoneB" modelID:@"iPhone7,1" epoch:1 key:@"phoneB"].peerID; + NSString *icycle = [self makePeerWithMachineID:@"icycle" modelID:@"iCycle1,1" epoch:1 key:@"icycle"].peerID; + + TPCircle *circle; + + // phoneA establishes clique, trusts icycle + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:@[icycle] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[phoneA, icycle], @[])); + + // icycle trusts phoneA and phoneB + circle = [self.model advancePeerWithID:icycle addingPeerIDs:@[phoneA, phoneB] removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[phoneA, phoneB, icycle], @[])); + + // phoneA updates, and it doesn't know iCycles can approve phones, so it should ignore phoneB, so no change. + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[phoneA, icycle], @[])); + + // icycle presents a new policy that says iCycles can approve phones + TPPeerStableInfo *stableInfo = [self.model createStableInfoWithDictionary:@{} + policyVersion:self.policyDocV2.policyVersion + policyHash:self.policyDocV2.policyHash + policySecrets:nil + forPeerWithID:icycle + error:NULL]; + [self.model updateStableInfo:stableInfo forPeerWithID:icycle]; + + // phoneA updates again, sees the new policy that says iCycles can approve phones, and now trusts phoneB + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[phoneA, phoneB, icycle], @[])); +} + +- (void)testICycleApprovingPhoneWithRedactedPolicy +{ + NSString *phoneA = [self makePeerWithMachineID:@"phoneA" modelID:@"iPhone7,1" epoch:1 key:@"phoneA"].peerID; + NSString *phoneB = [self makePeerWithMachineID:@"phoneB" modelID:@"iPhone7,1" epoch:1 key:@"phoneB"].peerID; + NSString *icycle = [self makePeerWithMachineID:@"icycle" modelID:@"iCycle1,1" epoch:1 key:@"icycle"].peerID; + + TPCircle *circle; + + // phoneA establishes clique, trusts icycle + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:@[icycle] removingPeerIDs:nil createClique:^NSString *{ + return @"clique1"; + }]; + XCTAssert(circleEquals(circle, @[phoneA, icycle], @[])); + + // icycle trusts phoneA and phoneB + circle = [self.model advancePeerWithID:icycle addingPeerIDs:@[phoneA, phoneB] removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[phoneA, phoneB, icycle], @[])); + + // phoneA updates, and it doesn't know iCycles can approve phones, so it should ignore phoneB, so no change. + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[phoneA, icycle], @[])); + + // icycle presents a new policy that says iCycles can approve phones + TPPeerStableInfo *stableInfo = [self.model createStableInfoWithDictionary:@{} + policyVersion:self.policyDocV1.policyVersion + policyHash:self.policyDocV1.policyHash + policySecrets:@{ + self.secretName: self.secretKey + } + forPeerWithID:icycle + error:NULL]; + [self.model updateStableInfo:stableInfo forPeerWithID:icycle]; + + // phoneA updates again, sees the new policy that says iCycles can approve phones, and now trusts phoneB + circle = [self.model advancePeerWithID:phoneA addingPeerIDs:nil removingPeerIDs:nil createClique:nil]; + XCTAssert(circleEquals(circle, @[phoneA, phoneB, icycle], @[])); +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPPeerPermanentInfoTests.m b/keychain/trust/TrustedPeersTests/TPPeerPermanentInfoTests.m new file mode 100644 index 00000000..58618257 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPPeerPermanentInfoTests.m @@ -0,0 +1,209 @@ +/* + * 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 +#import +#import "TPDummySigningKey.h" + +@interface TPPeerPermanentInfoTests : XCTestCase +@property (nonatomic, strong) TPPeerPermanentInfo* info; +@end + +@implementation TPPeerPermanentInfoTests + +- (void)setUp +{ + NSData *keyData = [@"key123" dataUsingEncoding:NSUTF8StringEncoding]; + TPDummySigningKey *key = [[TPDummySigningKey alloc] initWithPublicKeyData:keyData]; + + self.info + = [TPPeerPermanentInfo permanentInfoWithMachineID:@"machine123" + modelID:@"iPhone1,1" + epoch:7 + trustSigningKey:key + peerIDHashAlgo:kTPHashAlgoSHA256 + error:NULL]; + XCTAssertNotNil(self.info); +} + +- (void)testRoundTrip +{ + TPCounter epoch = 7; + NSString *machineID = @"machine123"; + NSString *modelID = @"iPhone1,1"; + + NSData *keyData = [@"key123" dataUsingEncoding:NSUTF8StringEncoding]; + + TPPeerPermanentInfo *info2 + = [TPPeerPermanentInfo permanentInfoWithPeerID:self.info.peerID + permanentInfoPList:self.info.permanentInfoPList + permanentInfoSig:self.info.permanentInfoSig + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + + XCTAssertEqual(info2.epoch, epoch); + XCTAssert([info2.machineID isEqualToString:machineID]); + XCTAssert([info2.modelID isEqualToString:modelID]); + XCTAssert([info2.trustSigningKey.publicKey isEqualToData:keyData]); + + XCTAssert([info2.peerID isEqualToString:self.info.peerID]); + XCTAssert([info2.permanentInfoPList isEqualToData:self.info.permanentInfoPList]); + XCTAssert([info2.permanentInfoSig isEqualToData:self.info.permanentInfoSig]); +} + +- (void)testNonDictionary +{ + NSData *data = [NSPropertyListSerialization dataWithPropertyList:@[ @"foo", @"bar"] + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:NULL]; + TPPeerPermanentInfo *info + = [TPPeerPermanentInfo permanentInfoWithPeerID:@"x" + permanentInfoPList:data + permanentInfoSig:data + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info); +} + +- (void)testBadMachineID +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"machineID": @5 + }]; + TPPeerPermanentInfo *info + = [TPPeerPermanentInfo permanentInfoWithPeerID:@"x" + permanentInfoPList:data + permanentInfoSig:data + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info); +} + +- (void)testBadModelID +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"machineID": @"aaa", + @"modelID": @5, + }]; + TPPeerPermanentInfo *info + = [TPPeerPermanentInfo permanentInfoWithPeerID:@"x" + permanentInfoPList:data + permanentInfoSig:data + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info); +} + +- (void)testBadEpoch +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"machineID": @"aaa", + @"modelID": @"iPhone7,1", + @"epoch": @"five", + }]; + TPPeerPermanentInfo *info + = [TPPeerPermanentInfo permanentInfoWithPeerID:@"x" + permanentInfoPList:data + permanentInfoSig:data + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info); +} + +- (void)testBadTrustSigningKey +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"machineID": @"aaa", + @"modelID": @"iPhone7,1", + @"epoch": @5, + @"trustSigningKey": @"foo", + }]; + TPPeerPermanentInfo *info + = [TPPeerPermanentInfo permanentInfoWithPeerID:@"x" + permanentInfoPList:data + permanentInfoSig:data + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info); +} + +- (void)testBadTrustSigningKey2 +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"machineID": @"aaa", + @"modelID": @"iPhone7,1", + @"epoch": @5, + @"trustSigningKey": [NSData data], + }]; + TPPeerPermanentInfo *info + = [TPPeerPermanentInfo permanentInfoWithPeerID:@"x" + permanentInfoPList:data + permanentInfoSig:data + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info); +} + +- (void)testBadSignature +{ + TPPeerPermanentInfo *info2 + = [TPPeerPermanentInfo permanentInfoWithPeerID:self.info.peerID + permanentInfoPList:self.info.permanentInfoPList + permanentInfoSig:[NSData data] + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info2); +} + +- (void)testBadHashAlgo +{ + TPPeerPermanentInfo *info2 + = [TPPeerPermanentInfo permanentInfoWithPeerID:@"foo" + permanentInfoPList:self.info.permanentInfoPList + permanentInfoSig:self.info.permanentInfoSig + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info2); +} + +- (void)testBadPeerID +{ + TPPeerPermanentInfo *info2 + = [TPPeerPermanentInfo permanentInfoWithPeerID:@"SHA256:foo" + permanentInfoPList:self.info.permanentInfoPList + permanentInfoSig:self.info.permanentInfoSig + keyFactory:[TPDummySigningKeyFactory dummySigningKeyFactory]]; + XCTAssertNil(info2); +} + +- (void)testSigningKeyIsUnavailable +{ + NSData *keyData = [@"key123" dataUsingEncoding:NSUTF8StringEncoding]; + TPDummySigningKey *key = [[TPDummySigningKey alloc] initWithPublicKeyData:keyData]; + key.privateKeyIsAvailable = NO; + + NSError *error = nil; + TPPeerPermanentInfo *info + = [TPPeerPermanentInfo permanentInfoWithMachineID:@"machine123" + modelID:@"iPhone1,1" + epoch:7 + trustSigningKey:key + peerIDHashAlgo:kTPHashAlgoSHA256 + error:&error]; + XCTAssertNil(info); + XCTAssertNotNil(error); +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPPeerStableInfoTests.m b/keychain/trust/TrustedPeersTests/TPPeerStableInfoTests.m new file mode 100644 index 00000000..5c21166d --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPPeerStableInfoTests.m @@ -0,0 +1,131 @@ +/* + * 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 +#import +#import "TPDummySigningKey.h" + +@interface TPPeerStableInfoTests : XCTestCase + +@end + +@implementation TPPeerStableInfoTests + +- (void)testSigningKeyIsUnavailable +{ + NSData *keyData = [@"key123" dataUsingEncoding:NSUTF8StringEncoding]; + TPDummySigningKey *key = [[TPDummySigningKey alloc] initWithPublicKeyData:keyData]; + key.privateKeyIsAvailable = NO; + + NSError *error = nil; + TPPeerStableInfo *info + = [TPPeerStableInfo stableInfoWithDict:@{} + clock:1 + policyVersion:1 + policyHash:@"foo" + policySecrets:nil + trustSigningKey:key + error:&error]; + XCTAssertNil(info); + XCTAssertNotNil(error); +} + +- (void)testNonDictionary +{ + NSData *data = [NSPropertyListSerialization dataWithPropertyList:@[ @"foo", @"bar"] + format:NSPropertyListXMLFormat_v1_0 + options:0 + error:NULL]; + TPPeerStableInfo *info + = [TPPeerStableInfo stableInfoWithPListData:data + stableInfoSig:data]; + XCTAssertNil(info); +} + +- (void)testBadClock +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"clock": @"five" + }]; + TPPeerStableInfo *info + = [TPPeerStableInfo stableInfoWithPListData:data + stableInfoSig:data]; + XCTAssertNil(info); +} + +- (void)testBadPolicyVersion +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"clock": @5, + @"policyVersion": @"five", + }]; + TPPeerStableInfo *info + = [TPPeerStableInfo stableInfoWithPListData:data + stableInfoSig:data]; + XCTAssertNil(info); +} + +- (void)testBadPolicyHash +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"clock": @5, + @"policyVersion": @5, + @"policyHash": @5 + }]; + TPPeerStableInfo *info + = [TPPeerStableInfo stableInfoWithPListData:data + stableInfoSig:data]; + XCTAssertNil(info); +} + +- (void)testBadSecrets +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"clock": @5, + @"policyVersion": @5, + @"policyHash": @"foo", + @"policySecrets": @5 + }]; + TPPeerStableInfo *info + = [TPPeerStableInfo stableInfoWithPListData:data + stableInfoSig:data]; + XCTAssertNil(info); +} + +- (void)testBadSecretData +{ + NSData *data = [TPUtils serializedPListWithDictionary:@{ + @"clock": @5, + @"policyVersion": @5, + @"policyHash": @"foo", + @"policySecrets": @{ + @"foo": @5 + } + }]; + TPPeerStableInfo *info + = [TPPeerStableInfo stableInfoWithPListData:data + stableInfoSig:data]; + XCTAssertNil(info); +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPPeerTests.m b/keychain/trust/TrustedPeersTests/TPPeerTests.m new file mode 100644 index 00000000..c882c766 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPPeerTests.m @@ -0,0 +1,119 @@ +/* + * 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 +#import +#import "TPDummySigningKey.h" + +@interface TPPeerTests : XCTestCase + +@property (nonatomic, strong) TPPeer *peer; +@property (nonatomic, strong) TPDummySigningKey *goodKey; +@property (nonatomic, strong) TPDummySigningKey *badKey; + +@end + +@implementation TPPeerTests + +- (void)setUp +{ + NSData *goodKeyData = [@"goodKey" dataUsingEncoding:NSUTF8StringEncoding]; + self.goodKey = [[TPDummySigningKey alloc] initWithPublicKeyData:goodKeyData]; + + NSData *badKeyData = [@"badKey" dataUsingEncoding:NSUTF8StringEncoding]; + self.badKey = [[TPDummySigningKey alloc] initWithPublicKeyData:badKeyData]; + + TPPeerPermanentInfo *permanentInfo; + permanentInfo = [TPPeerPermanentInfo permanentInfoWithMachineID:@"A" + modelID:@"iPhone8,1" + epoch:1 + trustSigningKey:self.goodKey + peerIDHashAlgo:kTPHashAlgoSHA256 + error:NULL]; + self.peer = [[TPPeer alloc] initWithPermanentInfo:permanentInfo]; +} + +- (void)testBadDynamicInfoKey +{ + // Create a dynamicInfo with the wrong key + TPPeerDynamicInfo *dynamicInfo = [TPPeerDynamicInfo dynamicInfoWithCircleID:@"123" + clique:@"clique" + removals:0 + clock:1 + trustSigningKey:self.badKey + error:NULL]; + XCTAssertEqual(TPResultSignatureMismatch, [self.peer updateDynamicInfo:dynamicInfo]); +} + +- (void)testStableInfo +{ + TPPeerStableInfo *info1 = [TPPeerStableInfo stableInfoWithDict:@{ @"hello": @"world1" } + clock:1 + policyVersion:1 + policyHash:@"" + policySecrets:nil + trustSigningKey:self.goodKey + error:NULL]; + XCTAssertEqual(TPResultOk, [self.peer updateStableInfo:info1]); + + // Attempt update without advancing clock + TPPeerStableInfo *info2 = [TPPeerStableInfo stableInfoWithDict:@{ @"hello": @"world2" } + clock:1 + policyVersion:1 + policyHash:@"" + policySecrets:nil + trustSigningKey:self.goodKey + error:NULL]; + XCTAssertEqual(TPResultClockViolation, [self.peer updateStableInfo:info2]); + XCTAssertEqualObjects(self.peer.stableInfo, info1); + + // Advance + TPPeerStableInfo *info3 = [TPPeerStableInfo stableInfoWithDict:@{ @"hello": @"world3" } + clock:3 + policyVersion:1 + policyHash:@"" + policySecrets:nil + trustSigningKey:self.goodKey + error:NULL]; + XCTAssertEqual(TPResultOk, [self.peer updateStableInfo:info3]); + + // No change, should return OK + XCTAssertEqual(TPResultOk, [self.peer updateStableInfo:info3]); + + // Attempt replay + XCTAssertEqual(TPResultClockViolation, [self.peer updateStableInfo:info1]); + XCTAssertEqualObjects(self.peer.stableInfo, info3); + + // Attempt update with wrong key + TPPeerStableInfo *info4 = [TPPeerStableInfo stableInfoWithDict:@{ @"hello": @"world4" } + clock:4 + policyVersion:1 + policyHash:@"" + policySecrets:nil + trustSigningKey:self.badKey + error:NULL]; + XCTAssertEqual(TPResultSignatureMismatch, [self.peer updateStableInfo:info4]); + XCTAssertEqualObjects(self.peer.stableInfo, info3); +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPPolicyDocumentTests.m b/keychain/trust/TrustedPeersTests/TPPolicyDocumentTests.m new file mode 100644 index 00000000..59ceb183 --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPPolicyDocumentTests.m @@ -0,0 +1,68 @@ +/* + * 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 +#import + +@interface TPPolicyDocumentTests : XCTestCase + +@end + +@implementation TPPolicyDocumentTests + +- (void)testRoundTrip +{ + TPPolicyDocument *doc1 + = [TPPolicyDocument policyDocWithVersion:1 + modelToCategory:@[ + @{ @"prefix": @"iPhone", @"category": @"full" }, + @{ @"prefix": @"iPad", @"category": @"full" }, + @{ @"prefix": @"Mac", @"category": @"full" }, + @{ @"prefix": @"iMac", @"category": @"full" }, + @{ @"prefix": @"AppleTV", @"category": @"tv" }, + @{ @"prefix": @"Watch", @"category": @"watch" }, + ] + categoriesByView:@{ + @"WiFi": @[ @"full", @"tv", @"watch" ], + @"SafariCreditCards": @[ @"full" ], + @"PCSEscrow": @[ @"full" ] + } + introducersByCategory:@{ + @"full": @[ @"full" ], + @"tv": @[ @"full", @"tv" ], + @"watch": @[ @"full", @"watch" ] + } + redactions:@{ + @"foo": [@"bar" dataUsingEncoding:NSUTF8StringEncoding] + } + hashAlgo:kTPHashAlgoSHA256]; + + + TPPolicyDocument *doc2 = [TPPolicyDocument policyDocWithHash:doc1.policyHash pList:doc1.pList]; + XCTAssert([doc1 isEqualToPolicyDocument:doc2]); + + TPPolicyDocument *doc3 = [TPPolicyDocument policyDocWithHash:@"SHA256:foo" pList:doc1.pList]; + XCTAssertNil(doc3); +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPUtilsTests.m b/keychain/trust/TrustedPeersTests/TPUtilsTests.m new file mode 100644 index 00000000..0376bfbf --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPUtilsTests.m @@ -0,0 +1,39 @@ +/* + * 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 +#import + +@interface TPUtilsTests : XCTestCase + +@end + +@implementation TPUtilsTests + +- (void)testErrorHandling { + XCTAssertThrows([TPUtils serializedPListWithDictionary:@{ + @"foo": [NSSet setWithObject:@"bar"] + }]); +} + +@end diff --git a/keychain/trust/TrustedPeersTests/TPVoucherTests.m b/keychain/trust/TrustedPeersTests/TPVoucherTests.m new file mode 100644 index 00000000..de49c6cd --- /dev/null +++ b/keychain/trust/TrustedPeersTests/TPVoucherTests.m @@ -0,0 +1,103 @@ +/* + * 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 +#import +#import "TPDummySigningKey.h" + +@interface TPVoucherTests : XCTestCase + +@end + +@implementation TPVoucherTests + +- (void)testRoundTrip +{ + NSData *keyData = [@"key" dataUsingEncoding:NSUTF8StringEncoding]; + id key = [[TPDummySigningKey alloc] initWithPublicKeyData:keyData]; + + TPVoucher *voucher1 = [TPVoucher voucherWithBeneficiaryID:@"B" + sponsorID:@"A" + clock:1 + trustSigningKey:key + error:NULL]; + TPVoucher *voucher1b = [TPVoucher voucherWithPList:voucher1.voucherInfoPList + sig:voucher1.voucherInfoSig]; + + XCTAssertEqualObjects(voucher1, voucher1b); + XCTAssertEqual([voucher1 hash], [voucher1b hash]); + XCTAssert([voucher1 isEqual:voucher1]); + XCTAssert([voucher1 isEqualToVoucher:voucher1]); + XCTAssert(![voucher1 isEqual:@"foo"]); + + TPVoucher *voucher2 = [TPVoucher voucherWithBeneficiaryID:@"C" + sponsorID:@"A" + clock:1 + trustSigningKey:key + error:NULL]; + XCTAssertNotEqualObjects(voucher1, voucher2); +} + +- (void)testMalformed +{ + NSData *data = [@"foo" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertNil([TPVoucher voucherWithPList:data sig:data]); + + data = [TPUtils serializedPListWithDictionary:@{ + @"beneficiaryID": @[], + @"sponsorID": @"A", + @"clock": @1 + }]; + XCTAssertNil([TPVoucher voucherWithPList:data sig:data]); + + data = [TPUtils serializedPListWithDictionary:@{ + @"beneficiaryID": @"B", + @"sponsorID": @7, + @"clock": @1 + }]; + XCTAssertNil([TPVoucher voucherWithPList:data sig:data]); + + data = [TPUtils serializedPListWithDictionary:@{ + @"beneficiaryID": @"B", + @"sponsorID": @"A", + @"clock": @"foo" + }]; + XCTAssertNil([TPVoucher voucherWithPList:data sig:data]); +} + +- (void)testCannotSign +{ + NSData *keyData = [@"key" dataUsingEncoding:NSUTF8StringEncoding]; + TPDummySigningKey *key = [[TPDummySigningKey alloc] initWithPublicKeyData:keyData]; + key.privateKeyIsAvailable = NO; + + NSError *error = nil; + TPVoucher *voucher = [TPVoucher voucherWithBeneficiaryID:@"B" + sponsorID:@"A" + clock:1 + trustSigningKey:key + error:&error]; + XCTAssertNil(voucher); +} + +@end diff --git a/lib/SecArgParse.c b/lib/SecArgParse.c new file mode 100644 index 00000000..3a326ac6 --- /dev/null +++ b/lib/SecArgParse.c @@ -0,0 +1,362 @@ +/* + * 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@ + */ + +#define __STDC_WANT_LIB_EXT1__ 1 +#include + +#include "SecArgParse.h" + +// Trinary: +// If flag is set and argument is not, it has no_argument +// If flag is set and argument is set, it is optional_argument +// If flag is not set and argument is set, it is required_argument +// If flag is not set and argument is not set, what are you doing? There's no output. + +static int argument_status(struct argument* option) { + if(option == NULL) { + return no_argument; + } + return (!!(option->flag) && !(option->argument) ? no_argument : + (!!(option->flag) && !!(option->argument) ? optional_argument : + ( !(option->flag) && !!(option->argument) ? required_argument : + no_argument))); +} + +static bool fill_long_option_array(struct argument* options, size_t noptions, struct option long_options[], size_t nloptions) { + size_t i = 0; + size_t longi = 0; + + for(i = 0; i <= noptions; i++) { + if(longi >= nloptions) { + return false; + } + + if(options[i].longname) { + long_options[longi].name = options[i].longname; + long_options[longi].has_arg = argument_status(&options[i]); + long_options[longi].flag = options[i].flag; + long_options[longi].val = options[i].flagval; + longi++; + } + } + + if(longi >= nloptions) { + return false; + } + + long_options[longi].name = NULL; + long_options[longi].has_arg = 0; + long_options[longi].flag = 0; + long_options[longi].val = 0; + + return true; +} + +static bool fill_short_option_array(struct argument* options, size_t noptions, char* short_options, size_t nshort_options) { + size_t index = 0; + for(size_t i = 0; i < noptions; i++) { + if(options[i].shortname != '\0') { + if(index >= nshort_options) { + return false; + } + short_options[index] = options[i].shortname; + index += 1; + + if(argument_status(&options[i]) == required_argument) { + if(index >= nshort_options) { + return false; + } + short_options[index] = ':'; + index += 1; + } + } + } + short_options[index] = '\0'; + return true; +} + +static void trigger(struct argument option, char* argument) { + if(option.flag) { + *(option.flag) = option.flagval; + } + if(option.argument) { + asprintf(option.argument, "%.1048576s", argument); + } +} + +static size_t num_arguments(struct arguments* args) { + size_t n = 0; + + if(!args) { + return 0; + } + + struct argument* a = args->arguments; + // Make an all-zero struct + struct argument final = {}; + + // Only 1024 arguments allowed. + while(a && n < 1024 && (memcmp(a, &final, sizeof(struct argument)) != 0)) { + n++; + a++; + } + + return n; +} + +bool options_parse(int argc, char * const *argv, struct arguments* args) { + if(!args) { + return false; + } + bool success = false; + + struct arguments realargs; + realargs.programname = args->programname; + realargs.description = args->description; + size_t num_args = num_arguments(args); + size_t noptions = num_args + 1; + realargs.arguments = (struct argument*) malloc((noptions +1) * sizeof(struct argument)); // extra array slot for null array + + struct argument help = {.shortname = 'h', .longname="help", .description="show this help message and exit"}; + + realargs.arguments[0] = help; + // Adds one to include the null terminator struct! + for(size_t i = 0; i < num_args + 1; i++) { + realargs.arguments[i+1] = args->arguments[i]; + } + + struct option* long_options = (struct option*) malloc((noptions+1) * sizeof(struct option)); + size_t short_options_length = 2* noptions * sizeof(char) + 2; // 2: one for -h, one for the null terminator + char* short_options = (char*) malloc(short_options_length); + + fill_long_option_array(realargs.arguments, noptions, long_options, noptions); + fill_short_option_array(realargs.arguments, noptions, short_options, short_options_length); + + int c; + int option_index = 0; + while((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) { + // We have a short arg or an arg with an argument. Parse it. + if(c==0) { + if(option_index == 0) { + // This is the --help option + print_usage(&realargs); + exit(1); + } else { + struct option* long_option = &long_options[option_index]; + + for(size_t i = 0; i < noptions; i++) { + if(realargs.arguments[i].longname && strncmp(long_option->name, realargs.arguments[i].longname, strlen(realargs.arguments[i].longname)) == 0) { + trigger(realargs.arguments[i], optarg); + } + } + } + } else { + // Handle short name + if(c == 'h') { + // This is the --help option + print_usage(&realargs); + exit(1); + } + size_t i = 0; + for(i = 0; i < noptions; i++) { + if(realargs.arguments[i].shortname == c) { + trigger(realargs.arguments[i], optarg); + break; + } + } + if(i == noptions) { + return false; + } + } + } + + if(optind < argc) { + bool command_triggered = false; + size_t positional_argument_index = 0; + + for(int parg = optind; parg < argc; parg++) { + for(size_t i = 0; i < noptions; i++) { + if(realargs.arguments[i].command) { + if(strcmp(argv[parg], realargs.arguments[i].command) == 0) { + trigger(realargs.arguments[i], NULL); + command_triggered = true; + break; + } + } + } + + if(command_triggered) { + break; + } + + while(positional_argument_index < noptions && !realargs.arguments[positional_argument_index].positional_name) { + positional_argument_index++; + } + + if(positional_argument_index >= noptions) { + // no positional argument found to save + // explode + goto out; + } else { + if(realargs.arguments[positional_argument_index].argument) { + *(realargs.arguments[positional_argument_index].argument) = argv[parg]; + positional_argument_index++; + } + + } + } + } + + success = true; + +out: + free(realargs.arguments); + free(long_options); + free(short_options); + + return success; +} + +void print_usage(struct arguments* args) { + if(!args) { + return; + } + printf("usage: %s", args->programname ? args->programname : "command"); + + size_t num_args = num_arguments(args); + + // Print all short options + for(size_t i = 0; i < num_args; i++) { + if(args->arguments[i].shortname) { + printf(" [-%c", args->arguments[i].shortname); + + if(argument_status(&args->arguments[i]) != no_argument) { + printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg"); + } + + printf("]"); + } + } + + // Print all long args->arguments that don't have short args->arguments + for(size_t i = 0; i < num_args; i++) { + if(args->arguments[i].longname && !args->arguments[i].shortname) { + + printf(" [--%s", args->arguments[i].longname); + + if(argument_status(&args->arguments[i]) != no_argument) { + printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg"); + } + + printf("]"); + } + } + + // Print all commands + for(size_t i = 0; i < num_args; i++) { + if(args->arguments[i].command) { + printf(" [%s]", args->arguments[i].command); + } + } + + // Print all positional arguments + for(size_t i = 0; i < num_args; i++) { + if(args->arguments[i].positional_name) { + if(args->arguments[i].positional_optional) { + printf(" [<%s>]", args->arguments[i].positional_name); + } else { + printf(" <%s>", args->arguments[i].positional_name); + } + } + } + + printf("\n"); + + if(args->description) { + printf("\n%s\n", args->description); + } + + printf("\npositional arguments:\n"); + for(size_t i = 0; i < num_args; i++) { + if(args->arguments[i].positional_name) { + printf(" %-31s %s\n", args->arguments[i].positional_name, args->arguments[i].description); + } + } + + printf("\noptional arguments:\n"); + // List all short args->arguments + for(size_t i = 0; i < num_args; i++) { + if(args->arguments[i].shortname) { + if(!args->arguments[i].longname) { + + if(argument_status(&args->arguments[i]) != no_argument) { + printf(" -%c %-*s", args->arguments[i].shortname, 28, "arg"); + } else { + printf(" -%-30c", args->arguments[i].shortname); + } + + } else { + printf(" -%c", args->arguments[i].shortname); + + if(argument_status(&args->arguments[i]) != no_argument) { + printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg"); + } + + if(args->arguments[i].longname) { + if(argument_status(&args->arguments[i]) == no_argument) { + printf(", --%-*s", 28 - (int) strlen(args->arguments[i].argname ? args->arguments[i].argname : "arg"), args->arguments[i].longname); + } else { + printf(", --%s %-*s", args->arguments[i].longname, 28 -5 - (int) strlen(args->arguments[i].longname) - (int) strlen(args->arguments[i].argname ? args->arguments[i].argname : "arg"), "arg"); + } + } + } + + printf("%s\n", args->arguments[i].description); + } + } + + // List all long args->arguments + for(size_t i = 0; i < num_args; i++) { + if(args->arguments[i].longname && !args->arguments[i].shortname) { + if(argument_status(&args->arguments[i]) != no_argument) { + printf(" --%s %-*s %s\n", + args->arguments[i].longname, + 28 - (int) strlen(args->arguments[i].longname), + args->arguments[i].argname ? args->arguments[i].argname : "arg", + args->arguments[i].description); + } else { + printf(" --%-29s %s\n", args->arguments[i].longname, args->arguments[i].description); + } + } + } + + printf("\noptional commands:\n"); + // Print all commands + for(size_t i = 0; i < num_args; i++) { + if(args->arguments[i].command) { + printf(" %-30s %s\n", args->arguments[i].command, args->arguments[i].description); + } + } + + printf("\n"); +} diff --git a/lib/SecArgParse.h b/lib/SecArgParse.h new file mode 100644 index 00000000..ad5b4ab8 --- /dev/null +++ b/lib/SecArgParse.h @@ -0,0 +1,85 @@ +/* + * 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 SecArgParse_h +#define SecArgParse_h + +#include + +#include +#include +#include + +/* This is a poor simulacrum of python's argparse library. To use, create an arguments struct, including an array of + * argument elements, and pass the struct (along with argv+argc) to options_parse(). This is one-shot argument parsing: + * you must set pointers for *argument and *flag in each option to receive the results of the argument parsing. + * + * Currently does not support: + * non-string arguments + * default values + * relationships between arguments + * detecting meaningless option configurations + * + * Example arguments: + * static struct argument options[] = { + * { .shortname='p', .longname="perfcounters", .flag=&perfCounters, .flagval=true, .description="Print performance counters"}, + * { .longname="test", .flag=&test, .flagval=true, .description="test long option"}, + * { .command="resync", .flag=&resync, .flagval=true, .description="Initiate a resync"}, + * { .positional_name="positional", .positional_optional=false, .argument=&position, .description = "Positional argument" }, + * { .shortname='a', .longname="asdf", .argname="number", .argument=&asdf, .description = "Long arg with argument" }, + * }; + * + * static struct arguments args = { + * .programname="testctl", + * .description="Control and report", + * .arguments = options, + * }; + * + * Note: this library automatically adds a '-h' and a '--help' operation. Don't try to override this. + */ + +struct argument { + char shortname; + char* longname; + char* command; + char* positional_name; + bool positional_optional; + char* argname; + + char** argument; + int* flag; + int flagval; + char* description; +}; + +struct arguments { + char* programname; + char* description; + + struct argument* arguments; +}; + +bool options_parse(int argc, char * const *argv, struct arguments* args); +void print_usage(struct arguments* args); + +#endif /* SecArgParse_h */ diff --git a/libsecurity_smime/lib/CMSDecoder.c b/libsecurity_smime/lib/CMSDecoder.c new file mode 100644 index 00000000..73434598 --- /dev/null +++ b/libsecurity_smime/lib/CMSDecoder.c @@ -0,0 +1,997 @@ +/* + * Copyright (c) 2006-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@ + */ + +/* + * CMSDecoder.c - Interface for decoding CMS messages. + */ + +#include "CMSDecoder.h" +#include "CMSUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma mark --- Private types and definitions --- + +/* + * Decoder state. + */ +typedef enum { + DS_Init, /* between CMSDecoderCreate and CMSDecoderUpdateMessage */ + DS_Updating, /* between first CMSDecoderUpdateMessage and CMSDecoderFinalizeMessage */ + DS_Final /* CMSDecoderFinalizeMessage has been called */ +} CMSDecoderState; + +/* + * Caller's CMSDecoderRef points to one of these. + */ +struct _CMSDecoder { + CFRuntimeBase base; + CMSDecoderState decState; + SecCmsDecoderRef decoder; + CFDataRef detachedContent; + + /* + * The following are valid (and quiescent) after CMSDecoderFinalizeMessage(). + */ + SecCmsMessageRef cmsMsg; + Boolean wasEncrypted; /* valid after CMSDecoderFinalizeMessage() */ + SecCmsSignedDataRef signedData; /* if there is one... */ + /* only non-NULL if we found a signedData */ + size_t numSigners; + SecAsn1Oid *eContentType; + /* etc. */ +}; + +static void cmsDecoderInit(CFTypeRef dec); +static void cmsDecoderFinalize(CFTypeRef dec); + +static CFRuntimeClass cmsDecoderRuntimeClass = +{ + 0, /* version */ + "CMSDecoder", + cmsDecoderInit, + NULL, /* copy */ + cmsDecoderFinalize, + NULL, /* equal - just use pointer equality */ + NULL, /* hash, ditto */ + NULL, /* copyFormattingDesc */ + NULL /* copyDebugDesc */ +}; + +#pragma mark --- Private Routines --- + +static CFTypeID cmsDecoderTypeID = _kCFRuntimeNotATypeID; + +/* one time only class init, called via pthread_once() in CMSDecoderGetTypeID() */ +static void cmsDecoderClassInitialize(void) +{ + cmsDecoderTypeID = + _CFRuntimeRegisterClass((const CFRuntimeClass * const)&cmsDecoderRuntimeClass); +} + +/* init called out from _CFRuntimeCreateInstance() */ +static void cmsDecoderInit(CFTypeRef dec) +{ + char *start = ((char *)dec) + sizeof(CFRuntimeBase); + memset(start, 0, sizeof(struct _CMSDecoder) - sizeof(CFRuntimeBase)); +} + +/* + * Dispose of a CMSDecoder. Called out from CFRelease(). + */ +static void cmsDecoderFinalize( + CFTypeRef dec) +{ + CMSDecoderRef cmsDecoder = (CMSDecoderRef)dec; + if(cmsDecoder == NULL) { + return; + } + if(cmsDecoder->decoder != NULL) { + /* + * Normally this gets freed in SecCmsDecoderFinish - this is + * an error case. Unlike Finish, this calls SecCmsMessageDestroy. + */ + SecCmsDecoderDestroy(cmsDecoder->decoder); + cmsDecoder->cmsMsg = NULL; + } + CFRELEASE(cmsDecoder->detachedContent); + if(cmsDecoder->cmsMsg != NULL) { + SecCmsMessageDestroy(cmsDecoder->cmsMsg); + cmsDecoder->cmsMsg = NULL; + } +} + + +/* + * Given detached content and a valid (decoded) SignedData, digest the detached + * content. This occurs at the later of {CMSDecoderFinalizeMessage() finding a + * SignedData when already have detachedContent, or CMSDecoderSetDetachedContent() + * when we already have a SignedData). + */ +static OSStatus cmsDigestDetachedContent( + CMSDecoderRef cmsDecoder) +{ + ASSERT((cmsDecoder->signedData != NULL) && (cmsDecoder->detachedContent != NULL)); + + SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(cmsDecoder->signedData); + if(digestAlgorithms == NULL) { + return errSecUnknownFormat; + } + SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestAlgorithms); + if(digcx == NULL) { + return errSecAllocate; + } + + SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(cmsDecoder->detachedContent), + CFDataGetLength(cmsDecoder->detachedContent)); + OSStatus ortn = SecCmsSignedDataSetDigestContext(cmsDecoder->signedData, digcx); + SecCmsDigestContextDestroy(digcx); + + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsSignedDataSetDigestContext", ortn); + return ortn; + } + + return ortn; +} + +#pragma mark --- Start of Public API --- + +CFTypeID CMSDecoderGetTypeID(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + + if(cmsDecoderTypeID == _kCFRuntimeNotATypeID) { + pthread_once(&once, &cmsDecoderClassInitialize); + } + return cmsDecoderTypeID; +} + +/* + * Create a CMSDecoder. Result must eventually be freed via CFRelease(). + */ +OSStatus CMSDecoderCreate( + CMSDecoderRef *cmsDecoderOut) /* RETURNED */ +{ + CMSDecoderRef cmsDecoder = NULL; + + uint32_t extra = sizeof(*cmsDecoder) - sizeof(cmsDecoder->base); + cmsDecoder = (CMSDecoderRef)_CFRuntimeCreateInstance(NULL, CMSDecoderGetTypeID(), + extra, NULL); + if(cmsDecoder == NULL) { + return errSecAllocate; + } + cmsDecoder->decState = DS_Init; + *cmsDecoderOut = cmsDecoder; + return errSecSuccess; +} + +/* + * Feed raw bytes of the message to be decoded into the decoder. Can be called + * multiple times. + */ +OSStatus CMSDecoderUpdateMessage( + CMSDecoderRef cmsDecoder, + const void *msgBytes, + size_t msgBytesLen) +{ + if(cmsDecoder == NULL) { + return errSecParam; + } + + OSStatus ortn; + switch(cmsDecoder->decState) { + 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); + CSSM_PERROR("SecCmsDecoderCreate", ortn); + return ortn; + } + cmsDecoder->decState = DS_Updating; + break; + + case DS_Updating: + ASSERT(cmsDecoder->decoder != NULL); + break; + + case DS_Final: + /* Too late for another update */ + return errSecParam; + + default: + dprintf("CMSDecoderUpdateMessage: bad decState\n"); + return errSecInternalComponent; + } + + /* FIXME - CFIndex same size as size_t on 64bit? */ + ortn = SecCmsDecoderUpdate(cmsDecoder->decoder, msgBytes, (CFIndex)msgBytesLen); + if(ortn) { + ortn = cmsRtnToOSStatusDefault(ortn, errSecUnknownFormat); + CSSM_PERROR("SecCmsDecoderUpdate", ortn); + } + return ortn; +} + +/* + * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming; + * finish decoding the message. We parse the message as best we can, up to + * but not including verifying individual signerInfos. + */ +OSStatus CMSDecoderFinalizeMessage( + CMSDecoderRef cmsDecoder) +{ + if(cmsDecoder == NULL) { + return errSecParam; + } + if(cmsDecoder->decState != DS_Updating) { + return errSecParam; + } + ASSERT(cmsDecoder->decoder != NULL); + OSStatus ortn = SecCmsDecoderFinish(cmsDecoder->decoder, &cmsDecoder->cmsMsg); + cmsDecoder->decState = DS_Final; + + /* SecCmsDecoderFinish destroyed the decoder even on failure */ + cmsDecoder->decoder = NULL; + + if(ortn) { + ortn = cmsRtnToOSStatusDefault(ortn, errSecUnknownFormat); + CSSM_PERROR("SecCmsDecoderFinish", ortn); + return ortn; + } + + ASSERT(cmsDecoder->cmsMsg != NULL); + cmsDecoder->wasEncrypted = SecCmsMessageIsEncrypted(cmsDecoder->cmsMsg); + + /* Look for a SignedData */ + int numContentInfos = SecCmsMessageContentLevelCount(cmsDecoder->cmsMsg); + int dex; + for(dex=0; dexcmsMsg, dex); + SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci); + switch(tag) { + case SEC_OID_PKCS7_SIGNED_DATA: + cmsDecoder->signedData = + (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci); + /* dig down one more layer for eContentType */ + ci = SecCmsSignedDataGetContentInfo(cmsDecoder->signedData); + cmsDecoder->eContentType = SecCmsContentInfoGetContentTypeOID(ci); + break; + default: + break; + } + if(cmsDecoder->signedData != NULL) { + break; + } + + } + + /* minimal processing of optional signedData... */ + if(cmsDecoder->signedData != NULL) { + cmsDecoder->numSigners = (size_t) + SecCmsSignedDataSignerInfoCount(cmsDecoder->signedData); + if(cmsDecoder->detachedContent != NULL) { + /* time to calculate digests from detached content */ + ortn = cmsDigestDetachedContent(cmsDecoder); + } + } + return ortn; +} + +/* + * A signed CMS message optionally includes the data which was signed. If the + * message does not include the signed data, caller specifies the signed data + * (the "detached content") here. + * + * This can be called either before or after the actual decoding of the message + * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only + * restriction is that, if detached content is required, this function must + * be called befoere successfully ascertaining the signature status via + * CMSDecoderCopySignerStatus(). + */ +OSStatus CMSDecoderSetDetachedContent( + CMSDecoderRef cmsDecoder, + CFDataRef detachedContent) +{ + if((cmsDecoder == NULL) || (detachedContent == NULL)) { + return errSecParam; + } + cmsDecoder->detachedContent = detachedContent; + CFRetain(detachedContent); + + if(cmsDecoder->signedData != NULL) { + /* time to calculate digests from detached content */ + ASSERT(cmsDecoder->decState == DS_Final); + return cmsDigestDetachedContent(cmsDecoder); + } + return errSecSuccess; +} + +/* + * Obtain the detached content specified in CMSDecoderSetDetachedContent(). + * Returns a NULL detachedContent if no detached content has been specified. + * Caller must CFRelease() the result. + */ +OSStatus CMSDecoderCopyDetachedContent( + CMSDecoderRef cmsDecoder, + CFDataRef *detachedContent) /* RETURNED */ +{ + if((cmsDecoder == NULL) || (detachedContent == NULL)) { + return errSecParam; + } + if(cmsDecoder->detachedContent != NULL) { + CFRetain(cmsDecoder->detachedContent); + } + *detachedContent = cmsDecoder->detachedContent; + return errSecSuccess; +} + +/* + * Obtain the number of signers of a message. A result of zero indicates that + * the message was not signed. + */ +OSStatus CMSDecoderGetNumSigners( + CMSDecoderRef cmsDecoder, + size_t *numSigners) /* RETURNED */ +{ + if((cmsDecoder == NULL) || (numSigners == NULL)) { + return errSecParam; + } + if(cmsDecoder->decState != DS_Final) { + return errSecParam; + } + *numSigners = cmsDecoder->numSigners; + return errSecSuccess; +} + +/* + * Obtain the status of a CMS message's signature. A CMS message can + * be signed my multiple signers; this function returns the status + * associated with signer 'n' as indicated by the signerIndex parameter. + */ +OSStatus CMSDecoderCopySignerStatus( + CMSDecoderRef cmsDecoder, + size_t signerIndex, + CFTypeRef policyOrArray, + Boolean evaluateSecTrust, + CMSSignerStatus *signerStatus, /* optional; RETURNED */ + SecTrustRef *secTrust, /* optional; RETURNED */ + OSStatus *certVerifyResultCode) /* optional; RETURNED */ +{ + if((cmsDecoder == NULL) || (cmsDecoder->decState != DS_Final) || (!policyOrArray)) { + return errSecParam; + } + + /* initialize return values */ + if(signerStatus) { + *signerStatus = kCMSSignerUnsigned; + } + if(secTrust) { + *secTrust = NULL; + } + if(certVerifyResultCode) { + *certVerifyResultCode = 0; + } + + if(cmsDecoder->signedData == NULL) { + *signerStatus = kCMSSignerUnsigned; /* redundant, I know, but explicit */ + return errSecSuccess; + } + ASSERT(cmsDecoder->numSigners > 0); + if(signerIndex >= cmsDecoder->numSigners) { + *signerStatus = kCMSSignerInvalidIndex; + return errSecSuccess; + } + if(!SecCmsSignedDataHasDigests(cmsDecoder->signedData)) { + *signerStatus = kCMSSignerNeedsDetachedContent; + return errSecSuccess; + } + + /* + * OK, we should be able to verify this signerInfo. + * I think we have to do the SecCmsSignedDataVerifySignerInfo first + * in order get all the cert pieces into place before returning them + * to the caller. + */ + SecTrustRef theTrust = NULL; + OSStatus vfyRtn = SecCmsSignedDataVerifySignerInfo(cmsDecoder->signedData, + (int)signerIndex, + NULL, + policyOrArray, + &theTrust); + +#if SECTRUST_VERBOSE_DEBUG + syslog(LOG_ERR, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn); + if (policyOrArray) CFShow(policyOrArray); + if (theTrust) CFShow(theTrust); +#endif + + /* Subsequent errors to errOut: */ + + /* + * NOTE the smime lib did NOT evaluate that SecTrust - it only does + * SecTrustEvaluate() if we don't ask for a copy. + * + * FIXME deal with multitudes of status returns here...for now, proceed with + * obtaining components the caller wants and assume that a nonzero vfyRtn + * means "bad signature". + */ + OSStatus ortn = errSecSuccess; + SecTrustResultType secTrustResult; + OSStatus evalRtn, verifyStatus = errSecSuccess; + + if(secTrust != NULL) { + *secTrust = theTrust; + /* we'll release our reference at the end */ + if (theTrust) + CFRetain(theTrust); + } + SecCmsSignerInfoRef signerInfo = + SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex); + if(signerInfo == NULL) { + /* should never happen */ + ASSERT(0); + dprintf("CMSDecoderCopySignerStatus: no signerInfo\n"); + ortn = errSecInternalComponent; + goto errOut; + } + + /* now do the actual cert verify */ + if(evaluateSecTrust) { + evalRtn = SecTrustEvaluate(theTrust, &secTrustResult); + if(evalRtn) { + /* should never happen */ + CSSM_PERROR("SecTrustEvaluate", evalRtn); + dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n"); + ortn = errSecInternalComponent; + goto errOut; + } + switch(secTrustResult) { + case kSecTrustResultUnspecified: + /* cert chain valid, no special UserTrust assignments */ + case kSecTrustResultProceed: + /* cert chain valid AND user explicitly trusts this */ + break; + case kSecTrustResultDeny: + verifyStatus = errSecTrustSettingDeny; + break; + default: + { + verifyStatus = errSecNotTrusted; + break; + } + } /* switch(secTrustResult) */ + } /* evaluateSecTrust true */ + if(certVerifyResultCode != NULL) { + *certVerifyResultCode = verifyStatus; + } + + /* cook up global status based on vfyRtn and tpVfyStatus */ + if(signerStatus != NULL) { + if((vfyRtn == errSecSuccess) && (verifyStatus == errSecSuccess)) { + *signerStatus = kCMSSignerValid; + } + else if(vfyRtn != errSecSuccess) { + /* this could mean other things, but for now... */ + *signerStatus = kCMSSignerInvalidSignature; + } + else { + *signerStatus = kCMSSignerInvalidCert; + } + } +errOut: + CFRELEASE(theTrust); + return ortn; +} + +/* + * Obtain the email address of signer 'signerIndex' of a CMS message, if + * present. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerEmailAddress( + CMSDecoderRef cmsDecoder, + size_t signerIndex, + CFStringRef *signerEmailAddress) /* RETURNED */ +{ + if((cmsDecoder == NULL) || + (signerEmailAddress == NULL) || + (cmsDecoder->signedData == NULL) || /* not signed */ + (signerIndex >= cmsDecoder->numSigners) || /* index out of range */ + (cmsDecoder->decState != DS_Final)) { + return errSecParam; + } + + SecCmsSignerInfoRef signerInfo = + SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex); + if(signerInfo == NULL) { + /* should never happen */ + ASSERT(0); + dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n"); + return errSecInternalComponent; + } + + /* + * This is leaking memory in libsecurityKeychain per Radar 4412699. + */ + *signerEmailAddress = SecCmsSignerInfoGetSignerEmailAddress(signerInfo); + return errSecSuccess; +} + +/* + * Obtain the certificate of signer 'signerIndex' of a CMS message, if + * present. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerCert( + CMSDecoderRef cmsDecoder, + size_t signerIndex, + SecCertificateRef *signerCert) /* RETURNED */ +{ + if((cmsDecoder == NULL) || + (signerCert == NULL) || + (cmsDecoder->signedData == NULL) || /* not signed */ + (signerIndex >= cmsDecoder->numSigners) || /* index out of range */ + (cmsDecoder->decState != DS_Final)) { + return errSecParam; + } + + SecCmsSignerInfoRef signerInfo = + SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex); + if(signerInfo == NULL) { + /* should never happen */ + ASSERT(0); + dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n"); + return errSecInternalComponent; + } + *signerCert = SecCmsSignerInfoGetSigningCertificate(signerInfo, NULL); + /* libsecurity_smime does NOT retain that */ + if(*signerCert == NULL) { + /* should never happen */ + ASSERT(0); + dprintf("CMSDecoderCopySignerCertificate: no signerCert\n"); + return errSecInternalComponent; + } + CFRetain(*signerCert); + return errSecSuccess; +} + +/* + * Determine whether a CMS message was encrypted, and if so, whether we were + * able to decrypt it. + */ +OSStatus CMSDecoderIsContentEncrypted( + CMSDecoderRef cmsDecoder, + Boolean *wasEncrypted) +{ + if((cmsDecoder == NULL) || (wasEncrypted == NULL)) { + return errSecParam; + } + if(cmsDecoder->decState != DS_Final) { + return errSecParam; + } + *wasEncrypted = cmsDecoder->wasEncrypted; + return errSecSuccess; +} + +/* + * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if + * present. + */ +OSStatus CMSDecoderCopyEncapsulatedContentType( + CMSDecoderRef cmsDecoder, + CFDataRef *eContentType) /* RETURNED */ +{ + if((cmsDecoder == NULL) || (eContentType == NULL)) { + return errSecParam; + } + if(cmsDecoder->decState != DS_Final) { + return errSecParam; + } + if(cmsDecoder->signedData == NULL) { + *eContentType = NULL; + } + else { + SecAsn1Oid *ecOid = cmsDecoder->eContentType; + *eContentType = CFDataCreate(NULL, ecOid->Data, ecOid->Length); + } + return errSecSuccess; +} + +/* + * Obtain an array of all of the certificates in a message. Elements of the + * returned array are SecCertificateRefs. The caller must CFRelease the returned + * array. + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopyAllCerts( + CMSDecoderRef cmsDecoder, + CFArrayRef *certs) /* RETURNED */ +{ + if((cmsDecoder == NULL) || (certs == NULL)) { + return errSecParam; + } + if(cmsDecoder->decState != DS_Final) { + return errSecParam; + } + if(cmsDecoder->signedData == NULL) { + /* message wasn't signed */ + *certs = NULL; + return errSecSuccess; + } + + /* NULL_terminated array of CSSM_DATA ptrs */ + SecAsn1Item **cssmCerts = SecCmsSignedDataGetCertificateList(cmsDecoder->signedData); + if((cssmCerts == NULL) || (*cssmCerts == NULL)) { + *certs = NULL; + return errSecSuccess; + } + + CFMutableArrayRef allCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + SecAsn1Item **cssmCert; + for(cssmCert=cssmCerts; *cssmCert!=NULL; cssmCert++) { + SecCertificateRef cfCert = SecCertificateCreateWithBytes(NULL, (*cssmCert)->Data, (*cssmCert)->Length); + if(!cfCert) { + CFRelease(allCerts); + return errSecDecode; + } + CFArrayAppendValue(allCerts, cfCert); + /* the array holds the only needed refcount */ + CFRelease(cfCert); + } + *certs = allCerts; + return errSecSuccess; +} + +/* + * Obtain the actual message content (payload), if any. If the message was + * signed with detached content this will return NULL. + * Caller must CFRelease the result. + */ +OSStatus CMSDecoderCopyContent( + CMSDecoderRef cmsDecoder, + CFDataRef *content) /* RETURNED */ +{ + if((cmsDecoder == NULL) || (content == NULL)) { + return errSecParam; + } + if(cmsDecoder->decState != DS_Final) { + return errSecParam; + } + if(cmsDecoder->cmsMsg == NULL) { + /* Hmmm....looks like the finalize call failed */ + return errSecParam; + } + const SecAsn1Item *odata = SecCmsMessageGetContent(cmsDecoder->cmsMsg); + if((odata == NULL) || (odata->Length == 0)) { + /* i.e., detached content */ + *content = NULL; + return errSecSuccess; + } + *content = CFDataCreate(NULL, (const UInt8 *)odata->Data, odata->Length); + return errSecSuccess; +} + +#pragma mark --- SPI declared in CMSPrivate.h --- + +/* + * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended + * to be called after decoding the message (i.e., after + * CMSDecoderFinalizeMessage() to gain finer access to the contents of the + * SecCmsMessageRef than is otherwise available via the CMSDecoder interface. + * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been + * called. + * + * The CMSDecoder retains ownership of the returned SecCmsMessageRef. + */ +OSStatus CMSDecoderGetCmsMessage( + CMSDecoderRef cmsDecoder, + SecCmsMessageRef *cmsMessage) /* RETURNED */ +{ + if((cmsDecoder == NULL) || (cmsMessage == NULL)) { + return errSecParam; + } + /* any state, whether we have a msg or not is OK */ + *cmsMessage = cmsDecoder->cmsMsg; + return errSecSuccess; +} + +/* + * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef. + * If this is called, it must be called before the first call to + * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the + * incoming SecCmsDecoderRef. + */ +OSStatus CMSDecoderSetDecoder( + CMSDecoderRef cmsDecoder, + SecCmsDecoderRef decoder) +{ + if((cmsDecoder == NULL) || (decoder == NULL)) { + return errSecParam; + } + switch(cmsDecoder->decState) { + case DS_Init: + ASSERT(cmsDecoder->decoder == NULL); + cmsDecoder->decoder = decoder; + cmsDecoder->decState = DS_Updating; + return errSecSuccess; + case DS_Updating: + case DS_Final: + return errSecParam; + } + return errSecSuccess; +} + +/* + * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef. + * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor + * CMSDecoderUpdateMessage() has been called. + * The CMSDecoderRef retains ownership of the SecCmsDecoderRef. + */ +OSStatus CMSDecoderGetDecoder( + CMSDecoderRef cmsDecoder, + SecCmsDecoderRef *decoder) /* RETURNED */ +{ + if((cmsDecoder == NULL) || (decoder == NULL)) { + return errSecParam; + } + /* any state, whether we have a decoder or not is OK */ + *decoder = cmsDecoder->decoder; + return errSecSuccess; +} + +/* + * Obtain the signing time of signer 'signerIndex' of a CMS message, if + * present. This is an unauthenticate time, although it is part of the + * signed attributes of the message. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerSigningTime( + CMSDecoderRef cmsDecoder, + size_t signerIndex, /* usually 0 */ + CFAbsoluteTime *signingTime) /* RETURNED */ +{ + OSStatus status = errSecParam; + SecCmsMessageRef cmsg; + SecCmsSignedDataRef signedData = NULL; + int numContentInfos = 0; + + require(cmsDecoder && signingTime, xit); + require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit); + numContentInfos = SecCmsMessageContentLevelCount(cmsg); + for (int dex = 0; !signedData && dex < numContentInfos; dex++) + { + SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex); + SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci); + if (tag == SEC_OID_PKCS7_SIGNED_DATA) + if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) { + SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex); + if (signerInfo) + { + status = SecCmsSignerInfoGetSigningTime(signerInfo, signingTime); + break; + } + } + } +xit: + return status; +} + +#if TIMESTAMPING_SUPPORTED +/* + * Obtain the timestamp of signer 'signerIndex' of a CMS message, if + * present. This timestamp is an authenticated timestamp provided by + * a timestamping authority. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ + +OSStatus CMSDecoderCopySignerTimestamp( + CMSDecoderRef cmsDecoder, + size_t signerIndex, /* usually 0 */ + CFAbsoluteTime *timestamp) /* RETURNED */ +{ + return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder, NULL, signerIndex, timestamp); +} + +OSStatus CMSDecoderCopySignerTimestampWithPolicy( + CMSDecoderRef cmsDecoder, + CFTypeRef timeStampPolicy, + size_t signerIndex, /* usually 0 */ + CFAbsoluteTime *timestamp) /* RETURNED */ +{ + OSStatus status = errSecParam; + SecCmsMessageRef cmsg; + SecCmsSignedDataRef signedData = NULL; + int numContentInfos = 0; + + require(cmsDecoder && timestamp, xit); + require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit); + numContentInfos = SecCmsMessageContentLevelCount(cmsg); + for (int dex = 0; !signedData && dex < numContentInfos; dex++) + { + SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex); + SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci); + if (tag == SEC_OID_PKCS7_SIGNED_DATA) + if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) { + SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex); + if (signerInfo) + { + status = SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo, timeStampPolicy, timestamp); + break; + } + } + } + +xit: + return status; +} + +/* + * Obtain an array of the certificates in a timestamp response. Elements of the + * returned array are SecCertificateRefs. The caller must CFRelease the returned + * array. This timestamp is an authenticated timestamp provided by + * a timestamping authority. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. It returns + * errSecItemNotFound if no certificates were found. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerTimestampCertificates( + CMSDecoderRef cmsDecoder, + size_t signerIndex, /* usually 0 */ + CFArrayRef *certificateRefs) /* RETURNED */ +{ + OSStatus status = errSecParam; + SecCmsMessageRef cmsg = NULL; + SecCmsSignedDataRef signedData = NULL; + int numContentInfos = 0; + CFIndex tsn = 0; + bool good = false; + + require(cmsDecoder && certificateRefs, xit); + require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit); + numContentInfos = SecCmsMessageContentLevelCount(cmsg); + for (int dex = 0; !signedData && dex < numContentInfos; dex++) + { + SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex); + SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci); + if (tag == SEC_OID_PKCS7_SIGNED_DATA) + if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) { + SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex); + if (signerInfo) + { + CFArrayRef certList = SecCmsSignerInfoGetTimestampCertList(signerInfo); + require_action(certList, xit, status = errSecItemNotFound); + CFMutableArrayRef certs = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(certList), certList); + + if(certs){ + //reorder certificates: + tsn = CFArrayGetCount(certs); + good = tsn > 0 && SecIsAppleTrustAnchor((SecCertificateRef)CFArrayGetValueAtIndex(certs, tsn-1), 0); + + if ( good == false ) + { + //change TS certificate ordering. + for (CFIndex n = 0; n < tsn; n++) + { + SecCertificateRef tsRoot = (SecCertificateRef)CFArrayGetValueAtIndex(certs, n); + if (tsRoot) + if ((good = SecIsAppleTrustAnchor(tsRoot, 0))) { + CFArrayExchangeValuesAtIndices(certs, n, tsn-1); + break; + } + } + } + + *certificateRefs = CFArrayCreateCopy(kCFAllocatorDefault, certs); + CFRelease(certs); + status = errSecSuccess; + } + break; + } + } + } + + +xit: + return status; +} +#endif + +/* + * Obtain the Hash Agility attribute value of signer 'signerIndex' + * of a CMS message, if present. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerAppleCodesigningHashAgility( + CMSDecoderRef cmsDecoder, + size_t signerIndex, /* usually 0 */ + CFDataRef CF_RETURNS_RETAINED *hashAgilityAttrValue) /* RETURNED */ +{ + OSStatus status = errSecParam; + SecCmsMessageRef cmsg; + SecCmsSignedDataRef signedData = NULL; + int numContentInfos = 0; + CFDataRef returnedValue = NULL; + + require(cmsDecoder && hashAgilityAttrValue, xit); + require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit); + numContentInfos = SecCmsMessageContentLevelCount(cmsg); + for (int dex = 0; !signedData && dex < numContentInfos; dex++) + { + SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex); + SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci); + if (tag == SEC_OID_PKCS7_SIGNED_DATA) + if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) { + SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex); + if (signerInfo) + { + status = SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo, &returnedValue); + break; + } + } + } +xit: + if (status == errSecSuccess && returnedValue) { + *hashAgilityAttrValue = (CFDataRef) CFRetain(returnedValue); + } else { + *hashAgilityAttrValue = NULL; + } + return status; +} diff --git a/libsecurity_smime/lib/CMSDecoder.h b/libsecurity_smime/lib/CMSDecoder.h new file mode 100644 index 00000000..8355d3ce --- /dev/null +++ b/libsecurity_smime/lib/CMSDecoder.h @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2006-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@ + */ + +/* + * CMSDecoder.h - decode, decrypt, and/or verify signatures of messages in the + * Cryptographic Message Syntax (CMS), per RFC 3852. + * + * See CMSEncoder.h for general information about CMS messages. + */ + +#ifndef _CMS_DECODER_H_ +#define _CMS_DECODER_H_ + +#include +#include +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN + +/* + * Opaque reference to a CMS decoder object. + * This is a CF object, with standard CF semantics; dispose of it + * with CFRelease(). + */ +typedef struct CF_BRIDGED_TYPE(id) _CMSDecoder *CMSDecoderRef; + +CFTypeID CMSDecoderGetTypeID(void); + +/* + * Status of signature and signer information in a signed message. + */ +typedef CF_ENUM(int32_t, CMSSignerStatus) { + kCMSSignerUnsigned = 0, /* message was not signed */ + kCMSSignerValid, /* message was signed and signature verify OK */ + kCMSSignerNeedsDetachedContent, /* message was signed but needs detached content + * to verify */ + kCMSSignerInvalidSignature, /* message was signed but had a signature error */ + kCMSSignerInvalidCert, /* message was signed but an error occurred in verifying + * the signer's certificate */ + kCMSSignerInvalidIndex /* specified signer index out of range */ +}; + +/* + * Create a CMSDecoder. Result must eventually be freed via CFRelease(). + */ +OSStatus CMSDecoderCreate(CMSDecoderRef * __nonnull CF_RETURNS_RETAINED cmsDecoderOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Feed raw bytes of the message to be decoded into the decoder. Can be called + * multiple times. + * Returns errSecUnknownFormat upon detection of improperly formatted CMS + * message. + */ +OSStatus CMSDecoderUpdateMessage( + CMSDecoderRef cmsDecoder, + const void *msgBytes, + size_t msgBytesLen) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming; + * finish decoding the message. + * Returns errSecUnknownFormat upon detection of improperly formatted CMS + * message. + */ +OSStatus CMSDecoderFinalizeMessage(CMSDecoderRef cmsDecoder) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * A signed CMS message optionally includes the data which was signed. If the + * message does not include the signed data, caller specifies the signed data + * (the "detached content") here. + * + * This can be called either before or after the actual decoding of the message + * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only + * restriction is that, if detached content is required, this function must + * be called befoere successfully ascertaining the signature status via + * CMSDecoderCopySignerStatus(). + */ +OSStatus CMSDecoderSetDetachedContent( + CMSDecoderRef cmsDecoder, + CFDataRef detachedContent) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the detached content specified in CMSDecoderSetDetachedContent(). + * Returns a NULL detachedContent if no detached content has been specified. + * Caller must CFRelease() the result. + */ +OSStatus CMSDecoderCopyDetachedContent( + CMSDecoderRef cmsDecoder, + CFDataRef * __nonnull CF_RETURNS_RETAINED detachedContentOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the number of signers of a message. A result of zero indicates that + * the message was not signed. + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderGetNumSigners( + CMSDecoderRef cmsDecoder, + size_t *numSignersOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the status of a CMS message's signature. A CMS message can + * be signed my multiple signers; this function returns the status + * associated with signer 'n' as indicated by the signerIndex parameter. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + * + * Note that signature and certificate verification of a decoded message + * does *not* occur until this routine is called. + * + * All returned values are optional - pass NULL if you don't need a + * particular parameter. + * + * Note that errors like "bad signature" and "bad cert" do NOT cause this + * routine to return a nonzero error status itself; such errors are reported + * in the various out parameters, listed below. + * + * Inputs: + * ------- + * cmsDecoder : a CMSDecoder which has successfully performed a + * CMSDecoderFinalizeMessage(). + * signerIndex : indicates which of 'n' signers is being examined. + * Range is 0...(numSigners-1). + * policyOrArray : Either a SecPolicyRef or a CFArray of them. + * These policies are used to verify the signer's certificate. + * evaluateSecTrust : When TRUE, causes the SecTrust oebject created for the + * evaluation of the signer cert to actually be evaluated + * via SecTrustEvaluate(). When FALSE, the caller performs + * the SecTrustEvaluate() operation on the SecTrust object + * returned via the secTrust out parameter. + * NOTE: it is hazardous and not recommended to pass in FALSE + * for the evaluateSecTrust parameter as well as NULL for the + * secTrust out parameter, since no evaluation of the signer + * cert can occur in that situation. + * + * Outputs: + * -------- + * signerStatusOut -- An enum indicating the overall status. + * kCMSSignerUnsigned : message was not signed. + * kCMSSignerValid : both signature and signer certificate verified OK. + * kCMSSignerNeedsDetachedContent : a call to CMSDecoderSetDetachedContent() + * is required to ascertain the signature status. + * kCMSSignerInvalidSignature : bad signature. + * kCMSSignerInvalidCert : an error occurred verifying the signer's certificate. + * Further information available via the secTrust and + * certVerifyResultCode parameters. This will never be + * returned if evaluateSecTrust is FALSE. + * kCMSSignerInvalidIndex : specified signerIndex is larger than the number of + * signers (minus 1). + * + * secTrustOut -- The SecTrust object used to verify the signer's + * certificate. Caller must CFRelease this. + * certVerifyResultCodeOut -- The result of the certificate verification. If + * the evaluateSecTrust argument is set to FALSE on + * input, this out parameter is undefined on return. + * + * The certVerifyResultCode value can indicate a large number of errors; some of + * the most common and interesting errors are: + * + * CSSMERR_TP_INVALID_ANCHOR_CERT : The cert was verified back to a + * self-signed (root) cert which was present in the message, but + * that root cert is not a known, trusted root cert. + * CSSMERR_TP_NOT_TRUSTED: The cert could not be verified back to + * a root cert. + * CSSMERR_TP_VERIFICATION_FAILURE: A root cert was found which does + * not self-verify. + * CSSMERR_TP_VERIFY_ACTION_FAILED: Indicates a failure of the requested + * policy action. + * CSSMERR_TP_INVALID_CERTIFICATE: Indicates a bad leaf cert. + * CSSMERR_TP_CERT_EXPIRED: A cert in the chain was expired at the time of + * verification. + * CSSMERR_TP_CERT_NOT_VALID_YET: A cert in the chain was not yet valie at + * the time of verification. + */ +OSStatus CMSDecoderCopySignerStatus( + CMSDecoderRef cmsDecoder, + size_t signerIndex, + CFTypeRef policyOrArray, + Boolean evaluateSecTrust, + CMSSignerStatus * __nullable signerStatusOut, /* optional; RETURNED */ + SecTrustRef * __nullable CF_RETURNS_RETAINED secTrustOut, /* optional; RETURNED */ + OSStatus * __nullable certVerifyResultCodeOut) /* optional; RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the email address of signer 'signerIndex' of a CMS message, if + * present. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerEmailAddress( + CMSDecoderRef cmsDecoder, + size_t signerIndex, + CFStringRef * __nonnull CF_RETURNS_RETAINED signerEmailAddressOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the certificate of signer 'signerIndex' of a CMS message, if + * present. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerCert( + CMSDecoderRef cmsDecoder, + size_t signerIndex, + SecCertificateRef * __nonnull CF_RETURNS_RETAINED signerCertOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Determine whether a CMS message was encrypted. Returns TRUE if so, FALSE if not. + * Note that if the message was encrypted, and the decoding succeeded, (i.e., + * CMSDecoderFinalizeMessage() returned errSecSuccess), then the message was successfully + * decrypted. + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderIsContentEncrypted( + CMSDecoderRef cmsDecoder, + Boolean *isEncryptedOut) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if + * present. If the message was not signed this will return NULL. + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + * The returned OID's data is in the same format as a CSSM_OID; i.e., it's + * the encoded content of the OID, not including the tag and length bytes. + */ +OSStatus CMSDecoderCopyEncapsulatedContentType( + CMSDecoderRef cmsDecoder, + CFDataRef * __nonnull CF_RETURNS_RETAINED eContentTypeOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain an array of all of the certificates in a message. Elements of the + * returned array are SecCertificateRefs. The caller must CFRelease the returned + * array. If a message does not contain any certificates (which is the case for + * a message which is encrypted but not signed), the returned *certs value + * is NULL. The function will return errSecSuccess in this case. + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopyAllCerts( + CMSDecoderRef cmsDecoder, + CFArrayRef * __nonnull CF_RETURNS_RETAINED certsOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the actual message content (payload), if any. If the message was + * signed with detached content this will return NULL. + * Caller must CFRelease the result. + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopyContent( + CMSDecoderRef cmsDecoder, + CFDataRef * __nonnull CF_RETURNS_RETAINED contentOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the signing time of signer 'signerIndex' of a CMS message, if + * present. This is an unauthenticate time, although it is part of the + * signed attributes of the message. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerSigningTime( + CMSDecoderRef cmsDecoder, + size_t signerIndex, + CFAbsoluteTime *signingTime) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_11_0); + +#if TIMESTAMPING_SUPPORTED +/* + * Obtain the timestamp of signer 'signerIndex' of a CMS message, if + * present. This timestamp is an authenticated timestamp provided by + * a timestamping authority. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerTimestamp( + CMSDecoderRef cmsDecoder, + size_t signerIndex, + CFAbsoluteTime *timestamp) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_NA); + +/* + * Obtain the timestamp of signer 'signerIndex' of a CMS message, if + * present. This timestamp is an authenticated timestamp provided by + * a timestamping authority. Use the policy provided as a parameter + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerTimestampWithPolicy( + CMSDecoderRef cmsDecoder, + CFTypeRef __nullable timeStampPolicy, + size_t signerIndex, /* usually 0 */ + CFAbsoluteTime *timestamp) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_NA); + +/* + * Obtain an array of the certificates in a timestamp response. Elements of the + * returned array are SecCertificateRefs. The caller must CFRelease the returned + * array. This timestamp is an authenticated timestamp provided by + * a timestamping authority. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. It returns + * errSecItemNotFound if no certificates were found. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerTimestampCertificates( + CMSDecoderRef cmsDecoder, + size_t signerIndex, /* usually 0 */ + CFArrayRef * __nonnull CF_RETURNS_RETAINED certificateRefs) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_NA); +#endif + +/* + * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended + * to be called after decoding the message (i.e., after + * CMSDecoderFinalizeMessage() to gain finer access to the contents of the + * SecCmsMessageRef than is otherwise available via the CMSDecoder interface. + * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been + * called. + * + * The CMSDecoder retains ownership of the returned SecCmsMessageRef. + */ +OSStatus CMSDecoderGetCmsMessage( + CMSDecoderRef cmsDecoder, + SecCmsMessageRef _Nullable * _Nonnull cmsMessage); /* RETURNED */ + + +/* + * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef. + * If this is called, it must be called before the first call to + * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the + * incoming SecCmsDecoderRef. + */ +OSStatus CMSDecoderSetDecoder( + CMSDecoderRef cmsDecoder, + SecCmsDecoderRef decoder); + +/* + * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef. + * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor + * CMSDecoderUpdateMessage() has been called. + * The CMSDecoderRef retains ownership of the SecCmsDecoderRef. + */ +OSStatus CMSDecoderGetDecoder( + CMSDecoderRef cmsDecoder, + SecCmsDecoderRef _Nullable * _Nonnull decoder); /* RETURNED */ + +/* + * Obtain the Hash Agility attribute value of signer 'signerIndex' + * of a CMS message, if present. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSDecoderFinalizeMessage() is called. + */ +OSStatus CMSDecoderCopySignerAppleCodesigningHashAgility( + CMSDecoderRef cmsDecoder, + size_t signerIndex, /* usually 0 */ + CFDataRef CF_RETURNS_RETAINED * _Nonnull hashAgilityAttrValue); /* RETURNED */ + + +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* _CMS_DECODER_H_ */ + diff --git a/libsecurity_smime/lib/CMSEncoder.c b/libsecurity_smime/lib/CMSEncoder.c new file mode 100644 index 00000000..c376a834 --- /dev/null +++ b/libsecurity_smime/lib/CMSEncoder.c @@ -0,0 +1,1493 @@ +/* + * Copyright (c) 2006-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@ + */ + +/* + * CMSEncoder.c - encode, sign, and/or encrypt CMS messages. + */ + +#include "CMSEncoder.h" +#include "CMSUtils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if TIMESTAMPING_SUPPORTED +#include +#endif + +#pragma mark --- Private types and definitions --- + +/* + * Encoder state. + */ +typedef enum { + ES_Init, /* between CMSEncoderCreate and earlier of CMSEncoderUpdateContent + * and CMSEncodeGetCmsMessage */ + ES_Msg, /* created cmsMsg in CMSEncodeGetCmsMessage, but no encoder yet */ + ES_Updating, /* between first CMSEncoderUpdateContent and CMSEncoderCopyEncodedContent */ + ES_Final /* CMSEncoderCopyEncodedContent has been called */ +} CMSEncoderState; + +/* + * High-level operation: what are we doing? + */ +typedef enum { + EO_Sign, + EO_Encrypt, + EO_SignEncrypt +} CMSEncoderOp; + +/* + * Caller's CMSEncoderRef points to one of these. + */ +struct _CMSEncoder { + CFRuntimeBase base; + CMSEncoderState encState; + CMSEncoderOp op; + Boolean detachedContent; + SecAsn1Oid eContentType; + CFMutableArrayRef signers; + CFMutableArrayRef recipients; + CFMutableArrayRef otherCerts; + CMSSignedAttributes signedAttributes; + CFAbsoluteTime signingTime; + SecCmsMessageRef cmsMsg; /* the encoder's arena */ + SecCmsEncoderRef encoder; + CFMutableDataRef encoderOut; /* output goes here... */ + bool customCoder; /* unless this is set by + * CMSEncoderSetEncoder */ + SECOidTag digestalgtag; + + CMSCertificateChainMode chainMode; + CFDataRef hashAgilityAttrValue; +}; + +static void cmsEncoderInit(CFTypeRef enc); +static void cmsEncoderFinalize(CFTypeRef enc); + +static CFRuntimeClass cmsEncoderRuntimeClass = +{ + 0, /* version */ + "CMSEncoder", + cmsEncoderInit, + NULL, /* copy */ + cmsEncoderFinalize, + NULL, /* equal - just use pointer equality */ + NULL, /* hash, ditto */ + NULL, /* copyFormattingDesc */ + NULL /* copyDebugDesc */ +}; + +#if TIMESTAMPING_SUPPORTED +void CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder, SecCmsTSACallback tsaCallback); +#endif + +#pragma mark --- Private routines --- + +/* + * Decode a CFStringRef representation of an integer + */ +static int cfStringToNumber( + CFStringRef inStr) +{ + int max = 32; + char buf[max]; + if (!inStr || !CFStringGetCString(inStr, buf, max-1, kCFStringEncodingASCII)) + return -1; + return atoi(buf); +} + +/* + * Encode an integer component of an OID, return resulting number of bytes; + * actual bytes are mallocd and returned in *encodeArray. + */ +static unsigned encodeNumber( + int num, + unsigned char **encodeArray) // mallocd and RETURNED +{ + unsigned char *result; + unsigned dex; + unsigned numDigits = 0; + unsigned scratch; + + /* trival case - 0 maps to 0 */ + if(num == 0) { + *encodeArray = (unsigned char *)malloc(1); + **encodeArray = 0; + return 1; + } + + /* first calculate the number of digits in num, base 128 */ + scratch = (unsigned)num; + while(scratch != 0) { + numDigits++; + scratch >>= 7; + } + + result = (unsigned char *)malloc(numDigits); + scratch = (unsigned)num; + for(dex=0; dex>= 7; + } + + /* all digits except the last one have m.s. bit set */ + for(dex=0; dex<(numDigits - 1); dex++) { + result[dex] |= 0x80; + } + + *encodeArray = result; + return numDigits; +} + +/* + * Given an OID in dotted-decimal string representation, convert to binary + * DER format. Returns a pointer in outOid which the caller must free(), + * as well as the length of the data in outLen. + * Function returns 0 if successful, non-zero otherwise. + */ +static int encodeOid( + const unsigned char *inStr, + unsigned char **outOid, + unsigned int *outLen) +{ + unsigned char **digits = NULL; /* array of char * from encodeNumber */ + unsigned *numDigits = NULL; /* array of unsigned from encodeNumber */ + CFIndex digit; + unsigned numDigitBytes; /* total #of output chars */ + unsigned char firstByte; + unsigned char *outP; + CFIndex numsToProcess; + CFStringRef oidStr = NULL; + CFArrayRef argvRef = NULL; + int num, result = 1; + CFIndex argc; + + /* parse input string into array of substrings */ + if (!inStr || !outOid || !outLen) goto cleanExit; + oidStr = CFStringCreateWithCString(NULL, (const char *)inStr, kCFStringEncodingASCII); + if (!oidStr) goto cleanExit; + argvRef = CFStringCreateArrayBySeparatingStrings(NULL, oidStr, CFSTR(".")); + if (!argvRef) goto cleanExit; + argc = CFArrayGetCount(argvRef); + if (argc < 3) goto cleanExit; + + /* first two numbers in OID munge together */ + num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, 0)); + if (num < 0) goto cleanExit; + firstByte = (40 * num); + num = cfStringToNumber((CFStringRef)CFArrayGetValueAtIndex(argvRef, 1)); + if (num < 0) goto cleanExit; + firstByte += num; + numDigitBytes = 1; + + numsToProcess = argc - 2; + if(numsToProcess > 0) { + /* skip this loop in the unlikely event that input is only two numbers */ + digits = (unsigned char **) malloc(numsToProcess * sizeof(unsigned char *)); + numDigits = (unsigned *) malloc(numsToProcess * sizeof(unsigned)); + for(digit=0; digitData. + * + * Function returns 0 if successful, non-zero otherwise. + */ + +static int convertOid( + CFTypeRef inRef, + SecAsn1Oid *outOid) +{ + if (!inRef || !outOid) + return errSecParam; + + unsigned char *oidData = NULL; + unsigned int oidLen = 0; + + if (CFGetTypeID(inRef) == CFStringGetTypeID()) { + // CFStringRef: OID representation is a dotted-decimal string + CFStringRef inStr = (CFStringRef)inRef; + CFIndex max = CFStringGetLength(inStr) * 3; + char buf[max]; + if (!CFStringGetCString(inStr, buf, max-1, kCFStringEncodingASCII)) + return errSecParam; + + if(encodeOid((unsigned char *)buf, &oidData, &oidLen) != 0) + return errSecParam; + } + else if (CFGetTypeID(inRef) == CFDataGetTypeID()) { + // CFDataRef: OID representation is in binary DER format + CFDataRef inData = (CFDataRef)inRef; + oidLen = (unsigned int) CFDataGetLength(inData); + oidData = (unsigned char *) malloc(oidLen); + memcpy(oidData, CFDataGetBytePtr(inData), oidLen); + } + else { + // Not in a format we understand + return errSecParam; + } + outOid->Length = oidLen; + outOid->Data = (uint8_t *)oidData; + return 0; +} + +static CFTypeID cmsEncoderTypeID = _kCFRuntimeNotATypeID; + +/* one time only class init, called via pthread_once() in CMSEncoderGetTypeID() */ +static void cmsEncoderClassInitialize(void) +{ + cmsEncoderTypeID = + _CFRuntimeRegisterClass((const CFRuntimeClass * const)&cmsEncoderRuntimeClass); +} + +/* init called out from _CFRuntimeCreateInstance() */ +static void cmsEncoderInit(CFTypeRef enc) +{ + char *start = ((char *)enc) + sizeof(CFRuntimeBase); + memset(start, 0, sizeof(struct _CMSEncoder) - sizeof(CFRuntimeBase)); +} + +/* + * Dispose of a CMSEncoder. Called out from CFRelease(). + */ +static void cmsEncoderFinalize( + CFTypeRef enc) +{ + CMSEncoderRef cmsEncoder = (CMSEncoderRef)enc; + if(cmsEncoder == NULL) { + return; + } + if(cmsEncoder->eContentType.Data != NULL) { + free(cmsEncoder->eContentType.Data); + } + CFRELEASE(cmsEncoder->signers); + CFRELEASE(cmsEncoder->recipients); + CFRELEASE(cmsEncoder->otherCerts); + if(cmsEncoder->cmsMsg != NULL) { + SecCmsMessageDestroy(cmsEncoder->cmsMsg); + cmsEncoder->cmsMsg = NULL; + } + if(cmsEncoder->encoder != NULL) { + /* + * Normally this gets freed in SecCmsEncoderFinish - this is + * an error case. + */ + SecCmsEncoderDestroy(cmsEncoder->encoder); + } +} + +static OSStatus cmsSetupEncoder( + CMSEncoderRef cmsEncoder) +{ + OSStatus ortn; + + ASSERT(cmsEncoder->arena == NULL); + ASSERT(cmsEncoder->encoder == NULL); + + cmsEncoder->encoderOut = CFDataCreateMutable(NULL, 0); + if (!cmsEncoder->encoderOut) { + return errSecAllocate; + } + + ortn = SecCmsEncoderCreate(cmsEncoder->cmsMsg, + NULL, NULL, // no callback + cmsEncoder->encoderOut, // data goes here + NULL, NULL, // no password callback (right?) + NULL, NULL, // decrypt key callback + &cmsEncoder->encoder); + if(ortn) { + return cmsRtnToOSStatus(ortn); + } + return errSecSuccess; +} + +/* + * Set up a SecCmsMessageRef for a SignedData creation. + */ +static OSStatus cmsSetupForSignedData( + CMSEncoderRef cmsEncoder) +{ + ASSERT((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL)); + + SecCmsContentInfoRef contentInfo = NULL; + SecCmsSignedDataRef signedData = NULL; + OSStatus ortn; + + /* build chain of objects: message->signedData->data */ + if(cmsEncoder->cmsMsg != NULL) { + SecCmsMessageDestroy(cmsEncoder->cmsMsg); + } + cmsEncoder->cmsMsg = SecCmsMessageCreate(); + if(cmsEncoder->cmsMsg == NULL) { + return errSecInternalComponent; + } + + signedData = SecCmsSignedDataCreate(cmsEncoder->cmsMsg); + if(signedData == NULL) { + return errSecInternalComponent; + } + contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg); + ortn = SecCmsContentInfoSetContentSignedData(contentInfo,signedData); + if(ortn) { + return cmsRtnToOSStatus(ortn); + } + contentInfo = SecCmsSignedDataGetContentInfo(signedData); + if(cmsEncoder->eContentType.Data != NULL) { + /* Override the default eContentType of id-data */ + ortn = SecCmsContentInfoSetContentOther(contentInfo, + NULL, /* data - provided to encoder, not here */ + cmsEncoder->detachedContent, + &cmsEncoder->eContentType); + } + else { + ortn = SecCmsContentInfoSetContentData(contentInfo, + NULL, /* data - provided to encoder, not here */ + cmsEncoder->detachedContent); + } + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsContentInfoSetContent*", ortn); + return ortn; + } + + /* optional 'global' (per-SignedData) certs */ + if(cmsEncoder->otherCerts != NULL) { + ortn = SecCmsSignedDataAddCertList(signedData, cmsEncoder->otherCerts); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsSignedDataAddCertList", ortn); + return ortn; + } + } + + /* SignerInfos, one per signer */ + CFIndex numSigners = 0; + if(cmsEncoder->signers != NULL) { + /* this is optional...in case we're just creating a cert bundle */ + numSigners = CFArrayGetCount(cmsEncoder->signers); + } + CFIndex dex; + SecCertificateRef ourCert = NULL; + SecCmsCertChainMode chainMode = SecCmsCMCertChain; + + switch(cmsEncoder->chainMode) { + case kCMSCertificateNone: + chainMode = SecCmsCMNone; + break; + case kCMSCertificateSignerOnly: + chainMode = SecCmsCMCertOnly; + break; + case kCMSCertificateChainWithRoot: + chainMode = SecCmsCMCertChainWithRoot; + break; + default: + break; + } + for(dex=0; dexsigners, dex); + ortn = SecIdentityCopyCertificate(ourId, &ourCert); + if(ortn) { + CSSM_PERROR("SecIdentityCopyCertificate", ortn); + break; + } + /* this creates the signerInfo and adds it to the signedData object */ + signerInfo = SecCmsSignerInfoCreate(signedData, ourId, cmsEncoder->digestalgtag); + if (signerInfo == NULL) { + ortn = errSecInternalComponent; + break; + } + + /* we want the cert chain included for this one */ + /* NOTE the usage parameter is currently unused by the SMIME lib */ + ortn = SecCmsSignerInfoIncludeCerts(signerInfo, chainMode, + certUsageEmailSigner); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsSignerInfoIncludeCerts", ortn); + break; + } + + /* other options */ + if(cmsEncoder->signedAttributes & kCMSAttrSmimeCapabilities) { + ortn = SecCmsSignerInfoAddSMIMECaps(signerInfo); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn); + break; + } + } + if(cmsEncoder->signedAttributes & kCMSAttrSmimeEncryptionKeyPrefs) { + ortn = SecCmsSignerInfoAddSMIMEEncKeyPrefs(signerInfo, ourCert, NULL); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsSignerInfoAddSMIMEEncKeyPrefs", ortn); + break; + } + } + if(cmsEncoder->signedAttributes & kCMSAttrSmimeMSEncryptionKeyPrefs) { + ortn = SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(signerInfo, ourCert, NULL); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsSignerInfoAddMSSMIMEEncKeyPrefs", ortn); + break; + } + } + if(cmsEncoder->signedAttributes & kCMSAttrSigningTime) { + if (cmsEncoder->signingTime == 0) + cmsEncoder->signingTime = CFAbsoluteTimeGetCurrent(); + ortn = SecCmsSignerInfoAddSigningTime(signerInfo, cmsEncoder->signingTime); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsSignerInfoAddSigningTime", ortn); + break; + } + } + if(cmsEncoder->signedAttributes & kCMSAttrAppleCodesigningHashAgility) { + ortn = SecCmsSignerInfoAddAppleCodesigningHashAgility(signerInfo, cmsEncoder->hashAgilityAttrValue); + /* libsecurity_smime made a copy of the attribute value. We don't need it anymore. */ + CFReleaseNull(cmsEncoder->hashAgilityAttrValue); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsSignerInfoAddAppleCodesigningHashAgility", ortn); + break; + } + } + + CFRELEASE(ourCert); + ourCert = NULL; + } + if(ortn) { + CFRELEASE(ourCert); + } + return ortn; +} + +/* + * Set up a SecCmsMessageRef for a EnvelopedData creation. + */ +static OSStatus cmsSetupForEnvelopedData( + CMSEncoderRef cmsEncoder) +{ + ASSERT(cmsEncoder->op == EO_Encrypt); + ASSERT(cmsEncoder->recipients != NULL); + + SecCmsContentInfoRef contentInfo = NULL; + SecCmsEnvelopedDataRef envelopedData = NULL; + SECOidTag algorithmTag; + int keySize; + OSStatus ortn; + + /* + * Find encryption algorithm...unfortunately we need a NULL-terminated array + * of SecCertificateRefs for this. + */ + CFIndex numCerts = CFArrayGetCount(cmsEncoder->recipients); + CFIndex dex; + SecCertificateRef *certArray = (SecCertificateRef *)malloc( + (numCerts+1) * sizeof(SecCertificateRef)); + + for(dex=0; dexrecipients, dex); + } + certArray[numCerts] = NULL; + ortn = SecSMIMEFindBulkAlgForRecipients(certArray, &algorithmTag, &keySize); + free(certArray); + if(ortn) { + CSSM_PERROR("SecSMIMEFindBulkAlgForRecipients", ortn); + return ortn; + } + + /* build chain of objects: message->envelopedData->data */ + if(cmsEncoder->cmsMsg != NULL) { + SecCmsMessageDestroy(cmsEncoder->cmsMsg); + } + cmsEncoder->cmsMsg = SecCmsMessageCreate(); + if(cmsEncoder->cmsMsg == NULL) { + return errSecInternalComponent; + } + envelopedData = SecCmsEnvelopedDataCreate(cmsEncoder->cmsMsg, + algorithmTag, keySize); + if(envelopedData == NULL) { + return errSecInternalComponent; + } + contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg); + ortn = SecCmsContentInfoSetContentEnvelopedData(contentInfo, envelopedData); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsContentInfoSetContentEnvelopedData", ortn); + return ortn; + } + contentInfo = SecCmsEnvelopedDataGetContentInfo(envelopedData); + if(cmsEncoder->eContentType.Data != NULL) { + /* Override the default ContentType of id-data */ + ortn = SecCmsContentInfoSetContentOther(contentInfo, + NULL, /* data - provided to encoder, not here */ + FALSE, /* detachedContent */ + &cmsEncoder->eContentType); + } + else { + ortn = SecCmsContentInfoSetContentData(contentInfo, + NULL /* data - provided to encoder, not here */, + cmsEncoder->detachedContent); + } + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsContentInfoSetContentData*", ortn); + return ortn; + } + + /* + * create & attach recipient information, one for each recipient + */ + for(dex=0; dexrecipients, dex); + recipientInfo = SecCmsRecipientInfoCreate(envelopedData, thisRecip); + ortn = SecCmsEnvelopedDataAddRecipient(envelopedData, recipientInfo); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsEnvelopedDataAddRecipient", ortn); + return ortn; + } + } + return errSecSuccess; +} + +/* + * Set up cmsMsg. Called from either the first call to CMSEncoderUpdateContent, or + * from CMSEncodeGetCmsMessage(). + */ +static OSStatus cmsSetupCmsMsg( + CMSEncoderRef cmsEncoder) +{ + ASSERT(cmsEncoder != NULL); + ASSERT(cmsEncoder->encState == ES_Init); + + /* figure out what high-level operation we're doing */ + if((cmsEncoder->signers != NULL) || (cmsEncoder->otherCerts != NULL)) { + if(cmsEncoder->recipients != NULL) { + cmsEncoder->op = EO_SignEncrypt; + } + else { + cmsEncoder->op = EO_Sign; + } + } + else if(cmsEncoder->recipients != NULL) { + cmsEncoder->op = EO_Encrypt; + } + else { + dprintf("CMSEncoderUpdateContent: nothing to do\n"); + return errSecParam; + } + + OSStatus ortn = errSecSuccess; + + switch(cmsEncoder->op) { + case EO_Sign: + case EO_SignEncrypt: + /* If we're signing & encrypting, do the signing first */ + ortn = cmsSetupForSignedData(cmsEncoder); + break; + case EO_Encrypt: + ortn = cmsSetupForEnvelopedData(cmsEncoder); + break; + } + cmsEncoder->encState = ES_Msg; + return ortn; +} + +/* + * ASN.1 template for decoding a ContentInfo. + */ +typedef struct { + SecAsn1Oid contentType; + SecAsn1Oid content; +} SimpleContentInfo; + +static const SecAsn1Template cmsSimpleContentInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SimpleContentInfo) }, + { SEC_ASN1_OBJECT_ID, offsetof(SimpleContentInfo, contentType) }, + { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, + offsetof(SimpleContentInfo, content), + kSecAsn1AnyTemplate }, + { 0, } +}; + +/* + * Obtain the content of a contentInfo, This basically strips off the contentType OID + * and returns its ASN_ANY content, allocated the provided coder's memory space. + */ +static OSStatus cmsContentInfoContent( + SecAsn1CoderRef asn1Coder, + const SecAsn1Item *contentInfo, + SecAsn1Item *content) /* RETURNED */ +{ + OSStatus ortn; + SimpleContentInfo decodedInfo; + + memset(&decodedInfo, 0, sizeof(decodedInfo)); + ortn = SecAsn1DecodeData(asn1Coder, contentInfo, + cmsSimpleContentInfoTemplate, &decodedInfo); + if(ortn) { + return ortn; + } + if(decodedInfo.content.Data == NULL) { + dprintf("***Error decoding contentInfo: no content\n"); + return errSecInternalComponent; + } + *content = decodedInfo.content; + return errSecSuccess; +} + +#pragma mark --- Start of Public API --- + +CFTypeID CMSEncoderGetTypeID(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + + if(cmsEncoderTypeID == _kCFRuntimeNotATypeID) { + pthread_once(&once, &cmsEncoderClassInitialize); + } + return cmsEncoderTypeID; +} + +/* + * Create a CMSEncoder. Result must eventually be freed via CFRelease(). + */ +OSStatus CMSEncoderCreate( + CMSEncoderRef *cmsEncoderOut) /* RETURNED */ +{ + CMSEncoderRef cmsEncoder = NULL; + + uint32_t extra = sizeof(*cmsEncoder) - sizeof(cmsEncoder->base); + cmsEncoder = (CMSEncoderRef)_CFRuntimeCreateInstance(NULL, CMSEncoderGetTypeID(), + extra, NULL); + if(cmsEncoder == NULL) { + return errSecAllocate; + } + cmsEncoder->encState = ES_Init; + cmsEncoder->chainMode = kCMSCertificateChain; + cmsEncoder->digestalgtag = SEC_OID_SHA1; + *cmsEncoderOut = cmsEncoder; + return errSecSuccess; +} + +#pragma mark --- Getters & Setters --- + +const CFStringRef __nonnull kCMSEncoderDigestAlgorithmSHA1 = CFSTR("sha1"); +const CFStringRef __nonnull kCMSEncoderDigestAlgorithmSHA256 = CFSTR("sha256"); + + +OSStatus CMSEncoderSetSignerAlgorithm( + CMSEncoderRef cmsEncoder, + CFStringRef digestAlgorithm) +{ + if (CFEqual(digestAlgorithm, kCMSEncoderDigestAlgorithmSHA1)) { + cmsEncoder->digestalgtag = SEC_OID_SHA1; + } else if (CFEqual(digestAlgorithm, kCMSEncoderDigestAlgorithmSHA256)) { + cmsEncoder->digestalgtag = SEC_OID_SHA256; + } else { + return errSecParam; + } + + return errSecSuccess; +} + +/* + * Specify signers of the CMS message; implies that the message will be signed. + */ +OSStatus CMSEncoderAddSigners( + CMSEncoderRef cmsEncoder, + CFTypeRef signerOrArray) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + if(cmsEncoder->encState != ES_Init) { + return errSecParam; + } + return cmsAppendToArray(signerOrArray, &cmsEncoder->signers, SecIdentityGetTypeID()); +} + +/* + * Obtain an array of signers as specified in CMSEncoderSetSigners(). + */ +OSStatus CMSEncoderCopySigners( + CMSEncoderRef cmsEncoder, + CFArrayRef *signers) +{ + if((cmsEncoder == NULL) || (signers == NULL)) { + return errSecParam; + } + if(cmsEncoder->signers != NULL) { + CFRetain(cmsEncoder->signers); + } + *signers = cmsEncoder->signers; + return errSecSuccess; +} + +/* + * Specify recipients of the message. Implies that the message will be encrypted. + */ +OSStatus CMSEncoderAddRecipients( + CMSEncoderRef cmsEncoder, + CFTypeRef recipientOrArray) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + if(cmsEncoder->encState != ES_Init) { + return errSecParam; + } + return cmsAppendToArray(recipientOrArray, &cmsEncoder->recipients, + SecCertificateGetTypeID()); +} + +/* + * Obtain an array of recipients as specified in CMSEncoderSetRecipients(). + */ +OSStatus CMSEncoderCopyRecipients( + CMSEncoderRef cmsEncoder, + CFArrayRef *recipients) +{ + if((cmsEncoder == NULL) || (recipients == NULL)) { + return errSecParam; + } + if(cmsEncoder->recipients != NULL) { + CFRetain(cmsEncoder->recipients); + } + *recipients = cmsEncoder->recipients; + return errSecSuccess; +} + +/* + * Specify additional certs to include in a signed message. + */ +OSStatus CMSEncoderAddSupportingCerts( + CMSEncoderRef cmsEncoder, + CFTypeRef certOrArray) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + if(cmsEncoder->encState != ES_Init) { + return errSecParam; + } + return cmsAppendToArray(certOrArray, &cmsEncoder->otherCerts, + SecCertificateGetTypeID()); +} + +/* + * Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts(). + */ +OSStatus CMSEncoderCopySupportingCerts( + CMSEncoderRef cmsEncoder, + CFArrayRef *certs) /* RETURNED */ +{ + if((cmsEncoder == NULL) || (certs == NULL)) { + return errSecParam; + } + if(cmsEncoder->otherCerts != NULL) { + CFRetain(cmsEncoder->otherCerts); + } + *certs = cmsEncoder->otherCerts; + return errSecSuccess; +} + +OSStatus CMSEncoderSetHasDetachedContent( + CMSEncoderRef cmsEncoder, + Boolean detachedContent) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + if(cmsEncoder->encState != ES_Init) { + return errSecParam; + } + cmsEncoder->detachedContent = detachedContent; + return errSecSuccess; +} + +OSStatus CMSEncoderGetHasDetachedContent( + CMSEncoderRef cmsEncoder, + Boolean *detachedContent) /* RETURNED */ +{ + if((cmsEncoder == NULL) || (detachedContent == NULL)) { + return errSecParam; + } + *detachedContent = cmsEncoder->detachedContent; + return errSecSuccess; +} + +/* + * Optionally specify an eContentType OID for the inner EncapsulatedData for + * a signed message. The default eContentType, used of this function is not + * called, is id-data. + */ +static OSStatus CMSEncoderSetEncapsulatedContentType( + CMSEncoderRef cmsEncoder, + const SecAsn1Oid *eContentType) +{ + if((cmsEncoder == NULL) || (eContentType == NULL)) { + return errSecParam; + } + if(cmsEncoder->encState != ES_Init) { + return errSecParam; + } + + SecAsn1Oid *ecOid = &cmsEncoder->eContentType; + if(ecOid->Data != NULL) { + free(ecOid->Data); + } + cmsCopyCmsData(eContentType, ecOid); + return errSecSuccess; +} + +OSStatus CMSEncoderSetEncapsulatedContentTypeOID( + CMSEncoderRef cmsEncoder, + CFTypeRef eContentTypeOID) +{ + // convert eContentTypeOID to a CSSM_OID + SecAsn1Oid contentType = { 0, NULL }; + if (!eContentTypeOID || convertOid(eContentTypeOID, &contentType) != 0) + return errSecParam; + OSStatus result = CMSEncoderSetEncapsulatedContentType(cmsEncoder, &contentType); + if (contentType.Data) + free(contentType.Data); + return result; +} + +/* + * Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType(). + */ +OSStatus CMSEncoderCopyEncapsulatedContentType( + CMSEncoderRef cmsEncoder, + CFDataRef *eContentType) +{ + if((cmsEncoder == NULL) || (eContentType == NULL)) { + return errSecParam; + } + + SecAsn1Oid *ecOid = &cmsEncoder->eContentType; + if(ecOid->Data == NULL) { + *eContentType = NULL; + } + else { + *eContentType = CFDataCreate(NULL, ecOid->Data, ecOid->Length); + } + return errSecSuccess; +} + +/* + * Optionally specify signed attributes. Only meaningful when creating a + * signed message. If this is called, it must be called before + * CMSEncoderUpdateContent(). + */ +OSStatus CMSEncoderAddSignedAttributes( + CMSEncoderRef cmsEncoder, + CMSSignedAttributes signedAttributes) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + if(cmsEncoder->encState != ES_Init) { + return errSecParam; + } + cmsEncoder->signedAttributes |= signedAttributes; + return errSecSuccess; +} + +/* + * Set the signing time for a CMSEncoder. + * This is only used if the kCMSAttrSigningTime attribute is included. + */ +OSStatus CMSEncoderSetSigningTime( + CMSEncoderRef cmsEncoder, + CFAbsoluteTime time) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + if(cmsEncoder->encState != ES_Init) { + return errSecParam; + } + cmsEncoder->signingTime = time; + return errSecSuccess; +} + +/* + * Set the hash agility attribute for a CMSEncoder. + * This is only used if the kCMSAttrAppleCodesigningHashAgility attribute + * is included. + */ +OSStatus CMSEncoderSetAppleCodesigningHashAgility( + CMSEncoderRef cmsEncoder, + CFDataRef hashAgilityAttrValue) +{ + if (cmsEncoder == NULL || cmsEncoder->encState != ES_Init) { + return errSecParam; + } + cmsEncoder->hashAgilityAttrValue = CFRetainSafe(hashAgilityAttrValue); + return errSecSuccess; +} + +OSStatus CMSEncoderSetCertificateChainMode( + CMSEncoderRef cmsEncoder, + CMSCertificateChainMode chainMode) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + if(cmsEncoder->encState != ES_Init) { + return errSecParam; + } + switch(chainMode) { + case kCMSCertificateNone: + case kCMSCertificateSignerOnly: + case kCMSCertificateChain: + case kCMSCertificateChainWithRoot: + break; + default: + return errSecParam; + } + cmsEncoder->chainMode = chainMode; + return errSecSuccess; +} + +OSStatus CMSEncoderGetCertificateChainMode( + CMSEncoderRef cmsEncoder, + CMSCertificateChainMode *chainModeOut) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + *chainModeOut = cmsEncoder->chainMode; + return errSecSuccess; +} + +#if TIMESTAMPING_SUPPORTED +void +CmsMessageSetTSACallback(CMSEncoderRef cmsEncoder, SecCmsTSACallback tsaCallback) +{ + if (cmsEncoder->cmsMsg) + SecCmsMessageSetTSACallback(cmsEncoder->cmsMsg, tsaCallback); +} + +void +CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder, CFTypeRef tsaContext) +{ + if (cmsEncoder->cmsMsg) + SecCmsMessageSetTSAContext(cmsEncoder->cmsMsg, tsaContext); +} +#endif + +#pragma mark --- Action --- + +/* + * Feed content bytes into the encoder. + * Can be called multiple times. + * No 'setter' routines can be called after this function has been called. + */ +OSStatus CMSEncoderUpdateContent( + CMSEncoderRef cmsEncoder, + const void *content, + size_t contentLen) +{ + if(cmsEncoder == NULL) { + return errSecParam; + } + + OSStatus ortn = errSecSuccess; + switch(cmsEncoder->encState) { + case ES_Init: + /* + * First time thru: do the CmsMsg setup. + */ + ortn = cmsSetupCmsMsg(cmsEncoder); + if(ortn) { + return ortn; + } + /* fall thru to set up the encoder */ + + case ES_Msg: + /* We have a cmsMsg but no encoder; create one */ + ASSERT(cmsEncoder->cmsMsg != NULL); + ASSERT(cmsEncoder->encoder == NULL); + ortn = cmsSetupEncoder(cmsEncoder); + if(ortn) { + return ortn; + } + /* only legal calls now are update and finalize */ + cmsEncoder->encState = ES_Updating; + break; + + case ES_Updating: + ASSERT(cmsEncoder->encoder != NULL); + break; + + case ES_Final: + /* Too late for another update */ + return errSecParam; + + default: + return errSecInternalComponent; + } + + /* FIXME - CFIndex same size as size_t on 64bit? */ + ortn = SecCmsEncoderUpdate(cmsEncoder->encoder, content, (CFIndex)contentLen); + if(ortn) { + ortn = cmsRtnToOSStatus(ortn); + CSSM_PERROR("SecCmsEncoderUpdate", ortn); + } + return ortn; +} + +/* forward declaration */ +static OSStatus CMSEncode( + CFTypeRef signers, + CFTypeRef recipients, + const SecAsn1Oid *eContentType, + Boolean detachedContent, + CMSSignedAttributes signedAttributes, + const void *content, + size_t contentLen, + CFDataRef *encodedContent); + +/* + * Finish encoding the message and obtain the encoded result. + * Caller must CFRelease the result. + */ +OSStatus CMSEncoderCopyEncodedContent( + CMSEncoderRef cmsEncoder, + CFDataRef *encodedContent) +{ + if((cmsEncoder == NULL) || (encodedContent == NULL)) { + return errSecParam; + } + + OSStatus ortn; + + switch(cmsEncoder->encState) { + case ES_Updating: + /* normal termination */ + break; + case ES_Final: + /* already been called */ + return errSecParam; + case ES_Msg: + case ES_Init: + /* + * The only time these are legal is when we're doing a SignedData + * with certificates only (no signers, no content). + */ + if((cmsEncoder->signers != NULL) || + (cmsEncoder->recipients != NULL) || + (cmsEncoder->otherCerts == NULL)) { + return errSecParam; + } + + /* Set up for certs only */ + ortn = cmsSetupForSignedData(cmsEncoder); + if(ortn) { + return ortn; + } + /* and an encoder */ + ortn = cmsSetupEncoder(cmsEncoder); + if(ortn) { + return ortn; + } + break; + } + + + ASSERT(cmsEncoder->encoder != NULL); + ortn = SecCmsEncoderFinish(cmsEncoder->encoder); + /* regardless of the outcome, the encoder itself has been freed */ + cmsEncoder->encoder = NULL; + if(ortn) { + return cmsRtnToOSStatus(ortn); + } + cmsEncoder->encState = ES_Final; + + if((cmsEncoder->encoderOut == NULL) && !cmsEncoder->customCoder) { + /* not sure how this could happen... */ + dprintf("Successful encode, but no data\n"); + return errSecInternalComponent; + } + if(cmsEncoder->customCoder) { + /* we're done */ + *encodedContent = NULL; + return errSecSuccess; + } + + /* in two out of three cases, we're done */ + switch(cmsEncoder->op) { + case EO_Sign: + case EO_Encrypt: + *encodedContent = CFDataCreateCopy(NULL, cmsEncoder->encoderOut); + return errSecSuccess; + case EO_SignEncrypt: + /* proceed, more work to do */ + break; + } + + /* + * Signing & encrypting. + * Due to bugs in the libsecurity_smime encoder, it can't encode nested + * ContentInfos in one shot. So we do another pass, specifying the SignedData + * inside of the ContentInfo we just created as the data to encrypt. + */ + SecAsn1CoderRef asn1Coder = NULL; + SecAsn1Item signedData = {0, NULL}; + + ortn = SecAsn1CoderCreate(&asn1Coder); + if(ortn) { + return ortn; + } + SecAsn1Item encoderOut = { CFDataGetLength(cmsEncoder->encoderOut), + CFDataGetMutableBytePtr(cmsEncoder->encoderOut)}; + ortn = cmsContentInfoContent(asn1Coder, &encoderOut, &signedData); + if(ortn) { + goto errOut; + } + + /* now just encrypt that, one-shot */ + ortn = CMSEncode(NULL, /* no signers this time */ + cmsEncoder->recipients, + &CSSMOID_PKCS7_SignedData, /* fake out encoder so it doesn't try to actually + * encode the signedData - this asserts the + * SEC_OID_OTHER OID tag in the EnvelopedData's + * ContentInfo */ + FALSE, /* detachedContent */ + kCMSAttrNone, /* signedAttributes - none this time */ + signedData.Data, signedData.Length, + encodedContent); + +errOut: + if(asn1Coder) { + SecAsn1CoderRelease(asn1Coder); + } + return ortn; +} + +#pragma mark --- High-level API --- + +/* + * High-level, one-shot encoder function. + */ +static OSStatus CMSEncode( + CFTypeRef signers, + CFTypeRef recipients, + const SecAsn1Oid *eContentType, + Boolean detachedContent, + CMSSignedAttributes signedAttributes, + const void *content, + size_t contentLen, + CFDataRef *encodedContent) /* RETURNED */ +{ + if((signers == NULL) && (recipients == NULL)) { + return errSecParam; + } + if(encodedContent == NULL) { + return errSecParam; + } + + CMSEncoderRef cmsEncoder; + OSStatus ortn; + + /* set up the encoder */ + ortn = CMSEncoderCreate(&cmsEncoder); + if(ortn) { + return ortn; + } + + /* subsequent errors to errOut: */ + if(signers) { + ortn = CMSEncoderAddSigners(cmsEncoder, signers); + if(ortn) { + goto errOut; + } + } + if(recipients) { + ortn = CMSEncoderAddRecipients(cmsEncoder, recipients); + if(ortn) { + goto errOut; + } + } + if(eContentType) { + ortn = CMSEncoderSetEncapsulatedContentType(cmsEncoder, eContentType); + if(ortn) { + goto errOut; + } + } + if(detachedContent) { + ortn = CMSEncoderSetHasDetachedContent(cmsEncoder, detachedContent); + if(ortn) { + goto errOut; + } + } + if(signedAttributes) { + ortn = CMSEncoderAddSignedAttributes(cmsEncoder, signedAttributes); + if(ortn) { + goto errOut; + } + } + /* GO */ + ortn = CMSEncoderUpdateContent(cmsEncoder, content, contentLen); + if(ortn) { + goto errOut; + } + ortn = CMSEncoderCopyEncodedContent(cmsEncoder, encodedContent); + +errOut: + CFRelease(cmsEncoder); + return ortn; +} + +OSStatus CMSEncodeContent( + CFTypeRef signers, + CFTypeRef recipients, + CFTypeRef eContentTypeOID, + Boolean detachedContent, + CMSSignedAttributes signedAttributes, + const void *content, + size_t contentLen, + CFDataRef *encodedContentOut) /* RETURNED */ +{ + // convert eContentTypeOID to a CSSM_OID + SecAsn1Oid contentType = { 0, NULL }; + if (eContentTypeOID && convertOid(eContentTypeOID, &contentType) != 0) + return errSecParam; + const SecAsn1Oid *contentTypePtr = (eContentTypeOID) ? &contentType : NULL; + OSStatus result = CMSEncode(signers, recipients, contentTypePtr, + detachedContent, signedAttributes, + content, contentLen, encodedContentOut); + if (contentType.Data) + free(contentType.Data); + return result; +} + +#pragma mark --- SPI routines declared in CMSPrivate.h --- + +/* + * Obtain the SecCmsMessageRef associated with a CMSEncoderRef. + * If we don't have a SecCmsMessageRef yet, we create one now. + * This is the only place where we go to state ES_Msg. + */ +OSStatus CMSEncoderGetCmsMessage( + CMSEncoderRef cmsEncoder, + SecCmsMessageRef *cmsMessage) /* RETURNED */ +{ + if((cmsEncoder == NULL) || (cmsMessage == NULL)) { + return errSecParam; + } + if(cmsEncoder->cmsMsg != NULL) { + ASSERT(cmsEncoder->encState != ES_Init); + *cmsMessage = cmsEncoder->cmsMsg; + return errSecSuccess; + } + + OSStatus ortn = cmsSetupCmsMsg(cmsEncoder); + if(ortn) { + return ortn; + } + *cmsMessage = cmsEncoder->cmsMsg; + + /* Don't set up encoder yet; caller might do that via CMSEncoderSetEncoder */ + cmsEncoder->encState = ES_Msg; + return errSecSuccess; +} + +/* + * Optionally specify a SecCmsEncoderRef to use with a CMSEncoderRef. + * If this is called, it must be called before the first call to + * CMSEncoderUpdateContent(). The CMSEncoderRef takes ownership of the + * incoming SecCmsEncoderRef. + */ +OSStatus CMSEncoderSetEncoder( + CMSEncoderRef cmsEncoder, + SecCmsEncoderRef encoder) +{ + if((cmsEncoder == NULL) || (encoder == NULL)) { + return errSecParam; + } + + OSStatus ortn; + + switch(cmsEncoder->encState) { + case ES_Init: + /* No message, no encoder */ + ASSERT(cmsEncoder->cmsMsg == NULL); + ASSERT(cmsEncoder->encoder == NULL); + ortn = cmsSetupCmsMsg(cmsEncoder); + if(ortn) { + return ortn; + } + /* drop thru to set encoder */ + case ES_Msg: + /* cmsMsg but no encoder */ + ASSERT(cmsEncoder->cmsMsg != NULL); + ASSERT(cmsEncoder->encoder == NULL); + cmsEncoder->encoder = encoder; + cmsEncoder->encState = ES_Updating; + cmsEncoder->customCoder = true; /* we won't see data */ + return errSecSuccess; + default: + /* no can do, too late */ + return errSecParam; + } +} + +/* + * Obtain the SecCmsEncoderRef associated with a CMSEncoderRef. + * Returns a NULL SecCmsEncoderRef if neither CMSEncoderSetEncoder nor + * CMSEncoderUpdateContent() has been called. + * The CMSEncoderRef retains ownership of the SecCmsEncoderRef. + */ +OSStatus CMSEncoderGetEncoder( + CMSEncoderRef cmsEncoder, + SecCmsEncoderRef *encoder) /* RETURNED */ +{ + if((cmsEncoder == NULL) || (encoder == NULL)) { + return errSecParam; + } + + /* any state, whether we have an encoder or not is OK */ + *encoder = cmsEncoder->encoder; + return errSecSuccess; +} + +#if TIMESTAMPING_SUPPORTED +#include +/* + * Obtain the timestamp of signer 'signerIndex' of a CMS message, if + * present. This timestamp is an authenticated timestamp provided by + * a timestamping authority. + * + * Returns errSecParam if the CMS message was not signed or if signerIndex + * is greater than the number of signers of the message minus one. + * + * This cannot be called until after CMSEncoderCopyEncodedContent() is called. + */ +OSStatus CMSEncoderCopySignerTimestamp( + CMSEncoderRef cmsEncoder, + size_t signerIndex, /* usually 0 */ + CFAbsoluteTime *timestamp) /* RETURNED */ +{ + return CMSEncoderCopySignerTimestampWithPolicy( + cmsEncoder, + NULL, + signerIndex, + timestamp); +} + +OSStatus CMSEncoderCopySignerTimestampWithPolicy( + CMSEncoderRef cmsEncoder, + CFTypeRef timeStampPolicy, + size_t signerIndex, /* usually 0 */ + CFAbsoluteTime *timestamp) /* RETURNED */ +{ + OSStatus status = errSecParam; + SecCmsMessageRef cmsg; + SecCmsSignedDataRef signedData = NULL; + int numContentInfos = 0; + + require(cmsEncoder && timestamp, xit); + require_noerr(CMSEncoderGetCmsMessage(cmsEncoder, &cmsg), xit); + numContentInfos = SecCmsMessageContentLevelCount(cmsg); + for (int dex = 0; !signedData && dex < numContentInfos; dex++) + { + SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex); + SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci); + if (tag == SEC_OID_PKCS7_SIGNED_DATA) + if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) { + SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex); + if (signerInfo) + { + status = SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo, timeStampPolicy, timestamp); + break; + } + } + } + +xit: + return status; +} +#endif diff --git a/libsecurity_smime/lib/CMSEncoder.h b/libsecurity_smime/lib/CMSEncoder.h new file mode 100644 index 00000000..dda5f2f1 --- /dev/null +++ b/libsecurity_smime/lib/CMSEncoder.h @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2006-2012 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@ + */ + +/* + * CMSEncoder.h - encode, sign, and/or encrypt messages in the Cryptographic + * Message Syntax (CMS), per RFC 3852. + * + * A CMS message can be signed, encrypted, or both. A message can be signed by + * an arbitrary number of signers; in this module, signers are expressed as + * SecIdentityRefs. A message can be encrypted for an arbitrary number of + * recipients; recipients are expressed here as SecCertificateRefs. + * + * In CMS terminology, this module performs encryption using the EnvelopedData + * ContentType and signing using the SignedData ContentType. + * + * If the message is both signed and encrypted, it uses "nested ContentInfos" + * in CMS terminology; in this implementation, signed & encrypted messages + * are implemented as an EnvelopedData containing a SignedData. + */ + +#ifndef _CMS_ENCODER_H_ +#define _CMS_ENCODER_H_ + +#include +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +CF_ASSUME_NONNULL_BEGIN + +/* + * Opaque reference to a CMS encoder object. + * This is a CF object, with standard CF semantics; dispose of it + * with CFRelease(). + */ +typedef struct CF_BRIDGED_TYPE(id) _CMSEncoder *CMSEncoderRef; + +CFTypeID CMSEncoderGetTypeID(void) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Create a CMSEncoder. Result must eventually be freed via CFRelease(). + */ +OSStatus CMSEncoderCreate(CMSEncoderRef * __nonnull CF_RETURNS_RETAINED cmsEncoderOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +extern const CFStringRef kCMSEncoderDigestAlgorithmSHA1; +extern const CFStringRef kCMSEncoderDigestAlgorithmSHA256; + +OSStatus CMSEncoderSetSignerAlgorithm( + CMSEncoderRef cmsEncoder, + CFStringRef digestAlgorithm) + __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_11_0); + +/* + * Specify signers of the CMS message; implies that the message will be signed. + * + * -- Caller can pass in one signer, as a SecIdentityRef, or an array of + * signers, as a CFArray of SecIdentityRefs. + * -- Can be called multiple times. + * -- If the message is not to be signed, don't call this. + * -- If this is called, it must be called before the first call to + * CMSEncoderUpdateContent(). + */ +OSStatus CMSEncoderAddSigners( + CMSEncoderRef cmsEncoder, + CFTypeRef signerOrArray) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain an array of signers as specified in CMSEncoderSetSigners(). + * Returns a NULL signers array if CMSEncoderSetSigners() has not been called. + * Caller must CFRelease the result. + */ +OSStatus CMSEncoderCopySigners( + CMSEncoderRef cmsEncoder, + CFArrayRef * __nonnull CF_RETURNS_RETAINED signersOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Specify recipients of the message. Implies that the message will + * be encrypted. + * + * -- Caller can pass in one recipient, as a SecCertificateRef, or an + * array of recipients, as a CFArray of SecCertificateRefs. + * -- Can be called multiple times. + * -- If the message is not to be encrypted, don't call this. + * -- If this is called, it must be called before the first call to + * CMSEncoderUpdateContent(). + */ +OSStatus CMSEncoderAddRecipients( + CMSEncoderRef cmsEncoder, + CFTypeRef recipientOrArray) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain an array of recipients as specified in CMSEncoderSetRecipients(). + * Returns a NULL recipients array if CMSEncoderSetRecipients() has not been + * called. + * Caller must CFRelease the result. + */ +OSStatus CMSEncoderCopyRecipients( + CMSEncoderRef cmsEncoder, + CFArrayRef * __nonnull CF_RETURNS_RETAINED recipientsOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * A signed message optionally includes the data to be signed. If the message + * is *not* to include the data to be signed, call this function with a value + * of TRUE for detachedContent. The default, if this function is not called, + * is detachedContent=FALSE, i.e., the message contains the data to be signed. + * + * -- Encrypted messages can not use detached content. (This restriction + * also applies to messages that are both signed and encrypted.) + * -- If this is called, it must be called before the first call to + * CMSEncoderUpdateContent(). + */ +OSStatus CMSEncoderSetHasDetachedContent( + CMSEncoderRef cmsEncoder, + Boolean detachedContent) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain a Boolean indicating whether the current message will have detached + * content. + * Returns the value specified in CMSEncoderHasDetachedContent() if that + * function has been called; else returns the default FALSE. + */ +OSStatus CMSEncoderGetHasDetachedContent( + CMSEncoderRef cmsEncoder, + Boolean *detachedContentOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Optionally specify an eContentType OID for the inner EncapsulatedData for + * a signed message. The default eContentTypeOID, used if this function is not + * called, is id-data (which is the normal eContentType for applications such + * as SMIME). + * + * The eContentTypeOID parameter may be specified as a CF string, e.g.: + * CFSTR("1.2.840.113549.1.7.1") + * + * If this is called, it must be called before the first call to + * CMSEncoderUpdateContent(). + */ +OSStatus CMSEncoderSetEncapsulatedContentTypeOID( + CMSEncoderRef cmsEncoder, + CFTypeRef eContentTypeOID) + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_11_0); + +/* + * Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType(). + * If CMSEncoderSetEncapsulatedContentType() has not been called this returns a + * NULL pointer. + * The returned OID's data is in the same format as the data provided to + * CMSEncoderSetEncapsulatedContentType;, i.e., it's the encoded content of + * the OID, not including the tag and length bytes. + */ +OSStatus CMSEncoderCopyEncapsulatedContentType( + CMSEncoderRef cmsEncoder, + CFDataRef * __nonnull CF_RETURNS_RETAINED eContentTypeOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Signed CMS messages can contain arbitrary sets of certificates beyond those + * indicating the identity of the signer(s). This function provides a means of + * adding these other certs. For normal signed messages it is not necessary to + * call this; the signer cert(s) and the intermediate certs needed to verify the + * signer(s) will be included in the message implicitly. + * + * -- Caller can pass in one cert, as a SecCertificateRef, or an array of certs, + * as a CFArray of SecCertificateRefs. + * -- If this is called, it must be called before the first call to + * CMSEncoderUpdateContent(). + * -- There is a "special case" use of CMS messages which involves neither + * signing nor encryption, but does include certificates. This is commonly + * used to transport "bags" of certificates. When constructing such a + * message, all an application needs to do is to create a CMSEncoderRef, + * call CMSEncoderAddSupportingCerts() one or more times, and then call + * CMSEncoderCopyEncodedContent() to get the resulting cert bag. No 'content' + * need be specified. (This is in fact the primary intended use for + * this function.) + */ +OSStatus CMSEncoderAddSupportingCerts( + CMSEncoderRef cmsEncoder, + CFTypeRef certOrArray) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts(). + * If CMSEncoderAddSupportingCerts() has not been called this will return a + * NULL value for *certs. + * Caller must CFRelease the result. + */ +OSStatus CMSEncoderCopySupportingCerts( + CMSEncoderRef cmsEncoder, + CFArrayRef * __nonnull CF_RETURNS_RETAINED certsOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Standard signed attributes, optionally specified in + * CMSEncoderAddSignedAttributes(). + */ +typedef CF_OPTIONS(uint32_t, CMSSignedAttributes) { + kCMSAttrNone = 0x0000, + /* + * S/MIME Capabilities - identifies supported signature, encryption, and + * digest algorithms. + */ + kCMSAttrSmimeCapabilities = 0x0001, + /* + * Indicates that a cert is the preferred cert for S/MIME encryption. + */ + kCMSAttrSmimeEncryptionKeyPrefs = 0x0002, + /* + * Same as kCMSSmimeEncryptionKeyPrefs, using an attribute OID preferred + * by Microsoft. + */ + kCMSAttrSmimeMSEncryptionKeyPrefs = 0x0004, + /* + * Include the signing time. + */ + kCMSAttrSigningTime = 0x0008, + /* + * Include the Apple Codesigning Hash Agility. + */ + kCMSAttrAppleCodesigningHashAgility = 0x0010 +}; + +/* + * Optionally specify signed attributes. Only meaningful when creating a + * signed message. If this is called, it must be called before + * CMSEncoderUpdateContent(). + */ +OSStatus CMSEncoderAddSignedAttributes( + CMSEncoderRef cmsEncoder, + CMSSignedAttributes signedAttributes) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Specification of what certificates to include in a signed message. + */ +typedef CF_ENUM(uint32_t, CMSCertificateChainMode) { + kCMSCertificateNone = 0, /* don't include any certificates */ + kCMSCertificateSignerOnly, /* only include signer certificate(s) */ + kCMSCertificateChain, /* signer certificate chain up to but not + * including root certiticate */ + kCMSCertificateChainWithRoot /* signer certificate chain including root */ +}; + +/* + * Optionally specify which certificates, if any, to include in a + * signed CMS message. The default, if this is not called, is + * kCMSCertificateChain, in which case the signer cert plus all CA + * certs needed to verify the signer cert, except for the root + * cert, are included. + * If this is called, it must be called before + * CMSEncoderUpdateContent(). + */ +OSStatus CMSEncoderSetCertificateChainMode( + CMSEncoderRef cmsEncoder, + CMSCertificateChainMode chainMode) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Obtain indication of which signer certs are to be included + * in a signed CMS message. + */ +OSStatus CMSEncoderGetCertificateChainMode( + CMSEncoderRef cmsEncoder, + CMSCertificateChainMode *chainModeOut) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Feed content bytes into the encoder. + * Can be called multiple times. + * No 'setter' routines can be called after this function has been called. + */ +OSStatus CMSEncoderUpdateContent( + CMSEncoderRef cmsEncoder, + const void *content, + size_t contentLen) + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * Finish encoding the message and obtain the encoded result. + * Caller must CFRelease the result. + */ +OSStatus CMSEncoderCopyEncodedContent( + CMSEncoderRef cmsEncoder, + CFDataRef * __nonnull CF_RETURNS_RETAINED encodedContentOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_11_0); + +/* + * High-level, one-shot encoder function. + * + * Inputs (all except for content optional, though at least one + * of {signers, recipients} must be non-NULL) + * ------------------------------------------------------------ + * signers : signer identities. Either a SecIdentityRef, or a + * CFArray of them. + * recipients : recipient certificates. Either a SecCertificateRef, + * or a CFArray of them. + * eContentTypeOID : contentType OID for inner EncapsulatedData, e.g.: + * CFSTR("1.2.840.113549.1.7.1") + * detachedContent : when true, do not include the signed data in the message. + * signedAttributes : Specifies which standard signed attributes are to be + * included in the message. + * content : raw content to be signed and/or encrypted. + * + * Output + * ------ + * encodedContent : the result of the encoding. + */ +OSStatus CMSEncodeContent( + CFTypeRef __nullable signers, + CFTypeRef __nullable recipients, + CFTypeRef __nullable eContentTypeOID, + Boolean detachedContent, + CMSSignedAttributes signedAttributes, + const void *content, + size_t contentLen, + CFDataRef * __nullable CF_RETURNS_RETAINED encodedContentOut) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_11_0); + +#if TIMESTAMPING_SUPOORTED +OSStatus CMSEncoderCopySignerTimestamp( + CMSEncoderRef cmsEncoder, + size_t signerIndex, /* usually 0 */ + CFAbsoluteTime *timestamp) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_NA); + +OSStatus CMSEncoderCopySignerTimestampWithPolicy( + CMSEncoderRef cmsEncoder, + CFTypeRef __nullable timeStampPolicy, + size_t signerIndex, /* usually 0 */ + CFAbsoluteTime *timestamp) /* RETURNED */ + __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_NA); + +void +CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder, CFTypeRef tsaContext); +#endif + +/* + * Obtain the SecCmsMessageRef associated with a CMSEncoderRef. Intended + * to be called after (optionally) setting the encoder's various attributes + * via CMSEncoderAddSigners(), CMSEncoderAddRecipients(), etc. and before + * the first call to CMSEncoderUpdateContent(). The returned SecCmsMessageRef + * will be initialized per the previously specified attributes; the caller + * can manipulate the SecCmsMessageRef prior to proceeding with + * CMSEncoderUpdateContent() calls. + */ +OSStatus CMSEncoderGetCmsMessage( + CMSEncoderRef cmsEncoder, + SecCmsMessageRef _Nullable * _Nonnull cmsMessage); /* RETURNED */ + +/* + * Optionally specify a SecCmsEncoderRef to use with a CMSEncoderRef. + * If this is called, it must be called before the first call to + * CMSEncoderUpdateContent(). The CMSEncoderRef takes ownership of the + * incoming SecCmsEncoderRef. + */ +OSStatus CMSEncoderSetEncoder( + CMSEncoderRef cmsEncoder, + SecCmsEncoderRef encoder); + +/* + * Obtain the SecCmsEncoderRef associated with a CMSEncoderRef. + * Returns a NULL SecCmsEncoderRef if neither CMSEncoderSetEncoder nor + * CMSEncoderUpdateContent() has been called. + * The CMSEncoderRef retains ownership of the SecCmsEncoderRef. + */ +OSStatus CMSEncoderGetEncoder( + CMSEncoderRef cmsEncoder, + SecCmsEncoderRef _Nullable * _Nonnull encoder); /* RETURNED */ + +/* + * Set the signing time for a CMSEncoder. + * This is only used if the kCMSAttrSigningTime attribute is included. + */ +OSStatus CMSEncoderSetSigningTime( + CMSEncoderRef cmsEncoder, + CFAbsoluteTime time); + +/* + * Set the hash agility attribute for a CMSEncoder. + * This is only used if the kCMSAttrAppleCodesigningHashAgility attribute + * is included. + */ +OSStatus CMSEncoderSetAppleCodesigningHashAgility( + CMSEncoderRef cmsEncoder, + CFDataRef hashAgilityAttrValue); + + +CF_ASSUME_NONNULL_END + +__END_DECLS + +#endif /* _CMS_ENCODER_H_ */ + diff --git a/libsecurity_smime/lib/CMSUtils.c b/libsecurity_smime/lib/CMSUtils.c new file mode 100644 index 00000000..80caf601 --- /dev/null +++ b/libsecurity_smime/lib/CMSUtils.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2006,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@ + */ + +/* + * CMSUtils.cpp - common utility routines for libCMS. + */ + +#include "CMSUtils.h" +#include +#include +#include +#include +#include + +/* + * Copy a CSSM_DATA, mallocing the result. + */ +void cmsCopyCmsData( + const SecAsn1Item *src, + SecAsn1Item *dst) +{ + dst->Data = (uint8_t *)malloc(src->Length); + memmove(dst->Data, src->Data, src->Length); + dst->Length = src->Length; +} + +/* + * Append a CF type, or the contents of an array, to another array. + * destination array will be created if necessary. + * If srcItemOrArray is not of the type specified in expectedType, + * errSecParam will be returned. + */ +OSStatus cmsAppendToArray( + CFTypeRef srcItemOrArray, + CFMutableArrayRef *dstArray, + CFTypeID expectedType) +{ + if(srcItemOrArray == NULL) { + return errSecSuccess; + } + if(*dstArray == NULL) { + *dstArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + CFTypeID inType = CFGetTypeID(srcItemOrArray); + if(inType == CFArrayGetTypeID()) { + CFArrayRef srcArray = (CFArrayRef)srcItemOrArray; + CFRange srcRange = {0, CFArrayGetCount(srcArray)}; + CFArrayAppendArray(*dstArray, srcArray, srcRange); + } + else if(inType == expectedType) { + CFArrayAppendValue(*dstArray, srcItemOrArray); + } + else { + return errSecParam; + } + return errSecSuccess; +} + +/* + * Munge an OSStatus returned from libsecurity_smime, which may well be an ASN.1 private + * error code, to a real OSStatus. + */ +OSStatus cmsRtnToOSStatusDefault(OSStatus smimeRtn, // from libsecurity_smime + OSStatus defaultRtn) // use this if we can't map smimeRtn +{ + if(smimeRtn == SECFailure) { + /* This is a SECStatus. Try to get detailed error info. */ + smimeRtn = PORT_GetError(); + if(smimeRtn == 0) { + /* S/MIME just gave us generic error; no further info available; punt. */ + dprintf("cmsRtnToOSStatus: SECFailure, no status avilable\n"); + return defaultRtn ? defaultRtn : errSecInternalComponent; + } + /* else proceed to map smimeRtn to OSStatus */ + } + if(!IS_SEC_ERROR(smimeRtn)) { + /* isn't ASN.1 or S/MIME error; use as is. */ + return smimeRtn; + } + + /* Convert SECErrorCodes to OSStatus */ + switch(smimeRtn) { + case SEC_ERROR_BAD_DER: + case SEC_ERROR_BAD_DATA: + return errSecUnknownFormat; + case SEC_ERROR_NO_MEMORY: + return errSecAllocate; + case SEC_ERROR_IO: + return errSecIO; + case SEC_ERROR_OUTPUT_LEN: + case SEC_ERROR_INPUT_LEN: + case SEC_ERROR_INVALID_ARGS: + case SEC_ERROR_INVALID_ALGORITHM: + case SEC_ERROR_INVALID_AVA: + case SEC_ERROR_INVALID_TIME: + return errSecParam; + case SEC_ERROR_PKCS7_BAD_SIGNATURE: + case SEC_ERROR_BAD_SIGNATURE: + return errSecInvalidSignature; + case SEC_ERROR_EXPIRED_CERTIFICATE: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + return errSecCertificateExpired; + case SEC_ERROR_REVOKED_CERTIFICATE: + return errSecCertificateRevoked; + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_ISSUER: + case SEC_ERROR_UNTRUSTED_CERT: + return errSecNotTrusted; + case SEC_ERROR_CERT_USAGES_INVALID: + case SEC_ERROR_INADEQUATE_KEY_USAGE: + return errSecKeyUsageIncorrect; + case SEC_INTERNAL_ONLY: + return errSecInternalComponent; + case SEC_ERROR_NO_USER_INTERACTION: + return errSecInteractionNotAllowed; + case SEC_ERROR_USER_CANCELLED: + return errSecUserCanceled; + default: + dprintf("cmsRtnToOSStatus: smimeRtn 0x%x\n", smimeRtn); + return defaultRtn ? defaultRtn : errSecInternalComponent; + } +} + +OSStatus cmsRtnToOSStatus(OSStatus smimeRtn) { + return cmsRtnToOSStatusDefault(smimeRtn, 0); +} diff --git a/libsecurity_smime/lib/CMSUtils.h b/libsecurity_smime/lib/CMSUtils.h new file mode 100644 index 00000000..25d5d8fd --- /dev/null +++ b/libsecurity_smime/lib/CMSUtils.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2006,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@ + */ + +/* + * CMSUtils.h - common utility routines for libCMS. + */ + +#ifndef _CMS_UTILS_H_ +#define _CMS_UTILS_H_ + +#include +#include +#include + +__BEGIN_DECLS + +/* + * Copy a CSSM_DATA, mallocing the result. + */ +void cmsCopyCmsData( + const SecAsn1Item *src, + SecAsn1Item *dst); + +/* + * Append a CF type, or the contents of an array, to another array. + * destination array will be created if necessary. + * If srcItemOrArray is not of the type specified in expectedType, + * errSecParam will be returned. + */ +OSStatus cmsAppendToArray( + CFTypeRef srcItemOrArray, + CFMutableArrayRef *dstArray, + CFTypeID expectedType); + +/* + * Munge an OSStatus returned from libsecurity_smime, which may well be an ASN.1 private + * error code, to a real OSStatus. + */ +OSStatus cmsRtnToOSStatus(OSStatus smimeRtn); + +OSStatus cmsRtnToOSStatusDefault(OSStatus smimeRtn, OSStatus defaultRtn); + +#define CFRELEASE(cfr) if(cfr != NULL) { CFRelease(cfr); } + +#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 + +__END_DECLS + +#endif /* _CMS_UTILS_H_ */ + diff --git a/libsecurity_smime/lib/SecCmsBase.h b/libsecurity_smime/lib/SecCmsBase.h index 728b695c..0111155b 100644 --- a/libsecurity_smime/lib/SecCmsBase.h +++ b/libsecurity_smime/lib/SecCmsBase.h @@ -40,7 +40,9 @@ #include #if !SEC_OS_OSX_INCLUDES +#if !USE_CDSA_CRYPTO typedef CFTypeRef SecKeychainRef; +#endif #endif // ! SEC_OS_OSX_INCLUDES #if defined(__cplusplus) diff --git a/libsecurity_smime/lib/SecCmsContentInfo.h b/libsecurity_smime/lib/SecCmsContentInfo.h index f0d72c49..8718d8dc 100644 --- a/libsecurity_smime/lib/SecCmsContentInfo.h +++ b/libsecurity_smime/lib/SecCmsContentInfo.h @@ -165,6 +165,9 @@ SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigest extern OSStatus SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd); +OSStatus +SecCmsContentInfoSetContentOther(SecCmsContentInfoRef cinfo, SecAsn1Item *data, Boolean detached, const SecAsn1Oid *eContentType); + /*! @function */ diff --git a/libsecurity_smime/lib/SecCmsSignerInfo.h b/libsecurity_smime/lib/SecCmsSignerInfo.h index 19cb5737..257a1d26 100644 --- a/libsecurity_smime/lib/SecCmsSignerInfo.h +++ b/libsecurity_smime/lib/SecCmsSignerInfo.h @@ -207,6 +207,15 @@ SecCmsSignerInfoIncludeCerts(SecCmsSignerInfoRef signerinfo, SecCmsCertChainMode extern const char * SecCmsUtilVerificationStatusToString(SecCmsVerificationStatus vs); +/*! + @function SecCmsSignerInfoCopyCertFromEncryptionKeyPreference + @abstract Copy the certificate specified in the encryption key preference. + @param signerinfo The SecCmsSignerInfo object for which we verified the signature. + @result The preferred encryption certificate of the user who signed this message, if found. + @discussion This function should be called after the signer info has been verified. + */ +SecCertificateRef SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo); + #if defined(__cplusplus) } diff --git a/libsecurity_smime/lib/SecSMIMEPriv.h b/libsecurity_smime/lib/SecSMIMEPriv.h index cc74760a..14922a91 100644 --- a/libsecurity_smime/lib/SecSMIMEPriv.h +++ b/libsecurity_smime/lib/SecSMIMEPriv.h @@ -163,7 +163,7 @@ extern OSStatus SecSMIMECreateMSSMIMEEncKeyPrefs(PLArenaPool *poolp, SecAsn1Item * SecSMIMEGetCertFromEncryptionKeyPreference - find cert marked by EncryptionKeyPreference * attribute */ -extern SecCertificateRef SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, SecAsn1Item * DERekp); + extern SecCertificateRef SecSMIMEGetCertFromEncryptionKeyPreference(SecAsn1Item **rawCerts, SecAsn1Item *DERekp); #ifdef __cplusplus diff --git a/libsecurity_smime/lib/cert.h b/libsecurity_smime/lib/cert.h index c9b38991..e2c11364 100644 --- a/libsecurity_smime/lib/cert.h +++ b/libsecurity_smime/lib/cert.h @@ -21,7 +21,9 @@ /************************************************************************/ SEC_BEGIN_PROTOS +#if !USE_CDSA_CRYPTO bool CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial); +#endif typedef void CERTVerifyLog; @@ -86,6 +88,7 @@ SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN); SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID); +SecCertificateRef CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID); // find the smime symmetric capabilities profile for a given cert SecAsn1Item *CERT_FindSMimeProfile(SecCertificateRef cert); @@ -107,8 +110,13 @@ SECStatus CERT_SaveSMimeProfile(SecCertificateRef cert, SecAsn1Item *emailProfil // is given in the common name of the certificate. SECStatus CERT_VerifyCertName(SecCertificateRef cert, const char *hostname); +#if USE_CDSA_CRYPTO +SECStatus CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert, + CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef); +#else SECStatus CERT_VerifyCert(SecKeychainRef keychainOrArray, CFArrayRef cert, CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef); +#endif CFTypeRef CERT_PolicyForCertUsage(SECCertUsage certUsage); diff --git a/libsecurity_smime/lib/cmscinfo.c b/libsecurity_smime/lib/cmscinfo.c index 9a7ebaf1..24540480 100644 --- a/libsecurity_smime/lib/cmscinfo.c +++ b/libsecurity_smime/lib/cmscinfo.c @@ -224,6 +224,35 @@ SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncry return SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_ENCRYPTED_DATA, (void *)encd); } +OSStatus +SecCmsContentInfoSetContentOther(SecCmsContentInfoRef cinfo, SecAsn1Item *data, Boolean detached, const SecAsn1Oid *eContentType) +{ + SECStatus srtn; + SECOidData *tmpOidData; + + /* just like SecCmsContentInfoSetContentData, except override the contentType and + * contentTypeTag. This OID is for encoding... */ + srtn = SECITEM_CopyItem (cinfo->cmsg->poolp, &(cinfo->contentType), eContentType); + if (srtn != SECSuccess) { + return errSecAllocate; + } + + /* this serves up a contentTypeTag with an empty OID */ + tmpOidData = SECOID_FindOIDByTag(SEC_OID_OTHER); + /* but that's const: cook up a new one we can write to */ + cinfo->contentTypeTag = (SECOidData *)PORT_ArenaZAlloc(cinfo->cmsg->poolp, sizeof(SECOidData)); + *cinfo->contentTypeTag = *tmpOidData; + /* now fill in the OID */ + srtn = SECITEM_CopyItem (cinfo->cmsg->poolp, &(cinfo->contentTypeTag->oid), eContentType); + if (srtn != SECSuccess) { + return errSecAllocate; + } + cinfo->content.pointer = data; + cinfo->rawContent = (detached) ? NULL : (data) ? + data : SECITEM_AllocItem(cinfo->cmsg->poolp, NULL, 1); + return noErr; +} + /* * SecCmsContentInfoGetContent - get pointer to inner content * @@ -365,11 +394,16 @@ SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo, void SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkkey) { +#ifdef USE_CDSA_CRYPTO + const CSSM_KEY *cssmKey = NULL; +#endif if (!bulkkey || !cinfo) return; - cinfo->bulkkey = bulkkey; CFRetain(cinfo->bulkkey); - +#ifdef USE_CDSA_CRYPTO + SecKeyGetCSSMKey(cinfo->bulkkey, &cssmKey); + cinfo->keysize = cssmKey ? cssmKey->KeyHeader.LogicalKeySizeInBits : 0; +#else long long bulkKeySize = CFDataGetLength((CFDataRef)bulkkey) * 8; if (bulkKeySize < INT_MAX) { cinfo->keysize = (int)bulkKeySize; @@ -378,6 +412,7 @@ SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkk cinfo->bulkkey = NULL; cinfo->keysize = 0; } +#endif } SecSymmetricKeyRef diff --git a/libsecurity_smime/lib/cmscipher.c b/libsecurity_smime/lib/cmscipher.c index 5d869a6e..3c86da76 100644 --- a/libsecurity_smime/lib/cmscipher.c +++ b/libsecurity_smime/lib/cmscipher.c @@ -45,8 +45,14 @@ #include #include +#if USE_CDSA_CRYPTO +#include +#include +#include +#else #include #include +#endif /* * ------------------------------------------------------------------- @@ -92,6 +98,68 @@ __unused static const SecAsn1Template sec_rc2cbc_parameter_template[] = { { 0 } }; +// TODO: get rid of this? +#if USE_CDSA_CRYPTO +/* +** Convert a der encoded *signed* integer into a machine integral value. +** If an underflow/overflow occurs, sets error code and returns min/max. +*/ +static long +DER_GetInteger(SecAsn1Item *it) +{ + long ival = 0; + unsigned len = it->Length; + unsigned char *cp = it->Data; + unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1); + unsigned long ofloinit; + + if (*cp & 0x80) + ival = -1L; + ofloinit = ival & overflow; + + while (len) { + if ((ival & overflow) != ofloinit) { + PORT_SetError(SEC_ERROR_BAD_DER); + if (ival < 0) { + return LONG_MIN; + } + return LONG_MAX; + } + ival = ival << 8; + ival |= *cp++; + --len; + } + return ival; +} + +/* S/MIME picked id values to represent differnt keysizes */ +/* I do have a formula, but it ain't pretty, and it only works because you + * can always match three points to a parabola:) */ +static unsigned char rc2_map(SecAsn1Item *version) +{ + long x; + + x = DER_GetInteger(version); + + switch (x) { + case 58: return 128; + case 120: return 64; + case 160: return 40; + } + return 128; +} + +static unsigned long rc2_unmap(unsigned long x) +{ + switch (x) { + case 128: return 58; + case 64: return 120; + case 40: return 160; + } + return 58; +} +#endif /* USE_CDSA_CRYPTO */ + /* default IV size in bytes */ #define DEFAULT_IV_SIZE 8 /* IV/block size for AES */ @@ -99,12 +167,14 @@ __unused static const SecAsn1Template sec_rc2cbc_parameter_template[] = { /* max IV size in bytes */ #define MAX_IV_SIZE AES_BLOCK_SIZE +#if !USE_CDSA_CRYPTO #ifndef kCCKeySizeMaxRC2 #define kCCKeySizeMaxRC2 16 #endif #ifndef kCCBlockSizeRC2 #define kCCBlockSizeRC2 8 #endif +#endif static SecCmsCipherContextRef SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid, Boolean encrypt) @@ -115,16 +185,79 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith OSStatus rv; uint8_t ivbuf[MAX_IV_SIZE]; SecAsn1Item initVector = { DEFAULT_IV_SIZE, ivbuf }; +#if USE_CDSA_CRYPTO + CSSM_CC_HANDLE ciphercc = 0; + CSSM_ALGORITHMS algorithm; + CSSM_PADDING padding = CSSM_PADDING_PKCS7; + CSSM_ENCRYPT_MODE mode; + CSSM_CSP_HANDLE cspHandle; + const CSSM_KEY *cssmKey; + //CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_ALG_PARAMS, sizeof(SecAsn1Item *) }; +#else CCCryptorRef ciphercc = NULL; CCOptions cipheroptions = kCCOptionPKCS7Padding; int cipher_blocksize = 0; +#endif + +#if USE_CDSA_CRYPTO + rv = SecKeyGetCSPHandle(key, &cspHandle); + if (rv) + goto loser; + rv = SecKeyGetCSSMKey(key, &cssmKey); + if (rv) + goto loser; +#endif + // @@@ Add support for PBE based stuff oidData = SECOID_FindOID(&algid->algorithm); if (!oidData) goto loser; algtag = oidData->offset; +#if USE_CDSA_CRYPTO + algorithm = oidData->cssmAlgorithm; + if (!algorithm) + goto loser; + + switch (algtag) + { + case SEC_OID_RC2_CBC: + case SEC_OID_RC4: + case SEC_OID_DES_EDE3_CBC: + case SEC_OID_DES_EDE: + case SEC_OID_DES_CBC: + case SEC_OID_RC5_CBC_PAD: + case SEC_OID_FORTEZZA_SKIPJACK: + mode = CSSM_ALGMODE_CBCPadIV8; + break; + + /* RFC 3565 says that these sizes refer to key size, NOT block size */ + case SEC_OID_AES_128_CBC: + case SEC_OID_AES_192_CBC: + case SEC_OID_AES_256_CBC: + initVector.Length = AES_BLOCK_SIZE; + mode = CSSM_ALGMODE_CBCPadIV8; + break; + + case SEC_OID_DES_ECB: + case SEC_OID_AES_128_ECB: + case SEC_OID_AES_192_ECB: + case SEC_OID_AES_256_ECB: + mode = CSSM_ALGMODE_ECBPad; + break; + + case SEC_OID_DES_OFB: + mode = CSSM_ALGMODE_OFBPadIV8; + break; + case SEC_OID_DES_CFB: + mode = CSSM_ALGMODE_CFBPadIV8; + break; + + default: + goto loser; + } +#else CCAlgorithm alg = -1; switch (algtag) { case SEC_OID_DES_CBC: @@ -149,12 +282,30 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith default: goto loser; } +#endif if (encrypt) { +#if USE_CDSA_CRYPTO + CSSM_CC_HANDLE randomcc; + //SecAsn1Item *parameters; + + // Generate random initVector + if (CSSM_CSP_CreateRandomGenContext(cspHandle, + CSSM_ALGID_APPLE_YARROW, + NULL, /* seed*/ + initVector.Length, + &randomcc)) + goto loser; + + if (CSSM_GenerateRandom(randomcc, &initVector)) + goto loser; + CSSM_DeleteContext(randomcc); +#else if (SecRandomCopyBytes(kSecRandomDefault, initVector.Length, initVector.Data)) goto loser; +#endif // Put IV into algid.parameters switch (algtag) @@ -179,6 +330,25 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith goto loser; break; case SEC_OID_RC2_CBC: +#if USE_CDSA_CRYPTO + { + sec_rc2cbcParameter rc2 = {}; + unsigned long rc2version; + SecAsn1Item *newParams; + + rc2.iv = initVector; + rc2version = rc2_unmap(cssmKey->KeyHeader.LogicalKeySizeInBits); + if (!SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion), + rc2version)) + goto loser; + newParams = SEC_ASN1EncodeItem (poolp, &algid->parameters, &rc2, + sec_rc2cbc_parameter_template); + PORT_Free(rc2.rc2ParameterVersion.Data); + if (newParams == NULL) + goto loser; + break; + } +#endif case SEC_OID_RC5_CBC_PAD: default: // @@@ Implement rc5 params stuff. @@ -221,6 +391,31 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith break; } case SEC_OID_RC2_CBC: +#if USE_CDSA_CRYPTO + { + sec_rc2cbcParameter rc2 = {}; + unsigned long ulEffectiveBits; + + rv = SEC_ASN1DecodeItem(NULL, &rc2 ,sec_rc2cbc_parameter_template, + &(algid->parameters)); + if (rv) + goto loser; + + if (initVector.Length != rc2.iv.Length) { + PORT_Free(rc2.iv.Data); + PORT_Free(rc2.rc2ParameterVersion.Data); + goto loser; + } + memcpy(initVector.Data, rc2.iv.Data, initVector.Length); + PORT_Free(rc2.iv.Data); + + ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion); + PORT_Free(rc2.rc2ParameterVersion.Data); + if (ulEffectiveBits != cssmKey->KeyHeader.LogicalKeySizeInBits) + goto loser; + break; + } +#endif case SEC_OID_RC5_CBC_PAD: default: // @@@ Implement rc5 params stuff. @@ -229,10 +424,30 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith } } +#if USE_CDSA_CRYPTO + if (CSSM_CSP_CreateSymmetricContext(cspHandle, + algorithm, + mode, + NULL, /* accessCred */ + cssmKey, + &initVector, + padding, + NULL, /* reserved */ + &ciphercc)) + goto loser; + + if (encrypt) + rv = CSSM_EncryptDataInit(ciphercc); + else + rv = CSSM_DecryptDataInit(ciphercc); + if (rv) + goto loser; +#else if (CCCryptorCreate(encrypt ? kCCEncrypt : kCCDecrypt, alg, cipheroptions, CFDataGetBytePtr(key), CFDataGetLength(key), initVector.Data, &ciphercc)) goto loser; +#endif cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext)); if (cc == NULL) @@ -240,11 +455,17 @@ SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorith cc->cc = ciphercc; cc->encrypt = encrypt; +#if !USE_CDSA_CRYPTO cc->block_size =cipher_blocksize; +#endif return cc; loser: if (ciphercc) +#if USE_CDSA_CRYPTO + CSSM_DeleteContext(ciphercc); +#else CCCryptorRelease(ciphercc); +#endif return NULL; } @@ -261,6 +482,88 @@ SecCmsCipherContextRef SecCmsCipherContextStartDecrypt(SecSymmetricKeyRef key, SECAlgorithmID *algid) { return SecCmsCipherContextStart(NULL, key, algid, PR_FALSE); +#if 0 + SecCmsCipherContextRef cc; + void *ciphercx; + CK_MECHANISM_TYPE mechanism; + SecAsn1Item * param; + PK11SlotInfo *slot; + SECOidTag algtag; + + algtag = SECOID_GetAlgorithmTag(algid); + + /* set param and mechanism */ + if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { + CK_MECHANISM pbeMech, cryptoMech; + SecAsn1Item * pbeParams; + SEC_PKCS5KeyAndPassword *keyPwd; + + PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM)); + PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM)); + + /* HACK ALERT! + * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword * + */ + keyPwd = (SEC_PKCS5KeyAndPassword *)key; + key = keyPwd->key; + + /* find correct PK11 mechanism and parameters to initialize pbeMech */ + pbeMech.mechanism = PK11_AlgtagToMechanism(algtag); + pbeParams = PK11_ParamFromAlgid(algid); + if (!pbeParams) + return NULL; + pbeMech.pParameter = pbeParams->Data; + pbeMech.ulParameterLen = pbeParams->Length; + + /* now map pbeMech to cryptoMech */ + if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem, + PR_FALSE) != CKR_OK) { + SECITEM_ZfreeItem(pbeParams, PR_TRUE); + return NULL; + } + SECITEM_ZfreeItem(pbeParams, PR_TRUE); + + /* and use it to initialize param & mechanism */ + if ((param = (SecAsn1Item *)PORT_ZAlloc(sizeof(SecAsn1Item))) == NULL) + return NULL; + + param->Data = (unsigned char *)cryptoMech.pParameter; + param->Length = cryptoMech.ulParameterLen; + mechanism = cryptoMech.mechanism; + } else { + mechanism = PK11_AlgtagToMechanism(algtag); + if ((param = PK11_ParamFromAlgid(algid)) == NULL) + return NULL; + } + + cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext)); + if (cc == NULL) { + SECITEM_FreeItem(param,PR_TRUE); + return NULL; + } + + /* figure out pad and block sizes */ + cc->pad_size = PK11_GetBlockSize(mechanism, param); + slot = PK11_GetSlotFromKey(key); + cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; + PK11_FreeSlot(slot); + + /* create PK11 cipher context */ + ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_DECRYPT, key, param); + SECITEM_FreeItem(param, PR_TRUE); + if (ciphercx == NULL) { + PORT_Free (cc); + return NULL; + } + + cc->cx = ciphercx; + cc->doit = (nss_cms_cipher_function) PK11_CipherOp; + cc->destroy = (nss_cms_cipher_destroy) PK11_DestroyContext; + cc->encrypt = PR_FALSE; + cc->pending_count = 0; + + return cc; +#endif } /* @@ -276,6 +579,107 @@ SecCmsCipherContextRef SecCmsCipherContextStartEncrypt(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid) { return SecCmsCipherContextStart(poolp, key, algid, PR_TRUE); +#if 0 + SecCmsCipherContextRef cc; + void *ciphercx; + SecAsn1Item * param; + OSStatus rv; + CK_MECHANISM_TYPE mechanism; + PK11SlotInfo *slot; + Boolean needToEncodeAlgid = PR_FALSE; + SECOidTag algtag = SECOID_GetAlgorithmTag(algid); + + /* set param and mechanism */ + if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { + CK_MECHANISM pbeMech, cryptoMech; + SecAsn1Item * pbeParams; + SEC_PKCS5KeyAndPassword *keyPwd; + + PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM)); + PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM)); + + /* HACK ALERT! + * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword * + */ + keyPwd = (SEC_PKCS5KeyAndPassword *)key; + key = keyPwd->key; + + /* find correct PK11 mechanism and parameters to initialize pbeMech */ + pbeMech.mechanism = PK11_AlgtagToMechanism(algtag); + pbeParams = PK11_ParamFromAlgid(algid); + if (!pbeParams) + return NULL; + pbeMech.pParameter = pbeParams->Data; + pbeMech.ulParameterLen = pbeParams->Length; + + /* now map pbeMech to cryptoMech */ + if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem, + PR_FALSE) != CKR_OK) { + SECITEM_ZfreeItem(pbeParams, PR_TRUE); + return NULL; + } + SECITEM_ZfreeItem(pbeParams, PR_TRUE); + + /* and use it to initialize param & mechanism */ + if ((param = (SecAsn1Item *)PORT_ZAlloc(sizeof(SecAsn1Item))) == NULL) + return NULL; + + param->Data = (unsigned char *)cryptoMech.pParameter; + param->Length = cryptoMech.ulParameterLen; + mechanism = cryptoMech.mechanism; + } else { + mechanism = PK11_AlgtagToMechanism(algtag); + if ((param = PK11_GenerateNewParam(mechanism, key)) == NULL) + return NULL; + needToEncodeAlgid = PR_TRUE; + } + + cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext)); + if (cc == NULL) + return NULL; + + /* now find pad and block sizes for our mechanism */ + cc->pad_size = PK11_GetBlockSize(mechanism,param); + slot = PK11_GetSlotFromKey(key); + cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; + PK11_FreeSlot(slot); + + /* and here we go, creating a PK11 cipher context */ + ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT, key, param); + if (ciphercx == NULL) { + PORT_Free(cc); + cc = NULL; + goto loser; + } + + /* + * These are placed after the CreateContextBySymKey() because some + * mechanisms have to generate their IVs from their card (i.e. FORTEZZA). + * Don't move it from here. + * XXX is that right? the purpose of this is to get the correct algid + * containing the IVs etc. for encoding. this means we need to set this up + * BEFORE encoding the algid in the contentInfo, right? + */ + if (needToEncodeAlgid) { + rv = PK11_ParamToAlgid(algtag, param, poolp, algid); + if(rv != SECSuccess) { + PORT_Free(cc); + cc = NULL; + goto loser; + } + } + + cc->cx = ciphercx; + cc->doit = (nss_cms_cipher_function)PK11_CipherOp; + cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext; + cc->encrypt = PR_TRUE; + cc->pending_count = 0; + +loser: + SECITEM_FreeItem(param, PR_TRUE); + + return cc; +#endif } void @@ -284,16 +688,31 @@ SecCmsCipherContextDestroy(SecCmsCipherContextRef cc) PORT_Assert(cc != NULL); if (cc == NULL) return; - +#if USE_CDSA_CRYPTO + CSSM_DeleteContext(cc->cc); +#else CCCryptorRelease(cc->cc); - +#endif PORT_Free(cc); } static unsigned int SecCmsCipherContextLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final, Boolean encrypt) { +#if USE_CDSA_CRYPTO + CSSM_QUERY_SIZE_DATA dataBlockSize[2] = { { input_len, 0 }, { input_len, 0 } }; + /* Hack CDSA treats the last block as the final one. So unless we are being asked to report the final size we ask for 2 block and ignore the second (final) one. */ + OSStatus rv = CSSM_QuerySize(cc->cc, cc->encrypt, final ? 1 : 2, dataBlockSize); + if (rv) + { + PORT_SetError(rv); + return 0; + } + + return dataBlockSize[0].SizeOutputBlock; +#else return ((input_len + cc->block_size - 1) / cc->block_size * cc->block_size) + (final ? cc->block_size : 0); +#endif } /* @@ -320,7 +739,46 @@ SecCmsCipherContextLength(SecCmsCipherContextRef cc, unsigned int input_len, Boo unsigned int SecCmsCipherContextDecryptLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final) { +#if 1 return SecCmsCipherContextLength(cc, input_len, final, PR_FALSE); +#else + int blocks, block_size; + + PORT_Assert (! cc->encrypt); + + block_size = cc->block_size; + + /* + * If this is not a block cipher, then we always have the same + * number of output bytes as we had input bytes. + */ + if (block_size == 0) + return input_len; + + /* + * On the final call, we will always use up all of the pending + * bytes plus all of the input bytes, *but*, there will be padding + * at the end and we cannot predict how many bytes of padding we + * will end up removing. The amount given here is actually known + * to be at least 1 byte too long (because we know we will have + * at least 1 byte of padding), but seemed clearer/better to me. + */ + if (final) + return cc->pending_count + input_len; + + /* + * Okay, this amount is exactly what we will output on the + * next cipher operation. We will always hang onto the last + * 1 - block_size bytes for non-final operations. That is, + * we will do as many complete blocks as we can *except* the + * last block (complete or partial). (This is because until + * we know we are at the end, we cannot know when to interpret + * and removing the padding byte(s), which are guaranteed to + * be there.) + */ + blocks = (cc->pending_count + input_len - 1) / block_size; + return blocks * block_size; +#endif } /* @@ -343,7 +801,48 @@ SecCmsCipherContextDecryptLength(SecCmsCipherContextRef cc, unsigned int input_l unsigned int SecCmsCipherContextEncryptLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final) { +#if 1 return SecCmsCipherContextLength(cc, input_len, final, PR_TRUE); +#else + int blocks, block_size; + int pad_size; + + PORT_Assert (cc->encrypt); + + block_size = cc->block_size; + pad_size = cc->pad_size; + + /* + * If this is not a block cipher, then we always have the same + * number of output bytes as we had input bytes. + */ + if (block_size == 0) + return input_len; + + /* + * On the final call, we only send out what we need for + * remaining bytes plus the padding. (There is always padding, + * so even if we have an exact number of blocks as input, we + * will add another full block that is just padding.) + */ + if (final) { + if (pad_size == 0) { + return cc->pending_count + input_len; + } else { + blocks = (cc->pending_count + input_len) / pad_size; + blocks++; + return blocks*pad_size; + } + } + + /* + * Now, count the number of complete blocks of data we have. + */ + blocks = (cc->pending_count + input_len) / block_size; + + + return blocks * block_size; +#endif } @@ -358,16 +857,34 @@ SecCmsCipherContextCrypt(SecCmsCipherContextRef cc, unsigned char *output, if (input_len) { + +#if USE_CDSA_CRYPTO + SecAsn1Item inputBuf = { input_len, (uint8_t *)input }; + SecAsn1Item outputBuf = { max_output_len, output }; + if (encrypt) + rv = CSSM_EncryptDataUpdate(cc->cc, &inputBuf, 1, &outputBuf, 1, &bytes_output); + else + rv = CSSM_DecryptDataUpdate(cc->cc, &inputBuf, 1, &outputBuf, 1, &bytes_output); +#else rv = CCCryptorUpdate(cc->cc, input, input_len, output, max_output_len, &bytes_output); +#endif } if (!rv && final) { +#if USE_CDSA_CRYPTO + SecAsn1Item remainderBuf = { max_output_len - bytes_output, output + bytes_output }; + if (encrypt) + rv = CSSM_EncryptDataFinal(cc->cc, &remainderBuf); + else + rv = CSSM_DecryptDataFinal(cc->cc, &remainderBuf); + bytes_output += remainderBuf.Length; +#else size_t bytes_output_final = 0; rv = CCCryptorFinal(cc->cc, output+bytes_output, max_output_len-bytes_output, &bytes_output_final); bytes_output += bytes_output_final; +#endif } - if (rv) PORT_SetError(SEC_ERROR_BAD_DATA); else if (output_len_p) @@ -412,10 +929,181 @@ SecCmsCipherContextDecrypt(SecCmsCipherContextRef cc, unsigned char *output, const unsigned char *input, unsigned int input_len, Boolean final) { +#if 1 return SecCmsCipherContextCrypt(cc, output, output_len_p, max_output_len, input, input_len, final, PR_FALSE); +#else + int blocks, bsize, pcount, padsize; + unsigned int max_needed, ifraglen, ofraglen, output_len; + unsigned char *pbuf; + OSStatus rv; + + PORT_Assert (! cc->encrypt); + + /* + * Check that we have enough room for the output. Our caller should + * already handle this; failure is really an internal error (i.e. bug). + */ + max_needed = SecCmsCipherContextDecryptLength(cc, input_len, final); + PORT_Assert (max_output_len >= max_needed); + if (max_output_len < max_needed) { + /* PORT_SetError (XXX); */ + return SECFailure; + } + + /* + * hardware encryption does not like small decryption sizes here, so we + * allow both blocking and padding. + */ + bsize = cc->block_size; + padsize = cc->pad_size; + + /* + * When no blocking or padding work to do, we can simply call the + * cipher function and we are done. + */ + if (bsize == 0) { + return (* cc->doit) (cc->cx, output, output_len_p, max_output_len, + input, input_len); + } + + pcount = cc->pending_count; + pbuf = cc->pending_buf; + + output_len = 0; + + if (pcount) { + /* + * Try to fill in an entire block, starting with the bytes + * we already have saved away. + */ + while (input_len && pcount < bsize) { + pbuf[pcount++] = *input++; + input_len--; + } + /* + * If we have at most a whole block and this is not our last call, + * then we are done for now. (We do not try to decrypt a lone + * single block because we cannot interpret the padding bytes + * until we know we are handling the very last block of all input.) + */ + if (input_len == 0 && !final) { + cc->pending_count = pcount; + if (output_len_p) + *output_len_p = 0; + return SECSuccess; + } + /* + * Given the logic above, we expect to have a full block by now. + * If we do not, there is something wrong, either with our own + * logic or with (length of) the data given to us. + */ + if ((padsize != 0) && (pcount % padsize) != 0) { + PORT_Assert (final); + PORT_SetError (SEC_ERROR_BAD_DATA); + return SECFailure; + } + /* + * Decrypt the block. + */ + rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len, + pbuf, pcount); + if (rv != SECSuccess) + return rv; + + /* + * For now anyway, all of our ciphers have the same number of + * bytes of output as they do input. If this ever becomes untrue, + * then SecCmsCipherContextDecryptLength needs to be made smarter! + */ + PORT_Assert(ofraglen == pcount); + + /* + * Account for the bytes now in output. + */ + max_output_len -= ofraglen; + output_len += ofraglen; + output += ofraglen; + } + + /* + * If this is our last call, we expect to have an exact number of + * blocks left to be decrypted; we will decrypt them all. + * + * If not our last call, we always save between 1 and bsize bytes + * until next time. (We must do this because we cannot be sure + * that none of the decrypted bytes are padding bytes until we + * have at least another whole block of data. You cannot tell by + * looking -- the data could be anything -- you can only tell by + * context, knowing you are looking at the last block.) We could + * decrypt a whole block now but it is easier if we just treat it + * the same way we treat partial block bytes. + */ + if (final) { + if (padsize) { + blocks = input_len / padsize; + ifraglen = blocks * padsize; + } else ifraglen = input_len; + PORT_Assert (ifraglen == input_len); + + if (ifraglen != input_len) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + } else { + blocks = (input_len - 1) / bsize; + ifraglen = blocks * bsize; + PORT_Assert (ifraglen < input_len); + + pcount = input_len - ifraglen; + PORT_Memcpy (pbuf, input + ifraglen, pcount); + cc->pending_count = pcount; + } + + if (ifraglen) { + rv = (* cc->doit)(cc->cx, output, &ofraglen, max_output_len, + input, ifraglen); + if (rv != SECSuccess) + return rv; + + /* + * For now anyway, all of our ciphers have the same number of + * bytes of output as they do input. If this ever becomes untrue, + * then sec_PKCS7DecryptLength needs to be made smarter! + */ + PORT_Assert (ifraglen == ofraglen); + if (ifraglen != ofraglen) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + output_len += ofraglen; + } else { + ofraglen = 0; + } + + /* + * If we just did our very last block, "remove" the padding by + * adjusting the output length. + */ + if (final && (padsize != 0)) { + unsigned int padlen = *(output + ofraglen - 1); + + if (padlen == 0 || padlen > padsize) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + output_len -= padlen; + } + + PORT_Assert (output_len_p != NULL || output_len == 0); + if (output_len_p != NULL) + *output_len_p = output_len; + + return SECSuccess; +#endif } /* @@ -459,8 +1147,146 @@ SecCmsCipherContextEncrypt(SecCmsCipherContextRef cc, unsigned char *output, const unsigned char *input, unsigned int input_len, Boolean final) { +#if 1 return SecCmsCipherContextCrypt(cc, output, output_len_p, max_output_len, input, input_len, final, PR_TRUE); +#else + int blocks, bsize, padlen, pcount, padsize; + unsigned int max_needed, ifraglen, ofraglen, output_len; + unsigned char *pbuf; + OSStatus rv; + + PORT_Assert (cc->encrypt); + + /* + * Check that we have enough room for the output. Our caller should + * already handle this; failure is really an internal error (i.e. bug). + */ + max_needed = SecCmsCipherContextEncryptLength (cc, input_len, final); + PORT_Assert (max_output_len >= max_needed); + if (max_output_len < max_needed) { + /* PORT_SetError (XXX); */ + return SECFailure; + } + + bsize = cc->block_size; + padsize = cc->pad_size; + + /* + * When no blocking and padding work to do, we can simply call the + * cipher function and we are done. + */ + if (bsize == 0) { + return (*cc->doit)(cc->cx, output, output_len_p, max_output_len, + input, input_len); + } + + pcount = cc->pending_count; + pbuf = cc->pending_buf; + + output_len = 0; + + if (pcount) { + /* + * Try to fill in an entire block, starting with the bytes + * we already have saved away. + */ + while (input_len && pcount < bsize) { + pbuf[pcount++] = *input++; + input_len--; + } + /* + * If we do not have a full block and we know we will be + * called again, then we are done for now. + */ + if (pcount < bsize && !final) { + cc->pending_count = pcount; + if (output_len_p != NULL) + *output_len_p = 0; + return SECSuccess; + } + /* + * If we have a whole block available, encrypt it. + */ + if ((padsize == 0) || (pcount % padsize) == 0) { + rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, + pbuf, pcount); + if (rv != SECSuccess) + return rv; + + /* + * For now anyway, all of our ciphers have the same number of + * bytes of output as they do input. If this ever becomes untrue, + * then sec_PKCS7EncryptLength needs to be made smarter! + */ + PORT_Assert (ofraglen == pcount); + + /* + * Account for the bytes now in output. + */ + max_output_len -= ofraglen; + output_len += ofraglen; + output += ofraglen; + + pcount = 0; + } + } + + if (input_len) { + PORT_Assert (pcount == 0); + + blocks = input_len / bsize; + ifraglen = blocks * bsize; + + if (ifraglen) { + rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, + input, ifraglen); + if (rv != SECSuccess) + return rv; + + /* + * For now anyway, all of our ciphers have the same number of + * bytes of output as they do input. If this ever becomes untrue, + * then sec_PKCS7EncryptLength needs to be made smarter! + */ + PORT_Assert (ifraglen == ofraglen); + + max_output_len -= ofraglen; + output_len += ofraglen; + output += ofraglen; + } + + pcount = input_len - ifraglen; + PORT_Assert (pcount < bsize); + if (pcount) + PORT_Memcpy (pbuf, input + ifraglen, pcount); + } + + if (final) { + padlen = padsize - (pcount % padsize); + PORT_Memset (pbuf + pcount, padlen, padlen); + rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, + pbuf, pcount+padlen); + if (rv != SECSuccess) + return rv; + + /* + * For now anyway, all of our ciphers have the same number of + * bytes of output as they do input. If this ever becomes untrue, + * then sec_PKCS7EncryptLength needs to be made smarter! + */ + PORT_Assert (ofraglen == (pcount+padlen)); + output_len += ofraglen; + } else { + cc->pending_count = pcount; + } + + PORT_Assert (output_len_p != NULL || output_len == 0); + if (output_len_p != NULL) + *output_len_p = output_len; + + return SECSuccess; +#endif } diff --git a/libsecurity_smime/lib/cmsdigest.c b/libsecurity_smime/lib/cmsdigest.c index 9b74567b..7b7b7acd 100644 --- a/libsecurity_smime/lib/cmsdigest.c +++ b/libsecurity_smime/lib/cmsdigest.c @@ -44,7 +44,11 @@ #include #include +#if USE_CDSA_CRYPTO +#include +#else #include +#endif #include "SecCmsDigestContext.h" @@ -56,7 +60,11 @@ struct SecCmsDigestContextStr { PLArenaPool * poolp; Boolean saw_contents; int digcnt; +#if USE_CDSA_CRYPTO + CSSM_CC_HANDLE * digobjs; +#else void ** digobjs; +#endif SECAlgorithmID ** digestalgs; }; @@ -69,7 +77,11 @@ SecCmsDigestContextStartMultiple(SECAlgorithmID **digestalgs) { PLArenaPool *poolp; SecCmsDigestContextRef cmsdigcx; +#if USE_CDSA_CRYPTO + CSSM_CC_HANDLE digobj; +#else void * digobj; +#endif int digcnt; int i; @@ -86,15 +98,23 @@ SecCmsDigestContextStartMultiple(SECAlgorithmID **digestalgs) cmsdigcx->poolp = poolp; if (digcnt > 0) { +#if USE_CDSA_CRYPTO + /* Security check to prevent under-allocation */ + if (digcnt >= (int)((INT_MAX/(MAX(sizeof(CSSM_CC_HANDLE),sizeof(SECAlgorithmID *))))-1)) { + goto loser; + } + cmsdigcx->digobjs = (CSSM_CC_HANDLE *)PORT_ArenaAlloc(poolp, digcnt * sizeof(CSSM_CC_HANDLE)); + if (cmsdigcx->digobjs == NULL) + goto loser; +#else /* Security check to prevent under-allocation */ if (digcnt >= (int)((INT_MAX/(MAX(sizeof(void *),sizeof(SECAlgorithmID *))))-1)) { goto loser; } cmsdigcx->digobjs = (void**)PORT_ArenaAlloc(poolp, digcnt * sizeof(void *)); - if (cmsdigcx->digobjs == NULL) goto loser; - +#endif cmsdigcx->digestalgs = (SECAlgorithmID **)PORT_ArenaZAlloc(poolp, (digcnt + 1) * sizeof(SECAlgorithmID *)); if (cmsdigcx->digestalgs == NULL) @@ -116,6 +136,11 @@ SecCmsDigestContextStartMultiple(SECAlgorithmID **digestalgs) * the particular algorithm may not actually be important, * but we cannot know that until later. */ +#if USE_CDSA_CRYPTO + if (digobj) + if (CSSM_DigestDataInit(digobj)) + goto loser; +#endif cmsdigcx->digobjs[cmsdigcx->digcnt] = digobj; cmsdigcx->digestalgs[cmsdigcx->digcnt] = PORT_ArenaAlloc(poolp, sizeof(SECAlgorithmID)); @@ -167,6 +192,9 @@ SecCmsDigestContextUpdate(SecCmsDigestContextRef cmsdigcx, const unsigned char * cmsdigcx->saw_contents = PR_TRUE; for (i = 0; i < cmsdigcx->digcnt; i++) { if (cmsdigcx->digobjs[i]) { +#if USE_CDSA_CRYPTO + CSSM_DigestDataUpdate(cmsdigcx->digobjs[i], &dataBuf, 1); +#else /* 64 bits cast: worst case is we truncate the length and we dont hash all the data. This may cause an invalid CMS blob larger than 4GB to be validated. Unlikely, but possible security issue. There is no way to return an error here, but a check at @@ -191,6 +219,7 @@ SecCmsDigestContextUpdate(SecCmsDigestContextRef cmsdigcx, const unsigned char * default: break; } +#endif } } } @@ -205,7 +234,11 @@ SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx) for (i = 0; i < cmsdigcx->digcnt; i++) if (cmsdigcx->digobjs[i]) +#if USE_CDSA_CRYPTO + CSSM_DeleteContext(cmsdigcx->digobjs[i]); +#else free(cmsdigcx->digobjs[i]); +#endif PORT_FreeArena(cmsdigcx->poolp, PR_TRUE); } @@ -227,7 +260,11 @@ SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, SECAlgorithmID ***digestalgsp, SecAsn1Item * **digestsp) { +#if USE_CDSA_CRYPTO + CSSM_CC_HANDLE digboj; +#else void * digobj; +#endif SecAsn1Item **digests, *digest; SECAlgorithmID **digestalgs; int i; @@ -235,6 +272,25 @@ SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, OSStatus rv = SECFailure; assert(cmsdigcx != NULL); + + /* A message with no contents (just signed attributes) is used within SCEP */ +#if 0 + /* no contents? do not update digests */ + if (digestsp == NULL || !cmsdigcx->saw_contents) { + for (i = 0; i < cmsdigcx->digcnt; i++) + if (cmsdigcx->digobjs[i]) +#if USE_CDSA_CRYPTO + CSSM_DeleteContext(cmsdigcx->digobjs[i]); +#else + free(cmsdigcx->digobjs[i]); +#endif + rv = SECSuccess; + if (digestsp) + *digestsp = NULL; + goto cleanup; + } +#endif + assert(digestsp != NULL); assert(digestalgsp != NULL); @@ -274,7 +330,10 @@ SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, if (digest->Data == NULL) goto loser; digest->Length = diglength; - +#if USE_CDSA_CRYPTO + CSSM_DigestDataFinal(digobj, digest); + CSSM_DeleteContext(digobj); +#else switch (hash_alg) { case SEC_OID_SHA1: CC_SHA1_Final(digest->Data, digobj); break; case SEC_OID_MD5: CC_MD5_Final(digest->Data, digobj); break; @@ -286,6 +345,7 @@ SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, } free(digobj); +#endif digestalgs[i] = cmsdigcx->digestalgs[i]; digests[i] = digest; } diff --git a/libsecurity_smime/lib/cmsencode.c b/libsecurity_smime/lib/cmsencode.c index e18a9492..9b89a58b 100644 --- a/libsecurity_smime/lib/cmsencode.c +++ b/libsecurity_smime/lib/cmsencode.c @@ -548,8 +548,11 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg, result = errSecParam; break; } - if (result) + + if (result) { + PORT_Free(p7ecx); goto loser; + } /* Initialize the BER encoder. * Note that this will not encode anything until the first call to SEC_ASN1EncoderUpdate */ @@ -557,7 +560,7 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg, nss_cms_encoder_out, &(p7ecx->output)); if (p7ecx->ecx == NULL) { result = PORT_GetError(); - PORT_Free (p7ecx); + PORT_Free(p7ecx); goto loser; } p7ecx->ecxupdated = PR_FALSE; @@ -578,7 +581,7 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg, * a child encoder). */ if (SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0) != SECSuccess) { result = PORT_GetError(); - PORT_Free (p7ecx); + PORT_Free(p7ecx); goto loser; } diff --git a/libsecurity_smime/lib/cmsenvdata.c b/libsecurity_smime/lib/cmsenvdata.c index 82f5ae05..b7ccbdd6 100644 --- a/libsecurity_smime/lib/cmsenvdata.c +++ b/libsecurity_smime/lib/cmsenvdata.c @@ -170,6 +170,9 @@ SecCmsEnvelopedDataEncodeBeforeStart(SecCmsEnvelopedDataRef envd) SecCmsRecipientInfoRef *recipientinfos; SecCmsContentInfoRef cinfo; SecSymmetricKeyRef bulkkey = NULL; +#if USE_CDSA_CRYPTO + SecAsn1AlgId algorithm; +#endif SECOidTag bulkalgtag; //CK_MECHANISM_TYPE type; //PK11SlotInfo *slot; @@ -186,6 +189,9 @@ SecCmsEnvelopedDataEncodeBeforeStart(SecCmsEnvelopedDataRef envd) recipientinfos = envd->recipientInfos; if (recipientinfos == NULL) { PORT_SetError(SEC_ERROR_BAD_DATA); +#if 0 + PORT_SetErrorString("Cannot find recipientinfos to encode."); +#endif goto loser; } @@ -215,12 +221,28 @@ SecCmsEnvelopedDataEncodeBeforeStart(SecCmsEnvelopedDataRef envd) bulkalgtag = SEC_OID_DES_EDE3_CBC; } +#if USE_CDSA_CRYPTO + algorithm = SECOID_FindyCssmAlgorithmByTag(bulkalgtag); + if (!algorithm) + goto loser; + rv = SecKeyGenerate(NULL, /* keychainRef */ + algorithm, + SecCmsContentInfoGetBulkKeySize(cinfo), + 0, /* contextHandle */ + CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT, + CSSM_KEYATTR_EXTRACTABLE, + NULL, /* initialAccess */ + &bulkkey); + if (rv) + goto loser; +#else { size_t keysize = (cinfo->keysize + 7)/8; uint8_t key_material[keysize]; require_noerr(SecRandomCopyBytes(kSecRandomDefault, keysize, key_material), loser); bulkkey = (SecSymmetricKeyRef)CFDataCreate(kCFAllocatorDefault, key_material, keysize); } +#endif mark = PORT_ArenaMark(poolp); diff --git a/libsecurity_smime/lib/cmslocal.h b/libsecurity_smime/lib/cmslocal.h index c86c6004..7be1a497 100644 --- a/libsecurity_smime/lib/cmslocal.h +++ b/libsecurity_smime/lib/cmslocal.h @@ -48,7 +48,9 @@ #include extern const SecAsn1Template SecCmsIssuerAndSNTemplate[]; +#if 0 extern const SecAsn1Template SecCmsContentInfoTemplate[]; +#endif extern const SecAsn1Template *nss_cms_get_kea_template(SecCmsKEATemplateSelector whichTemplate); /************************************************************************/ diff --git a/libsecurity_smime/lib/cmspriv.h b/libsecurity_smime/lib/cmspriv.h index 9040fdd0..1c309f03 100644 --- a/libsecurity_smime/lib/cmspriv.h +++ b/libsecurity_smime/lib/cmspriv.h @@ -95,7 +95,12 @@ SecCmsAlgArrayGetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *a extern int SecCmsAlgArrayGetIndexByAlgTag(SECAlgorithmID **algorithmArray, SECOidTag algtag); -extern void *SecCmsUtilGetHashObjByAlgID(SECAlgorithmID *algid); +#if USE_CDSA_CRYPTO +extern CSSM_CC_HANDLE +#else +extern void * +#endif +SecCmsUtilGetHashObjByAlgID(SECAlgorithmID *algid); /* * XXX I would *really* like to not have to do this, but the current diff --git a/libsecurity_smime/lib/cmspubkey.c b/libsecurity_smime/lib/cmspubkey.c index cbaafed4..eb7944e2 100644 --- a/libsecurity_smime/lib/cmspubkey.c +++ b/libsecurity_smime/lib/cmspubkey.c @@ -176,6 +176,10 @@ SecCmsUtilEncryptSymKeyMISSI(PLArenaPool *poolp, SecCertificateRef cert, SecSymm /* Clear keaParams, since cleanup code checks the lengths */ (void) memset(&keaParams, 0, sizeof(keaParams)); +#if USE_CDSA_CRYPTO + SecCertificateGetAlgorithmID(cert,&algid); +#endif + certalgtag = SECOID_GetAlgorithmTag(algid); PORT_Assert(certalgtag == SEC_OID_MISSI_KEA_DSS_OLD || certalgtag == SEC_OID_MISSI_KEA_DSS || diff --git a/libsecurity_smime/lib/cmsrecinfo.c b/libsecurity_smime/lib/cmsrecinfo.c index cf1145a8..5ee5e52b 100644 --- a/libsecurity_smime/lib/cmsrecinfo.c +++ b/libsecurity_smime/lib/cmsrecinfo.c @@ -94,6 +94,15 @@ nss_cmsrecipientinfo_create(SecCmsEnvelopedDataRef envd, SecCmsRecipientIDSelect ri->envelopedData = envd; +#if USE_CDSA_CRYPTO + if (type == SecCmsRecipientIDIssuerSN) + { + rv = SecCertificateGetAlgorithmID(cert,&algid); + } else { + PORT_Assert(pubKey); + rv = SecKeyGetAlgorithmID(pubKey,&algid); + } +#else ri->cert = CERT_DupCertificate(cert); if (ri->cert == NULL) goto loser; @@ -104,6 +113,7 @@ nss_cmsrecipientinfo_create(SecCmsEnvelopedDataRef envd, SecCmsRecipientIDSelect freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; algid = &freeAlgID; +#endif certalgtag = SECOID_GetAlgorithmTag(algid); @@ -457,6 +467,9 @@ SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bul SecCertificateRef cert; SECOidTag certalgtag; OSStatus rv = SECSuccess; +#if 0 + SecAsn1Item * params = NULL; +#endif /* 0 */ SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; const SECAlgorithmID *algid; @@ -466,18 +479,44 @@ SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bul uint8_t nullData[2] = {SEC_ASN1_NULL, 0}; SECItem nullItem; SecCmsKeyAgreeRecipientInfo *kari; +#if USE_CDSA_CRYPTO + SecCmsKeyTransRecipientInfoEx *extra = NULL; +#endif poolp = ri->envelopedData->contentInfo.cmsg->poolp; cert = ri->cert; usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); if (cert) { +#if USE_CDSA_CRYPTO + rv = SecCertificateGetAlgorithmID(cert,&algid); + if (rv) + return SECFailure; +#else const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert); freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data; freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length; freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; algid = &freeAlgID; - } else { +#endif + } +#if USE_CDSA_CRYPTO + else if (usesSubjKeyID) { + extra = &ri->ri.keyTransRecipientInfoEx; + /* sanity check */ + PORT_Assert(extra->pubKey); + if (!extra->pubKey) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + rv = SecKeyGetAlgorithmID(extra->pubKey,&algid); + if (rv) + + return SECFailure; + certalgtag = SECOID_GetAlgorithmTag(algid); + } +#endif + else { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } @@ -494,10 +533,61 @@ SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bul &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; +#if USE_CDSA_CRYPTO + } else if (usesSubjKeyID) { + PORT_Assert(extra != NULL); + rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey, + bulkkey, &ri->ri.keyTransRecipientInfo.encKey); + if (rv != SECSuccess) + break; +#endif } rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); break; +#if 0 + case SEC_OID_MISSI_KEA_DSS_OLD: + case SEC_OID_MISSI_KEA_DSS: + case SEC_OID_MISSI_KEA: + rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey, + bulkalgtag, + &ri->ri.keyTransRecipientInfo.encKey, + ¶ms, ri->cmsg->pwfn_arg); + if (rv != SECSuccess) + break; + + /* here, we DO need to pass the params to the wrap function because, with + * RSA, there is no funny stuff going on with generation of IV vectors or so */ + rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params); + break; + case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ + rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; + if (rek == NULL) { + rv = SECFailure; + break; + } + + oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); + PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); + + /* see RFC2630 12.3.1.1 */ + if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, + SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { + rv = SECFailure; + break; + } + + /* this will generate a key pair, compute the shared secret, */ + /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ + /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ + rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey, + &rek->encKey, + &ri->ri.keyAgreeRecipientInfo.ukm, + &ri->ri.keyAgreeRecipientInfo.keyEncAlg, + &oiok->id.originatorPublicKey.publicKey); + + break; +#endif /* 0 */ case SEC_OID_EC_PUBLIC_KEY: /* These were set up in nss_cmsrecipientinfo_create() */ kari = &ri->ri.keyAgreeRecipientInfo; @@ -538,6 +628,10 @@ SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bul rv = SECFailure; break; } +#if 0 + if (freeSpki) + SECKEY_DestroySubjectPublicKeyInfo(freeSpki); +#endif return rv; } diff --git a/libsecurity_smime/lib/cmssigdata.c b/libsecurity_smime/lib/cmssigdata.c index 99f08e11..c5a7706e 100644 --- a/libsecurity_smime/lib/cmssigdata.c +++ b/libsecurity_smime/lib/cmssigdata.c @@ -51,7 +51,9 @@ #include #include +#if !USE_CDSA_CRYPTO #include +#endif SecCmsSignedDataRef SecCmsSignedDataCreate(SecCmsMessageRef cmsg) @@ -323,10 +325,14 @@ SecCmsSignedDataEncodeAfterData(SecCmsSignedDataRef sigd) signerinfo = signerinfos[si]; for (ci = 0; ci < CFArrayGetCount(signerinfo->certList); ci++) { sigd->rawCerts[rci] = PORT_ArenaZAlloc(poolp, sizeof(SecAsn1Item)); - SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(signerinfo->certList, ci); + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(signerinfo->certList, ci); +#if USE_CDSA_CRYPTO + SecCertificateGetData(cert, sigd->rawCerts[rci++]); +#else SecAsn1Item cert_data = { SecCertificateGetLength(cert), (uint8_t *)SecCertificateGetBytePtr(cert) }; *(sigd->rawCerts[rci++]) = cert_data; +#endif } } } @@ -335,9 +341,13 @@ SecCmsSignedDataEncodeAfterData(SecCmsSignedDataRef sigd) for (ci = 0; ci < CFArrayGetCount(sigd->certs); ci++) { sigd->rawCerts[rci] = PORT_ArenaZAlloc(poolp, sizeof(SecAsn1Item)); SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(sigd->certs, ci); +#if USE_CDSA_CRYPTO + SecCertificateGetData(cert, sigd->rawCerts[rci++]); +#else SecAsn1Item cert_data = { SecCertificateGetLength(cert), (uint8_t *)SecCertificateGetBytePtr(cert) }; *(sigd->rawCerts[rci++]) = cert_data; +#endif } } @@ -475,6 +485,22 @@ SecCmsSignedDataImportCerts(SecCmsSignedDataRef sigd, SecKeychainRef keychain, SECCertUsage certusage, Boolean keepcerts) { OSStatus rv = -1; + +#if USE_CDSA_CRYPTO + int ix, certcount = SecCmsArrayCount((void **)sigd->rawCerts); + rv = CERT_ImportCerts(keychain, certusage, certcount, sigd->rawCerts, NULL, + keepcerts, PR_FALSE, NULL); + /* XXX CRL handling */ + + if (sigd->signerInfos != NULL) { + /* fill in all signerinfo's certs */ + for (ix = 0; sigd->signerInfos[ix] != NULL; i++) + (void)SecCmsSignerInfoGetSigningCertificate(sigd->signerInfos[ix], keychain); + } +#else + // XXX we should only ever import certs for a cert only data blob +#endif + return rv; } @@ -547,6 +573,45 @@ SecCmsSignedDataVerifySignerInfo(SecCmsSignedDataRef sigd, int i, return status; } +#if USE_CDSA_CRYPTO + +/* + * SecCmsSignedDataVerifyCertsOnly - verify the certs in a certs-only message + */ +OSStatus +SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd, + SecKeychainRef keychainOrArray, + CFTypeRef policies) +{ + SecCertificateRef cert; + OSStatus rv = SECSuccess; + int i; + int count; + + if (!sigd || !keychainOrArray || !sigd->rawCerts) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + count = SecCmsArrayCount((void**)sigd->rawCerts); + for (i=0; i < count; i++) { + if (sigd->certs && CFArrayGetCount(sigd->certs) > i) { + cert = (SecCertificateRef)CFArrayGetValueAtIndex(sigd->certs, i); + CFRetain(cert); + } else { + cert = CERT_FindCertByDERCert(keychainOrArray, sigd->rawCerts[i]); + if (!cert) { + rv = SECFailure; + break; + } + } + rv |= CERT_VerifyCert(keychainOrArray, cert, policies, CFAbsoluteTimeGetCurrent(), NULL); + CFRelease(cert); + } + + return rv; +} +#else OSStatus SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd, SecKeychainRef keychainOrArray, @@ -575,6 +640,7 @@ SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd, return rv; } +#endif /* * SecCmsSignedDataHasDigests - see if we have digests in place diff --git a/libsecurity_smime/lib/cmssiginfo.c b/libsecurity_smime/lib/cmssiginfo.c index 10afd418..21d9fd9a 100644 --- a/libsecurity_smime/lib/cmssiginfo.c +++ b/libsecurity_smime/lib/cmssiginfo.c @@ -49,6 +49,10 @@ #include #include +#if USE_CDSA_CRYPTO +#include +#endif + #include #include #include @@ -56,6 +60,7 @@ #include #include #include +#include #define HIDIGIT(v) (((v) / 10) + '0') @@ -189,12 +194,22 @@ SecCmsSignerInfoCreate(SecCmsSignedDataRef sigd, SecIdentityRef identity, SECOid SecCmsSignerInfoRef signerInfo = NULL; SecCertificateRef cert = NULL; SecPrivateKeyRef signingKey = NULL; + CFDictionaryRef keyAttrs = NULL; if (SecIdentityCopyCertificate(identity, &cert)) goto loser; if (SecIdentityCopyPrivateKey(identity, &signingKey)) goto loser; + /* In some situations, the "Private Key" in the identity is actually a public key. Check. */ + keyAttrs = SecKeyCopyAttributes(signingKey); + if (!keyAttrs) + goto loser; + CFTypeRef class = CFDictionaryGetValue(keyAttrs, kSecAttrKeyClass); + if (!class || (CFGetTypeID(class) != CFStringGetTypeID()) || !CFEqual(class, kSecAttrKeyClassPrivate)) { + goto loser; + } + signerInfo = nss_cmssignerinfo_create(sigd, SecCmsSignerIDIssuerSN, cert, NULL, NULL, signingKey, digestalgtag); loser: @@ -202,6 +217,8 @@ loser: CFRelease(cert); if (signingKey) CFRelease(signingKey); + if (keyAttrs) + CFRelease(keyAttrs); return signerInfo; } @@ -287,11 +304,17 @@ loser: void SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si) { - if (si->cert != NULL) - CERT_DestroyCertificate(si->cert); + if (si->cert != NULL) { + CERT_DestroyCertificate(si->cert); + } - if (si->certList != NULL) - CFRelease(si->certList); + if (si->certList != NULL) { + CFRelease(si->certList); + } + + if (si->hashAgilityAttrValue != NULL) { + CFRelease(si->hashAgilityAttrValue); + } /* XXX storage ??? */ } @@ -334,12 +357,34 @@ SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, SecAsn1Item * digest, SecAs privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; cert = signerinfo->cert; +#if USE_CDSA_CRYPTO + if (SecCertificateGetAlgorithmID(cert,&algID)) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + goto loser; + } +#else _algID = SecCertificateGetPublicKeyAlgorithmID(cert); algID = &_algID; +#endif break; case SecCmsSignerIDSubjectKeyID: privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; +#if 0 + spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey); + SECKEY_DestroyPublicKey(signerinfo->pubKey); + signerinfo->pubKey = NULL; + SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm); + SECKEY_DestroySubjectPublicKeyInfo(spki); + algID = &freeAlgID; +#else +#if USE_CDSA_CRYPTO + if (SecKeyGetAlgorithmID(signerinfo->pubKey,&algID)) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + goto loser; + } +#endif +#endif CFRelease(signerinfo->pubKey); signerinfo->pubKey = NULL; break; @@ -356,6 +401,19 @@ SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, SecAsn1Item * digest, SecAs goto loser; } +#if USE_CDSA_CRYPTO + if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) { + SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE); + } +#endif +#if 0 + // @@@ Not yet + /* Fortezza MISSI have weird signature formats. + * Map them to standard DSA formats + */ + pubkAlgTag = PK11_FortezzaMapSig(pubkAlgTag); +#endif + if (signerinfo->authAttr != NULL) { SecAsn1Item encoded_attrs; @@ -399,6 +457,10 @@ SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, SecAsn1Item * digest, SecAs &encoded_attrs) == NULL) goto loser; +#if USE_CDSA_CRYPTO + rv = SEC_SignData(&signature, encoded_attrs.Data, encoded_attrs.Length, + privkey, digestalgtag, pubkAlgTag); +#else signature.Length = SecKeyGetSize(privkey, kSecKeySignatureSize); signature.Data = PORT_ZAlloc(signature.Length); if (!signature.Data) { @@ -410,6 +472,7 @@ SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, SecAsn1Item * digest, SecAs PORT_ZFree(signature.Data, signature.Length); signature.Length = 0; } +#endif PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */ tmppoolp = 0; @@ -455,6 +518,7 @@ loser: return SECFailure; } +#if !USE_CDSA_CRYPTO static CFArrayRef SecCmsSignerInfoCopySigningCertificates(SecCmsSignerInfoRef signerinfo) { @@ -499,8 +563,20 @@ SecCmsSignerInfoCopySigningCertificates(SecCmsSignerInfoRef signerinfo) CFRelease(cert); } } + + if ((CFArrayGetCount(certs) == 0) && + (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID)) + { + SecCertificateRef cert = CERT_FindCertificateBySubjectKeyID(signerinfo->signedData->certs, + signerinfo->signerIdentifier.id.subjectKeyID); + if (cert) { + CFArrayAppendValue(certs, cert); + CFRelease(cert); + } + } return certs; } +#endif OSStatus SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray, @@ -509,9 +585,15 @@ SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef CFAbsoluteTime stime; OSStatus rv; +#if USE_CDSA_CRYPTO + SecCertificateRef cert; + + if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray)) == NULL) { +#else CFArrayRef certs; if ((certs = SecCmsSignerInfoCopySigningCertificates(signerinfo)) == NULL) { +#endif signerinfo->verificationStatus = SecCmsVSSigningCertNotFound; return SECFailure; } @@ -523,15 +605,27 @@ SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef if (SecCmsSignerInfoGetSigningTime(signerinfo, &stime) != SECSuccess) stime = CFAbsoluteTimeGetCurrent(); +#if USE_CDSA_CRYPTO + rv = CERT_VerifyCert(keychainOrArray, cert, policies, stime, trustRef); +#else rv = CERT_VerifyCert(keychainOrArray, certs, policies, stime, trustRef); CFRelease(certs); +#endif if (rv || !trustRef) { if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT) { /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */ +#if 0 +#warning DEBUG - SecCmsSignerInfoVerifyCertificate trusts everything! + if (signerinfo->verificationStatus == SecCmsVSGoodSignature) { + syslog(LOG_ERR, "SecCmsSignerInfoVerifyCertificate ignoring SEC_ERROR_UNTRUSTED_CERT"); + rv = SECSuccess; + } +#else if (signerinfo->verificationStatus == SecCmsVSGoodSignature) signerinfo->verificationStatus = SecCmsVSSigningCertNotTrusted; +#endif } } @@ -564,9 +658,16 @@ SecCmsSignerInfoVerify(SecCmsSignerInfoRef signerinfo, SecAsn1Item * digest, Sec goto loser; } +#if USE_CDSA_CRYPTO + if (SecCertificateCopyPublicKey(cert, &publickey)) { + vs = SecCmsVSProcessingError; + goto loser; + } +#else publickey = SecCertificateCopyPublicKey(cert); if (publickey == NULL) goto loser; +#endif if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) { if (contentType) { @@ -814,6 +915,31 @@ SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo, SecKeychai /* @@@ Make sure we search though all the certs in the cms message itself as well, it's silly to require them to be added to a keychain first. */ +#if USE_CDSA_CRYPTO + SecCmsSignerIdentifier *sid; + + /* + * This cert will also need to be freed, but since we save it + * in signerinfo for later, we do not want to destroy it when + * we leave this function -- we let the clean-up of the entire + * cinfo structure later do the destroy of this cert. + */ + sid = &signerinfo->signerIdentifier; + switch (sid->identifierType) { + case SecCmsSignerIDIssuerSN: + cert = CERT_FindCertByIssuerAndSN(keychainOrArray, sid->id.issuerAndSN); + break; + case SecCmsSignerIDSubjectKeyID: + cert = CERT_FindCertBySubjectKeyID(keychainOrArray, sid->id.subjectKeyID); + break; + default: + cert = NULL; + break; + } + + /* cert can be NULL at that point */ + signerinfo->cert = cert; /* earmark it */ +#else SecAsn1Item **cert_datas = signerinfo->signedData->rawCerts; SecAsn1Item *cert_data; if (cert_datas) while ((cert_data = *cert_datas) != NULL) { @@ -845,6 +971,11 @@ SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo, SecKeychai cert = CERT_FindCertificateByIssuerAndSN(signerinfo->signedData->certs, signerinfo->signerIdentifier.id.issuerAndSN); signerinfo->cert = cert; } + if (!signerinfo->cert && (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID)) { + cert = CERT_FindCertificateBySubjectKeyID(signerinfo->signedData->certs, signerinfo->signerIdentifier.id.subjectKeyID); + signerinfo->cert = cert; + } +#endif return cert; } @@ -868,6 +999,9 @@ SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo) if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL) return NULL; +#if USE_CDSA_CRYPTO + SecCertificateGetCommonName(signercert, &commonName); +#else CFArrayRef commonNames = SecCertificateCopyCommonNames(signercert); if (commonNames) { /* SecCertificateCopyCommonNames doesn't return empty arrays */ @@ -875,6 +1009,7 @@ SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo) CFRetain(commonName); CFRelease(commonNames); } +#endif return commonName; } @@ -896,6 +1031,9 @@ SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo) 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) @@ -904,6 +1042,7 @@ SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo) CFRetain(emailAddress); CFRelease(names); } +#endif return emailAddress; } @@ -1195,6 +1334,33 @@ loser: return status; } +SecCertificateRef SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo) { + SecCertificateRef cert = NULL; + SecCmsAttribute *attr; + SecAsn1Item *ekp; + + /* sanity check - see if verification status is ok (unverified does not count...) */ + if (signerinfo->verificationStatus != SecCmsVSGoodSignature) + return NULL; + + /* find preferred encryption cert */ + if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr) && + (attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, + SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL) + { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */ + ekp = SecCmsAttributeGetValue(attr); + if (ekp == NULL) + return NULL; + + SecAsn1Item **rawCerts = NULL; + if (signerinfo->signedData) { + rawCerts = signerinfo->signedData->rawCerts; + } + cert = SecSMIMEGetCertFromEncryptionKeyPreference(rawCerts, ekp); + } + return cert; +} + /* * XXXX the following needs to be done in the S/MIME layer code * after signature of a signerinfo is verified diff --git a/libsecurity_smime/lib/cmsutil.c b/libsecurity_smime/lib/cmsutil.c index 6af1f730..9ed5d173 100644 --- a/libsecurity_smime/lib/cmsutil.c +++ b/libsecurity_smime/lib/cmsutil.c @@ -48,9 +48,18 @@ #include #include +#if USE_CDSA_CRYPTO +#include +#include +#include + +#else #include #include +#endif + + /* * SecCmsArraySortByDER - sort array of objects by objects' DER encoding * @@ -218,12 +227,27 @@ SecCmsAlgArrayGetIndexByAlgTag(SECAlgorithmID **algorithmArray, return i; } +#if USE_CDSA_CRYPTO +CSSM_CC_HANDLE +#else void * +#endif SecCmsUtilGetHashObjByAlgID(SECAlgorithmID *algid) { SECOidData *oidData = SECOID_FindOID(&(algid->algorithm)); if (oidData) { +#if USE_CDSA_CRYPTO + CSSM_ALGORITHMS alg = oidData->cssmAlgorithm; + if (alg) + { + CSSM_CC_HANDLE digobj; + CSSM_CSP_HANDLE cspHandle = SecCspHandleForAlgorithm(alg); + + if (!CSSM_CSP_CreateDigestContext(cspHandle, alg, &digobj)) + return digobj; + } +#else void *digobj = NULL; switch (oidData->offset) { case SEC_OID_SHA1: @@ -254,6 +278,7 @@ SecCmsUtilGetHashObjByAlgID(SECAlgorithmID *algid) break; } return digobj; +#endif } return 0; diff --git a/libsecurity_smime/lib/crypto-embedded.c b/libsecurity_smime/lib/crypto-embedded.c index 8e9bea6b..d7e4504c 100644 --- a/libsecurity_smime/lib/crypto-embedded.c +++ b/libsecurity_smime/lib/crypto-embedded.c @@ -52,7 +52,7 @@ SECStatus CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs, - CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef) + CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef) { SecTrustRef trust = NULL; OSStatus rv; @@ -65,34 +65,34 @@ CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs, rv = SecTrustSetVerifyDate(trust, verifyDate); CFRelease(verifyDate); if (rv) - goto loser; + goto loser; if (trustRef) { - *trustRef = trust; + *trustRef = trust; } else { - SecTrustResultType result; - /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */ - rv = SecTrustEvaluate(trust, &result); - if (rv) - goto loser; - - switch (result) - { - case kSecTrustResultProceed: - case kSecTrustResultUnspecified: - /* TP Verification succeeded and there was either a UserTurst entry - telling us to procceed, or no user trust setting was specified. */ - CFRelease(trust); - break; - default: - PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); - rv = SECFailure; - goto loser; - break; - } + SecTrustResultType result; + /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */ + rv = SecTrustEvaluate(trust, &result); + if (rv) + goto loser; + + switch (result) + { + case kSecTrustResultProceed: + case kSecTrustResultUnspecified: + /* TP Verification succeeded and there was either a UserTurst entry + telling us to procceed, or no user trust setting was specified. */ + CFRelease(trust); + break; + default: + PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); + rv = SECFailure; + goto loser; + break; + } } return SECSuccess; @@ -170,10 +170,24 @@ CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SE if (SecTrustEvaluate(trust, &result)) goto out; CFIndex idx, count = SecTrustGetCertificateCount(trust); + + /* If we weren't able to build a chain to a self-signed cert, warn. */ + Boolean isSelfSigned = false; + SecCertificateRef lastCert = SecTrustGetCertificateAtIndex(trust, count - 1); + if (lastCert && (0 == SecCertificateIsSelfSigned(lastCert, &isSelfSigned)) && !isSelfSigned) { + CFStringRef commonName = NULL; + (void)SecCertificateCopyCommonName(cert, &commonName); + fprintf(stderr, "Warning: unable to build chain to self-signed root for signer \"%s\"", + commonName ? CFStringGetCStringPtr(commonName, kCFStringEncodingUTF8) : ""); + if (commonName) { CFRelease(commonName); } + } + + /* We don't drop the root if there is only 1 certificate in the chain. */ + if (!includeRoot && count > 1) { count--; } certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); for(idx = 0; idx < count; idx++) CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx)); - + out: if (trust) CFRelease(trust); if (policy) CFRelease(policy); @@ -288,7 +302,7 @@ static CFTypeRef CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray, CFTypeRef cl SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c); CFDataRef nic = (cert) ? SecCertificateGetNormalizedIssuerContent(cert) : NULL; if (nic && CFEqual(nic, issuer)) { - CFDataRef cert_serial = SecCertificateCopySerialNumber(cert); + CFDataRef cert_serial = SecCertificateCopySerialNumberData(cert, NULL); if (cert_serial) { bool found = CFEqual(cert_serial, serial); CFRelease(cert_serial); @@ -328,17 +342,34 @@ SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN); } -SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray __unused, const SecAsn1Item *subjKeyID) +// Generate a certificate key from the Subject Key ID, then look it up in the database. +// Return the cert if found. "subjKeyID" is the Subject Key ID to look for +static CFTypeRef CERT_FindBySubjectKeyID (CFTypeRef keychainOrArray, CFTypeRef class, const SecAsn1Item *subjKeyID) { - SecIdentityRef ident = NULL; - CFDictionaryRef query = NULL; + CFTypeRef ident = NULL; + CFDictionaryRef query = NULL; CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull); - const void *keys[] = { kSecClass, kSecAttrSubjectKeyID, kSecReturnRef }; - const void *values[] = { kSecClassIdentity, subjectkeyid, kCFBooleanTrue }; - query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL); - ident = (SecIdentityRef) CERT_FindItemInAllAvailableKeychains(query); + if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate)) + { + CFIndex c, count = CFArrayGetCount((CFArrayRef)keychainOrArray); + for (c = 0; c < count; c++) { + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c); + CFDataRef skid = (cert) ? SecCertificateGetSubjectKeyID(cert) : NULL; + if (skid && CFEqual(skid, subjectkeyid)) { + CFRetain(cert); + ident = cert; + goto out; + } + } + } + + const void *keys[] = { kSecClass, kSecAttrSubjectKeyID, kSecReturnRef }; + const void *values[] = { class, subjectkeyid, kCFBooleanTrue }; + query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL); + ident = CERT_FindItemInAllAvailableKeychains(query); +out: if (query) CFRelease(query); if (subjectkeyid) @@ -347,6 +378,16 @@ SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray __unus return ident; } +SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID) +{ + return (SecIdentityRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassIdentity, subjKeyID); +} + +SecCertificateRef CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID) +{ + return (SecCertificateRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassCertificate, subjKeyID); +} + SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey) diff --git a/libsecurity_smime/lib/cryptohi.h b/libsecurity_smime/lib/cryptohi.h index 382c0048..87f8e129 100644 --- a/libsecurity_smime/lib/cryptohi.h +++ b/libsecurity_smime/lib/cryptohi.h @@ -39,8 +39,34 @@ #include #include + SEC_BEGIN_PROTOS + +/****************************************/ +/* +** DER encode/decode DSA signatures +*/ + +/* ANSI X9.57 defines DSA signatures as DER encoded data. Our DSA code (and + * most of the rest of the world) just generates 40 bytes of raw data. These + * functions convert between formats. + */ +//extern SECStatus DSAU_EncodeDerSig(SecAsn1Item *dest, SecAsn1Item *src); +//extern SecAsn1Item *DSAU_DecodeDerSig(SecAsn1Item *item); + +#if USE_CDSA_CRYPTO +/* + * Return a csp handle able to deal with algorithm + */ +extern CSSM_CSP_HANDLE SecCspHandleForAlgorithm(CSSM_ALGORITHMS algorithm); + +/* + * Return a CSSM_ALGORITHMS for a given SECOidTag or 0 if there is none + */ +extern CSSM_ALGORITHMS SECOID_FindyCssmAlgorithmByTag(SECOidTag algTag); +#endif + /****************************************/ /* ** Signature creation operations diff --git a/libsecurity_smime/lib/secoid.c b/libsecurity_smime/lib/secoid.c index 2f0f62a9..af40f9ca 100644 --- a/libsecurity_smime/lib/secoid.c +++ b/libsecurity_smime/lib/secoid.c @@ -38,9 +38,12 @@ #include #include +#if USE_CDSA_CRYPTO +#include +#else #include #include - +#endif #include /* MISSI Mosaic Object ID space */ @@ -484,7 +487,11 @@ CONST_OID noOid[] = { 0 }; #define OI(x) { sizeof x, (uint8_t *)x } #ifndef SECOID_NO_STRINGS +#if USE_CDSA_CRYPTO +#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, mech, ext } +#else #define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, ext } +#endif #else #define OD(oid,tag,desc,mech,ext) { OI(oid), tag, 0, mech, ext } #endif @@ -1334,16 +1341,28 @@ InitOIDHash(void) } for ( ix = 0; ix < ( sizeof(oids) / sizeof(SECOidData) ); ix++ ) { - oid = &oids[ix]; + oid = &oids[ix]; + + PORT_Assert ( oid->offset == ix ); - PORT_Assert ( oid->offset == ix ); + entry = PL_HashTableAdd( oidhash, &oid->oid, (void *)oid ); + if ( entry == NULL ) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + PORT_Assert(0); /*This function should never fail. */ + return(SECFailure); + } - entry = PL_HashTableAdd( oidhash, &oid->oid, (void *)oid ); - if ( entry == NULL ) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - PORT_Assert(0); /*This function should never fail. */ - return(SECFailure); - } +#if USE_CDSA_CRYPTO + if ( oid->cssmAlgorithm.algorithm.Length /*CSSM_ALGID_NONE*/ ) { + entry = PL_HashTableAdd( oidmechhash, + (void *)&(oid->cssmAlgorithm), (void *)oid ); + if ( entry == NULL ) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + PORT_Assert(0); /* This function should never fail. */ + return(SECFailure); + } + } +#endif } PORT_Assert (ix == SEC_OID_TOTAL); diff --git a/libsecurity_smime/lib/secoidt.h b/libsecurity_smime/lib/secoidt.h index 85d02020..45731dbb 100644 --- a/libsecurity_smime/lib/secoidt.h +++ b/libsecurity_smime/lib/secoidt.h @@ -49,6 +49,9 @@ struct SECOidDataStr { SecAsn1Item oid; SECOidTag offset; const char * desc; +#if USE_CDSA_CRYPTO + SecAsn1AlgId cssmAlgorithm; +#endif SECSupportExtenTag supportedExtension; /* only used for x.509 v3 extensions, so that we can print the names of those diff --git a/libsecurity_smime/lib/smimeutil.c b/libsecurity_smime/lib/smimeutil.c index e5d89bbc..22694be9 100644 --- a/libsecurity_smime/lib/smimeutil.c +++ b/libsecurity_smime/lib/smimeutil.c @@ -46,6 +46,7 @@ #include #include #include +#include SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate) SEC_ASN1_MKSUB(SEC_OctetStringTemplate) @@ -241,7 +242,12 @@ nss_smime_get_cipher_for_alg_and_key(SECAlgorithmID *algid, SecSymmetricKeyRef k algtag = SECOID_GetAlgorithmTag(algid); switch (algtag) { case SEC_OID_RC2_CBC: +#if USE_CDSA_CRYPTO + if (SecKeyGetStrengthInBits(key, algid, &keylen_bits)) + return SECFailure; +#else keylen_bits = CFDataGetLength((CFDataRef)key) * 8; +#endif switch (keylen_bits) { case 40: c = SMIME_RC2_CBC_40; @@ -471,7 +477,11 @@ smime_choose_cipher(SecCertificateRef scert, SecCertificateRef *rcerts) key = CERT_ExtractPublicKey(rcerts[rcount]); pklen_bits = 0; if (key != NULL) { +#if USE_CDSA_CRYPTO + SecKeyGetStrengthInBits(key, NULL, &pklen_bits); +#else pklen_bits = SecKeyGetSize(key, kSecKeyKeySizeInBits); +#endif SECKEY_DestroyPublicKey (key); } @@ -738,7 +748,28 @@ loser: return (dummy == NULL) ? SECFailure : SECSuccess; } -#if 0 +static CFArrayRef CF_RETURNS_RETAINED copyCertsFromRawCerts(SecAsn1Item **rawCerts) { + CFMutableArrayRef certs = NULL; + SecCertificateRef certificate = NULL; + int numRawCerts = SecCmsArrayCount((void **)rawCerts); + int dex; + + certs = CFArrayCreateMutable(NULL, numRawCerts, &kCFTypeArrayCallBacks); + + for(dex=0; dexData, rawCerts[dex]->Length); + CFArrayAppendValue(certs, certificate); + CFRelease(certificate); + certificate = NULL; + } + + if (CFArrayGetCount(certs) == 0) { + CFRelease(certs); + return NULL; + } + return certs; +} + /* * SecSMIMEGetCertFromEncryptionKeyPreference - * find cert marked by EncryptionKeyPreference attribute @@ -750,11 +781,12 @@ loser: * they are assumed to have been imported already. */ SecCertificateRef -SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, SecAsn1Item *DERekp) +SecSMIMEGetCertFromEncryptionKeyPreference(SecAsn1Item **rawCerts, SecAsn1Item *DERekp) { PLArenaPool *tmppoolp = NULL; SecCertificateRef cert = NULL; NSSSMIMEEncryptionKeyPreference ekp; + CFArrayRef certs = NULL; tmppoolp = PORT_NewArena(1024); if (tmppoolp == NULL) @@ -764,24 +796,25 @@ SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, SecAs if (SEC_ASN1DecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, DERekp) != SECSuccess) goto loser; + certs = copyCertsFromRawCerts(rawCerts); + /* find cert */ switch (ekp.selector) { case NSSSMIMEEncryptionKeyPref_IssuerSN: - cert = CERT_FindCertByIssuerAndSN(keychainOrArray, ekp.id.issuerAndSN); + cert = CERT_FindCertificateByIssuerAndSN(certs, ekp.id.issuerAndSN); break; case NSSSMIMEEncryptionKeyPref_RKeyID: case NSSSMIMEEncryptionKeyPref_SubjectKeyID: - /* XXX not supported yet - we need to be able to look up certs by SubjectKeyID */ + cert = CERT_FindCertificateBySubjectKeyID(certs, ekp.id.subjectKeyID); break; default: PORT_Assert(0); } loser: if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); - + CFRelease(certs); return cert; } -#endif #if 0 extern const char __nss_smime_rcsid[]; diff --git a/libsecurity_smime/libCMS.xcodeproj/project.pbxproj b/libsecurity_smime/libCMS.xcodeproj/project.pbxproj index d816e09c..e87fd2ac 100644 --- a/libsecurity_smime/libCMS.xcodeproj/project.pbxproj +++ b/libsecurity_smime/libCMS.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ isa = PBXAggregateTarget; buildConfigurationList = D447C4DE1D31C9DD0082FC1D /* Build configuration list for PBXAggregateTarget "libCMSInstall" */; buildPhases = ( - D447C4E11D31C9F20082FC1D /* Copy Headers */, ); dependencies = ( D447C4E01D31C9E80082FC1D /* PBXTargetDependency */, @@ -106,7 +105,15 @@ 79DC33800D4E6F170039E4BC /* secoid.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C8E166C0438EEE700CA2E66 /* secoid.c */; }; 79DC33810D4E6F170039E4BC /* smimeutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C27420F03E9FC5B00A80181 /* smimeutil.c */; }; 79DC33820D4E6F170039E4BC /* cmsmessage.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C2741FE03E9FC5B00A80181 /* cmsmessage.c */; }; - D447C4E21D31CA360082FC1D /* SecSMIME.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4C7183470637153700230DDE /* SecSMIME.h */; }; + D4FBBD511DD660E9004408F7 /* CMSUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = D4FBBD4B1DD660E9004408F7 /* CMSUtils.h */; }; + D4FBBD521DD660E9004408F7 /* CMSUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = D4FBBD4C1DD660E9004408F7 /* CMSUtils.c */; }; + D4FBBD531DD660E9004408F7 /* CMSEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = D4FBBD4D1DD660E9004408F7 /* CMSEncoder.h */; }; + D4FBBD541DD660E9004408F7 /* CMSEncoder.c in Sources */ = {isa = PBXBuildFile; fileRef = D4FBBD4E1DD660E9004408F7 /* CMSEncoder.c */; }; + D4FBBD551DD660E9004408F7 /* CMSDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = D4FBBD4F1DD660E9004408F7 /* CMSDecoder.h */; }; + D4FBBD561DD660E9004408F7 /* CMSDecoder.c in Sources */ = {isa = PBXBuildFile; fileRef = D4FBBD501DD660E9004408F7 /* CMSDecoder.c */; }; + D4FBBD641DD661E7004408F7 /* CMSUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = D4FBBD4C1DD660E9004408F7 /* CMSUtils.c */; }; + D4FBBD651DD661E7004408F7 /* CMSEncoder.c in Sources */ = {isa = PBXBuildFile; fileRef = D4FBBD4E1DD660E9004408F7 /* CMSEncoder.c */; }; + D4FBBD661DD661E7004408F7 /* CMSDecoder.c in Sources */ = {isa = PBXBuildFile; fileRef = D4FBBD501DD660E9004408F7 /* CMSDecoder.c */; }; F64399010420118A01CA2DCC /* cert.h in Headers */ = {isa = PBXBuildFile; fileRef = F64398FF0420118A01CA2DCC /* cert.h */; }; F64399020420118A01CA2DCC /* cert.c in Sources */ = {isa = PBXBuildFile; fileRef = F64399000420118A01CA2DCC /* cert.c */; }; /* End PBXBuildFile section */ @@ -178,17 +185,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - D447C4E11D31C9F20082FC1D /* Copy Headers */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 8; - dstPath = /usr/local/include/Security; - dstSubfolderSpec = 0; - files = ( - D447C4E21D31CA360082FC1D /* SecSMIME.h in Copy Headers */, - ); - name = "Copy Headers"; - runOnlyForDeploymentPostprocessing = 1; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -243,6 +239,12 @@ 4CEDC82006371B1700B7E254 /* SecCmsEncryptedData.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCmsEncryptedData.h; sourceTree = ""; }; 79BDD29B0D60C75D000D84D3 /* crypto-embedded.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "crypto-embedded.c"; sourceTree = ""; }; 79DC33620D4E6EEA0039E4BC /* libCMS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCMS.a; sourceTree = BUILT_PRODUCTS_DIR; }; + D4FBBD4B1DD660E9004408F7 /* CMSUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMSUtils.h; sourceTree = ""; }; + D4FBBD4C1DD660E9004408F7 /* CMSUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CMSUtils.c; sourceTree = ""; }; + D4FBBD4D1DD660E9004408F7 /* CMSEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMSEncoder.h; sourceTree = ""; }; + D4FBBD4E1DD660E9004408F7 /* CMSEncoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CMSEncoder.c; sourceTree = ""; }; + D4FBBD4F1DD660E9004408F7 /* CMSDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMSDecoder.h; sourceTree = ""; }; + D4FBBD501DD660E9004408F7 /* CMSDecoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CMSDecoder.c; sourceTree = ""; }; F64398FF0420118A01CA2DCC /* cert.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cert.h; sourceTree = ""; tabWidth = 8; }; F64399000420118A01CA2DCC /* cert.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = cert.c; sourceTree = ""; tabWidth = 8; }; /* End PBXFileReference section */ @@ -337,6 +339,12 @@ children = ( F64399000420118A01CA2DCC /* cert.c */, F64398FF0420118A01CA2DCC /* cert.h */, + D4FBBD4B1DD660E9004408F7 /* CMSUtils.h */, + D4FBBD4C1DD660E9004408F7 /* CMSUtils.c */, + D4FBBD4D1DD660E9004408F7 /* CMSEncoder.h */, + D4FBBD4E1DD660E9004408F7 /* CMSEncoder.c */, + D4FBBD4F1DD660E9004408F7 /* CMSDecoder.h */, + D4FBBD501DD660E9004408F7 /* CMSDecoder.c */, 4C2741F203E9FC5B00A80181 /* cmsarray.c */, 4C2741F303E9FC5B00A80181 /* cmsasn1.c */, 4C2741F403E9FC5B00A80181 /* cmsattr.c */, @@ -405,9 +413,11 @@ 4C8E16750438EF5700CA2E66 /* plhash.h in Headers */, 4CCC260E0635F1A200CBF0D4 /* SecCmsBase.h in Headers */, 4CCC260F0635F1A200CBF0D4 /* SecCmsContentInfo.h in Headers */, + D4FBBD551DD660E9004408F7 /* CMSDecoder.h in Headers */, 4CCC26100635F1A200CBF0D4 /* SecCmsDecoder.h in Headers */, 4CCC26110635F1A200CBF0D4 /* SecCmsDigestContext.h in Headers */, 4CCC26120635F1A200CBF0D4 /* SecCmsDigestedData.h in Headers */, + D4FBBD511DD660E9004408F7 /* CMSUtils.h in Headers */, 4CCC26130635F1A200CBF0D4 /* SecCmsEncoder.h in Headers */, 4CEDC82106371B1700B7E254 /* SecCmsEncryptedData.h in Headers */, 4CCC26140635F1A200CBF0D4 /* SecCmsEnvelopedData.h in Headers */, @@ -416,6 +426,7 @@ 4CCC26170635F1A200CBF0D4 /* SecCmsSignedData.h in Headers */, 4CCC26180635F1A200CBF0D4 /* SecCmsSignerInfo.h in Headers */, 4C8E167A0438EFD700CA2E66 /* SecAsn1Item.h in Headers */, + D4FBBD531DD660E9004408F7 /* CMSEncoder.h in Headers */, 4C8E16700438EEE700CA2E66 /* secoid.h in Headers */, 4C7183480637153700230DDE /* SecSMIME.h in Headers */, 4C424BE8063F28F600E9831A /* SecSMIMEPriv.h in Headers */, @@ -476,7 +487,7 @@ 4C2741E803E9FBAF00A80181 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0830; TargetAttributes = { D447C4DB1D31C9DD0082FC1D = { CreatedOnToolsVersion = 8.0; @@ -540,6 +551,7 @@ 4C27421503E9FC6C00A80181 /* cmscinfo.c in Sources */, 4CDA0D5E04200AD600CA2E66 /* cmscipher.c in Sources */, 4C27421703E9FC6D00A80181 /* cmsdecode.c in Sources */, + D4FBBD541DD660E9004408F7 /* CMSEncoder.c in Sources */, 4C14208F0415845900CA2E66 /* cmsdigdata.c in Sources */, 4CDA0D6104200AD800CA2E66 /* cmsdigest.c in Sources */, 4CDA0D6004200AD800CA2E66 /* cmsencdata.c in Sources */, @@ -554,9 +566,11 @@ 4CB42E340421212D00CA2E66 /* cryptohi.c in Sources */, 4C8E16740438EF5700CA2E66 /* plhash.c in Sources */, 4CB6AADA040DA84D00CA2E66 /* secalgid.c in Sources */, + D4FBBD521DD660E9004408F7 /* CMSUtils.c in Sources */, 4C8E16790438EFD700CA2E66 /* SecAsn1Item.c in Sources */, 4C8E166F0438EEE700CA2E66 /* secoid.c in Sources */, 4CDA0D6704200B0F00CA2E66 /* smimeutil.c in Sources */, + D4FBBD561DD660E9004408F7 /* CMSDecoder.c in Sources */, 79DC32240D4949720039E4BC /* cmsmessage.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -565,6 +579,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D4FBBD641DD661E7004408F7 /* CMSUtils.c in Sources */, + D4FBBD651DD661E7004408F7 /* CMSEncoder.c in Sources */, + D4FBBD661DD661E7004408F7 /* CMSDecoder.c in Sources */, 79DC336B0D4E6F170039E4BC /* cmsarray.c in Sources */, 79DC336C0D4E6F170039E4BC /* cmsasn1.c in Sources */, 79DC336D0D4E6F170039E4BC /* cmsattr.c in Sources */, @@ -611,8 +628,20 @@ 79BDD2AE0D60CA06000D84D3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; GCC_TREAT_WARNINGS_AS_ERRORS = YES; @@ -626,12 +655,14 @@ GCC_WARN_MISSING_PARENTHESES = YES; GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( "-fconstant-cfstrings", "-fno-inline", @@ -712,6 +743,7 @@ "$(PROJECT_DIR)/../OSX/sec", "$(PROJECT_DIR)/../OSX/libsecurity_keychain/libDER", "$(PROJECT_DIR)/../OSX/libsecurity_asn1", + "$(PROJECT_DIR)/../header_symlinks/iOS/", "$(PROJECT_DIR)/../header_symlinks/", "$(BUILT_PRODUCTS_DIR)/usr/local/include", "$(DSTROOT)/usr/local/include", @@ -727,7 +759,19 @@ 79BDD2BA0D60CA0A000D84D3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; GCC_TREAT_WARNINGS_AS_ERRORS = YES; @@ -741,6 +785,7 @@ GCC_WARN_MISSING_PARENTHESES = YES; GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; @@ -824,6 +869,7 @@ "$(PROJECT_DIR)/../OSX/sec", "$(PROJECT_DIR)/../OSX/libsecurity_keychain/libDER", "$(PROJECT_DIR)/../OSX/libsecurity_asn1", + "$(PROJECT_DIR)/../header_symlinks/iOS/", "$(PROJECT_DIR)/../header_symlinks/", "$(BUILT_PRODUCTS_DIR)/usr/local/include", "$(DSTROOT)/usr/local/include", diff --git a/resources/English.lproj/Certificate.strings b/resources/English.lproj/Certificate.strings index 753cc7d53a0f407fce8a72bac28ed8c59bcbd1a8..643fb21f6b6dd3db33cef8eed9bc8573e6d73557 100644 GIT binary patch delta 352 zcmeA>$T;C7d;5yTE zDT5gnRbX+D%E=!B-b{WF;x)M

9`yA(5ekA#pNepe&=pTb(?$Qn3w?k7*!4c delta 73 zcmbPmlCkd~=3$%XYqt2CID6{7+(MY diff --git a/resources/English.lproj/CloudKeychain.strings b/resources/English.lproj/CloudKeychain.strings index 096def0f67958426049b9e402de8f1d3ff7e9d0d..e2c400c34f45896a144f08ae362d4cd03503e558 100644 GIT binary patch delta 887 zcmZ4I_bzh7493Ym{2`OiFuj_5kA;mll|g|)MnRRqfk9TmeljDgIGRYjq~zoPE+g4Q zh7_R6e1<$A>C2GFkPM`?81xyq7?c=7CSQ~hp4_MAGx?na*W_C=TtK$VtN( z%0U$210=I1r%T8}{U8K&zk|90(416;GN9{{fizBEOpX^4g;_T_Lx=~+2HC_nSwU20 z@-kHcZIJ#Ppd(7bp;!zwFC83`nP9RAXm%k`E)^IOC6mvxh%=^wVq)?laUq}ya+#@M z-5|9fH;`Z!P&F)$T!4B(Zh)Ag1eCD_VkHI?@y&uPh0Nk5z=!}@_9^7t7+C eY4Qd}p2;V8?Qog_3X2>NH21>h477%fooX5g8`4OKDSS*dd0!*t3oC4E-1l=YF2%ACK5HUVs vh?;Z4=YZmQAo35JY7%(Okhkof=)0Jwk(kN^Mx delta 30 kcmZ4RhiAbbo(-{v%q0vt%?XC>35JY7%(Okhkof=)0KGs8&;S4c diff --git a/resources/English.lproj/SharedWebCredentials.strings b/resources/English.lproj/SharedWebCredentials.strings index f39f5f3bd18adb4ef1d8ada73e3fa0bfd37ffa40..2b6f90d368337a0c0a37a748c871dd8336c9fd4f 100644 GIT binary patch delta 222 zcmZ3dHb;HJBw-x}BL)KoLk3d@7|VR(#J`gdFiULS!gz-T#F#vfg=_NxHXBA5XYv8I zvdJ7=LX+Lt6DCjK;+QPM=>n76Jb`l^(`Fx@M{JXGggESj8A=(F7)ls2fjEaDl|g|a zjUk_*2uPPQ6a)DnRsoPq1@rP4lEG?{88U!$GDG&{jl80oZVa9bK0p}25YFJjpaj%m h3&ctcZa`CWfKY*<5@=>AL($|$K2bI$25SZ`1^_$vH7Ec8 delta 91 zcmbQEzD{kzq>0P^u%|I3G88dnPVQ$@+`NbJ77I*Zb3a=uBa8!-ojUVaB~Ug VGA7 -#include +#include #include "testlist.h" -#include +#include #include "testlist.h" -#include +#include int main(int argc, char * const *argv) { diff --git a/secacltests/testlist.h b/secacltests/testlist.h index 7ed32bc9..fdde7e32 100644 --- a/secacltests/testlist.h +++ b/secacltests/testlist.h @@ -1,4 +1,4 @@ /* Don't preent multiple inclusions of this file */ -#include +#include ONE_TEST(sec_acl_stress) diff --git a/secdtests/main.m b/secdtests/main.m index ce2c7c92..822f2429 100644 --- a/secdtests/main.m +++ b/secdtests/main.m @@ -7,17 +7,22 @@ // #include -#include +#include #include "testlist.h" -#include +#include #include "testlist.h" -#include +#include + +#include "keychain/ckks/CKKS.h" #include int main(int argc, char * const *argv) { + // secdtests should not run any CKKS. It's not entitled for CloudKit, and CKKS threading interferes with many of the tests. + SecCKKSDisable(); + securityd_init(NULL); int result = tests_begin(argc, argv); diff --git a/secdtests/secdtests-entitlements.plist b/secdtests/secdtests-entitlements.plist index 7db44860..f8a9fb8a 100644 --- a/secdtests/secdtests-entitlements.plist +++ b/secdtests/secdtests-entitlements.plist @@ -2,6 +2,16 @@ + com.apple.private.keychain.sysbound + + com.apple.developer.icloud-services + + CloudKit + + com.apple.private.keychain.backuptableops + + com.apple.private.keychain.backuptableops.deleteall + com.apple.private.applecredentialmanager.allow com.apple.private.security.no-sandbox @@ -33,6 +43,8 @@ apple 123456.test.group 123456.test.group2 + com.apple.ProtectedCloudStorage + com.apple.security.ckks com.apple.private.ubiquity-kvstore-access diff --git a/sectask/SecEntitlements.h b/sectask/SecEntitlements.h index 1212e9f9..f366beb4 100644 --- a/sectask/SecEntitlements.h +++ b/sectask/SecEntitlements.h @@ -36,13 +36,20 @@ __BEGIN_DECLS can be debugged. */ #define kSecEntitlementGetTaskAllow CFSTR("get-task-allow") -#if TARGET_OS_IPHONE /* The identifier of this application, typically the same as the - CFBundleIdentifier. Used as the default access group for any keychain - items this application creates and accesses. */ + CFBundleIdentifier. On iOS, the identifier is prefixed with the team-id and + for some uses, the same applies to macOS. + + This is used as the default access group for any keychain items this + application creates and accesses unless there is a + keychain-access-group-entitlement. + + Note that iOS and macOS uses different value for the same constant. + */ + +#if TARGET_OS_IPHONE #define kSecEntitlementApplicationIdentifier CFSTR("application-identifier") #else -/* The identifier of this application, for Mac App Store applications. */ #define kSecEntitlementAppleApplicationIdentifier CFSTR("com.apple.application-identifier") #define kSecEntitlementApplicationIdentifier kSecEntitlementAppleApplicationIdentifier #endif @@ -64,6 +71,8 @@ __BEGIN_DECLS application group for keychain clients that don't specify an explicit one. */ #define kSecEntitlementAppleSecurityApplicationGroups CFSTR("com.apple.security.application-groups") +#define kSecEntitlementNetworkExtensionAccessGroups CFSTR("com.apple.networkextension.keychain") + /* Boolean entitlement, if present the application with the entitlement is allowed to modify the which certificates are trusted as anchors using the SecTrustStoreSetTrustSettings() and SecTrustStoreRemoveCertificate() @@ -90,6 +99,9 @@ __BEGIN_DECLS /* Boolean entitlement, if present you get access to the SPIs for keychain sync circle manipulation */ #define kSecEntitlementKeychainCloudCircle CFSTR("keychain-cloud-circle") +/* Boolean entitlement, if present you get access to the SPIs for keychain initial sync */ +#define kSecEntitlementKeychainInitialSync CFSTR("com.apple.private.security.initial-sync") + /* Associated Domains entitlement (contains array of fully-qualified domain names) */ #define kSecEntitlementAssociatedDomains CFSTR("com.apple.developer.associated-domains") @@ -117,6 +129,29 @@ __BEGIN_DECLS /* Entitlement to deny use of keychain APIs, only effective on iOS keychain */ #define kSecEntitlementKeychainDeny CFSTR("com.apple.private.keychain.deny") +/* Entitlement to control use of keychain certificate fetching functions */ +#define kSecEntitlementPrivateCertificateAllAccess CFSTR("com.apple.private.keychain.certificates") + +/* Entitlement to control use of CKKS */ +#define kSecEntitlementPrivateCKKS CFSTR("com.apple.private.ckks") + +/* Entitlement to allow manipulation of backup keybags in keychain table */ +#define kSecEntitlementBackupTableOperations CFSTR("com.apple.private.keychain.backuptableops") + +/* Entitlement to allow use of CKKS plaintext fields */ +#define kSecEntitlementPrivateCKKSPlaintextFields CFSTR("com.apple.private.ckks.plaintextfields") + +/* Entitlement to allow use of CKKS 'current item' changing SPI */ +#define kSecEntitlementPrivateCKKSWriteCurrentItemPointers CFSTR("com.apple.private.ckks.currentitempointers_write") + +/* Entitlement to allow use of CKKS 'current item' reading SPI */ +#define kSecEntitlementPrivateCKKSReadCurrentItemPointers CFSTR("com.apple.private.ckks.currentitempointers_read") + +/* Entitlement to allow use of sysbound field */ +#define kSecEntitlementPrivateSysBound CFSTR("com.apple.private.keychain.sysbound") + +#define kSecEntitlementBackupTableOperationsDeleteAll CFSTR("com.apple.private.keychain.backuptableops.deleteall") + __END_DECLS #endif /* !_SECURITY_SECENTITLEMENTS_H_ */ diff --git a/sectask/SecTask.c b/sectask/SecTask.c index 70917b98..284a480d 100644 --- a/sectask/SecTask.c +++ b/sectask/SecTask.c @@ -22,6 +22,7 @@ */ #include "SecTask.h" +#include "SecTaskPriv.h" #include @@ -35,17 +36,18 @@ #include #include -#define USE_LIBPROC 0 -#if USE_LIBPROC -#include -#else #include -#endif + +#if TARGET_OS_OSX +/* These won't exist until we unify codesigning */ +#include "SecCode.h" +#include "SecCodePriv.h" +#include "SecRequirement.h" +#endif /* TARGET_OS_OSX */ struct __SecTask { CFRuntimeBase base; - pid_t pid_self; audit_token_t token; /* Track whether we've loaded entitlements independently since after the @@ -64,11 +66,7 @@ static bool check_task(SecTaskRef task) { static void SecTaskFinalize(CFTypeRef cfTask) { SecTaskRef task = (SecTaskRef) cfTask; - - if (task->entitlements != NULL) { - CFRelease(task->entitlements); - task->entitlements = NULL; - } + CFReleaseNull(task->entitlements); } @@ -79,17 +77,8 @@ static CFStringRef SecTaskCopyDebugDescription(CFTypeRef cfTask) { SecTaskRef task = (SecTaskRef) cfTask; pid_t pid; - if (task->pid_self==-1) { - audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); - } else { - pid = task->pid_self; - } + audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); -#if USE_LIBPROC -#define MAX_PROCNAME 32 - char task_name[MAX_PROCNAME + 1] = {}; - proc_name(pid, task_name, MAX_PROCNAME); -#else const char *task_name; int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; struct kinfo_proc kp; @@ -98,7 +87,6 @@ static CFStringRef SecTaskCopyDebugDescription(CFTypeRef cfTask) task_name = strerror(errno); else task_name = kp.kp_proc.p_comm; -#endif return CFStringCreateWithFormat(CFGetAllocator(task), NULL, CFSTR("%s[%" PRIdPID "]/%d#%d LF=%d"), task_name, pid, task->entitlementsLoaded, task->entitlements ? (int)CFDictionaryGetCount(task->entitlements) : -1, task->lastFailure); @@ -117,10 +105,15 @@ SecTaskRef SecTaskCreateFromSelf(CFAllocatorRef allocator) SecTaskRef task = init_task_ref(allocator); if (task != NULL) { - memset(&task->token, 0, sizeof(task->token)); - task->entitlementsLoaded = false; - task->entitlements = NULL; - task->pid_self = getpid(); + kern_return_t kr = KERN_FAILURE; + mach_msg_type_number_t autoken_cnt = TASK_AUDIT_TOKEN_COUNT; + kr = task_info(mach_task_self(), TASK_AUDIT_TOKEN, (task_info_t)&task->token, &autoken_cnt); + if (kr == KERN_SUCCESS) { + task->entitlementsLoaded = false; + task->entitlements = NULL; + } else { + CFReleaseNull(task); + } } return task; @@ -134,7 +127,6 @@ SecTaskRef SecTaskCreateWithAuditToken(CFAllocatorRef allocator, audit_token_t t memcpy(&task->token, &token, sizeof(token)); task->entitlementsLoaded = false; task->entitlements = NULL; - task->pid_self = -1; } return task; @@ -149,13 +141,11 @@ static int csops_task(SecTaskRef task, int ops, void *blob, size_t size) { int rc; - if (task->pid_self==-1) { - pid_t pid; - audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); - rc = csops_audittoken(pid, ops, blob, size, &task->token); - } - else - rc = csops(task->pid_self, ops, blob, size); + + pid_t pid; + audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); + rc = csops_audittoken(pid, ops, blob, size, &task->token); + task->lastFailure = (rc == -1) ? errno : 0; return rc; } @@ -232,7 +222,10 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) } if (cs_flags != 0) { // was signed - syslog(LOG_NOTICE, "SecTaskLoadEntitlements failed error=%d cs_flags=%x, task->pid_self=%d", entitlementErrno, cs_flags, task->pid_self); // to ease diagnostics + + 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; @@ -243,7 +236,7 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) } syslog(LOG_NOTICE, "SecTaskCopyDebugDescription: %s", descriptionBuf); - CFRelease(description); + CFReleaseNull(description); free(descriptionBuf); } task->lastFailure = entitlementErrno; // was overwritten by csops_task(CS_OPS_STATUS) above @@ -275,7 +268,7 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer+8, bufferlen-8, kCFAllocatorNull); entitlements = (CFMutableDictionaryRef) CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, NULL, error); - CFRelease(data); + CFReleaseNull(data); if((entitlements==NULL) || (CFGetTypeID(entitlements)!=CFDictionaryGetTypeID())){ ret = EDOM; // don't use EINVAL here; it conflates problems with syscall error returns @@ -287,8 +280,7 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error) task->entitlementsLoaded = true; out: - if(entitlements) - CFRelease(entitlements); + CFReleaseNull(entitlements); if(buffer) free(buffer); if (ret && error && *error==NULL) @@ -349,3 +341,45 @@ CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef ent out: return values; } + +#if TARGET_OS_OSX +/* + * Determine if the given task meets a specified requirement. + */ +OSStatus +SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement) +{ + OSStatus status; + SecCodeRef code = NULL; + SecRequirementRef req = NULL; + + CFMutableDictionaryRef codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDataRef auditData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)&task->token, sizeof(audit_token_t)); + CFDictionarySetValue(codeDict, kSecGuestAttributeAudit, auditData); + status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &code); + CFReleaseNull(codeDict); + CFReleaseNull(auditData); + + if (!status) { + status = SecRequirementCreateWithString(requirement, + kSecCSDefaultFlags, &req); + } + if (!status) { + status = SecCodeCheckValidity(code, kSecCSDefaultFlags, req); + } + + CFReleaseNull(req); + CFReleaseNull(code); + + return status; +} +#endif /* TARGET_OS_OSX */ + +Boolean SecTaskEntitlementsValidated(SecTaskRef task) { + // TODO: Cache the result + uint32_t csflags = 0; + const uint32_t mask = CS_VALID | CS_KILL | CS_ENTITLEMENTS_VALIDATED; + int rc = csops_task(task, CS_OPS_STATUS, &csflags, sizeof(csflags)); + return rc != -1 && ((csflags & mask) == mask); +} + diff --git a/OSX/libsecurity_codesigning/lib/SecTaskPriv.h b/sectask/SecTaskPriv.h similarity index 84% rename from OSX/libsecurity_codesigning/lib/SecTaskPriv.h rename to sectask/SecTaskPriv.h index 8ab2469c..b72266ec 100644 --- a/OSX/libsecurity_codesigning/lib/SecTaskPriv.h +++ b/sectask/SecTaskPriv.h @@ -27,10 +27,9 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +__BEGIN_DECLS +#if SEC_OS_OSX /*! @function SecTaskValidateForRequirement @abstract Validate a SecTask instance for a specified requirement. @@ -39,16 +38,8 @@ extern "C" { @result An error code of type OSStatus. Returns errSecSuccess if the task satisfies the requirement. */ -OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); - -/*! - @function SecTaskEntitlementsValidated - @abstract Check whether entitlements can be trusted or not. If this returns - false the tasks entitlements must not be used for anything security sensetive. - @param task A previously created SecTask object -*/ -Boolean SecTaskEntitlementsValidated(SecTaskRef task); +OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); /*! @function SecTaskGetCodeSignStatus @@ -58,9 +49,18 @@ Boolean SecTaskEntitlementsValidated(SecTaskRef task); uint32_t SecTaskGetCodeSignStatus(SecTaskRef task); +#endif /* SEC_OS_OSX */ + +/*! + @function SecTaskEntitlementsValidated + @abstract Check whether entitlements can be trusted or not. If this returns + false the tasks entitlements must not be used for anything security sensetive. + @param task A previously created SecTask object + */ +Boolean SecTaskEntitlementsValidated(SecTaskRef task); + + -#if defined(__cplusplus) -} -#endif +__END_DECLS #endif /* !_SECURITY_SECTASKPRIV_H_ */ diff --git a/sectask/regressions/sectask-10-sectask.c b/sectask/regressions/sectask-10-sectask.c index b0eee593..d38abb2d 100644 --- a/sectask/regressions/sectask-10-sectask.c +++ b/sectask/regressions/sectask-10-sectask.c @@ -157,13 +157,13 @@ out: return 0; } -int sectask_11_sectask_audittoken(int argc, char *const *argv) +int sectask_10_sectask(int argc, char *const *argv) { SecTaskRef task=NULL; CFStringRef appId=NULL; CFStringRef signingIdentifier=NULL; - plan_tests(6); + plan_tests(7); init_self_audittoken(); diff --git a/sectask/regressions/sectask_regressions.h b/sectask/regressions/sectask_regressions.h index 0dfb4214..22d226e1 100644 --- a/sectask/regressions/sectask_regressions.h +++ b/sectask/regressions/sectask_regressions.h @@ -1,9 +1,9 @@ -#include +#include #if !TARGET_IPHONE_SIMULATOR ONE_TEST(sectask_10_sectask_self) -ONE_TEST(sectask_11_sectask_audittoken) +ONE_TEST(sectask_10_sectask) #else OFF_ONE_TEST(sectask_10_sectask_self) -OFF_ONE_TEST(sectask_11_sectask_audittoken) +OFF_ONE_TEST(sectask_10_sectask) #endif diff --git a/security-sysdiagnose/security-sysdiagnose.entitlements.plist b/security-sysdiagnose/security-sysdiagnose.entitlements.plist index d17fb037..2f7c59a9 100644 --- a/security-sysdiagnose/security-sysdiagnose.entitlements.plist +++ b/security-sysdiagnose/security-sysdiagnose.entitlements.plist @@ -2,7 +2,15 @@ + keychain-access-groups + + com.apple.hap.pairing + com.apple.hap.metadata + com.apple.continuity.unlock + keychain-cloud-circle + com.apple.private.ckks + diff --git a/security-sysdiagnose/security-sysdiagnose.m b/security-sysdiagnose/security-sysdiagnose.m index 61422e86..eca91e9f 100644 --- a/security-sysdiagnose/security-sysdiagnose.m +++ b/security-sysdiagnose/security-sysdiagnose.m @@ -22,9 +22,10 @@ */ #import +#import #import -#import +#import #import @@ -32,32 +33,28 @@ #import #import - +#import #include #include "secToolFileIO.h" #include "accountCirclesViewsPrint.h" - +#import "CKKSControlProtocol.h" +#import "SecItemPriv.h" #include @interface NSString (FileOutput) -- (void) writeTo: (FILE*) file; - (void) writeToStdOut; - (void) writeToStdErr; @end @implementation NSString (FileOutput) -- (void) writeTo: (FILE*) file { - CFStringPerformWithCString((__bridge CFStringRef) self, ^(const char *utf8String) { fputs(utf8String, file); }); -} - - (void) writeToStdOut { - [self writeTo: stdout]; + fputs([self UTF8String], stdout); } - (void) writeToStdErr { - [self writeTo: stderr]; + fputs([self UTF8String], stderr); } @end @@ -76,6 +73,21 @@ @end +static NSString *dictionaryToString(NSDictionary *dict) { + NSMutableString *result = [NSMutableString stringWithCapacity:0]; + [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + [result appendFormat:@"%@=%@,", key, obj]; + }]; + return [result substringToIndex:result.length-(result.length>0)]; +} + +@implementation NSDictionary (OneLiner) + +- (NSString*) asOneLineString { + return dictionaryToString(self); +} + +@end static void circle_sysdiagnose(void) @@ -99,14 +111,97 @@ engine_sysdiagnose(void) } } +/* + Here are the commands to dump out all keychain entries used by HomeKit: + security item class=genp,sync=1,agrp=com.apple.hap.pairing; + security item class=genp,sync=0,agrp=com.apple.hap.pairing; + security item class=genp,sync=0,agrp=com.apple.hap.metadata +*/ + +static void printSecItems(NSString *subsystem, CFTypeRef result) { + if (result) { + if (CFGetTypeID(result) == CFArrayGetTypeID()) { + NSArray *items = (__bridge NSArray *)(result); + NSObject *item; + for (item in items) { + if ([item respondsToSelector:@selector(asOneLineString)]) { + [[NSString stringWithFormat: @"%@: %@\n", subsystem, [(NSMutableDictionary *)item asOneLineString]] writeToStdOut]; + } + } + } else { + NSObject *item = (__bridge NSObject *)(result); + if ([item respondsToSelector:@selector(asOneLineString)]) { + [[NSString stringWithFormat: @"%@: %@\n", subsystem, [(NSMutableDictionary *)item asOneLineString]] writeToStdOut]; + } + } + } +} + static void homekit_sysdiagnose(void) { + NSString *kAccessGroupHapPairing = @"com.apple.hap.pairing"; + NSString *kAccessGroupHapMetadata = @"com.apple.hap.metadata"; + + [@"HomeKit keychain state:\n" writeToStdOut]; + + // First look for syncable hap.pairing items + NSMutableDictionary* query = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : kAccessGroupHapPairing, + (id)kSecAttrSynchronizable: (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @NO, + } mutableCopy]; + + CFTypeRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result); + if (status == noErr) { + printSecItems(@"HomeKit", result); + } + CFReleaseNull(result); + + // Now look for non-syncable hap.pairing items + query[(id)kSecAttrSynchronizable] = @NO; + status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result); + if (status == noErr) { + printSecItems(@"HomeKit", result); + } + CFReleaseNull(result); + + // Finally look for non-syncable hap.metadata items + query[(id)kSecAttrAccessGroup] = kAccessGroupHapMetadata; + status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result); + if (status == noErr) { + printSecItems(@"HomeKit", result); + } + CFReleaseNull(result); } static void unlock_sysdiagnose(void) { + NSString *kAccessGroupAutoUnlock = @"com.apple.continuity.unlock"; + + [@"AutoUnlock keychain state:\n" writeToStdOut]; + + NSDictionary* query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : kAccessGroupAutoUnlock, + (id)kSecAttrAccount : @"com.apple.continuity.auto-unlock.sync", + (id)kSecAttrSynchronizable: (id)kCFBooleanTrue, + (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @NO, + }; + + CFTypeRef result = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result); + if (status == noErr) { + printSecItems(@"AutoUnlock", result); + } + CFReleaseNull(result); } static void idsproxy_print_message(CFDictionaryRef messages) @@ -158,6 +253,48 @@ kvs_sysdiagnose(void) { } +static void +ckks_analytics_sysdiagnose(void) +{ + CFErrorRef error = NULL; + xpc_endpoint_t xpcEndpoint = _SecSecuritydCopyCKKSEndpoint(&error); + if (!xpcEndpoint) { + [[NSString stringWithFormat:@"failed to get CKKSControl endpoint with error: %@\n", error] writeToStdErr]; + return; + } + + NSXPCInterface* xpcInterface = [NSXPCInterface interfaceWithProtocol:@protocol(CKKSControlProtocol)]; + NSXPCListenerEndpoint* listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; + [listenerEndpoint _setEndpoint:xpcEndpoint]; + + NSXPCConnection* xpcConnection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; + if (!xpcConnection) { + [@"failed to setup xpc connection for CKKSControl\n" writeToStdErr]; + } + + xpcConnection.remoteObjectInterface = xpcInterface; + [xpcConnection resume]; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [[xpcConnection remoteObjectProxyWithErrorHandler:^(NSError* rpcError) { + [[NSString stringWithFormat:@"Error talking with daemon: %@\n", rpcError] writeToStdErr]; + dispatch_semaphore_signal(semaphore); + }] rpcGetAnalyticsSysdiagnoseWithReply:^(NSString* sysdiagnose, NSError* rpcError) { + if (sysdiagnose && !error) { + [[NSString stringWithFormat:@"\nAnalytics sysdiagnose:\n\n%@\n", sysdiagnose] writeToStdOut]; + } + else { + [[NSString stringWithFormat:@"error retrieving sysdiagnose: %@\n", rpcError] writeToStdErr]; + } + + dispatch_semaphore_signal(semaphore); + }]; + + if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) { + [@"\n\nError: timed out waiting for response\n" writeToStdErr]; + } +} + int main(int argc, const char ** argv) { @@ -169,6 +306,8 @@ main(int argc, const char ** argv) homekit_sysdiagnose(); unlock_sysdiagnose(); idsproxy_sysdiagnose(); + ckks_analytics_sysdiagnose(); + // Keep this one last kvs_sysdiagnose(); } diff --git a/securityd/etc/com.apple.securityd.plist b/securityd/etc/com.apple.securityd.plist index a93b364d..bc500da6 100644 --- a/securityd/etc/com.apple.securityd.plist +++ b/securityd/etc/com.apple.securityd.plist @@ -22,6 +22,13 @@ + EnvironmentVariables + + __CFPREFERENCES_AVOID_DAEMON + 1 + __CF_USER_TEXT_ENCODING + 0x0:0:0 + RunAtLoad LaunchOnlyOnce diff --git a/securityd/securityd_service/KeyStore/KeyStoreEvents.c b/securityd/securityd_service/KeyStore/KeyStoreEvents.c index 63a749d5..726743f8 100644 --- a/securityd/securityd_service/KeyStore/KeyStoreEvents.c +++ b/securityd/securityd_service/KeyStore/KeyStoreEvents.c @@ -9,14 +9,15 @@ #include #include #include +#include static void aksNotificationCallback(void *refcon,io_service_t service, natural_t messageType, void *messageArgument) { if(messageType == kAppleKeyStoreLockStateChangeMessage) { -// syslog(LOG_ERR, "KeyStoreNotifier - %s posting notification: %s\n", __func__, kAppleKeyStoreLockStatusNotificationID); + os_log(OS_LOG_DEFAULT, "KeyStoreNotifier posting lockstate change"); notify_post(kAppleKeyStoreLockStatusNotificationID); } else if (messageType == kAppleKeyStoreFirstUnlockMessage) { -// syslog(LOG_ERR, "KeyStoreNotifier - %s posting notification: %s\n", __func__, kAppleKeyStoreFirstUnlockNotificationID); + os_log(OS_LOG_DEFAULT, "KeyStoreNotifier posting first unlock"); notify_post(kAppleKeyStoreFirstUnlockNotificationID); } } diff --git a/securityd/securityd_service/securityd_service.xcodeproj/project.pbxproj b/securityd/securityd_service/securityd_service.xcodeproj/project.pbxproj index a2284527..0c3c44c0 100644 --- a/securityd/securityd_service/securityd_service.xcodeproj/project.pbxproj +++ b/securityd/securityd_service/securityd_service.xcodeproj/project.pbxproj @@ -25,6 +25,8 @@ 220C5DBA1BD189EC000946A0 /* libsecuritydservice_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1843240E1714797D00196B52 /* libsecuritydservice_client.a */; }; 220C5DC91BD19874000946A0 /* securityd_service_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 18CD2B731714D4B300633846 /* securityd_service_client.h */; settings = {ATTRIBUTES = (Public, ); }; }; 80C312B6169BA50700DA5DC6 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 189D4643166BFDCE001D8533 /* Security.framework */; }; + 8E701CFE1EDF71FC00489AE3 /* MobileKeyBag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E701CFD1EDF71FC00489AE3 /* MobileKeyBag.framework */; }; + EBF81FF61DD7DAE6008A755D /* securityd_service.8 in Copy man8 manual pages */ = {isa = PBXBuildFile; fileRef = EBF81FF31DD7D9C0008A755D /* securityd_service.8 */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -76,6 +78,17 @@ name = "Copy sandbox profile"; runOnlyForDeploymentPostprocessing = 1; }; + EBF81FF51DD7DAC6008A755D /* Copy man8 manual pages */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + EBF81FF61DD7DAE6008A755D /* securityd_service.8 in Copy man8 manual pages */, + ); + name = "Copy man8 manual pages"; + runOnlyForDeploymentPostprocessing = 1; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -100,6 +113,8 @@ 18F4809C174976D2009724DB /* KeyStoreEvents.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = KeyStoreEvents.c; sourceTree = ""; }; 18F4809F17498963009724DB /* AppleKeyStoreEvents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleKeyStoreEvents.h; sourceTree = ""; }; 220C5DCA1BD1A1B8000946A0 /* securitydservicectrl.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = securitydservicectrl.entitlements; sourceTree = ""; }; + 8E701CFD1EDF71FC00489AE3 /* MobileKeyBag.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileKeyBag.framework; path = System/Library/PrivateFrameworks/MobileKeyBag.framework; sourceTree = SDKROOT; }; + EBF81FF31DD7D9C0008A755D /* securityd_service.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = securityd_service.8; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -114,6 +129,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 8E701CFE1EDF71FC00489AE3 /* MobileKeyBag.framework in Frameworks */, 18404F991A8D13F200F74449 /* libbsm.dylib in Frameworks */, 18CD2B791715CEC800633846 /* libaks.a in Frameworks */, 189D4649166C11A6001D8533 /* IOKit.framework in Frameworks */, @@ -175,6 +191,7 @@ 189D4642166BD755001D8533 /* service.entitlements */, 189D4666166C171B001D8533 /* com.apple.securityd_service.plist */, 18D7BBD0171638B9008F80B3 /* com.apple.securitydservice.sb */, + EBF81FF31DD7D9C0008A755D /* securityd_service.8 */, ); path = securityd_service; sourceTree = ""; @@ -182,6 +199,7 @@ 189D4645166BFDD4001D8533 /* Frameworks */ = { isa = PBXGroup; children = ( + 8E701CFD1EDF71FC00489AE3 /* MobileKeyBag.framework */, 18404F981A8D13F200F74449 /* libbsm.dylib */, 18CD2B781715CEC800633846 /* libaks.a */, 189D4648166C11A6001D8533 /* IOKit.framework */, @@ -275,6 +293,7 @@ 189D4632166AC95C001D8533 /* Frameworks */, 189D4633166AC95C001D8533 /* Copy launchd plist */, 18D7BBD1171639CE008F80B3 /* Copy sandbox profile */, + EBF81FF51DD7DAC6008A755D /* Copy man8 manual pages */, ); buildRules = ( ); @@ -328,7 +347,7 @@ 189D462D166AC95C001D8533 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = Apple; }; buildConfigurationList = 189D4630166AC95C001D8533 /* Build configuration list for PBXProject "securityd_service" */; @@ -415,7 +434,6 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_ENUM_CONVERSION = YES; @@ -438,7 +456,6 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_ENUM_CONVERSION = YES; @@ -466,6 +483,7 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -494,7 +512,12 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "-isystem", + "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", + ); SDKROOT = macosx.internal; + SYSTEM_HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/PrivateFrameworks"; }; name = Debug; }; @@ -511,6 +534,7 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -533,7 +557,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_CFLAGS = ( + "-isystem", + "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", + ); SDKROOT = macosx.internal; + SYSTEM_HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/PrivateFrameworks"; }; name = Release; }; @@ -541,7 +570,10 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = securityd_service/service.entitlements; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); INSTALL_PATH = /usr/libexec; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -551,7 +583,10 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = securityd_service/service.entitlements; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); INSTALL_PATH = /usr/libexec; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -579,7 +614,6 @@ BUNDLE_LOADER = /usr/libexec/UserEventAgent; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_ENUM_CONVERSION = YES; @@ -605,7 +639,6 @@ BUNDLE_LOADER = /usr/libexec/UserEventAgent; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_ENUM_CONVERSION = YES; diff --git a/securityd/securityd_service/securityd_service/com.apple.securitydservice.sb b/securityd/securityd_service/securityd_service/com.apple.securitydservice.sb index 8760d133..f9bb91dd 100644 --- a/securityd/securityd_service/securityd_service/com.apple.securitydservice.sb +++ b/securityd/securityd_service/securityd_service/com.apple.securitydservice.sb @@ -19,7 +19,8 @@ (allow mach-lookup (global-name "com.apple.SecurityServer") - (global-name "com.apple.ocspd")) + (global-name "com.apple.ocspd") + (global-name "com.apple.mobile.keybagd.xpc")) (allow iokit-open (iokit-user-client-class "AppleFDEKeyStoreUserClient") diff --git a/securityd/securityd_service/securityd_service/main.c b/securityd/securityd_service/securityd_service/main.c index 1382b5d9..63a2a894 100644 --- a/securityd/securityd_service/securityd_service/main.c +++ b/securityd/securityd_service/securityd_service/main.c @@ -12,10 +12,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -26,15 +26,12 @@ #include #include #include +#include #include #include -#if DEBUG -#define LOG(...) syslog(LOG_ERR, ##__VA_ARGS__); -#else -#define LOG(...) -#endif +#define LOG(...) os_log_debug(OS_LOG_DEFAULT, ##__VA_ARGS__); static bool check_signature(xpc_connection_t connection); @@ -125,7 +122,8 @@ static service_user_record_t * get_user_record(uid_t uid) } char buf[bufsize]; struct passwd pwbuf, *pw = NULL; - if ((getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0) && pw != NULL) { + int rc; + if (((rc = getpwuid_r(uid, &pwbuf, buf, bufsize, &pw)) == 0) && pw != NULL) { ur = calloc(1u, sizeof(service_user_record_t)); require(ur, done); ur->uid = pw->pw_uid; @@ -133,7 +131,7 @@ static service_user_record_t * get_user_record(uid_t uid) ur->home = strdup(pw->pw_dir); ur->name = strdup(pw->pw_name); } else { - syslog(LOG_ERR, "failed to lookup user record for uid: %d", uid); + os_log(OS_LOG_DEFAULT, "failed (%d) to lookup user record for uid: %d", rc, uid); } done: @@ -163,7 +161,8 @@ static const char * get_host_uuid() if (gethostuuid(uuid, &timeout) == 0) { uuid_unparse(uuid, hostuuid); } else { - syslog(LOG_ERR, "failed to get host uuid"); + os_log(OS_LOG_DEFAULT, "failed to get host uuid"); + onceToken = 0; } }); @@ -209,21 +208,24 @@ _kb_verify_create_path(service_user_record_t * ur) if (S_ISDIR(st_info.st_mode)) { created = true; } else { - syslog(LOG_ERR, "invalid directory at '%s' moving aside", kb_path); + os_log(OS_LOG_DEFAULT, "invalid directory at '%s' moving aside", kb_path); snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path); unlink(new_path); if (rename(kb_path, new_path) != 0) { - syslog(LOG_ERR, "failed to rename file: %s (%s)", kb_path, strerror(errno)); + os_log(OS_LOG_DEFAULT, "failed to rename file: %s (%s)", kb_path, strerror(errno)); goto done; } } } if (!created) { - require_action(mkpath_np(kb_path, 0700) == 0, done, syslog(LOG_ERR, "could not create path: %s (%s)", kb_path, strerror(errno))); + require_action(mkpath_np(kb_path, 0700) == 0, done, os_log(OS_LOG_DEFAULT, "could not create path: %s (%s)", kb_path, strerror(errno))); created = true; } done: + if (!created) { + os_log(OS_LOG_DEFAULT, "_kb_verify_create_path failed %s", kb_path); + } return created; } @@ -231,17 +233,17 @@ static void _set_thread_credentials(service_user_record_t * ur) { int rc = pthread_setugid_np(ur->uid, ur->gid); - if (rc) { syslog(LOG_ERR, "failed to set thread credential: %i (%s)", errno, strerror(errno)); } + if (rc) { os_log(OS_LOG_DEFAULT, "failed to set thread credential: %i (%s)", errno, strerror(errno)); } rc = initgroups(ur->name, ur->gid); - if (rc) { syslog(LOG_ERR, "failed to initgroups: %i", rc); } + if (rc) { os_log(OS_LOG_DEFAULT, "failed to initgroups: %i", rc); } } static void _clear_thread_credentials() { int rc = pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE); - if (rc) { syslog(LOG_ERR, "failed to reset thread credential: %i (%s)", errno, strerror(errno)); } + if (rc) { os_log(OS_LOG_DEFAULT, "failed to reset thread credential: %i (%s)", errno, strerror(errno)); } } static bool @@ -258,11 +260,11 @@ _kb_bag_exists(service_user_record_t * ur, const char * bag_file) if (S_ISREG(st_info.st_mode)) { exists = true; } else { - syslog(LOG_ERR, "invalid file at '%s' moving aside", bag_file); + os_log(OS_LOG_DEFAULT, "invalid file at '%s' moving aside", bag_file); snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file); unlink(new_file); if (rename(bag_file, new_file) != 0) { - syslog(LOG_ERR, "failed to rename file: %s (%s)", bag_file, strerror(errno)); + os_log(OS_LOG_DEFAULT, "failed to rename file: %s (%s)", bag_file, strerror(errno)); } } } @@ -284,8 +286,8 @@ _kb_save_bag_to_disk(service_user_record_t * ur, const char * bag_file, void * d require(_kb_verify_create_path(ur), done); fd = open(bag_file, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0600); - require_action(fd != -1, done, syslog(LOG_ERR, "could not create file: %s (%s)", bag_file, strerror(errno))); - require_action(write(fd, data, length) != -1, done, syslog(LOG_ERR, "failed to write keybag to disk %s", strerror(errno))); + require_action(fd != -1, done, os_log(OS_LOG_DEFAULT, "could not create file: %s (%s)", bag_file, strerror(errno))); + require_action(write(fd, data, length) == length, done, os_log(OS_LOG_DEFAULT, "failed to write keybag to disk %s (%s)", bag_file, strerror(errno))); result = true; @@ -308,12 +310,12 @@ _kb_load_bag_from_disk(service_user_record_t * ur, const char * bag_file, uint8_ _set_thread_credentials(ur); require(_kb_verify_create_path(ur), done); - require_quiet(lstat(bag_file, &st_info) == 0, done); - require_action(S_ISREG(st_info.st_mode), done, syslog(LOG_ERR, "failed to load, not a file: %s", bag_file)); + require_action_quiet(lstat(bag_file, &st_info) == 0, done, os_log(OS_LOG_DEFAULT, "failed to stat file: %s (%s)", bag_file, strerror(errno))); + require_action(S_ISREG(st_info.st_mode), done, os_log(OS_LOG_DEFAULT, "failed to load, not a file: %s", bag_file)); buf_size = (size_t)st_info.st_size; fd = open(bag_file, O_RDONLY | O_NOFOLLOW); - require_action(fd != -1, done, syslog(LOG_ERR, "could not open file: %s (%s)", bag_file, strerror(errno))); + require_action(fd != -1, done, os_log(OS_LOG_DEFAULT, "could not open file: %s (%s)", bag_file, strerror(errno))); buf = (uint8_t *)calloc(1u, buf_size); require(buf != NULL, done); @@ -357,18 +359,36 @@ _kb_delete_bag_on_disk(service_user_record_t * ur, const char * bag_file) static int service_kb_load(service_context_t *context); static int service_kb_load_uid(uid_t s_uid); +#ifndef AKS_MACOS_ROOT_HANDLE +#define AKS_MACOS_ROOT_HANDLE 4 //temporary define to avoid dependency on AKS change, filed rdar://problem/30542034 +#endif /* AKS_MACOS_ROOT_HANDLE */ + +static int +_service_kb_set_system(keybag_handle_t handle, keybag_handle_t special_handle) +{ + //Use reserved root handle for root sessions, since 0 clashes with device_keybag_handle in AKS + return aks_set_system(handle, (special_handle == 0) ? AKS_MACOS_ROOT_HANDLE : special_handle); +} + +static int +_service_kb_get_system(keybag_handle_t special_handle, keybag_handle_t * handle_out) +{ + //Use reserved root handle for root sessions, since 0 clashes with device_keybag_handle in AKS + return aks_get_system((special_handle == 0) ? AKS_MACOS_ROOT_HANDLE : special_handle, handle_out); +} + static int _kb_get_session_handle(service_context_t * context, keybag_handle_t * handle_out) { int rc = KB_BagNotLoaded; - require_noerr_quiet(aks_get_system(context->s_uid, handle_out), done); + require_noerr_quiet(_service_kb_get_system(context->s_uid, handle_out), done); rc = KB_Success; done: if (rc == KB_BagNotLoaded) { if (service_kb_load(context) == KB_Success) { - if (aks_get_system(context->s_uid, handle_out) == kIOReturnSuccess) { + if (_service_kb_get_system(context->s_uid, handle_out) == kIOReturnSuccess) { rc = KB_Success; } } @@ -390,7 +410,7 @@ static void update_keybag_handle(keybag_handle_t handle) require(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done); require(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done); - syslog(LOG_NOTICE, "successfully updated handle %d", handle); + os_log(OS_LOG_DEFAULT, "successfully updated handle %d", handle); done: if (buf) free(buf); @@ -399,6 +419,50 @@ static void update_keybag_handle(keybag_handle_t handle) }); } +static int +_kb_get_options_for_uid(uid_t uid, CFMutableDictionaryRef *options_out) +{ + int result = KB_GeneralError; + CFMutableDictionaryRef options = NULL; + CFNumberRef cf_uid = NULL; + + require(options_out, out); + + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), out); + require(cf_uid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &uid), out); + CFDictionaryAddValue(options, kKeyBagDeviceHandle, cf_uid); + + *options_out = options; + options = NULL; + + result = KB_Success; +out: + if (options) { CFRelease(options); } + if (cf_uid) { CFRelease(cf_uid); } + + return result; +} + +static int +_kb_set_user_uuid(service_context_t * context, const void * secret, int secret_len) +{ + int result = KB_GeneralError; + CFMutableDictionaryRef options = NULL; + CFDataRef passcode = NULL; + + require_noerr(_kb_get_options_for_uid(context->s_uid, &options), done); + + /* set user uuid, if not already set */ + passcode = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, secret, secret_len, kCFAllocatorNull); + MKBKeyBagSetUserUUID(options, passcode); + + result = KB_Success; +done: + if (options) { CFRelease(options); } + if (passcode) { CFRelease(passcode); } + return result; +} + static int service_kb_create(service_context_t * context, const void * secret, int secret_len) { @@ -407,7 +471,7 @@ service_kb_create(service_context_t * context, const void * secret, int secret_l dispatch_sync(_kb_service_get_dispatch_queue(), ^{ uint8_t * buf = NULL; size_t buf_size = 0; - keybag_handle_t session_handle = bad_keybag_handle; + keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle; service_user_record_t * ur = get_user_record(context->s_uid); char * bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user); @@ -416,18 +480,24 @@ service_kb_create(service_context_t * context, const void * secret, int secret_l // check for the existance of the bagfile require_action(!_kb_bag_exists(ur, bag_file), done, rc = KB_BagExists); - require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &session_handle), done); - require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done); + require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &private_handle), done); + require_noerr(rc = aks_save_bag(private_handle, (void**)&buf, (int*)&buf_size), done); require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError); - require_noerr(rc = aks_set_system(session_handle, context->s_uid), done); - aks_unload_bag(session_handle); + require_noerr(rc = _service_kb_set_system(private_handle, context->s_uid), done); require_noerr(rc = _kb_get_session_handle(context, &session_handle), done); if (secret && rc == KB_Success) { aks_unlock_bag(session_handle, secret, secret_len); } + if (rc == KB_Success) { + _kb_set_user_uuid(context, secret, secret_len); + } + done: + if (private_handle != bad_keybag_handle) { + aks_unload_bag(private_handle); + } if (buf) free(buf); if (bag_file) { free(bag_file); } if (ur) free_user_record(ur); @@ -445,28 +515,35 @@ _service_kb_load_uid(uid_t s_uid) dispatch_sync(_kb_service_get_dispatch_queue(), ^{ uint8_t * buf = NULL; size_t buf_size = 0; - keybag_handle_t session_handle = bad_keybag_handle; + keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle; service_user_record_t * ur = NULL; char * bag_file = NULL; + int _stage = 0; - rc = aks_get_system(s_uid, &session_handle); + rc = _service_kb_get_system(s_uid, &session_handle); if (rc == kIOReturnNotFound) { - require_action(ur = get_user_record(s_uid), done, rc = KB_GeneralError); - require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError); - require_action_quiet(_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size), done, rc = KB_BagNotFound); - rc = aks_load_bag(buf, (int)buf_size, &session_handle); - if (rc == kIOReturnNotPermitted) { - syslog(LOG_ERR, "error loading keybag for uid (%i)", s_uid); + require_action(ur = get_user_record(s_uid), done, rc = KB_GeneralError; _stage = 1); + require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError; _stage = 2); + require_action_quiet(_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size), done, rc = KB_BagNotFound; _stage = 3); + rc = aks_load_bag(buf, (int)buf_size, &private_handle); + if (rc == kIOReturnNotPermitted || rc == kAKSReturnBadDeviceKey) { + os_log(OS_LOG_DEFAULT, "bag load failed %d for uid (%i)", rc, s_uid); _kb_rename_bag_on_disk(ur, bag_file); rc = KB_BagNotFound; } - require_noerr(rc, done); - require_noerr(rc = aks_set_system(session_handle, s_uid), done); - aks_unload_bag(session_handle); + require_noerr(rc, done; _stage = 4); + require_noerr(rc = _service_kb_set_system(private_handle, s_uid), done; _stage = 5); } require(rc == KB_Success, done); done: + if (private_handle != bad_keybag_handle) { + aks_unload_bag(private_handle); + } + // this function should never fail unless bootstrapping the user for the first time, or rare conditions from aks_load_bag + if (rc != KB_Success) { + os_log(OS_LOG_DEFAULT, "%d: error %d loading keybag for uid (%i) at path: %s", _stage, rc, s_uid, bag_file); + } if (buf) free(buf); if (ur) free_user_record(ur); if (bag_file) free(bag_file); @@ -495,23 +572,23 @@ service_kb_unload(service_context_t *context) dispatch_sync(_kb_service_get_dispatch_queue(), ^{ keybag_handle_t session_handle = bad_keybag_handle; - rc = aks_get_system(context->s_uid, &session_handle); + rc = _service_kb_get_system(context->s_uid, &session_handle); if (rc == kIOReturnNotFound) { // No session bag, nothing to do rc = KB_Success; return; } else if (rc != kIOReturnSuccess) { - syslog(LOG_ERR, "error locating session keybag for uid (%i) in session (%i)", context->s_uid, context->s_id); + os_log(OS_LOG_DEFAULT, "error locating session keybag for uid (%i) in session (%i)", context->s_uid, context->s_id); rc = KB_BagError; return; } rc = aks_unload_bag(session_handle); if (rc != kAKSReturnSuccess) { - syslog(LOG_ERR, "error unloading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id); + os_log(OS_LOG_DEFAULT, "error unloading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id); rc = KB_BagError; } else { - syslog(LOG_ERR, "successfully unloaded keybag (%ld) for uid (%i) in session (%i)", (long)session_handle, context->s_uid, context->s_id); + os_log(OS_LOG_DEFAULT, "successfully unloaded keybag (%ld) for uid (%i) in session (%i)", (long)session_handle, context->s_uid, context->s_id); } }); @@ -554,12 +631,22 @@ service_kb_unlock(service_context_t * context, const void * secret, int secret_l { int rc = KB_GeneralError; keybag_handle_t session_handle; + CFDataRef passcode = NULL; + CFMutableDictionaryRef options = NULL; + + require_noerr(_kb_get_options_for_uid(context->s_uid, &options), done); + + /* technically, session_handle is not needed. Call this to handle lazy keybag loading */ require_noerr(rc = _kb_get_session_handle(context, &session_handle), done); - rc = aks_unlock_bag(session_handle, secret, secret_len); + require(passcode = CFDataCreateWithBytesNoCopy(NULL, secret, secret_len, kCFAllocatorNull), done); + + rc = MKBUnlockDevice(passcode, options); + os_log(OS_LOG_DEFAULT, "MKBUnlockDevice result: (%ld)", (long)rc); done: - syslog(LOG_NOTICE, "aks_unlock_bag result: (%ld)", (long)rc); + if (options) { CFRelease(options); } + if (passcode) { CFRelease(passcode); } return rc; } @@ -583,7 +670,7 @@ service_kb_change_secret(service_context_t * context, const void * secret, int s service_user_record_t * ur = NULL; char * bag_file = NULL; - require_noerr(rc = aks_change_secret(session_handle, secret, secret_len, new_secret, new_secret_len, NULL, NULL), done); + require_noerr(rc = aks_change_secret(session_handle, secret, secret_len, new_secret, new_secret_len, generation_noop, NULL), done); require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done); require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError); require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError); @@ -615,23 +702,29 @@ service_kb_reset(service_context_t * context, const void * secret, int secret_le dispatch_sync(_kb_service_get_dispatch_queue(), ^{ uint8_t * buf = NULL; size_t buf_size = 0; - keybag_handle_t session_handle = bad_keybag_handle; + keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle; - syslog(LOG_ERR, "resetting keybag for uid (%i) in session (%i)", context->s_uid, context->s_id); + os_log(OS_LOG_DEFAULT, "resetting keybag for uid (%i) in session (%i)", context->s_uid, context->s_id); _kb_rename_bag_on_disk(ur, bag_file); - require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &session_handle), done); - require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done); + require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &private_handle), done); + require_noerr(rc = aks_save_bag(private_handle, (void**)&buf, (int*)&buf_size), done); require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError); - require_noerr(rc = aks_set_system(session_handle, context->s_uid), done); - aks_unload_bag(session_handle); + require_noerr(rc = _service_kb_set_system(private_handle, context->s_uid), done); require_noerr(rc = _kb_get_session_handle(context, &session_handle), done); if (secret && rc == KB_Success) { aks_unlock_bag(session_handle, secret, secret_len); } + if (rc == KB_Success) { + _kb_set_user_uuid(context, secret, secret_len); + } + done: + if (private_handle != bad_keybag_handle) { + aks_unload_bag(private_handle); + } if (buf) free(buf); return; }); @@ -659,6 +752,74 @@ done: return rc; } +static int +service_kb_wrap_key(service_context_t *context, xpc_object_t event, xpc_object_t reply) +{ + int rc = KB_GeneralError; + size_t sz; + const void *key; + int key_size; + keyclass_t key_class; + keybag_handle_t session_handle; + void *wrapped_key = NULL; + int wrapped_key_size; + keyclass_t wrapped_key_class; + + require_noerr(rc = _kb_get_session_handle(context, &session_handle), done); + + key = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &sz); + require_action(key != NULL, done, rc = KB_GeneralError); + require_action(sz <= APPLE_KEYSTORE_MAX_KEY_LEN, done, rc = KB_GeneralError); + key_size = (int)sz; + key_class = (keyclass_t)xpc_dictionary_get_int64(event, SERVICE_XPC_KEYCLASS); + + wrapped_key_size = APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN; + wrapped_key = calloc(1, wrapped_key_size); + + rc = aks_wrap_key(key, key_size, key_class, session_handle, wrapped_key, &wrapped_key_size, &wrapped_key_class); + if (rc == KB_Success) { + xpc_dictionary_set_data(reply, SERVICE_XPC_WRAPPED_KEY, wrapped_key, wrapped_key_size); + xpc_dictionary_set_int64(reply, SERVICE_XPC_KEYCLASS, wrapped_key_class); + } + +done: + free(wrapped_key); + return rc; +} + +static int +service_kb_unwrap_key(service_context_t *context, xpc_object_t event, xpc_object_t reply) +{ + int rc = KB_GeneralError; + size_t sz; + const void *wrapped_key; + int wrapped_key_size; + keyclass_t wrapped_key_class; + keybag_handle_t session_handle; + void *key = NULL; + int key_size; + + require_noerr(rc = _kb_get_session_handle(context, &session_handle), done); + + wrapped_key = xpc_dictionary_get_data(event, SERVICE_XPC_WRAPPED_KEY, &sz); + require_action(wrapped_key != NULL, done, rc = KB_GeneralError); + require_action(sz <= APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN, done, rc = KB_GeneralError); + wrapped_key_size = (int)sz; + wrapped_key_class = (keyclass_t)xpc_dictionary_get_int64(event, SERVICE_XPC_KEYCLASS); + + key_size = APPLE_KEYSTORE_MAX_KEY_LEN; + key = calloc(1, key_size); + + rc = aks_unwrap_key(wrapped_key, wrapped_key_size, wrapped_key_class, session_handle, key, &key_size); + if (rc == KB_Success) { + xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, key, key_size); + } + +done: + free(key); + return rc; +} + static int service_kb_stash_create(service_context_t * context, const void * key, unsigned key_size) { @@ -752,6 +913,8 @@ OSStatus service_stash_get_key(service_context_t * context, xpc_object_t event, if (kr == KERN_SUCCESS) { xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize); service_kb_stash_load(context, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize, false); + } else { + os_log(OS_LOG_DEFAULT, "failed to get stash key: %d", (int)kr); } done: @@ -818,6 +981,8 @@ OSStatus service_stash_set_key(service_context_t * context, xpc_object_t event, service_kb_stash_create(context, keydata, (unsigned)keydata_len); } done: + os_log(OS_LOG_DEFAULT, "set stashkey %d", (int)kr); + if (conn) closeiodev(conn); @@ -910,6 +1075,10 @@ static char * sel_to_char(uint64_t sel) return "kb_unload"; case SERVICE_KB_LOAD_UID: return "kb_load_uid"; + case SERVICE_KB_WRAP_KEY: + return "kb_wrap_key"; + case SERVICE_KB_UNWRAP_KEY: + return "kb_unwrap_key"; default: return "unknown"; } @@ -943,7 +1112,7 @@ void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event) uid_t uid; if (type == XPC_TYPE_ERROR) { - if (event == XPC_ERROR_CONNECTION_INVALID) { + if (event == XPC_ERROR_CONNECTION_INVALID) { } } else { assert(type == XPC_TYPE_DICTIONARY); @@ -1054,6 +1223,12 @@ void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event) uid = (uid_t)xpc_dictionary_get_uint64(event, SERVICE_XPC_UID); rc = service_kb_load_uid(uid); break; + case SERVICE_KB_WRAP_KEY: + rc = service_kb_wrap_key(context, event, reply); + break; + case SERVICE_KB_UNWRAP_KEY: + rc = service_kb_unwrap_key(context, event, reply); + break; #if DEBUG case SERVICE_STASH_BLOB: rc = service_stash_blob(event, reply); @@ -1069,7 +1244,7 @@ void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event) LOG("selector: %s (%llu), error: %s (%x), sid: %d, suid: %d, pid: %d", sel_to_char(request), request, err_to_char(rc), rc, context ? context->s_id : 0, context ? context->s_uid : 0, context ? get_caller_pid(&context->procToken) : 0); #else if (rc != 0) { - syslog(LOG_NOTICE, "selector: %s (%llu), error: %s (%x), sid: %d, suid: %d, pid: %d", sel_to_char(request), request, err_to_char(rc), rc, context ? context->s_id : 0, context ? context->s_uid : 0, context ? get_caller_pid(&context->procToken) : 0); + os_log(OS_LOG_DEFAULT, "selector: %s (%llu), error: %s (%x), sid: %d, suid: %d, pid: %d", sel_to_char(request), request, err_to_char(rc), rc, context ? context->s_id : 0, context ? context->s_uid : 0, context ? get_caller_pid(&context->procToken) : 0); } #endif xpc_dictionary_set_int64(reply, SERVICE_XPC_RC, rc); @@ -1090,14 +1265,14 @@ bool check_signature(xpc_connection_t connection) SecTaskRef task = SecTaskCreateWithAuditToken(NULL, token); if (task == NULL) { - syslog(LOG_NOTICE, "failed getting SecTaskRef of the client"); + os_log(OS_LOG_DEFAULT, "failed getting SecTaskRef of the client"); return false; } 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)) { - syslog(LOG_NOTICE, "client is not a platform binary: %0x08x", flags); + os_log(OS_LOG_DEFAULT, "client is not a platform binary: %0x08x", flags); CFRelease(task); return false; } @@ -1105,7 +1280,7 @@ bool check_signature(xpc_connection_t connection) CFStringRef signingIdentity = SecTaskCopySigningIdentifier(task, NULL); CFRelease(task); if (signingIdentity == NULL) { - syslog(LOG_NOTICE, "client have no code sign identity"); + os_log(OS_LOG_DEFAULT, "client have no code sign identity"); return false; } @@ -1113,7 +1288,7 @@ bool check_signature(xpc_connection_t connection) CFRelease(signingIdentity); if (!res) - syslog(LOG_NOTICE, "client is not not securityd"); + os_log(OS_LOG_DEFAULT, "client is not not securityd"); return res; #else @@ -1139,24 +1314,24 @@ static void register_for_notifications() if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_MSGID) { // ignored for now } else if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG) { - syslog(LOG_NOTICE, "request to update handle %d", msg->handle); + os_log(OS_LOG_DEFAULT, "request to update handle %d", msg->handle); update_keybag_handle(msg->handle); } else { - syslog(LOG_ERR, "mach_msg error: %x", mr); + os_log(OS_LOG_DEFAULT, "mach_msg error: %x", mr); } }); dispatch_resume(mach_src); } else { - syslog(LOG_NOTICE, "failed to create notification port"); + os_log(OS_LOG_DEFAULT, "failed to create notification port"); } }); kr = aks_register_for_notifications(mp, AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG); if (kr == KERN_SUCCESS) { - syslog(LOG_NOTICE, "registered for notifications"); + os_log(OS_LOG_DEFAULT, "registered for notifications"); } else { - syslog(LOG_NOTICE, "failed to register for notifications %d", kr); + os_log(OS_LOG_DEFAULT, "failed to register for notifications %d", kr); } } @@ -1164,7 +1339,7 @@ int main(int argc, const char * argv[]) { char * errorbuf; if (sandbox_init(SECURITYD_SERVICE_NAME, SANDBOX_NAMED, &errorbuf) != 0) { - syslog(LOG_ERR, "sandbox_init failed %s", errorbuf); + os_log(OS_LOG_DEFAULT, "sandbox_init failed %s", errorbuf); sandbox_free_error(errorbuf); #ifndef DEBUG abort(); diff --git a/securityd/securityd_service/securityd_service/securityd_service.8 b/securityd/securityd_service/securityd_service/securityd_service.8 new file mode 100644 index 00000000..6c0d68db --- /dev/null +++ b/securityd/securityd_service/securityd_service/securityd_service.8 @@ -0,0 +1,10 @@ +.Dd November 02, 2016 +.Dt securityd_service 8 +.Os +.Sh NAME +.Nm securityd_service +.Nd heler process to securityd to unlock keybag +.Sh DESCRIPTION +.Nm +lock and unlocks the keybag on behalf of +.Nm securityd . diff --git a/securityd/securityd_service/securityd_service/securityd_service.h b/securityd/securityd_service/securityd_service/securityd_service.h index ee9178f4..335c9784 100644 --- a/securityd/securityd_service/securityd_service/securityd_service.h +++ b/securityd/securityd_service/securityd_service/securityd_service.h @@ -14,6 +14,8 @@ #define SERVICE_XPC_LOCKED "_locked" #define SERVICE_XPC_NO_PIN "_no_pin" #define SERVICE_XPC_UID "_uid" +#define SERVICE_XPC_WRAPPED_KEY "_wrapped_key" +#define SERVICE_XPC_KEYCLASS "_keyclass" enum { @@ -31,6 +33,8 @@ enum { SERVICE_STASH_LOAD_KEY, SERVICE_KB_UNLOAD, SERVICE_KB_LOAD_UID, + SERVICE_KB_WRAP_KEY, + SERVICE_KB_UNWRAP_KEY, }; #endif diff --git a/securityd/securityd_service/securityd_service/securityd_service_client.c b/securityd/securityd_service/securityd_service/securityd_service_client.c index 047498be..fa8f8a10 100644 --- a/securityd/securityd_service/securityd_service/securityd_service_client.c +++ b/securityd/securityd_service/securityd_service/securityd_service_client.c @@ -199,6 +199,89 @@ done: return rc; } +int +service_client_kb_wrap_key(service_context_t *context, const void *key, int key_size, keyclass_t key_class, void **wrapped_key, int *wrapped_key_size, keyclass_t *wrapped_key_class) +{ + int rc = KB_GeneralError; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + const void *data; + size_t data_len; + + if (wrapped_key) *wrapped_key = NULL; + if (wrapped_key_size) *wrapped_key_size = 0; + if (wrapped_key_class) *wrapped_key_class = key_class_none; + + message = xpc_dictionary_create(NULL, NULL, 0); + require_quiet(message, done); + + xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_KB_WRAP_KEY); + xpc_dictionary_set_data(message, SERVICE_XPC_KEY, key, (size_t)key_size); + xpc_dictionary_set_int64(message, SERVICE_XPC_KEYCLASS, key_class); + + rc = _service_send_msg(context, message, &reply); + if (rc == KB_Success) { + data = xpc_dictionary_get_data(reply, SERVICE_XPC_WRAPPED_KEY, &data_len); + if (data) { + if (wrapped_key) { + *wrapped_key = malloc(data_len); + memcpy(*wrapped_key, data, data_len); + } + if (wrapped_key_size) { + *wrapped_key_size = (int)data_len; + } + } + + if (wrapped_key_class) { + *wrapped_key_class = (keyclass_t)xpc_dictionary_get_int64(reply, SERVICE_XPC_KEYCLASS); + } + } + +done: + if (message) xpc_release(message); + if (reply) xpc_release(reply); + return rc; +} + +int +service_client_kb_unwrap_key(service_context_t *context, const void *wrapped_key, int wrapped_key_size, keyclass_t wrapped_key_class, void **key, int *key_size) +{ + int rc = KB_GeneralError; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + const void *data; + size_t data_len; + + if (key) *key = NULL; + if (key_size) *key_size = 0; + + message = xpc_dictionary_create(NULL, NULL, 0); + require_quiet(message, done); + + xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_KB_UNWRAP_KEY); + xpc_dictionary_set_data(message, SERVICE_XPC_WRAPPED_KEY, wrapped_key, (size_t)wrapped_key_size); + xpc_dictionary_set_int64(message, SERVICE_XPC_KEYCLASS, wrapped_key_class); + + rc = _service_send_msg(context, message, &reply); + if (rc == KB_Success) { + data = xpc_dictionary_get_data(reply, SERVICE_XPC_KEY, &data_len); + if (data) { + if (key) { + *key = malloc(data_len); + memcpy(*key, data, data_len); + } + if (key_size) { + *key_size = (int)data_len; + } + } + } + +done: + if (message) xpc_release(message); + if (reply) xpc_release(reply); + return rc; +} + int service_client_stash_set_key(service_context_t *context, const void * key, int key_len) { diff --git a/securityd/securityd_service/securityd_service/securityd_service_client.h b/securityd/securityd_service/securityd_service/securityd_service_client.h index 123f10ef..c0d8667d 100644 --- a/securityd/securityd_service/securityd_service/securityd_service_client.h +++ b/securityd/securityd_service/securityd_service/securityd_service_client.h @@ -10,6 +10,7 @@ extern "C" { #include #include #include +#include enum { KB_Success = 0, @@ -37,6 +38,8 @@ int service_client_kb_lock(service_context_t *context); int service_client_kb_change_secret(service_context_t *context, const void * secret, int secret_len, const void * new_secret, int new_secret_len); int service_client_kb_is_locked(service_context_t *context, bool *locked, bool *no_pin); int service_client_kb_reset(service_context_t *context, const void * secret, int secret_len); +int service_client_kb_wrap_key(service_context_t *context, const void *key, int key_size, keyclass_t key_class, void **wrapped_key, int *wrapped_key_size, keyclass_t *wrapped_key_class); +int service_client_kb_unwrap_key(service_context_t *context, const void *wrapped_key, int wrapped_key_size, keyclass_t wrapped_key_class, void **key, int *key_size); 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); diff --git a/securityd/securityd_service/securityd_service/service.entitlements b/securityd/securityd_service/securityd_service/service.entitlements index b4ad6417..cd19a719 100644 --- a/securityd/securityd_service/securityd_service/service.entitlements +++ b/securityd/securityd_service/securityd_service/service.entitlements @@ -2,10 +2,14 @@ - com.apple.keystore.stash.access + com.apple.keystore.access-keychain-keys + + com.apple.keystore.config.set.user_uuid com.apple.keystore.device + com.apple.keystore.stash.access + com.apple.private.securityd.keychain com.apple.private.securityd.stash diff --git a/securityd/src/SharedMemoryServer.cpp b/securityd/src/SharedMemoryServer.cpp index 5c437919..3b95482b 100644 --- a/securityd/src/SharedMemoryServer.cpp +++ b/securityd/src/SharedMemoryServer.cpp @@ -24,6 +24,7 @@ #include "SharedMemoryServer.h" #include #include +#include #include #include #include @@ -50,6 +51,23 @@ std::string SharedMemoryCommon::SharedMemoryFilePath(const char *segmentName, ui return path; } +static bool makedir(const char *path, mode_t mode) { + // Returns true on success. Primarily to centralize logging + if (::mkdir(path, mode)==0 || errno==EEXIST) { + return true; + } else { + secdebug("MDSPRIVACY","Failed to make directory: %s (%d)", path, errno); + return false; + } +} + +static void unlinkfile(const char *path) { + // Primarily to centralize logging + if (::unlink(path)==-1) { + secdebug("MDSPRIVACY","Failed to unlink file: %s (%d)", path, errno); + } +} + SharedMemoryServer::SharedMemoryServer (const char* segmentName, SegmentOffsetType segmentSize, uid_t uid, gid_t gid) : mSegmentName (segmentName), mSegmentSize (segmentSize), mUID(SharedMemoryCommon::fixUID(uid)) { @@ -59,42 +77,41 @@ SharedMemoryServer::SharedMemoryServer (const char* segmentName, SegmentOffsetTy // make the mds directory, just in case it doesn't exist if (mUID == 0) { - mkdir(SharedMemoryCommon::kMDSDirectory, perm1777); - mkdir(SharedMemoryCommon::kMDSMessagesDirectory, perm0755); + makedir(SharedMemoryCommon::kMDSDirectory, perm1777); + makedir(SharedMemoryCommon::kMDSMessagesDirectory, perm0755); } else { // Assume kMDSMessagesDirectory was created first by securityd std::string uidstr = std::to_string(mUID); std::string upath = SharedMemoryCommon::kMDSMessagesDirectory; upath += "/" + uidstr; - mkdir(upath.c_str(), perm0755); + makedir(upath.c_str(), perm0755); } mFileName = SharedMemoryCommon::SharedMemoryFilePath(segmentName, uid); // make the file name // clean any old file away - unlink(mFileName.c_str()); + unlinkfile(mFileName.c_str()); // open the file secdebug("MDSPRIVACY","creating %s",mFileName.c_str ()); - mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if(mUID != 0) { + mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT | O_EXCL, perm0600); + } + else { + mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + } + if (mBackingFile < 0) { secdebug("MDSPRIVACY","creation of %s failed", mFileName.c_str()); return; } - int rx = chown(mFileName.c_str (), uid, gid); + int rx = fchown(mBackingFile, uid, gid); if (rx) { secdebug("MDSPRIVACY","chown of %s to %d/%d failed : %d", mFileName.c_str(), uid, gid, rx); } - if (mUID != 0) { - int rx = fchmod(mBackingFile, perm0600); - if (rx) { - secdebug("MDSPRIVACY","chmod of %s to %x failed : %d", mFileName.c_str(), perm0600, rx); - } - } - // set the segment size ftruncate (mBackingFile, segmentSize); @@ -104,7 +121,7 @@ SharedMemoryServer::SharedMemoryServer (const char* segmentName, SegmentOffsetTy if (mSegment == MAP_FAILED) // can't map the memory? { mSegment = NULL; - unlink(mFileName.c_str()); + unlinkfile(mFileName.c_str()); } else { mDataPtr = mDataArea = mSegment + sizeof(SegmentOffsetType); mDataMax = mSegment + segmentSize;; @@ -127,7 +144,7 @@ SharedMemoryServer::~SharedMemoryServer () close(mBackingFile); // mark the segment for deletion - unlink (mFileName.c_str ()); + unlinkfile(mFileName.c_str ()); } @@ -141,8 +158,11 @@ const SegmentOffsetType void SharedMemoryServer::WriteMessage (SegmentOffsetType domain, SegmentOffsetType event, const void *message, SegmentOffsetType messageLength) { - // backing file MUST be right size - ftruncate (mBackingFile, mSegmentSize); + // backing file MUST be right size, don't ftruncate() more then needed though to avoid reaching too deep into filesystem + struct stat sb; + if (::fstat(mBackingFile, &sb) == 0 && sb.st_size != (off_t)mSegmentSize) { + ::ftruncate(mBackingFile, mSegmentSize); + } // assemble the final message ssize_t messageSize = kHeaderLength + messageLength; diff --git a/securityd/src/acls.cpp b/securityd/src/acls.cpp index 10d1c351..958ecb05 100644 --- a/securityd/src/acls.cpp +++ b/securityd/src/acls.cpp @@ -167,11 +167,11 @@ void SecurityServerAcl::validatePartition(SecurityServerEnvironment& env, bool p CFArrayRef partitionList; if (cfscan(partition, "{Partitions=%AO}", &partitionList)) { CFRef partitionDebug = CFCopyDescription(partitionList); // for debugging only - secnotice("integrity", "ACL partitionID = %s", cfString(partitionDebug).c_str()); + secinfo("integrity", "ACL partitionID = %s", cfString(partitionDebug).c_str()); if (env.database) { CFRef clientPartitionID = makeCFString(env.database->process().partitionId()); if (CFArrayContainsValue(partitionList, CFRangeMake(0, CFArrayGetCount(partitionList)), clientPartitionID)) { - secnotice("integrity", "ACL partitions match: %s", cfString(clientPartitionID).c_str()); + secinfo("integrity", "ACL partitions match: %s", cfString(clientPartitionID).c_str()); return; } else { secnotice("integrity", "ACL partition mismatch: client %s ACL %s", cfString(clientPartitionID).c_str(), cfString(partitionDebug).c_str()); @@ -377,7 +377,7 @@ bool SecurityServerAcl::createClientPartitionID(Process& process) ObjectAcl::AclEntry partition(subject); partition.addAuthorization(CSSM_ACL_AUTHORIZATION_PARTITION_ID); this->add(CSSM_APPLE_ACL_TAG_PARTITION_ID, partition); - secnotice("integrity", "added partition %s to new key", partitionID.c_str()); + secinfo("integrity", "added partition %s to new key", partitionID.c_str()); return true; } diff --git a/securityd/src/agentquery.cpp b/securityd/src/agentquery.cpp index 2fe7beb8..908fc168 100644 --- a/securityd/src/agentquery.cpp +++ b/securityd/src/agentquery.cpp @@ -106,7 +106,7 @@ SecurityAgentXPCConnection::~SecurityAgentXPCConnection() // If a connection has been established, we need to tear it down. if (NULL != mXPCConnection) { // Tearing this down is a multi-step process. First, request a cancellation. - // This is safe even if the connection is already in the cancelled state. + // This is safe even if the connection is already in the canceled state. xpc_connection_cancel(mXPCConnection); // Then release the XPC connection @@ -247,7 +247,7 @@ SecurityAgentXPCQuery::inferHints(Process &thisProcess) bool validSignature = thisProcess.checkAppleSigned(); AuthItemSet clientImmutableHints; - clientImmutableHints.insert(AuthItemRef(AGENT_HINT_PROCESS_SIGNED, AuthValueOverlay(sizeof(validSignature), &validSignature))); + clientImmutableHints.insert(AuthItemRef(AGENT_HINT_CLIENT_SIGNED, AuthValueOverlay(sizeof(validSignature), &validSignature))); mImmutableHints.insert(clientImmutableHints.begin(), clientImmutableHints.end()); } @@ -427,10 +427,8 @@ static xpc_object_t authItemSetToXPCArray(AuthItemSet input) { return outputArray; } -OSStatus +void SecurityAgentXPCQuery::invoke() { - __block OSStatus status = kAuthorizationResultUndefined; - xpc_object_t hintsArray = authItemSetToXPCArray(mInHints); xpc_object_t contextArray = authItemSetToXPCArray(mInContext); xpc_object_t immutableHintsArray = authItemSetToXPCArray(mImmutableHints); @@ -467,8 +465,6 @@ SecurityAgentXPCQuery::invoke() { xpc_release(contextArray); xpc_release(immutableHintsArray); xpc_release(requestObject); - - return status; } void SecurityAgentXPCQuery::checkResult() @@ -499,8 +495,7 @@ QueryKeychainUse::QueryKeychainUse(bool needPass, const Database *db) Reason QueryKeychainUse::queryUser (const char *database, const char *description, AclAuthorization action) { Reason reason = SecurityAgent::noReason; - uint32_t retryCount = 0; - OSStatus status; + uint32_t retryCount = 0; AuthItemSet hints, context; // prepopulate with client hints @@ -537,7 +532,7 @@ Reason QueryKeychainUse::queryUser (const char *database, const char *descriptio hints.erase(retryHint); hints.insert(retryHint); // replace setInput(hints, context); - status = invoke(); + invoke(); if (retryCount > kMaximumAuthorizationTries) { @@ -575,7 +570,6 @@ Reason QueryKeychainUse::queryUser (const char *database, const char *descriptio Reason QueryOld::query() { Reason reason = SecurityAgent::noReason; - OSStatus status; AuthItemSet hints, context; CssmAutoData passphrase(Allocator::standard(Allocator::sensitive)); int retryCount = 0; @@ -605,7 +599,7 @@ Reason QueryOld::query() hints.erase(retryHint); hints.insert(retryHint); // replace setInput(hints, context); - status = invoke(); + invoke(); if (retryCount > maxTries) { @@ -670,7 +664,6 @@ QueryKeybagPassphrase::QueryKeybagPassphrase(Session & session, int32_t tries) : Reason QueryKeybagPassphrase::query() { Reason reason = SecurityAgent::noReason; - OSStatus status; AuthItemSet hints, context; CssmAutoData passphrase(Allocator::standard(Allocator::sensitive)); int retryCount = 0; @@ -701,7 +694,7 @@ Reason QueryKeybagPassphrase::query() hints.erase(retryHint); hints.insert(retryHint); // replace setInput(hints, context); - status = invoke(); + invoke(); checkResult(); @@ -732,7 +725,6 @@ Reason QueryKeybagNewPassphrase::query(CssmOwnedData &oldPassphrase, CssmOwnedDa CssmAutoData pass(Allocator::standard(Allocator::sensitive)); CssmAutoData oldPass(Allocator::standard(Allocator::sensitive)); Reason reason = SecurityAgent::noReason; - OSStatus status; AuthItemSet hints, context; int retryCount = 0; @@ -766,7 +758,7 @@ Reason QueryKeybagNewPassphrase::query(CssmOwnedData &oldPassphrase, CssmOwnedDa hints.erase(retryHint); hints.insert(retryHint); // replace setInput(hints, context); - status = invoke(); + invoke(); checkResult(); @@ -823,7 +815,6 @@ Reason QueryNewPassphrase::query() CssmAutoData passphrase(Allocator::standard(Allocator::sensitive)); CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive)); - OSStatus status; AuthItemSet hints, context; int retryCount = 0; @@ -860,7 +851,7 @@ Reason QueryNewPassphrase::query() hints.erase(retryHint); hints.insert(retryHint); // replace setInput(hints, context); - status = invoke(); + invoke(); if (retryCount > maxTries) { @@ -940,7 +931,6 @@ Reason QueryGenericPassphrase::query(const CssmData *prompt, bool verify, string &passphrase) { Reason reason = SecurityAgent::noReason; - OSStatus status; // not really used; remove? AuthItemSet hints, context; hints.insert(mClientHints.begin(), mClientHints.end()); @@ -959,7 +949,7 @@ Reason QueryGenericPassphrase::query(const CssmData *prompt, bool verify, do { setInput(hints, context); - status = invoke(); + invoke(); checkResult(); passwordItem = mOutContext.find(AGENT_PASSWORD); @@ -983,7 +973,6 @@ Reason QueryDBBlobSecret::query(DbHandle *dbHandleArray, uint8 dbHandleArrayCoun { Reason reason = SecurityAgent::noReason; CssmAutoData passphrase(Allocator::standard(Allocator::sensitive)); - OSStatus status; // not really used; remove? AuthItemSet hints/*NUKEME*/, context; hints.insert(mClientHints.begin(), mClientHints.end()); @@ -1006,7 +995,7 @@ Reason QueryDBBlobSecret::query(DbHandle *dbHandleArray, uint8 dbHandleArrayCoun hints.erase(retryHint); hints.insert(retryHint); // replace setInput(hints, context); - status = invoke(); + invoke(); checkResult(); secretItem = mOutContext.find(AGENT_PASSWORD); if (!secretItem) @@ -1055,7 +1044,7 @@ QueryKeychainAuth::operator () (const char *database, const char *description, A string password; using CommonCriteria::Securityd::KeychainAuthLogger; - KeychainAuthLogger logger(mAuditToken, AUE_ssauthint, database, description); + KeychainAuthLogger logger(mAuditToken, (short)AUE_ssauthint, database, description); hints.insert(mClientHints.begin(), mClientHints.end()); diff --git a/securityd/src/agentquery.h b/securityd/src/agentquery.h index b059a5ed..3c9bf9f4 100644 --- a/securityd/src/agentquery.h +++ b/securityd/src/agentquery.h @@ -89,7 +89,7 @@ public: virtual void disconnect(); virtual void terminate(); void create(const char *pluginId, const char *mechanismId); - OSStatus invoke(); + void invoke(); void setTerminateOnSleep(bool terminateOnSleep) {mTerminateOnSleep = terminateOnSleep;} bool getTerminateOnSleep() {return mTerminateOnSleep;} void setInput(const AuthItemSet& inHints, const AuthItemSet& inContext) { mInHints = inHints; mInContext = inContext; } diff --git a/securityd/src/csproxy.cpp b/securityd/src/csproxy.cpp index 9ab149e4..8c3e8661 100644 --- a/securityd/src/csproxy.cpp +++ b/securityd/src/csproxy.cpp @@ -25,13 +25,15 @@ // // csproxy - Code Signing Hosting Proxy // +#include + #include "csproxy.h" #include "server.h" #include #include #include #include - +#include // // Construct a CodeSigningHost @@ -64,7 +66,7 @@ void CodeSigningHost::reset() case dynamicHosting: mHostingPort.destroy(); mHostingPort = MACH_PORT_NULL; - secnotice("SS", "%p host unregister", this); + secnotice("SS", "%d host unregister", mHostingPort.port()); break; case proxyHosting: Server::active().remove(*this); // unhook service handler @@ -72,7 +74,7 @@ void CodeSigningHost::reset() mHostingState = noHosting; mHostingPort = MACH_PORT_NULL; mGuests.erase(mGuests.begin(), mGuests.end()); - secnotice("SS", "%p host unregister", this); + secnotice("SS", "%d host unregister", mHostingPort.port()); break; } } @@ -194,7 +196,7 @@ void CodeSigningHost::registerCodeSigning(mach_port_t hostingPort, SecCSFlags fl case noHosting: mHostingPort = hostingPort; mHostingState = dynamicHosting; - secnotice("SS", "%p host register: %d", this, mHostingPort.port()); + secnotice("SS", "%d host register: %d", mHostingPort.port(), mHostingPort.port()); break; default: MacOSError::throwMe(errSecCSHostProtocolContradiction); @@ -225,7 +227,7 @@ SecGuestRef CodeSigningHost::createGuest(SecGuestRef hostRef, MachServer::Handler::port(mHostingPort); // put into Handler MachServer::active().add(*this); // start listening mHostingState = proxyHosting; // now proxying for this host - secnotice("SS", "%p host proxy: %d", this, mHostingPort.port()); + secnotice("SS", "%d host proxy: %d", mHostingPort.port(), mHostingPort.port()); break; case proxyHosting: // already proxying break; @@ -253,7 +255,7 @@ SecGuestRef CodeSigningHost::createGuest(SecGuestRef hostRef, guest->setHash(cdhash, flags & kSecCSGenerateGuestHash); guest->dedicated = (flags & kSecCSDedicatedHost); mGuests[guest->guestRef()] = guest; - secnotice("SS", "%p guest create %d %d status:%d %d %s", this, hostRef, guest->guestRef(), guest->status, flags, guest->path.c_str()); + secnotice("SS", "%d guest create %d %d status:%d %d %s", mHostingPort.port(), hostRef, guest->guestRef(), guest->status, flags, guest->path.c_str()); return guest->guestRef(); } @@ -271,7 +273,7 @@ void CodeSigningHost::setGuestStatus(SecGuestRef guestRef, uint32_t status, cons if ((~status & guest->status) & (kSecCodeStatusHard | kSecCodeStatusKill)) MacOSError::throwMe(errSecCSHostProtocolStateError); // can't clear guest->status = status; - secnotice("SS", "%p guest change %d %d", this, guestRef, status); + secnotice("SS", "%d guest change %d %d", mHostingPort.port(), guestRef, status); // replace attributes if requested if (attributes) @@ -293,11 +295,19 @@ void CodeSigningHost::removeGuest(SecGuestRef hostRef, SecGuestRef guestRef) MacOSError::throwMe(errSecCSHostProtocolDedicationError); if (!guest->isGuestOf(host, strict)) MacOSError::throwMe(errSecCSHostProtocolUnrelated); - for (GuestMap::iterator it = mGuests.begin(); it != mGuests.end(); ++it) - if (it->second->isGuestOf(guest, loose)) { - secnotice("SS", "%p guest destroy %d", this, it->first); - mGuests.erase(it); + + set matchingGuests; + + for (auto &it : mGuests) { + if (it.second->isGuestOf(guest, loose)) { + matchingGuests.insert(it.first); } + } + + for (auto &it : matchingGuests) { + secnotice("SS", "%d guest destroy %d", mHostingPort.port(), it); + mGuests.erase(it); + } } @@ -311,8 +321,10 @@ void CodeSigningHost::Guest::setAttributes(const CssmData &attrData) { CFRef guest = makeCFNumber(guestRef()); if (attrData) { + CFDictionaryRef attrs = makeCFDictionaryFrom(attrData.data(), attrData.length()); attributes.take(cfmake("{+%O,%O=%O}", - makeCFDictionaryFrom(attrData.data(), attrData.length()), kSecGuestAttributeCanonical, guest.get())); + attrs, kSecGuestAttributeCanonical, guest.get())); + CFReleaseNull(attrs); } else { attributes.take(makeCFDictionary(1, kSecGuestAttributeCanonical, guest.get())); } @@ -532,7 +544,7 @@ void CodeSigningHost::Guest::dump() const Debug::dump("0x%x", *it); } Debug::dump("; status=0x%x attrs=%s]", - status, cfString(CFCopyDescription(attributes), true).c_str()); + status, cfStringRelease(CFCopyDescription(attributes)).c_str()); } #endif //DEBUGDUMP diff --git a/securityd/src/dbcrypto.cpp b/securityd/src/dbcrypto.cpp index 4e4b1f99..ad615d3b 100644 --- a/securityd/src/dbcrypto.cpp +++ b/securityd/src/dbcrypto.cpp @@ -208,7 +208,8 @@ bool DatabaseCryptoCore::validateKey(const CssmClient::Key& master) { cryptor.mode(CSSM_ALGMODE_CBCPadIV8); cryptor.padding(CSSM_PADDING_PKCS1); uint8 iv[8]; // leave uninitialized; pseudo-random is cool - cryptor.initVector(CssmData::wrap(iv)); + CssmData ivData = CssmData::wrap(iv); + cryptor.initVector(ivData); cryptor.key(master); CssmAutoData cipher1(Server::csp().allocator()); diff --git a/securityd/src/kcdatabase.cpp b/securityd/src/kcdatabase.cpp index 18e40a78..b80dee1b 100644 --- a/securityd/src/kcdatabase.cpp +++ b/securityd/src/kcdatabase.cpp @@ -59,6 +59,9 @@ #include #include #include +__BEGIN_DECLS +#include +__END_DECLS void unflattenKey(const CssmData &flatKey, CssmKey &rawKey); //>> make static method on KeychainDatabase @@ -842,6 +845,7 @@ void KeychainDatabase::stashDbCheck() free(stash_key); } } else { + secnotice("KCdb", "failed to get stash from securityd_service: %d", (int)rc); CssmError::throwMe(rc); } @@ -1039,6 +1043,14 @@ void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds) return; } break; + case CSSM_SAMPLE_TYPE_KEYBAG_KEY: + assert(mBlob); + secinfo("KCdb", "%p attempting keybag key unlock", this); + common().setup(mBlob, keyFromKeybag(sample)); + if (decode()) { + return; + } + break; // explicitly defeat the default action but don't try anything in particular case CSSM_WORDID_CANCELED: secinfo("KCdb", "%p defeat default action", this); @@ -1428,6 +1440,76 @@ void unflattenKey(const CssmData &flatKey, CssmKey &rawKey) Security::n2hi(rawKey.KeyHeader); // convert it to host byte order } +CssmClient::Key +KeychainDatabase::keyFromKeybag(const TypedList &sample) +{ + service_context_t context; + uint8_t *session_key; + int session_key_size; + int rc; + const struct ccmode_siv *mode = ccaes_siv_decrypt_mode(); + const size_t session_key_wrapped_len = 40; + const size_t version_len = 1, nonce_len = 16; + uint8_t *decrypted_data; + size_t decrypted_len; + + assert(sample.type() == CSSM_SAMPLE_TYPE_KEYBAG_KEY); + + CssmData &unlock_token = sample[2].data(); + + context = common().session().get_current_service_context(); + rc = service_client_kb_unwrap_key(&context, unlock_token.data(), session_key_wrapped_len, key_class_ak, (void **)&session_key, &session_key_size); + if (rc != 0) { + CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA); + } + + uint8_t *indata = (uint8_t *)unlock_token.data() + session_key_wrapped_len; + size_t inlen = unlock_token.length() - session_key_wrapped_len; + + decrypted_len = ccsiv_plaintext_size(mode, inlen - (version_len + nonce_len)); + decrypted_data = (uint8_t *)calloc(1, decrypted_len); + + ccsiv_ctx_decl(mode->size, ctx); + + rc = ccsiv_init(mode, ctx, session_key_size, session_key); + if (rc != 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA); + rc = ccsiv_set_nonce(mode, ctx, nonce_len, indata + version_len); + if (rc != 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA); + rc = ccsiv_aad(mode, ctx, 1, indata); + if (rc != 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA); + rc = ccsiv_crypt(mode, ctx, inlen - (version_len + nonce_len), indata + version_len + nonce_len, decrypted_data); + if (rc != 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA); + + ccsiv_ctx_clear(mode->size, ctx); + + //free(decrypted_data); + free(session_key); + return makeRawKey(decrypted_data, decrypted_len, CSSM_ALGID_3DES_3KEY_EDE, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT); +} + +// adapted from DatabaseCryptoCore::makeRawKey +CssmClient::Key KeychainDatabase::makeRawKey(void *data, size_t length, + CSSM_ALGORITHMS algid, CSSM_KEYUSE usage) +{ + // build a fake key + CssmKey key; + key.header().BlobType = CSSM_KEYBLOB_RAW; + key.header().Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; + key.header().AlgorithmId = algid; + key.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY; + key.header().KeyUsage = usage; + key.header().KeyAttr = 0; + key.KeyData = CssmData(data, length); + + // unwrap it into the CSP (but keep it raw) + CssmClient::UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE); + CssmKey unwrappedKey; + CssmData descriptiveData; + unwrap(key, + CssmClient::KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE), + unwrappedKey, &descriptiveData, NULL); + return CssmClient::Key(Server::csp(), unwrappedKey); +} // // Verify a putative database passphrase. @@ -1835,7 +1917,6 @@ void KeychainDbCommon::setUnlocked() void KeychainDbCommon::lockDb() { - bool lock = false; { StLock _(*this); if (!isLocked()) { @@ -1845,7 +1926,6 @@ void KeychainDbCommon::lockDb() Server::active().clearTimer(this); mIsLocked = true; // mark locked - lock = true; // this call may destroy us if we have no databases anymore session().removeReference(*this); diff --git a/securityd/src/kcdatabase.h b/securityd/src/kcdatabase.h index ae1fadc9..f321fc19 100644 --- a/securityd/src/kcdatabase.h +++ b/securityd/src/kcdatabase.h @@ -283,6 +283,8 @@ protected: bool interactiveUnlock(); CssmClient::Key keyFromCreds(const TypedList &sample, unsigned int requiredLength); + CssmClient::Key keyFromKeybag(const TypedList &sample); + CssmClient::Key makeRawKey(void *data, size_t length, CSSM_ALGORITHMS algid, CSSM_KEYUSE usage); void encode(); // (re)generate mBlob if needed diff --git a/securityd/src/main.cpp b/securityd/src/main.cpp index bc07d918..9f66038d 100644 --- a/securityd/src/main.cpp +++ b/securityd/src/main.cpp @@ -170,12 +170,16 @@ int main(int argc, char *argv[]) } else { +#ifndef __clang_analyzer__ messagingName = bootstrapName; +#endif } } else { +#ifndef __clang_analyzer__ messagingName = bootstrapName; +#endif } // configure logging first @@ -220,6 +224,9 @@ int main(int argc, char *argv[]) exit(1); } +// The clang static analyzer isn't a big fan of our "object creation hooks object into global pointer graph" model. +// Tell it not to worry. +#ifndef __clang_analyzer__ // introduce all supported ACL subject types new AnyAclSubject::Maker(); new PasswordAclSubject::Maker(); @@ -233,10 +240,11 @@ int main(int argc, char *argv[]) new PartitionAclSubject::Maker(); new PreAuthorizationAcls::OriginMaker(); new PreAuthorizationAcls::SourceMaker(); - +#endif // establish the code equivalents database CodeSignatures codeSignatures; + // create the main server object and register it Server server(codeSignatures, bootstrapName); @@ -264,11 +272,12 @@ int main(int argc, char *argv[]) // install MDS (if needed) and initialize the local CSSM server.loadCssm(mdsIsInstalled); - - // create the shared memory notification hub + #ifndef __clang_analyzer__ + // create the shared memory notification hub new SharedMemoryListener(messagingName, kSharedMemoryPoolSize); -#endif // __clang_analyzer__ +#endif + // okay, we're ready to roll secnotice("SS", "Entering service as %s", (char*)bootstrapName); @@ -330,7 +339,5 @@ static PCSCMonitor::ServiceLevel scOptions(const char *optionString) // static void handleSignals(int sig) { - secnotice("SS", "signal received: %d", sig); - if (kern_return_t rc = self_client_handleSignal(gMainServerPort, mach_task_self(), sig)) - Syslog::error("self-send failed (mach error %d)", rc); + (void)self_client_handleSignal(gMainServerPort, mach_task_self(), sig); } diff --git a/securityd/src/notifications.cpp b/securityd/src/notifications.cpp index 26440052..8ef8872b 100644 --- a/securityd/src/notifications.cpp +++ b/securityd/src/notifications.cpp @@ -206,11 +206,6 @@ SharedMemoryListener::SharedMemoryListener(const char* segmentName, SegmentOffse SharedMemoryServer (segmentName, segmentSize, uid, gid), mActive (false) { - if (segmentName == NULL) - { - secerror("Attempted to start securityd with a NULL segmentName"); - abort(); - } } SharedMemoryListener::~SharedMemoryListener () diff --git a/securityd/src/structure.cpp b/securityd/src/structure.cpp index 80bcb054..ec86e07b 100644 --- a/securityd/src/structure.cpp +++ b/securityd/src/structure.cpp @@ -33,11 +33,13 @@ // but its dump support is conditionally included. // NodeCore::~NodeCore() -{ +try { #if defined(DEBUGDUMP) StLock _(mCoreLock); mCoreNodes.erase(this); #endif //DEBUGDUMP +} catch(...) { + return; } diff --git a/securityd/src/tokend.cpp b/securityd/src/tokend.cpp index 7a5c6a83..0462d7d6 100644 --- a/securityd/src/tokend.cpp +++ b/securityd/src/tokend.cpp @@ -102,9 +102,11 @@ void TokenDaemon::childAction() UnixError::check(::setgid(mGid)); UnixError::check(::setuid(mUid)); #else //NDEBUG +#ifndef __clang_analyzer__ // best effort, okay if not ::setgid(mGid); ::setuid(mUid); +#endif // clang_analyzer #endif //NDEBUG secinfo("tokend", "uid=%d gid=%d", getuid(), getgid()); diff --git a/securityd/src/tokendatabase.cpp b/securityd/src/tokendatabase.cpp index a70814e2..afb38d0c 100644 --- a/securityd/src/tokendatabase.cpp +++ b/securityd/src/tokendatabase.cpp @@ -711,7 +711,6 @@ void TokenDatabase::findRecordHandle(Database::Record *rRecord, GUARD access().Tokend::ClientSession::findRecordHandle(record->tokenHandle(), inAttributes, inAttributesLength, data, hKey, outAttributes, outAttributesLength); - rRecord = record; if (hKey != noKey && data) { // tokend returned a key reference & data CssmKey &keyForm = *data->interpretedAs(CSSMERR_CSP_INVALID_KEY); key = new TokenKey(*this, hKey, keyForm.header()); diff --git a/securityd/src/transition.cpp b/securityd/src/transition.cpp index 8d8e31ed..37852c0f 100644 --- a/securityd/src/transition.cpp +++ b/securityd/src/transition.cpp @@ -327,7 +327,10 @@ kern_return_t ucsp_server_openToken(UCSP_ARGS, uint32 ssid, FilePath name, { BEGIN_IPC(openToken) CopyOutAccessCredentials creds(accessCredentials, accessCredentialsLength); +// The static analyzer is not a fan of this "create object, send handle to foreign process" model. Tell it not to worry. +#ifndef __clang_analyzer__ *db = (new TokenDatabase(ssid, connection.process(), name, creds))->handle(); +#endif END_IPC(DL) } @@ -538,7 +541,9 @@ kern_return_t ucsp_server_createDb(UCSP_ARGS, DbHandle *db, CopyOutAccessCredentials creds(cred, credLength); CopyOutEntryAcl owneracl(owner, ownerLength); CopyOut flatident(ident, identLength, reinterpret_cast(xdr_DLDbFlatIdentifierRef)); +#ifndef __clang_analyzer__ *db = (new KeychainDatabase(*reinterpret_cast(flatident.data()), params, connection.process(), creds, owneracl))->handle(); +#endif END_IPC(DL) } @@ -552,9 +557,11 @@ kern_return_t ucsp_server_cloneDb(UCSP_ARGS, DbHandle srcDb, DATA_IN(ident), DbH RefPointer srcKC = Server::keychain(srcDb); secnotice("integrity", "cloning db %d", srcKC->handle()); +#ifndef __clang_analyzer__ KeychainDatabase* newKC = new KeychainDatabase(*reinterpret_cast(flatident.data()), *srcKC, connection.process()); secnotice("integrity", "returning db %d", newKC->handle()); *newDb = newKC->handle(); +#endif END_IPC(DL) } @@ -564,7 +571,9 @@ kern_return_t ucsp_server_recodeDbForSync(UCSP_ARGS, DbHandle dbToClone, { BEGIN_IPC(recodeDbForSync) RefPointer srcKC = Server::keychain(srcDb); +#ifndef __clang_analyzer__ *newDb = (new KeychainDatabase(*srcKC, connection.process(), dbToClone))->handle(); +#endif END_IPC(DL) } @@ -650,8 +659,10 @@ kern_return_t ucsp_server_decodeDb(UCSP_ARGS, DbHandle *db, DLDbFlatIdentifier* flatID = (DLDbFlatIdentifier*) flatident.data(); DLDbIdentifier id = *flatID; // invokes a casting operator +#ifndef __clang_analyzer__ *db = (new KeychainDatabase(id, SSBLOB(DbBlob, blob), connection.process(), creds))->handle(); +#endif END_IPC(DL) } diff --git a/sslViewer/SSLViewer.c b/sslViewer/SSLViewer.c index ca155921..589d1da7 100644 --- a/sslViewer/SSLViewer.c +++ b/sslViewer/SSLViewer.c @@ -218,11 +218,6 @@ static OSStatus sslEvaluateTrust( res = "kSecTrustResultInvalid"; break; case kSecTrustResultProceed: res = "kSecTrustResultProceed"; break; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - case kSecTrustResultConfirm: -#pragma clang diagnostic pop - res = "kSecTrustResultConfirm"; break; case kSecTrustResultDeny: res = "kSecTrustResultDeny"; break; case kSecTrustResultUnspecified: @@ -254,6 +249,25 @@ static OSStatus sslEvaluateTrust( *peerCerts = NULL; +#ifdef USE_CDSA_CRYPTO + /* one more thing - get peer certs in the form of an evidence chain */ + CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; + OSStatus thisRtn = SecTrustGetResult(secTrust, &secTrustResult, + peerCerts, &dummyEv); + if(thisRtn) { + printSslErrStr("SecTrustGetResult", thisRtn); + } + else { + /* workaround for the fact that SSLGetPeerCertificates() + * leaves a retain count on each element in the returned array, + * requiring us to do a release on each cert. + */ + CFIndex numCerts = CFArrayGetCount(*peerCerts); + for(CFIndex dex=0; dexacceptedProts) { - ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false); if(ortn) { printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn); goto cleanup; } for(const char *cp = pargs->acceptedProts; *cp; cp++) { - SSLProtocol prot; switch(*cp) { case '2': - prot = kSSLProtocol2; + ortn = SSLSetProtocolVersionMax(ctx, kSSLProtocol2); break; case '3': - prot = kSSLProtocol3; + ortn = SSLSetProtocolVersionMax(ctx, kSSLProtocol3); break; case 't': - prot = kTLSProtocol12; + ortn = SSLSetProtocolVersionMax(ctx, kTLSProtocol12); break; default: usage(pargs->argv); } - ortn = SSLSetProtocolVersionEnabled(ctx, prot, true); if(ortn) { - printSslErrStr("SSLSetProtocolVersionEnabled", ortn); + printSslErrStr("SSLSetProtocolVersionMax", ortn); goto cleanup; } } + } else { + SSLSetProtocolVersionMax(ctx, pargs->tryVersion); } - else { - ortn = SSLSetProtocolVersion(ctx, pargs->tryVersion); - if(ortn) { - printSslErrStr("SSLSetProtocolVersion", ortn); - goto cleanup; - } - SSLProtocol getVers; - ortn = SSLGetProtocolVersion(ctx, &getVers); - if(ortn) { - printSslErrStr("SSLGetProtocolVersion", ortn); - goto cleanup; - } - if(getVers != pargs->tryVersion) { - printf("***SSLGetProtocolVersion screwup: try %s get %s\n", - sslGetProtocolVersionString(pargs->tryVersion), - sslGetProtocolVersionString(getVers)); - ortn = errSecParam; - goto cleanup; - } - } + if(pargs->resumableEnable) { const void *rtnId = NULL; size_t rtnIdLen = 0; @@ -1338,6 +1332,16 @@ int main(int argc, char **argv) if(pargs.clientCerts == nil) { exit(1); } +#ifdef USE_CDSA_CRYPTO + if(pargs.password) { + OSStatus ortn = SecKeychainUnlock(serverKc, + strlen(pargs.password), pargs.password, true); + if(ortn) { + printf("SecKeychainUnlock returned %d\n", (int)ortn); + /* oh well */ + } + } +#endif } { diff --git a/sslViewer/sslAppUtils.cpp b/sslViewer/sslAppUtils.cpp index 46091921..26e9f1ea 100644 --- a/sslViewer/sslAppUtils.cpp +++ b/sslViewer/sslAppUtils.cpp @@ -295,7 +295,7 @@ const char *sslGetSSLErrString(OSStatus err) case errSSLPeerInternalError: return "errSSLPeerInternalError"; case errSSLPeerUserCancelled: - return "errSSLPeerUserCancelled"; + return "errSSLPeerUserCanceled"; case errSSLPeerNoRenegotiation: return "errSSLPeerNoRenegotiation"; case errSSLHostNameMismatch: diff --git a/sslViewer/sslServer.cpp b/sslViewer/sslServer.cpp index 75c265b0..699fb4b7 100644 --- a/sslViewer/sslServer.cpp +++ b/sslViewer/sslServer.cpp @@ -473,8 +473,7 @@ static OSStatus sslServe( SSLGetNegotiatedCipher(ctx, negCipher); SSLGetNegotiatedProtocolVersion(ctx, negVersion); *sessionIDLength = MAX_SESSION_ID_LENGTH; - SSLGetResumableSessionInfo(ctx, sessionWasResumed, sessionID, - sessionIDLength); + ortn = SSLGetResumableSessionInfo(ctx, sessionWasResumed, sessionID, sessionIDLength); if(!silent) { printf("\n"); diff --git a/tests/secfuzzer/SecCertificateFuzzer.c b/tests/secfuzzer/SecCertificateFuzzer.c new file mode 100644 index 00000000..78fedc71 --- /dev/null +++ b/tests/secfuzzer/SecCertificateFuzzer.c @@ -0,0 +1,22 @@ +// +// SecCertificateFuzzer.c +// Security +// + +#include +#include + +int +SecCertificateFuzzer(const void *data, size_t len); + +int +SecCertificateFuzzer(const void *data, size_t len) +{ + CFDataRef d = CFDataCreateWithBytesNoCopy(NULL, data, len, kCFAllocatorNull); + SecCertificateRef cert = SecCertificateCreateWithData(NULL, d); + CFRelease(d); + if (cert) + CFRelease(cert); + + return 0; +} diff --git a/tests/secfuzzer/secfuzzer.m b/tests/secfuzzer/secfuzzer.m new file mode 100644 index 00000000..1fa355f3 --- /dev/null +++ b/tests/secfuzzer/secfuzzer.m @@ -0,0 +1,48 @@ +// +// secfuzzer.c +// Security +// + +#import +#import +#import +#import + +int +main(int argc, char **argv) +{ + int (*function)(const void *data, size_t len) = NULL; + + if (argc < 2) + err(1, "%s library funcation", getprogname()); + + char *libraryName = argv[1]; + char *funcationName = argv[2]; + void *library; + + library = dlopen(libraryName, RTLD_NOW); + if (library == NULL) + errx(1, "failed to open %s: %s", libraryName, dlerror()); + + + function = dlsym(library, funcationName); + if (function == NULL) + errx(1, "didn't find %s in %s: %s", funcationName, libraryName, dlerror()); + + argc -= 3; + argv += 3; + + while (argc > 0) { + @autoreleasepool { + NSError *error = NULL; + NSData *data = [NSData dataWithContentsOfFile:[NSString stringWithUTF8String:argv[0]] options:0 error:&error]; + if (data == NULL) + NSLog(@"%s: %@", argv[0], error); + + function([data bytes], [data length]); + } + argv++; + argc--; + } + return 0; +} diff --git a/trust/SecCertificate.h b/trust/SecCertificate.h index b284fc0b..d3c19711 100644 --- a/trust/SecCertificate.h +++ b/trust/SecCertificate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -169,29 +169,40 @@ OSStatus SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef * __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); #endif +/*! + @function SecCertificateCopySerialNumberData + @abstract Return the certificate's serial number. + @param certificate The certificate from which to get values. + @param error An optional pointer to a CFErrorRef which will be set on return from the function if an error occurred. If not NULL, the caller is responsible for releasing the CFErrorRef. + @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. + */ +__nullable +CFDataRef SecCertificateCopySerialNumberData(SecCertificateRef certificate, CFErrorRef *error) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + #if TARGET_OS_IPHONE /*! @function SecCertificateCopySerialNumber @abstract Return the certificate's serial number. - @param certificate The certificate from which to get values - @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. + @param certificate The certificate from which to get values. + @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. NOTE: Deprecated in iOS 11.0; use SecCertificateCopySerialNumberData instead for cross-platform availability. */ __nullable CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate) - __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_10_3); + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_NA, __MAC_NA, __IPHONE_10_3, __IPHONE_11_0, "SecCertificateCopySerialNumber is deprecated. Use SecCertificateCopySerialNumberData instead."); #endif #if TARGET_OS_OSX /*! @function SecCertificateCopySerialNumber @abstract Return the certificate's serial number. - @param certificate The certificate from which to get values - @param error 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. - @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. + @param certificate The certificate from which to get values. + @param error An optional pointer to a CFErrorRef which will be set on return from the function if an error occurred. If not NULL, the caller is responsible for releasing the CFErrorRef. + @discussion Return the content of a DER-encoded integer (without the tag and length fields) for this certificate's serial number. The caller must CFRelease the value returned. NOTE: Deprecated in macOS 10.13; use SecCertificateCopySerialNumberData instead for cross-platform availability. */ __nullable CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate, CFErrorRef *error) - __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); + __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_7, __MAC_10_13, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopySerialNumber is deprecated. Use SecCertificateCopySerialNumberData instead."); #endif /* diff --git a/trust/SecCertificatePriv.h b/trust/SecCertificatePriv.h index 807fc417..37147d53 100644 --- a/trust/SecCertificatePriv.h +++ b/trust/SecCertificatePriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2004,2006-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2002-2004,2006-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -374,6 +374,20 @@ typedef CF_ENUM(uint32_t, SeciAuthVersion) { SeciAuthVersion SecCertificateGetiAuthVersion(SecCertificateRef certificate) __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); +/* Return the normalized name or NULL if it fails to parse */ +CFDataRef SecDistinguishedNameCopyNormalizedSequence(CFDataRef distinguished_name) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + +/* Returns the Subject Key ID extension from the certificate or NULL if none */ +CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRef certificate) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + +/* Returns an array of SecCertificateRefs containing the iPhone Device CA and + * its parent certificates. This interface is meant as a workaround and should + * not be used without consulting the Security team. */ +CFArrayRef SecCertificateCopyiPhoneDeviceCAChain(void) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0); + /* * Legacy functions (OS X only) diff --git a/trust/SecCertificateRequest.h b/trust/SecCertificateRequest.h index 92b7515a..baac95d9 100644 --- a/trust/SecCertificateRequest.h +++ b/trust/SecCertificateRequest.h @@ -34,163 +34,8 @@ #include #include -#if SEC_OS_OSX -#include -#endif - __BEGIN_DECLS -#if SEC_OS_OSX - -struct SecCertificateRequestAttribute /* for optional oids */ -{ - CSSM_OID oid; - CSSM_DATA value; -}; -typedef struct SecCertificateRequestAttribute SecCertificateRequestAttribute; - -struct SecCertificateRequestAttributeList -{ - UInt32 count; - SecCertificateRequestAttribute *attr; -}; -typedef struct SecCertificateRequestAttributeList SecCertificateRequestAttributeList; - -/*! - @typedef SecCertificateRequestRef - @abstract Contains information about a certificate request. -*/ -typedef struct OpaqueSecCertificateRequestRef *SecCertificateRequestRef; - -/*! - @function SecCertificateRequestGetTypeID - Returns the type identifier of all SecCertificateRequest instances. -*/ -CFTypeID SecCertificateRequestGetTypeID(void); - -/*! - @function SecCertificateRequestCreate - - Create a certificate request operation based on a policy and certificate - type. If a policy is not specified, one will be chosen for the caller. - Once the requeste is created, a request reference is returned. - To submit the request call SecCertificateRequestSubmit(). - - @param policy A policy. - @param certificateType The certificate type (i.e. X509, PGP, etc). - These types are in cssmtype.h - @param requestType The identifier to the type of request to submit (i.e. - issue, verify, revoke, etc.). These are defined in cssmtype.h - @param privateKeyItemRef The keychain item private key to be used for this - certificate request. The private key item must be of class type - kSecAppleKeyItemClass. - @param attributeList An optional list of OIDs for the certificate request. - @param certRequest A returned reference to the certificate request. Call CFRelease when done with this certificate request. - @result errSecSuccess 0 No error. -*/ -OSStatus SecCertificateRequestCreate( - const CSSM_OID *policy, - CSSM_CERT_TYPE certificateType, - CSSM_TP_AUTHORITY_REQUEST_TYPE requestType, - SecKeyRef privateKeyItemRef, - SecKeyRef publicKeyItemRef, - const SecCertificateRequestAttributeList* attributeList, - SecCertificateRequestRef* certRequest); - -/*! - @function SecCertificateRequestSubmit - - Submit a certificate request to be processed by the Security framework. - Once the request is submitted, an estimated time is returned indicating - when the request results can be retrieved. Once the estimated time has - elapsed, obtain the result by calling SecCertificateRequestGetResult(). - - @param certRequest A reference to the certificate request. - @param estimatedTime The number of estimated seconds before the result - can be retrieved. - @result errSecSuccess 0 No error. -*/ -OSStatus SecCertificateRequestSubmit( - SecCertificateRequestRef certRequest, - sint32* estimatedTime); - -/*! - @function SecCertificateRequestGetType - Returns the certificate request type (i.e. issue, revoke, etc) for a given - certificate request item reference. - @param certRequestRef A reference to a submitted request. - @param requestType The returned request type. - @result errSecSuccess 0 No error. -*/ -OSStatus SecCertificateRequestGetType( - SecCertificateRequestRef certRequestRef, - CSSM_TP_AUTHORITY_REQUEST_TYPE* requestType); - -/*! - @function SecCertificateRequestGetResult - Get the results of a certificate request. If the request is still - pending, the estimated time will be returned which indicates when to - call this function again. - @param certRequestRef A reference for the submitted request. - @param keychain The keychain in which to store the new certificate (for - a new cert request) and the cert request item reference. Pass NULL - to specify the default keychain. - @param estimatedTime The number of estimated seconds before the result can - be retrieved. - @param certificateRef The returned certificate reference for a - CSSM_TP_AUTHORITY_REQUEST_CERTISSUE only. All other request types return - NULL here. Call CFRelease when done with this certificate reference. - @result errSecSuccess 0 No error. -*/ -OSStatus SecCertificateRequestGetResult( - SecCertificateRequestRef certRequestRef, - SecKeychainRef keychain, - sint32* estimatedTime, - SecCertificateRef* certificateRef); - -/*! - @function SecCertificateFindRequest - Find a pending certificate request and return a reference object - for it. The search criteria is based on the input parameters. - @param policy A policy. - @param certificateType The certificate type (i.e. X509, PGP, etc). - These types are in cssmtype.h - @param requestType The identifier to the type of request to find (i.e. - issue, verify, revoke, etc.). These are defined in cssmtype.h - @param privateKeyItemRef Optional private key to be used - for the certificate request. Matches the same argument as passed to - SecCertificateRequestCreate(). - @param publicKeyItemRef Optional public key to be used - for the certificate request. Matches the same argument as passed to - SecCertificateRequestCreate(). - @param attributeList An optional list of OID/value pairs for finding the - certificate request. - @param certRequest A returned reference to the certificate request. Call CFRelease when done with this reference. -*/ -OSStatus SecCertificateFindRequest( - const CSSM_OID *policy, - CSSM_CERT_TYPE certificateType, - CSSM_TP_AUTHORITY_REQUEST_TYPE requestType, - SecKeyRef privateKeyItemRef, - SecKeyRef publicKeyItemRef, - const SecCertificateRequestAttributeList* attributeList, - SecCertificateRequestRef* certRequest); - -/*! - @function SecCertificateRequestGetData - Get policy-specific data following a SecCertificateRequestSubmit. - @param certRequestRef A reference for the submitted request. - @param data Policy-specific data. - @result errSecSuccess 0 No error. -*/ - -OSStatus SecCertificateRequestGetData( - SecCertificateRequestRef certRequestRef, - CSSM_DATA *data); - - -#endif - extern const void * kSecOidCommonName; extern const void * kSecOidCountryName; extern const void * kSecOidStateProvinceName; diff --git a/trust/SecPolicyPriv.h b/trust/SecPolicyPriv.h index 6d66769a..adf34d4e 100644 --- a/trust/SecPolicyPriv.h +++ b/trust/SecPolicyPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2003-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -100,6 +100,12 @@ CF_IMPLICIT_BRIDGING_ENABLED @constant kSecPolicyAppleWarsaw @constant kSecPolicyAppleiCloudSetupServerAuth @constant kSecPolicyAppleiCloudSetupCompatibilityServerAuth + @constant kSecPolicyAppleAppTransportSecurity + @constant kSecPolicyAppleMobileSoftwareUpdate + @constant kSecPolicyAppleMobileAssetDevelopment + @constant kSecPolicyAppleBasicAttestationSystem + @constant kSecPolicyAppleBasicAttestationUser + @constant kSecPolicyAppleiPhoneVPNApplicationSigning */ extern const CFStringRef kSecPolicyAppleMobileStore __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); @@ -213,8 +219,59 @@ extern const CFStringRef kSecPolicyAppleiCloudSetupServerAuth __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); extern const CFStringRef kSecPolicyAppleiCloudSetupCompatibilityServerAuth __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); - - +extern const CFStringRef kSecPolicyAppleAppTransportSecurity + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleMobileSoftwareUpdate + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleMobileAssetDevelopment + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleMacOSProfileApplicationSigning + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleBasicAttestationSystem + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleBasicAttestationUser + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyAppleiPhoneVPNApplicationSigning + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @enum Policy Name Constants (Private) + @discussion Predefined constants used to specify a SSL Pinning policy. + To be used with SecTrustSetPolicyName. + @constant kSecPolicyNameAppleAST2Service + @constant kSecPolicyNameAppleEscrowProxyService + @constant kSecPolicyNameAppleFMiPService + @constant kSecPolicyNameAppleGSService + @constant kSecPolicyNameAppleHomeKitService + @constant kSecPolicyNameAppleiCloudSetupService + @constant kSecPolicyNameAppleIDSService + @constant kSecPolicyNameAppleMMCSService + @constant kSecPolicyNameApplePPQService + @constant kSecPolicyNameApplePushService + @constant kSecPolicyNameAppleGalaxyProviderService + */ +extern const CFStringRef kSecPolicyNameAppleAST2Service + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleEscrowProxyService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleFMiPService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleGSService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleHomeKitService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleiCloudSetupService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleIDSService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleMMCSService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameApplePPQService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameApplePushService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); +extern const CFStringRef kSecPolicyNameAppleGalaxyProviderService + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); /*! @enum Policy Value Constants @@ -271,7 +328,9 @@ extern const CFStringRef kSecPolicyRootDigest checks are only applicable to OCSP; this constant will not force a fresh CRL download. */ -extern const CFOptionFlags kSecRevocationOnlineCheck; +CF_ENUM(CFOptionFlags) { + kSecRevocationOnlineCheck = (1 << 5) +}; /*! @function SecPolicyCreateApplePinned @@ -484,7 +543,7 @@ SecPolicyRef SecPolicyCreateApplePackageSigning(void); @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 to be anchored to Test 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". @@ -498,19 +557,75 @@ SecPolicyRef SecPolicyCreateApplePackageSigning(void); __nullable CF_RETURNS_RETAINED SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void); +/*! + @function SecPolicyCreateiPhoneVPNApplicationSigning + @abstract Returns a policy object for evaluating signed VPN application + 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. + * 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". + * The leaf has a marker extension with 1.2.840.113635.100.6.1.6. + * The leaf has ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID + or the CodeSigning OID. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateiPhoneVPNApplicationSigning(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + /*! @function SecPolicyCreateiPhoneProfileApplicationSigning @abstract Returns a policy object for evaluating signed application signatures. This policy is for certificates inside a UPP or regular profile. - @discussion This policy only verifies that the leaf is temporally valid - and not revoked via any available method. + @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. + * 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: + * 1.2.840.113635.100.6.1.2 ("iPhone Developer" leaf) + * 1.2.840.113635.100.6.1.4 ("iPhone Distribution" leaf) + * 1.2.840.113635.100.6.1.25.1 ("TestFlight" leaf) + * On internal releases, 1.2.840.113635.100.6.1.25.2 + * The leaf has an ExtendedKeyUsage OID matching 1.3.6.1.5.5.7.3.3 (CodeSigning EKU). + * 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 SecPolicyCreateiPhoneProfileApplicationSigning(void); +/*! + @function SecPolicyCreateMacOSProfileApplicationSigning + @abstract Returns a policy object for evaluating signed application + signatures. This policy is for certificates inside a UPP or regular + 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. + * 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) + * 1.2.840.113635.100.6.1.12 ("Mac Developer" leaf) + * 1.2.840.113635.100.6.1.13 ("Developer ID Application" leaf) + * 1.2.840.113635.100.6.22 ("Software Signing" leaf + * The leaf has an ExtendedKeyUsage OID matching 1.3.6.1.5.5.7.3.3 (CodeSigning EKU). + * 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 SecPolicyCreateMacOSProfileApplicationSigning(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + /*! @function SecPolicyCreateiPhoneProvisioningProfileSigning @abstract Returns a policy object for evaluating provisioning profile signatures. @@ -571,7 +686,8 @@ enum { kSecKeyExchangeEncryptSMIMEUsage = (1 << 4), kSecKeyExchangeBothSMIMEUsage = (1 << 5), kSecAnyEncryptSMIME = kSecKeyEncryptSMIMEUsage | kSecDataEncryptSMIMEUsage | - kSecKeyExchangeDecryptSMIMEUsage | kSecKeyExchangeEncryptSMIMEUsage + kSecKeyExchangeDecryptSMIMEUsage | kSecKeyExchangeEncryptSMIMEUsage, + kSecIgnoreExpirationSMIMEUsage = (1 << 6) }; /*! @@ -589,6 +705,7 @@ enum { * 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. + Note that temporal validity checking can be disabled with kSecIgnoreExpirationSMIMEUsage @result A policy object. The caller is responsible for calling CFRelease on this when it is no longer needed. */ @@ -662,6 +779,24 @@ SecPolicyRef SecPolicyCreateOTATasking(void); __nullable CF_RETURNS_RETAINED SecPolicyRef SecPolicyCreateMobileAsset(void); +/*! + @function SecPolicyCreateMobileAssetDevelopment + @abstract Returns a policy object for evaluating certificate chains for signing development + 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. + * 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. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateMobileAssetDevelopment(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + /*! @function SecPolicyCreateAppleIDAuthorityPolicy @abstract Returns a policy object for evaluating certificate chains for Apple ID Authority. @@ -672,6 +807,7 @@ SecPolicyRef SecPolicyCreateMobileAsset(void); * 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. + * 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. */ @@ -1490,6 +1626,67 @@ __nullable CF_RETURNS_RETAINED SecPolicyRef SecPolicyCreateAppleCompatibilityiCloudSetupService(CFStringRef hostname) __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); +/*! + @function SecPolicyCreateAppleAppTransportSecurity + @abstract Ensure all certs in the evaluation meet ATS minimums + @discussion This policy is meant to be used alongside an SSL policy in order to enforce App Transport Security certificate rules: + * All certificates use either RSA key sizes of 2048-bits or larger or EC key sizes of 256-bits or larger. + * All certificates use SHA-256 or better for signature hash algorithms. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateAppleAppTransportSecurity(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateMobileSoftwareUpdate + @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. + * 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, + 1.2.840.113635.100.6.57.1. + * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. + @result A policy object. The caller is responsible for calling CFRelease + on this when it is no longer needed. + */ +__nullable CF_RETURNS_RETAINED +SecPolicyRef SecPolicyCreateMobileSoftwareUpdate(void) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateAppleBasicAttestationSystem + @abstract Returns a policy object for verifying Basic Attestation Authority SCRT-attested certs + @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to the Basic Attestation System Root CA. + * There are exactly 3 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 SecPolicyCreateAppleBasicAttestationSystem(CFDataRef __nullable testRootHash) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecPolicyCreateAppleBasicAttestationUser + @abstract Returns a policy object for verifying Basic Attestation Authority UCRT-attested certs + @param testRootHash Optional; The SHA-256 fingerprint of a test root for pinning. + @discussion The resulting policy uses the Basic X.509 policy with validity check and + pinning options: + * The chain is anchored to the Basic Attestation User Root CA. + * There are exactly 3 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 SecPolicyCreateAppleBasicAttestationUser(CFDataRef __nullable testRootHash) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); CF_IMPLICIT_BRIDGING_DISABLED CF_ASSUME_NONNULL_END @@ -1546,11 +1743,13 @@ CFStringRef SecPolicyGetStringForOID(CSSM_OID* oid); @function SecPolicyCreateAppleTimeStampingAndRevocationPolicies @abstract Create timeStamping policy array from a given set of policies by applying identical revocation behavior @param policyOrArray can be a SecPolicyRef or a CFArray of SecPolicyRef - @discussion This function is soon to be deprecated. Callers should create an array of the non-deprecated timestamping - and revocation policies. + @discussion This function is deprecated in macOS 10.13 and later. Your code should call SecPolicyCreateAppleTimeStamping + and SecPolicyCreateRevocation instead to obtain these policies, then insert them into an array as needed. */ __nullable CF_RETURNS_RETAINED -CFArrayRef SecPolicyCreateAppleTimeStampingAndRevocationPolicies(CFTypeRef policyOrArray); +CFArrayRef SecPolicyCreateAppleTimeStampingAndRevocationPolicies(CFTypeRef policyOrArray) + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_10, __MAC_10_13, __IPHONE_NA, __IPHONE_NA); + CF_IMPLICIT_BRIDGING_DISABLED CF_ASSUME_NONNULL_END diff --git a/trust/SecTrust.h b/trust/SecTrust.h index 2bdb7b97..3783409e 100644 --- a/trust/SecTrust.h +++ b/trust/SecTrust.h @@ -168,7 +168,7 @@ extern const CFStringRef kSecTrustRevocationValidUntilDate extern const CFStringRef kSecTrustCertificateTransparency __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0); extern const CFStringRef kSecTrustCertificateTransparencyWhiteList - __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13, __IPHONE_10_0, __IPHONE_11_0); #ifdef __BLOCKS__ /*! @@ -603,13 +603,16 @@ OSStatus SecTrustSetParameters(SecTrustRef trustRef, @param keychainOrArray A reference to an array of keychains to search, a single keychain, or NULL to use the default keychain search list. @result A result code. See "Security Error Codes" (SecBase.h). - @discussion By default, the user's keychain search list and the system - anchors keychain are searched for certificates to complete the chain. You - can specify a zero-element array if you do not want any keychains searched. - Note: this function is not applicable to iOS. + @discussion This function is deprecated in macOS 10.13 and later. Beginning in + macOS 10.12, this function no longer affected the behavior of the trust + evaluation: the user's keychain search list and the system + anchors keychain are searched for certificates to complete the chain. To change + the keychains that are searched, callers must use SecKeychainSetSearchList to + change the user's keychain search list. + Note: this function was never applicable to iOS. */ OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef __nullable keychainOrArray) - __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); + __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_13, __IPHONE_NA, __IPHONE_NA); /*! @function SecTrustGetResult diff --git a/trust/SecTrustPriv.h b/trust/SecTrustPriv.h index 441b0220..a616b86a 100644 --- a/trust/SecTrustPriv.h +++ b/trust/SecTrustPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2003-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -61,7 +61,13 @@ extern const CFStringRef kSecTrustInfoCompanyNameKey; extern const CFStringRef kSecTrustInfoRevocationKey; extern const CFStringRef kSecTrustInfoRevocationValidUntilKey; extern const CFStringRef kSecTrustInfoCertificateTransparencyKey; -extern const CFStringRef kSecTrustInfoCertificateTransparencyWhiteListKey; + +/* Constants used as keys in the certificate details dictionary. + An array of per-certificate details is returned by SecTrustCopyResult + as the value of the kSecTrustResultDetails key. +*/ +extern const CFStringRef kSecCertificateDetailStatusCodes; + /*__OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0);*/ /*! @enum Trust Result Constants @@ -218,6 +224,23 @@ CFArrayRef SecTrustGetDetails(SecTrustRef trust); __nullable CF_RETURNS_RETAINED CFArrayRef SecTrustCopyFilteredDetails(SecTrustRef trust); +/*! + @function SecTrustIsExpiredOnly + @abstract Determine whether expiration is the only problem with a certificate chain. + @param trust A reference to a trust object. + @result A boolean value indicating whether expiration is the only problem found + with the certificate chain in the given trust reference. + @discussion Returns true if one or more certificates in the chain have expired, + expiration is an error (i.e. it is not being ignored by existing trust settings), + and it is the only error encountered. Returns false if the certificate(s) have not + expired, or are expired but have trust settings to override their expiration, + or if the trust chain has other errors beside expiration. Your code should call + this function after SecTrustEvaluate has returned a recoverable trust failure, + so you can distinguish this case from other possible errors. + */ +Boolean SecTrustIsExpiredOnly(SecTrustRef trust) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + /* For debugging purposes. */ __nullable CF_RETURNS_RETAINED CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust); @@ -256,11 +279,11 @@ OSStatus SecTrustSetTrustedLogs(SecTrustRef trust, CFArrayRef trustedLogs); -network-fetched issuers User must provide all necessary certificates in the input certificates and/or anchors. */ OSStatus SecTrustSetKeychainsAllowed(SecTrustRef trust, Boolean allowed) - __OSX_AVAILABLE(__MAC_10_12) __IOS_AVAILABLE(__IPHONE_10_0) __TVOS_AVAILABLE(__TVOS_10_0) __WATCHOS_AVAILABLE(__WATCHOS_3_0); + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); /* Get the keychain search policy for the trust object. */ OSStatus SecTrustGetKeychainsAllowed(SecTrustRef trust, Boolean * __nonnull allowed) - __OSX_AVAILABLE(__MAC_10_12) __IOS_AVAILABLE(__IPHONE_10_0) __TVOS_AVAILABLE(__TVOS_10_0) __WATCHOS_AVAILABLE(__WATCHOS_3_0); + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); /*! @function SecTrustEvaluateLeafOnly @@ -274,7 +297,7 @@ OSStatus SecTrustGetKeychainsAllowed(SecTrustRef trust, Boolean * __nonnull allo any set exceptions or usage constraints. */ OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType * __nonnull result) - __OSX_AVAILABLE(__MAC_10_12) __IOS_AVAILABLE(__IPHONE_10_0) __TVOS_AVAILABLE(__TVOS_10_0) __WATCHOS_AVAILABLE(__WATCHOS_3_0); + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); /*! @function SecTrustSerialize @@ -288,7 +311,7 @@ OSStatus SecTrustEvaluateLeafOnly(SecTrustRef trust, SecTrustResultType * __nonn */ __nullable CF_RETURNS_RETAINED CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) - __OSX_AVAILABLE(__MAC_10_12) __IOS_AVAILABLE(__IPHONE_10_0) __TVOS_AVAILABLE(__TVOS_10_0) __WATCHOS_AVAILABLE(__WATCHOS_3_0); + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); /*! @function SecTrustDeserialize @@ -302,7 +325,7 @@ CFDataRef SecTrustSerialize(SecTrustRef trust, CFErrorRef *error) */ __nullable CF_RETURNS_RETAINED SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) - __OSX_AVAILABLE(__MAC_10_12) __IOS_AVAILABLE(__IPHONE_10_0) __TVOS_AVAILABLE(__TVOS_10_0) __WATCHOS_AVAILABLE(__WATCHOS_3_0); + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); /*! @function SecTrustGetTrustExceptionsArray @@ -314,7 +337,7 @@ SecTrustRef SecTrustDeserialize(CFDataRef serializedTrust, CFErrorRef *error) exceptions which could be set using SecTrustSetExceptions. */ __nullable CFArrayRef SecTrustGetTrustExceptionsArray(SecTrustRef trust) - __OSX_AVAILABLE(__MAC_10_12) __IOS_AVAILABLE(__IPHONE_10_0) __TVOS_AVAILABLE(__TVOS_10_0) __WATCHOS_AVAILABLE(__WATCHOS_3_0); + __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0); /*! @function SecTrustCopyInputCertificates @@ -338,6 +361,32 @@ __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_ OSStatus SecTrustAddToInputCertificates(SecTrustRef trust, CFTypeRef _Nonnull certificates) __OSX_AVAILABLE(10.12.4) __IOS_AVAILABLE(10.3) __TVOS_AVAILABLE(10.2) __WATCHOS_AVAILABLE(3.2); +/*! + @function SecTrustSetPinningPolicyName + @abstract Set the policy name to be used during the trust evaluation. + @param trust A reference to the trust object + @param policyName A string representing the name of the pinning policy to be used. + @result A result code. See "Security Error Codes" (SecBase.h) + @discussion This function permits the caller to enable the dynamic lookup of the + pinning policy using a built-in database as an alternative to using a SecPolicyCreate function + with the pinning rules and calling SecTrustCreateWithCertificates or SecTrustSetPolicies. + */ +OSStatus SecTrustSetPinningPolicyName(SecTrustRef trust, CFStringRef policyName) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + +/*! + @function SecTrustSetPinningException + @abstract Remove pinning requirement from this trust evaluation + @param trust A reference to the trust object + @result A result code. See "Security Error Codes" (SecBase.h) + @discussion This function provides an exception for this particular trust for a bundle that + otherwise requires pinning for all connections. Bundles use the SecTrustPinningRequired key + with boolean value of true in their info plist to indicate that all SSL connections from the + bundle must be pinned. + */ +OSStatus SecTrustSetPinningException(SecTrustRef trust) + __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); + CF_IMPLICIT_BRIDGING_DISABLED CF_ASSUME_NONNULL_END diff --git a/trust/SecTrustSettingsPriv.h b/trust/SecTrustSettingsPriv.h index fe235e31..89feb679 100644 --- a/trust/SecTrustSettingsPriv.h +++ b/trust/SecTrustSettingsPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#ifndef _SECURITY_SECTRUSTSETTINGSPRIV_H_ +#ifndef _SECURITY_SECTRUSTSETTINGSPRIV_H_ #define _SECURITY_SECTRUSTSETTINGSPRIV_H_ #include @@ -149,6 +149,23 @@ OSStatus SecTrustSettingsSetTrustSettingsExternal( CFTypeRef trustSettingsDictOrArray, /* optional */ CFDataRef *settingsOut); /* RETURNED */ +/* + * Add user trust settings for a SSL certificate and a given hostname. + * This is a wrapper around the SecTrustSettingsSetTrustSettings API + * and should be functionally equivalent to "Always trust" in the UI. + * + * When this function is called, the user will be prompted to authorize + * the trust settings change. After they successfully authenticate, or + * cancel the dialog, the result block will be called to indicate the + * current trust status. If an error occurred (such as errUserCanceled), + * the error reference provided to the block will be non-NULL. + */ +void SecTrustSettingsSetTrustedCertificateForSSLHost( + SecCertificateRef certificate, + CFStringRef hostname, + void (^result)(SecTrustSettingsResult trustResult, CFErrorRef error)) + __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_NA); + /* * Purge the cache of User and Admin Certs */ diff --git a/xcconfig/PlatformFeatures.xcconfig b/xcconfig/PlatformFeatures.xcconfig new file mode 100644 index 00000000..3c5e655d --- /dev/null +++ b/xcconfig/PlatformFeatures.xcconfig @@ -0,0 +1,26 @@ + +#include "xcconfig/PlatformLibraries.xcconfig" + +PLATFORM_STR = "unknown" +PLATFORM_STR[sdk=macosx*] = "macos" +PLATFORM_STR[sdk=iphoneos*] = "iphone" +PLATFORM_STR[sdk=watchos*] = "watch" +PLATFORM_STR[sdk=appletvos*] = "tv" + +// Octagon is on for the mac and non-bridge non-horizon iphones +OCTAGON_ON=0 +OCTAGON_ON[sdk=macosx*]=1 + +// HORIZON Will be either "unset" (horizon on) or "0" (horizon off) +HORIZON_INTERMEDIATE_ = 0 +HORIZON = $(HORIZON_INTERMEDIATE_$(RC_HORIZON)) + +// If horizon is off, OCTAGON should be ON +OCTAGON_ON_IOS_HORIZON_0 = 1 +OCTAGON_ON_IOS_HORIZON_ = 0 + +OCTAGON_ON_IOS_BRIDGE_NO = $(OCTAGON_ON_IOS_HORIZON_$(HORIZON)) +OCTAGON_ON_IOS_BRIDGE_YES = 0 +OCTAGON_ON[sdk=iphone*] = $(OCTAGON_ON_IOS_BRIDGE_$(BRIDGE)) +OCTAGON_ON[sdk=watch*] = 0 +OCTAGON_ON[sdk=appletv*] = 0 diff --git a/xcconfig/PlatformLibraries.xcconfig b/xcconfig/PlatformLibraries.xcconfig new file mode 100644 index 00000000..00b64c06 --- /dev/null +++ b/xcconfig/PlatformLibraries.xcconfig @@ -0,0 +1,55 @@ + +AOSKIT_FRAMEWORK[sdk=macosx*] = -framework AOSAccounts +APPLE_AKS_LIBRARY[sdk=macosx*] = -L$(SDKROOT)/usr/local/lib -laks -framework MobileKeyBag +APPLE_AKS_LIBRARY[sdk=iphoneos*] = -L$(SDKROOT)/usr/local/lib -laks -framework MobileKeyBag +APPLE_AKS_LIBRARY[sdk=watchos*] = -L$(SDKROOT)/usr/local/lib -laks -framework MobileKeyBag +APPLE_AKS_LIBRARY[sdk=appletvos*] = -L$(SDKROOT)/usr/local/lib -laks -framework MobileKeyBag + +OTHER_LDFLAGS_AGGREGATEDICTIONARY[sdk=embedded] = -framework AggregateDictionary +OTHER_LDFLAGS_APPLESYSTEMINFO[sdk=macos*] = -framework AppleSystemInfo +OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT[sdk=macosx*] = -lDiagnosticMessagesClient +OTHER_LDFLAGS_LIBCMS[sdk=embedded*] = -lCMS +OTHER_LDFLAGS_MOBILEGESTALT[sdk=embedded*] = -lMobileGestalt + +// +// Play games to avoid issues with bridge trains +// +BRIDGE_YES = YES +BRIDGE_ = NO +BRIDGE_NO = NO +BRIDGE = $(BRIDGE_$(RC_BRIDGE)) + +OTHER_LDFLAGS_APS_BRIDGE_NO = -framework ApplePushService +OTHER_LDFLAGS_APS_BRIDGE_YES = +OTHER_LDFLAGS_APS = $(OTHER_LDFLAGS_APS_BRIDGE_$(BRIDGE)) + +OTHER_LDFLAGS_CLOUDKIT_BRIDGE_NO = -framework CloudKit +OTHER_LDFLAGS_CLOUDKIT_BRIDGE_YES = +OTHER_LDFLAGS_CLOUDKIT = $(OTHER_LDFLAGS_CLOUDKIT_BRIDGE_$(BRIDGE)) + +OTHER_LDFLAGS_PROTOBUF_BRIDGE_NO = -framework ProtocolBuffer +OTHER_LDFLAGS_PROTOBUF_BRIDGE_YES = +OTHER_LDFLAGS_PROTOBUF = $(OTHER_LDFLAGS_PROTOBUF_BRIDGE_$(BRIDGE)) + +OTHER_LDFLAGS_SHAREDWEBCREDENTIALS_IOS_NO = -framework SharedWebCredentials +OTHER_LDFLAGS_SHAREDWEBCREDENTIALS_IOS_YES = +OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=iphoneos*] = $(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS_IOS_$(BRIDGE)) +OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=watchos*] = +OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=appletvos*] = + +//OTHER_LDFLAGS_APPLEIDAUTHSUPPORT_BRIDGE_NO = -Wl,-upward_framework,AppleIDAuthSupport +OTHER_LDFLAGS_APPLEIDAUTHSUPPORT_BRIDGE_NO = +OTHER_LDFLAGS_APPLEIDAUTHSUPPORT_BRIDGE_YES = +OTHER_LDFLAGS_APPLEIDAUTHSUPPORT = $(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT_BRIDGE_$(BRIDGE)) + +OTHER_LDFLAGS_WIRELESSDIAGNOSTICS_BRIDGE_NO = -framework WirelessDiagnostics +OTHER_LDFLAGS_WIRELESSDIAGNOSTICS_BRIDGE_YES = +OTHER_LDFLAGS_WIRELESSDIAGNOSTICS = $(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS_BRIDGE_$(BRIDGE)) + +OTHER_LDFLAGS_MOBILEASSET_BRIDGE_NO = -framework MobileAsset +OTHER_LDFLAGS_MOBILEASSET_BRIDGE_YES = +OTHER_LDFLAGS_MOBILEASSET = $(OTHER_LDFLAGS_MOBILEASSET_BRIDGE_$(BRIDGE)) + +OTHER_LDFLAGS_SECURITYFOUNDATION_BRIDGE_NO = -framework SecurityFoundation +OTHER_LDFLAGS_SECURITYFOUNDATION_BRIDGE_YES = +OTHER_LDFLAGS_SECURITYFOUNDATION = $(OTHER_LDFLAGS_SECURITYFOUNDATION_BRIDGE_$(BRIDGE)) diff --git a/xcconfig/Security.xcconfig b/xcconfig/Security.xcconfig index 72588c89..c0cbe4fb 100644 --- a/xcconfig/Security.xcconfig +++ b/xcconfig/Security.xcconfig @@ -1,18 +1,22 @@ -APPLE_AKS_LIBRARY[sdk=macosx*] = -L$(SDKROOT)/usr/local/lib -laks -framework MobileKeyBag -APPLE_AKS_LIBRARY[sdk=iphoneos*] = -L$(SDKROOT)/usr/local/lib -laks -framework MobileKeyBag -APPLE_AKS_LIBRARY[sdk=watchos*] = -L$(SDKROOT)/usr/local/lib -laks -framework MobileKeyBag -APPLE_AKS_LIBRARY[sdk=tvos*] = -L$(SDKROOT)/usr/local/lib -laks -framework MobileKeyBag +SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) $(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks +OTHER_CFLAGS = -isystem $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders -fconstant-cfstrings -FRAMEWORK_SEARCH_PATHS = $(inherited) $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(DEVELOPER_LIBRARY_DIR) -HEADER_SEARCH_PATHS = $(PROJECT_DIR)/header_symlinks/ $(PROJECT_DIR) $(PROJECT_DIR)/OSX/libsecurity_keychain/libDER $(PROJECT_DIR)/OSX/libsecurity_asn1 $(PROJECT_DIR)/libsecurity_smime $(PROJECT_DIR)/OSX/sec/ProjectHeaders $(PROJECT_DIR)/OSX/sec $(PROJECT_DIR)/OSX/sec/SOSCircle $(PROJECT_DIR)/OSX/utilities $(PROJECT_DIR)/OSX/regressions $(PROJECT_DIR)/OSX/ $(inherited) +HEADER_SEARCH_PATHS = $(PROJECT_DIR) $(PROJECT_DIR)/OSX/libsecurity_keychain/libDER $(PROJECT_DIR)/OSX/libsecurity_asn1 $(PROJECT_DIR)/OSX/sec/ProjectHeaders $(PROJECT_DIR)/OSX/sec $(PROJECT_DIR)/OSX/utilities $(PROJECT_DIR)/OSX $(inherited) +ARCHS[sdk=macosx*] = $(ARCHS_STANDARD) -HEADER_SEARCH_PATHS[sdk=macosx*] = $(PROJECT_DIR)/header_symlinks/macOS/ $(inherited) -HEADER_SEARCH_PATHS[sdk=embedded*] = $(PROJECT_DIR)/header_symlinks/iOS/ $(inherited) +#include "xcconfig/PlatformFeatures.xcconfig" -ARCHS[sdk=macosx*] = $(ARCHS_STANDARD) +// Note that the 'Settings' view in Xcode will display the wrong values for platform-dependent settings +// Refer to the actual build command for final computed value +GCC_PREPROCESSOR_DEFINITIONS = __KEYCHAINCORE__=1 CORECRYPTO_DONOT_USE_TRANSPARENT_UNION=1 OCTAGON=$(OCTAGON_ON) PLATFORM=$(PLATFORM_STR) $(GCC_PREPROCESSOR_DEFINITIONS) + +SECURITY_FUZZER_BASE_DIR = /AppleInternal/CoreOS/Fuzzers/Security + +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 -AOSKIT_FRAMEWORK[sdk=macosx*] = -framework AOSAccounts -GCC_PREPROCESSOR_DEFINITIONS = __KEYCHAINCORE__=1 OSSPINLOCK_USE_INLINED=0 $(GCC_PREPROCESSOR_DEFINITIONS) +WARNING_CFLAGS[sdk=iphone*] = $(WARNING_CFLAGS) -Wformat=2 +WARNING_CFLAGS[sdk=tvos*] = $(WARNING_CFLAGS) -Wformat=2 +WARNING_CFLAGS[sdk=watchos*] = $(WARNING_CFLAGS) -Wformat=2 diff --git a/xcconfig/framework_requiring_modern_objc_runtime.xcconfig b/xcconfig/framework_requiring_modern_objc_runtime.xcconfig new file mode 100644 index 00000000..504ae89e --- /dev/null +++ b/xcconfig/framework_requiring_modern_objc_runtime.xcconfig @@ -0,0 +1,7 @@ + +// 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 arm64 x86_64 x86_64h + +VALID_ARCHS[sdk=*simulator*] = armv6 armv7 arm64 i386 x86_64 x86_64h diff --git a/xcconfig/ios_on_macos.xcconfig b/xcconfig/ios_on_macos.xcconfig index b0209111..6965faa7 100644 --- a/xcconfig/ios_on_macos.xcconfig +++ b/xcconfig/ios_on_macos.xcconfig @@ -1,2 +1,4 @@ GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*] = $(inherited) SECITEM_SHIM_OSX=1 SEC_IOS_ON_OSX=1 + +GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO diff --git a/xcconfig/lib_ios.xcconfig b/xcconfig/lib_ios.xcconfig index 0d2ee597..f848c535 100644 --- a/xcconfig/lib_ios.xcconfig +++ b/xcconfig/lib_ios.xcconfig @@ -5,16 +5,16 @@ EXECUTABLE_EXTENSION = a CODE_SIGN_IDENTITY = -HEADER_SEARCH_PATHS = $(inherited) $(PROJECT_DIR) $(PROJECT_DIR)/OSX/sec/ProjectHeaders $(PROJECT_DIR)/OSX/utilities $(PROJECT_DIR)/OSX/sec/ipc $(PROJECT_DIR)/OSX/sectask $(PROJECT_DIR)/OSX/libsecurity_asn1 $(PROJECT_DIR)/OSX/libsecurity_ssl $(PROJECT_DIR)/OSX/regressions $(PROJECT_DIR)/OSX/ibsecurity_keychain/libDER $(BUILT_PRODUCTS_DIR)/usr/local/include +HEADER_SEARCH_PATHS = $(inherited) $(PROJECT_DIR) $(PROJECT_DIR)/header_symlinks $(PROJECT_DIR)/OSX/sec/ProjectHeaders $(PROJECT_DIR)/OSX/utilities $(PROJECT_DIR)/OSX/sec/ipc $(PROJECT_DIR)/OSX/sectask $(PROJECT_DIR)/OSX/libsecurity_asn1 $(PROJECT_DIR)/OSX/libsecurity_ssl $(PROJECT_DIR)/OSX/regressions $(PROJECT_DIR)/OSX/ibsecurity_keychain/libDER $(BUILT_PRODUCTS_DIR)/usr/local/include -HEADER_SEARCH_PATHS[sdk=macosx*] = $(inherited) $(PROJECT_DIR)/OSX/libsecurity_smime $(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers - -HEADER_SEARCH_PATHS[sdk=embedded*] = $(inherited) $(PROJECT_DIR)/libsecurity_smime $(PROJECT_DIR)/OSX/sec/sectask +HEADER_SEARCH_PATHS[sdk=macosx*] = $(inherited) $(PROJECT_DIR)/OSX/libsecurity_smime $(PROJECT_DIR)/header_symlinks/macOS $(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers +HEADER_SEARCH_PATHS[sdk=embedded*] = $(inherited) $(PROJECT_DIR)/libsecurity_smime $(PROJECT_DIR)/OSX/sec/sectask $(PROJECT_DIR)/header_symlinks/iOS // Turning off deprecations here is the worst hack. Enable whenever possible. WARNING_CFLAGS = -Wno-deprecated-declarations -Wglobal-constructors -Wmost -Wno-four-char-constants -Wno-unknown-pragmas $(inherited) -OTHER_CFLAGS = -isystem$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders -iframework$(SDKROOT)/System/Library/PrivateFrameworks $(inherited) + +OTHER_CFLAGS = -isystem $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders -fconstant-cfstrings $(inherited) DEAD_CODE_STRIPPING = YES COPY_PHASE_STRIP = NO @@ -44,3 +44,5 @@ GCC_WARN_SHADOW = NO GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*] = $(inherited) SEC_IOS_ON_OSX=1 GCC_PREPROCESSOR_DEFINITIONS[sdk=embeddedsimulator*] = $(inherited) NO_SERVER=1 + +GCC_PREPROCESSOR_DEFINITIONS[config=Debug][sdk=embedded] = $(inherited) NO_SERVER=1 diff --git a/xcconfig/lib_ios_debug.xcconfig b/xcconfig/lib_ios_debug.xcconfig deleted file mode 100644 index 15920593..00000000 --- a/xcconfig/lib_ios_debug.xcconfig +++ /dev/null @@ -1,5 +0,0 @@ -#include "xcconfig/lib_ios.xcconfig" - -GCC_PREPROCESSOR_DEFINITIONS[sdk=embedded] = $(inherited) NO_SERVER=1 - -ONLY_ACTIVE_ARCH = YES diff --git a/xcconfig/lib_ios_debug_all_archs.xcconfig b/xcconfig/lib_ios_debug_all_archs.xcconfig deleted file mode 100644 index 61b4eba5..00000000 --- a/xcconfig/lib_ios_debug_all_archs.xcconfig +++ /dev/null @@ -1,7 +0,0 @@ -// -// lib_ios_debug_all_archs.xcconfig -// Security -// -// Created by Bailey Basile on 11/2/16. -// -// diff --git a/xcconfig/lib_ios_release.xcconfig b/xcconfig/lib_ios_release.xcconfig deleted file mode 100644 index 874d7c47..00000000 --- a/xcconfig/lib_ios_release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "xcconfig/lib_ios.xcconfig" diff --git a/xcconfig/lib_ios_debug_shim.xcconfig b/xcconfig/lib_ios_shim.xcconfig similarity index 68% rename from xcconfig/lib_ios_debug_shim.xcconfig rename to xcconfig/lib_ios_shim.xcconfig index f71c45e8..0ff54168 100644 --- a/xcconfig/lib_ios_debug_shim.xcconfig +++ b/xcconfig/lib_ios_shim.xcconfig @@ -1,3 +1,3 @@ -#include "xcconfig/lib_ios_debug.xcconfig" +#include "xcconfig/lib_ios.xcconfig" GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*] = SECITEM_SHIM_OSX=1 SEC_IOS_ON_OSX=1 $(inherited) diff --git a/xcconfig/lib_ios_x64_debug.xcconfig b/xcconfig/lib_ios_x64_debug.xcconfig deleted file mode 100644 index 5e38fbd3..00000000 --- a/xcconfig/lib_ios_x64_debug.xcconfig +++ /dev/null @@ -1,5 +0,0 @@ -#include "xcconfig/lib_ios_x64.xcconfig" - -GCC_PREPROCESSOR_DEFINITIONS[sdk=embedded] = $(inherited) NO_SERVER=1 - -ONLY_ACTIVE_ARCH = YES diff --git a/xcconfig/lib_ios_x64_debug_shim.xcconfig b/xcconfig/lib_ios_x64_debug_shim.xcconfig deleted file mode 100644 index 40ce8e60..00000000 --- a/xcconfig/lib_ios_x64_debug_shim.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "xcconfig/lib_ios_x64_debug.xcconfig" - -GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*] = SECITEM_SHIM_OSX=1 SEC_IOS_ON_OSX=1 $(inherited) diff --git a/xcconfig/lib_ios_x64_release.xcconfig b/xcconfig/lib_ios_x64_release.xcconfig deleted file mode 100644 index e6acb04a..00000000 --- a/xcconfig/lib_ios_x64_release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "xcconfig/lib_ios_x64.xcconfig" diff --git a/xcconfig/lib_ios_x64_release_shim.xcconfig b/xcconfig/lib_ios_x64_release_shim.xcconfig deleted file mode 100644 index 93f151cc..00000000 --- a/xcconfig/lib_ios_x64_release_shim.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "xcconfig/lib_ios_x64_release.xcconfig" - -GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*] = SECITEM_SHIM_OSX=1 SEC_IOS_ON_OSX=1 $(inherited) diff --git a/xcconfig/lib_ios_release_shim.xcconfig b/xcconfig/lib_ios_x64_shim.xcconfig similarity index 67% rename from xcconfig/lib_ios_release_shim.xcconfig rename to xcconfig/lib_ios_x64_shim.xcconfig index 9d629e5f..4c61b8c7 100644 --- a/xcconfig/lib_ios_release_shim.xcconfig +++ b/xcconfig/lib_ios_x64_shim.xcconfig @@ -1,3 +1,3 @@ -#include "xcconfig/lib_ios_release.xcconfig" +#include "xcconfig/lib_ios_x64.xcconfig" GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*] = SECITEM_SHIM_OSX=1 SEC_IOS_ON_OSX=1 $(inherited) diff --git a/xcconfig/macos_legacy_lib.xcconfig b/xcconfig/macos_legacy_lib.xcconfig index 74367cb4..34d7d2c9 100644 --- a/xcconfig/macos_legacy_lib.xcconfig +++ b/xcconfig/macos_legacy_lib.xcconfig @@ -15,7 +15,7 @@ GCC_GENERATE_DEBUGGING_SYMBOLS = YES CODE_SIGN_IDENTITY = SKIP_INSTALL = YES -PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/$(TARGET_NAME +PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/$(TARGET_NAME) // Code is ugly. Turn off some warnings. -- 2.47.2